aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-03 13:43:22 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-03 13:43:22 -0800
commit181683a6bdfbd4b536a8b37860c7dd779a0468a4 (patch)
tree2e419d90ce36f37507417e2992f9a18d266fccbb
parent6c929efccc340ed6fe76185e7176aa5fe343ea69 (diff)
downloadltsi-kernel-181683a6bdfbd4b536a8b37860c7dd779a0468a4.tar.gz
more zynq patches
-rw-r--r--patches.zynq/0001-i2c-xilinx-merge-i2c-driver-from-Xilinx-repository-i.patch1004
-rw-r--r--patches.zynq/0002-i2c-si570-merge-support-for-si570-clock-generator.patch662
-rw-r--r--patches.zynq/0003-mmc-arasan-add-a-driver-for-Arasan-s-SDHCI-controlle.patch327
-rw-r--r--patches.zynq/0004-net-ethernet-xilinx-Merge-driver-from-Xilinx-reposit.patch4349
-rw-r--r--patches.zynq/0005-gpio-xilinx-merge-Xilinx-gpio-support-into-LTSI-3.10.patch1207
-rw-r--r--patches.zynq/0006-spi-xilinx-merge-qspi-support-from-xilinx-repository.patch2303
-rw-r--r--patches.zynq/0007-mtd-xilinx-merge-nand-flash-support-from-xilinx-repo.patch1876
-rw-r--r--patches.zynq/0008-watchdog-xilinx-merge-support-for-xilinx-watchdog.patch619
-rw-r--r--patches.zynq/0009-usb-zynq-merge-usb-support-for-xilinx-zynq-soc.patch3821
-rw-r--r--patches.zynq/0010-memory-zynq-merge-driver-for-Zynq-SMC.patch706
-rw-r--r--patches.zynq/0011-arm-dts-zynq-Merge-zynq-zc702.dts-with-Xilinx-reposi.patch418
-rw-r--r--patches.zynq/0012-defconfig-zynq-merge-xilinx-zynq-defconfig-from-xili.patch2477
-rw-r--r--series12
13 files changed, 19781 insertions, 0 deletions
diff --git a/patches.zynq/0001-i2c-xilinx-merge-i2c-driver-from-Xilinx-repository-i.patch b/patches.zynq/0001-i2c-xilinx-merge-i2c-driver-from-Xilinx-repository-i.patch
new file mode 100644
index 00000000000000..ab31681856c130
--- /dev/null
+++ b/patches.zynq/0001-i2c-xilinx-merge-i2c-driver-from-Xilinx-repository-i.patch
@@ -0,0 +1,1004 @@
+From b23b4c001f284dba44b70ba7d2d88b0f9b7d5c71 Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Fri, 20 Dec 2013 15:57:55 +0900
+Subject: i2c: xilinx: merge i2c driver from Xilinx repository into LTSI
+
+This merges i2c functionality from Xilinx repository (commit
+efc27505715e64526653f35274717c0fc56491e3 in master branch). It has
+been tested to read the eeprom on a zc702 board.
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/i2c/busses/Kconfig | 9
+ drivers/i2c/busses/i2c-xilinx_ps.c | 966 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 975 insertions(+)
+ create mode 100644 drivers/i2c/busses/i2c-xilinx_ps.c
+
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -736,6 +736,15 @@ config I2C_WMT
+ This driver can also be built as a module. If so, the module will be
+ called i2c-wmt.
+
++config I2C_XILINX_PS
++ tristate "XILINX PS I2C Controller"
++ depends on ARCH_ZYNQ
++ help
++ Say yes here to select Xilnx PS I2C Host Controller
++
++ This driver can also be built as a module. If so, the module
++ will be called i2c-xilinx_ps.
++
+ config I2C_OCTEON
+ tristate "Cavium OCTEON I2C bus support"
+ depends on CPU_CAVIUM_OCTEON
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-xilinx_ps.c
+@@ -0,0 +1,966 @@
++/*
++ * Xilinx I2C bus driver for the PS I2C Interfaces.
++ *
++ * 2009-2011 (c) Xilinx, Inc.
++ *
++ * This program is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU General Public
++ * License as published by the Free Software Foundation;
++ * either version 2 of the License, or (at your option) any
++ * later version.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
++ * 02139, USA.
++ *
++ *
++ * Workaround in Receive Mode
++ * If there is only one message to be processed, then based on length of
++ * the message we set the HOLD bit.
++ * If the length is less than the FIFO depth, then we will directly
++ * receive a COMP interrupt and the transaction is done.
++ * If the length is more than the FIFO depth, then we enable the HOLD bit.
++ * if the requested data is greater than the max transfer size(252 bytes)
++ * update the transfer size register with max transfer size else update
++ * with the requested size.
++ * We will receive the DATA interrupt, if the transfer size register value
++ * is zero then repeat the above step for the remaining bytes (if any) and
++ * process the data in the fifo.
++ *
++ * The bus hold flag logic provides support for repeated start.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/export.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_i2c.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++/*
++ * Register Map
++ * Register offsets for the I2C device.
++ */
++#define XI2CPS_CR_OFFSET 0x00 /* Control Register, RW */
++#define XI2CPS_SR_OFFSET 0x04 /* Status Register, RO */
++#define XI2CPS_ADDR_OFFSET 0x08 /* I2C Address Register, RW */
++#define XI2CPS_DATA_OFFSET 0x0C /* I2C Data Register, RW */
++#define XI2CPS_ISR_OFFSET 0x10 /* Interrupt Status Register, RW */
++#define XI2CPS_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */
++#define XI2CPS_SLV_PAUSE_OFFSET 0x18 /* Slave monitor pause Register, RW */
++#define XI2CPS_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */
++#define XI2CPS_IMR_OFFSET 0x20 /* Interrupt Mask Register, RO */
++#define XI2CPS_IER_OFFSET 0x24 /* Interrupt Enable Register, WO */
++#define XI2CPS_IDR_OFFSET 0x28 /* Interrupt Disable Register, WO */
++
++/*
++ * Control Register Bit mask definitions
++ * This register contains various control bits that affect the operation of the
++ * I2C controller.
++ */
++#define XI2CPS_CR_HOLD_BUS_MASK 0x00000010 /* Hold Bus bit */
++#define XI2CPS_CR_RW_MASK 0x00000001 /* Read or Write Master transfer
++ * 0= Transmitter, 1= Receiver */
++#define XI2CPS_CR_CLR_FIFO_MASK 0x00000040 /* 1 = Auto init FIFO to zeroes */
++
++/*
++ * I2C Address Register Bit mask definitions
++ * Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0]
++ * bits. A write access to this register always initiates a transfer if the I2C
++ * is in master mode.
++ */
++#define XI2CPS_ADDR_MASK 0x000003FF /* I2C Address Mask */
++
++/*
++ * I2C Interrupt Registers Bit mask definitions
++ * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
++ * bit definitions.
++ */
++#define XI2CPS_IXR_ALL_INTR_MASK 0x000002FF /* All ISR Mask */
++
++#define XI2CPS_FIFO_DEPTH 16 /* FIFO Depth */
++#define XI2CPS_TIMEOUT (50 * HZ) /* Timeout for bus busy check */
++#define XI2CPS_ENABLED_INTR 0x2EF /* Enabled Interrupts */
++
++#define XI2CPS_DATA_INTR_DEPTH (XI2CPS_FIFO_DEPTH - 2)/* FIFO depth at which
++ * the DATA interrupt
++ * occurs
++ */
++#define XI2CPS_MAX_TRANSFER_SIZE 255 /* Max transfer size */
++#define XI2CPS_TRANSFER_SIZE (XI2CPS_MAX_TRANSFER_SIZE - 3) /* Transfer size
++ in multiples of data interrupt depth */
++
++#define DRIVER_NAME "xi2cps"
++
++#define xi2cps_readreg(offset) __raw_readl(id->membase + offset)
++#define xi2cps_writereg(val, offset) __raw_writel(val, id->membase + offset)
++
++/**
++ * struct xi2cps - I2C device private data structure
++ * @membase: Base address of the I2C device
++ * @adap: I2C adapter instance
++ * @p_msg: Message pointer
++ * @err_status: Error status in Interrupt Status Register
++ * @xfer_done: Transfer complete status
++ * @p_send_buf: Pointer to transmit buffer
++ * @p_recv_buf: Pointer to receive buffer
++ * @suspended: Flag holding the device's PM status
++ * @send_count: Number of bytes still expected to send
++ * @recv_count: Number of bytes still expected to receive
++ * @irq: IRQ number
++ * @cur_timeout: The current timeout value used by the device
++ * @input_clk: Input clock to I2C controller
++ * @i2c_clk: Current I2C frequency
++ * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
++ * @clk: Pointer to struct clk
++ * @clk_rate_change_nb: Notifier block for clock rate changes
++ */
++struct xi2cps {
++ void __iomem *membase;
++ struct i2c_adapter adap;
++ struct i2c_msg *p_msg;
++ int err_status;
++ struct completion xfer_done;
++ unsigned char *p_send_buf;
++ unsigned char *p_recv_buf;
++ u8 suspended;
++ int send_count;
++ int recv_count;
++ int irq;
++ int cur_timeout;
++ unsigned int input_clk;
++ unsigned int i2c_clk;
++ unsigned int bus_hold_flag;
++ struct clk *clk;
++ struct notifier_block clk_rate_change_nb;
++};
++
++#define to_xi2cps(_nb) container_of(_nb, struct xi2cps,\
++ clk_rate_change_nb)
++#define MAX_F_ERR 10000
++
++/**
++ * xi2cps_isr - Interrupt handler for the I2C device
++ * @irq: irq number for the I2C device
++ * @ptr: void pointer to xi2cps structure
++ *
++ * Returns IRQ_HANDLED always
++ *
++ * This function handles the data interrupt, transfer complete interrupt and
++ * the error interrupts of the I2C device.
++ */
++static irqreturn_t xi2cps_isr(int irq, void *ptr)
++{
++ unsigned int isr_status, avail_bytes;
++ unsigned int bytes_to_recv, bytes_to_send;
++ unsigned int ctrl_reg = 0;
++ struct xi2cps *id = ptr;
++
++ isr_status = xi2cps_readreg(XI2CPS_ISR_OFFSET);
++
++ /* Handling Nack interrupt */
++ if (isr_status & 0x00000004)
++ complete(&id->xfer_done);
++
++ /* Handling Arbitration lost interrupt */
++ if (isr_status & 0x00000200)
++ complete(&id->xfer_done);
++
++ /* Handling Data interrupt */
++ if (isr_status & 0x00000002) {
++ if (id->recv_count >= XI2CPS_DATA_INTR_DEPTH) {
++ /* Always read data interrupt threshold bytes */
++ bytes_to_recv = XI2CPS_DATA_INTR_DEPTH;
++ id->recv_count = id->recv_count -
++ XI2CPS_DATA_INTR_DEPTH;
++ avail_bytes = xi2cps_readreg(XI2CPS_XFER_SIZE_OFFSET);
++ /*
++ * if the tranfer size register value is zero, then
++ * check for the remaining bytes and update the
++ * transfer size register.
++ */
++ if (avail_bytes == 0) {
++ if (id->recv_count > XI2CPS_TRANSFER_SIZE)
++ xi2cps_writereg(XI2CPS_TRANSFER_SIZE,
++ XI2CPS_XFER_SIZE_OFFSET);
++ else
++ xi2cps_writereg(id->recv_count,
++ XI2CPS_XFER_SIZE_OFFSET);
++ }
++ /* Process the data received */
++ while (bytes_to_recv) {
++ *(id->p_recv_buf)++ =
++ xi2cps_readreg(XI2CPS_DATA_OFFSET);
++ bytes_to_recv = bytes_to_recv - 1;
++ }
++
++ if ((id->bus_hold_flag == 0) &&
++ (id->recv_count <= XI2CPS_FIFO_DEPTH)) {
++ /* Clear the hold bus bit */
++ xi2cps_writereg(
++ (xi2cps_readreg(XI2CPS_CR_OFFSET) &
++ (~XI2CPS_CR_HOLD_BUS_MASK)),
++ XI2CPS_CR_OFFSET);
++ }
++ }
++ }
++
++ /* Handling Transfer Complete interrupt */
++ if (isr_status & 0x00000001) {
++ if ((id->p_recv_buf) == NULL) {
++ /*
++ * If the device is sending data If there is further
++ * data to be sent. Calculate the available space
++ * in FIFO and fill the FIFO with that many bytes.
++ */
++ if (id->send_count > 0) {
++ avail_bytes = XI2CPS_FIFO_DEPTH -
++ xi2cps_readreg(XI2CPS_XFER_SIZE_OFFSET);
++ if (id->send_count > avail_bytes)
++ bytes_to_send = avail_bytes;
++ else
++ bytes_to_send = id->send_count;
++
++ while (bytes_to_send--) {
++ xi2cps_writereg(
++ (*(id->p_send_buf)++),
++ XI2CPS_DATA_OFFSET);
++ id->send_count--;
++ }
++ } else {
++ /*
++ * Signal the completion of transaction and clear the hold bus
++ * bit if there are no further messages to be processed.
++ */
++ complete(&id->xfer_done);
++ }
++ if (id->send_count == 0) {
++ if (id->bus_hold_flag == 0) {
++ /* Clear the hold bus bit */
++ ctrl_reg =
++ xi2cps_readreg(XI2CPS_CR_OFFSET);
++ if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK)
++ == XI2CPS_CR_HOLD_BUS_MASK)
++ xi2cps_writereg(
++ (ctrl_reg &
++ (~XI2CPS_CR_HOLD_BUS_MASK)),
++ XI2CPS_CR_OFFSET);
++ }
++ }
++ } else {
++ if (id->bus_hold_flag == 0) {
++ /* Clear the hold bus bit */
++ ctrl_reg =
++ xi2cps_readreg(XI2CPS_CR_OFFSET);
++ if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK)
++ == XI2CPS_CR_HOLD_BUS_MASK)
++ xi2cps_writereg(
++ (ctrl_reg &
++ (~XI2CPS_CR_HOLD_BUS_MASK)),
++ XI2CPS_CR_OFFSET);
++ }
++ /*
++ * If the device is receiving data, then signal the completion
++ * of transaction and read the data present in the FIFO.
++ * Signal the completion of transaction.
++ */
++ while (xi2cps_readreg(XI2CPS_SR_OFFSET)
++ & 0x00000020) {
++ *(id->p_recv_buf)++ =
++ xi2cps_readreg(XI2CPS_DATA_OFFSET);
++ id->recv_count--;
++ }
++ complete(&id->xfer_done);
++ }
++ }
++
++ /* Update the status for errors */
++ id->err_status = isr_status & 0x000002EC;
++ xi2cps_writereg(isr_status, XI2CPS_ISR_OFFSET);
++ return IRQ_HANDLED;
++}
++
++/**
++ * xi2cps_mrecv - Prepare and start a master receive operation
++ * @id: pointer to the i2c device structure
++ *
++ */
++static void xi2cps_mrecv(struct xi2cps *id)
++{
++ unsigned int ctrl_reg;
++ unsigned int isr_status;
++
++ id->p_recv_buf = id->p_msg->buf;
++ id->recv_count = id->p_msg->len;
++
++ /*
++ * Set the controller in master receive mode and clear the FIFO.
++ * Set the slave address in address register.
++ * Check for the message size against FIFO depth and set the
++ * HOLD bus bit if it is more than FIFO depth.
++ * Clear the interrupts in interrupt status register.
++ */
++ ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET);
++ ctrl_reg |= (XI2CPS_CR_RW_MASK | XI2CPS_CR_CLR_FIFO_MASK);
++
++ if ((id->p_msg->flags & I2C_M_RECV_LEN) == I2C_M_RECV_LEN)
++ id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
++
++ if (id->recv_count > XI2CPS_FIFO_DEPTH)
++ ctrl_reg |= XI2CPS_CR_HOLD_BUS_MASK;
++
++ xi2cps_writereg(ctrl_reg, XI2CPS_CR_OFFSET);
++
++ isr_status = xi2cps_readreg(XI2CPS_ISR_OFFSET);
++ xi2cps_writereg(isr_status, XI2CPS_ISR_OFFSET);
++
++ xi2cps_writereg((id->p_msg->addr & XI2CPS_ADDR_MASK),
++ XI2CPS_ADDR_OFFSET);
++ /*
++ * The no. of bytes to receive is checked against the limit of
++ * max transfer size. Set transfer size register with no of bytes
++ * receive if it is less than transfer size and transfer size if
++ * it is more. Enable the interrupts.
++ */
++ if (id->recv_count > XI2CPS_TRANSFER_SIZE)
++ xi2cps_writereg(XI2CPS_TRANSFER_SIZE, XI2CPS_XFER_SIZE_OFFSET);
++ else
++ xi2cps_writereg(id->recv_count, XI2CPS_XFER_SIZE_OFFSET);
++ /*
++ * Clear the bus hold flag if bytes to receive is less than FIFO size.
++ */
++ if (id->bus_hold_flag == 0 &&
++ ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
++ (id->recv_count <= XI2CPS_FIFO_DEPTH)) {
++ /* Clear the hold bus bit */
++ ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET);
++ if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK) ==
++ XI2CPS_CR_HOLD_BUS_MASK)
++ xi2cps_writereg(
++ (ctrl_reg & (~XI2CPS_CR_HOLD_BUS_MASK)),
++ XI2CPS_CR_OFFSET);
++ }
++ xi2cps_writereg(XI2CPS_ENABLED_INTR, XI2CPS_IER_OFFSET);
++}
++
++/**
++ * xi2cps_msend - Prepare and start a master send operation
++ * @id: pointer to the i2c device
++ *
++ */
++static void xi2cps_msend(struct xi2cps *id)
++{
++ unsigned int avail_bytes;
++ unsigned int bytes_to_send;
++ unsigned int ctrl_reg;
++ unsigned int isr_status;
++
++ id->p_recv_buf = NULL;
++ id->p_send_buf = id->p_msg->buf;
++ id->send_count = id->p_msg->len;
++
++ /*
++ * Set the controller in Master transmit mode and clear the FIFO.
++ * Set the slave address in address register.
++ * Check for the message size against FIFO depth and set the
++ * HOLD bus bit if it is more than FIFO depth.
++ * Clear the interrupts in interrupt status register.
++ */
++ ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET);
++ ctrl_reg &= ~XI2CPS_CR_RW_MASK;
++ ctrl_reg |= XI2CPS_CR_CLR_FIFO_MASK;
++
++ if ((id->send_count) > XI2CPS_FIFO_DEPTH)
++ ctrl_reg |= XI2CPS_CR_HOLD_BUS_MASK;
++ xi2cps_writereg(ctrl_reg, XI2CPS_CR_OFFSET);
++
++ isr_status = xi2cps_readreg(XI2CPS_ISR_OFFSET);
++ xi2cps_writereg(isr_status, XI2CPS_ISR_OFFSET);
++
++ /*
++ * Calculate the space available in FIFO. Check the message length
++ * against the space available, and fill the FIFO accordingly.
++ * Enable the interrupts.
++ */
++ avail_bytes = XI2CPS_FIFO_DEPTH -
++ xi2cps_readreg(XI2CPS_XFER_SIZE_OFFSET);
++
++ if (id->send_count > avail_bytes)
++ bytes_to_send = avail_bytes;
++ else
++ bytes_to_send = id->send_count;
++
++ while (bytes_to_send--) {
++ xi2cps_writereg((*(id->p_send_buf)++), XI2CPS_DATA_OFFSET);
++ id->send_count--;
++ }
++
++ xi2cps_writereg((id->p_msg->addr & XI2CPS_ADDR_MASK),
++ XI2CPS_ADDR_OFFSET);
++
++ /*
++ * Clear the bus hold flag if there is no more data
++ * and if it is the last message.
++ */
++ if (id->bus_hold_flag == 0 && id->send_count == 0) {
++ /* Clear the hold bus bit */
++ ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET);
++ if ((ctrl_reg & XI2CPS_CR_HOLD_BUS_MASK) ==
++ XI2CPS_CR_HOLD_BUS_MASK)
++ xi2cps_writereg(
++ (ctrl_reg & (~XI2CPS_CR_HOLD_BUS_MASK)),
++ XI2CPS_CR_OFFSET);
++ }
++ xi2cps_writereg(XI2CPS_ENABLED_INTR, XI2CPS_IER_OFFSET);
++}
++
++/**
++ * xi2cps_master_reset - Reset the interface
++ * @adap: pointer to the i2c adapter driver instance
++ *
++ * Returns none
++ *
++ * This function cleanup the fifos, clear the hold bit and status
++ * and disable the interrupts.
++ */
++static void xi2cps_master_reset(struct i2c_adapter *adap)
++{
++ struct xi2cps *id = adap->algo_data;
++ u32 regval;
++
++ /* Disable the interrupts */
++ xi2cps_writereg(XI2CPS_IXR_ALL_INTR_MASK, XI2CPS_IDR_OFFSET);
++ /* Clear the hold bit and fifos */
++ regval = xi2cps_readreg(XI2CPS_CR_OFFSET);
++ regval &= ~XI2CPS_CR_HOLD_BUS_MASK;
++ regval |= XI2CPS_CR_CLR_FIFO_MASK;
++ xi2cps_writereg(regval, XI2CPS_CR_OFFSET);
++ /* Update the transfercount register to zero */
++ xi2cps_writereg(0x0, XI2CPS_XFER_SIZE_OFFSET);
++ /* Clear the interupt status register */
++ regval = xi2cps_readreg(XI2CPS_ISR_OFFSET);
++ xi2cps_writereg(regval, XI2CPS_ISR_OFFSET);
++ /* Clear the status register */
++ regval = xi2cps_readreg(XI2CPS_SR_OFFSET);
++ xi2cps_writereg(regval, XI2CPS_SR_OFFSET);
++}
++
++/**
++ * xi2cps_master_xfer - The main i2c transfer function
++ * @adap: pointer to the i2c adapter driver instance
++ * @msgs: pointer to the i2c message structure
++ * @num: the number of messages to transfer
++ *
++ * Returns number of msgs processed on success, negative error otherwise
++ *
++ * This function waits for the bus idle condition and updates the timeout if
++ * modified by user. Then initiates the send/recv activity based on the
++ * transfer message received.
++ */
++static int xi2cps_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++ int num)
++{
++ struct xi2cps *id = adap->algo_data;
++ unsigned int count, retries;
++ unsigned long timeout;
++ int ret;
++
++ /* Waiting for bus-ready. If bus not ready, it returns after timeout */
++ timeout = jiffies + XI2CPS_TIMEOUT;
++ while ((xi2cps_readreg(XI2CPS_SR_OFFSET)) & 0x00000100) {
++ if (time_after(jiffies, timeout)) {
++ dev_warn(id->adap.dev.parent,
++ "timedout waiting for bus ready\n");
++ xi2cps_master_reset(adap);
++ return -ETIMEDOUT;
++ }
++ schedule_timeout(1);
++ }
++
++
++ /* The bus is free. Set the new timeout value if updated */
++ if (id->adap.timeout != id->cur_timeout) {
++ xi2cps_writereg((id->adap.timeout & 0xFF),
++ XI2CPS_TIME_OUT_OFFSET);
++ id->cur_timeout = id->adap.timeout;
++ }
++
++ /*
++ * Set the flag to one when multiple messages are to be
++ * processed with a repeated start.
++ */
++ if (num > 1) {
++ id->bus_hold_flag = 1;
++ xi2cps_writereg((xi2cps_readreg(XI2CPS_CR_OFFSET) |
++ XI2CPS_CR_HOLD_BUS_MASK), XI2CPS_CR_OFFSET);
++ } else {
++ id->bus_hold_flag = 0;
++ }
++
++ /* Process the msg one by one */
++ for (count = 0; count < num; count++, msgs++) {
++
++ if (count == (num - 1))
++ id->bus_hold_flag = 0;
++ retries = adap->retries;
++retry:
++ id->err_status = 0;
++ id->p_msg = msgs;
++ init_completion(&id->xfer_done);
++
++ /* Check for the TEN Bit mode on each msg */
++ if (msgs->flags & I2C_M_TEN) {
++ xi2cps_writereg((xi2cps_readreg(XI2CPS_CR_OFFSET) &
++ (~0x00000004)), XI2CPS_CR_OFFSET);
++ } else {
++ if ((xi2cps_readreg(XI2CPS_CR_OFFSET) & 0x00000004)
++ == 0)
++ xi2cps_writereg(
++ (xi2cps_readreg(XI2CPS_CR_OFFSET) |
++ (0x00000004)), XI2CPS_CR_OFFSET);
++ }
++
++ /* Check for the R/W flag on each msg */
++ if (msgs->flags & I2C_M_RD)
++ xi2cps_mrecv(id);
++ else
++ xi2cps_msend(id);
++
++ /* Wait for the signal of completion */
++ ret = wait_for_completion_interruptible_timeout(
++ &id->xfer_done, HZ);
++ if (ret == 0) {
++ dev_err(id->adap.dev.parent,
++ "timeout waiting on completion\n");
++ xi2cps_master_reset(adap);
++ return -ETIMEDOUT;
++ }
++ xi2cps_writereg(XI2CPS_IXR_ALL_INTR_MASK, XI2CPS_IDR_OFFSET);
++
++ /* If it is bus arbitration error, try again */
++ if (id->err_status & 0x00000200) {
++ dev_dbg(id->adap.dev.parent,
++ "Lost ownership on bus, trying again\n");
++ if (retries--) {
++ mdelay(2);
++ goto retry;
++ }
++ dev_err(id->adap.dev.parent,
++ "Retries completed, exit\n");
++ num = -EREMOTEIO;
++ break;
++ }
++ /* Report the other error interrupts to application as EIO */
++ if (id->err_status & 0x000000E4) {
++ xi2cps_master_reset(adap);
++ num = -EIO;
++ break;
++ }
++ }
++
++ id->p_msg = NULL;
++ id->err_status = 0;
++
++ return num;
++}
++
++/**
++ * xi2cps_func - Returns the supported features of the I2C driver
++ * @adap: pointer to the i2c adapter structure
++ *
++ * Returns 32 bit value, each bit corresponding to a feature
++ */
++static u32 xi2cps_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
++ (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
++ I2C_FUNC_SMBUS_BLOCK_DATA;
++}
++
++static const struct i2c_algorithm xi2cps_algo = {
++ .master_xfer = xi2cps_master_xfer,
++ .functionality = xi2cps_func,
++};
++
++/**
++ * xi2cps_calc_divs() - Calculate clock dividers
++ * @f: I2C clock frequency
++ * @input_clk: Input clock frequency
++ * @a: First divider (return value)
++ * @b: Second divider (return value)
++ * @err: Frequency error
++ * Return 0 on success, negative errno otherwise.
++ *
++ * f is used as input and output variable. As input it is used as target I2C
++ * frequency. On function exit f holds the actually resulting I2C frequency.
++ */
++static int xi2cps_calc_divs(unsigned int *f, unsigned int input_clk,
++ unsigned int *a, unsigned int *b, unsigned int *err)
++{
++ unsigned int fscl = *f;
++ unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
++ unsigned int last_error, current_error;
++ unsigned int best_fscl = *f, actual_fscl, temp;
++
++ /* calculate (divisor_a+1) x (divisor_b+1) */
++ temp = input_clk / (22 * fscl);
++
++ /*
++ * If the calculated value is negative or 0, the fscl input is out of
++ * range. Return error.
++ */
++ if (!temp)
++ return -EINVAL;
++
++ last_error = -1;
++ for (div_b = 0; div_b < 64; div_b++) {
++ div_a = input_clk / (22 * fscl * (div_b + 1));
++
++ if (div_a != 0)
++ div_a = div_a - 1;
++
++ if (div_a > 3)
++ continue;
++
++ actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
++
++ current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
++ (fscl - actual_fscl));
++
++ if (last_error > current_error) {
++ calc_div_a = div_a;
++ calc_div_b = div_b;
++ best_fscl = actual_fscl;
++ last_error = current_error;
++ }
++ }
++
++ *err = last_error;
++ *a = calc_div_a;
++ *b = calc_div_b;
++ *f = best_fscl;
++
++ return 0;
++}
++
++/**
++ * xi2cps_setclk - This function sets the serial clock rate for the I2C device
++ * @fscl: The clock frequency in Hz
++ * @id: Pointer to the I2C device structure
++ *
++ * Returns zero on success, negative error otherwise
++ *
++ * The device must be idle rather than busy transferring data before setting
++ * these device options.
++ * The data rate is set by values in the control register.
++ * The formula for determining the correct register values is
++ * Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
++ * See the hardware data sheet for a full explanation of setting the serial
++ * clock rate. The clock can not be faster than the input clock divide by 22.
++ * The two most common clock rates are 100KHz and 400KHz.
++ */
++static int xi2cps_setclk(unsigned int fscl, struct xi2cps *id)
++{
++ unsigned int div_a, div_b;
++ unsigned int ctrl_reg;
++ unsigned int err;
++ int ret = 0;
++
++ ret = xi2cps_calc_divs(&fscl, id->input_clk, &div_a, &div_b, &err);
++ if (ret)
++ return ret;
++
++ ctrl_reg = xi2cps_readreg(XI2CPS_CR_OFFSET);
++ ctrl_reg &= ~(0x0000C000 | 0x00003F00);
++ ctrl_reg |= ((div_a << 14) | (div_b << 8));
++ xi2cps_writereg(ctrl_reg, XI2CPS_CR_OFFSET);
++
++ return 0;
++}
++
++/**
++ * xi2cps_clk_notifier_cb - Clock rate change callback
++ * @nb: Pointer to notifier block
++ * @event: Notification reason
++ * @data: Pointer to notification data object
++ * Returns NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
++ * otherwise.
++ *
++ * This function is called when the xi2cps input clock frequency changes. In the
++ * pre-rate change notification here it is determined if the rate change may be
++ * allowed or not.
++ * In th post-change case necessary adjustments are conducted.
++ */
++static int xi2cps_clk_notifier_cb(struct notifier_block *nb, unsigned long
++ event, void *data)
++{
++ struct clk_notifier_data *ndata = data;
++ struct xi2cps *id = to_xi2cps(nb);
++
++ if (id->suspended)
++ return NOTIFY_OK;
++
++ switch (event) {
++ case PRE_RATE_CHANGE:
++ {
++ /*
++ * if a rate change is announced we need to check whether we can
++ * maintain the current frequency by changing the clock
++ * dividers. Probably we could also define an acceptable
++ * frequency range.
++ */
++ unsigned int input_clk = (unsigned int)ndata->new_rate;
++ unsigned int fscl = id->i2c_clk;
++ unsigned int div_a, div_b;
++ unsigned int err = 0;
++ int ret;
++
++ ret = xi2cps_calc_divs(&fscl, input_clk, &div_a, &div_b, &err);
++ if (ret)
++ return NOTIFY_STOP;
++ if (err > MAX_F_ERR)
++ return NOTIFY_STOP;
++
++ return NOTIFY_OK;
++ }
++ case POST_RATE_CHANGE:
++ id->input_clk = ndata->new_rate;
++ /* We probably need to stop the HW before this and restart
++ * afterwards */
++ xi2cps_setclk(id->i2c_clk, id);
++ return NOTIFY_OK;
++ case ABORT_RATE_CHANGE:
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
++#ifdef CONFIG_PM_SLEEP
++/**
++ * xi2cps_suspend - Suspend method for the driver
++ * @_dev: Address of the platform_device structure
++ * Returns 0 on success and error value on error
++ *
++ * Put the driver into low power mode.
++ */
++static int xi2cps_suspend(struct device *_dev)
++{
++ struct platform_device *pdev = container_of(_dev,
++ struct platform_device, dev);
++ struct xi2cps *xi2c = platform_get_drvdata(pdev);
++
++ clk_disable(xi2c->clk);
++ xi2c->suspended = 1;
++
++ return 0;
++}
++
++/**
++ * xi2cps_resume - Resume from suspend
++ * @_dev: Address of the platform_device structure
++ * Returns 0 on success and error value on error
++ *
++ * Resume operation after suspend.
++ */
++static int xi2cps_resume(struct device *_dev)
++{
++ struct platform_device *pdev = container_of(_dev,
++ struct platform_device, dev);
++ struct xi2cps *xi2c = platform_get_drvdata(pdev);
++ int ret;
++
++ ret = clk_enable(xi2c->clk);
++ if (ret) {
++ dev_err(_dev, "Cannot enable clock.\n");
++ return ret;
++ }
++
++ xi2c->suspended = 0;
++
++ return 0;
++}
++
++static const struct dev_pm_ops xi2cps_dev_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(xi2cps_suspend, xi2cps_resume)
++};
++#define XI2CPS_PM (&xi2cps_dev_pm_ops)
++
++#else /* ! CONFIG_PM_SLEEP */
++#define XI2CPS_PM NULL
++#endif /* ! CONFIG_PM_SLEEP */
++
++/************************/
++/* Platform bus binding */
++/************************/
++
++/**
++ * xi2cps_probe - Platform registration call
++ * @pdev: Handle to the platform device structure
++ *
++ * Returns zero on success, negative error otherwise
++ *
++ * This function does all the memory allocation and registration for the i2c
++ * device. User can modify the address mode to 10 bit address mode using the
++ * ioctl call with option I2C_TENBIT.
++ */
++static int xi2cps_probe(struct platform_device *pdev)
++{
++ struct resource *r_mem = NULL;
++ struct xi2cps *id;
++ int ret = 0;
++ const unsigned int *prop;
++ /*
++ * Allocate memory for xi2cps structure.
++ * Initialize the structure to zero and set the platform data.
++ * Obtain the resource base address from platform data and remap it.
++ * Get the irq resource from platform data.Initialize the adapter
++ * structure members and also xi2cps structure.
++ */
++ id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
++ if (!id)
++ return -ENOMEM;
++
++ platform_set_drvdata(pdev, id);
++
++ r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
++ if (IS_ERR(id->membase)) {
++ dev_err(&pdev->dev, "ioremap failed\n");
++ return PTR_ERR(id->membase);
++ }
++
++ id->irq = platform_get_irq(pdev, 0);
++
++ prop = of_get_property(pdev->dev.of_node, "bus-id", NULL);
++ if (prop) {
++ id->adap.nr = be32_to_cpup(prop);
++ } else {
++ dev_err(&pdev->dev, "couldn't determine bus-id\n");
++ return -ENXIO;
++ }
++ id->adap.dev.of_node = pdev->dev.of_node;
++ id->adap.algo = (struct i2c_algorithm *) &xi2cps_algo;
++ id->adap.timeout = 0x1F; /* Default timeout value */
++ id->adap.retries = 3; /* Default retry value. */
++ id->adap.algo_data = id;
++ id->adap.dev.parent = &pdev->dev;
++ snprintf(id->adap.name, sizeof(id->adap.name),
++ "XILINX I2C at %08lx", (unsigned long)r_mem->start);
++
++ id->cur_timeout = id->adap.timeout;
++ id->clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(id->clk)) {
++ dev_err(&pdev->dev, "input clock not found.\n");
++ return PTR_ERR(id->clk);
++ }
++ ret = clk_prepare_enable(id->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable clock.\n");
++ return ret;
++ }
++ id->clk_rate_change_nb.notifier_call = xi2cps_clk_notifier_cb;
++ id->clk_rate_change_nb.next = NULL;
++ if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
++ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
++ id->input_clk = (unsigned int)clk_get_rate(id->clk);
++
++ prop = of_get_property(pdev->dev.of_node, "i2c-clk", NULL);
++ if (prop) {
++ id->i2c_clk = be32_to_cpup(prop);
++ } else {
++ ret = -ENXIO;
++ dev_err(&pdev->dev, "couldn't determine i2c-clk\n");
++ goto err_clk_dis;
++ }
++
++ /*
++ * Set Master Mode,Normal addressing mode (7 bit address),
++ * Enable Transmission of Ack in Control Register.
++ * Set the timeout and I2C clock and request the IRQ(ISR mapped).
++ * Call to the i2c_add_numbered_adapter registers the adapter.
++ */
++ xi2cps_writereg(0x0000000E, XI2CPS_CR_OFFSET);
++ xi2cps_writereg(id->adap.timeout, XI2CPS_TIME_OUT_OFFSET);
++
++ ret = xi2cps_setclk(id->i2c_clk, id);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n", id->i2c_clk);
++ ret = -EINVAL;
++ goto err_clk_dis;
++ }
++
++ ret = devm_request_irq(&pdev->dev, id->irq, xi2cps_isr, 0,
++ DRIVER_NAME, id);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
++ goto err_clk_dis;
++ }
++
++ ret = i2c_add_numbered_adapter(&id->adap);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
++ goto err_clk_dis;
++ }
++
++ of_i2c_register_devices(&id->adap);
++
++ dev_info(&pdev->dev, "%d kHz mmio %08lx irq %d\n",
++ id->i2c_clk/1000, (unsigned long)r_mem->start, id->irq);
++
++ return 0;
++
++err_clk_dis:
++ clk_disable_unprepare(id->clk);
++ return ret;
++}
++
++/**
++ * xi2cps_remove - Unregister the device after releasing the resources
++ * @pdev: Handle to the platform device structure
++ *
++ * Returns zero always
++ *
++ * This function frees all the resources allocated to the device.
++ */
++static int xi2cps_remove(struct platform_device *pdev)
++{
++ struct xi2cps *id = platform_get_drvdata(pdev);
++
++ i2c_del_adapter(&id->adap);
++ clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
++ clk_disable_unprepare(id->clk);
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++static const struct of_device_id xi2cps_of_match[] = {
++ { .compatible = "xlnx,ps7-i2c-1.00.a", },
++ { /* end of table */}
++};
++MODULE_DEVICE_TABLE(of, xi2cps_of_match);
++
++static struct platform_driver xi2cps_drv = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = xi2cps_of_match,
++ .pm = XI2CPS_PM,
++ },
++ .probe = xi2cps_probe,
++ .remove = xi2cps_remove,
++};
++
++module_platform_driver(xi2cps_drv);
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_DESCRIPTION("Xilinx PS I2C bus driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/patches.zynq/0002-i2c-si570-merge-support-for-si570-clock-generator.patch b/patches.zynq/0002-i2c-si570-merge-support-for-si570-clock-generator.patch
new file mode 100644
index 00000000000000..19e78b8951e2c9
--- /dev/null
+++ b/patches.zynq/0002-i2c-si570-merge-support-for-si570-clock-generator.patch
@@ -0,0 +1,662 @@
+From 2fd63c1e6eab20cbaa637da81fcf988b23f91d66 Mon Sep 17 00:00:00 2001
+From: Rob Armstrong <ra@xilinx.com>
+Date: Tue, 24 Dec 2013 09:31:54 +0900
+Subject: i2c: si570: merge support for si570 clock generator
+
+This merges support for the si5790 clock generator from the Xilinx
+repository (commit efc27505715e64526653f35274717c0fc56491e3 from
+master branch).
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/misc/Kconfig | 10
+ drivers/misc/Makefile | 1
+ drivers/misc/si570.c | 576 ++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/i2c/si570.h | 31 ++
+ 4 files changed, 618 insertions(+)
+ create mode 100644 drivers/misc/si570.c
+ create mode 100644 include/linux/i2c/si570.h
+
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -507,6 +507,16 @@ config USB_SWITCH_FSA9480
+ stereo and mono audio, video, microphone and UART data to use
+ a common connector port.
+
++config SI570
++ tristate "Silicon Labs Si570 Clock Generator"
++ depends on I2C && SYSFS
++ help
++ If you say yes here you get support for the Silicon Labs Si570
++ digital clock generator.
++
++ To compile this driver as a module, choose M here: the module
++ will be called si570
++
+ config LATTICE_ECP3_CONFIG
+ tristate "Lattice ECP3 FPGA bitstream configuration via SPI"
+ depends on SPI && SYSFS
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -50,6 +50,7 @@ obj-y += carma/
+ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
+ obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
+ obj-$(CONFIG_INTEL_MEI) += mei/
++obj-$(CONFIG_SI570) += si570.o
+ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
+ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
+ obj-$(CONFIG_SRAM) += sram.o
+--- /dev/null
++++ b/drivers/misc/si570.c
+@@ -0,0 +1,576 @@
++/*
++ * Driver for Silicon Labs Si570/Si571 Programmable XO/VCXO
++ *
++ * Copyright (C) 2010, 2011 Ericsson AB.
++ * Copyright (C) 2011 Guenter Roeck.
++ *
++ * Author: Guenter Roeck <guenter.roeck@ericsson.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/jiffies.h>
++#include <linux/i2c.h>
++#include <linux/err.h>
++#include <linux/mutex.h>
++#include <linux/delay.h>
++#include <linux/log2.h>
++#include <linux/slab.h>
++#include <linux/of_i2c.h>
++#include <linux/i2c/si570.h>
++
++/* Si570 registers */
++#define SI570_REG_HS_N1 7
++#define SI570_REG_N1_RFREQ0 8
++#define SI570_REG_RFREQ1 9
++#define SI570_REG_RFREQ2 10
++#define SI570_REG_RFREQ3 11
++#define SI570_REG_RFREQ4 12
++#define SI570_REG_CONTROL 135
++#define SI570_REG_FREEZE_DCO 137
++
++#define HS_DIV_SHIFT 5
++#define HS_DIV_MASK 0xe0
++#define HS_DIV_OFFSET 4
++#define N1_6_2_MASK 0x1f
++#define N1_1_0_MASK 0xc0
++#define RFREQ_37_32_MASK 0x3f
++
++#define SI570_FOUT_FACTORY_DFLT 156250000LL
++#define SI598_FOUT_FACTORY_DFLT 10000000LL
++
++#define SI570_MIN_FREQ 10000000L
++#define SI570_MAX_FREQ 1417500000L
++#define SI598_MAX_FREQ 525000000L
++
++#define FDCO_MIN 4850000000LL
++#define FDCO_MAX 5670000000LL
++#define FDCO_CENTER ((FDCO_MIN + FDCO_MAX) / 2)
++
++#define SI570_CNTRL_RECALL (1 << 0)
++#define SI570_CNTRL_FREEZE_ADC (1 << 4)
++#define SI570_CNTRL_FREEZE_M (1 << 5)
++#define SI570_CNTRL_NEWFREQ (1 << 6)
++#define SI570_CNTRL_RESET (1 << 7)
++
++#define SI570_FREEZE_DCO (1 << 4)
++#define SI570_UNFREEZE_DCO 0xEF
++
++struct si570_data {
++ struct attribute_group attrs;
++ struct mutex lock;
++ u64 max_freq;
++ u64 fout; /* Factory default frequency */
++ u64 fxtal; /* Factory xtal frequency */
++ unsigned int n1;
++ unsigned int hs_div;
++ u64 rfreq;
++ u64 frequency;
++};
++
++
++static struct i2c_client *si570_client;
++
++
++static int si570_get_defaults(struct i2c_client *client)
++{
++ struct si570_data *data = i2c_get_clientdata(client);
++ int reg1, reg2, reg3, reg4, reg5, reg6;
++ u64 fdco;
++
++ i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
++ SI570_CNTRL_RECALL);
++
++ reg1 = i2c_smbus_read_byte_data(client, SI570_REG_HS_N1);
++ if (reg1 < 0)
++ return reg1;
++ reg2 = i2c_smbus_read_byte_data(client, SI570_REG_N1_RFREQ0);
++ if (reg2 < 0)
++ return reg2;
++ reg3 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ1);
++ if (reg3 < 0)
++ return reg3;
++ reg4 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ2);
++ if (reg4 < 0)
++ return reg4;
++ reg5 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ3);
++ if (reg5 < 0)
++ return reg5;
++ reg6 = i2c_smbus_read_byte_data(client, SI570_REG_RFREQ4);
++ if (reg6 < 0)
++ return reg6;
++
++ data->hs_div = ((reg1 & HS_DIV_MASK) >> HS_DIV_SHIFT) + HS_DIV_OFFSET;
++ data->n1 = ((reg1 & N1_6_2_MASK) << 2) + ((reg2 & N1_1_0_MASK) >> 6)
++ + 1;
++ /* Handle invalid cases */
++ if (data->n1 > 1)
++ data->n1 &= ~1;
++
++ data->rfreq = reg2 & RFREQ_37_32_MASK;
++ data->rfreq = (data->rfreq << 8) + reg3;
++ data->rfreq = (data->rfreq << 8) + reg4;
++ data->rfreq = (data->rfreq << 8) + reg5;
++ data->rfreq = (data->rfreq << 8) + reg6;
++
++ /*
++ * Accept optional precision loss to avoid arithmetic overflows.
++ * Acceptable per Silicon Labs Application Note AN334.
++ */
++ fdco = data->fout * data->n1 * data->hs_div;
++ if (fdco >= (1LL << 36))
++ data->fxtal = div64_u64((fdco << 24), (data->rfreq >> 4));
++ else
++ data->fxtal = div64_u64((fdco << 28), data->rfreq);
++
++ data->frequency = data->fout;
++
++ return 0;
++}
++
++/*
++ * Update rfreq registers
++ * This function must be called with update mutex lock held.
++ */
++static void si570_update_rfreq(struct i2c_client *client,
++ struct si570_data *data)
++{
++ int status;
++ status = i2c_smbus_write_byte_data(client, SI570_REG_N1_RFREQ0,
++ ((data->n1 - 1) << 6)
++ | ((data->rfreq >> 32) & RFREQ_37_32_MASK));
++ if (status < 0)
++ dev_err(&client->dev,
++ "unable to write 0x%llX to REG_N1_RFREQ0: %d\n",
++ (((data->n1 - 1) << 6) | ((data->rfreq >> 32) &
++ RFREQ_37_32_MASK)) & 0xff, status);
++ status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ1,
++ (data->rfreq >> 24) & 0xff);
++ if (status < 0)
++ dev_err(&client->dev,
++ "unable to write 0x%llX to REG_RFREQ1: %d\n",
++ (data->rfreq >> 24) & 0xff, status);
++ status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ2,
++ (data->rfreq >> 16) & 0xff);
++ if (status < 0)
++ dev_err(&client->dev,
++ "unable to write 0x%llX to REG_RFREQ2: %d\n",
++ (data->rfreq >> 16) & 0xff, status);
++ status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ3,
++ (data->rfreq >> 8) & 0xff);
++ if (status < 0)
++ dev_err(&client->dev,
++ "unable to write 0x%llX to REG_RFREQ3: %d\n",
++ (data->rfreq >> 8) & 0xff, status);
++ status = i2c_smbus_write_byte_data(client, SI570_REG_RFREQ4,
++ data->rfreq & 0xff);
++ if (status < 0)
++ dev_err(&client->dev,
++ "unable to write 0x%llX to REG_RFREQ4: %d\n",
++ data->rfreq & 0xff, status);
++}
++
++/*
++ * Update si570 frequency for small frequency changes (< 3,500 ppm)
++ * This function must be called with update mutex lock held.
++ */
++static int si570_set_frequency_small(struct i2c_client *client,
++ struct si570_data *data,
++ unsigned long frequency)
++{
++ data->frequency = frequency;
++ /* This is a re-implementation of DIV_ROUND_CLOSEST
++ * using the div64_u64 function lieu of letting the compiler
++ * insert EABI calls
++ */
++ data->rfreq = div64_u64((data->rfreq * frequency) +
++ div64_u64(data->frequency, 2), data->frequency);
++ i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
++ SI570_CNTRL_FREEZE_M);
++ si570_update_rfreq(client, data);
++ i2c_smbus_write_byte_data(client, SI570_REG_CONTROL, 0);
++
++ return 0;
++}
++
++static const uint8_t si570_hs_div_values[] = { 11, 9, 7, 6, 5, 4 };
++
++/*
++ * Set si570 frequency.
++ * This function must be called with update mutex lock held.
++ */
++static int si570_set_frequency(struct i2c_client *client,
++ struct si570_data *data,
++ unsigned long frequency)
++{
++ int i, n1, hs_div;
++ u64 fdco, best_fdco = ULLONG_MAX;
++
++ for (i = 0; i < ARRAY_SIZE(si570_hs_div_values); i++) {
++ hs_div = si570_hs_div_values[i];
++ /* Calculate lowest possible value for n1 */
++ n1 = div64_u64(div64_u64(FDCO_MIN, (u64)hs_div),
++ (u64)frequency);
++ if (!n1 || (n1 & 1))
++ n1++;
++ while (n1 <= 128) {
++ fdco = (u64)frequency * (u64)hs_div * (u64)n1;
++ if (fdco > FDCO_MAX)
++ break;
++ if (fdco >= FDCO_MIN && fdco < best_fdco) {
++ data->n1 = n1;
++ data->hs_div = hs_div;
++ data->frequency = frequency;
++ data->rfreq = div64_u64((fdco << 28),
++ data->fxtal);
++ best_fdco = fdco;
++ }
++ n1 += (n1 == 1 ? 1 : 2);
++ }
++ }
++ if (best_fdco == ULLONG_MAX) {
++ dev_err(&client->dev, "error - best FDCO is out of range\n");
++ return -EINVAL;
++ }
++
++ /* The DCO reg should be accessed with a read-modify-write operation
++ * per AN334
++ */
++ i2c_smbus_write_byte_data(client, SI570_REG_FREEZE_DCO,
++ SI570_FREEZE_DCO);
++ i2c_smbus_write_byte_data(client, SI570_REG_HS_N1,
++ ((data->hs_div - HS_DIV_OFFSET) <<
++ HS_DIV_SHIFT)
++ | (((data->n1 - 1) >> 2) & N1_6_2_MASK));
++ si570_update_rfreq(client, data);
++ i2c_smbus_write_byte_data(client, SI570_REG_FREEZE_DCO,
++ 0);
++ i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
++ SI570_CNTRL_NEWFREQ);
++ return 0;
++}
++
++/*
++ * Reset chip.
++ * This function must be called with update mutex lock held.
++ */
++static int si570_reset(struct i2c_client *client, struct si570_data *data)
++{
++ i2c_smbus_write_byte_data(client, SI570_REG_CONTROL,
++ SI570_CNTRL_RESET);
++ usleep_range(1000, 5000);
++ return si570_set_frequency(client, data, data->frequency);
++}
++
++static ssize_t show_frequency_attr(struct device *dev,
++ struct device_attribute *devattr,
++ char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct si570_data *data = i2c_get_clientdata(client);
++
++ return sprintf(buf, "%llu\n", data->frequency);
++}
++
++int get_frequency_si570(struct device *dev, unsigned long *freq)
++{
++ int err;
++ char buf[10+1];
++
++ if ((!dev) || (to_i2c_client(dev) != si570_client))
++ return -EINVAL;
++
++ show_frequency_attr(dev, NULL, buf);
++
++ err = kstrtoul(buf, 10, freq);
++ if (err)
++ return err;
++
++ return 0;
++}
++EXPORT_SYMBOL(get_frequency_si570);
++
++static ssize_t set_frequency_attr(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct si570_data *data = i2c_get_clientdata(client);
++ unsigned long val;
++ int err;
++
++ err = kstrtoul(buf, 10, &val);
++ if (err)
++ return err;
++
++ if (val < SI570_MIN_FREQ || val > data->max_freq) {
++ dev_err(&client->dev,
++ "requested frequency %lu Hz is out of range\n", val);
++ return -EINVAL;
++ }
++
++ mutex_lock(&data->lock);
++
++ if (div64_u64(abs(val - data->frequency) * 10000LL,
++ data->frequency) < 35)
++ err = si570_set_frequency_small(client, data, val);
++ else
++ err = si570_set_frequency(client, data, val);
++ mutex_unlock(&data->lock);
++ if (err) {
++ dev_warn(&client->dev,
++ "unable to set output frequency %lu Hz: %d\n",
++ val, err);
++ return err;
++ }
++
++ dev_info(&client->dev,
++ "set new output frequency %lu Hz\n", val);
++
++ return count;
++}
++
++int set_frequency_si570(struct device *dev, unsigned long freq)
++{
++ char buf[10+1];
++
++ if ((!dev) || (to_i2c_client(dev) != si570_client))
++ return -EINVAL;
++
++ sprintf(buf, "%lu", freq);
++
++ return set_frequency_attr(dev, NULL, buf, 0);
++}
++EXPORT_SYMBOL(set_frequency_si570);
++
++static ssize_t show_reset_attr(struct device *dev,
++ struct device_attribute *devattr,
++ char *buf)
++{
++ return sprintf(buf, "%d\n", 0);
++}
++
++static ssize_t set_reset_attr(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct si570_data *data = i2c_get_clientdata(client);
++ unsigned long val;
++ int err;
++
++ err = kstrtoul(buf, 10, &val);
++ if (err)
++ return err;
++ if (val == 0)
++ goto done;
++
++ mutex_lock(&data->lock);
++ err = si570_reset(client, data);
++ mutex_unlock(&data->lock);
++ if (err)
++ return err;
++done:
++ return count;
++}
++
++int reset_si570(struct device *dev, int id)
++{
++ char buf[4];
++
++ if ((!dev) || (to_i2c_client(dev) != si570_client))
++ return -EINVAL;
++
++ sprintf(buf, "%lu", (unsigned long)id);
++ return set_reset_attr(dev, NULL, buf, 0);
++}
++EXPORT_SYMBOL(reset_si570);
++
++struct i2c_client *get_i2c_client_si570(void)
++{
++ return si570_client;
++}
++EXPORT_SYMBOL(get_i2c_client_si570);
++
++static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO, show_frequency_attr,
++ set_frequency_attr);
++static DEVICE_ATTR(reset, S_IWUSR | S_IRUGO, show_reset_attr, set_reset_attr);
++
++static struct attribute *si570_attr[] = {
++ &dev_attr_frequency.attr,
++ &dev_attr_reset.attr,
++ NULL
++};
++
++static const struct i2c_device_id si570_id[] = {
++ { "si570", 0 },
++ { "si571", 0 },
++ { "si598", 1 },
++ { "si599", 1 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, si570_id);
++
++static int si570_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct si570_platform_data *pdata = client->dev.platform_data;
++ struct si570_data *data;
++ int err;
++ unsigned long initial_fout;
++ u32 tmp = SI570_FOUT_FACTORY_DFLT;
++
++ data = kzalloc(sizeof(struct si570_data), GFP_KERNEL);
++ if (!data) {
++ err = -ENOMEM;
++ goto exit;
++ }
++
++ if (id->driver_data) {
++ data->fout = SI598_FOUT_FACTORY_DFLT;
++ data->max_freq = SI598_MAX_FREQ;
++ } else {
++ data->fout = SI570_FOUT_FACTORY_DFLT;
++ data->max_freq = SI570_MAX_FREQ;
++ }
++
++ if (pdata && pdata->factory_fout)
++ data->fout = pdata->factory_fout;
++
++ if (client->dev.of_node &&
++ (of_property_read_u32(client->dev.of_node, "factory-fout",
++ &tmp) < 0))
++ dev_warn(&client->dev,
++ "DTS does not contain factory-fout, using default\n");
++ else
++ data->fout = tmp;
++
++ i2c_set_clientdata(client, data);
++ err = si570_get_defaults(client);
++ if (err < 0)
++ goto exit_free;
++
++ mutex_init(&data->lock);
++
++ /* Register sysfs hooks */
++ data->attrs.attrs = si570_attr;
++ err = sysfs_create_group(&client->dev.kobj, &data->attrs);
++ if (err)
++ goto exit_free;
++
++ /* Display a message indicating that we've successfully registered */
++ dev_info(&client->dev,
++ "registered %s with default frequency %llu Hz\n",
++ id->name, data->fout);
++
++ /* Read the requested initial fout from either platform data or the
++ * device tree
++ */
++ initial_fout = 0;
++ if (pdata && pdata->initial_fout)
++ initial_fout = pdata->initial_fout;
++ if (client->dev.of_node) {
++ of_property_read_u32(client->dev.of_node, "initial-fout",
++ (u32 *)&initial_fout);
++ if (pdata && pdata->initial_fout &&
++ (pdata->initial_fout != initial_fout)) {
++ dev_warn(&client->dev,
++ "OF initial fout %lu overrides platform data fout %lu\n",
++ initial_fout,
++ pdata->initial_fout);
++ }
++ }
++
++ if (initial_fout != 0) {
++ if (initial_fout < SI570_MIN_FREQ ||
++ initial_fout > data->max_freq) {
++ dev_err(&client->dev,
++ "requested initial frequency %lu is out of range, using default\n",
++ initial_fout);
++ return 0;
++ }
++
++ mutex_lock(&data->lock);
++
++ if (div64_u64(abs(initial_fout - data->frequency) *
++ 10000LL, data->frequency) < 35)
++ err = si570_set_frequency_small(client, data,
++ initial_fout);
++ else
++ err = si570_set_frequency(client, data,
++ initial_fout);
++ mutex_unlock(&data->lock);
++ if (err) {
++ dev_warn(&client->dev,
++ "unable to set initial output frequency %lu: %d\n",
++ initial_fout, err);
++ return err;
++ }
++
++ dev_info(&client->dev,
++ "set initial output frequency %lu Hz\n",
++ initial_fout);
++ }
++
++ si570_client = client;
++
++ return 0;
++
++exit_free:
++ kfree(data);
++exit:
++ return err;
++}
++
++static int si570_remove(struct i2c_client *client)
++{
++ struct si570_data *data = i2c_get_clientdata(client);
++
++ sysfs_remove_group(&client->dev.kobj, &data->attrs);
++ kfree(data);
++ return 0;
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id i2c_si570_of_match[] = {
++ { .compatible = "si570" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, i2c_si570_of_match);
++#endif
++
++static struct i2c_driver si570_driver = {
++ .driver = {
++ .name = "si570",
++ .of_match_table = of_match_ptr(i2c_si570_of_match),
++ },
++ .probe = si570_probe,
++ .remove = si570_remove,
++ .id_table = si570_id,
++};
++
++static int __init si570_init(void)
++{
++ return i2c_add_driver(&si570_driver);
++}
++
++static void __exit si570_exit(void)
++{
++ i2c_del_driver(&si570_driver);
++}
++
++MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
++MODULE_DESCRIPTION("Si570 driver");
++MODULE_LICENSE("GPL");
++
++module_init(si570_init);
++module_exit(si570_exit);
+--- /dev/null
++++ b/include/linux/i2c/si570.h
+@@ -0,0 +1,31 @@
++/*
++ * si570.h - Configuration for si570 misc driver.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation (version 2 of the License only).
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __LINUX_SI570_H
++#define __LINUX_SI570_H
++
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++
++struct si570_platform_data {
++ u64 factory_fout; /* Factory default output frequency */
++ unsigned long initial_fout; /* Requested initial frequency */
++};
++
++int get_frequency_si570(struct device *dev, unsigned long *freq);
++int set_frequency_si570(struct device *dev, unsigned long freq);
++int reset_si570(struct device *dev, int id);
++struct i2c_client *get_i2c_client_si570(void);
++
++#endif /* __LINUX_SI570_H */
diff --git a/patches.zynq/0003-mmc-arasan-add-a-driver-for-Arasan-s-SDHCI-controlle.patch b/patches.zynq/0003-mmc-arasan-add-a-driver-for-Arasan-s-SDHCI-controlle.patch
new file mode 100644
index 00000000000000..e312ac48e52c5b
--- /dev/null
+++ b/patches.zynq/0003-mmc-arasan-add-a-driver-for-Arasan-s-SDHCI-controlle.patch
@@ -0,0 +1,327 @@
+From 85d930d0b091235da43623db984ef49b982f9881 Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Fri, 20 Dec 2013 09:23:18 +0900
+Subject: mmc: arasan: add a driver for Arasan's SDHCI controller core.
+
+As discussed, I left binding and license header as is and fixed the typos.
+v3:
+ - fix typo in binding documentation
+ - add missing '>' in MODULE_AUTHOR string
+v2:
+ - document 'interrupts' and 'interrupt-parent' properties in the driver
+ bindings
+ - append '-8.9a' IP version specifier to comaptibility string
+
+Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Acked-by: Rob Herring <rob.herring@calxeda.com> [binding]
+(patch from https://lkml.org/lkml/2013/12/2/413)
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ Documentation/devicetree/bindings/mmc/arasan,sdhci.txt | 27 ++
+ MAINTAINERS | 1
+ drivers/mmc/host/Kconfig | 12
+ drivers/mmc/host/Makefile | 1
+ drivers/mmc/host/sdhci-of-arasan.c | 224 +++++++++++++++++
+ 5 files changed, 265 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
+ create mode 100644 drivers/mmc/host/sdhci-of-arasan.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
+@@ -0,0 +1,27 @@
++Device Tree Bindings for the Arasan SDHCI Controller
++
++ The bindings follow the mmc[1], clock[2] and interrupt[3] bindings. Only
++ deviations are documented here.
++
++ [1] Documentation/devicetree/bindings/mmc/mmc.txt
++ [2] Documentation/devicetree/bindings/clock/clock-bindings.txt
++ [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
++
++Required Properties:
++ - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a'
++ - reg: From mmc bindings: Register location and length.
++ - clocks: From clock bindings: Handles to clock inputs.
++ - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
++ - interrupts: Interrupt specifier
++ - interrupt-parent: Phandle for the interrupt controller that services
++ interrupts for this device.
++
++Example:
++ sdhci@e0100000 {
++ compatible = "arasan,sdhci-8.9a";
++ reg = <0xe0100000 0x1000>;
++ clock-names = "clk_xin", "clk_ahb";
++ clocks = <&clkc 21>, <&clkc 32>;
++ interrupt-parent = <&gic>;
++ interrupts = <0 24 4>;
++ } ;
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1311,6 +1311,7 @@ T: git git://git.xilinx.com/linux-xlnx.g
+ S: Supported
+ F: arch/arm/mach-zynq/
+ F: drivers/cpuidle/cpuidle-zynq.c
++F: drivers/mmc/host/sdhci-of-arasan.c
+
+ ARM64 PORT (AARCH64 ARCHITECTURE)
+ M: Catalin Marinas <catalin.marinas@arm.com>
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -104,6 +104,18 @@ config MMC_SDHCI_PLTFM
+
+ If unsure, say N.
+
++config MMC_SDHCI_OF_ARASAN
++ tristate "SDHCI OF support for the Arasan SDHCI controllers"
++ depends on MMC_SDHCI_PLTFM
++ depends on OF
++ help
++ This selects the Arasan Secure Digital Host Controller Interface
++ (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
++
++ If you have a controller with this interface, say Y or M here.
++
++ If unsure, say N.
++
+ config MMC_SDHCI_OF_ESDHC
+ tristate "SDHCI OF support for the Freescale eSDHC controller"
+ depends on MMC_SDHCI_PLTFM
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -58,6 +58,7 @@ obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhc
+ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
+ obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
+ obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
++obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
+ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
+ obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
+ obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
+--- /dev/null
++++ b/drivers/mmc/host/sdhci-of-arasan.c
+@@ -0,0 +1,224 @@
++/*
++ * Arasan Secure Digital Host Controller Interface.
++ * Copyright (C) 2011 - 2012 Michal Simek <monstr@monstr.eu>
++ * Copyright (c) 2012 Wind River Systems, Inc.
++ * Copyright (C) 2013 Pengutronix e.K.
++ * Copyright (C) 2013 Xilinx Inc.
++ *
++ * Based on sdhci-of-esdhc.c
++ *
++ * Copyright (c) 2007 Freescale Semiconductor, Inc.
++ * Copyright (c) 2009 MontaVista Software, Inc.
++ *
++ * Authors: Xiaobo Xie <X.Xie@freescale.com>
++ * Anton Vorontsov <avorontsov@ru.mvista.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ */
++
++#include <linux/module.h>
++#include "sdhci-pltfm.h"
++
++#define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c
++
++#define CLK_CTRL_TIMEOUT_SHIFT 16
++#define CLK_CTRL_TIMEOUT_MASK (0xf << CLK_CTRL_TIMEOUT_SHIFT)
++#define CLK_CTRL_TIMEOUT_MIN_EXP 13
++
++/**
++ * struct sdhci_arasan_data
++ * @clk_ahb: Pointer to the AHB clock
++ */
++struct sdhci_arasan_data {
++ struct clk *clk_ahb;
++};
++
++static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
++{
++ u32 div;
++ unsigned long freq;
++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++
++ div = readl(host->ioaddr + SDHCI_ARASAN_CLK_CTRL_OFFSET);
++ div = (div & CLK_CTRL_TIMEOUT_MASK) >> CLK_CTRL_TIMEOUT_SHIFT;
++
++ freq = clk_get_rate(pltfm_host->clk);
++ freq /= 1 << (CLK_CTRL_TIMEOUT_MIN_EXP + div);
++
++ return freq;
++}
++
++static struct sdhci_ops sdhci_arasan_ops = {
++ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
++ .get_timeout_clock = sdhci_arasan_get_timeout_clock,
++};
++
++static struct sdhci_pltfm_data sdhci_arasan_pdata = {
++ .ops = &sdhci_arasan_ops,
++};
++
++#ifdef CONFIG_PM_SLEEP
++/**
++ * sdhci_arasan_suspend - Suspend method for the driver
++ * @dev: Address of the device structure
++ * Returns 0 on success and error value on error
++ *
++ * Put the device in a low power state.
++ */
++static int sdhci_arasan_suspend(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct sdhci_host *host = platform_get_drvdata(pdev);
++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++ struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv;
++ int ret;
++
++ ret = sdhci_suspend_host(host);
++ if (ret)
++ return ret;
++
++ clk_disable(pltfm_host->clk);
++ clk_disable(sdhci_arasan->clk_ahb);
++
++ return 0;
++}
++
++/**
++ * sdhci_arasan_resume - Resume method for the driver
++ * @dev: Address of the device structure
++ * Returns 0 on success and error value on error
++ *
++ * Resume operation after suspend
++ */
++static int sdhci_arasan_resume(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct sdhci_host *host = platform_get_drvdata(pdev);
++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++ struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv;
++ int ret;
++
++ ret = clk_enable(sdhci_arasan->clk_ahb);
++ if (ret) {
++ dev_err(dev, "Cannot enable AHB clock.\n");
++ return ret;
++ }
++
++ ret = clk_enable(pltfm_host->clk);
++ if (ret) {
++ dev_err(dev, "Cannot enable SD clock.\n");
++ clk_disable(sdhci_arasan->clk_ahb);
++ return ret;
++ }
++
++ return sdhci_resume_host(host);
++}
++#endif /* ! CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
++ sdhci_arasan_resume);
++
++static int sdhci_arasan_probe(struct platform_device *pdev)
++{
++ int ret;
++ struct clk *clk_xin;
++ struct sdhci_host *host;
++ struct sdhci_pltfm_host *pltfm_host;
++ struct sdhci_arasan_data *sdhci_arasan;
++
++ sdhci_arasan = devm_kzalloc(&pdev->dev, sizeof(*sdhci_arasan),
++ GFP_KERNEL);
++ if (!sdhci_arasan)
++ return -ENOMEM;
++
++ sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb");
++ if (IS_ERR(sdhci_arasan->clk_ahb)) {
++ dev_err(&pdev->dev, "clk_ahb clock not found.\n");
++ return PTR_ERR(sdhci_arasan->clk_ahb);
++ }
++
++ clk_xin = devm_clk_get(&pdev->dev, "clk_xin");
++ if (IS_ERR(clk_xin)) {
++ dev_err(&pdev->dev, "clk_xin clock not found.\n");
++ return PTR_ERR(clk_xin);
++ }
++
++ ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable AHB clock.\n");
++ return ret;
++ }
++
++ ret = clk_prepare_enable(clk_xin);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable SD clock.\n");
++ goto clk_dis_ahb;
++ }
++
++ host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata);
++ if (IS_ERR(host)) {
++ ret = PTR_ERR(host);
++ dev_err(&pdev->dev, "platform init failed (%u)\n", ret);
++ goto clk_disable_all;
++ }
++
++ sdhci_get_of_property(pdev);
++ pltfm_host = sdhci_priv(host);
++ pltfm_host->priv = sdhci_arasan;
++ pltfm_host->clk = clk_xin;
++
++ ret = sdhci_add_host(host);
++ if (ret) {
++ dev_err(&pdev->dev, "platform register failed (%u)\n", ret);
++ goto err_pltfm_free;
++ }
++
++ return 0;
++
++err_pltfm_free:
++ sdhci_pltfm_free(pdev);
++clk_disable_all:
++ clk_disable_unprepare(clk_xin);
++clk_dis_ahb:
++ clk_disable_unprepare(sdhci_arasan->clk_ahb);
++
++ return ret;
++}
++
++static int sdhci_arasan_remove(struct platform_device *pdev)
++{
++ struct sdhci_host *host = platform_get_drvdata(pdev);
++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++ struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv;
++
++ clk_disable_unprepare(pltfm_host->clk);
++ clk_disable_unprepare(sdhci_arasan->clk_ahb);
++
++ return sdhci_pltfm_unregister(pdev);
++}
++
++static const struct of_device_id sdhci_arasan_of_match[] = {
++ { .compatible = "arasan,sdhci-8.9a" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
++
++static struct platform_driver sdhci_arasan_driver = {
++ .driver = {
++ .name = "sdhci-arasan",
++ .owner = THIS_MODULE,
++ .of_match_table = sdhci_arasan_of_match,
++ .pm = &sdhci_arasan_dev_pm_ops,
++ },
++ .probe = sdhci_arasan_probe,
++ .remove = sdhci_arasan_remove,
++};
++
++module_platform_driver(sdhci_arasan_driver);
++
++MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller");
++MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
++MODULE_LICENSE("GPL");
diff --git a/patches.zynq/0004-net-ethernet-xilinx-Merge-driver-from-Xilinx-reposit.patch b/patches.zynq/0004-net-ethernet-xilinx-Merge-driver-from-Xilinx-reposit.patch
new file mode 100644
index 00000000000000..8021561cca7524
--- /dev/null
+++ b/patches.zynq/0004-net-ethernet-xilinx-Merge-driver-from-Xilinx-reposit.patch
@@ -0,0 +1,4349 @@
+From 4158b8d5c7b3e5a2af192c9790a7c759834f8852 Mon Sep 17 00:00:00 2001
+From: Michal Simek <michal.simek@xilinx.com>
+Date: Fri, 20 Dec 2013 10:18:12 +0900
+Subject: net: ethernet: xilinx: Merge driver from Xilinx repository
+
+Update the Xilinx ethernet driver used in ZYNQ to the one in the
+Xilinx repository.
+(commit efc27505715e64526653f35274717c0fc56491e3 in master branch).
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/net/ethernet/xilinx/Kconfig | 19
+ drivers/net/ethernet/xilinx/Makefile | 1
+ drivers/net/ethernet/xilinx/ll_temac_main.c | 48
+ drivers/net/ethernet/xilinx/ll_temac_mdio.c | 5
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 78
+ drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 336 +-
+ drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c | 86
+ drivers/net/ethernet/xilinx/xilinx_emaclite.c | 51
+ drivers/net/ethernet/xilinx/xilinx_emacps.c | 2912 ++++++++++++++++++++++
+ 9 files changed, 3261 insertions(+), 275 deletions(-)
+ create mode 100644 drivers/net/ethernet/xilinx/xilinx_emacps.c
+
+--- a/drivers/net/ethernet/xilinx/Kconfig
++++ b/drivers/net/ethernet/xilinx/Kconfig
+@@ -27,18 +27,25 @@ config XILINX_EMACLITE
+
+ config XILINX_AXI_EMAC
+ tristate "Xilinx 10/100/1000 AXI Ethernet support"
+- depends on MICROBLAZE
++ depends on (MICROBLAZE || ARCH_ZYNQ)
+ select PHYLIB
+ ---help---
+ This driver supports the 10/100/1000 Ethernet from Xilinx for the
+ AXI bus interface used in Xilinx Virtex FPGAs.
+
+-config XILINX_LL_TEMAC
+- tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
+- depends on (PPC || MICROBLAZE)
++config XILINX_PS_EMAC
++ tristate "Xilinx PS tri-speed EMAC support"
++ depends on ARCH_ZYNQ
+ select PHYLIB
+ ---help---
+- This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
+- core used in Xilinx Spartan and Virtex FPGAs
++ This driver supports tri-speed EMAC.
++
++config XILINX_PS_EMAC_HWTSTAMP
++ bool "Generate hardware packet timestamps"
++ depends on XILINX_PS_EMAC
++ default n
++ ---help---
++ Generate hardare packet timestamps. This is to facilitate IEE 1588.
++
+
+ endif # NET_VENDOR_XILINX
+--- a/drivers/net/ethernet/xilinx/Makefile
++++ b/drivers/net/ethernet/xilinx/Makefile
+@@ -5,5 +5,6 @@
+ ll_temac-objs := ll_temac_main.o ll_temac_mdio.o
+ obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o
+ obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
++obj-$(CONFIG_XILINX_PS_EMAC) += xilinx_emacps.o
+ xilinx_emac-objs := xilinx_axienet_main.o xilinx_axienet_mdio.o
+ obj-$(CONFIG_XILINX_AXI_EMAC) += xilinx_emac.o
+--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
++++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
+@@ -36,7 +36,6 @@
+ #include <linux/netdevice.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+-#include <linux/of_irq.h>
+ #include <linux/of_mdio.h>
+ #include <linux/of_platform.h>
+ #include <linux/of_address.h>
+@@ -244,15 +243,15 @@ static int temac_dma_bd_init(struct net_
+
+ /* allocate the tx and rx ring buffer descriptors. */
+ /* returns a virtual address and a physical address. */
+- lp->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+- sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+- &lp->tx_bd_p, GFP_KERNEL);
++ lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
++ sizeof(*lp->tx_bd_v) * TX_BD_NUM,
++ &lp->tx_bd_p, GFP_KERNEL | __GFP_ZERO);
+ if (!lp->tx_bd_v)
+ goto out;
+
+- lp->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+- sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+- &lp->rx_bd_p, GFP_KERNEL);
++ lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
++ sizeof(*lp->rx_bd_v) * RX_BD_NUM,
++ &lp->rx_bd_p, GFP_KERNEL | __GFP_ZERO);
+ if (!lp->rx_bd_v)
+ goto out;
+
+@@ -298,12 +297,6 @@ static int temac_dma_bd_init(struct net_
+ lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+ lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
+
+- /* Init descriptor indexes */
+- lp->tx_bd_ci = 0;
+- lp->tx_bd_next = 0;
+- lp->tx_bd_tail = 0;
+- lp->rx_bd_ci = 0;
+-
+ return 0;
+
+ out:
+@@ -685,15 +678,12 @@ static int temac_start_xmit(struct sk_bu
+ skb_frag_t *frag;
+
+ num_frag = skb_shinfo(skb)->nr_frags;
+- frag = &skb_shinfo(skb)->frags[0];
+ start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
+ cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+
+ if (temac_check_tx_bd_space(lp, num_frag)) {
+- if (!netif_queue_stopped(ndev)) {
++ if (!netif_queue_stopped(ndev))
+ netif_stop_queue(ndev);
+- return NETDEV_TX_BUSY;
+- }
+ return NETDEV_TX_BUSY;
+ }
+
+@@ -709,11 +699,12 @@ static int temac_start_xmit(struct sk_bu
+
+ cur_p->app0 |= STS_CTRL_APP0_SOP;
+ cur_p->len = skb_headlen(skb);
+- cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len,
+- DMA_TO_DEVICE);
++ cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
++ skb_headlen(skb), DMA_TO_DEVICE);
+ cur_p->app4 = (unsigned long)skb;
+
+ for (ii = 0; ii < num_frag; ii++) {
++ frag = &skb_shinfo(skb)->frags[ii];
+ lp->tx_bd_tail++;
+ if (lp->tx_bd_tail >= TX_BD_NUM)
+ lp->tx_bd_tail = 0;
+@@ -724,7 +715,6 @@ static int temac_start_xmit(struct sk_bu
+ skb_frag_size(frag), DMA_TO_DEVICE);
+ cur_p->len = skb_frag_size(frag);
+ cur_p->app0 = 0;
+- frag++;
+ }
+ cur_p->app0 |= STS_CTRL_APP0_EOP;
+
+@@ -1014,7 +1004,7 @@ static int temac_of_probe(struct platfor
+ return -ENOMEM;
+
+ ether_setup(ndev);
+- platform_set_drvdata(op, ndev);
++ dev_set_drvdata(&op->dev, ndev);
+ SET_NETDEV_DEV(ndev, &op->dev);
+ ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
+ ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
+@@ -1052,12 +1042,14 @@ static int temac_of_probe(struct platfor
+ /* Setup checksum offload, but default to off if not specified */
+ lp->temac_features = 0;
+ p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
++ dev_info(&op->dev, "TX_CSUM %d\n", be32_to_cpup(p));
+ if (p && be32_to_cpu(*p)) {
+ lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+ /* Can checksum TCP/UDP over IPv4. */
+ ndev->features |= NETIF_F_IP_CSUM;
+ }
+ p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
++ dev_info(&op->dev, "RX_CSUM %d\n", be32_to_cpup(p));
+ if (p && be32_to_cpu(*p))
+ lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+
+@@ -1105,14 +1097,15 @@ static int temac_of_probe(struct platfor
+ }
+ temac_init_mac_address(ndev, (void *)addr);
+
+- rc = temac_mdio_setup(lp, op->dev.of_node);
+- if (rc)
+- dev_warn(&op->dev, "error registering MDIO bus\n");
+-
+ lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
+- if (lp->phy_node)
++ if (lp->phy_node) {
+ dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np);
+
++ rc = temac_mdio_setup(lp, op->dev.of_node);
++ if (rc)
++ dev_warn(&op->dev, "error registering MDIO bus\n");
++ }
++
+ /* Add the device attributes */
+ rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
+ if (rc) {
+@@ -1143,7 +1136,7 @@ static int temac_of_probe(struct platfor
+
+ static int temac_of_remove(struct platform_device *op)
+ {
+- struct net_device *ndev = platform_get_drvdata(op);
++ struct net_device *ndev = dev_get_drvdata(&op->dev);
+ struct temac_local *lp = netdev_priv(ndev);
+
+ temac_mdio_teardown(lp);
+@@ -1152,6 +1145,7 @@ static int temac_of_remove(struct platfo
+ if (lp->phy_node)
+ of_node_put(lp->phy_node);
+ lp->phy_node = NULL;
++ dev_set_drvdata(&op->dev, NULL);
+ iounmap(lp->regs);
+ if (lp->sdma_regs)
+ iounmap(lp->sdma_regs);
+--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
++++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+@@ -63,6 +63,7 @@ int temac_mdio_setup(struct temac_local
+ int clk_div;
+ int rc, size;
+ struct resource res;
++ struct device_node *np1 = of_get_parent(lp->phy_node);
+
+ /* Calculate a reasonable divisor for the clock rate */
+ clk_div = 0x3f; /* worst-case default setting */
+@@ -85,7 +86,7 @@ int temac_mdio_setup(struct temac_local
+ if (!bus)
+ return -ENOMEM;
+
+- of_address_to_resource(np, 0, &res);
++ of_address_to_resource(np1, 0, &res);
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+ (unsigned long long)res.start);
+ bus->priv = lp;
+@@ -97,7 +98,7 @@ int temac_mdio_setup(struct temac_local
+
+ lp->mii_bus = bus;
+
+- rc = of_mdiobus_register(bus, np);
++ rc = of_mdiobus_register(bus, np1);
+ if (rc)
+ goto err_register;
+
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -9,18 +9,19 @@
+ #define XILINX_AXIENET_H
+
+ #include <linux/netdevice.h>
++#include <linux/of_irq.h>
+ #include <linux/spinlock.h>
+ #include <linux/interrupt.h>
++#include <linux/if_vlan.h>
+
+ /* Packet size info */
+ #define XAE_HDR_SIZE 14 /* Size of Ethernet header */
+-#define XAE_HDR_VLAN_SIZE 18 /* Size of an Ethernet hdr + VLAN */
+ #define XAE_TRL_SIZE 4 /* Size of Ethernet trailer (FCS) */
+ #define XAE_MTU 1500 /* Max MTU of an Ethernet frame */
+ #define XAE_JUMBO_MTU 9000 /* Max MTU of a jumbo Eth. frame */
+
+ #define XAE_MAX_FRAME_SIZE (XAE_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE)
+-#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + XAE_HDR_VLAN_SIZE + XAE_TRL_SIZE)
++#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + VLAN_ETH_HLEN + XAE_TRL_SIZE)
+ #define XAE_MAX_JUMBO_FRAME_SIZE (XAE_JUMBO_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE)
+
+ /* Configuration options */
+@@ -66,20 +67,20 @@
+
+ /* Axi DMA Register definitions */
+
+-#define XAXIDMA_TX_CR_OFFSET 0x00000000 /* Channel control */
+-#define XAXIDMA_TX_SR_OFFSET 0x00000004 /* Status */
+-#define XAXIDMA_TX_CDESC_OFFSET 0x00000008 /* Current descriptor pointer */
+-#define XAXIDMA_TX_TDESC_OFFSET 0x00000010 /* Tail descriptor pointer */
+-
+-#define XAXIDMA_RX_CR_OFFSET 0x00000030 /* Channel control */
+-#define XAXIDMA_RX_SR_OFFSET 0x00000034 /* Status */
+-#define XAXIDMA_RX_CDESC_OFFSET 0x00000038 /* Current descriptor pointer */
+-#define XAXIDMA_RX_TDESC_OFFSET 0x00000040 /* Tail descriptor pointer */
++#define XAXIDMA_TX_CR_OFFSET 0x00000000 /* Channel control */
++#define XAXIDMA_TX_SR_OFFSET 0x00000004 /* Status */
++#define XAXIDMA_TX_CDESC_OFFSET 0x00000008 /* Current descriptor pointer */
++#define XAXIDMA_TX_TDESC_OFFSET 0x00000010 /* Tail descriptor pointer */
++
++#define XAXIDMA_RX_CR_OFFSET 0x00000030 /* Channel control */
++#define XAXIDMA_RX_SR_OFFSET 0x00000034 /* Status */
++#define XAXIDMA_RX_CDESC_OFFSET 0x00000038 /* Current descriptor pointer */
++#define XAXIDMA_RX_TDESC_OFFSET 0x00000040 /* Tail descriptor pointer */
+
+-#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA channel */
+-#define XAXIDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */
++#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA channel */
++#define XAXIDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */
+
+-#define XAXIDMA_BD_NDESC_OFFSET 0x00 /* Next descriptor pointer */
++#define XAXIDMA_BD_NDESC_OFFSET 0x00 /* Next descriptor pointer */
+ #define XAXIDMA_BD_BUFA_OFFSET 0x08 /* Buffer address */
+ #define XAXIDMA_BD_CTRL_LEN_OFFSET 0x18 /* Control/buffer length */
+ #define XAXIDMA_BD_STS_OFFSET 0x1C /* Status */
+@@ -93,8 +94,8 @@
+ #define XAXIDMA_BD_HAS_DRE_OFFSET 0x3C /* Whether has DRE */
+
+ #define XAXIDMA_BD_HAS_DRE_SHIFT 8 /* Whether has DRE shift */
+-#define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+-#define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
++#define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
++#define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+ #define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+@@ -130,7 +131,7 @@
+ #define XAXIDMA_BD_STS_ALL_ERR_MASK 0x70000000 /* All errors */
+ #define XAXIDMA_BD_STS_RXSOF_MASK 0x08000000 /* First rx pkt */
+ #define XAXIDMA_BD_STS_RXEOF_MASK 0x04000000 /* Last rx pkt */
+-#define XAXIDMA_BD_STS_ALL_MASK 0xFC000000 /* All status bits */
++#define XAXIDMA_BD_STS_ALL_MASK 0xFC000000 /* All status bits */
+
+ #define XAXIDMA_BD_MINIMUM_ALIGNMENT 0x40
+
+@@ -158,7 +159,7 @@
+ #define XAE_MDIO_MCR_OFFSET 0x00000504 /* MII Management Control */
+ #define XAE_MDIO_MWD_OFFSET 0x00000508 /* MII Management Write Data */
+ #define XAE_MDIO_MRD_OFFSET 0x0000050C /* MII Management Read Data */
+-#define XAE_MDIO_MIS_OFFSET 0x00000600 /* MII Management Interrupt Status */
++#define XAE_MDIO_MIS_OFFSET 0x00000600 /* MII Management Int. Status */
+ #define XAE_MDIO_MIP_OFFSET 0x00000620 /* MII Mgmt Interrupt Pending
+ * register offset */
+ #define XAE_MDIO_MIE_OFFSET 0x00000640 /* MII Management Interrupt Enable
+@@ -180,16 +181,16 @@
+ * destination address */
+ #define XAE_RAF_BCSTREJ_MASK 0x00000004 /* Reject receive broadcast
+ * destination address */
+-#define XAE_RAF_TXVTAGMODE_MASK 0x00000018 /* Tx VLAN TAG mode */
+-#define XAE_RAF_RXVTAGMODE_MASK 0x00000060 /* Rx VLAN TAG mode */
++#define XAE_RAF_TXVTAGMODE_MASK 0x00000018 /* Tx VLAN TAG mode */
++#define XAE_RAF_RXVTAGMODE_MASK 0x00000060 /* Rx VLAN TAG mode */
+ #define XAE_RAF_TXVSTRPMODE_MASK 0x00000180 /* Tx VLAN STRIP mode */
+ #define XAE_RAF_RXVSTRPMODE_MASK 0x00000600 /* Rx VLAN STRIP mode */
+-#define XAE_RAF_NEWFNCENBL_MASK 0x00000800 /* New function mode */
++#define XAE_RAF_NEWFNCENBL_MASK 0x00000800 /* New function mode */
+ #define XAE_RAF_EMULTIFLTRENBL_MASK 0x00001000 /* Exteneded Multicast
+ * Filtering mode
+ */
+ #define XAE_RAF_STATSRST_MASK 0x00002000 /* Stats. Counter Reset */
+-#define XAE_RAF_RXBADFRMEN_MASK 0x00004000 /* Recv Bad Frame Enable */
++#define XAE_RAF_RXBADFRMEN_MASK 0x00004000 /* Recv Bad Frame Enable */
+ #define XAE_RAF_TXVTAGMODE_SHIFT 3 /* Tx Tag mode shift bits */
+ #define XAE_RAF_RXVTAGMODE_SHIFT 5 /* Rx Tag mode shift bits */
+ #define XAE_RAF_TXVSTRPMODE_SHIFT 7 /* Tx strip mode shift bits*/
+@@ -273,22 +274,22 @@
+ #define XAE_PHYC_SGMIILINKSPEED_MASK 0xC0000000 /* SGMII link speed mask*/
+ #define XAE_PHYC_RGMIILINKSPEED_MASK 0x0000000C /* RGMII link speed */
+ #define XAE_PHYC_RGMIIHD_MASK 0x00000002 /* RGMII Half-duplex */
+-#define XAE_PHYC_RGMIILINK_MASK 0x00000001 /* RGMII link status */
++#define XAE_PHYC_RGMIILINK_MASK 0x00000001 /* RGMII link status */
+ #define XAE_PHYC_RGLINKSPD_10 0x00000000 /* RGMII link 10 Mbit */
+ #define XAE_PHYC_RGLINKSPD_100 0x00000004 /* RGMII link 100 Mbit */
+-#define XAE_PHYC_RGLINKSPD_1000 0x00000008 /* RGMII link 1000 Mbit */
++#define XAE_PHYC_RGLINKSPD_1000 0x00000008 /* RGMII link 1000 Mbit */
+ #define XAE_PHYC_SGLINKSPD_10 0x00000000 /* SGMII link 10 Mbit */
+ #define XAE_PHYC_SGLINKSPD_100 0x40000000 /* SGMII link 100 Mbit */
+-#define XAE_PHYC_SGLINKSPD_1000 0x80000000 /* SGMII link 1000 Mbit */
++#define XAE_PHYC_SGLINKSPD_1000 0x80000000 /* SGMII link 1000 Mbit */
+
+ /* Bit masks for Axi Ethernet MDIO interface MC register */
+-#define XAE_MDIO_MC_MDIOEN_MASK 0x00000040 /* MII management enable */
++#define XAE_MDIO_MC_MDIOEN_MASK 0x00000040 /* MII management enable */
+ #define XAE_MDIO_MC_CLOCK_DIVIDE_MAX 0x3F /* Maximum MDIO divisor */
+
+ /* Bit masks for Axi Ethernet MDIO interface MCR register */
+-#define XAE_MDIO_MCR_PHYAD_MASK 0x1F000000 /* Phy Address Mask */
++#define XAE_MDIO_MCR_PHYAD_MASK 0x1F000000 /* Phy Address Mask */
+ #define XAE_MDIO_MCR_PHYAD_SHIFT 24 /* Phy Address Shift */
+-#define XAE_MDIO_MCR_REGAD_MASK 0x001F0000 /* Reg Address Mask */
++#define XAE_MDIO_MCR_REGAD_MASK 0x001F0000 /* Reg Address Mask */
+ #define XAE_MDIO_MCR_REGAD_SHIFT 16 /* Reg Address Shift */
+ #define XAE_MDIO_MCR_OP_MASK 0x0000C000 /* Operation Code Mask */
+ #define XAE_MDIO_MCR_OP_SHIFT 13 /* Operation Code Shift */
+@@ -312,13 +313,13 @@
+
+ #define XAE_MDIO_DIV_DFT 29 /* Default MDIO clock divisor */
+
+-/* Defines for different options for C_PHY_TYPE parameter in Axi Ethernet IP */
++/* Defines different options for C_PHY_TYPE parameter in Axi Ethernet IP */
+ #define XAE_PHY_TYPE_MII 0
+ #define XAE_PHY_TYPE_GMII 1
+ #define XAE_PHY_TYPE_RGMII_1_3 2
+ #define XAE_PHY_TYPE_RGMII_2_0 3
+ #define XAE_PHY_TYPE_SGMII 4
+-#define XAE_PHY_TYPE_1000BASE_X 5
++#define XAE_PHY_TYPE_1000BASE_X 5
+
+ #define XAE_MULTICAST_CAM_TABLE_NUM 4 /* Total number of entries in the
+ * hardware multicast table. */
+@@ -337,6 +338,14 @@
+
+ #define DELAY_OF_ONE_MILLISEC 1000
+
++/* Read/Write access to the registers */
++#ifndef out_be32
++#ifdef CONFIG_ARCH_ZYNQ
++#define in_be32(offset) __raw_readl(offset)
++#define out_be32(offset, val) __raw_writel(val, offset)
++#endif
++#endif
++
+ /**
+ * struct axidma_bd - Axi Dma buffer descriptor layout
+ * @next: MM2S/S2MM Next Descriptor Pointer
+@@ -408,8 +417,9 @@ struct axidma_bd {
+ * Txed/Rxed in the existing hardware. If jumbo option is
+ * supported, the maximum frame size would be 9k. Else it is
+ * 1522 bytes (assuming support for basic VLAN)
+- * @jumbo_support: Stores hardware configuration for jumbo support. If hardware
+- * can handle jumbo packets, this entry will be 1, else 0.
++ * @jumbo_support: Stores hardware configuration for jumbo support. If
++ * hardware can handle jumbo packets, this entry will be 1,
++ * else 0.
+ */
+ struct axienet_local {
+ struct net_device *ndev;
+@@ -434,7 +444,7 @@ struct axienet_local {
+ u32 temac_type;
+ u32 phy_type;
+
+- u32 options; /* Current options word */
++ u32 options; /* Current options word */
+ u32 last_link;
+ u32 features;
+
+@@ -448,7 +458,7 @@ struct axienet_local {
+ u32 rx_bd_ci;
+
+ u32 max_frm_size;
+- u32 jumbo_support;
++ u32 rxmem;
+
+ int csum_offload_on_tx_path;
+ int csum_offload_on_rx_path;
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+@@ -201,15 +201,17 @@ static int axienet_dma_bd_init(struct ne
+ /*
+ * Allocate the Tx and Rx buffer descriptors.
+ */
+- lp->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+- sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+- &lp->tx_bd_p, GFP_KERNEL);
++ lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
++ sizeof(*lp->tx_bd_v) * TX_BD_NUM,
++ &lp->tx_bd_p,
++ GFP_KERNEL | __GFP_ZERO);
+ if (!lp->tx_bd_v)
+ goto out;
+
+- lp->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+- sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+- &lp->rx_bd_p, GFP_KERNEL);
++ lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
++ sizeof(*lp->rx_bd_v) * RX_BD_NUM,
++ &lp->rx_bd_p,
++ GFP_KERNEL | __GFP_ZERO);
+ if (!lp->rx_bd_v)
+ goto out;
+
+@@ -263,7 +265,8 @@ static int axienet_dma_bd_init(struct ne
+ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
+
+ /* Populate the tail pointer and bring the Rx Axi DMA engine out of
+- * halted state. This will make the Rx side ready for reception.*/
++ * halted state. This will make the Rx side ready for reception.
++ */
+ axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
+ cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
+ axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
+@@ -273,7 +276,8 @@ static int axienet_dma_bd_init(struct ne
+
+ /* Write to the RS (Run-stop) bit in the Tx channel control register.
+ * Tx channel is now ready to run. But only after we write to the
+- * tail pointer register that the Tx channel will start transmitting */
++ * tail pointer register that the Tx channel will start transmitting.
++ */
+ axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
+ cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
+ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
+@@ -354,7 +358,8 @@ static void axienet_set_multicast_list(s
+ netdev_mc_count(ndev) > XAE_MULTICAST_CAM_TABLE_NUM) {
+ /* We must make the kernel realize we had to move into
+ * promiscuous mode. If it was a promiscuous mode request
+- * the flag is already set. If not we set it. */
++ * the flag is already set. If not we set it.
++ */
+ ndev->flags |= IFF_PROMISC;
+ reg = axienet_ior(lp, XAE_FMI_OFFSET);
+ reg |= XAE_FMI_PM_MASK;
+@@ -438,14 +443,15 @@ static void __axienet_device_reset(struc
+ /* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset
+ * process of Axi DMA takes a while to complete as all pending
+ * commands/transfers will be flushed or completed during this
+- * reset process. */
++ * reset process.
++ */
+ axienet_dma_out32(lp, offset, XAXIDMA_CR_RESET_MASK);
+ timeout = DELAY_OF_ONE_MILLISEC;
+ while (axienet_dma_in32(lp, offset) & XAXIDMA_CR_RESET_MASK) {
+ udelay(1);
+ if (--timeout == 0) {
+- dev_err(dev, "axienet_device_reset DMA "
+- "reset timeout!\n");
++ dev_err(dev,
++ "axienet_device_reset DMA reset timeout!\n");
+ break;
+ }
+ }
+@@ -471,18 +477,21 @@ static void axienet_device_reset(struct
+ __axienet_device_reset(lp, &ndev->dev, XAXIDMA_RX_CR_OFFSET);
+
+ lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
++ lp->options |= XAE_OPTION_VLAN;
+ lp->options &= (~XAE_OPTION_JUMBO);
+
+ if ((ndev->mtu > XAE_MTU) &&
+- (ndev->mtu <= XAE_JUMBO_MTU) &&
+- (lp->jumbo_support)) {
+- lp->max_frm_size = ndev->mtu + XAE_HDR_VLAN_SIZE +
+- XAE_TRL_SIZE;
+- lp->options |= XAE_OPTION_JUMBO;
++ (ndev->mtu <= XAE_JUMBO_MTU)) {
++ lp->max_frm_size = ndev->mtu + VLAN_ETH_HLEN +
++ XAE_TRL_SIZE;
++
++ if (lp->max_frm_size <= lp->rxmem)
++ lp->options |= XAE_OPTION_JUMBO;
+ }
+
+ if (axienet_dma_bd_init(ndev)) {
+- dev_err(&ndev->dev, "axienet_device_reset descriptor "
++ dev_err(&ndev->dev,
++ "axienet_device_reset descriptor "
+ "allocation failed\n");
+ }
+
+@@ -497,7 +506,8 @@ static void axienet_device_reset(struct
+ axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+
+ /* Sync default options with HW but leave receiver and
+- * transmitter disabled.*/
++ * transmitter disabled.
++ */
+ axienet_setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ axienet_set_mac_address(ndev, NULL);
+@@ -549,7 +559,8 @@ static void axienet_adjust_link(struct n
+ emmc_reg |= XAE_EMMC_LINKSPD_10;
+ break;
+ default:
+- dev_err(&ndev->dev, "Speed other than 10, 100 "
++ dev_err(&ndev->dev,
++ "Speed other than 10, 100 "
+ "or 1Gbps is not supported\n");
+ break;
+ }
+@@ -558,8 +569,8 @@ static void axienet_adjust_link(struct n
+ lp->last_link = link_state;
+ phy_print_status(phy);
+ } else {
+- dev_err(&ndev->dev, "Error setting Axi Ethernet "
+- "mac speed\n");
++ dev_err(&ndev->dev,
++ "Error setting Axi Ethernet mac speed\n");
+ }
+ }
+ }
+@@ -601,7 +612,8 @@ static void axienet_start_xmit_done(stru
+ size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
+ packets++;
+
+- lp->tx_bd_ci = ++lp->tx_bd_ci % TX_BD_NUM;
++ ++lp->tx_bd_ci;
++ lp->tx_bd_ci %= TX_BD_NUM;
+ cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
+ status = cur_p->status;
+ }
+@@ -687,7 +699,8 @@ static int axienet_start_xmit(struct sk_
+ skb_headlen(skb), DMA_TO_DEVICE);
+
+ for (ii = 0; ii < num_frag; ii++) {
+- lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
++ ++lp->tx_bd_tail;
++ lp->tx_bd_tail %= TX_BD_NUM;
+ cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+ frag = &skb_shinfo(skb)->frags[ii];
+ cur_p->phys = dma_map_single(ndev->dev.parent,
+@@ -701,9 +714,12 @@ static int axienet_start_xmit(struct sk_
+ cur_p->app4 = (unsigned long)skb;
+
+ tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
++ wmb();
++
+ /* Start the transfer */
+ axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p);
+- lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
++ ++lp->tx_bd_tail;
++ lp->tx_bd_tail %= TX_BD_NUM;
+
+ return NETDEV_TX_OK;
+ }
+@@ -723,15 +739,16 @@ static void axienet_recv(struct net_devi
+ u32 csumstatus;
+ u32 size = 0;
+ u32 packets = 0;
+- dma_addr_t tail_p;
++ dma_addr_t tail_p = 0;
+ struct axienet_local *lp = netdev_priv(ndev);
+ struct sk_buff *skb, *new_skb;
+ struct axidma_bd *cur_p;
+
+- tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
++ rmb();
+ cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
+
+ while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
++ tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
+ skb = (struct sk_buff *) (cur_p->sw_id_offset);
+ length = cur_p->app4 & 0x0000FFFF;
+
+@@ -775,14 +792,16 @@ static void axienet_recv(struct net_devi
+ cur_p->status = 0;
+ cur_p->sw_id_offset = (u32) new_skb;
+
+- lp->rx_bd_ci = ++lp->rx_bd_ci % RX_BD_NUM;
++ ++lp->rx_bd_ci;
++ lp->rx_bd_ci %= RX_BD_NUM;
+ cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
+ }
+
+ ndev->stats.rx_packets += packets;
+ ndev->stats.rx_bytes += size;
+
+- axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p);
++ if (tail_p)
++ axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p);
+ }
+
+ /**
+@@ -804,6 +823,7 @@ static irqreturn_t axienet_tx_irq(int ir
+
+ status = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+ if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
++ axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
+ axienet_start_xmit_done(lp->ndev);
+ goto out;
+ }
+@@ -827,9 +847,9 @@ static irqreturn_t axienet_tx_irq(int ir
+ axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
+
+ tasklet_schedule(&lp->dma_err_tasklet);
++ axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
+ }
+ out:
+- axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET, status);
+ return IRQ_HANDLED;
+ }
+
+@@ -852,6 +872,7 @@ static irqreturn_t axienet_rx_irq(int ir
+
+ status = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+ if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) {
++ axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
+ axienet_recv(lp->ndev);
+ goto out;
+ }
+@@ -875,9 +896,9 @@ static irqreturn_t axienet_rx_irq(int ir
+ axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
+
+ tasklet_schedule(&lp->dma_err_tasklet);
++ axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
+ }
+ out:
+- axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET, status);
+ return IRQ_HANDLED;
+ }
+
+@@ -891,10 +912,10 @@ static void axienet_dma_err_handler(unsi
+ * -ENODEV, if PHY cannot be connected to
+ * non-zero error value on failure
+ *
+- * This is the driver open routine. It calls phy_start to start the PHY device.
+- * It also allocates interrupt service routines, enables the interrupt lines
+- * and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer
+- * descriptors are initialized.
++ * This is the driver open routine. It calls phy_start to start the PHY
++ * device. It also allocates interrupt service routines, enables the
++ * interrupt lines and ISR handling. Axi Ethernet core is reset through Axi
++ * DMA core. Buffer descriptors are initialized.
+ */
+ static int axienet_open(struct net_device *ndev)
+ {
+@@ -910,7 +931,8 @@ static int axienet_open(struct net_devic
+ /* Disable the MDIO interface till Axi Ethernet Reset is completed.
+ * When we do an Axi Ethernet reset, it resets the complete core
+ * including the MDIO. If MDIO is not disabled when the reset
+- * process is started, MDIO will be broken afterwards. */
++ * process is started, MDIO will be broken afterwards.
++ */
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET,
+ (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK)));
+ axienet_device_reset(ndev);
+@@ -921,14 +943,20 @@ static int axienet_open(struct net_devic
+ return ret;
+
+ if (lp->phy_node) {
+- lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
++ if (lp->phy_type == XAE_PHY_TYPE_GMII) {
++ lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+ axienet_adjust_link, 0,
+ PHY_INTERFACE_MODE_GMII);
+- if (!lp->phy_dev) {
+- dev_err(lp->dev, "of_phy_connect() failed\n");
+- return -ENODEV;
++ } else if (lp->phy_type == XAE_PHY_TYPE_RGMII_2_0) {
++ lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
++ axienet_adjust_link, 0,
++ PHY_INTERFACE_MODE_RGMII_ID);
+ }
+- phy_start(lp->phy_dev);
++
++ if (!lp->phy_dev)
++ dev_err(lp->dev, "of_phy_connect() failed\n");
++ else
++ phy_start(lp->phy_dev);
+ }
+
+ /* Enable tasklets for Axi DMA error handling */
+@@ -1013,15 +1041,15 @@ static int axienet_change_mtu(struct net
+
+ if (netif_running(ndev))
+ return -EBUSY;
+- if (lp->jumbo_support) {
+- if ((new_mtu > XAE_JUMBO_MTU) || (new_mtu < 64))
+- return -EINVAL;
+- ndev->mtu = new_mtu;
+- } else {
+- if ((new_mtu > XAE_MTU) || (new_mtu < 64))
+- return -EINVAL;
+- ndev->mtu = new_mtu;
+- }
++
++ if ((new_mtu + VLAN_ETH_HLEN +
++ XAE_TRL_SIZE) > lp->rxmem)
++ return -EINVAL;
++
++ if ((new_mtu > XAE_JUMBO_MTU) || (new_mtu < 64))
++ return -EINVAL;
++
++ ndev->mtu = new_mtu;
+
+ return 0;
+ }
+@@ -1031,8 +1059,8 @@ static int axienet_change_mtu(struct net
+ * axienet_poll_controller - Axi Ethernet poll mechanism.
+ * @ndev: Pointer to net_device structure
+ *
+- * This implements Rx/Tx ISR poll mechanisms. The interrupts are disabled prior
+- * to polling the ISRs and are enabled back after the polling is done.
++ * This implements Rx/Tx ISR poll mechanisms. The interrupts are disabled
++ * prior to polling the ISRs and are enabled back after the polling is done.
+ */
+ static void axienet_poll_controller(struct net_device *ndev)
+ {
+@@ -1046,6 +1074,20 @@ static void axienet_poll_controller(stru
+ }
+ #endif
+
++/* Ioctl MII Interface */
++static int axienet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++ struct axienet_local *priv = netdev_priv(dev);
++
++ if (!netif_running(dev))
++ return -EINVAL;
++
++ if (!priv->phy_dev)
++ return -EOPNOTSUPP;
++
++ return phy_mii_ioctl(priv->phy_dev, rq, cmd);
++}
++
+ static const struct net_device_ops axienet_netdev_ops = {
+ .ndo_open = axienet_open,
+ .ndo_stop = axienet_stop,
+@@ -1054,6 +1096,7 @@ static const struct net_device_ops axien
+ .ndo_set_mac_address = netdev_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_rx_mode = axienet_set_multicast_list,
++ .ndo_do_ioctl = axienet_ioctl,
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = axienet_poll_controller,
+ #endif
+@@ -1209,7 +1252,7 @@ axienet_ethtools_get_pauseparam(struct n
+ * axienet_ethtools_set_pauseparam - Set device pause parameter(flow control)
+ * settings.
+ * @ndev: Pointer to net_device structure
+- * @epauseparam:Pointer to ethtool_pauseparam structure
++ * @epauseparm:Pointer to ethtool_pauseparam structure
+ *
+ * This implements ethtool command for enabling flow control on Rx and Tx
+ * paths. Issue "ethtool -A ethX tx on|off" under linux prompt to execute this
+@@ -1223,8 +1266,9 @@ axienet_ethtools_set_pauseparam(struct n
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+- printk(KERN_ERR "%s: Please stop netif before applying "
+- "configruation\n", ndev->name);
++ dev_err(&ndev->dev,
++ "%s: Please stop netif before configuration\n",
++ ndev->name);
+ return -EFAULT;
+ }
+
+@@ -1280,8 +1324,9 @@ static int axienet_ethtools_set_coalesce
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+- printk(KERN_ERR "%s: Please stop netif before applying "
+- "configruation\n", ndev->name);
++ dev_err(&ndev->dev,
++ "%s: Please stop netif before configuration\n",
++ ndev->name);
+ return -EFAULT;
+ }
+
+@@ -1350,7 +1395,8 @@ static void axienet_dma_err_handler(unsi
+ /* Disable the MDIO interface till Axi Ethernet Reset is completed.
+ * When we do an Axi Ethernet reset, it resets the complete core
+ * including the MDIO. So if MDIO is not disabled when the reset
+- * process is started, MDIO will be broken afterwards. */
++ * process is started, MDIO will be broken afterwards.
++ */
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg &
+ ~XAE_MDIO_MC_MDIOEN_MASK));
+
+@@ -1421,7 +1467,8 @@ static void axienet_dma_err_handler(unsi
+ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
+
+ /* Populate the tail pointer and bring the Rx Axi DMA engine out of
+- * halted state. This will make the Rx side ready for reception.*/
++ * halted state. This will make the Rx side ready for reception.
++ */
+ axienet_dma_out32(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
+ cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
+ axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
+@@ -1431,7 +1478,8 @@ static void axienet_dma_err_handler(unsi
+
+ /* Write to the RS (Run-stop) bit in the Tx channel control register.
+ * Tx channel is now ready to run. But only after we write to the
+- * tail pointer register that the Tx channel will start transmitting */
++ * tail pointer register that the Tx channel will start transmitting
++ */
+ axienet_dma_out32(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
+ cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
+ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
+@@ -1447,7 +1495,8 @@ static void axienet_dma_err_handler(unsi
+ axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+
+ /* Sync default options with HW but leave receiver and
+- * transmitter disabled.*/
++ * transmitter disabled.
++ */
+ axienet_setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ axienet_set_mac_address(ndev, NULL);
+@@ -1456,77 +1505,84 @@ static void axienet_dma_err_handler(unsi
+ }
+
+ /**
+- * axienet_of_probe - Axi Ethernet probe function.
+- * @op: Pointer to platform device structure.
+- * @match: Pointer to device id structure
++ * axienet_probe - Axi Ethernet probe function.
++ * @pdev: Pointer to platform device structure.
+ *
+ * returns: 0, on success
+ * Non-zero error value on failure.
+ *
+ * This is the probe routine for Axi Ethernet driver. This is called before
+- * any other driver routines are invoked. It allocates and sets up the Ethernet
+- * device. Parses through device tree and populates fields of
++ * any other driver routines are invoked. It allocates and sets up the
++ * Ethernet device. Parses through device tree and populates fields of
+ * axienet_local. It registers the Ethernet device.
+ */
+-static int axienet_of_probe(struct platform_device *op)
++static int axienet_probe(struct platform_device *pdev)
+ {
+- __be32 *p;
+- int size, ret = 0;
++ int ret;
+ struct device_node *np;
+ struct axienet_local *lp;
+ struct net_device *ndev;
+- const void *addr;
++ u8 mac_addr[6];
++ struct resource *ethres, dmares;
++ u32 value;
+
+ ndev = alloc_etherdev(sizeof(*lp));
+ if (!ndev)
+ return -ENOMEM;
+
+ ether_setup(ndev);
+- platform_set_drvdata(op, ndev);
++ platform_set_drvdata(pdev, ndev);
+
+- SET_NETDEV_DEV(ndev, &op->dev);
++ SET_NETDEV_DEV(ndev, &pdev->dev);
+ ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
+- ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
++ ndev->features = NETIF_F_FRAGLIST;
+ ndev->netdev_ops = &axienet_netdev_ops;
+ ndev->ethtool_ops = &axienet_ethtool_ops;
+
+ lp = netdev_priv(ndev);
+ lp->ndev = ndev;
+- lp->dev = &op->dev;
++ lp->dev = &pdev->dev;
+ lp->options = XAE_OPTION_DEFAULTS;
+ /* Map device registers */
+- lp->regs = of_iomap(op->dev.of_node, 0);
++ ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
+ if (!lp->regs) {
+- dev_err(&op->dev, "could not map Axi Ethernet regs.\n");
+- goto nodev;
++ dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n");
++ ret = -ENOMEM;
++ goto free_netdev;
+ }
++
+ /* Setup checksum offload, but default to off if not specified */
+ lp->features = 0;
+
+- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
+- if (p) {
+- switch (be32_to_cpup(p)) {
++ ret = of_property_read_u32(pdev->dev.of_node, "xlnx,txcsum", &value);
++ if (!ret) {
++ dev_info(&pdev->dev, "TX_CSUM %d\n", value);
++
++ switch (value) {
+ case 1:
+ lp->csum_offload_on_tx_path =
+ XAE_FEATURE_PARTIAL_TX_CSUM;
+ lp->features |= XAE_FEATURE_PARTIAL_TX_CSUM;
+ /* Can checksum TCP/UDP over IPv4. */
+- ndev->features |= NETIF_F_IP_CSUM;
++ ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ break;
+ case 2:
+ lp->csum_offload_on_tx_path =
+ XAE_FEATURE_FULL_TX_CSUM;
+ lp->features |= XAE_FEATURE_FULL_TX_CSUM;
+ /* Can checksum TCP/UDP over IPv4. */
+- ndev->features |= NETIF_F_IP_CSUM;
++ ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ break;
+ default:
+ lp->csum_offload_on_tx_path = XAE_NO_CSUM_OFFLOAD;
+ }
+ }
+- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
+- if (p) {
+- switch (be32_to_cpup(p)) {
++ ret = of_property_read_u32(pdev->dev.of_node, "xlnx,rxcsum", &value);
++ if (!ret) {
++ dev_info(&pdev->dev, "RX_CSUM %d\n", value);
++
++ switch (value) {
+ case 1:
+ lp->csum_offload_on_rx_path =
+ XAE_FEATURE_PARTIAL_RX_CSUM;
+@@ -1542,85 +1598,80 @@ static int axienet_of_probe(struct platf
+ }
+ }
+ /* For supporting jumbo frames, the Axi Ethernet hardware must have
+- * a larger Rx/Tx Memory. Typically, the size must be more than or
+- * equal to 16384 bytes, so that we can enable jumbo option and start
+- * supporting jumbo frames. Here we check for memory allocated for
+- * Rx/Tx in the hardware from the device-tree and accordingly set
+- * flags. */
+- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,rxmem", NULL);
+- if (p) {
+- if ((be32_to_cpup(p)) >= 0x4000)
+- lp->jumbo_support = 1;
+- }
+- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,temac-type",
+- NULL);
+- if (p)
+- lp->temac_type = be32_to_cpup(p);
+- p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL);
+- if (p)
+- lp->phy_type = be32_to_cpup(p);
+-
+- /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
+- np = of_parse_phandle(op->dev.of_node, "axistream-connected", 0);
+- if (!np) {
+- dev_err(&op->dev, "could not find DMA node\n");
+- goto err_iounmap;
+- }
+- lp->dma_regs = of_iomap(np, 0);
+- if (lp->dma_regs) {
+- dev_dbg(&op->dev, "MEM base: %p\n", lp->dma_regs);
+- } else {
+- dev_err(&op->dev, "unable to map DMA registers\n");
+- of_node_put(np);
++ * a larger Rx/Tx Memory. Typically, the size must be large so that
++ * we can enable jumbo option and start supporting jumbo frames.
++ * Here we check for memory allocated for Rx/Tx in the hardware from
++ * the device-tree and accordingly set flags.
++ */
++ of_property_read_u32(pdev->dev.of_node, "xlnx,rxmem", &lp->rxmem);
++ of_property_read_u32(pdev->dev.of_node, "xlnx,temac-type",
++ &lp->temac_type);
++ of_property_read_u32(pdev->dev.of_node, "xlnx,phy-type",
++ &lp->phy_type);
++
++ /* Find the DMA node, map the DMA registers, and decode DMA IRQs */
++ np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
++ if (IS_ERR(np)) {
++ dev_err(&pdev->dev, "could not find DMA node\n");
++ ret = PTR_ERR(np);
++ goto free_netdev;
++ }
++ ret = of_address_to_resource(np, 0, &dmares);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to get DMA resource\n");
++ goto free_netdev;
++ }
++ lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares);
++ if (!lp->dma_regs) {
++ dev_err(&pdev->dev, "could not map DMA regs\n");
++ ret = -ENOMEM;
++ goto free_netdev;
+ }
+ lp->rx_irq = irq_of_parse_and_map(np, 1);
+ lp->tx_irq = irq_of_parse_and_map(np, 0);
+ of_node_put(np);
+ if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {
+- dev_err(&op->dev, "could not determine irqs\n");
++ dev_err(&pdev->dev, "could not determine irqs\n");
+ ret = -ENOMEM;
+- goto err_iounmap_2;
++ goto free_netdev;
+ }
+
+ /* Retrieve the MAC address */
+- addr = of_get_property(op->dev.of_node, "local-mac-address", &size);
+- if ((!addr) || (size != 6)) {
+- dev_err(&op->dev, "could not find MAC address\n");
+- ret = -ENODEV;
+- goto err_iounmap_2;
++ ret = of_property_read_u8_array(pdev->dev.of_node,
++ "local-mac-address", mac_addr, 6);
++ if (ret) {
++ dev_err(&pdev->dev, "could not find MAC address\n");
++ goto free_netdev;
+ }
+- axienet_set_mac_address(ndev, (void *) addr);
++ axienet_set_mac_address(ndev, (void *) mac_addr);
+
+ lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
+ lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
+
+- lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
+- ret = axienet_mdio_setup(lp, op->dev.of_node);
+- if (ret)
+- dev_warn(&op->dev, "error registering MDIO bus\n");
++ lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
++ if (lp->phy_node) {
++ ret = axienet_mdio_setup(lp, pdev->dev.of_node);
++ if (ret)
++ dev_warn(&pdev->dev, "error registering MDIO bus\n");
++ }
+
+ ret = register_netdev(lp->ndev);
+ if (ret) {
+ dev_err(lp->dev, "register_netdev() error (%i)\n", ret);
+- goto err_iounmap_2;
++ goto free_netdev;
+ }
+
+ return 0;
+
+-err_iounmap_2:
+- if (lp->dma_regs)
+- iounmap(lp->dma_regs);
+-err_iounmap:
+- iounmap(lp->regs);
+-nodev:
++free_netdev:
+ free_netdev(ndev);
+- ndev = NULL;
++
+ return ret;
+ }
+
+-static int axienet_of_remove(struct platform_device *op)
++static int axienet_remove(struct platform_device *pdev)
+ {
+- struct net_device *ndev = platform_get_drvdata(op);
++ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ axienet_mdio_teardown(lp);
+@@ -1630,17 +1681,14 @@ static int axienet_of_remove(struct plat
+ of_node_put(lp->phy_node);
+ lp->phy_node = NULL;
+
+- iounmap(lp->regs);
+- if (lp->dma_regs)
+- iounmap(lp->dma_regs);
+ free_netdev(ndev);
+
+ return 0;
+ }
+
+-static struct platform_driver axienet_of_driver = {
+- .probe = axienet_of_probe,
+- .remove = axienet_of_remove,
++static struct platform_driver axienet_driver = {
++ .probe = axienet_probe,
++ .remove = axienet_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "xilinx_axienet",
+@@ -1648,7 +1696,7 @@ static struct platform_driver axienet_of
+ },
+ };
+
+-module_platform_driver(axienet_of_driver);
++module_platform_driver(axienet_driver);
+
+ MODULE_DESCRIPTION("Xilinx Axi Ethernet driver");
+ MODULE_AUTHOR("Xilinx");
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+@@ -120,7 +120,8 @@ static int axienet_mdio_write(struct mii
+ * @np: Pointer to device node
+ *
+ * returns: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
+- * mdiobus_alloc (to allocate memory for mii bus structure) fails.
++ * mdiobus_alloc (to allocate memory for mii bus structure)
++ * fails.
+ *
+ * Sets up the MDIO interface by initializing the MDIO clock and enabling the
+ * MDIO interface in hardware. Register the MDIO interface.
+@@ -128,11 +129,12 @@ static int axienet_mdio_write(struct mii
+ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
+ {
+ int ret;
+- u32 clk_div, host_clock;
+- u32 *property_p;
++ u32 clk_div;
+ struct mii_bus *bus;
+ struct resource res;
+ struct device_node *np1;
++ /* the ethernet controller device node */
++ struct device_node *npp = NULL;
+
+ /* clk_div can be calculated by deriving it from the equation:
+ * fMDIO = fHOST / ((1 + clk_div) * 2)
+@@ -158,42 +160,50 @@ int axienet_mdio_setup(struct axienet_lo
+ * fHOST can be read from the flattened device tree as property
+ * "clock-frequency" from the CPU
+ */
+-
+- np1 = of_find_node_by_name(NULL, "cpu");
+- if (!np1) {
+- printk(KERN_WARNING "%s(): Could not find CPU device node.",
+- __func__);
+- printk(KERN_WARNING "Setting MDIO clock divisor to "
+- "default %d\n", DEFAULT_CLOCK_DIVISOR);
+- clk_div = DEFAULT_CLOCK_DIVISOR;
+- goto issue;
+- }
+- property_p = (u32 *) of_get_property(np1, "clock-frequency", NULL);
+- if (!property_p) {
+- printk(KERN_WARNING "%s(): Could not find CPU property: "
+- "clock-frequency.", __func__);
+- printk(KERN_WARNING "Setting MDIO clock divisor to "
+- "default %d\n", DEFAULT_CLOCK_DIVISOR);
++ np1 = of_get_parent(lp->phy_node);
++ if (np1)
++ npp = of_get_parent(np1);
++ if (!npp) {
++ dev_warn(lp->dev,
++ "Could not find ethernet controller device node.");
++ dev_warn(lp->dev,
++ "Setting MDIO clock divisor to default %d\n",
++ DEFAULT_CLOCK_DIVISOR);
+ clk_div = DEFAULT_CLOCK_DIVISOR;
+- of_node_put(np1);
+- goto issue;
++ } else {
++ u32 *property_p;
++
++ property_p = (uint32_t *)of_get_property(npp,
++ "clock-frequency", NULL);
++ if (!property_p) {
++ dev_warn(lp->dev,
++ "Could not find clock ethernet "
++ "controller property.");
++ dev_warn(lp->dev,
++ "Setting MDIO clock divisor to default %d\n",
++ DEFAULT_CLOCK_DIVISOR);
++ clk_div = DEFAULT_CLOCK_DIVISOR;
++ } else {
++ u32 host_clock = be32_to_cpup(property_p);
++
++ clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
++
++ /* If there is any remainder from the division of
++ * fHOST / (MAX_MDIO_FREQ * 2), then we need to add 1
++ * to the clock divisor or we will surely be
++ * above 2.5 MHz
++ */
++ if (host_clock % (MAX_MDIO_FREQ * 2))
++ clk_div++;
++ dev_dbg(lp->dev,
++ "Setting MDIO clock divisor to %u "
++ "based on %u Hz host clock.\n",
++ clk_div, host_clock);
++ }
+ }
+
+- host_clock = be32_to_cpup(property_p);
+- clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
+- /* If there is any remainder from the division of
+- * fHOST / (MAX_MDIO_FREQ * 2), then we need to add
+- * 1 to the clock divisor or we will surely be above 2.5 MHz */
+- if (host_clock % (MAX_MDIO_FREQ * 2))
+- clk_div++;
+-
+- printk(KERN_DEBUG "%s(): Setting MDIO clock divisor to %u based "
+- "on %u Hz host clock.\n", __func__, clk_div, host_clock);
+-
+- of_node_put(np1);
+-issue:
+- axienet_iow(lp, XAE_MDIO_MC_OFFSET,
+- (((u32) clk_div) | XAE_MDIO_MC_MDIOEN_MASK));
++ axienet_iow(lp, XAE_MDIO_MC_OFFSET, (((u32)clk_div) |
++ XAE_MDIO_MC_MDIOEN_MASK));
+
+ ret = axienet_mdio_wait_until_ready(lp);
+ if (ret < 0)
+@@ -203,8 +213,7 @@ issue:
+ if (!bus)
+ return -ENOMEM;
+
+- np1 = of_get_parent(lp->phy_node);
+- of_address_to_resource(np1, 0, &res);
++ of_address_to_resource(npp, 0, &res);
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+ (unsigned long long) res.start);
+
+@@ -233,7 +242,6 @@ issue:
+ void axienet_mdio_teardown(struct axienet_local *lp)
+ {
+ mdiobus_unregister(lp->mii_bus);
+- kfree(lp->mii_bus->irq);
+ mdiobus_free(lp->mii_bus);
+ lp->mii_bus = NULL;
+ }
+--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
++++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+@@ -22,6 +22,7 @@
+ #include <linux/slab.h>
+ #include <linux/of_address.h>
+ #include <linux/of_device.h>
++#include <linux/of_irq.h>
+ #include <linux/of_platform.h>
+ #include <linux/of_mdio.h>
+ #include <linux/of_net.h>
+@@ -44,7 +45,7 @@
+ #define XEL_RPLR_OFFSET 0x100C /* Rx packet length */
+ #define XEL_RSR_OFFSET 0x17FC /* Rx status */
+
+-#define XEL_BUFFER_OFFSET 0x0800 /* Next Tx/Rx buffer's offset */
++#define XEL_BUFFER_OFFSET 0x0800 /* Next Tx/Rx buffer offset */
+
+ /* MDIO Address Register Bit Masks */
+ #define XEL_MDIOADDR_REGADR_MASK 0x0000001F /* Register Address */
+@@ -110,8 +111,8 @@
+ * @next_rx_buf_to_use: next Rx buffer to read from
+ * @base_addr: base address of the Emaclite device
+ * @reset_lock: lock used for synchronization
+- * @deferred_skb: holds an skb (for transmission at a later time) when the
+- * Tx buffer is not free
++ * @deferred_skb: holds an skb (for transmission at a later time) when
++ * the Tx buffer is not free
+ * @phy_dev: pointer to the PHY device
+ * @phy_node: pointer to the PHY device node
+ * @mii_bus: pointer to the MII bus
+@@ -151,8 +152,8 @@ struct net_local {
+ * xemaclite_enable_interrupts - Enable the interrupts for the EmacLite device
+ * @drvdata: Pointer to the Emaclite device private data
+ *
+- * This function enables the Tx and Rx interrupts for the Emaclite device along
+- * with the Global Interrupt Enable.
++ * This function enables the Tx and Rx interrupts for the Emaclite device
++ * along with the Global Interrupt Enable.
+ */
+ static void xemaclite_enable_interrupts(struct net_local *drvdata)
+ {
+@@ -174,7 +175,8 @@ static void xemaclite_enable_interrupts(
+ }
+
+ /* Enable the Rx interrupts for the first buffer */
+- __raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + XEL_RSR_OFFSET);
++ __raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr +
++ XEL_RSR_OFFSET);
+
+ /* Enable the Rx interrupts for the second Buffer if
+ * configured in HW */
+@@ -188,7 +190,8 @@ static void xemaclite_enable_interrupts(
+ }
+
+ /**
+- * xemaclite_disable_interrupts - Disable the interrupts for the EmacLite device
++ * xemaclite_disable_interrupts - Disable the interrupts for the EmacLite
++ * device.
+ * @drvdata: Pointer to the Emaclite device private data
+ *
+ * This function disables the Tx and Rx interrupts for the Emaclite device,
+@@ -209,8 +212,8 @@ static void xemaclite_disable_interrupts
+ /* Disable the Tx interrupts for the second Buffer
+ * if configured in HW */
+ if (drvdata->tx_ping_pong != 0) {
+- reg_data = __raw_readl(drvdata->base_addr + XEL_BUFFER_OFFSET +
+- XEL_TSR_OFFSET);
++ reg_data = __raw_readl(drvdata->base_addr +
++ XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
+ __raw_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK),
+ drvdata->base_addr + XEL_BUFFER_OFFSET +
+ XEL_TSR_OFFSET);
+@@ -225,8 +228,8 @@ static void xemaclite_disable_interrupts
+ * if configured in HW */
+ if (drvdata->rx_ping_pong != 0) {
+
+- reg_data = __raw_readl(drvdata->base_addr + XEL_BUFFER_OFFSET +
+- XEL_RSR_OFFSET);
++ reg_data = __raw_readl(drvdata->base_addr +
++ XEL_BUFFER_OFFSET + XEL_RSR_OFFSET);
+ __raw_writel(reg_data & (~XEL_RSR_RECV_IE_MASK),
+ drvdata->base_addr + XEL_BUFFER_OFFSET +
+ XEL_RSR_OFFSET);
+@@ -234,7 +237,8 @@ static void xemaclite_disable_interrupts
+ }
+
+ /**
+- * xemaclite_aligned_write - Write from 16-bit aligned to 32-bit aligned address
++ * xemaclite_aligned_write - Write from 16-bit aligned to 32-bit aligned
++ * address.
+ * @src_ptr: Void pointer to the 16-bit aligned source address
+ * @dest_ptr: Pointer to the 32-bit aligned destination address
+ * @length: Number bytes to write from source to destination
+@@ -283,8 +287,8 @@ static void xemaclite_aligned_write(void
+ * @dest_ptr: Pointer to the 16-bit aligned destination address
+ * @length: Number bytes to read from source to destination
+ *
+- * This function reads data from a 32-bit aligned address in the EmacLite device
+- * to a 16-bit aligned buffer.
++ * This function reads data from a 32-bit aligned address in the EmacLite
++ * device to a 16-bit aligned buffer.
+ */
+ static void xemaclite_aligned_read(u32 *src_ptr, u8 *dest_ptr,
+ unsigned length)
+@@ -326,14 +330,14 @@ static void xemaclite_aligned_read(u32 *
+ * @data: Pointer to the data to be sent
+ * @byte_count: Total frame size, including header
+ *
+- * This function checks if the Tx buffer of the Emaclite device is free to send
+- * data. If so, it fills the Tx buffer with data for transmission. Otherwise, it
+- * returns an error.
++ * This function checks if the Tx buffer of the Emaclite device is free to
++ * send data. If so, it fills the Tx buffer with data for transmission.
++ * Otherwise, it returns an error.
+ *
+ * Return: 0 upon success or -1 if the buffer(s) are full.
+ *
+- * Note: The maximum Tx packet size can not be more than Ethernet header
+- * (14 Bytes) + Maximum MTU (1500 bytes). This is excluding FCS.
++ * Note: The maximum Tx packet size can not be more than Ethernet header
++ * (14 Bytes) + Maximum MTU (1500 bytes). This is excluding FCS.
+ */
+ static int xemaclite_send_data(struct net_local *drvdata, u8 *data,
+ unsigned int byte_count)
+@@ -687,7 +691,8 @@ static irqreturn_t xemaclite_interrupt(i
+ }
+
+ /* Check if the Transmission for the second buffer is completed */
+- tx_status = __raw_readl(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
++ tx_status = __raw_readl(base_addr + XEL_BUFFER_OFFSET +
++ XEL_TSR_OFFSET);
+ if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) &&
+ (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) {
+
+@@ -1053,7 +1058,7 @@ static int xemaclite_send(struct sk_buff
+ * current transmission is complete */
+ netif_stop_queue(dev);
+ lp->deferred_skb = new_skb;
+- /* Take the time stamp now, since we can't do this in an ISR. */
++ /* Take the time stamp now, since we can't do this in an ISR */
+ skb_tx_timestamp(new_skb);
+ spin_unlock_irqrestore(&lp->reset_lock, flags);
+ return 0;
+@@ -1090,7 +1095,7 @@ static void xemaclite_remove_ndev(struct
+ * This function looks for a property in the device node and returns the value
+ * of the property if its found or 0 if the property is not found.
+ *
+- * Return: Value of the parameter if the parameter is found, or 0 otherwise
++ * Return: Value of the parameter if the parameter is found, or 0 otherwise
+ */
+ static bool get_bool(struct platform_device *ofdev, const char *s)
+ {
+@@ -1172,7 +1177,7 @@ static int xemaclite_of_probe(struct pla
+
+ if (mac_address)
+ /* Set the MAC address. */
+- memcpy(ndev->dev_addr, mac_address, ETH_ALEN);
++ memcpy(ndev->dev_addr, mac_address, 6);
+ else
+ dev_warn(dev, "No MAC address found\n");
+
+--- /dev/null
++++ b/drivers/net/ethernet/xilinx/xilinx_emacps.c
+@@ -0,0 +1,2912 @@
++/*
++ * Xilinx Ethernet: Linux driver for Ethernet.
++ *
++ * Author: Xilinx, Inc.
++ *
++ * 2010 (c) Xilinx, Inc. This file is licensed uner the terms of the GNU
++ * General Public License version 2. This program is licensed "as is"
++ * without any warranty of any kind, whether express or implied.
++ *
++ * This is a driver for xilinx processor sub-system (ps) ethernet device.
++ * This driver is mainly used in Linux 2.6.30 and above and it does _not_
++ * support Linux 2.4 kernel due to certain new features (e.g. NAPI) is
++ * introduced in this driver.
++ *
++ * TODO:
++ * 1. JUMBO frame is not enabled per EPs spec. Please update it if this
++ * support is added in and set MAX_MTU to 9000.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/phy.h>
++#include <linux/mii.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/io.h>
++#include <linux/ethtool.h>
++#include <linux/vmalloc.h>
++#include <linux/version.h>
++#include <linux/of.h>
++#include <linux/interrupt.h>
++#include <linux/clocksource.h>
++#include <linux/net_tstamp.h>
++#include <linux/pm_runtime.h>
++#include <linux/clk.h>
++#include <linux/of_net.h>
++#include <linux/of_address.h>
++#include <linux/of_mdio.h>
++#include <linux/timer.h>
++
++/************************** Constant Definitions *****************************/
++
++/* Must be shorter than length of ethtool_drvinfo.driver field to fit */
++#define DRIVER_NAME "xemacps"
++#define DRIVER_DESCRIPTION "Xilinx Tri-Mode Ethernet MAC driver"
++#define DRIVER_VERSION "1.00a"
++
++/* Transmission timeout is 3 seconds. */
++#define TX_TIMEOUT (3*HZ)
++
++/* for RX skb IP header word-aligned */
++#define RX_IP_ALIGN_OFFSET 2
++
++/* DMA buffer descriptors must be aligned on a 4-byte boundary. */
++#define ALIGNMENT_BD 8
++
++/* Maximum value for hash bits. 2**6 */
++#define XEMACPS_MAX_HASH_BITS 64
++
++/* MDC clock division
++ * currently supporting 8, 16, 32, 48, 64, 96, 128, 224.
++ */
++enum { MDC_DIV_8 = 0, MDC_DIV_16, MDC_DIV_32, MDC_DIV_48,
++MDC_DIV_64, MDC_DIV_96, MDC_DIV_128, MDC_DIV_224 };
++
++/* Specify the receive buffer size in bytes, 64, 128, 192, 10240 */
++#define XEMACPS_RX_BUF_SIZE 1536
++
++/* Number of receive buffer bytes as a unit, this is HW setup */
++#define XEMACPS_RX_BUF_UNIT 64
++
++/* Default SEND and RECV buffer descriptors (BD) numbers.
++ * BD Space needed is (XEMACPS_SEND_BD_CNT+XEMACPS_RECV_BD_CNT)*8
++ */
++#undef DEBUG
++#define DEBUG
++
++#define XEMACPS_SEND_BD_CNT 256
++#define XEMACPS_RECV_BD_CNT 256
++
++#define XEMACPS_NAPI_WEIGHT 64
++
++/* Register offset definitions. Unless otherwise noted, register access is
++ * 32 bit. Names are self explained here.
++ */
++#define XEMACPS_NWCTRL_OFFSET 0x00000000 /* Network Control reg */
++#define XEMACPS_NWCFG_OFFSET 0x00000004 /* Network Config reg */
++#define XEMACPS_NWSR_OFFSET 0x00000008 /* Network Status reg */
++#define XEMACPS_USERIO_OFFSET 0x0000000C /* User IO reg */
++#define XEMACPS_DMACR_OFFSET 0x00000010 /* DMA Control reg */
++#define XEMACPS_TXSR_OFFSET 0x00000014 /* TX Status reg */
++#define XEMACPS_RXQBASE_OFFSET 0x00000018 /* RX Q Base address reg */
++#define XEMACPS_TXQBASE_OFFSET 0x0000001C /* TX Q Base address reg */
++#define XEMACPS_RXSR_OFFSET 0x00000020 /* RX Status reg */
++#define XEMACPS_ISR_OFFSET 0x00000024 /* Interrupt Status reg */
++#define XEMACPS_IER_OFFSET 0x00000028 /* Interrupt Enable reg */
++#define XEMACPS_IDR_OFFSET 0x0000002C /* Interrupt Disable reg */
++#define XEMACPS_IMR_OFFSET 0x00000030 /* Interrupt Mask reg */
++#define XEMACPS_PHYMNTNC_OFFSET 0x00000034 /* Phy Maintaince reg */
++#define XEMACPS_RXPAUSE_OFFSET 0x00000038 /* RX Pause Time reg */
++#define XEMACPS_TXPAUSE_OFFSET 0x0000003C /* TX Pause Time reg */
++#define XEMACPS_HASHL_OFFSET 0x00000080 /* Hash Low address reg */
++#define XEMACPS_HASHH_OFFSET 0x00000084 /* Hash High address reg */
++#define XEMACPS_LADDR1L_OFFSET 0x00000088 /* Specific1 addr low */
++#define XEMACPS_LADDR1H_OFFSET 0x0000008C /* Specific1 addr high */
++#define XEMACPS_LADDR2L_OFFSET 0x00000090 /* Specific2 addr low */
++#define XEMACPS_LADDR2H_OFFSET 0x00000094 /* Specific2 addr high */
++#define XEMACPS_LADDR3L_OFFSET 0x00000098 /* Specific3 addr low */
++#define XEMACPS_LADDR3H_OFFSET 0x0000009C /* Specific3 addr high */
++#define XEMACPS_LADDR4L_OFFSET 0x000000A0 /* Specific4 addr low */
++#define XEMACPS_LADDR4H_OFFSET 0x000000A4 /* Specific4 addr high */
++#define XEMACPS_MATCH1_OFFSET 0x000000A8 /* Type ID1 Match reg */
++#define XEMACPS_MATCH2_OFFSET 0x000000AC /* Type ID2 Match reg */
++#define XEMACPS_MATCH3_OFFSET 0x000000B0 /* Type ID3 Match reg */
++#define XEMACPS_MATCH4_OFFSET 0x000000B4 /* Type ID4 Match reg */
++#define XEMACPS_WOL_OFFSET 0x000000B8 /* Wake on LAN reg */
++#define XEMACPS_STRETCH_OFFSET 0x000000BC /* IPG Stretch reg */
++#define XEMACPS_SVLAN_OFFSET 0x000000C0 /* Stacked VLAN reg */
++#define XEMACPS_MODID_OFFSET 0x000000FC /* Module ID reg */
++#define XEMACPS_OCTTXL_OFFSET 0x00000100 /* Octects transmitted Low
++ reg */
++#define XEMACPS_OCTTXH_OFFSET 0x00000104 /* Octects transmitted High
++ reg */
++#define XEMACPS_TXCNT_OFFSET 0x00000108 /* Error-free Frmaes
++ transmitted counter */
++#define XEMACPS_TXBCCNT_OFFSET 0x0000010C /* Error-free Broadcast
++ Frames counter*/
++#define XEMACPS_TXMCCNT_OFFSET 0x00000110 /* Error-free Multicast
++ Frame counter */
++#define XEMACPS_TXPAUSECNT_OFFSET 0x00000114 /* Pause Frames Transmitted
++ Counter */
++#define XEMACPS_TX64CNT_OFFSET 0x00000118 /* Error-free 64 byte Frames
++ Transmitted counter */
++#define XEMACPS_TX65CNT_OFFSET 0x0000011C /* Error-free 65-127 byte
++ Frames Transmitted counter */
++#define XEMACPS_TX128CNT_OFFSET 0x00000120 /* Error-free 128-255 byte
++ Frames Transmitted counter */
++#define XEMACPS_TX256CNT_OFFSET 0x00000124 /* Error-free 256-511 byte
++ Frames transmitted counter */
++#define XEMACPS_TX512CNT_OFFSET 0x00000128 /* Error-free 512-1023 byte
++ Frames transmitted counter */
++#define XEMACPS_TX1024CNT_OFFSET 0x0000012C /* Error-free 1024-1518 byte
++ Frames transmitted counter */
++#define XEMACPS_TX1519CNT_OFFSET 0x00000130 /* Error-free larger than
++ 1519 byte Frames transmitted
++ Counter */
++#define XEMACPS_TXURUNCNT_OFFSET 0x00000134 /* TX under run error
++ Counter */
++#define XEMACPS_SNGLCOLLCNT_OFFSET 0x00000138 /* Single Collision Frame
++ Counter */
++#define XEMACPS_MULTICOLLCNT_OFFSET 0x0000013C /* Multiple Collision Frame
++ Counter */
++#define XEMACPS_EXCESSCOLLCNT_OFFSET 0x00000140 /* Excessive Collision Frame
++ Counter */
++#define XEMACPS_LATECOLLCNT_OFFSET 0x00000144 /* Late Collision Frame
++ Counter */
++#define XEMACPS_TXDEFERCNT_OFFSET 0x00000148 /* Deferred Transmission
++ Frame Counter */
++#define XEMACPS_CSENSECNT_OFFSET 0x0000014C /* Carrier Sense Error
++ Counter */
++#define XEMACPS_OCTRXL_OFFSET 0x00000150 /* Octects Received register
++ Low */
++#define XEMACPS_OCTRXH_OFFSET 0x00000154 /* Octects Received register
++ High */
++#define XEMACPS_RXCNT_OFFSET 0x00000158 /* Error-free Frames
++ Received Counter */
++#define XEMACPS_RXBROADCNT_OFFSET 0x0000015C /* Error-free Broadcast
++ Frames Received Counter */
++#define XEMACPS_RXMULTICNT_OFFSET 0x00000160 /* Error-free Multicast
++ Frames Received Counter */
++#define XEMACPS_RXPAUSECNT_OFFSET 0x00000164 /* Pause Frames
++ Received Counter */
++#define XEMACPS_RX64CNT_OFFSET 0x00000168 /* Error-free 64 byte Frames
++ Received Counter */
++#define XEMACPS_RX65CNT_OFFSET 0x0000016C /* Error-free 65-127 byte
++ Frames Received Counter */
++#define XEMACPS_RX128CNT_OFFSET 0x00000170 /* Error-free 128-255 byte
++ Frames Received Counter */
++#define XEMACPS_RX256CNT_OFFSET 0x00000174 /* Error-free 256-512 byte
++ Frames Received Counter */
++#define XEMACPS_RX512CNT_OFFSET 0x00000178 /* Error-free 512-1023 byte
++ Frames Received Counter */
++#define XEMACPS_RX1024CNT_OFFSET 0x0000017C /* Error-free 1024-1518 byte
++ Frames Received Counter */
++#define XEMACPS_RX1519CNT_OFFSET 0x00000180 /* Error-free 1519-max byte
++ Frames Received Counter */
++#define XEMACPS_RXUNDRCNT_OFFSET 0x00000184 /* Undersize Frames Received
++ Counter */
++#define XEMACPS_RXOVRCNT_OFFSET 0x00000188 /* Oversize Frames Received
++ Counter */
++#define XEMACPS_RXJABCNT_OFFSET 0x0000018C /* Jabbers Received
++ Counter */
++#define XEMACPS_RXFCSCNT_OFFSET 0x00000190 /* Frame Check Sequence
++ Error Counter */
++#define XEMACPS_RXLENGTHCNT_OFFSET 0x00000194 /* Length Field Error
++ Counter */
++#define XEMACPS_RXSYMBCNT_OFFSET 0x00000198 /* Symbol Error Counter */
++#define XEMACPS_RXALIGNCNT_OFFSET 0x0000019C /* Alignment Error
++ Counter */
++#define XEMACPS_RXRESERRCNT_OFFSET 0x000001A0 /* Receive Resource Error
++ Counter */
++#define XEMACPS_RXORCNT_OFFSET 0x000001A4 /* Receive Overrun */
++#define XEMACPS_RXIPCCNT_OFFSET 0x000001A8 /* IP header Checksum Error
++ Counter */
++#define XEMACPS_RXTCPCCNT_OFFSET 0x000001AC /* TCP Checksum Error
++ Counter */
++#define XEMACPS_RXUDPCCNT_OFFSET 0x000001B0 /* UDP Checksum Error
++ Counter */
++
++#define XEMACPS_1588S_OFFSET 0x000001D0 /* 1588 Timer Seconds */
++#define XEMACPS_1588NS_OFFSET 0x000001D4 /* 1588 Timer Nanoseconds */
++#define XEMACPS_1588ADJ_OFFSET 0x000001D8 /* 1588 Timer Adjust */
++#define XEMACPS_1588INC_OFFSET 0x000001DC /* 1588 Timer Increment */
++#define XEMACPS_PTPETXS_OFFSET 0x000001E0 /* PTP Event Frame
++ Transmitted Seconds */
++#define XEMACPS_PTPETXNS_OFFSET 0x000001E4 /* PTP Event Frame
++ Transmitted Nanoseconds */
++#define XEMACPS_PTPERXS_OFFSET 0x000001E8 /* PTP Event Frame Received
++ Seconds */
++#define XEMACPS_PTPERXNS_OFFSET 0x000001EC /* PTP Event Frame Received
++ Nanoseconds */
++#define XEMACPS_PTPPTXS_OFFSET 0x000001E0 /* PTP Peer Frame
++ Transmitted Seconds */
++#define XEMACPS_PTPPTXNS_OFFSET 0x000001E4 /* PTP Peer Frame
++ Transmitted Nanoseconds */
++#define XEMACPS_PTPPRXS_OFFSET 0x000001E8 /* PTP Peer Frame Received
++ Seconds */
++#define XEMACPS_PTPPRXNS_OFFSET 0x000001EC /* PTP Peer Frame Received
++ Nanoseconds */
++
++/* network control register bit definitions */
++#define XEMACPS_NWCTRL_FLUSH_DPRAM_MASK 0x00040000
++#define XEMACPS_NWCTRL_RXTSTAMP_MASK 0x00008000 /* RX Timestamp in CRC */
++#define XEMACPS_NWCTRL_ZEROPAUSETX_MASK 0x00001000 /* Transmit zero quantum
++ pause frame */
++#define XEMACPS_NWCTRL_PAUSETX_MASK 0x00000800 /* Transmit pause frame */
++#define XEMACPS_NWCTRL_HALTTX_MASK 0x00000400 /* Halt transmission
++ after current frame */
++#define XEMACPS_NWCTRL_STARTTX_MASK 0x00000200 /* Start tx (tx_go) */
++
++#define XEMACPS_NWCTRL_STATWEN_MASK 0x00000080 /* Enable writing to
++ stat counters */
++#define XEMACPS_NWCTRL_STATINC_MASK 0x00000040 /* Increment statistic
++ registers */
++#define XEMACPS_NWCTRL_STATCLR_MASK 0x00000020 /* Clear statistic
++ registers */
++#define XEMACPS_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */
++#define XEMACPS_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */
++#define XEMACPS_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */
++#define XEMACPS_NWCTRL_LOOPEN_MASK 0x00000002 /* local loopback */
++
++/* name network configuration register bit definitions */
++#define XEMACPS_NWCFG_BADPREAMBEN_MASK 0x20000000 /* disable rejection of
++ non-standard preamble */
++#define XEMACPS_NWCFG_IPDSTRETCH_MASK 0x10000000 /* enable transmit IPG */
++#define XEMACPS_NWCFG_FCSIGNORE_MASK 0x04000000 /* disable rejection of
++ FCS error */
++#define XEMACPS_NWCFG_HDRXEN_MASK 0x02000000 /* RX half duplex */
++#define XEMACPS_NWCFG_RXCHKSUMEN_MASK 0x01000000 /* enable RX checksum
++ offload */
++#define XEMACPS_NWCFG_PAUSECOPYDI_MASK 0x00800000 /* Do not copy pause
++ Frames to memory */
++#define XEMACPS_NWCFG_MDC_SHIFT_MASK 18 /* shift bits for MDC */
++#define XEMACPS_NWCFG_MDCCLKDIV_MASK 0x001C0000 /* MDC Mask PCLK divisor */
++#define XEMACPS_NWCFG_FCSREM_MASK 0x00020000 /* Discard FCS from
++ received frames */
++#define XEMACPS_NWCFG_LENGTHERRDSCRD_MASK 0x00010000
++/* RX length error discard */
++#define XEMACPS_NWCFG_RXOFFS_MASK 0x0000C000 /* RX buffer offset */
++#define XEMACPS_NWCFG_PAUSEEN_MASK 0x00002000 /* Enable pause TX */
++#define XEMACPS_NWCFG_RETRYTESTEN_MASK 0x00001000 /* Retry test */
++#define XEMACPS_NWCFG_1000_MASK 0x00000400 /* Gigbit mode */
++#define XEMACPS_NWCFG_EXTADDRMATCHEN_MASK 0x00000200
++/* External address match enable */
++#define XEMACPS_NWCFG_UCASTHASHEN_MASK 0x00000080 /* Receive unicast hash
++ frames */
++#define XEMACPS_NWCFG_MCASTHASHEN_MASK 0x00000040 /* Receive multicast hash
++ frames */
++#define XEMACPS_NWCFG_BCASTDI_MASK 0x00000020 /* Do not receive
++ broadcast frames */
++#define XEMACPS_NWCFG_COPYALLEN_MASK 0x00000010 /* Copy all frames */
++
++#define XEMACPS_NWCFG_NVLANDISC_MASK 0x00000004 /* Receive only VLAN
++ frames */
++#define XEMACPS_NWCFG_FDEN_MASK 0x00000002 /* Full duplex */
++#define XEMACPS_NWCFG_100_MASK 0x00000001 /* 10 or 100 Mbs */
++
++/* network status register bit definitaions */
++#define XEMACPS_NWSR_MDIOIDLE_MASK 0x00000004 /* PHY management idle */
++#define XEMACPS_NWSR_MDIO_MASK 0x00000002 /* Status of mdio_in */
++
++/* MAC address register word 1 mask */
++#define XEMACPS_LADDR_MACH_MASK 0x0000FFFF /* Address bits[47:32]
++ bit[31:0] are in BOTTOM */
++
++/* DMA control register bit definitions */
++#define XEMACPS_DMACR_RXBUF_MASK 0x00FF0000 /* Mask bit for RX buffer
++ size */
++#define XEMACPS_DMACR_RXBUF_SHIFT 16 /* Shift bit for RX buffer
++ size */
++#define XEMACPS_DMACR_TCPCKSUM_MASK 0x00000800 /* enable/disable TX
++ checksum offload */
++#define XEMACPS_DMACR_TXSIZE_MASK 0x00000400 /* TX buffer memory size */
++#define XEMACPS_DMACR_RXSIZE_MASK 0x00000300 /* RX buffer memory size */
++#define XEMACPS_DMACR_ENDIAN_MASK 0x00000080 /* Endian configuration */
++#define XEMACPS_DMACR_BLENGTH_MASK 0x0000001F /* Buffer burst length */
++#define XEMACPS_DMACR_BLENGTH_INCR16 0x00000010 /* Buffer burst length */
++#define XEMACPS_DMACR_BLENGTH_INCR8 0x00000008 /* Buffer burst length */
++#define XEMACPS_DMACR_BLENGTH_INCR4 0x00000004 /* Buffer burst length */
++#define XEMACPS_DMACR_BLENGTH_SINGLE 0x00000002 /* Buffer burst length */
++
++/* transmit status register bit definitions */
++#define XEMACPS_TXSR_HRESPNOK_MASK 0x00000100 /* Transmit hresp not OK */
++#define XEMACPS_TXSR_COL1000_MASK 0x00000080 /* Collision Gbs mode */
++#define XEMACPS_TXSR_URUN_MASK 0x00000040 /* Transmit underrun */
++#define XEMACPS_TXSR_TXCOMPL_MASK 0x00000020 /* Transmit completed OK */
++#define XEMACPS_TXSR_BUFEXH_MASK 0x00000010 /* Transmit buffs exhausted
++ mid frame */
++#define XEMACPS_TXSR_TXGO_MASK 0x00000008 /* Status of go flag */
++#define XEMACPS_TXSR_RXOVR_MASK 0x00000004 /* Retry limit exceeded */
++#define XEMACPS_TXSR_COL100_MASK 0x00000002 /* Collision 10/100 mode */
++#define XEMACPS_TXSR_USEDREAD_MASK 0x00000001 /* TX buffer used bit set */
++
++#define XEMACPS_TXSR_ERROR_MASK (XEMACPS_TXSR_HRESPNOK_MASK | \
++ XEMACPS_TXSR_COL1000_MASK | \
++ XEMACPS_TXSR_URUN_MASK | \
++ XEMACPS_TXSR_BUFEXH_MASK | \
++ XEMACPS_TXSR_RXOVR_MASK | \
++ XEMACPS_TXSR_COL100_MASK | \
++ XEMACPS_TXSR_USEDREAD_MASK)
++
++/* receive status register bit definitions */
++#define XEMACPS_RXSR_HRESPNOK_MASK 0x00000008 /* Receive hresp not OK */
++#define XEMACPS_RXSR_RXOVR_MASK 0x00000004 /* Receive overrun */
++#define XEMACPS_RXSR_FRAMERX_MASK 0x00000002 /* Frame received OK */
++#define XEMACPS_RXSR_BUFFNA_MASK 0x00000001 /* RX buffer used bit set */
++
++#define XEMACPS_RXSR_ERROR_MASK (XEMACPS_RXSR_HRESPNOK_MASK | \
++ XEMACPS_RXSR_RXOVR_MASK | \
++ XEMACPS_RXSR_BUFFNA_MASK)
++
++/* interrupts bit definitions
++ * Bits definitions are same in XEMACPS_ISR_OFFSET,
++ * XEMACPS_IER_OFFSET, XEMACPS_IDR_OFFSET, and XEMACPS_IMR_OFFSET
++ */
++#define XEMACPS_IXR_PTPPSTX_MASK 0x02000000 /* PTP Psync transmitted */
++#define XEMACPS_IXR_PTPPDRTX_MASK 0x01000000 /* PTP Pdelay_req
++ transmitted */
++#define XEMACPS_IXR_PTPSTX_MASK 0x00800000 /* PTP Sync transmitted */
++#define XEMACPS_IXR_PTPDRTX_MASK 0x00400000 /* PTP Delay_req
++ transmitted */
++#define XEMACPS_IXR_PTPPSRX_MASK 0x00200000 /* PTP Psync received */
++#define XEMACPS_IXR_PTPPDRRX_MASK 0x00100000 /* PTP Pdelay_req
++ received */
++#define XEMACPS_IXR_PTPSRX_MASK 0x00080000 /* PTP Sync received */
++#define XEMACPS_IXR_PTPDRRX_MASK 0x00040000 /* PTP Delay_req received */
++#define XEMACPS_IXR_PAUSETX_MASK 0x00004000 /* Pause frame
++ transmitted */
++#define XEMACPS_IXR_PAUSEZERO_MASK 0x00002000 /* Pause time has reached
++ zero */
++#define XEMACPS_IXR_PAUSENZERO_MASK 0x00001000 /* Pause frame received */
++#define XEMACPS_IXR_HRESPNOK_MASK 0x00000800 /* hresp not ok */
++#define XEMACPS_IXR_RXOVR_MASK 0x00000400 /* Receive overrun
++ occurred */
++#define XEMACPS_IXR_TXCOMPL_MASK 0x00000080 /* Frame transmitted ok */
++#define XEMACPS_IXR_TXEXH_MASK 0x00000040 /* Transmit err occurred or
++ no buffers*/
++#define XEMACPS_IXR_RETRY_MASK 0x00000020 /* Retry limit exceeded */
++#define XEMACPS_IXR_URUN_MASK 0x00000010 /* Transmit underrun */
++#define XEMACPS_IXR_TXUSED_MASK 0x00000008 /* Tx buffer used bit read */
++#define XEMACPS_IXR_RXUSED_MASK 0x00000004 /* Rx buffer used bit read */
++#define XEMACPS_IXR_FRAMERX_MASK 0x00000002 /* Frame received ok */
++#define XEMACPS_IXR_MGMNT_MASK 0x00000001 /* PHY management complete */
++#define XEMACPS_IXR_ALL_MASK 0x03FC7FFE /* Everything except MDIO */
++
++#define XEMACPS_IXR_TX_ERR_MASK (XEMACPS_IXR_TXEXH_MASK | \
++ XEMACPS_IXR_RETRY_MASK | \
++ XEMACPS_IXR_URUN_MASK | \
++ XEMACPS_IXR_TXUSED_MASK)
++
++#define XEMACPS_IXR_RX_ERR_MASK (XEMACPS_IXR_HRESPNOK_MASK | \
++ XEMACPS_IXR_RXUSED_MASK | \
++ XEMACPS_IXR_RXOVR_MASK)
++/* PHY Maintenance bit definitions */
++#define XEMACPS_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */
++#define XEMACPS_PHYMNTNC_OP_R_MASK 0x20000000 /* read operation */
++#define XEMACPS_PHYMNTNC_OP_W_MASK 0x10000000 /* write operation */
++#define XEMACPS_PHYMNTNC_ADDR_MASK 0x0F800000 /* Address bits */
++#define XEMACPS_PHYMNTNC_REG_MASK 0x007C0000 /* register bits */
++#define XEMACPS_PHYMNTNC_DATA_MASK 0x0000FFFF /* data bits */
++#define XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK 23 /* Shift bits for PHYAD */
++#define XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK 18 /* Shift bits for PHREG */
++
++/* Wake on LAN bit definition */
++#define XEMACPS_WOL_MCAST_MASK 0x00080000
++#define XEMACPS_WOL_SPEREG1_MASK 0x00040000
++#define XEMACPS_WOL_ARP_MASK 0x00020000
++#define XEMACPS_WOL_MAGIC_MASK 0x00010000
++#define XEMACPS_WOL_ARP_ADDR_MASK 0x0000FFFF
++
++/* Buffer descriptor status words offset */
++#define XEMACPS_BD_ADDR_OFFSET 0x00000000 /**< word 0/addr of BDs */
++#define XEMACPS_BD_STAT_OFFSET 0x00000004 /**< word 1/status of BDs */
++
++/* Transmit buffer descriptor status words bit positions.
++ * Transmit buffer descriptor consists of two 32-bit registers,
++ * the first - word0 contains a 32-bit address pointing to the location of
++ * the transmit data.
++ * The following register - word1, consists of various information to
++ * control transmit process. After transmit, this is updated with status
++ * information, whether the frame was transmitted OK or why it had failed.
++ */
++#define XEMACPS_TXBUF_USED_MASK 0x80000000 /* Used bit. */
++#define XEMACPS_TXBUF_WRAP_MASK 0x40000000 /* Wrap bit, last
++ descriptor */
++#define XEMACPS_TXBUF_RETRY_MASK 0x20000000 /* Retry limit exceeded */
++#define XEMACPS_TXBUF_EXH_MASK 0x08000000 /* Buffers exhausted */
++#define XEMACPS_TXBUF_LAC_MASK 0x04000000 /* Late collision. */
++#define XEMACPS_TXBUF_NOCRC_MASK 0x00010000 /* No CRC */
++#define XEMACPS_TXBUF_LAST_MASK 0x00008000 /* Last buffer */
++#define XEMACPS_TXBUF_LEN_MASK 0x00003FFF /* Mask for length field */
++
++#define XEMACPS_TXBUF_ERR_MASK 0x3C000000 /* Mask for length field */
++
++/* Receive buffer descriptor status words bit positions.
++ * Receive buffer descriptor consists of two 32-bit registers,
++ * the first - word0 contains a 32-bit word aligned address pointing to the
++ * address of the buffer. The lower two bits make up the wrap bit indicating
++ * the last descriptor and the ownership bit to indicate it has been used.
++ * The following register - word1, contains status information regarding why
++ * the frame was received (the filter match condition) as well as other
++ * useful info.
++ */
++#define XEMACPS_RXBUF_BCAST_MASK 0x80000000 /* Broadcast frame */
++#define XEMACPS_RXBUF_MULTIHASH_MASK 0x40000000 /* Multicast hashed frame */
++#define XEMACPS_RXBUF_UNIHASH_MASK 0x20000000 /* Unicast hashed frame */
++#define XEMACPS_RXBUF_EXH_MASK 0x08000000 /* buffer exhausted */
++#define XEMACPS_RXBUF_AMATCH_MASK 0x06000000 /* Specific address
++ matched */
++#define XEMACPS_RXBUF_IDFOUND_MASK 0x01000000 /* Type ID matched */
++#define XEMACPS_RXBUF_IDMATCH_MASK 0x00C00000 /* ID matched mask */
++#define XEMACPS_RXBUF_VLAN_MASK 0x00200000 /* VLAN tagged */
++#define XEMACPS_RXBUF_PRI_MASK 0x00100000 /* Priority tagged */
++#define XEMACPS_RXBUF_VPRI_MASK 0x000E0000 /* Vlan priority */
++#define XEMACPS_RXBUF_CFI_MASK 0x00010000 /* CFI frame */
++#define XEMACPS_RXBUF_EOF_MASK 0x00008000 /* End of frame. */
++#define XEMACPS_RXBUF_SOF_MASK 0x00004000 /* Start of frame. */
++#define XEMACPS_RXBUF_LEN_MASK 0x00003FFF /* Mask for length field */
++
++#define XEMACPS_RXBUF_WRAP_MASK 0x00000002 /* Wrap bit, last BD */
++#define XEMACPS_RXBUF_NEW_MASK 0x00000001 /* Used bit.. */
++#define XEMACPS_RXBUF_ADD_MASK 0xFFFFFFFC /* Mask for address */
++
++#define XEAMCPS_GEN_PURPOSE_TIMER_LOAD 100 /* timeout value is msecs */
++
++#define XEMACPS_GMII2RGMII_FULLDPLX BMCR_FULLDPLX
++#define XEMACPS_GMII2RGMII_SPEED1000 BMCR_SPEED1000
++#define XEMACPS_GMII2RGMII_SPEED100 BMCR_SPEED100
++#define XEMACPS_GMII2RGMII_REG_NUM 0x10
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++#define NS_PER_SEC 1000000000ULL /* Nanoseconds per
++ second */
++#endif
++
++#define xemacps_read(base, reg) \
++ __raw_readl(((void __iomem *)(base)) + (reg))
++#define xemacps_write(base, reg, val) \
++ __raw_writel((val), ((void __iomem *)(base)) + (reg))
++
++struct ring_info {
++ struct sk_buff *skb;
++ dma_addr_t mapping;
++ size_t len;
++};
++
++/* DMA buffer descriptor structure. Each BD is two words */
++struct xemacps_bd {
++ u32 addr;
++ u32 ctrl;
++};
++
++
++/* Our private device data. */
++struct net_local {
++ void __iomem *baseaddr;
++ struct clk *devclk;
++ struct clk *aperclk;
++ struct notifier_block clk_rate_change_nb;
++
++ struct device_node *phy_node;
++ struct device_node *gmii2rgmii_phy_node;
++ struct ring_info *tx_skb;
++ struct ring_info *rx_skb;
++
++ struct xemacps_bd *rx_bd;
++ struct xemacps_bd *tx_bd;
++
++ dma_addr_t rx_bd_dma; /* physical address */
++ dma_addr_t tx_bd_dma; /* physical address */
++
++ u32 tx_bd_ci;
++ u32 tx_bd_tail;
++ u32 rx_bd_ci;
++
++ u32 tx_bd_freecnt;
++
++ spinlock_t tx_lock;
++ spinlock_t rx_lock;
++ spinlock_t nwctrlreg_lock;
++
++ struct platform_device *pdev;
++ struct net_device *ndev; /* this device */
++ struct tasklet_struct tx_bdreclaim_tasklet;
++ struct workqueue_struct *txtimeout_handler_wq;
++ struct work_struct txtimeout_reinit;
++
++ struct napi_struct napi; /* napi information for device */
++ struct net_device_stats stats; /* Statistics for this device */
++
++ struct timer_list gen_purpose_timer; /* Used for stats update */
++
++ /* Manage internal timer for packet timestamping */
++ struct cyclecounter cycles;
++ struct timecounter clock;
++ struct hwtstamp_config hwtstamp_config;
++
++ struct mii_bus *mii_bus;
++ struct phy_device *phy_dev;
++ struct phy_device *gmii2rgmii_phy_dev;
++ phy_interface_t phy_interface;
++ unsigned int link;
++ unsigned int speed;
++ unsigned int duplex;
++ /* RX ip/tcp/udp checksum */
++ unsigned ip_summed;
++ unsigned int enetnum;
++ unsigned int lastrxfrmscntr;
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++ unsigned int ptpenetclk;
++#endif
++};
++#define to_net_local(_nb) container_of(_nb, struct net_local,\
++ clk_rate_change_nb)
++
++static struct net_device_ops netdev_ops;
++
++/**
++ * xemacps_mdio_read - Read current value of phy register indicated by
++ * phyreg.
++ * @bus: mdio bus
++ * @mii_id: mii id
++ * @phyreg: phy register to be read
++ *
++ * @return: value read from specified phy register.
++ *
++ * note: This is for 802.3 clause 22 phys access. For 802.3 clause 45 phys
++ * access, set bit 30 to be 1. e.g. change XEMACPS_PHYMNTNC_OP_MASK to
++ * 0x00020000.
++ */
++static int xemacps_mdio_read(struct mii_bus *bus, int mii_id, int phyreg)
++{
++ struct net_local *lp = bus->priv;
++ u32 regval;
++ int value;
++ volatile u32 ipisr;
++
++ regval = XEMACPS_PHYMNTNC_OP_MASK;
++ regval |= XEMACPS_PHYMNTNC_OP_R_MASK;
++ regval |= (mii_id << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK);
++ regval |= (phyreg << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK);
++
++ xemacps_write(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET, regval);
++
++ /* wait for end of transfer */
++ do {
++ cpu_relax();
++ ipisr = xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET);
++ } while ((ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0);
++
++ value = xemacps_read(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET) &
++ XEMACPS_PHYMNTNC_DATA_MASK;
++
++ return value;
++}
++
++/**
++ * xemacps_mdio_write - Write passed in value to phy register indicated
++ * by phyreg.
++ * @bus: mdio bus
++ * @mii_id: mii id
++ * @phyreg: phy register to be configured.
++ * @value: value to be written to phy register.
++ * return 0. This API requires to be int type or compile warning generated
++ *
++ * note: This is for 802.3 clause 22 phys access. For 802.3 clause 45 phys
++ * access, set bit 30 to be 1. e.g. change XEMACPS_PHYMNTNC_OP_MASK to
++ * 0x00020000.
++ */
++static int xemacps_mdio_write(struct mii_bus *bus, int mii_id, int phyreg,
++ u16 value)
++{
++ struct net_local *lp = bus->priv;
++ u32 regval;
++ volatile u32 ipisr;
++
++ regval = XEMACPS_PHYMNTNC_OP_MASK;
++ regval |= XEMACPS_PHYMNTNC_OP_W_MASK;
++ regval |= (mii_id << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK);
++ regval |= (phyreg << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK);
++ regval |= value;
++
++ xemacps_write(lp->baseaddr, XEMACPS_PHYMNTNC_OFFSET, regval);
++
++ /* wait for end of transfer */
++ do {
++ cpu_relax();
++ ipisr = xemacps_read(lp->baseaddr, XEMACPS_NWSR_OFFSET);
++ } while ((ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0);
++
++ return 0;
++}
++
++
++/**
++ * xemacps_mdio_reset - mdio reset. It seems to be required per open
++ * source documentation phy.txt. But there is no reset in this device.
++ * Provide function API for now.
++ * @bus: mdio bus
++ **/
++static int xemacps_mdio_reset(struct mii_bus *bus)
++{
++ return 0;
++}
++
++/**
++ * xemacps_set_freq() - Set a clock to a new frequency
++ * @clk Pointer to the clock to change
++ * @rate New frequency in Hz
++ * @dev Pointer to the struct device
++ */
++static void xemacps_set_freq(struct clk *clk, long rate, struct device *dev)
++{
++ rate = clk_round_rate(clk, rate);
++ if (rate < 0)
++ return;
++
++ dev_info(dev, "Set clk to %ld Hz\n", rate);
++ if (clk_set_rate(clk, rate))
++ dev_err(dev, "Setting new clock rate failed.\n");
++}
++
++/**
++ * xemacps_adjust_link - handles link status changes, such as speed,
++ * duplex, up/down, ...
++ * @ndev: network device
++ */
++static void xemacps_adjust_link(struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ struct phy_device *phydev = lp->phy_dev;
++ struct phy_device *gmii2rgmii_phydev = lp->gmii2rgmii_phy_dev;
++ int status_change = 0;
++ u32 regval;
++ u16 gmii2rgmii_reg = 0;
++
++ if (phydev->link) {
++ if ((lp->speed != phydev->speed) ||
++ (lp->duplex != phydev->duplex)) {
++ regval = xemacps_read(lp->baseaddr,
++ XEMACPS_NWCFG_OFFSET);
++ regval &= ~(XEMACPS_NWCFG_FDEN_MASK |
++ XEMACPS_NWCFG_1000_MASK |
++ XEMACPS_NWCFG_100_MASK);
++
++ if (phydev->duplex) {
++ regval |= XEMACPS_NWCFG_FDEN_MASK;
++ gmii2rgmii_reg |= XEMACPS_GMII2RGMII_FULLDPLX;
++ }
++
++ if (phydev->speed == SPEED_1000) {
++ regval |= XEMACPS_NWCFG_1000_MASK;
++ gmii2rgmii_reg |= XEMACPS_GMII2RGMII_SPEED1000;
++ xemacps_set_freq(lp->devclk, 125000000,
++ &lp->pdev->dev);
++ } else if (phydev->speed == SPEED_100) {
++ regval |= XEMACPS_NWCFG_100_MASK;
++ gmii2rgmii_reg |= XEMACPS_GMII2RGMII_SPEED100;
++ xemacps_set_freq(lp->devclk, 25000000,
++ &lp->pdev->dev);
++ } else if (phydev->speed == SPEED_10) {
++ xemacps_set_freq(lp->devclk, 2500000,
++ &lp->pdev->dev);
++ } else {
++ dev_err(&lp->pdev->dev,
++ "%s: unknown PHY speed %d\n",
++ __func__, phydev->speed);
++ return;
++ }
++
++ xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET,
++ regval);
++
++ if (gmii2rgmii_phydev != NULL) {
++ xemacps_mdio_write(lp->mii_bus,
++ gmii2rgmii_phydev->addr,
++ XEMACPS_GMII2RGMII_REG_NUM,
++ gmii2rgmii_reg);
++ }
++
++ lp->speed = phydev->speed;
++ lp->duplex = phydev->duplex;
++ status_change = 1;
++ }
++ }
++
++ if (phydev->link != lp->link) {
++ lp->link = phydev->link;
++ status_change = 1;
++ }
++
++ if (status_change) {
++ if (phydev->link)
++ dev_info(&lp->pdev->dev, "link up (%d/%s)\n",
++ phydev->speed,
++ DUPLEX_FULL == phydev->duplex ?
++ "FULL" : "HALF");
++ else
++ dev_info(&lp->pdev->dev, "link down\n");
++ }
++}
++
++static int xemacps_clk_notifier_cb(struct notifier_block *nb, unsigned long
++ event, void *data)
++{
++/*
++ struct clk_notifier_data *ndata = data;
++ struct net_local *nl = to_net_local(nb);
++*/
++
++ switch (event) {
++ case PRE_RATE_CHANGE:
++ /* if a rate change is announced we need to check whether we
++ * can maintain the current frequency by changing the clock
++ * dividers.
++ * I don't see how this can be done using the current fmwk!?
++ * For now we always allow the rate change. Otherwise we would
++ * even prevent ourself to change the rate.
++ */
++ return NOTIFY_OK;
++ case POST_RATE_CHANGE:
++ /* not sure this will work. actually i'm sure it does not. this
++ * callback is not allowed to call back into COMMON_CLK, what
++ * adjust_link() does...
++ */
++ /*xemacps_adjust_link(nl->ndev); would likely lock up kernel */
++ return NOTIFY_OK;
++ case ABORT_RATE_CHANGE:
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
++/**
++ * xemacps_mii_probe - probe mii bus, find the right bus_id to register
++ * phy callback function.
++ * @ndev: network interface device structure
++ * return 0 on success, negative value if error
++ **/
++static int xemacps_mii_probe(struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ struct phy_device *phydev = NULL;
++
++ if (lp->phy_node) {
++ phydev = of_phy_connect(lp->ndev,
++ lp->phy_node,
++ &xemacps_adjust_link,
++ 0,
++ lp->phy_interface);
++ }
++ if (!phydev) {
++ dev_err(&lp->pdev->dev, "%s: no PHY found\n", ndev->name);
++ return -1;
++ }
++
++ dev_dbg(&lp->pdev->dev,
++ "GEM: phydev %p, phydev->phy_id 0x%x, phydev->addr 0x%x\n",
++ phydev, phydev->phy_id, phydev->addr);
++
++ phydev->supported &= (PHY_GBIT_FEATURES | SUPPORTED_Pause |
++ SUPPORTED_Asym_Pause);
++ phydev->advertising = phydev->supported;
++
++ lp->link = 0;
++ lp->speed = 0;
++ lp->duplex = -1;
++ lp->phy_dev = phydev;
++
++ phy_start(lp->phy_dev);
++
++ dev_dbg(&lp->pdev->dev, "phy_addr 0x%x, phy_id 0x%08x\n",
++ lp->phy_dev->addr, lp->phy_dev->phy_id);
++
++ dev_dbg(&lp->pdev->dev, "attach [%s] phy driver\n",
++ lp->phy_dev->drv->name);
++
++ if (lp->gmii2rgmii_phy_node) {
++ phydev = of_phy_connect(lp->ndev,
++ lp->gmii2rgmii_phy_node,
++ NULL,
++ 0, 0);
++ if (!phydev) {
++ dev_err(&lp->pdev->dev,
++ "%s: no gmii to rgmii converter found\n",
++ ndev->name);
++ return -1;
++ }
++ lp->gmii2rgmii_phy_dev = phydev;
++ } else
++ lp->gmii2rgmii_phy_dev = NULL;
++
++ return 0;
++}
++
++/**
++ * xemacps_mii_init - Initialize and register mii bus to network device
++ * @lp: local device instance pointer
++ * return 0 on success, negative value if error
++ **/
++static int xemacps_mii_init(struct net_local *lp)
++{
++ int rc = -ENXIO, i;
++ struct resource res;
++ struct device_node *np = of_get_parent(lp->phy_node);
++ struct device_node *npp;
++
++ lp->mii_bus = mdiobus_alloc();
++ if (lp->mii_bus == NULL) {
++ rc = -ENOMEM;
++ goto err_out;
++ }
++
++ lp->mii_bus->name = "XEMACPS mii bus";
++ lp->mii_bus->read = &xemacps_mdio_read;
++ lp->mii_bus->write = &xemacps_mdio_write;
++ lp->mii_bus->reset = &xemacps_mdio_reset;
++ lp->mii_bus->priv = lp;
++ lp->mii_bus->parent = &lp->ndev->dev;
++
++ lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
++ if (!lp->mii_bus->irq) {
++ rc = -ENOMEM;
++ goto err_out_free_mdiobus;
++ }
++
++ for (i = 0; i < PHY_MAX_ADDR; i++)
++ lp->mii_bus->irq[i] = PHY_POLL;
++ npp = of_get_parent(np);
++ of_address_to_resource(npp, 0, &res);
++ snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%.8llx",
++ (unsigned long long)res.start);
++ if (of_mdiobus_register(lp->mii_bus, np))
++ goto err_out_free_mdio_irq;
++
++ return 0;
++
++err_out_free_mdio_irq:
++ kfree(lp->mii_bus->irq);
++err_out_free_mdiobus:
++ mdiobus_free(lp->mii_bus);
++err_out:
++ return rc;
++}
++
++/**
++ * xemacps_update_hdaddr - Update device's MAC address when configured
++ * MAC address is not valid, reconfigure with a good one.
++ * @lp: local device instance pointer
++ **/
++static void xemacps_update_hwaddr(struct net_local *lp)
++{
++ u32 regvall;
++ u16 regvalh;
++ u8 addr[6];
++
++ regvall = xemacps_read(lp->baseaddr, XEMACPS_LADDR1L_OFFSET);
++ regvalh = xemacps_read(lp->baseaddr, XEMACPS_LADDR1H_OFFSET);
++ addr[0] = regvall & 0xFF;
++ addr[1] = (regvall >> 8) & 0xFF;
++ addr[2] = (regvall >> 16) & 0xFF;
++ addr[3] = (regvall >> 24) & 0xFF;
++ addr[4] = regvalh & 0xFF;
++ addr[5] = (regvalh >> 8) & 0xFF;
++
++ if (is_valid_ether_addr(addr)) {
++ memcpy(lp->ndev->dev_addr, addr, sizeof(addr));
++ } else {
++ dev_info(&lp->pdev->dev, "invalid address, use assigned\n");
++ random_ether_addr(lp->ndev->dev_addr);
++ dev_info(&lp->pdev->dev,
++ "MAC updated %02x:%02x:%02x:%02x:%02x:%02x\n",
++ lp->ndev->dev_addr[0], lp->ndev->dev_addr[1],
++ lp->ndev->dev_addr[2], lp->ndev->dev_addr[3],
++ lp->ndev->dev_addr[4], lp->ndev->dev_addr[5]);
++ }
++}
++
++/**
++ * xemacps_set_hwaddr - Set device's MAC address from ndev->dev_addr
++ * @lp: local device instance pointer
++ **/
++static void xemacps_set_hwaddr(struct net_local *lp)
++{
++ u32 regvall = 0;
++ u16 regvalh = 0;
++#ifdef __LITTLE_ENDIAN
++ regvall = cpu_to_le32(*((u32 *)lp->ndev->dev_addr));
++ regvalh = cpu_to_le16(*((u16 *)(lp->ndev->dev_addr + 4)));
++#endif
++#ifdef __BIG_ENDIAN
++ regvall = cpu_to_be32(*((u32 *)lp->ndev->dev_addr));
++ regvalh = cpu_to_be16(*((u16 *)(lp->ndev->dev_addr + 4)));
++#endif
++ /* LADDRXH has to be wriiten latter than LADDRXL to enable
++ * this address even if these 16 bits are zeros.
++ */
++ xemacps_write(lp->baseaddr, XEMACPS_LADDR1L_OFFSET, regvall);
++ xemacps_write(lp->baseaddr, XEMACPS_LADDR1H_OFFSET, regvalh);
++#ifdef DEBUG
++ regvall = xemacps_read(lp->baseaddr, XEMACPS_LADDR1L_OFFSET);
++ regvalh = xemacps_read(lp->baseaddr, XEMACPS_LADDR1H_OFFSET);
++ dev_dbg(&lp->pdev->dev,
++ "MAC 0x%08x, 0x%08x, %02x:%02x:%02x:%02x:%02x:%02x\n",
++ regvall, regvalh,
++ (regvall & 0xff), ((regvall >> 8) & 0xff),
++ ((regvall >> 16) & 0xff), (regvall >> 24),
++ (regvalh & 0xff), (regvalh >> 8));
++#endif
++}
++
++/**
++ * xemacps_reset_hw - Helper function to reset the underlying hardware.
++ * This is called when we get into such deep trouble that we don't know
++ * how to handle otherwise.
++ * @lp: local device instance pointer
++ */
++static void xemacps_reset_hw(struct net_local *lp)
++{
++ u32 regisr;
++ /* make sure we have the buffer for ourselves */
++ wmb();
++
++ /* Have a clean start */
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, 0);
++
++ /* Clear statistic counters */
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET,
++ XEMACPS_NWCTRL_STATCLR_MASK);
++
++ /* Clear TX and RX status */
++ xemacps_write(lp->baseaddr, XEMACPS_TXSR_OFFSET, ~0UL);
++ xemacps_write(lp->baseaddr, XEMACPS_RXSR_OFFSET, ~0UL);
++
++ /* Disable all interrupts */
++ xemacps_write(lp->baseaddr, XEMACPS_IDR_OFFSET, ~0UL);
++ synchronize_irq(lp->ndev->irq);
++ regisr = xemacps_read(lp->baseaddr, XEMACPS_ISR_OFFSET);
++ xemacps_write(lp->baseaddr, XEMACPS_ISR_OFFSET, regisr);
++}
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++
++/**
++ * xemacps_get_hwticks - get the current value of the GEM internal timer
++ * @lp: local device instance pointer
++ * return: nothing
++ **/
++static inline void
++xemacps_get_hwticks(struct net_local *lp, u64 *sec, u64 *nsec)
++{
++ do {
++ *nsec = xemacps_read(lp->baseaddr, XEMACPS_1588NS_OFFSET);
++ *sec = xemacps_read(lp->baseaddr, XEMACPS_1588S_OFFSET);
++ } while (*nsec > xemacps_read(lp->baseaddr, XEMACPS_1588NS_OFFSET));
++}
++
++/**
++ * xemacps_read_clock - read raw cycle counter (to be used by time counter)
++ */
++static cycle_t xemacps_read_clock(const struct cyclecounter *tc)
++{
++ struct net_local *lp =
++ container_of(tc, struct net_local, cycles);
++ u64 stamp;
++ u64 sec, nsec;
++
++ xemacps_get_hwticks(lp, &sec, &nsec);
++ stamp = (sec << 32) | nsec;
++
++ return stamp;
++}
++
++
++/**
++ * xemacps_systim_to_hwtstamp - convert system time value to hw timestamp
++ * @adapter: board private structure
++ * @shhwtstamps: timestamp structure to update
++ * @regval: unsigned 64bit system time value.
++ *
++ * We need to convert the system time value stored in the RX/TXSTMP registers
++ * into a hwtstamp which can be used by the upper level timestamping functions
++ */
++static void xemacps_systim_to_hwtstamp(struct net_local *lp,
++ struct skb_shared_hwtstamps *shhwtstamps,
++ u64 regval)
++{
++ u64 ns;
++
++ ns = timecounter_cyc2time(&lp->clock, regval);
++ timecompare_update(&lp->compare, ns);
++ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
++ shhwtstamps->hwtstamp = ns_to_ktime(ns);
++ shhwtstamps->syststamp = timecompare_transform(&lp->compare, ns);
++}
++
++static void
++xemacps_rx_hwtstamp(struct net_local *lp,
++ struct sk_buff *skb, unsigned msg_type)
++{
++ u64 time64, sec, nsec;
++
++ if (!msg_type) {
++ /* PTP Event Frame packets */
++ sec = xemacps_read(lp->baseaddr, XEMACPS_PTPERXS_OFFSET);
++ nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPERXNS_OFFSET);
++ } else {
++ /* PTP Peer Event Frame packets */
++ sec = xemacps_read(lp->baseaddr, XEMACPS_PTPPRXS_OFFSET);
++ nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPPRXNS_OFFSET);
++ }
++ time64 = (sec << 32) | nsec;
++ xemacps_systim_to_hwtstamp(lp, skb_hwtstamps(skb), time64);
++}
++
++static void
++xemacps_tx_hwtstamp(struct net_local *lp,
++ struct sk_buff *skb, unsigned msg_type)
++{
++ u64 time64, sec, nsec;
++
++ if (!msg_type) {
++ /* PTP Event Frame packets */
++ sec = xemacps_read(lp->baseaddr, XEMACPS_PTPETXS_OFFSET);
++ nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPETXNS_OFFSET);
++ } else {
++ /* PTP Peer Event Frame packets */
++ sec = xemacps_read(lp->baseaddr, XEMACPS_PTPPTXS_OFFSET);
++ nsec = xemacps_read(lp->baseaddr, XEMACPS_PTPPTXNS_OFFSET);
++ }
++
++ time64 = (sec << 32) | nsec;
++ xemacps_systim_to_hwtstamp(lp, skb_hwtstamps(skb), time64);
++ skb_tstamp_tx(skb, skb_hwtstamps(skb));
++}
++
++#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */
++
++/**
++ * xemacps_rx - process received packets when napi called
++ * @lp: local device instance pointer
++ * @budget: NAPI budget
++ * return: number of BDs processed
++ **/
++static int xemacps_rx(struct net_local *lp, int budget)
++{
++ struct xemacps_bd *cur_p;
++ u32 len;
++ struct sk_buff *skb;
++ struct sk_buff *new_skb;
++ u32 new_skb_baddr;
++ unsigned int numbdfree = 0;
++ u32 size = 0;
++ u32 packets = 0;
++ u32 regval;
++
++ cur_p = &lp->rx_bd[lp->rx_bd_ci];
++ regval = cur_p->addr;
++ rmb();
++ while (numbdfree < budget) {
++ if (!(regval & XEMACPS_RXBUF_NEW_MASK))
++ break;
++
++ new_skb = netdev_alloc_skb(lp->ndev, XEMACPS_RX_BUF_SIZE);
++ if (new_skb == NULL) {
++ dev_err(&lp->ndev->dev, "no memory for new sk_buff\n");
++ break;
++ }
++ /* Get dma handle of skb->data */
++ new_skb_baddr = (u32) dma_map_single(lp->ndev->dev.parent,
++ new_skb->data,
++ XEMACPS_RX_BUF_SIZE,
++ DMA_FROM_DEVICE);
++
++ /* the packet length */
++ len = cur_p->ctrl & XEMACPS_RXBUF_LEN_MASK;
++ rmb();
++ skb = lp->rx_skb[lp->rx_bd_ci].skb;
++ dma_unmap_single(lp->ndev->dev.parent,
++ lp->rx_skb[lp->rx_bd_ci].mapping,
++ lp->rx_skb[lp->rx_bd_ci].len,
++ DMA_FROM_DEVICE);
++
++ /* setup received skb and send it upstream */
++ skb_put(skb, len); /* Tell the skb how much data we got. */
++ skb->protocol = eth_type_trans(skb, lp->ndev);
++
++ skb->ip_summed = lp->ip_summed;
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++ if ((lp->hwtstamp_config.rx_filter == HWTSTAMP_FILTER_ALL) &&
++ (ntohs(skb->protocol) == 0x800)) {
++ unsigned ip_proto, dest_port, msg_type;
++
++ /* While the GEM can timestamp PTP packets, it does
++ * not mark the RX descriptor to identify them. This
++ * is entirely the wrong place to be parsing UDP
++ * headers, but some minimal effort must be made.
++ * NOTE: the below parsing of ip_proto and dest_port
++ * depend on the use of Ethernet_II encapsulation,
++ * IPv4 without any options.
++ */
++ ip_proto = *((u8 *)skb->mac_header + 14 + 9);
++ dest_port = ntohs(*(((u16 *)skb->mac_header) +
++ ((14 + 20 + 2)/2)));
++ msg_type = *((u8 *)skb->mac_header + 42);
++ if ((ip_proto == IPPROTO_UDP) &&
++ (dest_port == 0x13F)) {
++ /* Timestamp this packet */
++ xemacps_rx_hwtstamp(lp, skb, msg_type & 0x2);
++ }
++ }
++#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */
++ size += len;
++ packets++;
++ netif_receive_skb(skb);
++
++ cur_p->addr = (cur_p->addr & ~XEMACPS_RXBUF_ADD_MASK)
++ | (new_skb_baddr);
++ lp->rx_skb[lp->rx_bd_ci].skb = new_skb;
++ lp->rx_skb[lp->rx_bd_ci].mapping = new_skb_baddr;
++ lp->rx_skb[lp->rx_bd_ci].len = XEMACPS_RX_BUF_SIZE;
++
++ cur_p->ctrl = 0;
++ cur_p->addr &= (~XEMACPS_RXBUF_NEW_MASK);
++ wmb();
++
++ lp->rx_bd_ci++;
++ lp->rx_bd_ci = lp->rx_bd_ci % XEMACPS_RECV_BD_CNT;
++ cur_p = &lp->rx_bd[lp->rx_bd_ci];
++ regval = cur_p->addr;
++ rmb();
++ numbdfree++;
++ }
++ wmb();
++ lp->stats.rx_packets += packets;
++ lp->stats.rx_bytes += size;
++ return numbdfree;
++}
++
++/**
++ * xemacps_rx_poll - NAPI poll routine
++ * napi: pointer to napi struct
++ * budget:
++ **/
++static int xemacps_rx_poll(struct napi_struct *napi, int budget)
++{
++ struct net_local *lp = container_of(napi, struct net_local, napi);
++ int work_done = 0;
++ u32 regval;
++
++ spin_lock(&lp->rx_lock);
++ while (1) {
++ regval = xemacps_read(lp->baseaddr, XEMACPS_RXSR_OFFSET);
++ xemacps_write(lp->baseaddr, XEMACPS_RXSR_OFFSET, regval);
++ if (regval & XEMACPS_RXSR_HRESPNOK_MASK)
++ dev_err(&lp->pdev->dev, "RX error 0x%x\n", regval);
++
++ work_done += xemacps_rx(lp, budget - work_done);
++ if (work_done >= budget)
++ break;
++
++ napi_complete(napi);
++ /* We disabled RX interrupts in interrupt service
++ * routine, now it is time to enable it back.
++ */
++ xemacps_write(lp->baseaddr,
++ XEMACPS_IER_OFFSET, XEMACPS_IXR_FRAMERX_MASK);
++
++ /* If a packet has come in between the last check of the BD
++ * list and unmasking the interrupts, we may have missed the
++ * interrupt, so reschedule here.
++ */
++ if ((lp->rx_bd[lp->rx_bd_ci].addr & XEMACPS_RXBUF_NEW_MASK)
++ && napi_reschedule(napi)) {
++ xemacps_write(lp->baseaddr,
++ XEMACPS_IDR_OFFSET, XEMACPS_IXR_FRAMERX_MASK);
++ continue;
++ }
++ break;
++ }
++ spin_unlock(&lp->rx_lock);
++ return work_done;
++}
++
++/**
++ * xemacps_tx_poll - tx bd reclaim tasklet handler
++ * @data: pointer to network interface device structure
++ **/
++static void xemacps_tx_poll(unsigned long data)
++{
++ struct net_device *ndev = (struct net_device *)data;
++ struct net_local *lp = netdev_priv(ndev);
++ u32 regval;
++ u32 len = 0;
++ unsigned int bdcount = 0;
++ unsigned int bdpartialcount = 0;
++ unsigned int sop = 0;
++ struct xemacps_bd *cur_p;
++ u32 cur_i;
++ u32 numbdstofree;
++ u32 numbdsinhw;
++ struct ring_info *rp;
++ struct sk_buff *skb;
++ unsigned long flags;
++
++ spin_lock(&lp->tx_lock);
++ regval = xemacps_read(lp->baseaddr, XEMACPS_TXSR_OFFSET);
++ xemacps_write(lp->baseaddr, XEMACPS_TXSR_OFFSET, regval);
++ dev_dbg(&lp->pdev->dev, "TX status 0x%x\n", regval);
++ if (regval & (XEMACPS_TXSR_HRESPNOK_MASK | XEMACPS_TXSR_BUFEXH_MASK))
++ dev_err(&lp->pdev->dev, "TX error 0x%x\n", regval);
++
++ cur_i = lp->tx_bd_ci;
++ cur_p = &lp->tx_bd[cur_i];
++ numbdsinhw = XEMACPS_SEND_BD_CNT - lp->tx_bd_freecnt;
++ while (bdcount < numbdsinhw) {
++ if (sop == 0) {
++ if (cur_p->ctrl & XEMACPS_TXBUF_USED_MASK)
++ sop = 1;
++ else
++ break;
++ }
++
++ bdcount++;
++ bdpartialcount++;
++
++ /* hardware has processed this BD so check the "last" bit.
++ * If it is clear, then there are more BDs for the current
++ * packet. Keep a count of these partial packet BDs.
++ */
++ if (cur_p->ctrl & XEMACPS_TXBUF_LAST_MASK) {
++ sop = 0;
++ bdpartialcount = 0;
++ }
++
++ cur_i++;
++ cur_i = cur_i % XEMACPS_SEND_BD_CNT;
++ cur_p = &lp->tx_bd[cur_i];
++ }
++ numbdstofree = bdcount - bdpartialcount;
++ lp->tx_bd_freecnt += numbdstofree;
++ numbdsinhw -= numbdstofree;
++ if (!numbdstofree)
++ goto tx_poll_out;
++
++ cur_p = &lp->tx_bd[lp->tx_bd_ci];
++ while (numbdstofree) {
++ rp = &lp->tx_skb[lp->tx_bd_ci];
++ skb = rp->skb;
++
++ len += (cur_p->ctrl & XEMACPS_TXBUF_LEN_MASK);
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++ if ((lp->hwtstamp_config.tx_type == HWTSTAMP_TX_ON) &&
++ (ntohs(skb->protocol) == 0x800)) {
++ unsigned ip_proto, dest_port, msg_type;
++
++ skb_reset_mac_header(skb);
++
++ ip_proto = *((u8 *)skb->mac_header + 14 + 9);
++ dest_port = ntohs(*(((u16 *)skb->mac_header) +
++ ((14 + 20 + 2)/2)));
++ msg_type = *((u8 *)skb->mac_header + 42);
++ if ((ip_proto == IPPROTO_UDP) &&
++ (dest_port == 0x13F)) {
++ /* Timestamp this packet */
++ xemacps_tx_hwtstamp(lp, skb, msg_type & 0x2);
++ }
++ }
++#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */
++
++ dma_unmap_single(&lp->pdev->dev, rp->mapping, rp->len,
++ DMA_TO_DEVICE);
++ rp->skb = NULL;
++ dev_kfree_skb(skb);
++ /* log tx completed packets and bytes, errors logs
++ * are in other error counters.
++ */
++ if (cur_p->ctrl & XEMACPS_TXBUF_LAST_MASK) {
++ lp->stats.tx_packets++;
++ lp->stats.tx_bytes += len;
++ len = 0;
++ }
++
++ /* Set used bit, preserve wrap bit; clear everything else. */
++ cur_p->ctrl |= XEMACPS_TXBUF_USED_MASK;
++ cur_p->ctrl &= (XEMACPS_TXBUF_USED_MASK |
++ XEMACPS_TXBUF_WRAP_MASK);
++
++ lp->tx_bd_ci++;
++ lp->tx_bd_ci = lp->tx_bd_ci % XEMACPS_SEND_BD_CNT;
++ cur_p = &lp->tx_bd[lp->tx_bd_ci];
++ numbdstofree--;
++ }
++ wmb();
++
++ if (numbdsinhw) {
++ spin_lock_irqsave(&lp->nwctrlreg_lock, flags);
++ regval = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET);
++ regval |= XEMACPS_NWCTRL_STARTTX_MASK;
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regval);
++ spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags);
++ }
++
++ netif_wake_queue(ndev);
++
++tx_poll_out:
++ spin_unlock(&lp->tx_lock);
++}
++
++/**
++ * xemacps_interrupt - interrupt main service routine
++ * @irq: interrupt number
++ * @dev_id: pointer to a network device structure
++ * return IRQ_HANDLED or IRQ_NONE
++ **/
++static irqreturn_t xemacps_interrupt(int irq, void *dev_id)
++{
++ struct net_device *ndev = dev_id;
++ struct net_local *lp = netdev_priv(ndev);
++ u32 regisr;
++ u32 regctrl;
++
++ regisr = xemacps_read(lp->baseaddr, XEMACPS_ISR_OFFSET);
++ if (unlikely(!regisr))
++ return IRQ_NONE;
++
++ xemacps_write(lp->baseaddr, XEMACPS_ISR_OFFSET, regisr);
++
++ while (regisr) {
++ if (regisr & (XEMACPS_IXR_TXCOMPL_MASK |
++ XEMACPS_IXR_TX_ERR_MASK)) {
++ tasklet_schedule(&lp->tx_bdreclaim_tasklet);
++ }
++
++ if (regisr & XEMACPS_IXR_RXUSED_MASK) {
++ spin_lock(&lp->nwctrlreg_lock);
++ regctrl = xemacps_read(lp->baseaddr,
++ XEMACPS_NWCTRL_OFFSET);
++ regctrl |= XEMACPS_NWCTRL_FLUSH_DPRAM_MASK;
++ xemacps_write(lp->baseaddr,
++ XEMACPS_NWCTRL_OFFSET, regctrl);
++ spin_unlock(&lp->nwctrlreg_lock);
++ }
++
++ if (regisr & XEMACPS_IXR_FRAMERX_MASK) {
++ xemacps_write(lp->baseaddr,
++ XEMACPS_IDR_OFFSET, XEMACPS_IXR_FRAMERX_MASK);
++ napi_schedule(&lp->napi);
++ }
++ regisr = xemacps_read(lp->baseaddr, XEMACPS_ISR_OFFSET);
++ xemacps_write(lp->baseaddr, XEMACPS_ISR_OFFSET, regisr);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/* Free all packets presently in the descriptor rings. */
++static void xemacps_clean_rings(struct net_local *lp)
++{
++ int i;
++
++ for (i = 0; i < XEMACPS_RECV_BD_CNT; i++) {
++ if (lp->rx_skb && lp->rx_skb[i].skb) {
++ dma_unmap_single(lp->ndev->dev.parent,
++ lp->rx_skb[i].mapping,
++ lp->rx_skb[i].len,
++ DMA_FROM_DEVICE);
++
++ dev_kfree_skb(lp->rx_skb[i].skb);
++ lp->rx_skb[i].skb = NULL;
++ lp->rx_skb[i].mapping = 0;
++ }
++ }
++
++ for (i = 0; i < XEMACPS_SEND_BD_CNT; i++) {
++ if (lp->tx_skb && lp->tx_skb[i].skb) {
++ dma_unmap_single(lp->ndev->dev.parent,
++ lp->tx_skb[i].mapping,
++ lp->tx_skb[i].len,
++ DMA_TO_DEVICE);
++
++ dev_kfree_skb(lp->tx_skb[i].skb);
++ lp->tx_skb[i].skb = NULL;
++ lp->tx_skb[i].mapping = 0;
++ }
++ }
++}
++
++/**
++ * xemacps_descriptor_free - Free allocated TX and RX BDs
++ * @lp: local device instance pointer
++ **/
++static void xemacps_descriptor_free(struct net_local *lp)
++{
++ int size;
++
++ xemacps_clean_rings(lp);
++
++ /* kfree(NULL) is safe, no need to check here */
++ kfree(lp->tx_skb);
++ lp->tx_skb = NULL;
++ kfree(lp->rx_skb);
++ lp->rx_skb = NULL;
++
++ size = XEMACPS_RECV_BD_CNT * sizeof(struct xemacps_bd);
++ if (lp->rx_bd) {
++ dma_free_coherent(&lp->pdev->dev, size,
++ lp->rx_bd, lp->rx_bd_dma);
++ lp->rx_bd = NULL;
++ }
++
++ size = XEMACPS_SEND_BD_CNT * sizeof(struct xemacps_bd);
++ if (lp->tx_bd) {
++ dma_free_coherent(&lp->pdev->dev, size,
++ lp->tx_bd, lp->tx_bd_dma);
++ lp->tx_bd = NULL;
++ }
++}
++
++/**
++ * xemacps_descriptor_init - Allocate both TX and RX BDs
++ * @lp: local device instance pointer
++ * return 0 on success, negative value if error
++ **/
++static int xemacps_descriptor_init(struct net_local *lp)
++{
++ int size;
++ struct sk_buff *new_skb;
++ u32 new_skb_baddr;
++ u32 i;
++ struct xemacps_bd *cur_p;
++ u32 regval;
++
++ lp->tx_skb = NULL;
++ lp->rx_skb = NULL;
++ lp->rx_bd = NULL;
++ lp->tx_bd = NULL;
++
++ /* Reset the indexes which are used for accessing the BDs */
++ lp->tx_bd_ci = 0;
++ lp->tx_bd_tail = 0;
++ lp->rx_bd_ci = 0;
++
++ size = XEMACPS_SEND_BD_CNT * sizeof(struct ring_info);
++ lp->tx_skb = kzalloc(size, GFP_KERNEL);
++ if (!lp->tx_skb)
++ goto err_out;
++ size = XEMACPS_RECV_BD_CNT * sizeof(struct ring_info);
++ lp->rx_skb = kzalloc(size, GFP_KERNEL);
++ if (!lp->rx_skb)
++ goto err_out;
++
++ /* Set up RX buffer descriptors. */
++
++ size = XEMACPS_RECV_BD_CNT * sizeof(struct xemacps_bd);
++ lp->rx_bd = dma_alloc_coherent(&lp->pdev->dev, size,
++ &lp->rx_bd_dma, GFP_KERNEL);
++ if (!lp->rx_bd)
++ goto err_out;
++ dev_dbg(&lp->pdev->dev, "RX ring %d bytes at 0x%x mapped %p\n",
++ size, lp->rx_bd_dma, lp->rx_bd);
++
++ for (i = 0; i < XEMACPS_RECV_BD_CNT; i++) {
++ cur_p = &lp->rx_bd[i];
++
++ new_skb = netdev_alloc_skb(lp->ndev, XEMACPS_RX_BUF_SIZE);
++ if (new_skb == NULL) {
++ dev_err(&lp->ndev->dev, "alloc_skb error %d\n", i);
++ goto err_out;
++ }
++
++ /* Get dma handle of skb->data */
++ new_skb_baddr = (u32) dma_map_single(lp->ndev->dev.parent,
++ new_skb->data,
++ XEMACPS_RX_BUF_SIZE,
++ DMA_FROM_DEVICE);
++
++ /* set wrap bit for last BD */
++ regval = (new_skb_baddr & XEMACPS_RXBUF_ADD_MASK);
++ if (i == XEMACPS_RECV_BD_CNT - 1)
++ regval |= XEMACPS_RXBUF_WRAP_MASK;
++ cur_p->addr = regval;
++ cur_p->ctrl = 0;
++ wmb();
++
++ lp->rx_skb[i].skb = new_skb;
++ lp->rx_skb[i].mapping = new_skb_baddr;
++ lp->rx_skb[i].len = XEMACPS_RX_BUF_SIZE;
++ }
++
++ /* Set up TX buffer descriptors. */
++
++ size = XEMACPS_SEND_BD_CNT * sizeof(struct xemacps_bd);
++ lp->tx_bd = dma_alloc_coherent(&lp->pdev->dev, size,
++ &lp->tx_bd_dma, GFP_KERNEL);
++ if (!lp->tx_bd)
++ goto err_out;
++ dev_dbg(&lp->pdev->dev, "TX ring %d bytes at 0x%x mapped %p\n",
++ size, lp->tx_bd_dma, lp->tx_bd);
++
++ for (i = 0; i < XEMACPS_SEND_BD_CNT; i++) {
++ cur_p = &lp->tx_bd[i];
++ /* set wrap bit for last BD */
++ cur_p->addr = 0;
++ regval = XEMACPS_TXBUF_USED_MASK;
++ if (i == XEMACPS_SEND_BD_CNT - 1)
++ regval |= XEMACPS_TXBUF_WRAP_MASK;
++ cur_p->ctrl = regval;
++ }
++ wmb();
++
++ lp->tx_bd_freecnt = XEMACPS_SEND_BD_CNT;
++
++ dev_dbg(&lp->pdev->dev,
++ "lp->tx_bd %p lp->tx_bd_dma %p lp->tx_skb %p\n",
++ lp->tx_bd, (void *)lp->tx_bd_dma, lp->tx_skb);
++ dev_dbg(&lp->pdev->dev,
++ "lp->rx_bd %p lp->rx_bd_dma %p lp->rx_skb %p\n",
++ lp->rx_bd, (void *)lp->rx_bd_dma, lp->rx_skb);
++
++ return 0;
++
++err_out:
++ xemacps_descriptor_free(lp);
++ return -ENOMEM;
++}
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++/*
++ * Initialize the GEM Time Stamp Unit
++ */
++static void xemacps_init_tsu(struct net_local *lp)
++{
++
++ memset(&lp->cycles, 0, sizeof(lp->cycles));
++ lp->cycles.read = xemacps_read_clock;
++ lp->cycles.mask = CLOCKSOURCE_MASK(64);
++ lp->cycles.mult = 1;
++ lp->cycles.shift = 0;
++
++ /* Set registers so that rollover occurs soon to test this. */
++ xemacps_write(lp->baseaddr, XEMACPS_1588NS_OFFSET, 0x00000000);
++ xemacps_write(lp->baseaddr, XEMACPS_1588S_OFFSET, 0xFF800000);
++
++ /* program the timer increment register with the numer of nanoseconds
++ * per clock tick.
++ *
++ * Note: The value is calculated based on the current operating
++ * frequency 50MHz
++ */
++ xemacps_write(lp->baseaddr, XEMACPS_1588INC_OFFSET,
++ (NS_PER_SEC/lp->ptpenetclk));
++
++ timecounter_init(&lp->clock, &lp->cycles,
++ ktime_to_ns(ktime_get_real()));
++ /*
++ * Synchronize our NIC clock against system wall clock.
++ */
++ memset(&lp->compare, 0, sizeof(lp->compare));
++ lp->compare.source = &lp->clock;
++ lp->compare.target = ktime_get_real;
++ lp->compare.num_samples = 10;
++ timecompare_update(&lp->compare, 0);
++
++ /* Initialize hwstamp config */
++ lp->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
++ lp->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF;
++
++}
++#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */
++
++/**
++ * xemacps_init_hw - Initialize hardware to known good state
++ * @lp: local device instance pointer
++ **/
++static void xemacps_init_hw(struct net_local *lp)
++{
++ u32 regval;
++
++ xemacps_reset_hw(lp);
++ xemacps_set_hwaddr(lp);
++
++ /* network configuration */
++ regval = 0;
++ regval |= XEMACPS_NWCFG_FDEN_MASK;
++ regval |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
++ regval |= XEMACPS_NWCFG_PAUSECOPYDI_MASK;
++ regval |= XEMACPS_NWCFG_FCSREM_MASK;
++ regval |= XEMACPS_NWCFG_PAUSEEN_MASK;
++ regval |= XEMACPS_NWCFG_100_MASK;
++ regval |= XEMACPS_NWCFG_HDRXEN_MASK;
++
++ regval |= (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK);
++ if (lp->ndev->flags & IFF_PROMISC) /* copy all */
++ regval |= XEMACPS_NWCFG_COPYALLEN_MASK;
++ if (!(lp->ndev->flags & IFF_BROADCAST)) /* No broadcast */
++ regval |= XEMACPS_NWCFG_BCASTDI_MASK;
++ xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval);
++
++ /* Init TX and RX DMA Q address */
++ xemacps_write(lp->baseaddr, XEMACPS_RXQBASE_OFFSET, lp->rx_bd_dma);
++ xemacps_write(lp->baseaddr, XEMACPS_TXQBASE_OFFSET, lp->tx_bd_dma);
++
++ /* DMACR configurations */
++ regval = (((XEMACPS_RX_BUF_SIZE / XEMACPS_RX_BUF_UNIT) +
++ ((XEMACPS_RX_BUF_SIZE % XEMACPS_RX_BUF_UNIT) ? 1 : 0)) <<
++ XEMACPS_DMACR_RXBUF_SHIFT);
++ regval |= XEMACPS_DMACR_RXSIZE_MASK;
++ regval |= XEMACPS_DMACR_TXSIZE_MASK;
++ regval |= XEMACPS_DMACR_TCPCKSUM_MASK;
++#ifdef __LITTLE_ENDIAN
++ regval &= ~XEMACPS_DMACR_ENDIAN_MASK;
++#endif
++#ifdef __BIG_ENDIAN
++ regval |= XEMACPS_DMACR_ENDIAN_MASK;
++#endif
++ regval |= XEMACPS_DMACR_BLENGTH_INCR16;
++ xemacps_write(lp->baseaddr, XEMACPS_DMACR_OFFSET, regval);
++
++ /* Enable TX, RX and MDIO port */
++ regval = 0;
++ regval |= XEMACPS_NWCTRL_MDEN_MASK;
++ regval |= XEMACPS_NWCTRL_TXEN_MASK;
++ regval |= XEMACPS_NWCTRL_RXEN_MASK;
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regval);
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++ /* Initialize the Time Stamp Unit */
++ xemacps_init_tsu(lp);
++#endif
++
++ /* Enable interrupts */
++ regval = XEMACPS_IXR_ALL_MASK;
++ xemacps_write(lp->baseaddr, XEMACPS_IER_OFFSET, regval);
++}
++
++/**
++ * xemacps_resetrx_for_no_rxdata - Resets the Rx if there is no data
++ * for a while (presently 100 msecs)
++ * @data: Used for net_local instance pointer
++ **/
++static void xemacps_resetrx_for_no_rxdata(unsigned long data)
++{
++ struct net_local *lp = (struct net_local *)data;
++ unsigned long regctrl;
++ unsigned long tempcntr;
++ unsigned long flags;
++
++ tempcntr = xemacps_read(lp->baseaddr, XEMACPS_RXCNT_OFFSET);
++ if ((!tempcntr) && (!(lp->lastrxfrmscntr))) {
++ spin_lock_irqsave(&lp->nwctrlreg_lock, flags);
++ regctrl = xemacps_read(lp->baseaddr,
++ XEMACPS_NWCTRL_OFFSET);
++ regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
++ xemacps_write(lp->baseaddr,
++ XEMACPS_NWCTRL_OFFSET, regctrl);
++ regctrl = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET);
++ regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regctrl);
++ spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags);
++ }
++ lp->lastrxfrmscntr = tempcntr;
++}
++
++/**
++ * xemacps_update_stats - Update the statistic structure entries from
++ * the corresponding emacps hardware statistic registers
++ * @data: Used for net_local instance pointer
++ **/
++static void xemacps_update_stats(unsigned long data)
++{
++ struct net_local *lp = (struct net_local *)data;
++ struct net_device_stats *nstat = &lp->stats;
++ u32 cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXUNDRCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_length_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXOVRCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_length_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXJABCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_length_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXFCSCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_crc_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXLENGTHCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_length_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXALIGNCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_frame_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXRESERRCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_missed_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXORCNT_OFFSET);
++ nstat->rx_errors += cnt;
++ nstat->rx_fifo_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_TXURUNCNT_OFFSET);
++ nstat->tx_errors += cnt;
++ nstat->tx_fifo_errors += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_SNGLCOLLCNT_OFFSET);
++ nstat->collisions += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_MULTICOLLCNT_OFFSET);
++ nstat->collisions += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_EXCESSCOLLCNT_OFFSET);
++ nstat->tx_errors += cnt;
++ nstat->tx_aborted_errors += cnt;
++ nstat->collisions += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_LATECOLLCNT_OFFSET);
++ nstat->tx_errors += cnt;
++ nstat->collisions += cnt;
++
++ cnt = xemacps_read(lp->baseaddr, XEMACPS_CSENSECNT_OFFSET);
++ nstat->tx_errors += cnt;
++ nstat->tx_carrier_errors += cnt;
++}
++
++/**
++ * xemacps_gen_purpose_timerhandler - Timer handler that is called at regular
++ * intervals upon expiry of the gen_purpose_timer defined in net_local struct.
++ * @data: Used for net_local instance pointer
++ *
++ * This timer handler is used to update the statistics by calling the API
++ * xemacps_update_stats. The statistics register can typically overflow pretty
++ * quickly under heavy load conditions. This timer is used to periodically
++ * read the stats registers and update the corresponding stats structure
++ * entries. The stats registers when read reset to 0.
++ **/
++static void xemacps_gen_purpose_timerhandler(unsigned long data)
++{
++ struct net_local *lp = (struct net_local *)data;
++
++ xemacps_update_stats(data);
++ xemacps_resetrx_for_no_rxdata(data);
++ mod_timer(&(lp->gen_purpose_timer),
++ jiffies + msecs_to_jiffies(XEAMCPS_GEN_PURPOSE_TIMER_LOAD));
++}
++
++/**
++ * xemacps_open - Called when a network device is made active
++ * @ndev: network interface device structure
++ * return 0 on success, negative value if error
++ *
++ * The open entry point is called when a network interface is made active
++ * by the system (IFF_UP). At this point all resources needed for transmit
++ * and receive operations are allocated, the interrupt handler is
++ * registered with OS, the watchdog timer is started, and the stack is
++ * notified that the interface is ready.
++ *
++ * note: if error(s), allocated resources before error require to be
++ * released or system issues (such as memory) leak might happen.
++ **/
++static int xemacps_open(struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ int rc;
++
++ dev_dbg(&lp->pdev->dev, "open\n");
++ if (!is_valid_ether_addr(ndev->dev_addr))
++ return -EADDRNOTAVAIL;
++
++ rc = xemacps_descriptor_init(lp);
++ if (rc) {
++ dev_err(&lp->pdev->dev,
++ "Unable to allocate DMA memory, rc %d\n", rc);
++ return rc;
++ }
++
++ rc = pm_runtime_get_sync(&lp->pdev->dev);
++ if (rc < 0) {
++ dev_err(&lp->pdev->dev,
++ "pm_runtime_get_sync() failed, rc %d\n", rc);
++ goto err_free_rings;
++ }
++
++ xemacps_init_hw(lp);
++ rc = xemacps_mii_probe(ndev);
++ if (rc != 0) {
++ dev_err(&lp->pdev->dev,
++ "%s mii_probe fail.\n", lp->mii_bus->name);
++ if (rc == (-2)) {
++ mdiobus_unregister(lp->mii_bus);
++ kfree(lp->mii_bus->irq);
++ mdiobus_free(lp->mii_bus);
++ }
++ rc = -ENXIO;
++ goto err_pm_put;
++ }
++
++ setup_timer(&(lp->gen_purpose_timer), xemacps_gen_purpose_timerhandler,
++ (unsigned long)lp);
++ mod_timer(&(lp->gen_purpose_timer),
++ jiffies + msecs_to_jiffies(XEAMCPS_GEN_PURPOSE_TIMER_LOAD));
++
++ napi_enable(&lp->napi);
++ netif_carrier_on(ndev);
++ netif_start_queue(ndev);
++ tasklet_enable(&lp->tx_bdreclaim_tasklet);
++
++ return 0;
++
++err_pm_put:
++ xemacps_reset_hw(lp);
++ pm_runtime_put(&lp->pdev->dev);
++err_free_rings:
++ xemacps_descriptor_free(lp);
++
++ return rc;
++}
++
++/**
++ * xemacps_close - disable a network interface
++ * @ndev: network interface device structure
++ * return 0
++ *
++ * The close entry point is called when a network interface is de-activated
++ * by OS. The hardware is still under the driver control, but needs to be
++ * disabled. A global MAC reset is issued to stop the hardware, and all
++ * transmit and receive resources are freed.
++ **/
++static int xemacps_close(struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++
++ del_timer_sync(&(lp->gen_purpose_timer));
++ netif_stop_queue(ndev);
++ napi_disable(&lp->napi);
++ tasklet_disable(&lp->tx_bdreclaim_tasklet);
++ netif_carrier_off(ndev);
++ if (lp->phy_dev)
++ phy_disconnect(lp->phy_dev);
++ if (lp->gmii2rgmii_phy_node)
++ phy_disconnect(lp->gmii2rgmii_phy_dev);
++ xemacps_reset_hw(lp);
++ mdelay(500);
++ xemacps_descriptor_free(lp);
++
++ pm_runtime_put(&lp->pdev->dev);
++
++ return 0;
++}
++
++/**
++ * xemacps_reinit_for_txtimeout - work queue scheduled for the tx timeout
++ * handling.
++ * @ndev: queue work structure
++ **/
++static void xemacps_reinit_for_txtimeout(struct work_struct *data)
++{
++ struct net_local *lp = container_of(data, struct net_local,
++ txtimeout_reinit);
++ int rc;
++
++ netif_stop_queue(lp->ndev);
++ napi_disable(&lp->napi);
++ tasklet_disable(&lp->tx_bdreclaim_tasklet);
++ spin_lock_bh(&lp->tx_lock);
++ xemacps_reset_hw(lp);
++ spin_unlock_bh(&lp->tx_lock);
++
++ if (lp->phy_dev)
++ phy_stop(lp->phy_dev);
++
++ xemacps_descriptor_free(lp);
++ rc = xemacps_descriptor_init(lp);
++ if (rc) {
++ dev_err(&lp->pdev->dev,
++ "Unable to allocate DMA memory, rc %d\n", rc);
++ return;
++ }
++
++ xemacps_init_hw(lp);
++
++ lp->link = 0;
++ lp->speed = 0;
++ lp->duplex = -1;
++
++ if (lp->phy_dev)
++ phy_start(lp->phy_dev);
++
++ napi_enable(&lp->napi);
++ tasklet_enable(&lp->tx_bdreclaim_tasklet);
++ lp->ndev->trans_start = jiffies;
++ netif_wake_queue(lp->ndev);
++}
++
++/**
++ * xemacps_tx_timeout - callback used when the transmitter has not made
++ * any progress for dev->watchdog ticks.
++ * @ndev: network interface device structure
++ **/
++static void xemacps_tx_timeout(struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++
++ dev_err(&lp->pdev->dev, "transmit timeout %lu ms, reseting...\n",
++ TX_TIMEOUT * 1000UL / HZ);
++ queue_work(lp->txtimeout_handler_wq, &lp->txtimeout_reinit);
++}
++
++/**
++ * xemacps_set_mac_address - set network interface mac address
++ * @ndev: network interface device structure
++ * @addr: pointer to MAC address
++ * return 0 on success, negative value if error
++ **/
++static int xemacps_set_mac_address(struct net_device *ndev, void *addr)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ struct sockaddr *hwaddr = (struct sockaddr *)addr;
++
++ if (netif_running(ndev))
++ return -EBUSY;
++
++ if (!is_valid_ether_addr(hwaddr->sa_data))
++ return -EADDRNOTAVAIL;
++
++ dev_dbg(&lp->pdev->dev, "hwaddr 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
++ hwaddr->sa_data[0], hwaddr->sa_data[1], hwaddr->sa_data[2],
++ hwaddr->sa_data[3], hwaddr->sa_data[4], hwaddr->sa_data[5]);
++
++ memcpy(ndev->dev_addr, hwaddr->sa_data, ndev->addr_len);
++
++ xemacps_set_hwaddr(lp);
++ return 0;
++}
++
++/**
++ * xemacps_clear_csum - Clear the csum field for transport protocols
++ * @skb: socket buffer
++ * @ndev: network interface device structure
++ * return 0 on success, other value if error
++ **/
++static int xemacps_clear_csum(struct sk_buff *skb, struct net_device *ndev)
++{
++ /* Only run for packets requiring a checksum. */
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
++ return 0;
++
++ if (unlikely(skb_cow_head(skb, 0)))
++ return -1;
++
++ *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) = 0;
++
++ return 0;
++}
++
++/**
++ * xemacps_start_xmit - transmit a packet (called by kernel)
++ * @skb: socket buffer
++ * @ndev: network interface device structure
++ * return 0 on success, other value if error
++ **/
++static int xemacps_start_xmit(struct sk_buff *skb, struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ dma_addr_t mapping;
++ unsigned int nr_frags, len;
++ int i;
++ u32 regval;
++ void *virt_addr;
++ skb_frag_t *frag;
++ struct xemacps_bd *cur_p;
++ unsigned long flags;
++ u32 bd_tail;
++
++ nr_frags = skb_shinfo(skb)->nr_frags + 1;
++ spin_lock_bh(&lp->tx_lock);
++
++ if (nr_frags > lp->tx_bd_freecnt) {
++ netif_stop_queue(ndev); /* stop send queue */
++ spin_unlock_bh(&lp->tx_lock);
++ return NETDEV_TX_BUSY;
++ }
++
++ if (xemacps_clear_csum(skb, ndev)) {
++ spin_unlock_bh(&lp->tx_lock);
++ kfree(skb);
++ return NETDEV_TX_OK;
++ }
++
++ bd_tail = lp->tx_bd_tail;
++ cur_p = &lp->tx_bd[bd_tail];
++ lp->tx_bd_freecnt -= nr_frags;
++ frag = &skb_shinfo(skb)->frags[0];
++
++ for (i = 0; i < nr_frags; i++) {
++ if (i == 0) {
++ len = skb_headlen(skb);
++ mapping = dma_map_single(&lp->pdev->dev, skb->data,
++ len, DMA_TO_DEVICE);
++ } else {
++ len = skb_frag_size(frag);
++ virt_addr = skb_frag_address(frag);
++ mapping = dma_map_single(&lp->pdev->dev, virt_addr,
++ len, DMA_TO_DEVICE);
++ frag++;
++ skb_get(skb);
++ }
++
++ lp->tx_skb[lp->tx_bd_tail].skb = skb;
++ lp->tx_skb[lp->tx_bd_tail].mapping = mapping;
++ lp->tx_skb[lp->tx_bd_tail].len = len;
++ cur_p->addr = mapping;
++
++ /* preserve critical status bits */
++ regval = cur_p->ctrl;
++ regval &= (XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK);
++ /* update length field */
++ regval |= ((regval & ~XEMACPS_TXBUF_LEN_MASK) | len);
++ /* commit second to last buffer to hardware */
++ if (i != 0)
++ regval &= ~XEMACPS_TXBUF_USED_MASK;
++ /* last fragment of this packet? */
++ if (i == (nr_frags - 1))
++ regval |= XEMACPS_TXBUF_LAST_MASK;
++ cur_p->ctrl = regval;
++
++ lp->tx_bd_tail++;
++ lp->tx_bd_tail = lp->tx_bd_tail % XEMACPS_SEND_BD_CNT;
++ cur_p = &(lp->tx_bd[lp->tx_bd_tail]);
++ }
++ wmb();
++
++ /* commit first buffer to hardware -- do this after
++ * committing the other buffers to avoid an underrun */
++ cur_p = &lp->tx_bd[bd_tail];
++ regval = cur_p->ctrl;
++ regval &= ~XEMACPS_TXBUF_USED_MASK;
++ cur_p->ctrl = regval;
++ wmb();
++
++ spin_lock_irqsave(&lp->nwctrlreg_lock, flags);
++ regval = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET);
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET,
++ (regval | XEMACPS_NWCTRL_STARTTX_MASK));
++ spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags);
++
++ spin_unlock_bh(&lp->tx_lock);
++ ndev->trans_start = jiffies;
++ return 0;
++}
++
++/* Get the MAC Address bit from the specified position */
++static unsigned get_bit(u8 *mac, unsigned bit)
++{
++ unsigned byte;
++
++ byte = mac[bit / 8];
++ byte >>= (bit & 0x7);
++ byte &= 1;
++
++ return byte;
++}
++
++/* Calculate a GEM MAC Address hash index */
++static unsigned calc_mac_hash(u8 *mac)
++{
++ int index_bit, mac_bit;
++ unsigned hash_index;
++
++ hash_index = 0;
++ mac_bit = 5;
++ for (index_bit = 5; index_bit >= 0; index_bit--) {
++ hash_index |= (get_bit(mac, mac_bit) ^
++ get_bit(mac, mac_bit + 6) ^
++ get_bit(mac, mac_bit + 12) ^
++ get_bit(mac, mac_bit + 18) ^
++ get_bit(mac, mac_bit + 24) ^
++ get_bit(mac, mac_bit + 30) ^
++ get_bit(mac, mac_bit + 36) ^
++ get_bit(mac, mac_bit + 42))
++ << index_bit;
++ mac_bit--;
++ }
++
++ return hash_index;
++}
++
++/**
++ * xemacps_set_hashtable - Add multicast addresses to the internal
++ * multicast-hash table. Called from xemac_set_rx_mode().
++ * @ndev: network interface device structure
++ *
++ * The hash address register is 64 bits long and takes up two
++ * locations in the memory map. The least significant bits are stored
++ * in EMAC_HSL and the most significant bits in EMAC_HSH.
++ *
++ * The unicast hash enable and the multicast hash enable bits in the
++ * network configuration register enable the reception of hash matched
++ * frames. The destination address is reduced to a 6 bit index into
++ * the 64 bit hash register using the following hash function. The
++ * hash function is an exclusive or of every sixth bit of the
++ * destination address.
++ *
++ * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47]
++ * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46]
++ * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45]
++ * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44]
++ * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43]
++ * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42]
++ *
++ * da[0] represents the least significant bit of the first byte
++ * received, that is, the multicast/unicast indicator, and da[47]
++ * represents the most significant bit of the last byte received. If
++ * the hash index, hi[n], points to a bit that is set in the hash
++ * register then the frame will be matched according to whether the
++ * frame is multicast or unicast. A multicast match will be signalled
++ * if the multicast hash enable bit is set, da[0] is 1 and the hash
++ * index points to a bit set in the hash register. A unicast match
++ * will be signalled if the unicast hash enable bit is set, da[0] is 0
++ * and the hash index points to a bit set in the hash register. To
++ * receive all multicast frames, the hash register should be set with
++ * all ones and the multicast hash enable bit should be set in the
++ * network configuration register.
++ **/
++static void xemacps_set_hashtable(struct net_device *ndev)
++{
++ struct netdev_hw_addr *curr;
++ u32 regvalh, regvall, hash_index;
++ u8 *mc_addr;
++ struct net_local *lp;
++
++ lp = netdev_priv(ndev);
++
++ regvalh = regvall = 0;
++
++ netdev_for_each_mc_addr(curr, ndev) {
++ if (!curr) /* end of list */
++ break;
++ mc_addr = curr->addr;
++ hash_index = calc_mac_hash(mc_addr);
++
++ if (hash_index >= XEMACPS_MAX_HASH_BITS) {
++ dev_err(&lp->pdev->dev,
++ "hash calculation out of range %d\n",
++ hash_index);
++ break;
++ }
++ if (hash_index < 32)
++ regvall |= (1 << hash_index);
++ else
++ regvalh |= (1 << (hash_index - 32));
++ }
++
++ xemacps_write(lp->baseaddr, XEMACPS_HASHL_OFFSET, regvall);
++ xemacps_write(lp->baseaddr, XEMACPS_HASHH_OFFSET, regvalh);
++}
++
++/**
++ * xemacps_set_rx_mode - enable/disable promiscuous and multicast modes
++ * @ndev: network interface device structure
++ **/
++static void xemacps_set_rx_mode(struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ u32 regval;
++
++ regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET);
++
++ /* promisc mode */
++ if (ndev->flags & IFF_PROMISC)
++ regval |= XEMACPS_NWCFG_COPYALLEN_MASK;
++ if (!(ndev->flags & IFF_PROMISC))
++ regval &= ~XEMACPS_NWCFG_COPYALLEN_MASK;
++
++ /* All multicast mode */
++ if (ndev->flags & IFF_ALLMULTI) {
++ regval |= XEMACPS_NWCFG_MCASTHASHEN_MASK;
++ xemacps_write(lp->baseaddr, XEMACPS_HASHL_OFFSET, ~0UL);
++ xemacps_write(lp->baseaddr, XEMACPS_HASHH_OFFSET, ~0UL);
++ /* Specific multicast mode */
++ } else if ((ndev->flags & IFF_MULTICAST)
++ && (netdev_mc_count(ndev) > 0)) {
++ regval |= XEMACPS_NWCFG_MCASTHASHEN_MASK;
++ xemacps_set_hashtable(ndev);
++ /* Disable multicast mode */
++ } else {
++ xemacps_write(lp->baseaddr, XEMACPS_HASHL_OFFSET, 0x0);
++ xemacps_write(lp->baseaddr, XEMACPS_HASHH_OFFSET, 0x0);
++ regval &= ~XEMACPS_NWCFG_MCASTHASHEN_MASK;
++ }
++
++ /* broadcast mode */
++ if (ndev->flags & IFF_BROADCAST)
++ regval &= ~XEMACPS_NWCFG_BCASTDI_MASK;
++ /* No broadcast */
++ if (!(ndev->flags & IFF_BROADCAST))
++ regval |= XEMACPS_NWCFG_BCASTDI_MASK;
++
++ xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval);
++}
++
++#define MIN_MTU 60
++#define MAX_MTU 1500
++/**
++ * xemacps_change_mtu - Change maximum transfer unit
++ * @ndev: network interface device structure
++ * @new_mtu: new vlaue for maximum frame size
++ * return: 0 on success, negative value if error.
++ **/
++static int xemacps_change_mtu(struct net_device *ndev, int new_mtu)
++{
++ if ((new_mtu < MIN_MTU) ||
++ ((new_mtu + ndev->hard_header_len) > MAX_MTU))
++ return -EINVAL;
++
++ ndev->mtu = new_mtu; /* change mtu in net_device structure */
++ return 0;
++}
++
++/**
++ * xemacps_get_settings - get device specific settings.
++ * Usage: Issue "ethtool ethX" under linux prompt.
++ * @ndev: network device
++ * @ecmd: ethtool command structure
++ * return: 0 on success, negative value if error.
++ **/
++static int
++xemacps_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ struct phy_device *phydev = lp->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_gset(phydev, ecmd);
++}
++
++/**
++ * xemacps_set_settings - set device specific settings.
++ * Usage: Issue "ethtool -s ethX speed 1000" under linux prompt
++ * to change speed
++ * @ndev: network device
++ * @ecmd: ethtool command structure
++ * return: 0 on success, negative value if error.
++ **/
++static int
++xemacps_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ struct phy_device *phydev = lp->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_sset(phydev, ecmd);
++}
++
++/**
++ * xemacps_get_drvinfo - report driver information
++ * Usage: Issue "ethtool -i ethX" under linux prompt
++ * @ndev: network device
++ * @ed: device driver information structure
++ **/
++static void
++xemacps_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *ed)
++{
++ struct net_local *lp = netdev_priv(ndev);
++
++ memset(ed, 0, sizeof(struct ethtool_drvinfo));
++ strcpy(ed->driver, lp->pdev->dev.driver->name);
++ strcpy(ed->version, DRIVER_VERSION);
++}
++
++/**
++ * xemacps_get_ringparam - get device dma ring information.
++ * Usage: Issue "ethtool -g ethX" under linux prompt
++ * @ndev: network device
++ * @erp: ethtool ring parameter structure
++ **/
++static void
++xemacps_get_ringparam(struct net_device *ndev, struct ethtool_ringparam *erp)
++{
++ memset(erp, 0, sizeof(struct ethtool_ringparam));
++
++ erp->rx_max_pending = XEMACPS_RECV_BD_CNT;
++ erp->tx_max_pending = XEMACPS_SEND_BD_CNT;
++ erp->rx_pending = 0;
++ erp->tx_pending = 0;
++}
++
++/**
++ * xemacps_get_wol - get device wake on lan status
++ * Usage: Issue "ethtool ethX" under linux prompt
++ * @ndev: network device
++ * @ewol: wol status
++ **/
++static void
++xemacps_get_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ u32 regval;
++
++ ewol->supported = WAKE_MAGIC | WAKE_ARP | WAKE_UCAST | WAKE_MCAST;
++
++ regval = xemacps_read(lp->baseaddr, XEMACPS_WOL_OFFSET);
++ if (regval | XEMACPS_WOL_MCAST_MASK)
++ ewol->wolopts |= WAKE_MCAST;
++ if (regval | XEMACPS_WOL_ARP_MASK)
++ ewol->wolopts |= WAKE_ARP;
++ if (regval | XEMACPS_WOL_SPEREG1_MASK)
++ ewol->wolopts |= WAKE_UCAST;
++ if (regval | XEMACPS_WOL_MAGIC_MASK)
++ ewol->wolopts |= WAKE_MAGIC;
++
++}
++
++/**
++ * xemacps_set_wol - set device wake on lan configuration
++ * Usage: Issue "ethtool -s ethX wol u|m|b|g" under linux prompt to enable
++ * specified type of packet.
++ * Usage: Issue "ethtool -s ethX wol d" under linux prompt to disable
++ * this feature.
++ * @ndev: network device
++ * @ewol: wol status
++ * return 0 on success, negative value if not supported
++ **/
++static int
++xemacps_set_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ u32 regval;
++
++ if (ewol->wolopts & ~(WAKE_MAGIC | WAKE_ARP | WAKE_UCAST | WAKE_MCAST))
++ return -EOPNOTSUPP;
++
++ regval = xemacps_read(lp->baseaddr, XEMACPS_WOL_OFFSET);
++ regval &= ~(XEMACPS_WOL_MCAST_MASK | XEMACPS_WOL_ARP_MASK |
++ XEMACPS_WOL_SPEREG1_MASK | XEMACPS_WOL_MAGIC_MASK);
++
++ if (ewol->wolopts & WAKE_MAGIC)
++ regval |= XEMACPS_WOL_MAGIC_MASK;
++ if (ewol->wolopts & WAKE_ARP)
++ regval |= XEMACPS_WOL_ARP_MASK;
++ if (ewol->wolopts & WAKE_UCAST)
++ regval |= XEMACPS_WOL_SPEREG1_MASK;
++ if (ewol->wolopts & WAKE_MCAST)
++ regval |= XEMACPS_WOL_MCAST_MASK;
++
++ xemacps_write(lp->baseaddr, XEMACPS_WOL_OFFSET, regval);
++
++ return 0;
++}
++
++/**
++ * xemacps_get_pauseparam - get device pause status
++ * Usage: Issue "ethtool -a ethX" under linux prompt
++ * @ndev: network device
++ * @epauseparam: pause parameter
++ *
++ * note: hardware supports only tx flow control
++ **/
++static void
++xemacps_get_pauseparam(struct net_device *ndev,
++ struct ethtool_pauseparam *epauseparm)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ u32 regval;
++
++ epauseparm->autoneg = 0;
++ epauseparm->rx_pause = 0;
++
++ regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET);
++ epauseparm->tx_pause = regval & XEMACPS_NWCFG_PAUSEEN_MASK;
++}
++
++/**
++ * xemacps_set_pauseparam - set device pause parameter(flow control)
++ * Usage: Issue "ethtool -A ethX tx on|off" under linux prompt
++ * @ndev: network device
++ * @epauseparam: pause parameter
++ * return 0 on success, negative value if not supported
++ *
++ * note: hardware supports only tx flow control
++ **/
++static int
++xemacps_set_pauseparam(struct net_device *ndev,
++ struct ethtool_pauseparam *epauseparm)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ u32 regval;
++
++ if (netif_running(ndev)) {
++ dev_err(&lp->pdev->dev,
++ "Please stop netif before apply configruation\n");
++ return -EFAULT;
++ }
++
++ regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET);
++
++ if (epauseparm->tx_pause)
++ regval |= XEMACPS_NWCFG_PAUSEEN_MASK;
++ if (!(epauseparm->tx_pause))
++ regval &= ~XEMACPS_NWCFG_PAUSEEN_MASK;
++
++ xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval);
++ return 0;
++}
++
++/**
++ * xemacps_get_stats - get device statistic raw data in 64bit mode
++ * @ndev: network device
++ **/
++static struct net_device_stats
++*xemacps_get_stats(struct net_device *ndev)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ struct net_device_stats *nstat = &lp->stats;
++
++ xemacps_update_stats((unsigned long)lp);
++ return nstat;
++}
++
++static struct ethtool_ops xemacps_ethtool_ops = {
++ .get_settings = xemacps_get_settings,
++ .set_settings = xemacps_set_settings,
++ .get_drvinfo = xemacps_get_drvinfo,
++ .get_link = ethtool_op_get_link, /* ethtool default */
++ .get_ringparam = xemacps_get_ringparam,
++ .get_wol = xemacps_get_wol,
++ .set_wol = xemacps_set_wol,
++ .get_pauseparam = xemacps_get_pauseparam,
++ .set_pauseparam = xemacps_set_pauseparam,
++};
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++static int xemacps_hwtstamp_ioctl(struct net_device *netdev,
++ struct ifreq *ifr, int cmd)
++{
++ struct hwtstamp_config config;
++ struct net_local *lp;
++ u32 regval;
++
++ lp = netdev_priv(netdev);
++
++ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
++ return -EFAULT;
++
++ /* reserved for future extensions */
++ if (config.flags)
++ return -EINVAL;
++
++ if ((config.tx_type != HWTSTAMP_TX_OFF) &&
++ (config.tx_type != HWTSTAMP_TX_ON))
++ return -ERANGE;
++
++ switch (config.rx_filter) {
++ case HWTSTAMP_FILTER_NONE:
++ break;
++ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
++ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
++ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
++ case HWTSTAMP_FILTER_ALL:
++ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
++ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
++ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
++ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
++ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
++ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
++ case HWTSTAMP_FILTER_PTP_V2_EVENT:
++ case HWTSTAMP_FILTER_PTP_V2_SYNC:
++ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
++ config.rx_filter = HWTSTAMP_FILTER_ALL;
++ regval = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET);
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET,
++ (regval | XEMACPS_NWCTRL_RXTSTAMP_MASK));
++ break;
++ default:
++ return -ERANGE;
++ }
++
++ config.tx_type = HWTSTAMP_TX_ON;
++ lp->hwtstamp_config = config;
++
++ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
++ -EFAULT : 0;
++}
++#endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */
++
++/**
++ * xemacps_ioctl - ioctl entry point
++ * @ndev: network device
++ * @rq: interface request ioctl
++ * @cmd: command code
++ *
++ * Called when user issues an ioctl request to the network device.
++ **/
++static int xemacps_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
++{
++ struct net_local *lp = netdev_priv(ndev);
++ struct phy_device *phydev = lp->phy_dev;
++
++ if (!netif_running(ndev))
++ return -EINVAL;
++
++ if (!phydev)
++ return -ENODEV;
++
++ switch (cmd) {
++ case SIOCGMIIPHY:
++ case SIOCGMIIREG:
++ case SIOCSMIIREG:
++ return phy_mii_ioctl(phydev, rq, cmd);
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++ case SIOCSHWTSTAMP:
++ return xemacps_hwtstamp_ioctl(ndev, rq, cmd);
++#endif
++ default:
++ dev_info(&lp->pdev->dev, "ioctl %d not implemented.\n", cmd);
++ return -EOPNOTSUPP;
++ }
++
++}
++
++/**
++ * xemacps_probe - Platform driver probe
++ * @pdev: Pointer to platform device structure
++ *
++ * Return 0 on success, negative value if error
++ */
++static int xemacps_probe(struct platform_device *pdev)
++{
++ struct resource *r_mem = NULL;
++ struct resource *r_irq = NULL;
++ struct net_device *ndev;
++ struct net_local *lp;
++ u32 regval = 0;
++ int rc = -ENXIO;
++
++ r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!r_mem || !r_irq) {
++ dev_err(&pdev->dev, "no IO resource defined.\n");
++ return -ENXIO;
++ }
++
++ ndev = alloc_etherdev(sizeof(*lp));
++ if (!ndev) {
++ dev_err(&pdev->dev, "etherdev allocation failed.\n");
++ return -ENOMEM;
++ }
++
++ SET_NETDEV_DEV(ndev, &pdev->dev);
++
++ lp = netdev_priv(ndev);
++ lp->pdev = pdev;
++ lp->ndev = ndev;
++
++ spin_lock_init(&lp->tx_lock);
++ spin_lock_init(&lp->rx_lock);
++ spin_lock_init(&lp->nwctrlreg_lock);
++
++ lp->baseaddr = devm_ioremap_resource(&pdev->dev, r_mem);
++ if (IS_ERR(lp->baseaddr)) {
++ dev_err(&pdev->dev, "failed to map baseaddress.\n");
++ rc = PTR_ERR(lp->baseaddr);
++ goto err_out_free_netdev;
++ }
++
++ dev_dbg(&lp->pdev->dev, "BASEADDRESS hw: %p virt: %p\n",
++ (void *)r_mem->start, lp->baseaddr);
++
++ ndev->irq = platform_get_irq(pdev, 0);
++
++ ndev->netdev_ops = &netdev_ops;
++ ndev->watchdog_timeo = TX_TIMEOUT;
++ ndev->ethtool_ops = &xemacps_ethtool_ops;
++ ndev->base_addr = r_mem->start;
++ ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG;
++ netif_napi_add(ndev, &lp->napi, xemacps_rx_poll, XEMACPS_NAPI_WEIGHT);
++
++ lp->ip_summed = CHECKSUM_UNNECESSARY;
++
++ rc = register_netdev(ndev);
++ if (rc) {
++ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
++ goto err_out_free_netdev;
++ }
++
++ if (ndev->irq == 54)
++ lp->enetnum = 0;
++ else
++ lp->enetnum = 1;
++
++ lp->aperclk = devm_clk_get(&pdev->dev, "aper_clk");
++ if (IS_ERR(lp->aperclk)) {
++ dev_err(&pdev->dev, "aper_clk clock not found.\n");
++ rc = PTR_ERR(lp->aperclk);
++ goto err_out_unregister_netdev;
++ }
++ lp->devclk = devm_clk_get(&pdev->dev, "ref_clk");
++ if (IS_ERR(lp->devclk)) {
++ dev_err(&pdev->dev, "ref_clk clock not found.\n");
++ rc = PTR_ERR(lp->devclk);
++ goto err_out_unregister_netdev;
++ }
++
++ rc = clk_prepare_enable(lp->aperclk);
++ if (rc) {
++ dev_err(&pdev->dev, "Unable to enable APER clock.\n");
++ goto err_out_unregister_netdev;
++ }
++ rc = clk_prepare_enable(lp->devclk);
++ if (rc) {
++ dev_err(&pdev->dev, "Unable to enable device clock.\n");
++ goto err_out_clk_dis_aper;
++ }
++
++ lp->clk_rate_change_nb.notifier_call = xemacps_clk_notifier_cb;
++ lp->clk_rate_change_nb.next = NULL;
++ if (clk_notifier_register(lp->devclk, &lp->clk_rate_change_nb))
++ dev_warn(&pdev->dev,
++ "Unable to register clock notifier.\n");
++
++#ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP
++ prop = of_get_property(lp->pdev->dev.of_node,
++ "xlnx,ptp-enet-clock", NULL);
++ if (prop)
++ lp->ptpenetclk = (u32)be32_to_cpup(prop);
++ else
++ lp->ptpenetclk = 133333328;
++#endif
++
++ lp->phy_node = of_parse_phandle(lp->pdev->dev.of_node,
++ "phy-handle", 0);
++ lp->gmii2rgmii_phy_node = of_parse_phandle(lp->pdev->dev.of_node,
++ "gmii2rgmii-phy-handle", 0);
++ rc = of_get_phy_mode(lp->pdev->dev.of_node);
++ if (rc < 0) {
++ dev_err(&lp->pdev->dev, "error in getting phy i/f\n");
++ goto err_out_unregister_clk_notifier;
++ }
++
++ lp->phy_interface = rc;
++
++ /* Set MDIO clock divider */
++ regval = (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK);
++ xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval);
++
++
++ regval = XEMACPS_NWCTRL_MDEN_MASK;
++ xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regval);
++
++ rc = xemacps_mii_init(lp);
++ if (rc) {
++ dev_err(&lp->pdev->dev, "error in xemacps_mii_init\n");
++ goto err_out_unregister_clk_notifier;
++ }
++
++ xemacps_update_hwaddr(lp);
++ tasklet_init(&lp->tx_bdreclaim_tasklet, xemacps_tx_poll,
++ (unsigned long) ndev);
++ tasklet_disable(&lp->tx_bdreclaim_tasklet);
++
++ lp->txtimeout_handler_wq = create_singlethread_workqueue(DRIVER_NAME);
++ INIT_WORK(&lp->txtimeout_reinit, xemacps_reinit_for_txtimeout);
++
++ platform_set_drvdata(pdev, ndev);
++ pm_runtime_set_active(&pdev->dev);
++ pm_runtime_enable(&pdev->dev);
++
++ dev_info(&lp->pdev->dev, "pdev->id %d, baseaddr 0x%08lx, irq %d\n",
++ pdev->id, ndev->base_addr, ndev->irq);
++
++ rc = devm_request_irq(&pdev->dev, ndev->irq, &xemacps_interrupt, 0,
++ ndev->name, ndev);
++ if (rc) {
++ dev_err(&lp->pdev->dev, "Unable to request IRQ %p, error %d\n",
++ r_irq, rc);
++ goto err_out_unregister_clk_notifier;
++ }
++
++ return 0;
++
++err_out_unregister_clk_notifier:
++ clk_notifier_unregister(lp->devclk, &lp->clk_rate_change_nb);
++ clk_disable_unprepare(lp->devclk);
++err_out_clk_dis_aper:
++ clk_disable_unprepare(lp->aperclk);
++err_out_unregister_netdev:
++ unregister_netdev(ndev);
++err_out_free_netdev:
++ free_netdev(ndev);
++ platform_set_drvdata(pdev, NULL);
++ return rc;
++}
++
++/**
++ * xemacps_remove - called when platform driver is unregistered
++ * @pdev: Pointer to the platform device structure
++ *
++ * return: 0 on success
++ */
++static int xemacps_remove(struct platform_device *pdev)
++{
++ struct net_device *ndev = platform_get_drvdata(pdev);
++ struct net_local *lp;
++
++ if (ndev) {
++ lp = netdev_priv(ndev);
++
++ mdiobus_unregister(lp->mii_bus);
++ kfree(lp->mii_bus->irq);
++ mdiobus_free(lp->mii_bus);
++ unregister_netdev(ndev);
++
++ clk_notifier_unregister(lp->devclk, &lp->clk_rate_change_nb);
++ if (!pm_runtime_suspended(&pdev->dev)) {
++ clk_disable_unprepare(lp->devclk);
++ clk_disable_unprepare(lp->aperclk);
++ } else {
++ clk_unprepare(lp->devclk);
++ clk_unprepare(lp->aperclk);
++ }
++
++ free_netdev(ndev);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++#ifdef CONFIG_PM_SLEEP
++/**
++ * xemacps_suspend - Suspend event
++ * @device: Pointer to device structure
++ *
++ * Return 0
++ */
++static int xemacps_suspend(struct device *device)
++{
++ struct platform_device *pdev = container_of(device,
++ struct platform_device, dev);
++ struct net_device *ndev = platform_get_drvdata(pdev);
++ struct net_local *lp = netdev_priv(ndev);
++
++ netif_device_detach(ndev);
++ if (!pm_runtime_suspended(device)) {
++ clk_disable(lp->devclk);
++ clk_disable(lp->aperclk);
++ }
++ return 0;
++}
++
++/**
++ * xemacps_resume - Resume after previous suspend
++ * @pdev: Pointer to platform device structure
++ *
++ * Returns 0 on success, errno otherwise.
++ */
++static int xemacps_resume(struct device *device)
++{
++ struct platform_device *pdev = container_of(device,
++ struct platform_device, dev);
++ struct net_device *ndev = platform_get_drvdata(pdev);
++ struct net_local *lp = netdev_priv(ndev);
++
++ if (!pm_runtime_suspended(device)) {
++ int ret;
++
++ ret = clk_enable(lp->aperclk);
++ if (ret)
++ return ret;
++
++ ret = clk_enable(lp->devclk);
++ if (ret) {
++ clk_disable(lp->aperclk);
++ return ret;
++ }
++ }
++ netif_device_attach(ndev);
++ return 0;
++}
++#endif /* ! CONFIG_PM_SLEEP */
++
++#ifdef CONFIG_PM_RUNTIME
++static int xemacps_runtime_idle(struct device *dev)
++{
++ return pm_schedule_suspend(dev, 1);
++}
++
++static int xemacps_runtime_resume(struct device *device)
++{
++ int ret;
++ struct platform_device *pdev = container_of(device,
++ struct platform_device, dev);
++ struct net_device *ndev = platform_get_drvdata(pdev);
++ struct net_local *lp = netdev_priv(ndev);
++
++ ret = clk_enable(lp->aperclk);
++ if (ret)
++ return ret;
++
++ ret = clk_enable(lp->devclk);
++ if (ret) {
++ clk_disable(lp->aperclk);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int xemacps_runtime_suspend(struct device *device)
++{
++ struct platform_device *pdev = container_of(device,
++ struct platform_device, dev);
++ struct net_device *ndev = platform_get_drvdata(pdev);
++ struct net_local *lp = netdev_priv(ndev);
++
++ clk_disable(lp->devclk);
++ clk_disable(lp->aperclk);
++ return 0;
++}
++#endif /* CONFIG_PM_RUNTIME */
++
++static const struct dev_pm_ops xemacps_dev_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(xemacps_suspend, xemacps_resume)
++ SET_RUNTIME_PM_OPS(xemacps_runtime_suspend, xemacps_runtime_resume,
++ xemacps_runtime_idle)
++};
++#define XEMACPS_PM (&xemacps_dev_pm_ops)
++#else /* ! CONFIG_PM */
++#define XEMACPS_PM NULL
++#endif /* ! CONFIG_PM */
++
++static struct net_device_ops netdev_ops = {
++ .ndo_open = xemacps_open,
++ .ndo_stop = xemacps_close,
++ .ndo_start_xmit = xemacps_start_xmit,
++ .ndo_set_rx_mode = xemacps_set_rx_mode,
++ .ndo_set_mac_address = xemacps_set_mac_address,
++ .ndo_do_ioctl = xemacps_ioctl,
++ .ndo_change_mtu = xemacps_change_mtu,
++ .ndo_tx_timeout = xemacps_tx_timeout,
++ .ndo_get_stats = xemacps_get_stats,
++};
++
++static struct of_device_id xemacps_of_match[] = {
++ { .compatible = "xlnx,ps7-ethernet-1.00.a", },
++ { /* end of table */}
++};
++MODULE_DEVICE_TABLE(of, xemacps_of_match);
++
++static struct platform_driver xemacps_driver = {
++ .probe = xemacps_probe,
++ .remove = xemacps_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = xemacps_of_match,
++ .pm = XEMACPS_PM,
++ },
++};
++
++module_platform_driver(xemacps_driver);
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_DESCRIPTION("Xilinx Ethernet driver");
++MODULE_LICENSE("GPL v2");
diff --git a/patches.zynq/0005-gpio-xilinx-merge-Xilinx-gpio-support-into-LTSI-3.10.patch b/patches.zynq/0005-gpio-xilinx-merge-Xilinx-gpio-support-into-LTSI-3.10.patch
new file mode 100644
index 00000000000000..f7d7d0dd71f973
--- /dev/null
+++ b/patches.zynq/0005-gpio-xilinx-merge-Xilinx-gpio-support-into-LTSI-3.10.patch
@@ -0,0 +1,1207 @@
+From 142b902012ca81b1dfb65700f203aab9be6929aa Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Fri, 20 Dec 2013 15:24:18 +0900
+Subject: gpio: xilinx: merge Xilinx gpio support into LTSI 3.10.y
+
+This commits merges support for the GPIO bus from the Xilinx
+master branch (commit efc27505715e64526653f35274717c0fc56491e3 in
+master branch).
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/gpio/Kconfig | 12
+ drivers/gpio/Makefile | 1
+ drivers/gpio/gpio-xilinx.c | 321 +++++++++++++++++--
+ drivers/gpio/gpio-xilinxps.c | 722 +++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1026 insertions(+), 30 deletions(-)
+ create mode 100644 drivers/gpio/gpio-xilinxps.c
+
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -234,9 +234,17 @@ config GPIO_TS5500
+
+ config GPIO_XILINX
+ bool "Xilinx GPIO support"
+- depends on PPC_OF || MICROBLAZE
++ depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
++ select GENERIC_IRQ_CHIP
+ help
+- Say yes here to support the Xilinx FPGA GPIO device
++ Say yes here to support the Xilinx AXI/XPS GPIO device
++
++config GPIO_XILINX_PS
++ tristate "Xilinx GPIO PS"
++ depends on ARCH_ZYNQ
++ select GENERIC_IRQ_CHIP
++ help
++ Say yes here to support Xilinx GPIO PS controller
+
+ config GPIO_VR41XX
+ tristate "NEC VR4100 series General-purpose I/O Uint support"
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -87,3 +87,4 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x
+ obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
+ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
+ obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
++obj-$(CONFIG_GPIO_XILINX_PS) += gpio-xilinxps.o
+--- a/drivers/gpio/gpio-xilinx.c
++++ b/drivers/gpio/gpio-xilinx.c
+@@ -17,15 +17,25 @@
+ #include <linux/errno.h>
+ #include <linux/module.h>
+ #include <linux/of_device.h>
++#include <linux/of_irq.h>
+ #include <linux/of_platform.h>
+ #include <linux/of_gpio.h>
++#include <linux/interrupt.h>
+ #include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqdomain.h>
+ #include <linux/gpio.h>
+ #include <linux/slab.h>
+
+ /* Register Offset Definitions */
+-#define XGPIO_DATA_OFFSET (0x0) /* Data register */
+-#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */
++#define XGPIO_DATA_OFFSET 0x0 /* Data register */
++#define XGPIO_TRI_OFFSET 0x4 /* I/O direction register */
++#define XGPIO_GIER_OFFSET 0x11c /* Global Interrupt Enable */
++#define XGPIO_GIER_IE BIT(31)
++
++#define XGPIO_IPISR_OFFSET 0x120 /* IP Interrupt Status */
++#define XGPIO_IPIER_OFFSET 0x128 /* IP Interrupt Enable */
+
+ #define XGPIO_CHANNEL_OFFSET 0x8
+
+@@ -40,18 +50,24 @@
+
+ /**
+ * struct xgpio_instance - Stores information about GPIO device
+- * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks
+- * gpio_state: GPIO state shadow register
+- * gpio_dir: GPIO direction shadow register
+- * offset: GPIO channel offset
+- * gpio_lock: Lock used for synchronization
++ * @mmchip: OF GPIO chip for memory mapped banks
++ * @gpio_state: GPIO state shadow register
++ * @gpio_dir: GPIO direction shadow register
++ * @offset: GPIO channel offset
++ * @irq_base: GPIO channel irq base address
++ * @irq_enable: GPIO irq enable/disable bitfield
++ * @gpio_lock: Lock used for synchronization
++ * @irq_domain: irq_domain of the controller
+ */
+ struct xgpio_instance {
+ struct of_mm_gpio_chip mmchip;
+ u32 gpio_state;
+ u32 gpio_dir;
+ u32 offset;
++ int irq_base;
++ u32 irq_enable;
+ spinlock_t gpio_lock;
++ struct irq_domain *irq_domain;
+ };
+
+ /**
+@@ -59,8 +75,11 @@ struct xgpio_instance {
+ * @gc: Pointer to gpio_chip device structure.
+ * @gpio: GPIO signal number.
+ *
+- * This function reads the specified signal of the GPIO device. It returns 0 if
+- * the signal clear, 1 if signal is set or negative value on error.
++ * This function reads the specified signal of the GPIO device.
++ *
++ * Return:
++ * 0 if direction of GPIO signals is set as input otherwise it
++ * returns negative error value.
+ */
+ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
+ {
+@@ -110,8 +129,10 @@ static void xgpio_set(struct gpio_chip *
+ * @gpio: GPIO signal number.
+ *
+ * This function sets the direction of specified GPIO signal as input.
+- * It returns 0 if direction of GPIO signals is set as input otherwise it
+- * returns negative error value.
++ *
++ * Return:
++ * 0 - if direction of GPIO signals is set as input
++ * otherwise it returns negative error value.
+ */
+ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+ {
+@@ -138,8 +159,10 @@ static int xgpio_dir_in(struct gpio_chip
+ * @gpio: GPIO signal number.
+ * @val: Value to be written to specified signal.
+ *
+- * This function sets the direction of specified GPIO signal as output. If all
+- * GPIO signals of GPIO chip is configured as input then it returns
++ * This function sets the direction of specified GPIO signal as output.
++ *
++ * Return:
++ * If all GPIO signals of GPIO chip is configured as input then it returns
+ * error otherwise it returns 0.
+ */
+ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+@@ -171,7 +194,7 @@ static int xgpio_dir_out(struct gpio_chi
+
+ /**
+ * xgpio_save_regs - Set initial values of GPIO pins
+- * @mm_gc: pointer to memory mapped GPIO chip structure
++ * @mm_gc: Pointer to memory mapped GPIO chip structure
+ */
+ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
+ {
+@@ -185,20 +208,245 @@ static void xgpio_save_regs(struct of_mm
+ }
+
+ /**
++ * xgpio_xlate - Set initial values of GPIO pins
++ * @gc: Pointer to gpio_chip device structure.
++ * @gpiospec: gpio specifier as found in the device tree
++ * @flags: A flags pointer based on binding
++ *
++ * Return:
++ * irq number otherwise -EINVAL
++ */
++static int xgpio_xlate(struct gpio_chip *gc,
++ const struct of_phandle_args *gpiospec, u32 *flags)
++{
++ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
++ struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance,
++ mmchip);
++
++ if (gpiospec->args[1] == chip->offset)
++ return gpiospec->args[0];
++
++ return -EINVAL;
++}
++
++/**
++ * xgpio_irq_mask - Write the specified signal of the GPIO device.
++ * @irq_data: per irq and chip data passed down to chip functions
++ */
++static void xgpio_irq_mask(struct irq_data *irq_data)
++{
++ unsigned long flags;
++ struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
++ struct of_mm_gpio_chip *mm_gc = &chip->mmchip;
++ u32 offset = irq_data->irq - chip->irq_base;
++ u32 temp;
++
++ pr_debug("%s: Disable %d irq, irq_enable_mask 0x%x\n",
++ __func__, offset, chip->irq_enable);
++
++ spin_lock_irqsave(&chip->gpio_lock, flags);
++
++ chip->irq_enable &= ~BIT(offset);
++
++ if (!chip->irq_enable) {
++ /* Enable per channel interrupt */
++ temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET);
++ temp &= chip->offset / XGPIO_CHANNEL_OFFSET + 1;
++ xgpio_writereg(mm_gc->regs + XGPIO_IPIER_OFFSET, temp);
++
++ /* Disable global interrupt if channel interrupts are unused */
++ temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET);
++ if (!temp)
++ xgpio_writereg(mm_gc->regs + XGPIO_GIER_OFFSET,
++ ~XGPIO_GIER_IE);
++
++ }
++ spin_unlock_irqrestore(&chip->gpio_lock, flags);
++}
++
++/**
++ * xgpio_irq_unmask - Write the specified signal of the GPIO device.
++ * @irq_data: per irq and chip data passed down to chip functions
++ */
++static void xgpio_irq_unmask(struct irq_data *irq_data)
++{
++ unsigned long flags;
++ struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
++ struct of_mm_gpio_chip *mm_gc = &chip->mmchip;
++ u32 offset = irq_data->irq - chip->irq_base;
++ u32 temp;
++
++ pr_debug("%s: Enable %d irq, irq_enable_mask 0x%x\n",
++ __func__, offset, chip->irq_enable);
++
++ /* Setup pin as input */
++ xgpio_dir_in(&mm_gc->gc, offset);
++
++ spin_lock_irqsave(&chip->gpio_lock, flags);
++
++ chip->irq_enable |= BIT(offset);
++
++ if (chip->irq_enable) {
++
++ /* Enable per channel interrupt */
++ temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET);
++ temp |= chip->offset / XGPIO_CHANNEL_OFFSET + 1;
++ xgpio_writereg(mm_gc->regs + XGPIO_IPIER_OFFSET, temp);
++
++ /* Enable global interrupts */
++ xgpio_writereg(mm_gc->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE);
++ }
++
++ spin_unlock_irqrestore(&chip->gpio_lock, flags);
++}
++
++/**
++ * xgpio_set_irq_type - Write the specified signal of the GPIO device.
++ * @irq_data: Per irq and chip data passed down to chip functions
++ * @type: Interrupt type that is to be set for the gpio pin
++ *
++ * Return:
++ * 0 if interrupt type is supported otherwise otherwise -EINVAL
++ */
++static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
++{
++ /* Only rising edge case is supported now */
++ if (type == IRQ_TYPE_EDGE_RISING)
++ return 0;
++
++ return -EINVAL;
++}
++
++/* irq chip descriptor */
++static struct irq_chip xgpio_irqchip = {
++ .name = "xgpio",
++ .irq_mask = xgpio_irq_mask,
++ .irq_unmask = xgpio_irq_unmask,
++ .irq_set_type = xgpio_set_irq_type,
++};
++
++/**
++ * xgpio_to_irq - Find out gpio to Linux irq mapping
++ * @gc: Pointer to gpio_chip device structure.
++ * @offset: Gpio pin offset
++ *
++ * Return:
++ * irq number otherwise -EINVAL
++ */
++static int xgpio_to_irq(struct gpio_chip *gc, unsigned offset)
++{
++ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
++ struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance,
++ mmchip);
++
++ return irq_find_mapping(chip->irq_domain, offset);
++}
++
++/**
++ * xgpio_irqhandler - Gpio interrupt service routine
++ * @irq: gpio irq number
++ * @desc: Pointer to interrupt description
++ */
++static void xgpio_irqhandler(unsigned int irq, struct irq_desc *desc)
++{
++ struct xgpio_instance *chip = (struct xgpio_instance *)
++ irq_get_handler_data(irq);
++ struct of_mm_gpio_chip *mm_gc = &chip->mmchip;
++ struct irq_chip *irqchip = irq_desc_get_chip(desc);
++ int offset;
++ unsigned long val;
++
++ chained_irq_enter(irqchip, desc);
++
++ val = xgpio_readreg(mm_gc->regs + chip->offset);
++ /* Only rising edge is supported */
++ val &= chip->irq_enable;
++
++ for_each_set_bit(offset, &val, chip->mmchip.gc.ngpio) {
++ generic_handle_irq(chip->irq_base + offset);
++ }
++
++ xgpio_writereg(mm_gc->regs + XGPIO_IPISR_OFFSET,
++ chip->offset / XGPIO_CHANNEL_OFFSET + 1);
++
++ chained_irq_exit(irqchip, desc);
++}
++
++static struct lock_class_key gpio_lock_class;
++
++/**
++ * xgpio_irq_setup - Allocate irq for gpio and setup appropriate functions
++ * @np: Device node of the GPIO chip
++ * @chip: Pointer to private gpio channel structure
++ *
++ * Return:
++ * 0 if success, otherwise -1
++ */
++static int xgpio_irq_setup(struct device_node *np, struct xgpio_instance *chip)
++{
++ u32 pin_num;
++ struct resource res;
++
++ int ret = of_irq_to_resource(np, 0, &res);
++ if (!ret) {
++ pr_info("GPIO IRQ not connected\n");
++ return 0;
++ }
++
++ chip->mmchip.gc.of_xlate = xgpio_xlate;
++ chip->mmchip.gc.of_gpio_n_cells = 2;
++ chip->mmchip.gc.to_irq = xgpio_to_irq;
++
++ chip->irq_base = irq_alloc_descs(-1, 0, chip->mmchip.gc.ngpio, 0);
++ if (chip->irq_base < 0) {
++ pr_err("Couldn't allocate IRQ numbers\n");
++ return -1;
++ }
++ chip->irq_domain = irq_domain_add_legacy(np, chip->mmchip.gc.ngpio,
++ chip->irq_base, 0,
++ &irq_domain_simple_ops, NULL);
++
++ /*
++ * set the irq chip, handler and irq chip data for callbacks for
++ * each pin
++ */
++ for (pin_num = 0; pin_num < chip->mmchip.gc.ngpio; pin_num++) {
++ u32 gpio_irq = irq_find_mapping(chip->irq_domain, pin_num);
++ irq_set_lockdep_class(gpio_irq, &gpio_lock_class);
++ pr_debug("IRQ Base: %d, Pin %d = IRQ %d\n",
++ chip->irq_base, pin_num, gpio_irq);
++ irq_set_chip_and_handler(gpio_irq, &xgpio_irqchip,
++ handle_simple_irq);
++ irq_set_chip_data(gpio_irq, (void *)chip);
++#ifdef CONFIG_ARCH_ZYNQ
++ set_irq_flags(gpio_irq, IRQF_VALID);
++#endif
++ }
++ irq_set_handler_data(res.start, (void *)chip);
++ irq_set_chained_handler(res.start, xgpio_irqhandler);
++
++ return 0;
++}
++
++/**
+ * xgpio_of_probe - Probe method for the GPIO device.
+ * @np: pointer to device tree node
+ *
+ * This function probes the GPIO device in the device tree. It initializes the
+- * driver data structure. It returns 0, if the driver is bound to the GPIO
+- * device, or a negative value if there is an error.
++ * driver data structure.
++ *
++ * Return:
++ * It returns 0, if the driver is bound to the GPIO device, or
++ * a negative value if there is an error.
+ */
+-static int xgpio_of_probe(struct device_node *np)
++static int xgpio_of_probe(struct platform_device *pdev)
+ {
++ struct device_node *np = pdev->dev.of_node;
+ struct xgpio_instance *chip;
+ int status = 0;
+ const u32 *tree_info;
+
+- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
++ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+@@ -230,18 +478,24 @@ static int xgpio_of_probe(struct device_
+ /* Call the OF gpio helper to setup and register the GPIO device */
+ status = of_mm_gpiochip_add(np, &chip->mmchip);
+ if (status) {
+- kfree(chip);
+ pr_err("%s: error in probe function with status %d\n",
+ np->full_name, status);
+ return status;
+ }
+
++ status = xgpio_irq_setup(np, chip);
++ if (status) {
++ pr_err("%s: GPIO IRQ initialization failed %d\n",
++ np->full_name, status);
++ return status;
++ }
++
+ pr_info("XGpio: %s: registered, base is %d\n", np->full_name,
+ chip->mmchip.gc.base);
+
+ tree_info = of_get_property(np, "xlnx,is-dual", NULL);
+ if (tree_info && be32_to_cpup(tree_info)) {
+- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
++ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+@@ -274,12 +528,18 @@ static int xgpio_of_probe(struct device_
+
+ chip->mmchip.save_regs = xgpio_save_regs;
+
++ status = xgpio_irq_setup(np, chip);
++ if (status) {
++ pr_err("%s: GPIO IRQ initialization failed %d\n",
++ np->full_name, status);
++ return status;
++ }
++
+ /* Call the OF gpio helper to setup and register the GPIO dev */
+ status = of_mm_gpiochip_add(np, &chip->mmchip);
+ if (status) {
+- kfree(chip);
+ pr_err("%s: error in probe function with status %d\n",
+- np->full_name, status);
++ np->full_name, status);
+ return status;
+ }
+ pr_info("XGpio: %s: dual channel registered, base is %d\n",
+@@ -293,15 +553,20 @@ static struct of_device_id xgpio_of_matc
+ { .compatible = "xlnx,xps-gpio-1.00.a", },
+ { /* end of list */ },
+ };
++MODULE_DEVICE_TABLE(of, xgpio_of_match);
++
++static struct platform_driver xilinx_gpio_driver = {
++ .probe = xgpio_of_probe,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "xilinx-gpio",
++ .of_match_table = xgpio_of_match,
++ },
++};
+
+ static int __init xgpio_init(void)
+ {
+- struct device_node *np;
+-
+- for_each_matching_node(np, xgpio_of_match)
+- xgpio_of_probe(np);
+-
+- return 0;
++ return platform_driver_register(&xilinx_gpio_driver);
+ }
+
+ /* Make sure we get initialized before anyone else tries to use us */
+--- /dev/null
++++ b/drivers/gpio/gpio-xilinxps.c
+@@ -0,0 +1,722 @@
++/*
++ * Xilinx PS GPIO device driver
++ *
++ * 2009-2011 (c) Xilinx, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License as published by the Free Software
++ * Foundation; either version 2 of the License, or (at your option) any later
++ * version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
++ * Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/export.h>
++#include <linux/gpio.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/pm_wakeup.h>
++#include <linux/slab.h>
++#include <asm/mach/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/irqchip/chained_irq.h>
++
++#define DRIVER_NAME "xgpiops"
++#define XGPIOPS_NR_GPIOS 118
++
++static struct irq_domain *irq_domain;
++
++/* Register offsets for the GPIO device */
++
++#define XGPIOPS_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK)) /* LSW Mask &
++ Data -WO */
++#define XGPIOPS_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK)) /* MSW Mask &
++ Data -WO */
++#define XGPIOPS_DATA_OFFSET(BANK) (0x040 + (4 * BANK)) /* Data Register
++ -RW */
++#define XGPIOPS_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK)) /* Direction
++ mode reg-RW */
++#define XGPIOPS_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK)) /* Output
++ enable reg-RW
++ */
++#define XGPIOPS_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK)) /* Interrupt
++ mask reg-RO */
++#define XGPIOPS_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK)) /* Interrupt
++ enable reg-WO
++ */
++#define XGPIOPS_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK)) /* Interrupt
++ disable reg-WO
++ */
++#define XGPIOPS_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK)) /* Interrupt
++ status reg-RO
++ */
++#define XGPIOPS_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK)) /* Interrupt
++ type reg-RW
++ */
++#define XGPIOPS_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK)) /* Interrupt
++ polarity reg
++ -RW */
++#define XGPIOPS_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK)) /* Interrupt on
++ any, reg-RW */
++
++/* Read/Write access to the GPIO PS registers */
++#define xgpiops_readreg(offset) __raw_readl(offset)
++#define xgpiops_writereg(val, offset) __raw_writel(val, offset)
++
++static unsigned int xgpiops_pin_table[] = {
++ 31, /* 0 - 31 */
++ 53, /* 32 - 53 */
++ 85, /* 54 - 85 */
++ 117 /* 86 - 117 */
++};
++
++/**
++ * struct xgpiops - gpio device private data structure
++ * @chip: instance of the gpio_chip
++ * @base_addr: base address of the GPIO device
++ * @gpio_lock: lock used for synchronization
++ */
++struct xgpiops {
++ struct gpio_chip chip;
++ void __iomem *base_addr;
++ unsigned int irq;
++ unsigned int irq_base;
++ struct clk *clk;
++ spinlock_t gpio_lock;
++};
++
++/**
++ * xgpiops_get_bank_pin - Get the bank number and pin number within that bank
++ * for a given pin in the GPIO device
++ * @pin_num: gpio pin number within the device
++ * @bank_num: an output parameter used to return the bank number of the gpio
++ * pin
++ * @bank_pin_num: an output parameter used to return pin number within a bank
++ * for the given gpio pin
++ *
++ * Returns the bank number.
++ */
++static inline void xgpiops_get_bank_pin(unsigned int pin_num,
++ unsigned int *bank_num,
++ unsigned int *bank_pin_num)
++{
++ for (*bank_num = 0; *bank_num < 4; (*bank_num)++)
++ if (pin_num <= xgpiops_pin_table[*bank_num])
++ break;
++
++ if (*bank_num == 0)
++ *bank_pin_num = pin_num;
++ else
++ *bank_pin_num = pin_num %
++ (xgpiops_pin_table[*bank_num - 1] + 1);
++}
++
++/**
++ * xgpiops_get_value - Get the state of the specified pin of GPIO device
++ * @chip: gpio_chip instance to be worked on
++ * @pin: gpio pin number within the device
++ *
++ * This function reads the state of the specified pin of the GPIO device.
++ * It returns 0 if the pin is low, 1 if pin is high.
++ */
++static int xgpiops_get_value(struct gpio_chip *chip, unsigned int pin)
++{
++ unsigned int bank_num, bank_pin_num;
++ struct xgpiops *gpio = container_of(chip, struct xgpiops, chip);
++
++ xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num);
++
++ return (xgpiops_readreg(gpio->base_addr +
++ XGPIOPS_DATA_OFFSET(bank_num)) >>
++ bank_pin_num) & 1;
++}
++
++/**
++ * xgpiops_set_value - Modify the state of the pin with specified value
++ * @chip: gpio_chip instance to be worked on
++ * @pin: gpio pin number within the device
++ * @state: value used to modify the state of the specified pin
++ *
++ * This function calculates the register offset (i.e to lower 16 bits or
++ * upper 16 bits) based on the given pin number and sets the state of a
++ * gpio pin to the specified value. The state is either 0 or non-zero.
++ */
++static void xgpiops_set_value(struct gpio_chip *chip, unsigned int pin,
++ int state)
++{
++ unsigned long flags;
++ unsigned int reg_offset;
++ unsigned int bank_num, bank_pin_num;
++ struct xgpiops *gpio = container_of(chip, struct xgpiops, chip);
++
++ xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num);
++
++ if (bank_pin_num >= 16) {
++ bank_pin_num -= 16; /* only 16 data bits in bit maskable reg */
++ reg_offset = XGPIOPS_DATA_MSW_OFFSET(bank_num);
++ } else {
++ reg_offset = XGPIOPS_DATA_LSW_OFFSET(bank_num);
++ }
++
++ /*
++ * get the 32 bit value to be written to the mask/data register where
++ * the upper 16 bits is the mask and lower 16 bits is the data
++ */
++ if (state)
++ state = 1;
++ state = ~(1 << (bank_pin_num + 16)) & ((state << bank_pin_num) |
++ 0xFFFF0000);
++
++ spin_lock_irqsave(&gpio->gpio_lock, flags);
++ xgpiops_writereg(state, gpio->base_addr + reg_offset);
++ spin_unlock_irqrestore(&gpio->gpio_lock, flags);
++}
++
++/**
++ * xgpiops_dir_in - Set the direction of the specified GPIO pin as input
++ * @chip: gpio_chip instance to be worked on
++ * @pin: gpio pin number within the device
++ *
++ * This function uses the read-modify-write sequence to set the direction of
++ * the gpio pin as input. Returns 0 always.
++ */
++static int xgpiops_dir_in(struct gpio_chip *chip, unsigned int pin)
++{
++ unsigned int reg, bank_num, bank_pin_num;
++ struct xgpiops *gpio = container_of(chip, struct xgpiops, chip);
++
++ xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num);
++ /* clear the bit in direction mode reg to set the pin as input */
++ reg = xgpiops_readreg(gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num));
++ reg &= ~(1 << bank_pin_num);
++ xgpiops_writereg(reg, gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num));
++
++ return 0;
++}
++
++/**
++ * xgpiops_dir_out - Set the direction of the specified GPIO pin as output
++ * @chip: gpio_chip instance to be worked on
++ * @pin: gpio pin number within the device
++ * @state: value to be written to specified pin
++ *
++ * This function sets the direction of specified GPIO pin as output, configures
++ * the Output Enable register for the pin and uses xgpiops_set to set the state
++ * of the pin to the value specified. Returns 0 always.
++ */
++static int xgpiops_dir_out(struct gpio_chip *chip, unsigned int pin, int state)
++{
++ struct xgpiops *gpio = container_of(chip, struct xgpiops, chip);
++ unsigned int reg, bank_num, bank_pin_num;
++
++ xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num);
++
++ /* set the GPIO pin as output */
++ reg = xgpiops_readreg(gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num));
++ reg |= 1 << bank_pin_num;
++ xgpiops_writereg(reg, gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num));
++
++ /* configure the output enable reg for the pin */
++ reg = xgpiops_readreg(gpio->base_addr + XGPIOPS_OUTEN_OFFSET(bank_num));
++ reg |= 1 << bank_pin_num;
++ xgpiops_writereg(reg, gpio->base_addr + XGPIOPS_OUTEN_OFFSET(bank_num));
++
++ /* set the state of the pin */
++ xgpiops_set_value(chip, pin, state);
++ return 0;
++}
++
++static int xgpiops_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ return irq_find_mapping(irq_domain, offset);
++}
++
++/**
++ * xgpiops_irq_ack - Acknowledge the interrupt of a gpio pin
++ * @irq_data: irq data containing irq number of gpio pin for the irq to ack
++ *
++ * This function calculates gpio pin number from irq number and sets the bit
++ * in the Interrupt Status Register of the corresponding bank, to ACK the irq.
++ */
++static void xgpiops_irq_ack(struct irq_data *irq_data)
++{
++ struct xgpiops *gpio = (struct xgpiops *)
++ irq_data_get_irq_chip_data(irq_data);
++ unsigned int device_pin_num, bank_num, bank_pin_num;
++
++ device_pin_num = irq_data->hwirq;
++ xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
++ xgpiops_writereg(1 << bank_pin_num, gpio->base_addr +
++ (XGPIOPS_INTSTS_OFFSET(bank_num)));
++}
++
++/**
++ * xgpiops_irq_mask - Disable the interrupts for a gpio pin
++ * @irq: irq number of gpio pin for which interrupt is to be disabled
++ *
++ * This function calculates gpio pin number from irq number and sets the
++ * bit in the Interrupt Disable register of the corresponding bank to disable
++ * interrupts for that pin.
++ */
++static void xgpiops_irq_mask(struct irq_data *irq_data)
++{
++ struct xgpiops *gpio = (struct xgpiops *)
++ irq_data_get_irq_chip_data(irq_data);
++ unsigned int device_pin_num, bank_num, bank_pin_num;
++
++ device_pin_num = irq_data->hwirq;
++ xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
++ xgpiops_writereg(1 << bank_pin_num,
++ gpio->base_addr + XGPIOPS_INTDIS_OFFSET(bank_num));
++}
++
++/**
++ * xgpiops_irq_unmask - Enable the interrupts for a gpio pin
++ * @irq_data: irq data containing irq number of gpio pin for the irq to enable
++ *
++ * This function calculates the gpio pin number from irq number and sets the
++ * bit in the Interrupt Enable register of the corresponding bank to enable
++ * interrupts for that pin.
++ */
++static void xgpiops_irq_unmask(struct irq_data *irq_data)
++{
++ struct xgpiops *gpio = irq_data_get_irq_chip_data(irq_data);
++ unsigned int device_pin_num, bank_num, bank_pin_num;
++
++ device_pin_num = irq_data->hwirq;
++ xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
++ xgpiops_writereg(1 << bank_pin_num,
++ gpio->base_addr + XGPIOPS_INTEN_OFFSET(bank_num));
++}
++
++/**
++ * xgpiops_set_irq_type - Set the irq type for a gpio pin
++ * @irq_data: irq data containing irq number of gpio pin
++ * @type: interrupt type that is to be set for the gpio pin
++ *
++ * This function gets the gpio pin number and its bank from the gpio pin number
++ * and configures the INT_TYPE, INT_POLARITY and INT_ANY registers. Returns 0,
++ * negative error otherwise.
++ * TYPE-EDGE_RISING, INT_TYPE - 1, INT_POLARITY - 1, INT_ANY - 0;
++ * TYPE-EDGE_FALLING, INT_TYPE - 1, INT_POLARITY - 0, INT_ANY - 0;
++ * TYPE-EDGE_BOTH, INT_TYPE - 1, INT_POLARITY - NA, INT_ANY - 1;
++ * TYPE-LEVEL_HIGH, INT_TYPE - 0, INT_POLARITY - 1, INT_ANY - NA;
++ * TYPE-LEVEL_LOW, INT_TYPE - 0, INT_POLARITY - 0, INT_ANY - NA
++ */
++static int xgpiops_set_irq_type(struct irq_data *irq_data, unsigned int type)
++{
++ struct xgpiops *gpio = irq_data_get_irq_chip_data(irq_data);
++ unsigned int device_pin_num, bank_num, bank_pin_num;
++ unsigned int int_type, int_pol, int_any;
++
++ device_pin_num = irq_data->hwirq;
++ xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
++
++ int_type = xgpiops_readreg(gpio->base_addr +
++ XGPIOPS_INTTYPE_OFFSET(bank_num));
++ int_pol = xgpiops_readreg(gpio->base_addr +
++ XGPIOPS_INTPOL_OFFSET(bank_num));
++ int_any = xgpiops_readreg(gpio->base_addr +
++ XGPIOPS_INTANY_OFFSET(bank_num));
++
++ /*
++ * based on the type requested, configure the INT_TYPE, INT_POLARITY
++ * and INT_ANY registers
++ */
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ int_type |= (1 << bank_pin_num);
++ int_pol |= (1 << bank_pin_num);
++ int_any &= ~(1 << bank_pin_num);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ int_type |= (1 << bank_pin_num);
++ int_pol &= ~(1 << bank_pin_num);
++ int_any &= ~(1 << bank_pin_num);
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ int_type |= (1 << bank_pin_num);
++ int_any |= (1 << bank_pin_num);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ int_type &= ~(1 << bank_pin_num);
++ int_pol |= (1 << bank_pin_num);
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ int_type &= ~(1 << bank_pin_num);
++ int_pol &= ~(1 << bank_pin_num);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ xgpiops_writereg(int_type,
++ gpio->base_addr + XGPIOPS_INTTYPE_OFFSET(bank_num));
++ xgpiops_writereg(int_pol,
++ gpio->base_addr + XGPIOPS_INTPOL_OFFSET(bank_num));
++ xgpiops_writereg(int_any,
++ gpio->base_addr + XGPIOPS_INTANY_OFFSET(bank_num));
++ return 0;
++}
++
++static int xgpiops_set_wake(struct irq_data *data, unsigned int on)
++{
++ if (on)
++ xgpiops_irq_unmask(data);
++ else
++ xgpiops_irq_mask(data);
++
++ return 0;
++}
++
++/* irq chip descriptor */
++static struct irq_chip xgpiops_irqchip = {
++ .name = DRIVER_NAME,
++ .irq_ack = xgpiops_irq_ack,
++ .irq_mask = xgpiops_irq_mask,
++ .irq_unmask = xgpiops_irq_unmask,
++ .irq_set_type = xgpiops_set_irq_type,
++ .irq_set_wake = xgpiops_set_wake,
++};
++
++/**
++ * xgpiops_irqhandler - IRQ handler for the gpio banks of a gpio device
++ * @irq: irq number of the gpio bank where interrupt has occurred
++ * @desc: irq descriptor instance of the 'irq'
++ *
++ * This function reads the Interrupt Status Register of each bank to get the
++ * gpio pin number which has triggered an interrupt. It then acks the triggered
++ * interrupt and calls the pin specific handler set by the higher layer
++ * application for that pin.
++ * Note: A bug is reported if no handler is set for the gpio pin.
++ */
++static void xgpiops_irqhandler(unsigned int irq, struct irq_desc *desc)
++{
++ struct xgpiops *gpio = (struct xgpiops *)irq_get_handler_data(irq);
++ int gpio_irq = gpio->irq_base;
++ unsigned int int_sts, int_enb, bank_num;
++ struct irq_desc *gpio_irq_desc;
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++
++ chained_irq_enter(chip, desc);
++
++ for (bank_num = 0; bank_num < 4; bank_num++) {
++ int_sts = xgpiops_readreg(gpio->base_addr +
++ XGPIOPS_INTSTS_OFFSET(bank_num));
++ int_enb = xgpiops_readreg(gpio->base_addr +
++ XGPIOPS_INTMASK_OFFSET(bank_num));
++ int_sts &= ~int_enb;
++
++ for (; int_sts != 0; int_sts >>= 1, gpio_irq++) {
++ if ((int_sts & 1) == 0)
++ continue;
++ gpio_irq_desc = irq_to_desc(gpio_irq);
++ BUG_ON(!gpio_irq_desc);
++ chip = irq_desc_get_chip(gpio_irq_desc);
++ BUG_ON(!chip);
++ chip->irq_ack(&gpio_irq_desc->irq_data);
++
++ /* call the pin specific handler */
++ generic_handle_irq(gpio_irq);
++ }
++ /* shift to first virtual irq of next bank */
++ gpio_irq = gpio->irq_base + xgpiops_pin_table[bank_num] + 1;
++ }
++
++ chip = irq_desc_get_chip(desc);
++ chained_irq_exit(chip, desc);
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int xgpiops_suspend(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct xgpiops *gpio = platform_get_drvdata(pdev);
++
++ if (!device_may_wakeup(dev)) {
++ if (!pm_runtime_suspended(dev))
++ clk_disable(gpio->clk);
++ return 0;
++ }
++
++ return 0;
++}
++
++static int xgpiops_resume(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct xgpiops *gpio = platform_get_drvdata(pdev);
++
++ if (!device_may_wakeup(dev)) {
++ if (!pm_runtime_suspended(dev))
++ return clk_enable(gpio->clk);
++ }
++
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_PM_RUNTIME
++static int xgpiops_runtime_suspend(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct xgpiops *gpio = platform_get_drvdata(pdev);
++
++ clk_disable(gpio->clk);
++
++ return 0;
++}
++
++static int xgpiops_runtime_resume(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct xgpiops *gpio = platform_get_drvdata(pdev);
++
++ return clk_enable(gpio->clk);
++}
++
++static int xgpiops_idle(struct device *dev)
++{
++ return pm_schedule_suspend(dev, 1);
++}
++
++static int xgpiops_request(struct gpio_chip *chip, unsigned offset)
++{
++ int ret;
++
++ ret = pm_runtime_get_sync(chip->dev);
++
++ /*
++ * If the device is already active pm_runtime_get() will return 1 on
++ * success, but gpio_request still needs to return 0.
++ */
++ return ret < 0 ? ret : 0;
++}
++
++static void xgpiops_free(struct gpio_chip *chip, unsigned offset)
++{
++ pm_runtime_put_sync(chip->dev);
++}
++
++static void xgpiops_pm_runtime_init(struct platform_device *pdev)
++{
++ struct xgpiops *gpio = platform_get_drvdata(pdev);
++
++ clk_disable(gpio->clk);
++ pm_runtime_enable(&pdev->dev);
++}
++
++#else /* ! CONFIG_PM_RUNTIME */
++#define xgpiops_request NULL
++#define xgpiops_free NULL
++static void xgpiops_pm_runtime_init(struct platform_device *pdev) {}
++#endif /* ! CONFIG_PM_RUNTIME */
++
++#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
++static const struct dev_pm_ops xgpiops_dev_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(xgpiops_suspend, xgpiops_resume)
++ SET_RUNTIME_PM_OPS(xgpiops_runtime_suspend, xgpiops_runtime_resume,
++ xgpiops_idle)
++};
++#define XGPIOPS_PM (&xgpiops_dev_pm_ops)
++
++#else /*! CONFIG_PM_RUNTIME || ! CONFIG_PM_SLEEP */
++#define XGPIOPS_PM NULL
++#endif /*! CONFIG_PM_RUNTIME */
++
++/**
++ * xgpiops_probe - Initialization method for a xgpiops device
++ * @pdev: platform device instance
++ *
++ * This function allocates memory resources for the gpio device and registers
++ * all the banks of the device. It will also set up interrupts for the gpio
++ * pins.
++ * Note: Interrupts are disabled for all the banks during initialization.
++ * Returns 0 on success, negative error otherwise.
++ */
++static int xgpiops_probe(struct platform_device *pdev)
++{
++ int ret;
++ unsigned int irq_num;
++ struct xgpiops *gpio;
++ struct gpio_chip *chip;
++ resource_size_t remap_size;
++ struct resource *mem_res = NULL;
++ int pin_num, bank_num, gpio_irq;
++
++ gpio = kzalloc(sizeof(struct xgpiops), GFP_KERNEL);
++ if (!gpio) {
++ dev_err(&pdev->dev,
++ "couldn't allocate memory for gpio private data\n");
++ return -ENOMEM;
++ }
++
++ spin_lock_init(&gpio->gpio_lock);
++
++ platform_set_drvdata(pdev, gpio);
++
++ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem_res) {
++ dev_err(&pdev->dev, "No memory resource\n");
++ ret = -ENODEV;
++ goto err_free_gpio;
++ }
++
++ remap_size = mem_res->end - mem_res->start + 1;
++ if (!request_mem_region(mem_res->start, remap_size, pdev->name)) {
++ dev_err(&pdev->dev, "Cannot request IO\n");
++ ret = -ENXIO;
++ goto err_free_gpio;
++ }
++
++ gpio->base_addr = ioremap(mem_res->start, remap_size);
++ if (gpio->base_addr == NULL) {
++ dev_err(&pdev->dev, "Couldn't ioremap memory at 0x%08lx\n",
++ (unsigned long)mem_res->start);
++ ret = -ENOMEM;
++ goto err_release_region;
++ }
++
++ irq_num = platform_get_irq(pdev, 0);
++ gpio->irq = irq_num;
++
++ /* configure the gpio chip */
++ chip = &gpio->chip;
++ chip->label = "xgpiops";
++ chip->owner = THIS_MODULE;
++ chip->dev = &pdev->dev;
++ chip->get = xgpiops_get_value;
++ chip->set = xgpiops_set_value;
++ chip->request = xgpiops_request;
++ chip->free = xgpiops_free;
++ chip->direction_input = xgpiops_dir_in;
++ chip->direction_output = xgpiops_dir_out;
++ chip->to_irq = xgpiops_to_irq;
++ chip->dbg_show = NULL;
++ chip->base = 0; /* default pin base */
++ chip->ngpio = XGPIOPS_NR_GPIOS;
++ chip->can_sleep = 0;
++
++ gpio->irq_base = irq_alloc_descs(-1, 0, chip->ngpio, 0);
++ if (gpio->irq_base < 0) {
++ dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n");
++ ret = -ENODEV;
++ goto err_iounmap;
++ }
++
++ irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
++ chip->ngpio, gpio->irq_base, 0,
++ &irq_domain_simple_ops, NULL);
++
++ /* report a bug if gpio chip registration fails */
++ ret = gpiochip_add(chip);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "gpio chip registration failed\n");
++ goto err_iounmap;
++ } else {
++ dev_info(&pdev->dev, "gpio at 0x%08lx mapped to 0x%08lx\n",
++ (unsigned long)mem_res->start,
++ (unsigned long)gpio->base_addr);
++ }
++
++ /* Enable GPIO clock */
++ gpio->clk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(gpio->clk)) {
++ dev_err(&pdev->dev, "input clock not found.\n");
++ ret = PTR_ERR(gpio->clk);
++ goto err_chip_remove;
++ }
++ ret = clk_prepare_enable(gpio->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable clock.\n");
++ goto err_clk_put;
++ }
++
++ /* disable interrupts for all banks */
++ for (bank_num = 0; bank_num < 4; bank_num++) {
++ xgpiops_writereg(0xffffffff, gpio->base_addr +
++ XGPIOPS_INTDIS_OFFSET(bank_num));
++ }
++
++ /*
++ * set the irq chip, handler and irq chip data for callbacks for
++ * each pin
++ */
++ for (pin_num = 0; pin_num < min_t(int, XGPIOPS_NR_GPIOS,
++ (int)chip->ngpio); pin_num++) {
++ gpio_irq = irq_find_mapping(irq_domain, pin_num);
++ irq_set_chip_and_handler(gpio_irq, &xgpiops_irqchip,
++ handle_simple_irq);
++ irq_set_chip_data(gpio_irq, (void *)gpio);
++ set_irq_flags(gpio_irq, IRQF_VALID);
++ }
++
++ irq_set_handler_data(irq_num, (void *)gpio);
++ irq_set_chained_handler(irq_num, xgpiops_irqhandler);
++
++ xgpiops_pm_runtime_init(pdev);
++
++ device_set_wakeup_capable(&pdev->dev, 1);
++
++ return 0;
++
++err_clk_put:
++ clk_put(gpio->clk);
++err_chip_remove:
++ gpiochip_remove(chip);
++err_iounmap:
++ iounmap(gpio->base_addr);
++err_release_region:
++ release_mem_region(mem_res->start, remap_size);
++err_free_gpio:
++ platform_set_drvdata(pdev, NULL);
++ kfree(gpio);
++
++ return ret;
++}
++
++static int xgpiops_remove(struct platform_device *pdev)
++{
++ struct xgpiops *gpio = platform_get_drvdata(pdev);
++
++ clk_disable_unprepare(gpio->clk);
++ clk_put(gpio->clk);
++ device_set_wakeup_capable(&pdev->dev, 0);
++ return 0;
++}
++
++static struct of_device_id xgpiops_of_match[] = {
++ { .compatible = "xlnx,ps7-gpio-1.00.a", },
++ { /* end of table */}
++};
++MODULE_DEVICE_TABLE(of, xgpiops_of_match);
++
++static struct platform_driver xgpiops_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = XGPIOPS_PM,
++ .of_match_table = xgpiops_of_match,
++ },
++ .probe = xgpiops_probe,
++ .remove = xgpiops_remove,
++};
++
++/**
++ * xgpiops_init - Initial driver registration call
++ */
++static int __init xgpiops_init(void)
++{
++ return platform_driver_register(&xgpiops_driver);
++}
++
++postcore_initcall(xgpiops_init);
diff --git a/patches.zynq/0006-spi-xilinx-merge-qspi-support-from-xilinx-repository.patch b/patches.zynq/0006-spi-xilinx-merge-qspi-support-from-xilinx-repository.patch
new file mode 100644
index 00000000000000..bb8e527d1baa26
--- /dev/null
+++ b/patches.zynq/0006-spi-xilinx-merge-qspi-support-from-xilinx-repository.patch
@@ -0,0 +1,2303 @@
+From 99e292bf8f472ce9475a68b37eb89ef201ff8acb Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Tue, 24 Dec 2013 09:10:07 +0900
+Subject: spi: xilinx: merge qspi support from xilinx repository
+
+This merges support for Xilinx QSPI from the Xilinx repository
+(based on commit efc27505715e64526653f35274717c0fc56491e3 in master
+branch). This has been tested to read the QSPI flash in the
+Zynq 702 board.
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/spi/Kconfig | 24
+ drivers/spi/Makefile | 2
+ drivers/spi/spi-xilinx-ps.c | 927 ++++++++++++++++++++++++++++++++
+ drivers/spi/spi-xilinx-qps.c | 1220 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/spi/spi-xilinx.c | 27
+ include/linux/spi/spi.h | 2
+ 6 files changed, 2196 insertions(+), 6 deletions(-)
+ create mode 100644 drivers/spi/spi-xilinx-ps.c
+ create mode 100644 drivers/spi/spi-xilinx-qps.c
+
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -474,12 +474,32 @@ config SPI_XILINX
+ select SPI_BITBANG
+ help
+ This exposes the SPI controller IP from the Xilinx EDK.
+-
+ See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
+ Product Specification document (DS464) for hardware details.
+-
+ Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
+
++config SPI_XILINX_PS_QSPI
++ tristate "Xilinx PS QSPI controller"
++ depends on ARCH_ZYNQ
++ depends on SPI_MASTER
++ help
++ This selects the PS Quad SPI controller master driver from the Xilinx.
++
++config SPI_XILINX_PS_QSPI_DUAL_STACKED
++ bool "Xilinx PS QSPI Dual stacked configuration"
++ depends on SPI_XILINX_PS_QSPI
++ help
++ This selects the PS Quad SPI controller in dual stacked mode.
++ Enable this option if your hw design is using dual stacked
++ configuration.
++
++config SPI_XILINX_PS_SPI
++ tristate "Xilinx PS SPI controller"
++ depends on ARCH_ZYNQ
++ depends on SPI_MASTER
++ help
++ This selects the PS SPI controller master driver from the Xilinx.
++
+ config SPI_NUC900
+ tristate "Nuvoton NUC900 series SPI"
+ depends on ARCH_W90X900
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -74,3 +74,5 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-t
+ obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
+ obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
+ obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
++obj-$(CONFIG_SPI_XILINX_PS_SPI) += spi-xilinx-ps.o
++obj-$(CONFIG_SPI_XILINX_PS_QSPI) += spi-xilinx-qps.o
+--- /dev/null
++++ b/drivers/spi/spi-xilinx-ps.c
+@@ -0,0 +1,927 @@
++/*
++ *
++ * Xilinx PS SPI controller driver (master mode only)
++ *
++ * (c) 2008-2011 Xilinx, Inc.
++ *
++ * based on Blackfin On-Chip SPI Driver (spi_bfin5xx.c)
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++
++/*
++ * Name of this driver
++ */
++#define XSPIPS_NAME "xspips"
++
++/*
++ * Register offset definitions
++ */
++#define XSPIPS_CR_OFFSET 0x00 /* Configuration Register, RW */
++#define XSPIPS_ISR_OFFSET 0x04 /* Interrupt Status Register, RO */
++#define XSPIPS_IER_OFFSET 0x08 /* Interrupt Enable Register, WO */
++#define XSPIPS_IDR_OFFSET 0x0c /* Interrupt Disable Register, WO */
++#define XSPIPS_IMR_OFFSET 0x10 /* Interrupt Enabled Mask Register, RO */
++#define XSPIPS_ER_OFFSET 0x14 /* Enable/Disable Register, RW */
++#define XSPIPS_DR_OFFSET 0x18 /* Delay Register, RW */
++#define XSPIPS_TXD_OFFSET 0x1C /* Data Transmit Register, WO */
++#define XSPIPS_RXD_OFFSET 0x20 /* Data Receive Register, RO */
++#define XSPIPS_SICR_OFFSET 0x24 /* Slave Idle Count Register, RW */
++#define XSPIPS_THLD_OFFSET 0x28 /* Transmit FIFO Watermark Register,RW */
++
++/*
++ * SPI Configuration Register bit Masks
++ *
++ * This register contains various control bits that affect the operation
++ * of the SPI controller
++ */
++#define XSPIPS_CR_MANSTRT_MASK 0x00010000 /* Manual TX Start */
++#define XSPIPS_CR_CPHA_MASK 0x00000004 /* Clock Phase Control */
++#define XSPIPS_CR_CPOL_MASK 0x00000002 /* Clock Polarity Control */
++#define XSPIPS_CR_SSCTRL_MASK 0x00003C00 /* Slave Select Mask */
++
++/*
++ * SPI Interrupt Registers bit Masks
++ *
++ * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
++ * bit definitions.
++ */
++#define XSPIPS_IXR_TXOW_MASK 0x00000004 /* SPI TX FIFO Overwater */
++#define XSPIPS_IXR_MODF_MASK 0x00000002 /* SPI Mode Fault */
++#define XSPIPS_IXR_RXNEMTY_MASK 0x00000010 /* SPI RX FIFO Not Empty */
++#define XSPIPS_IXR_ALL_MASK (XSPIPS_IXR_TXOW_MASK | XSPIPS_IXR_MODF_MASK)
++
++/*
++ * SPI Enable Register bit Masks
++ *
++ * This register is used to enable or disable the SPI controller
++ */
++#define XSPIPS_ER_ENABLE_MASK 0x00000001 /* SPI Enable Bit Mask */
++
++/*
++ * Definitions for the status of queue
++ */
++#define XSPIPS_QUEUE_STOPPED 0
++#define XSPIPS_QUEUE_RUNNING 1
++
++/*
++ * Macros for the SPI controller read/write
++ */
++#define xspips_read(addr) __raw_readl(addr)
++#define xspips_write(addr, val) __raw_writel((val), (addr))
++
++
++/**
++ * struct xspips - This definition defines spi driver instance
++ * @workqueue: Queue of all the transfers
++ * @work: Information about current transfer
++ * @queue: Head of the queue
++ * @queue_state: Queue status
++ * @regs: Virtual address of the SPI controller registers
++ * @devclk: Pointer to the peripheral clock
++ * @aperclk: Pointer to the APER clock
++ * @clk_rate_change_nb: Notifier block for clock frequency change callback
++ * @irq: IRQ number
++ * @speed_hz: Current SPI bus clock speed in Hz
++ * @trans_queue_lock: Lock used for accessing transfer queue
++ * @ctrl_reg_lock: Lock used for accessing configuration register
++ * @txbuf: Pointer to the TX buffer
++ * @rxbuf: Pointer to the RX buffer
++ * @remaining_bytes: Number of bytes left to transfer
++ * @dev_busy: Device busy flag
++ * @done: Transfer complete status
++ */
++struct xspips {
++ struct workqueue_struct *workqueue;
++ struct work_struct work;
++ struct list_head queue;
++ int queue_state;
++ void __iomem *regs;
++ struct clk *devclk;
++ struct clk *aperclk;
++ struct notifier_block clk_rate_change_nb;
++ int irq;
++ u32 speed_hz;
++ spinlock_t trans_queue_lock;
++ spinlock_t ctrl_reg_lock;
++ const u8 *txbuf;
++ u8 *rxbuf;
++ int remaining_bytes;
++ u8 dev_busy;
++ struct completion done;
++};
++
++
++/**
++ * xspips_init_hw - Initialize the hardware and configure the SPI controller
++ * @regs_base: Base address of SPI controller
++ *
++ * On reset the SPI controller is configured to be in master mode, baud rate
++ * divisor is set to 2, threshold value for TX FIFO not full interrupt is set
++ * to 1 and size of the word to be transferred as 8 bit.
++ * This function initializes the SPI controller to disable and clear all the
++ * interrupts, enable manual slave select and manual start, deselect all the
++ * chip select lines, and enable the SPI controller.
++ */
++static void xspips_init_hw(void __iomem *regs_base)
++{
++ xspips_write(regs_base + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK);
++ xspips_write(regs_base + XSPIPS_IDR_OFFSET, 0x7F);
++
++ /* Clear the RX FIFO */
++ while (xspips_read(regs_base + XSPIPS_ISR_OFFSET) &
++ XSPIPS_IXR_RXNEMTY_MASK)
++ xspips_read(regs_base + XSPIPS_RXD_OFFSET);
++
++ xspips_write(regs_base + XSPIPS_ISR_OFFSET, 0x7F);
++ xspips_write(regs_base + XSPIPS_CR_OFFSET, 0x0000FC01);
++ xspips_write(regs_base + XSPIPS_ER_OFFSET, XSPIPS_ER_ENABLE_MASK);
++}
++
++/**
++ * xspips_chipselect - Select or deselect the chip select line
++ * @spi: Pointer to the spi_device structure
++ * @is_on: Select(1) or deselect (0) the chip select line
++ */
++static void xspips_chipselect(struct spi_device *spi, int is_on)
++{
++ struct xspips *xspi = spi_master_get_devdata(spi->master);
++ u32 ctrl_reg;
++ unsigned long flags;
++
++ spin_lock_irqsave(&xspi->ctrl_reg_lock, flags);
++
++ ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET);
++
++ if (is_on) {
++ /* Select the slave */
++ ctrl_reg &= ~XSPIPS_CR_SSCTRL_MASK;
++ ctrl_reg |= (((~(0x0001 << spi->chip_select)) << 10) &
++ XSPIPS_CR_SSCTRL_MASK);
++ } else {
++ /* Deselect the slave */
++ ctrl_reg |= XSPIPS_CR_SSCTRL_MASK;
++ }
++
++ xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg);
++
++ spin_unlock_irqrestore(&xspi->ctrl_reg_lock, flags);
++}
++
++/**
++ * xspips_setup_transfer - Configure SPI controller for specified transfer
++ * @spi: Pointer to the spi_device structure
++ * @transfer: Pointer to the spi_transfer structure which provides information
++ * about next transfer setup parameters
++ *
++ * Sets the operational mode of SPI controller for the next SPI transfer and
++ * sets the requested clock frequency.
++ *
++ * returns: 0 on success and error value on error
++ *
++ * Note: If the requested frequency is not an exact match with what can be
++ * obtained using the prescalar value the driver sets the clock frequency which
++ * is lower than the requested frequency (maximum lower) for the transfer. If
++ * the requested frequency is higher or lower than that is supported by the SPI
++ * controller the driver will set the highest or lowest frequency supported by
++ * controller.
++ */
++static int xspips_setup_transfer(struct spi_device *spi,
++ struct spi_transfer *transfer)
++{
++ struct xspips *xspi = spi_master_get_devdata(spi->master);
++ u8 bits_per_word;
++ u32 ctrl_reg;
++ u32 req_hz;
++ u32 baud_rate_val;
++ unsigned long flags, frequency;
++
++ bits_per_word = (transfer) ?
++ transfer->bits_per_word : spi->bits_per_word;
++ req_hz = (transfer) ? transfer->speed_hz : spi->max_speed_hz;
++
++ if (bits_per_word != 8) {
++ dev_err(&spi->dev, "%s, unsupported bits per word %x\n",
++ __func__, spi->bits_per_word);
++ return -EINVAL;
++ }
++
++ frequency = clk_get_rate(xspi->devclk);
++
++ spin_lock_irqsave(&xspi->ctrl_reg_lock, flags);
++
++ xspips_write(xspi->regs + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK);
++ ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET);
++
++ /* Set the SPI clock phase and clock polarity */
++ ctrl_reg &= (~XSPIPS_CR_CPHA_MASK) & (~XSPIPS_CR_CPOL_MASK);
++ if (spi->mode & SPI_CPHA)
++ ctrl_reg |= XSPIPS_CR_CPHA_MASK;
++ if (spi->mode & SPI_CPOL)
++ ctrl_reg |= XSPIPS_CR_CPOL_MASK;
++
++ /* Set the clock frequency */
++ if (xspi->speed_hz != req_hz) {
++ baud_rate_val = 0;
++ while ((baud_rate_val < 8) && (frequency /
++ (2 << baud_rate_val)) > req_hz)
++ baud_rate_val++;
++
++ ctrl_reg &= 0xFFFFFFC7;
++ ctrl_reg |= (baud_rate_val << 3);
++
++ xspi->speed_hz = (frequency / (2 << baud_rate_val));
++ }
++
++ xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg);
++ xspips_write(xspi->regs + XSPIPS_ER_OFFSET, XSPIPS_ER_ENABLE_MASK);
++
++ spin_unlock_irqrestore(&xspi->ctrl_reg_lock, flags);
++
++ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u clock speed\n",
++ __func__, spi->mode, spi->bits_per_word,
++ xspi->speed_hz);
++
++ return 0;
++}
++
++/**
++ * xspips_setup - Configure the SPI controller
++ * @spi: Pointer to the spi_device structure
++ *
++ * Sets the operational mode of SPI controller for the next SPI transfer, sets
++ * the baud rate and divisor value to setup the requested spi clock.
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xspips_setup(struct spi_device *spi)
++{
++ if (!spi->max_speed_hz)
++ return -EINVAL;
++
++ if (!spi->bits_per_word)
++ spi->bits_per_word = 8;
++
++ return xspips_setup_transfer(spi, NULL);
++}
++
++/**
++ * xspips_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
++ * @xspi: Pointer to the xspips structure
++ */
++static void xspips_fill_tx_fifo(struct xspips *xspi)
++{
++ while ((xspips_read(xspi->regs + XSPIPS_ISR_OFFSET) & 0x00000008) == 0
++ && (xspi->remaining_bytes > 0)) {
++ if (xspi->txbuf)
++ xspips_write(xspi->regs + XSPIPS_TXD_OFFSET,
++ *xspi->txbuf++);
++ else
++ xspips_write(xspi->regs + XSPIPS_TXD_OFFSET, 0);
++
++ xspi->remaining_bytes--;
++ }
++}
++
++/**
++ * xspips_irq - Interrupt service routine of the SPI controller
++ * @irq: IRQ number
++ * @dev_id: Pointer to the xspi structure
++ *
++ * This function handles TX empty and Mode Fault interrupts only.
++ * On TX empty interrupt this function reads the received data from RX FIFO and
++ * fills the TX FIFO if there is any data remaining to be transferred.
++ * On Mode Fault interrupt this function indicates that transfer is completed,
++ * the SPI subsystem will identify the error as the remaining bytes to be
++ * transferred is non-zero.
++ *
++ * returns: IRQ_HANDLED always
++ */
++static irqreturn_t xspips_irq(int irq, void *dev_id)
++{
++ struct xspips *xspi = dev_id;
++ u32 intr_status;
++
++ intr_status = xspips_read(xspi->regs + XSPIPS_ISR_OFFSET);
++ xspips_write(xspi->regs + XSPIPS_ISR_OFFSET, intr_status);
++ xspips_write(xspi->regs + XSPIPS_IDR_OFFSET, XSPIPS_IXR_ALL_MASK);
++
++ if (intr_status & XSPIPS_IXR_MODF_MASK) {
++ /* Indicate that transfer is completed, the SPI subsystem will
++ * identify the error as the remaining bytes to be
++ * transferred is non-zero */
++ complete(&xspi->done);
++ } else if (intr_status & XSPIPS_IXR_TXOW_MASK) {
++ u32 ctrl_reg;
++
++ /* Read out the data from the RX FIFO */
++ while (xspips_read(xspi->regs + XSPIPS_ISR_OFFSET) &
++ XSPIPS_IXR_RXNEMTY_MASK) {
++ u8 data;
++
++ data = xspips_read(xspi->regs + XSPIPS_RXD_OFFSET);
++ if (xspi->rxbuf)
++ *xspi->rxbuf++ = data;
++
++ /* Data memory barrier is placed here to ensure that
++ * data read operation is completed before the status
++ * read is initiated. Without dmb, there are chances
++ * that data and status reads will appear at the SPI
++ * peripheral back-to-back which results in an
++ * incorrect status read.
++ */
++ dmb();
++ }
++
++ if (xspi->remaining_bytes) {
++ /* There is more data to send */
++ xspips_fill_tx_fifo(xspi);
++
++ xspips_write(xspi->regs + XSPIPS_IER_OFFSET,
++ XSPIPS_IXR_ALL_MASK);
++
++ spin_lock(&xspi->ctrl_reg_lock);
++
++ ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET);
++ ctrl_reg |= XSPIPS_CR_MANSTRT_MASK;
++ xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg);
++
++ spin_unlock(&xspi->ctrl_reg_lock);
++ } else {
++ /* Transfer is completed */
++ complete(&xspi->done);
++ }
++ }
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * xspips_start_transfer - Initiates the SPI transfer
++ * @spi: Pointer to the spi_device structure
++ * @transfer: Pointer to the spi_transfer structure which provide information
++ * about next transfer parameters
++ *
++ * This function fills the TX FIFO, starts the SPI transfer, and waits for the
++ * transfer to be completed.
++ *
++ * returns: Number of bytes transferred in the last transfer
++ */
++static int xspips_start_transfer(struct spi_device *spi,
++ struct spi_transfer *transfer)
++{
++ struct xspips *xspi = spi_master_get_devdata(spi->master);
++ u32 ctrl_reg;
++ unsigned long flags;
++
++ xspi->txbuf = transfer->tx_buf;
++ xspi->rxbuf = transfer->rx_buf;
++ xspi->remaining_bytes = transfer->len;
++ INIT_COMPLETION(xspi->done);
++
++ xspips_fill_tx_fifo(xspi);
++
++ xspips_write(xspi->regs + XSPIPS_IER_OFFSET, XSPIPS_IXR_ALL_MASK);
++
++ spin_lock_irqsave(&xspi->ctrl_reg_lock, flags);
++
++ /* Start the transfer by enabling manual start bit */
++ ctrl_reg = xspips_read(xspi->regs + XSPIPS_CR_OFFSET);
++ ctrl_reg |= XSPIPS_CR_MANSTRT_MASK;
++ xspips_write(xspi->regs + XSPIPS_CR_OFFSET, ctrl_reg);
++
++ spin_unlock_irqrestore(&xspi->ctrl_reg_lock, flags);
++
++ wait_for_completion(&xspi->done);
++
++ return (transfer->len) - (xspi->remaining_bytes);
++}
++
++/**
++ * xspips_work_queue - Get the transfer request from queue to perform transfers
++ * @work: Pointer to the work_struct structure
++ */
++static void xspips_work_queue(struct work_struct *work)
++{
++ struct xspips *xspi = container_of(work, struct xspips, work);
++ unsigned long flags;
++
++ spin_lock_irqsave(&xspi->trans_queue_lock, flags);
++ xspi->dev_busy = 1;
++
++ if (list_empty(&xspi->queue) ||
++ xspi->queue_state == XSPIPS_QUEUE_STOPPED) {
++ xspi->dev_busy = 0;
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++ return;
++ }
++
++ while (!list_empty(&xspi->queue)) {
++ struct spi_message *msg;
++ struct spi_device *spi;
++ struct spi_transfer *transfer = NULL;
++ unsigned cs_change = 1;
++ int status = 0;
++
++ msg = container_of(xspi->queue.next, struct spi_message, queue);
++ list_del_init(&msg->queue);
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++ spi = msg->spi;
++
++ list_for_each_entry(transfer, &msg->transfers, transfer_list) {
++ if ((transfer->bits_per_word || transfer->speed_hz) &&
++ cs_change) {
++ status = xspips_setup_transfer(spi, transfer);
++ if (status < 0)
++ break;
++ }
++
++ if (cs_change)
++ xspips_chipselect(spi, 1);
++
++ cs_change = transfer->cs_change;
++
++ if (!transfer->tx_buf && !transfer->rx_buf &&
++ transfer->len) {
++ status = -EINVAL;
++ break;
++ }
++
++ if (transfer->len)
++ status = xspips_start_transfer(spi, transfer);
++
++ if (status != transfer->len) {
++ if (status > 0)
++ status = -EMSGSIZE;
++ break;
++ }
++ msg->actual_length += status;
++ status = 0;
++
++ if (transfer->delay_usecs)
++ udelay(transfer->delay_usecs);
++
++ if (!cs_change)
++ continue;
++ if (transfer->transfer_list.next == &msg->transfers)
++ break;
++
++ xspips_chipselect(spi, 0);
++ }
++
++ msg->status = status;
++ msg->complete(msg->context);
++
++ if (!(status == 0 && cs_change))
++ xspips_chipselect(spi, 0);
++
++ spin_lock_irqsave(&xspi->trans_queue_lock, flags);
++ }
++ xspi->dev_busy = 0;
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++}
++
++/**
++ * xspips_transfer - Add a new transfer request at the tail of work queue
++ * @spi: Pointer to the spi_device structure
++ * @message: Pointer to the spi_transfer structure which provide information
++ * about next transfer parameters
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xspips_transfer(struct spi_device *spi, struct spi_message *message)
++{
++ struct xspips *xspi = spi_master_get_devdata(spi->master);
++ struct spi_transfer *transfer;
++ unsigned long flags;
++
++ if (xspi->queue_state == XSPIPS_QUEUE_STOPPED)
++ return -ESHUTDOWN;
++
++ message->actual_length = 0;
++ message->status = -EINPROGRESS;
++
++ /* Check each transfer's parameters */
++ list_for_each_entry(transfer, &message->transfers, transfer_list) {
++ u8 bits_per_word =
++ transfer->bits_per_word ? : spi->bits_per_word;
++
++ bits_per_word = bits_per_word ? : 8;
++ if (!transfer->tx_buf && !transfer->rx_buf && transfer->len)
++ return -EINVAL;
++ if (bits_per_word != 8)
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&xspi->trans_queue_lock, flags);
++ list_add_tail(&message->queue, &xspi->queue);
++ if (!xspi->dev_busy)
++ queue_work(xspi->workqueue, &xspi->work);
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++
++ return 0;
++}
++
++/**
++ * xspips_start_queue - Starts the queue of the SPI driver
++ * @xspi: Pointer to the xspips structure
++ *
++ * returns: 0 on success and error value on error
++ */
++static inline int xspips_start_queue(struct xspips *xspi)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&xspi->trans_queue_lock, flags);
++
++ if (xspi->queue_state == XSPIPS_QUEUE_RUNNING || xspi->dev_busy) {
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++ return -EBUSY;
++ }
++
++ xspi->queue_state = XSPIPS_QUEUE_RUNNING;
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++
++ return 0;
++}
++
++/**
++ * xspips_stop_queue - Stops the queue of the SPI driver
++ * @xspi: Pointer to the xspips structure
++ *
++ * This function waits till queue is empty and then stops the queue.
++ * Maximum time out is set to 5 seconds.
++ *
++ * returns: 0 on success and error value on error
++ */
++static inline int xspips_stop_queue(struct xspips *xspi)
++{
++ unsigned long flags;
++ unsigned limit = 500;
++ int ret = 0;
++
++ if (xspi->queue_state != XSPIPS_QUEUE_RUNNING)
++ return ret;
++
++ spin_lock_irqsave(&xspi->trans_queue_lock, flags);
++
++ while ((!list_empty(&xspi->queue) || xspi->dev_busy) && limit--) {
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++ msleep(10);
++ spin_lock_irqsave(&xspi->trans_queue_lock, flags);
++ }
++
++ if (!list_empty(&xspi->queue) || xspi->dev_busy)
++ ret = -EBUSY;
++
++ if (ret == 0)
++ xspi->queue_state = XSPIPS_QUEUE_STOPPED;
++
++ spin_unlock_irqrestore(&xspi->trans_queue_lock, flags);
++
++ return ret;
++}
++
++/**
++ * xspips_destroy_queue - Destroys the queue of the SPI driver
++ * @xspi: Pointer to the xspips structure
++ *
++ * returns: 0 on success and error value on error
++ */
++static inline int xspips_destroy_queue(struct xspips *xspi)
++{
++ int ret;
++
++ ret = xspips_stop_queue(xspi);
++ if (ret != 0)
++ return ret;
++
++ destroy_workqueue(xspi->workqueue);
++
++ return 0;
++}
++
++static int xspips_clk_notifier_cb(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++ switch (event) {
++ case PRE_RATE_CHANGE:
++ /* if a rate change is announced we need to check whether we can
++ * maintain the current frequency by changing the clock
++ * dividers. And we may have to suspend operation and return
++ * after the rate change or its abort
++ */
++ return NOTIFY_OK;
++ case POST_RATE_CHANGE:
++ return NOTIFY_OK;
++ case ABORT_RATE_CHANGE:
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
++/**
++ * xspips_probe - Probe method for the SPI driver
++ * @pdev: Pointer to the platform_device structure
++ *
++ * This function initializes the driver data structures and the hardware.
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xspips_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ struct spi_master *master;
++ struct xspips *xspi;
++ struct resource *res;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(*xspi));
++ if (master == NULL)
++ return -ENOMEM;
++
++ xspi = spi_master_get_devdata(master);
++ master->dev.of_node = pdev->dev.of_node;
++ platform_set_drvdata(pdev, master);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ xspi->regs = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(xspi->regs)) {
++ ret = PTR_ERR(xspi->regs);
++ dev_err(&pdev->dev, "ioremap failed\n");
++ goto remove_master;
++ }
++
++ xspi->irq = platform_get_irq(pdev, 0);
++ if (xspi->irq < 0) {
++ ret = -ENXIO;
++ dev_err(&pdev->dev, "irq number is negative\n");
++ goto remove_master;
++ }
++
++ ret = devm_request_irq(&pdev->dev, xspi->irq, xspips_irq,
++ 0, pdev->name, xspi);
++ if (ret != 0) {
++ ret = -ENXIO;
++ dev_err(&pdev->dev, "request_irq failed\n");
++ goto remove_master;
++ }
++
++ xspi->aperclk = clk_get(&pdev->dev, "aper_clk");
++ if (IS_ERR(xspi->aperclk)) {
++ dev_err(&pdev->dev, "aper_clk clock not found.\n");
++ ret = PTR_ERR(xspi->aperclk);
++ goto remove_master;
++ }
++
++ xspi->devclk = clk_get(&pdev->dev, "ref_clk");
++ if (IS_ERR(xspi->devclk)) {
++ dev_err(&pdev->dev, "ref_clk clock not found.\n");
++ ret = PTR_ERR(xspi->devclk);
++ goto clk_put_aper;
++ }
++
++ ret = clk_prepare_enable(xspi->aperclk);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable APER clock.\n");
++ goto clk_put;
++ }
++
++ ret = clk_prepare_enable(xspi->devclk);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable device clock.\n");
++ goto clk_dis_aper;
++ }
++
++ xspi->clk_rate_change_nb.notifier_call = xspips_clk_notifier_cb;
++ xspi->clk_rate_change_nb.next = NULL;
++ if (clk_notifier_register(xspi->devclk, &xspi->clk_rate_change_nb))
++ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
++
++ /* SPI controller initializations */
++ xspips_init_hw(xspi->regs);
++
++ init_completion(&xspi->done);
++
++ ret = of_property_read_u32(pdev->dev.of_node, "num-chip-select",
++ (u32 *)&master->num_chipselect);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "couldn't determine num-chip-select\n");
++ goto clk_notif_unreg;
++ }
++ master->setup = xspips_setup;
++ master->transfer = xspips_transfer;
++ master->mode_bits = SPI_CPOL | SPI_CPHA;
++
++ xspi->speed_hz = clk_get_rate(xspi->devclk) / 2;
++
++ xspi->dev_busy = 0;
++
++ INIT_LIST_HEAD(&xspi->queue);
++ spin_lock_init(&xspi->trans_queue_lock);
++ spin_lock_init(&xspi->ctrl_reg_lock);
++
++ xspi->queue_state = XSPIPS_QUEUE_STOPPED;
++ xspi->dev_busy = 0;
++
++ INIT_WORK(&xspi->work, xspips_work_queue);
++ xspi->workqueue =
++ create_singlethread_workqueue(dev_name(&pdev->dev));
++ if (!xspi->workqueue) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "problem initializing queue\n");
++ goto clk_notif_unreg;
++ }
++
++ ret = xspips_start_queue(xspi);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "problem starting queue\n");
++ goto remove_queue;
++ }
++
++ ret = spi_register_master(master);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_register_master failed\n");
++ goto remove_queue;
++ }
++
++ dev_info(&pdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n", res->start,
++ (u32 __force)xspi->regs, xspi->irq);
++
++ return ret;
++
++remove_queue:
++ (void)xspips_destroy_queue(xspi);
++clk_notif_unreg:
++ clk_notifier_unregister(xspi->devclk, &xspi->clk_rate_change_nb);
++ clk_disable_unprepare(xspi->devclk);
++clk_dis_aper:
++ clk_disable_unprepare(xspi->aperclk);
++clk_put:
++ clk_put(xspi->devclk);
++clk_put_aper:
++ clk_put(xspi->aperclk);
++remove_master:
++ spi_master_put(master);
++ return ret;
++}
++
++/**
++ * xspips_remove - Remove method for the SPI driver
++ * @pdev: Pointer to the platform_device structure
++ *
++ * This function is called if a device is physically removed from the system or
++ * if the driver module is being unloaded. It frees all resources allocated to
++ * the device.
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xspips_remove(struct platform_device *pdev)
++{
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct xspips *xspi = spi_master_get_devdata(master);
++ int ret = 0;
++
++ ret = xspips_destroy_queue(xspi);
++ if (ret != 0)
++ return ret;
++
++ xspips_write(xspi->regs + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK);
++
++ clk_notifier_unregister(xspi->devclk, &xspi->clk_rate_change_nb);
++ clk_disable_unprepare(xspi->devclk);
++ clk_disable_unprepare(xspi->aperclk);
++ clk_put(xspi->devclk);
++ clk_put(xspi->aperclk);
++
++ spi_unregister_master(master);
++ spi_master_put(master);
++
++ dev_dbg(&pdev->dev, "remove succeeded\n");
++ return 0;
++
++}
++
++#ifdef CONFIG_PM_SLEEP
++/**
++ * xspips_suspend - Suspend method for the SPI driver
++ * @dev: Address of the platform_device structure
++ *
++ * This function stops the SPI driver queue and disables the SPI controller
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xspips_suspend(struct device *dev)
++{
++ struct platform_device *pdev = container_of(dev,
++ struct platform_device, dev);
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct xspips *xspi = spi_master_get_devdata(master);
++ int ret = 0;
++
++ ret = xspips_stop_queue(xspi);
++ if (ret != 0)
++ return ret;
++
++ xspips_write(xspi->regs + XSPIPS_ER_OFFSET, ~XSPIPS_ER_ENABLE_MASK);
++
++ clk_disable(xspi->devclk);
++ clk_disable(xspi->aperclk);
++
++ dev_dbg(&pdev->dev, "suspend succeeded\n");
++ return 0;
++}
++
++/**
++ * xspips_resume - Resume method for the SPI driver
++ * @dev: Address of the platform_device structure
++ *
++ * This function starts the SPI driver queue and initializes the SPI controller
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xspips_resume(struct device *dev)
++{
++ struct platform_device *pdev = container_of(dev,
++ struct platform_device, dev);
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct xspips *xspi = spi_master_get_devdata(master);
++ int ret = 0;
++
++ ret = clk_enable(xspi->aperclk);
++ if (ret) {
++ dev_err(dev, "Cannot enable APER clock.\n");
++ return ret;
++ }
++
++ ret = clk_enable(xspi->devclk);
++ if (ret) {
++ dev_err(dev, "Cannot enable device clock.\n");
++ clk_disable(xspi->aperclk);
++ return ret;
++ }
++
++ xspips_init_hw(xspi->regs);
++
++ ret = xspips_start_queue(xspi);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "problem starting queue (%d)\n", ret);
++ return ret;
++ }
++
++ dev_dbg(&pdev->dev, "resume succeeded\n");
++ return 0;
++}
++#endif /* ! CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(xspips_dev_pm_ops, xspips_suspend, xspips_resume);
++
++/* Work with hotplug and coldplug */
++MODULE_ALIAS("platform:" XSPIPS_NAME);
++
++static struct of_device_id xspips_of_match[] = {
++ { .compatible = "xlnx,ps7-spi-1.00.a", },
++ { /* end of table */}
++};
++MODULE_DEVICE_TABLE(of, xspips_of_match);
++
++/*
++ * xspips_driver - This structure defines the SPI subsystem platform driver
++ */
++static struct platform_driver xspips_driver = {
++ .probe = xspips_probe,
++ .remove = xspips_remove,
++ .driver = {
++ .name = XSPIPS_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = xspips_of_match,
++ .pm = &xspips_dev_pm_ops,
++ },
++};
++
++module_platform_driver(xspips_driver);
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_DESCRIPTION("Xilinx PS SPI driver");
++MODULE_LICENSE("GPL");
++
+--- /dev/null
++++ b/drivers/spi/spi-xilinx-qps.c
+@@ -0,0 +1,1220 @@
++/*
++ *
++ * Xilinx PS Quad-SPI (QSPI) controller driver (master mode only)
++ *
++ * (c) 2009-2011 Xilinx, Inc.
++ *
++ * based on Xilinx PS SPI Driver (xspips.c)
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++
++/*
++ * Name of this driver
++ */
++#define DRIVER_NAME "xqspips"
++
++/*
++ * Register offset definitions
++ */
++#define XQSPIPS_CONFIG_OFFSET 0x00 /* Configuration Register, RW */
++#define XQSPIPS_STATUS_OFFSET 0x04 /* Interrupt Status Register, RO */
++#define XQSPIPS_IEN_OFFSET 0x08 /* Interrupt Enable Register, WO */
++#define XQSPIPS_IDIS_OFFSET 0x0C /* Interrupt Disable Reg, WO */
++#define XQSPIPS_IMASK_OFFSET 0x10 /* Interrupt Enabled Mask Reg,RO */
++#define XQSPIPS_ENABLE_OFFSET 0x14 /* Enable/Disable Register, RW */
++#define XQSPIPS_DELAY_OFFSET 0x18 /* Delay Register, RW */
++#define XQSPIPS_TXD_00_00_OFFSET 0x1C /* Transmit 4-byte inst, WO */
++#define XQSPIPS_TXD_00_01_OFFSET 0x80 /* Transmit 1-byte inst, WO */
++#define XQSPIPS_TXD_00_10_OFFSET 0x84 /* Transmit 2-byte inst, WO */
++#define XQSPIPS_TXD_00_11_OFFSET 0x88 /* Transmit 3-byte inst, WO */
++#define XQSPIPS_RXD_OFFSET 0x20 /* Data Receive Register, RO */
++#define XQSPIPS_SIC_OFFSET 0x24 /* Slave Idle Count Register, RW */
++#define XQSPIPS_TX_THRESH_OFFSET 0x28 /* TX FIFO Watermark Reg, RW */
++#define XQSPIPS_RX_THRESH_OFFSET 0x2C /* RX FIFO Watermark Reg, RW */
++#define XQSPIPS_GPIO_OFFSET 0x30 /* GPIO Register, RW */
++#define XQSPIPS_LINEAR_CFG_OFFSET 0xA0 /* Linear Adapter Config Ref, RW */
++#define XQSPIPS_MOD_ID_OFFSET 0xFC /* Module ID Register, RO */
++
++/*
++ * QSPI Configuration Register bit Masks
++ *
++ * This register contains various control bits that effect the operation
++ * of the QSPI controller
++ */
++#define XQSPIPS_CONFIG_MANSRT_MASK 0x00010000 /* Manual TX Start */
++#define XQSPIPS_CONFIG_CPHA_MASK 0x00000004 /* Clock Phase Control */
++#define XQSPIPS_CONFIG_CPOL_MASK 0x00000002 /* Clock Polarity Control */
++#define XQSPIPS_CONFIG_SSCTRL_MASK 0x00003C00 /* Slave Select Mask */
++
++/*
++ * QSPI Interrupt Registers bit Masks
++ *
++ * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
++ * bit definitions.
++ */
++#define XQSPIPS_IXR_TXNFULL_MASK 0x00000004 /* QSPI TX FIFO Overflow */
++#define XQSPIPS_IXR_TXFULL_MASK 0x00000008 /* QSPI TX FIFO is full */
++#define XQSPIPS_IXR_RXNEMTY_MASK 0x00000010 /* QSPI RX FIFO Not Empty */
++#define XQSPIPS_IXR_ALL_MASK (XQSPIPS_IXR_TXNFULL_MASK)
++
++/*
++ * QSPI Enable Register bit Masks
++ *
++ * This register is used to enable or disable the QSPI controller
++ */
++#define XQSPIPS_ENABLE_ENABLE_MASK 0x00000001 /* QSPI Enable Bit Mask */
++
++/*
++ * QSPI Linear Configuration Register
++ *
++ * It is named Linear Configuration but it controls other modes when not in
++ * linear mode also.
++ */
++#define XQSPIPS_LCFG_TWO_MEM_MASK 0x40000000 /* LQSPI Two memories Mask */
++#define XQSPIPS_LCFG_SEP_BUS_MASK 0x20000000 /* LQSPI Separate bus Mask */
++#define XQSPIPS_LCFG_U_PAGE_MASK 0x10000000 /* LQSPI Upper Page Mask */
++
++#define XQSPIPS_LCFG_DUMMY_SHIFT 8
++
++#define XQSPIPS_FAST_READ_QOUT_CODE 0x6B /* read instruction code */
++
++/*
++ * The modebits configurable by the driver to make the SPI support different
++ * data formats
++ */
++#define MODEBITS (SPI_CPOL | SPI_CPHA)
++
++/*
++ * Definitions for the status of queue
++ */
++#define XQSPIPS_QUEUE_STOPPED 0
++#define XQSPIPS_QUEUE_RUNNING 1
++
++/*
++ * Definitions of the flash commands
++ */
++/* Flash opcodes in ascending order */
++#define XQSPIPS_FLASH_OPCODE_WRSR 0x01 /* Write status register */
++#define XQSPIPS_FLASH_OPCODE_PP 0x02 /* Page program */
++#define XQSPIPS_FLASH_OPCODE_NORM_READ 0x03 /* Normal read data bytes */
++#define XQSPIPS_FLASH_OPCODE_WRDS 0x04 /* Write disable */
++#define XQSPIPS_FLASH_OPCODE_RDSR1 0x05 /* Read status register 1 */
++#define XQSPIPS_FLASH_OPCODE_WREN 0x06 /* Write enable */
++#define XQSPIPS_FLASH_OPCODE_BRRD 0x16 /* Bank Register Read */
++#define XQSPIPS_FLASH_OPCODE_BRWR 0x17 /* Bank Register Write */
++#define XQSPIPS_FLASH_OPCODE_EXTADRD 0xC8 /* Micron - Bank Reg Read */
++#define XQSPIPS_FLASH_OPCODE_EXTADWR 0xC5 /* Micron - Bank Reg Write */
++#define XQSPIPS_FLASH_OPCODE_FAST_READ 0x0B /* Fast read data bytes */
++#define XQSPIPS_FLASH_OPCODE_BE_4K 0x20 /* Erase 4KiB block */
++#define XQSPIPS_FLASH_OPCODE_RDSR2 0x35 /* Read status register 2 */
++#define XQSPIPS_FLASH_OPCODE_RDFSR 0x70 /* Read flag status register */
++#define XQSPIPS_FLASH_OPCODE_DUAL_READ 0x3B /* Dual read data bytes */
++#define XQSPIPS_FLASH_OPCODE_BE_32K 0x52 /* Erase 32KiB block */
++#define XQSPIPS_FLASH_OPCODE_QUAD_READ 0x6B /* Quad read data bytes */
++#define XQSPIPS_FLASH_OPCODE_ERASE_SUS 0x75 /* Erase suspend */
++#define XQSPIPS_FLASH_OPCODE_ERASE_RES 0x7A /* Erase resume */
++#define XQSPIPS_FLASH_OPCODE_RDID 0x9F /* Read JEDEC ID */
++#define XQSPIPS_FLASH_OPCODE_BE 0xC7 /* Erase whole flash block */
++#define XQSPIPS_FLASH_OPCODE_SE 0xD8 /* Sector erase (usually 64KB)*/
++#define XQSPIPS_FLASH_OPCODE_QPP 0x32 /* Quad page program */
++
++/*
++ * Macros for the QSPI controller read/write
++ */
++#define xqspips_read(addr) readl(addr)
++#define xqspips_write(addr, val) writel((val), (addr))
++
++/**
++ * struct xqspips - Defines qspi driver instance
++ * @workqueue: Queue of all the transfers
++ * @work: Information about current transfer
++ * @queue: Head of the queue
++ * @queue_state: Queue status
++ * @regs: Virtual address of the QSPI controller registers
++ * @devclk: Pointer to the peripheral clock
++ * @aperclk: Pointer to the APER clock
++ * @clk_rate_change_nb: Notifier block for clock frequency change callback
++ * @irq: IRQ number
++ * @speed_hz: Current QSPI bus clock speed in Hz
++ * @trans_queue_lock: Lock used for accessing transfer queue
++ * @config_reg_lock: Lock used for accessing configuration register
++ * @txbuf: Pointer to the TX buffer
++ * @rxbuf: Pointer to the RX buffer
++ * @bytes_to_transfer: Number of bytes left to transfer
++ * @bytes_to_receive: Number of bytes left to receive
++ * @dev_busy: Device busy flag
++ * @done: Transfer complete status
++ * @is_inst: Flag to indicate the first message in a Transfer request
++ * @is_dual: Flag to indicate whether dual flash memories are used
++ */
++struct xqspips {
++ struct workqueue_struct *workqueue;
++ struct work_struct work;
++ struct list_head queue;
++ u8 queue_state;
++ void __iomem *regs;
++ struct clk *devclk;
++ struct clk *aperclk;
++ struct notifier_block clk_rate_change_nb;
++ int irq;
++ u32 speed_hz;
++ spinlock_t trans_queue_lock;
++ spinlock_t config_reg_lock;
++ const void *txbuf;
++ void *rxbuf;
++ int bytes_to_transfer;
++ int bytes_to_receive;
++ u8 dev_busy;
++ struct completion done;
++ bool is_inst;
++ u32 is_dual;
++};
++
++/**
++ * struct xqspips_inst_format - Defines qspi flash instruction format
++ * @opcode: Operational code of instruction
++ * @inst_size: Size of the instruction including address bytes
++ * @offset: Register address where instruction has to be written
++ */
++struct xqspips_inst_format {
++ u8 opcode;
++ u8 inst_size;
++ u8 offset;
++};
++
++/*
++ * List of all the QSPI instructions and its format
++ */
++static struct xqspips_inst_format flash_inst[] = {
++ { XQSPIPS_FLASH_OPCODE_WREN, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_WRDS, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_RDSR1, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_RDSR2, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_WRSR, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_RDFSR, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_PP, 4, XQSPIPS_TXD_00_00_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_SE, 4, XQSPIPS_TXD_00_00_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_BE_32K, 4, XQSPIPS_TXD_00_00_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_BE_4K, 4, XQSPIPS_TXD_00_00_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_BE, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_ERASE_SUS, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_ERASE_RES, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_RDID, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_NORM_READ, 4, XQSPIPS_TXD_00_00_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_FAST_READ, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_DUAL_READ, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_QUAD_READ, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_BRRD, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_BRWR, 2, XQSPIPS_TXD_00_10_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_EXTADRD, 1, XQSPIPS_TXD_00_01_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_EXTADWR, 2, XQSPIPS_TXD_00_10_OFFSET },
++ { XQSPIPS_FLASH_OPCODE_QPP, 4, XQSPIPS_TXD_00_00_OFFSET },
++ /* Add all the instructions supported by the flash device */
++};
++
++/**
++ * xqspips_init_hw - Initialize the hardware
++ * @regs_base: Base address of QSPI controller
++ * @is_dual: Indicates whether dual memories are used
++ *
++ * The default settings of the QSPI controller's configurable parameters on
++ * reset are
++ * - Master mode
++ * - Baud rate divisor is set to 2
++ * - Threshold value for TX FIFO not full interrupt is set to 1
++ * - Flash memory interface mode enabled
++ * - Size of the word to be transferred as 8 bit
++ * This function performs the following actions
++ * - Disable and clear all the interrupts
++ * - Enable manual slave select
++ * - Enable manual start
++ * - Deselect all the chip select lines
++ * - Set the size of the word to be transferred as 32 bit
++ * - Set the little endian mode of TX FIFO and
++ * - Enable the QSPI controller
++ */
++static void xqspips_init_hw(void __iomem *regs_base, int is_dual)
++{
++ u32 config_reg;
++
++ xqspips_write(regs_base + XQSPIPS_ENABLE_OFFSET,
++ ~XQSPIPS_ENABLE_ENABLE_MASK);
++ xqspips_write(regs_base + XQSPIPS_IDIS_OFFSET, 0x7F);
++
++ /* Disable linear mode as the boot loader may have used it */
++ xqspips_write(regs_base + XQSPIPS_LINEAR_CFG_OFFSET, 0);
++
++ /* Clear the RX FIFO */
++ while (xqspips_read(regs_base + XQSPIPS_STATUS_OFFSET) &
++ XQSPIPS_IXR_RXNEMTY_MASK)
++ xqspips_read(regs_base + XQSPIPS_RXD_OFFSET);
++
++ xqspips_write(regs_base + XQSPIPS_STATUS_OFFSET , 0x7F);
++ config_reg = xqspips_read(regs_base + XQSPIPS_CONFIG_OFFSET);
++ config_reg &= 0xFBFFFFFF; /* Set little endian mode of TX FIFO */
++ config_reg |= 0x8000FCC1;
++ xqspips_write(regs_base + XQSPIPS_CONFIG_OFFSET, config_reg);
++
++ if (is_dual == 1)
++ /* Enable two memories on seperate buses */
++ xqspips_write(regs_base + XQSPIPS_LINEAR_CFG_OFFSET,
++ (XQSPIPS_LCFG_TWO_MEM_MASK |
++ XQSPIPS_LCFG_SEP_BUS_MASK |
++ (1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
++ XQSPIPS_FAST_READ_QOUT_CODE));
++#ifdef CONFIG_SPI_XILINX_PS_QSPI_DUAL_STACKED
++ /* Enable two memories on shared bus */
++ xqspips_write(regs_base + XQSPIPS_LINEAR_CFG_OFFSET,
++ (XQSPIPS_LCFG_TWO_MEM_MASK |
++ (1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
++ XQSPIPS_FAST_READ_QOUT_CODE));
++#endif
++ xqspips_write(regs_base + XQSPIPS_ENABLE_OFFSET,
++ XQSPIPS_ENABLE_ENABLE_MASK);
++}
++
++/**
++ * xqspips_copy_read_data - Copy data to RX buffer
++ * @xqspi: Pointer to the xqspips structure
++ * @data: The 32 bit variable where data is stored
++ * @size: Number of bytes to be copied from data to RX buffer
++ */
++static void xqspips_copy_read_data(struct xqspips *xqspi, u32 data, u8 size)
++{
++ if (xqspi->rxbuf) {
++ data >>= (4 - size) * 8;
++ data = le32_to_cpu(data);
++ memcpy((u8 *)xqspi->rxbuf, &data, size);
++ xqspi->rxbuf += size;
++ }
++ xqspi->bytes_to_receive -= size;
++ if (xqspi->bytes_to_receive < 0)
++ xqspi->bytes_to_receive = 0;
++}
++
++/**
++ * xqspips_copy_write_data - Copy data from TX buffer
++ * @xqspi: Pointer to the xqspips structure
++ * @data: Pointer to the 32 bit variable where data is to be copied
++ * @size: Number of bytes to be copied from TX buffer to data
++ */
++static void xqspips_copy_write_data(struct xqspips *xqspi, u32 *data, u8 size)
++{
++
++ if (xqspi->txbuf) {
++ switch (size) {
++ case 1:
++ *data = *((u8 *)xqspi->txbuf);
++ xqspi->txbuf += 1;
++ *data |= 0xFFFFFF00;
++ break;
++ case 2:
++ *data = *((u16 *)xqspi->txbuf);
++ xqspi->txbuf += 2;
++ *data |= 0xFFFF0000;
++ break;
++ case 3:
++ *data = *((u16 *)xqspi->txbuf);
++ xqspi->txbuf += 2;
++ *data |= (*((u8 *)xqspi->txbuf) << 16);
++ xqspi->txbuf += 1;
++ *data |= 0xFF000000;
++ break;
++ case 4:
++ *data = *((u32 *)xqspi->txbuf);
++ xqspi->txbuf += 4;
++ break;
++ default:
++ /* This will never execute */
++ break;
++ }
++ } else {
++ *data = 0;
++ }
++
++ xqspi->bytes_to_transfer -= size;
++ if (xqspi->bytes_to_transfer < 0)
++ xqspi->bytes_to_transfer = 0;
++}
++
++/**
++ * xqspips_chipselect - Select or deselect the chip select line
++ * @qspi: Pointer to the spi_device structure
++ * @is_on: Select(1) or deselect (0) the chip select line
++ */
++static void xqspips_chipselect(struct spi_device *qspi, int is_on)
++{
++ struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
++ u32 config_reg;
++ unsigned long flags;
++
++ spin_lock_irqsave(&xqspi->config_reg_lock, flags);
++
++ config_reg = xqspips_read(xqspi->regs + XQSPIPS_CONFIG_OFFSET);
++
++ if (is_on) {
++ /* Select the slave */
++ config_reg &= ~XQSPIPS_CONFIG_SSCTRL_MASK;
++ config_reg |= (((~(0x0001 << qspi->chip_select)) << 10) &
++ XQSPIPS_CONFIG_SSCTRL_MASK);
++ } else {
++ /* Deselect the slave */
++ config_reg |= XQSPIPS_CONFIG_SSCTRL_MASK;
++ }
++
++ xqspips_write(xqspi->regs + XQSPIPS_CONFIG_OFFSET, config_reg);
++
++ spin_unlock_irqrestore(&xqspi->config_reg_lock, flags);
++}
++
++/**
++ * xqspips_setup_transfer - Configure QSPI controller for specified transfer
++ * @qspi: Pointer to the spi_device structure
++ * @transfer: Pointer to the spi_transfer structure which provides information
++ * about next transfer setup parameters
++ *
++ * Sets the operational mode of QSPI controller for the next QSPI transfer and
++ * sets the requested clock frequency.
++ *
++ * returns: 0 on success and -EINVAL on invalid input parameter
++ *
++ * Note: If the requested frequency is not an exact match with what can be
++ * obtained using the prescalar value, the driver sets the clock frequency which
++ * is lower than the requested frequency (maximum lower) for the transfer. If
++ * the requested frequency is higher or lower than that is supported by the QSPI
++ * controller the driver will set the highest or lowest frequency supported by
++ * controller.
++ */
++static int xqspips_setup_transfer(struct spi_device *qspi,
++ struct spi_transfer *transfer)
++{
++ struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
++ u32 config_reg;
++ u32 req_hz;
++ u32 baud_rate_val = 0;
++ unsigned long flags;
++ int update_baud = 0;
++
++ req_hz = (transfer) ? transfer->speed_hz : qspi->max_speed_hz;
++
++ if (qspi->mode & ~MODEBITS) {
++ dev_err(&qspi->dev, "%s, unsupported mode bits %x\n",
++ __func__, qspi->mode & ~MODEBITS);
++ return -EINVAL;
++ }
++
++ if (transfer && (transfer->speed_hz == 0))
++ req_hz = qspi->max_speed_hz;
++
++ /* Set the clock frequency */
++ if (xqspi->speed_hz != req_hz) {
++ while ((baud_rate_val < 8) &&
++ (clk_get_rate(xqspi->devclk) / (2 << baud_rate_val)) >
++ req_hz)
++ baud_rate_val++;
++ xqspi->speed_hz = req_hz;
++ update_baud = 1;
++ }
++
++ spin_lock_irqsave(&xqspi->config_reg_lock, flags);
++
++ config_reg = xqspips_read(xqspi->regs + XQSPIPS_CONFIG_OFFSET);
++
++ /* Set the QSPI clock phase and clock polarity */
++ config_reg &= (~XQSPIPS_CONFIG_CPHA_MASK) &
++ (~XQSPIPS_CONFIG_CPOL_MASK);
++ if (qspi->mode & SPI_CPHA)
++ config_reg |= XQSPIPS_CONFIG_CPHA_MASK;
++ if (qspi->mode & SPI_CPOL)
++ config_reg |= XQSPIPS_CONFIG_CPOL_MASK;
++
++ if (update_baud) {
++ config_reg &= 0xFFFFFFC7;
++ config_reg |= (baud_rate_val << 3);
++ }
++
++ xqspips_write(xqspi->regs + XQSPIPS_CONFIG_OFFSET, config_reg);
++
++ spin_unlock_irqrestore(&xqspi->config_reg_lock, flags);
++
++ dev_dbg(&qspi->dev, "%s, mode %d, %u bits/w, %u clock speed\n",
++ __func__, qspi->mode & MODEBITS, qspi->bits_per_word,
++ xqspi->speed_hz);
++
++ return 0;
++}
++
++/**
++ * xqspips_setup - Configure the QSPI controller
++ * @qspi: Pointer to the spi_device structure
++ *
++ * Sets the operational mode of QSPI controller for the next QSPI transfer, baud
++ * rate and divisor value to setup the requested qspi clock.
++ *
++ * returns: 0 on success and error value on failure
++ */
++static int xqspips_setup(struct spi_device *qspi)
++{
++
++ if (qspi->mode & SPI_LSB_FIRST)
++ return -EINVAL;
++
++ if (!qspi->max_speed_hz)
++ return -EINVAL;
++
++ if (!qspi->bits_per_word)
++ qspi->bits_per_word = 32;
++
++ return xqspips_setup_transfer(qspi, NULL);
++}
++
++/**
++ * xqspips_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
++ * @xqspi: Pointer to the xqspips structure
++ */
++static void xqspips_fill_tx_fifo(struct xqspips *xqspi)
++{
++ u32 data = 0;
++
++ while ((!(xqspips_read(xqspi->regs + XQSPIPS_STATUS_OFFSET) &
++ XQSPIPS_IXR_TXFULL_MASK)) && (xqspi->bytes_to_transfer >= 4)) {
++ xqspips_copy_write_data(xqspi, &data, 4);
++ xqspips_write(xqspi->regs + XQSPIPS_TXD_00_00_OFFSET, data);
++ }
++}
++
++/**
++ * xqspips_irq - Interrupt service routine of the QSPI controller
++ * @irq: IRQ number
++ * @dev_id: Pointer to the xqspi structure
++ *
++ * This function handles TX empty only.
++ * On TX empty interrupt this function reads the received data from RX FIFO and
++ * fills the TX FIFO if there is any data remaining to be transferred.
++ *
++ * returns: IRQ_HANDLED always
++ */
++static irqreturn_t xqspips_irq(int irq, void *dev_id)
++{
++ struct xqspips *xqspi = dev_id;
++ u32 intr_status;
++ u8 offset[3] = {XQSPIPS_TXD_00_01_OFFSET, XQSPIPS_TXD_00_10_OFFSET,
++ XQSPIPS_TXD_00_11_OFFSET};
++
++ intr_status = xqspips_read(xqspi->regs + XQSPIPS_STATUS_OFFSET);
++ xqspips_write(xqspi->regs + XQSPIPS_STATUS_OFFSET , intr_status);
++ xqspips_write(xqspi->regs + XQSPIPS_IDIS_OFFSET,
++ XQSPIPS_IXR_ALL_MASK);
++
++ if ((intr_status & XQSPIPS_IXR_TXNFULL_MASK) ||
++ (intr_status & XQSPIPS_IXR_RXNEMTY_MASK)) {
++ /* This bit is set when Tx FIFO has < THRESHOLD entries. We have
++ the THRESHOLD value set to 1, so this bit indicates Tx FIFO
++ is empty */
++ u32 config_reg;
++ u32 data;
++
++ /* Read out the data from the RX FIFO */
++ while (xqspips_read(xqspi->regs + XQSPIPS_STATUS_OFFSET) &
++ XQSPIPS_IXR_RXNEMTY_MASK) {
++
++ data = xqspips_read(xqspi->regs + XQSPIPS_RXD_OFFSET);
++
++ if (xqspi->bytes_to_receive < 4 && !xqspi->is_dual)
++ xqspips_copy_read_data(xqspi, data,
++ xqspi->bytes_to_receive);
++ else
++ xqspips_copy_read_data(xqspi, data, 4);
++ }
++
++ if (xqspi->bytes_to_transfer) {
++ if (xqspi->bytes_to_transfer >= 4) {
++ /* There is more data to send */
++ xqspips_fill_tx_fifo(xqspi);
++ } else {
++ int tmp;
++ tmp = xqspi->bytes_to_transfer;
++ xqspips_copy_write_data(xqspi, &data,
++ xqspi->bytes_to_transfer);
++ if (xqspi->is_dual)
++ xqspips_write(xqspi->regs +
++ XQSPIPS_TXD_00_00_OFFSET, data);
++ else
++ xqspips_write(xqspi->regs +
++ offset[tmp - 1], data);
++ }
++ xqspips_write(xqspi->regs + XQSPIPS_IEN_OFFSET,
++ XQSPIPS_IXR_ALL_MASK);
++
++ spin_lock(&xqspi->config_reg_lock);
++ config_reg = xqspips_read(xqspi->regs +
++ XQSPIPS_CONFIG_OFFSET);
++
++ config_reg |= XQSPIPS_CONFIG_MANSRT_MASK;
++ xqspips_write(xqspi->regs + XQSPIPS_CONFIG_OFFSET,
++ config_reg);
++ spin_unlock(&xqspi->config_reg_lock);
++ } else {
++ /* If transfer and receive is completed then only send
++ * complete signal */
++ if (xqspi->bytes_to_receive) {
++ /* There is still some data to be received.
++ Enable Rx not empty interrupt */
++ xqspips_write(xqspi->regs + XQSPIPS_IEN_OFFSET,
++ XQSPIPS_IXR_RXNEMTY_MASK);
++ } else {
++ xqspips_write(xqspi->regs + XQSPIPS_IDIS_OFFSET,
++ XQSPIPS_IXR_RXNEMTY_MASK);
++ complete(&xqspi->done);
++ }
++ }
++ }
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * xqspips_start_transfer - Initiates the QSPI transfer
++ * @qspi: Pointer to the spi_device structure
++ * @transfer: Pointer to the spi_transfer structure which provide information
++ * about next transfer parameters
++ *
++ * This function fills the TX FIFO, starts the QSPI transfer, and waits for the
++ * transfer to be completed.
++ *
++ * returns: Number of bytes transferred in the last transfer
++ */
++static int xqspips_start_transfer(struct spi_device *qspi,
++ struct spi_transfer *transfer)
++{
++ struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
++ u32 config_reg;
++ unsigned long flags;
++ u32 data = 0;
++ u8 instruction = 0;
++ u8 index;
++ struct xqspips_inst_format *curr_inst;
++
++ xqspi->txbuf = transfer->tx_buf;
++ xqspi->rxbuf = transfer->rx_buf;
++ xqspi->bytes_to_transfer = transfer->len;
++ xqspi->bytes_to_receive = transfer->len;
++
++ if (xqspi->txbuf)
++ instruction = *(u8 *)xqspi->txbuf;
++
++ INIT_COMPLETION(xqspi->done);
++ if (instruction && xqspi->is_inst) {
++ for (index = 0; index < ARRAY_SIZE(flash_inst); index++)
++ if (instruction == flash_inst[index].opcode)
++ break;
++
++ /* Instruction might have already been transmitted. This is a
++ * 'data only' transfer */
++ if (index == ARRAY_SIZE(flash_inst))
++ goto xfer_data;
++
++ curr_inst = &flash_inst[index];
++
++ /* Get the instruction */
++ data = 0;
++ xqspips_copy_write_data(xqspi, &data,
++ curr_inst->inst_size);
++
++ /* Write the instruction to LSB of the FIFO. The core is
++ * designed such that it is not necessary to check whether the
++ * write FIFO is full before writing. However, write would be
++ * delayed if the user tries to write when write FIFO is full
++ */
++ xqspips_write(xqspi->regs + curr_inst->offset, data);
++ goto xfer_start;
++ }
++
++xfer_data:
++ /* In case of Fast, Dual and Quad reads, transmit the instruction first.
++ * Address and dummy byte will be transmitted in interrupt handler,
++ * after instruction is transmitted */
++ if (((xqspi->is_inst == 0) && (xqspi->bytes_to_transfer >= 4)) ||
++ ((xqspi->bytes_to_transfer >= 4) &&
++ (instruction != XQSPIPS_FLASH_OPCODE_FAST_READ) &&
++ (instruction != XQSPIPS_FLASH_OPCODE_DUAL_READ) &&
++ (instruction != XQSPIPS_FLASH_OPCODE_QUAD_READ)))
++ xqspips_fill_tx_fifo(xqspi);
++
++xfer_start:
++ xqspips_write(xqspi->regs + XQSPIPS_IEN_OFFSET,
++ XQSPIPS_IXR_ALL_MASK);
++ /* Start the transfer by enabling manual start bit */
++ spin_lock_irqsave(&xqspi->config_reg_lock, flags);
++ config_reg = xqspips_read(xqspi->regs +
++ XQSPIPS_CONFIG_OFFSET) | XQSPIPS_CONFIG_MANSRT_MASK;
++ xqspips_write(xqspi->regs + XQSPIPS_CONFIG_OFFSET, config_reg);
++ spin_unlock_irqrestore(&xqspi->config_reg_lock, flags);
++
++ wait_for_completion(&xqspi->done);
++
++ return (transfer->len) - (xqspi->bytes_to_transfer);
++}
++
++/**
++ * xqspips_work_queue - Get the request from queue to perform transfers
++ * @work: Pointer to the work_struct structure
++ */
++static void xqspips_work_queue(struct work_struct *work)
++{
++ struct xqspips *xqspi = container_of(work, struct xqspips, work);
++ unsigned long flags;
++#ifdef CONFIG_SPI_XILINX_PS_QSPI_DUAL_STACKED
++ u32 lqspi_cfg_reg;
++#endif
++
++ spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
++ xqspi->dev_busy = 1;
++
++ /* Check if list is empty or queue is stoped */
++ if (list_empty(&xqspi->queue) ||
++ xqspi->queue_state == XQSPIPS_QUEUE_STOPPED) {
++ xqspi->dev_busy = 0;
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++ return;
++ }
++
++ /* Keep requesting transfer till list is empty */
++ while (!list_empty(&xqspi->queue)) {
++ struct spi_message *msg;
++ struct spi_device *qspi;
++ struct spi_transfer *transfer = NULL;
++ unsigned cs_change = 1;
++ int status = 0;
++
++ msg = container_of(xqspi->queue.next, struct spi_message,
++ queue);
++ list_del_init(&msg->queue);
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++ qspi = msg->spi;
++
++#ifdef CONFIG_SPI_XILINX_PS_QSPI_DUAL_STACKED
++ lqspi_cfg_reg = xqspips_read(xqspi->regs +
++ XQSPIPS_LINEAR_CFG_OFFSET);
++ if (qspi->master->flags & SPI_MASTER_U_PAGE)
++ lqspi_cfg_reg |= XQSPIPS_LCFG_U_PAGE_MASK;
++ else
++ lqspi_cfg_reg &= ~XQSPIPS_LCFG_U_PAGE_MASK;
++ xqspips_write(xqspi->regs + XQSPIPS_LINEAR_CFG_OFFSET,
++ lqspi_cfg_reg);
++#endif
++
++ list_for_each_entry(transfer, &msg->transfers, transfer_list) {
++ if (transfer->bits_per_word || transfer->speed_hz) {
++ status = xqspips_setup_transfer(qspi, transfer);
++ if (status < 0)
++ break;
++ }
++
++ /* Select the chip if required */
++ if (cs_change) {
++ xqspips_chipselect(qspi, 1);
++ xqspi->is_inst = 1;
++ }
++
++ cs_change = transfer->cs_change;
++
++ if (!transfer->tx_buf && !transfer->rx_buf &&
++ transfer->len) {
++ status = -EINVAL;
++ break;
++ }
++
++ /* Request the transfer */
++ if (transfer->len) {
++ status = xqspips_start_transfer(qspi, transfer);
++ xqspi->is_inst = 0;
++ }
++
++ if (status != transfer->len) {
++ if (status > 0)
++ status = -EMSGSIZE;
++ break;
++ }
++ msg->actual_length += status;
++ status = 0;
++
++ if (transfer->delay_usecs)
++ udelay(transfer->delay_usecs);
++
++ if (cs_change)
++ /* Deselect the chip */
++ xqspips_chipselect(qspi, 0);
++
++ if (transfer->transfer_list.next == &msg->transfers)
++ break;
++ }
++
++ msg->status = status;
++ msg->complete(msg->context);
++
++ xqspips_setup_transfer(qspi, NULL);
++
++ if (!(status == 0 && cs_change))
++ xqspips_chipselect(qspi, 0);
++
++ spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
++ }
++ xqspi->dev_busy = 0;
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++}
++
++/**
++ * xqspips_transfer - Add a new transfer request at the tail of work queue
++ * @qspi: Pointer to the spi_device structure
++ * @message: Pointer to the spi_transfer structure which provides information
++ * about next transfer parameters
++ *
++ * returns: 0 on success, -EINVAL on invalid input parameter and
++ * -ESHUTDOWN if queue is stopped by module unload function
++ */
++static int xqspips_transfer(struct spi_device *qspi,
++ struct spi_message *message)
++{
++ struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
++ struct spi_transfer *transfer;
++ unsigned long flags;
++
++ if (xqspi->queue_state == XQSPIPS_QUEUE_STOPPED)
++ return -ESHUTDOWN;
++
++ message->actual_length = 0;
++ message->status = -EINPROGRESS;
++
++ /* Check each transfer's parameters */
++ list_for_each_entry(transfer, &message->transfers, transfer_list) {
++ if (!transfer->tx_buf && !transfer->rx_buf && transfer->len)
++ return -EINVAL;
++ /* QSPI controller supports only 32 bit transfers whereas higher
++ * layer drivers request 8 bit transfers. Re-visit at a later
++ * time */
++ /* if (bits_per_word != 32)
++ return -EINVAL; */
++ }
++
++ spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
++ list_add_tail(&message->queue, &xqspi->queue);
++ if (!xqspi->dev_busy)
++ queue_work(xqspi->workqueue, &xqspi->work);
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++
++ return 0;
++}
++
++/**
++ * xqspips_start_queue - Starts the queue of the QSPI driver
++ * @xqspi: Pointer to the xqspips structure
++ *
++ * returns: 0 on success and -EBUSY if queue is already running or device is
++ * busy
++ */
++static inline int xqspips_start_queue(struct xqspips *xqspi)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
++
++ if (xqspi->queue_state == XQSPIPS_QUEUE_RUNNING || xqspi->dev_busy) {
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++ return -EBUSY;
++ }
++
++ xqspi->queue_state = XQSPIPS_QUEUE_RUNNING;
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++
++ return 0;
++}
++
++/**
++ * xqspips_stop_queue - Stops the queue of the QSPI driver
++ * @xqspi: Pointer to the xqspips structure
++ *
++ * This function waits till queue is empty and then stops the queue.
++ * Maximum time out is set to 5 seconds.
++ *
++ * returns: 0 on success and -EBUSY if queue is not empty or device is busy
++ */
++static inline int xqspips_stop_queue(struct xqspips *xqspi)
++{
++ unsigned long flags;
++ unsigned limit = 500;
++ int ret = 0;
++
++ if (xqspi->queue_state != XQSPIPS_QUEUE_RUNNING)
++ return ret;
++
++ spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
++
++ while ((!list_empty(&xqspi->queue) || xqspi->dev_busy) && limit--) {
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++ msleep(10);
++ spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
++ }
++
++ if (!list_empty(&xqspi->queue) || xqspi->dev_busy)
++ ret = -EBUSY;
++
++ if (ret == 0)
++ xqspi->queue_state = XQSPIPS_QUEUE_STOPPED;
++
++ spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
++
++ return ret;
++}
++
++/**
++ * xqspips_destroy_queue - Destroys the queue of the QSPI driver
++ * @xqspi: Pointer to the xqspips structure
++ *
++ * returns: 0 on success and error value on failure
++ */
++static inline int xqspips_destroy_queue(struct xqspips *xqspi)
++{
++ int ret;
++
++ ret = xqspips_stop_queue(xqspi);
++ if (ret != 0)
++ return ret;
++
++ destroy_workqueue(xqspi->workqueue);
++
++ return 0;
++}
++
++static int xqspips_clk_notifier_cb(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++ switch (event) {
++ case PRE_RATE_CHANGE:
++ /* if a rate change is announced we need to check whether we can
++ * maintain the current frequency by changing the clock
++ * dividers. And we may have to suspend operation and return
++ * after the rate change or its abort
++ */
++ return NOTIFY_OK;
++ case POST_RATE_CHANGE:
++ return NOTIFY_OK;
++ case ABORT_RATE_CHANGE:
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
++#ifdef CONFIG_PM_SLEEP
++/**
++ * xqspips_suspend - Suspend method for the QSPI driver
++ * @_dev: Address of the platform_device structure
++ *
++ * This function stops the QSPI driver queue and disables the QSPI controller
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xqspips_suspend(struct device *_dev)
++{
++ struct platform_device *pdev = container_of(_dev,
++ struct platform_device, dev);
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct xqspips *xqspi = spi_master_get_devdata(master);
++ int ret = 0;
++
++ ret = xqspips_stop_queue(xqspi);
++ if (ret != 0)
++ return ret;
++
++ xqspips_write(xqspi->regs + XQSPIPS_ENABLE_OFFSET,
++ ~XQSPIPS_ENABLE_ENABLE_MASK);
++
++ clk_disable(xqspi->devclk);
++ clk_disable(xqspi->aperclk);
++
++ dev_dbg(&pdev->dev, "suspend succeeded\n");
++ return 0;
++}
++
++/**
++ * xqspips_resume - Resume method for the QSPI driver
++ * @dev: Address of the platform_device structure
++ *
++ * The function starts the QSPI driver queue and initializes the QSPI controller
++ *
++ * returns: 0 on success and error value on error
++ */
++static int xqspips_resume(struct device *dev)
++{
++ struct platform_device *pdev = container_of(dev,
++ struct platform_device, dev);
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct xqspips *xqspi = spi_master_get_devdata(master);
++ int ret = 0;
++
++ ret = clk_enable(xqspi->aperclk);
++ if (ret) {
++ dev_err(dev, "Cannot enable APER clock.\n");
++ return ret;
++ }
++
++ ret = clk_enable(xqspi->devclk);
++ if (ret) {
++ dev_err(dev, "Cannot enable device clock.\n");
++ clk_disable(xqspi->aperclk);
++ return ret;
++ }
++
++ xqspips_init_hw(xqspi->regs, xqspi->is_dual);
++
++ ret = xqspips_start_queue(xqspi);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "problem starting queue (%d)\n", ret);
++ return ret;
++ }
++
++ dev_dbg(&pdev->dev, "resume succeeded\n");
++ return 0;
++}
++#endif /* ! CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(xqspips_dev_pm_ops, xqspips_suspend, xqspips_resume);
++
++/**
++ * xqspips_probe - Probe method for the QSPI driver
++ * @pdev: Pointer to the platform_device structure
++ *
++ * This function initializes the driver data structures and the hardware.
++ *
++ * returns: 0 on success and error value on failure
++ */
++static int xqspips_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ struct spi_master *master;
++ struct xqspips *xqspi;
++ struct resource *res;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
++ if (master == NULL)
++ return -ENOMEM;
++
++ xqspi = spi_master_get_devdata(master);
++ master->dev.of_node = pdev->dev.of_node;
++ platform_set_drvdata(pdev, master);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ xqspi->regs = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(xqspi->regs)) {
++ ret = PTR_ERR(xqspi->regs);
++ dev_err(&pdev->dev, "ioremap failed\n");
++ goto remove_master;
++ }
++
++ xqspi->irq = platform_get_irq(pdev, 0);
++ if (xqspi->irq < 0) {
++ ret = -ENXIO;
++ dev_err(&pdev->dev, "irq resource not found\n");
++ goto remove_master;
++ }
++ ret = devm_request_irq(&pdev->dev, xqspi->irq, xqspips_irq,
++ 0, pdev->name, xqspi);
++ if (ret != 0) {
++ ret = -ENXIO;
++ dev_err(&pdev->dev, "request_irq failed\n");
++ goto remove_master;
++ }
++
++ if (of_property_read_u32(pdev->dev.of_node, "is-dual", &xqspi->is_dual))
++ dev_warn(&pdev->dev, "couldn't determine configuration info "
++ "about dual memories. defaulting to single memory\n");
++
++ xqspi->aperclk = clk_get(&pdev->dev, "aper_clk");
++ if (IS_ERR(xqspi->aperclk)) {
++ dev_err(&pdev->dev, "aper_clk clock not found.\n");
++ ret = PTR_ERR(xqspi->aperclk);
++ goto remove_master;
++ }
++
++ xqspi->devclk = clk_get(&pdev->dev, "ref_clk");
++ if (IS_ERR(xqspi->devclk)) {
++ dev_err(&pdev->dev, "ref_clk clock not found.\n");
++ ret = PTR_ERR(xqspi->devclk);
++ goto clk_put_aper;
++ }
++
++ ret = clk_prepare_enable(xqspi->aperclk);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable APER clock.\n");
++ goto clk_put;
++ }
++
++ ret = clk_prepare_enable(xqspi->devclk);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to enable device clock.\n");
++ goto clk_dis_aper;
++ }
++
++ xqspi->clk_rate_change_nb.notifier_call = xqspips_clk_notifier_cb;
++ xqspi->clk_rate_change_nb.next = NULL;
++ if (clk_notifier_register(xqspi->devclk, &xqspi->clk_rate_change_nb))
++ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
++
++
++ /* QSPI controller initializations */
++ xqspips_init_hw(xqspi->regs, xqspi->is_dual);
++
++ init_completion(&xqspi->done);
++
++ ret = of_property_read_u32(pdev->dev.of_node, "num-chip-select",
++ (u32 *)&master->num_chipselect);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "couldn't determine num-chip-select\n");
++ goto clk_unreg_notif;
++ }
++
++ master->setup = xqspips_setup;
++ master->transfer = xqspips_transfer;
++ master->flags = SPI_MASTER_QUAD_MODE;
++
++ xqspi->speed_hz = clk_get_rate(xqspi->devclk) / 2;
++
++ xqspi->dev_busy = 0;
++
++ INIT_LIST_HEAD(&xqspi->queue);
++ spin_lock_init(&xqspi->trans_queue_lock);
++ spin_lock_init(&xqspi->config_reg_lock);
++
++ xqspi->queue_state = XQSPIPS_QUEUE_STOPPED;
++ xqspi->dev_busy = 0;
++
++ INIT_WORK(&xqspi->work, xqspips_work_queue);
++ xqspi->workqueue =
++ create_singlethread_workqueue(dev_name(&pdev->dev));
++ if (!xqspi->workqueue) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "problem initializing queue\n");
++ goto clk_unreg_notif;
++ }
++
++ ret = xqspips_start_queue(xqspi);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "problem starting queue\n");
++ goto remove_queue;
++ }
++
++ ret = spi_register_master(master);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_register_master failed\n");
++ goto remove_queue;
++ }
++
++ dev_info(&pdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n", res->start,
++ (u32 __force)xqspi->regs, xqspi->irq);
++
++ return ret;
++
++remove_queue:
++ (void)xqspips_destroy_queue(xqspi);
++clk_unreg_notif:
++ clk_notifier_unregister(xqspi->devclk, &xqspi->clk_rate_change_nb);
++ clk_disable_unprepare(xqspi->devclk);
++clk_dis_aper:
++ clk_disable_unprepare(xqspi->aperclk);
++clk_put:
++ clk_put(xqspi->devclk);
++clk_put_aper:
++ clk_put(xqspi->aperclk);
++remove_master:
++ spi_master_put(master);
++ return ret;
++}
++
++/**
++ * xqspips_remove - Remove method for the QSPI driver
++ * @pdev: Pointer to the platform_device structure
++ *
++ * This function is called if a device is physically removed from the system or
++ * if the driver module is being unloaded. It frees all resources allocated to
++ * the device.
++ *
++ * returns: 0 on success and error value on failure
++ */
++static int xqspips_remove(struct platform_device *pdev)
++{
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct xqspips *xqspi = spi_master_get_devdata(master);
++ int ret = 0;
++
++ ret = xqspips_destroy_queue(xqspi);
++ if (ret != 0)
++ return ret;
++
++ xqspips_write(xqspi->regs + XQSPIPS_ENABLE_OFFSET,
++ ~XQSPIPS_ENABLE_ENABLE_MASK);
++
++ clk_notifier_unregister(xqspi->devclk, &xqspi->clk_rate_change_nb);
++ clk_disable_unprepare(xqspi->devclk);
++ clk_disable_unprepare(xqspi->aperclk);
++ clk_put(xqspi->devclk);
++ clk_put(xqspi->aperclk);
++
++
++ spi_unregister_master(master);
++ spi_master_put(master);
++
++
++ dev_dbg(&pdev->dev, "remove succeeded\n");
++ return 0;
++}
++
++/* Work with hotplug and coldplug */
++MODULE_ALIAS("platform:" DRIVER_NAME);
++
++static struct of_device_id xqspips_of_match[] = {
++ { .compatible = "xlnx,ps7-qspi-1.00.a", },
++ { /* end of table */}
++};
++MODULE_DEVICE_TABLE(of, xqspips_of_match);
++
++/*
++ * xqspips_driver - This structure defines the QSPI platform driver
++ */
++static struct platform_driver xqspips_driver = {
++ .probe = xqspips_probe,
++ .remove = xqspips_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = xqspips_of_match,
++ .pm = &xqspips_dev_pm_ops,
++ },
++};
++
++module_platform_driver(xqspips_driver);
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_DESCRIPTION("Xilinx PS QSPI driver");
++MODULE_LICENSE("GPL");
+--- a/drivers/spi/spi-xilinx.c
++++ b/drivers/spi/spi-xilinx.c
+@@ -82,7 +82,7 @@ struct xilinx_spi {
+ struct completion done;
+ void __iomem *regs; /* virt. address of the control registers */
+
+- int irq;
++ int irq;
+
+ u8 *rx_ptr; /* pointer in the Tx buffer */
+ const u8 *tx_ptr; /* pointer in the Rx buffer */
+@@ -232,6 +232,21 @@ static int xilinx_spi_setup_transfer(str
+ return 0;
+ }
+
++static int xilinx_spi_setup(struct spi_device *spi)
++{
++ /* always return 0, we can not check the number of bits.
++ * There are cases when SPI setup is called before any driver is
++ * there, in that case the SPI core defaults to 8 bits, which we
++ * do not support in some cases. But if we return an error, the
++ * SPI device would not be registered and no driver can get hold of it
++ * When the driver is there, it will call SPI setup again with the
++ * correct number of bits per transfer.
++ * If a driver setups with the wrong bit number, it will fail when
++ * it tries to do a transfer
++ */
++ return 0;
++}
++
+ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
+ {
+ u8 sr;
+@@ -300,7 +315,7 @@ static int xilinx_spi_txrx_bufs(struct s
+ }
+
+ /* See if there is more data to send */
+- if (xspi->remaining_bytes <= 0)
++ if (!xspi->remaining_bytes > 0)
+ break;
+ }
+
+@@ -349,7 +364,7 @@ static int xilinx_spi_probe(struct platf
+ u32 tmp;
+ u8 i;
+
+- pdata = dev_get_platdata(&pdev->dev);
++ pdata = pdev->dev.platform_data;
+ if (pdata) {
+ num_cs = pdata->num_chipselect;
+ bits_per_word = pdata->bits_per_word;
+@@ -368,14 +383,18 @@ static int xilinx_spi_probe(struct platf
+ if (!master)
+ return -ENODEV;
+
++ /* clear the dma_mask, to try to disable use of dma */
++ master->dev.dma_mask = 0;
++
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+
+ xspi = spi_master_get_devdata(master);
+- xspi->bitbang.master = master;
++ xspi->bitbang.master = spi_master_get(master);
+ xspi->bitbang.chipselect = xilinx_spi_chipselect;
+ xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
+ xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
++ xspi->bitbang.master->setup = xilinx_spi_setup;
+ init_completion(&xspi->done);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -314,6 +314,8 @@ struct spi_master {
+ #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
+ #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */
+ #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */
++#define SPI_MASTER_U_PAGE BIT(3) /* select upper flash */
++#define SPI_MASTER_QUAD_MODE BIT(4) /* support quad mode */
+
+ /* lock and mutex for SPI bus locking */
+ spinlock_t bus_lock_spinlock;
diff --git a/patches.zynq/0007-mtd-xilinx-merge-nand-flash-support-from-xilinx-repo.patch b/patches.zynq/0007-mtd-xilinx-merge-nand-flash-support-from-xilinx-repo.patch
new file mode 100644
index 00000000000000..2f1c62fcfd1279
--- /dev/null
+++ b/patches.zynq/0007-mtd-xilinx-merge-nand-flash-support-from-xilinx-repo.patch
@@ -0,0 +1,1876 @@
+From 74eaf4cb9dfdfc0deab5c9a1b8e3de82916ca94b Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Tue, 24 Dec 2013 09:18:18 +0900
+Subject: mtd: xilinx: merge nand flash support from xilinx repository
+
+This merges support for the Xilinx nand flash support from the
+Xilinx repository (commit efc27505715e64526653f35274717c0fc56491e3
+in master branch). It has been tested by reading the QSPI flash
+in the Zynq 702 board.
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/mtd/devices/m25p80.c | 417 +++++++++++++--
+ drivers/mtd/nand/Kconfig | 7
+ drivers/mtd/nand/Makefile | 1
+ drivers/mtd/nand/nand_base.c | 28 +
+ drivers/mtd/nand/xilinx_nandps.c | 1064 +++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 1469 insertions(+), 48 deletions(-)
+ create mode 100644 drivers/mtd/nand/xilinx_nandps.c
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -41,12 +41,16 @@
+ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */
+ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */
+ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
++#define OPCODE_QUAD_READ 0x6b /* Quad read command */
+ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
++#define OPCODE_QPP 0x32 /* Quad page program */
+ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
+ #define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
+ #define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
+ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
+ #define OPCODE_RDID 0x9f /* Read JEDEC ID */
++#define OPCODE_RDFSR 0x70 /* Read Flag Status Register */
++#define OPCODE_WREAR 0xc5 /* Write Extended Address Register */
+
+ /* Used for SST flashes only. */
+ #define OPCODE_BP 0x02 /* Byte program */
+@@ -59,6 +63,7 @@
+
+ /* Used for Spansion flashes only. */
+ #define OPCODE_BRWR 0x17 /* Bank register write */
++#define OPCODE_BRRD 0x16 /* Bank register read */
+
+ /* Status Register bits. */
+ #define SR_WIP 1 /* Write in progress */
+@@ -69,8 +74,11 @@
+ #define SR_BP2 0x10 /* Block protect 2 */
+ #define SR_SRWD 0x80 /* SR write protect */
+
++/* Flag Status Register bits. */
++#define FSR_RDY 0x80 /* Ready/Busy program erase
++ controller */
+ /* Define max times to check status register before we give up. */
+-#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
++#define MAX_READY_WAIT_JIFFIES (480 * HZ) /* N25Q specs 480s max chip erase */
+ #define MAX_CMD_SIZE 5
+
+ #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16)
+@@ -86,6 +94,15 @@ struct m25p {
+ u8 erase_opcode;
+ u8 *command;
+ bool fast_read;
++ u16 curbank;
++ u32 jedec_id;
++ bool check_fsr;
++ bool shift;
++ bool isparallel;
++ bool isstacked;
++ u8 read_opcode;
++ u8 prog_opcode;
++ u8 dummycount;
+ };
+
+ static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
+@@ -100,21 +117,19 @@ static inline struct m25p *mtd_to_m25p(s
+ */
+
+ /*
+- * Read the status register, returning its value in the location
+- * Return the status register value.
++ * Read register, returning its value in the location
+ * Returns negative if error occurred.
+ */
+-static int read_sr(struct m25p *flash)
++static inline int read_spi_reg(struct m25p *flash, u8 code, const char *name)
+ {
+ ssize_t retval;
+- u8 code = OPCODE_RDSR;
+ u8 val;
+
+ retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
+
+ if (retval < 0) {
+- dev_err(&flash->spi->dev, "error %d reading SR\n",
+- (int) retval);
++ dev_err(&flash->spi->dev, "error %d reading %s\n",
++ (int) retval, name);
+ return retval;
+ }
+
+@@ -122,6 +137,26 @@ static int read_sr(struct m25p *flash)
+ }
+
+ /*
++ * Read flag status register, returning its value in the location
++ * Return flag status register value.
++ * Returns negative if error occurred.
++ */
++static int read_fsr(struct m25p *flash)
++{
++ return read_spi_reg(flash, OPCODE_RDFSR, "FSR");
++}
++
++/*
++ * Read the status register, returning its value in the location
++ * Return the status register value.
++ * Returns negative if error occurred.
++ */
++static int read_sr(struct m25p *flash)
++{
++ return read_spi_reg(flash, OPCODE_RDSR, "SR");
++}
++
++/*
+ * Write status register 1 byte
+ * Returns negative if error occurred.
+ */
+@@ -159,6 +194,9 @@ static inline int write_disable(struct m
+ */
+ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
+ {
++ int ret;
++ u8 val;
++
+ switch (JEDEC_MFR(jedec_id)) {
+ case CFI_MFR_MACRONIX:
+ case 0xEF /* winbond */:
+@@ -168,7 +206,19 @@ static inline int set_4byte(struct m25p
+ /* Spansion style */
+ flash->command[0] = OPCODE_BRWR;
+ flash->command[1] = enable << 7;
+- return spi_write(flash->spi, flash->command, 2);
++ ret = spi_write(flash->spi, flash->command, 2);
++
++ /* verify the 4 byte mode is enabled */
++ flash->command[0] = OPCODE_BRRD;
++ spi_write_then_read(flash->spi, flash->command, 1, &val, 1);
++ if (val != enable << 7) {
++ dev_warn(&flash->spi->dev,
++ "fallback to 3-byte address mode\n");
++ dev_warn(&flash->spi->dev,
++ "maximum accessible size is 16MB\n");
++ flash->addr_width = 3;
++ }
++ return ret;
+ }
+ }
+
+@@ -179,15 +229,21 @@ static inline int set_4byte(struct m25p
+ static int wait_till_ready(struct m25p *flash)
+ {
+ unsigned long deadline;
+- int sr;
++ int sr, fsr;
+
+ deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+
+ do {
+ if ((sr = read_sr(flash)) < 0)
+ break;
+- else if (!(sr & SR_WIP))
++ else if (!(sr & SR_WIP)) {
++ if (flash->check_fsr) {
++ fsr = read_fsr(flash);
++ if (!(fsr & FSR_RDY))
++ return 1;
++ }
+ return 0;
++ }
+
+ cond_resched();
+
+@@ -197,6 +253,48 @@ static int wait_till_ready(struct m25p *
+ }
+
+ /*
++ * Update Extended Address/bank selection Register.
++ * Call with flash->lock locked.
++ */
++static int write_ear(struct m25p *flash, u32 addr)
++{
++ u8 ear;
++ int ret;
++
++ /* Wait until finished previous write command. */
++ if (wait_till_ready(flash))
++ return 1;
++
++ if (flash->mtd.size <= (0x1000000) << flash->shift)
++ return 0;
++
++ addr = addr % (u32) flash->mtd.size;
++ ear = addr >> 24;
++
++ if ((!flash->isstacked) && (ear == flash->curbank))
++ return 0;
++
++ if (flash->isstacked && (flash->mtd.size <= 0x2000000))
++ return 0;
++
++ if (JEDEC_MFR(flash->jedec_id) == 0x01)
++ flash->command[0] = OPCODE_BRWR;
++ if (JEDEC_MFR(flash->jedec_id) == 0x20) {
++ write_enable(flash);
++ flash->command[0] = OPCODE_WREAR;
++ }
++ flash->command[1] = ear;
++
++ ret = spi_write(flash->spi, flash->command, 2);
++ if (ret)
++ return ret;
++
++ flash->curbank = ear;
++
++ return 0;
++}
++
++/*
+ * Erase the whole flash memory
+ *
+ * Returns 0 if successful, non-zero otherwise.
+@@ -210,6 +308,9 @@ static int erase_chip(struct m25p *flash
+ if (wait_till_ready(flash))
+ return 1;
+
++ if (flash->isstacked)
++ flash->spi->master->flags &= ~SPI_MASTER_U_PAGE;
++
+ /* Send write enable, then erase commands. */
+ write_enable(flash);
+
+@@ -218,16 +319,32 @@ static int erase_chip(struct m25p *flash
+
+ spi_write(flash->spi, flash->command, 1);
+
++ if (flash->isstacked) {
++ /* Wait until finished previous write command. */
++ if (wait_till_ready(flash))
++ return 1;
++
++ flash->spi->master->flags |= SPI_MASTER_U_PAGE;
++
++ /* Send write enable, then erase commands. */
++ write_enable(flash);
++
++ /* Set up command buffer. */
++ flash->command[0] = OPCODE_CHIP_ERASE;
++
++ spi_write(flash->spi, flash->command, 1);
++ }
++
+ return 0;
+ }
+
+ static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd)
+ {
++ int i;
++
+ /* opcode is in cmd[0] */
+- cmd[1] = addr >> (flash->addr_width * 8 - 8);
+- cmd[2] = addr >> (flash->addr_width * 8 - 16);
+- cmd[3] = addr >> (flash->addr_width * 8 - 24);
+- cmd[4] = addr >> (flash->addr_width * 8 - 32);
++ for (i = 1; i <= flash->addr_width; i++)
++ cmd[i] = addr >> (flash->addr_width * 8 - i * 8);
+ }
+
+ static int m25p_cmdsz(struct m25p *flash)
+@@ -250,6 +367,10 @@ static int erase_sector(struct m25p *fla
+ if (wait_till_ready(flash))
+ return 1;
+
++ /* update Extended Address Register */
++ if (write_ear(flash, offset))
++ return 1;
++
+ /* Send write enable, then erase commands. */
+ write_enable(flash);
+
+@@ -275,7 +396,7 @@ static int erase_sector(struct m25p *fla
+ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
+ {
+ struct m25p *flash = mtd_to_m25p(mtd);
+- u32 addr,len;
++ u32 addr, len, offset;
+ uint32_t rem;
+
+ pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev),
+@@ -307,7 +428,19 @@ static int m25p80_erase(struct mtd_info
+ /* "sector"-at-a-time erase */
+ } else {
+ while (len) {
+- if (erase_sector(flash, addr)) {
++ offset = addr;
++ if (flash->isparallel == 1)
++ offset /= 2;
++ if (flash->isstacked == 1) {
++ if (offset >= (flash->mtd.size / 2)) {
++ offset = offset - (flash->mtd.size / 2);
++ flash->spi->master->flags |=
++ SPI_MASTER_U_PAGE;
++ } else
++ flash->spi->master->flags &=
++ ~SPI_MASTER_U_PAGE;
++ }
++ if (erase_sector(flash, offset)) {
+ instr->state = MTD_ERASE_FAILED;
+ mutex_unlock(&flash->lock);
+ return -EIO;
+@@ -336,7 +469,6 @@ static int m25p80_read(struct mtd_info *
+ struct m25p *flash = mtd_to_m25p(mtd);
+ struct spi_transfer t[2];
+ struct spi_message m;
+- uint8_t opcode;
+
+ pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
+ __func__, (u32)from, len);
+@@ -349,21 +481,17 @@ static int m25p80_read(struct mtd_info *
+ * Should add 1 byte DUMMY_BYTE.
+ */
+ t[0].tx_buf = flash->command;
+- t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0);
++ t[0].len = m25p_cmdsz(flash) + flash->dummycount;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+- mutex_lock(&flash->lock);
+-
+ /* Wait till previous write/erase is done. */
+- if (wait_till_ready(flash)) {
++ if (wait_till_ready(flash))
+ /* REVISIT status return?? */
+- mutex_unlock(&flash->lock);
+ return 1;
+- }
+
+ /* FIXME switch to OPCODE_FAST_READ. It's required for higher
+ * clocks; and at this writing, every chip this driver handles
+@@ -371,17 +499,65 @@ static int m25p80_read(struct mtd_info *
+ */
+
+ /* Set up the write data buffer. */
+- opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
+- flash->command[0] = opcode;
++ flash->command[0] = flash->read_opcode;
+ m25p_addr2cmd(flash, from, flash->command);
+
+ spi_sync(flash->spi, &m);
+
+ *retlen = m.actual_length - m25p_cmdsz(flash) -
+- (flash->fast_read ? 1 : 0);
++ flash->dummycount;
+
+- mutex_unlock(&flash->lock);
++ return 0;
++}
++
++static int m25p80_read_ext(struct mtd_info *mtd, loff_t from, size_t len,
++ size_t *retlen, u_char *buf)
++{
++ struct m25p *flash = mtd_to_m25p(mtd);
++ u32 addr = from;
++ u32 offset = from;
++ u32 read_len = 0;
++ u32 actual_len = 0;
++ u32 read_count = 0;
++ u32 rem_bank_len = 0;
++ u8 bank = 0;
++
++#define OFFSET_16_MB 0x1000000
++
++ mutex_lock(&flash->lock);
++
++ while (len) {
++ bank = addr / (OFFSET_16_MB << flash->shift);
++ rem_bank_len = ((OFFSET_16_MB << flash->shift) * (bank + 1)) -
++ addr;
++ offset = addr;
++ if (flash->isparallel == 1)
++ offset /= 2;
++ if (flash->isstacked == 1) {
++ if (offset >= (flash->mtd.size / 2)) {
++ offset = offset - (flash->mtd.size / 2);
++ flash->spi->master->flags |= SPI_MASTER_U_PAGE;
++ } else {
++ flash->spi->master->flags &= ~SPI_MASTER_U_PAGE;
++ }
++ }
++ write_ear(flash, offset);
++ if (len < rem_bank_len)
++ read_len = len;
++ else
++ read_len = rem_bank_len;
++
++ m25p80_read(mtd, offset, read_len, &actual_len, buf);
+
++ addr += actual_len;
++ len -= actual_len;
++ buf += actual_len;
++ read_count += actual_len;
++ }
++
++ *retlen = read_count;
++
++ mutex_unlock(&flash->lock);
+ return 0;
+ }
+
+@@ -411,19 +587,15 @@ static int m25p80_write(struct mtd_info
+ t[1].tx_buf = buf;
+ spi_message_add_tail(&t[1], &m);
+
+- mutex_lock(&flash->lock);
+-
+ /* Wait until finished previous write command. */
+- if (wait_till_ready(flash)) {
+- mutex_unlock(&flash->lock);
++ if (wait_till_ready(flash))
+ return 1;
+- }
+
+ write_enable(flash);
+
+ /* Set up the opcode in the write buffer. */
+- flash->command[0] = OPCODE_PP;
+- m25p_addr2cmd(flash, to, flash->command);
++ flash->command[0] = flash->prog_opcode;
++ m25p_addr2cmd(flash, (to >> flash->shift), flash->command);
+
+ page_offset = to & (flash->page_size - 1);
+
+@@ -452,12 +624,14 @@ static int m25p80_write(struct mtd_info
+ page_size = flash->page_size;
+
+ /* write the next page to flash */
+- m25p_addr2cmd(flash, to + i, flash->command);
++ m25p_addr2cmd(flash, ((to + i) >> flash->shift),
++ flash->command);
+
+ t[1].tx_buf = buf + i;
+ t[1].len = page_size;
+
+- wait_till_ready(flash);
++ if (wait_till_ready(flash))
++ return 1;
+
+ write_enable(flash);
+
+@@ -467,8 +641,55 @@ static int m25p80_write(struct mtd_info
+ }
+ }
+
+- mutex_unlock(&flash->lock);
++ return 0;
++}
++
++static int m25p80_write_ext(struct mtd_info *mtd, loff_t to, size_t len,
++ size_t *retlen, const u_char *buf)
++{
++ struct m25p *flash = mtd_to_m25p(mtd);
++ u32 addr = to;
++ u32 offset = to;
++ u32 write_len = 0;
++ u32 actual_len = 0;
++ u32 write_count = 0;
++ u32 rem_bank_len = 0;
++ u8 bank = 0;
++
++#define OFFSET_16_MB 0x1000000
++
++ mutex_lock(&flash->lock);
++ while (len) {
++ bank = addr / (OFFSET_16_MB << flash->shift);
++ rem_bank_len = ((OFFSET_16_MB << flash->shift) * (bank + 1)) -
++ addr;
++ offset = addr;
++
++ if (flash->isstacked == 1) {
++ if (offset >= (flash->mtd.size / 2)) {
++ offset = offset - (flash->mtd.size / 2);
++ flash->spi->master->flags |= SPI_MASTER_U_PAGE;
++ } else {
++ flash->spi->master->flags &= ~SPI_MASTER_U_PAGE;
++ }
++ }
++ write_ear(flash, (offset >> flash->shift));
++ if (len < rem_bank_len)
++ write_len = len;
++ else
++ write_len = rem_bank_len;
+
++ m25p80_write(mtd, offset, write_len, &actual_len, buf);
++
++ addr += actual_len;
++ len -= actual_len;
++ buf += actual_len;
++ write_count += actual_len;
++ }
++
++ *retlen = write_count;
++
++ mutex_unlock(&flash->lock);
+ return 0;
+ }
+
+@@ -682,6 +903,8 @@ struct flash_info {
+ #define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */
+ #define M25P_NO_ERASE 0x02 /* No erase command needed */
+ #define SST_WRITE 0x04 /* use SST byte programming */
++#define SECT_32K 0x10 /* OPCODE_BE_32K */
++#define E_FSR 0x08 /* Flag SR exists for flash */
+ };
+
+ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
+@@ -761,6 +984,15 @@ static const struct spi_device_id m25p_i
+ { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
+ { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
+ { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
++ /* Numonyx flash n25q128 - FIXME check the name */
++ { "n25q128", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
++ { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, E_FSR) },
++ { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, E_FSR) },
++ { "n25q256a13", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | E_FSR) },
++ { "n25q256a11", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | E_FSR) },
++ { "n25q512a13", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | E_FSR) },
++ { "n25q512a11", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | E_FSR) },
++ { "n25q00aa13", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | E_FSR) },
+
+ /* Spansion -- single (large) sector size only, at least
+ * for the chips listed here (without boot sectors).
+@@ -781,7 +1013,11 @@ static const struct spi_device_id m25p_i
+ { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) },
+ { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) },
+ { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) },
+- { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
++ /* s25fl064k supports 4KiB, 32KiB and 64KiB sectors erase size. */
++ /* To support JFFS2, the minimum erase size is 8KiB(>4KiB). */
++ /* And thus, the sector size of s25fl064k is set to 32KiB for */
++ /* JFFS2 support. */
++ { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_32K) },
+
+ /* SST -- large erase sizes are "overlays", "sectors" are 4K */
+ { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
+@@ -789,10 +1025,11 @@ static const struct spi_device_id m25p_i
+ { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
+ { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
+ { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
+- { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) },
+- { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) },
+- { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) },
+- { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
++ { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) },
++ { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) },
++ { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) },
++ { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
++ { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
+
+ /* ST Microelectronics -- newer production may have feature updates */
+ { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) },
+@@ -839,7 +1076,12 @@ static const struct spi_device_id m25p_i
+ { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
+ { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
+ { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
+- { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
++ /* Winbond -- w25q "blocks" are 64K, "sectors" are 32KiB */
++ /* w25q64 supports 4KiB, 32KiB and 64KiB sectors erase size. */
++ /* To support JFFS2, the minimum erase size is 8KiB(>4KiB). */
++ /* And thus, the sector size of w25q64 is set to 32KiB for */
++ /* JFFS2 support. */
++ { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_32K) },
+ { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
+ { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
+ { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
+@@ -995,8 +1237,54 @@ static int m25p_probe(struct spi_device
+ flash->mtd.writesize = 1;
+ flash->mtd.flags = MTD_CAP_NORFLASH;
+ flash->mtd.size = info->sector_size * info->n_sectors;
++
++ {
++#ifdef CONFIG_OF
++ const char *comp_str;
++ u32 is_dual;
++ np = of_get_next_parent(spi->dev.of_node);
++ of_property_read_string(np, "compatible", &comp_str);
++ if (!strcmp(comp_str, "xlnx,ps7-qspi-1.00.a")) {
++ if (of_property_read_u32(np, "is-dual", &is_dual) < 0) {
++ /* Default to single if prop not defined */
++ flash->shift = 0;
++ flash->isstacked = 0;
++ flash->isparallel = 0;
++ } else {
++ if (is_dual == 1) {
++ /* dual parallel */
++ flash->shift = 1;
++ info->sector_size <<= flash->shift;
++ info->page_size <<= flash->shift;
++ flash->mtd.size <<= flash->shift;
++ flash->isparallel = 1;
++ flash->isstacked = 0;
++ } else {
++#ifdef CONFIG_SPI_XILINX_PS_QSPI_DUAL_STACKED
++ /* dual stacked */
++ flash->shift = 0;
++ flash->mtd.size <<= 1;
++ flash->isstacked = 1;
++ flash->isparallel = 0;
++#else
++ /* single */
++ flash->shift = 0;
++ flash->isstacked = 0;
++ flash->isparallel = 0;
++#endif
++ }
++ }
++ }
++#else
++ /* Default to single */
++ flash->shift = 0;
++ flash->isstacked = 0;
++ flash->isparallel = 0;
++#endif
++ }
++
+ flash->mtd._erase = m25p80_erase;
+- flash->mtd._read = m25p80_read;
++ flash->mtd._read = m25p80_read_ext;
+
+ /* flash protection support for STmicro chips */
+ if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
+@@ -1008,20 +1296,31 @@ static int m25p_probe(struct spi_device
+ if (info->flags & SST_WRITE)
+ flash->mtd._write = sst_write;
+ else
+- flash->mtd._write = m25p80_write;
++ flash->mtd._write = m25p80_write_ext;
+
+ /* prefer "small sector" erase if possible */
+ if (info->flags & SECT_4K) {
+ flash->erase_opcode = OPCODE_BE_4K;
+- flash->mtd.erasesize = 4096;
++ flash->mtd.erasesize = 4096 << flash->shift;
++ } else if (info->flags & SECT_32K) {
++ flash->erase_opcode = OPCODE_BE_32K;
++ flash->mtd.erasesize = 32768 << flash->shift;
+ } else {
+ flash->erase_opcode = OPCODE_SE;
+ flash->mtd.erasesize = info->sector_size;
+ }
+
++ flash->read_opcode = OPCODE_NORM_READ;
++ flash->prog_opcode = OPCODE_PP;
++ flash->dummycount = 0;
++
+ if (info->flags & M25P_NO_ERASE)
+ flash->mtd.flags |= MTD_NO_ERASE;
+
++ if (info->flags & E_FSR)
++ flash->check_fsr = 1;
++
++ flash->jedec_id = info->jedec_id;
+ ppdata.of_node = spi->dev.of_node;
+ flash->mtd.dev.parent = &spi->dev;
+ flash->page_size = info->page_size;
+@@ -1036,14 +1335,36 @@ static int m25p_probe(struct spi_device
+ #ifdef CONFIG_M25PXX_USE_FAST_READ
+ flash->fast_read = true;
+ #endif
++ if (flash->fast_read) {
++ flash->read_opcode = OPCODE_FAST_READ;
++ flash->dummycount = 1;
++ }
++
++ if (spi->master->flags & SPI_MASTER_QUAD_MODE) {
++ flash->read_opcode = OPCODE_QUAD_READ;
++ flash->prog_opcode = OPCODE_QPP;
++ flash->dummycount = 1;
++ }
+
+ if (info->addr_width)
+ flash->addr_width = info->addr_width;
+ else {
+ /* enable 4-byte addressing if the device exceeds 16MiB */
+ if (flash->mtd.size > 0x1000000) {
+- flash->addr_width = 4;
+- set_4byte(flash, info->jedec_id, 1);
++#ifdef CONFIG_OF
++ const char *comp_str;
++ np = of_get_next_parent(spi->dev.of_node);
++ of_property_read_string(np, "compatible", &comp_str);
++ if (!strcmp(comp_str, "xlnx,ps7-qspi-1.00.a")) {
++ flash->addr_width = 3;
++ set_4byte(flash, info->jedec_id, 0);
++ } else {
++#endif
++ flash->addr_width = 4;
++ set_4byte(flash, info->jedec_id, 1);
++#ifdef CONFIG_OF
++ }
++#endif
+ } else
+ flash->addr_width = 3;
+ }
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -523,6 +523,13 @@ config MTD_NAND_NUC900
+ This enables the driver for the NAND Flash on evaluation board based
+ on w90p910 / NUC9xx.
+
++config MTD_NAND_XILINX_PS
++ tristate "Xilinx Zynq NAND flash driver"
++ depends on MTD_NAND && ARCH_ZYNQ
++ select ZYNQ_SMC
++ help
++ This enables access to the NAND flash device on Xilinx Zynq.
++
+ config MTD_NAND_JZ4740
+ tristate "Support for JZ4740 SoC NAND controller"
+ depends on MACH_JZ4740
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -44,6 +44,7 @@ obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.
+ obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
+ obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
+ obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
++obj-$(CONFIG_MTD_NAND_XILINX_PS) += xilinx_nandps.o
+ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
+ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
+ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -814,6 +814,11 @@ static int nand_wait(struct mtd_info *mt
+ int status, state = chip->state;
+ unsigned long timeo = (state == FL_ERASING ? 400 : 20);
+
++#if defined(ARCH_ZYNQ) && (CONFIG_HZ == 20)
++ /* Xilinx Zynq NAND work around for HZ=20 */
++ timeo += 1;
++#endif
++
+ led_trigger_event(nand_led_trigger, LED_FULL);
+
+ /*
+@@ -2858,11 +2863,18 @@ static int nand_flash_detect_onfi(struct
+ int i;
+ int val;
+
++#ifdef CONFIG_MTD_NAND_XILINX_PS
++ uint8_t *buf;
++ unsigned int options;
++ int j;
++#endif
++
+ /* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */
+ if (chip->options & NAND_BUSWIDTH_16) {
+ pr_err("Trying ONFI probe in 16 bits mode, aborting !\n");
+ return 0;
+ }
++
+ /* Try ONFI for unknown chip or LP */
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
+ if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
+@@ -2871,7 +2883,13 @@ static int nand_flash_detect_onfi(struct
+
+ chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
+ for (i = 0; i < 3; i++) {
++#ifdef CONFIG_MTD_NAND_XILINX_PS
++ buf = (uint8_t *)p;
++ for (j = 0; j < 256; j++)
++ buf[j] = chip->read_byte(mtd);
++#else
+ chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
++#endif
+ if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
+ le16_to_cpu(p->crc)) {
+ pr_info("ONFI param page %d valid\n", i);
+@@ -2924,7 +2942,17 @@ static int nand_flash_detect_onfi(struct
+ if (le16_to_cpu(p->features) & 1)
+ *busw = NAND_BUSWIDTH_16;
+
++#ifdef CONFIG_MTD_NAND_XILINX_PS
++ /* Read the chip options before clearing the bits */
++ options = chip->options;
++#endif
++
+ pr_info("ONFI flash detected\n");
++#ifdef CONFIG_MTD_NAND_XILINX_PS
++ /* set the bus width option */
++ if (options & NAND_BUSWIDTH_16)
++ chip->options |= NAND_BUSWIDTH_16;
++#endif
+ return 1;
+ }
+
+--- /dev/null
++++ b/drivers/mtd/nand/xilinx_nandps.c
+@@ -0,0 +1,1064 @@
++/*
++ * Xilinx Zynq NAND Flash Controller Driver
++ *
++ * Copyright (C) 2009 Xilinx, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/*
++ * This driver is based on plat_nand.c and mxc_nand.c drivers
++ */
++
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/irq.h>
++#include <linux/memory/zynq-smc.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#define XNANDPS_DRIVER_NAME "xilinx_nandps"
++
++/* NAND flash driver defines */
++#define XNANDPS_CMD_PHASE 1 /* End command valid in command phase */
++#define XNANDPS_DATA_PHASE 2 /* End command valid in data phase */
++#define XNANDPS_ECC_SIZE 512 /* Size of data for ECC operation */
++
++/* Flash memory controller operating parameters */
++
++#define XNANDPS_ECC_CONFIG ((1 << 4) | /* ECC read at end of page */ \
++ (0 << 5)) /* No Jumping */
++
++/* AXI Address definitions */
++#define START_CMD_SHIFT 3
++#define END_CMD_SHIFT 11
++#define END_CMD_VALID_SHIFT 20
++#define ADDR_CYCLES_SHIFT 21
++#define CLEAR_CS_SHIFT 21
++#define ECC_LAST_SHIFT 10
++#define COMMAND_PHASE (0 << 19)
++#define DATA_PHASE (1 << 19)
++
++#define XNANDPS_ECC_LAST (1 << ECC_LAST_SHIFT) /* Set ECC_Last */
++#define XNANDPS_CLEAR_CS (1 << CLEAR_CS_SHIFT) /* Clear chip select */
++
++#define ONDIE_ECC_FEATURE_ADDR 0x90
++
++/* Macros for the NAND controller register read/write */
++#define xnandps_write32(addr, val) __raw_writel((val), (addr))
++
++
++/**
++ * struct xnandps_command_format - Defines NAND flash command format
++ * @start_cmd: First cycle command (Start command)
++ * @end_cmd: Second cycle command (Last command)
++ * @addr_cycles: Number of address cycles required to send the address
++ * @end_cmd_valid: The second cycle command is valid for cmd or data phase
++ **/
++struct xnandps_command_format {
++ int start_cmd;
++ int end_cmd;
++ u8 addr_cycles;
++ u8 end_cmd_valid;
++};
++
++/**
++ * struct xnandps_info - Defines the NAND flash driver instance
++ * @chip: NAND chip information structure
++ * @mtd: MTD information structure
++ * @parts: Pointer to the mtd_partition structure
++ * @nand_base: Virtual address of the NAND flash device
++ * @end_cmd_pending: End command is pending
++ * @end_cmd: End command
++ **/
++struct xnandps_info {
++ struct nand_chip chip;
++ struct mtd_info mtd;
++ struct mtd_partition *parts;
++ void __iomem *nand_base;
++ unsigned long end_cmd_pending;
++ unsigned long end_cmd;
++};
++
++/*
++ * The NAND flash operations command format
++ */
++static const struct xnandps_command_format xnandps_commands[] = {
++ {NAND_CMD_READ0, NAND_CMD_READSTART, 5, XNANDPS_CMD_PHASE},
++ {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, XNANDPS_CMD_PHASE},
++ {NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE},
++ {NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE},
++ {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, XNANDPS_DATA_PHASE},
++ {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE},
++ {NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, XNANDPS_CMD_PHASE},
++ {NAND_CMD_RESET, NAND_CMD_NONE, 0, NAND_CMD_NONE},
++ {NAND_CMD_PARAM, NAND_CMD_NONE, 1, NAND_CMD_NONE},
++ {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE},
++ {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE},
++ {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0},
++ /* Add all the flash commands supported by the flash device and Linux */
++ /* The cache program command is not supported by driver because driver
++ * cant differentiate between page program and cached page program from
++ * start command, these commands can be differentiated through end
++ * command, which doesn't fit in to the driver design. The cache program
++ * command is not supported by NAND subsystem also, look at 1612 line
++ * number (in nand_write_page function) of nand_base.c file.
++ * {NAND_CMD_SEQIN, NAND_CMD_CACHEDPROG, 5, XNANDPS_YES}, */
++};
++
++/* Define default oob placement schemes for large and small page devices */
++static struct nand_ecclayout nand_oob_16 = {
++ .eccbytes = 3,
++ .eccpos = {0, 1, 2},
++ .oobfree = {
++ {.offset = 8,
++ . length = 8} }
++};
++
++static struct nand_ecclayout nand_oob_64 = {
++ .eccbytes = 12,
++ .eccpos = {
++ 52, 53, 54, 55, 56, 57,
++ 58, 59, 60, 61, 62, 63},
++ .oobfree = {
++ {.offset = 2,
++ .length = 50} }
++};
++
++static struct nand_ecclayout ondie_nand_oob_64 = {
++ .eccbytes = 32,
++
++ .eccpos = {
++ 8, 9, 10, 11, 12, 13, 14, 15,
++ 24, 25, 26, 27, 28, 29, 30, 31,
++ 40, 41, 42, 43, 44, 45, 46, 47,
++ 56, 57, 58, 59, 60, 61, 62, 63
++ },
++
++ .oobfree = {
++ { .offset = 4, .length = 4 },
++ { .offset = 20, .length = 4 },
++ { .offset = 36, .length = 4 },
++ { .offset = 52, .length = 4 }
++ }
++};
++
++/* Generic flash bbt decriptors
++*/
++static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
++static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
++
++static struct nand_bbt_descr bbt_main_descr = {
++ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++ .offs = 4,
++ .len = 4,
++ .veroffs = 20,
++ .maxblocks = 4,
++ .pattern = bbt_pattern
++};
++
++static struct nand_bbt_descr bbt_mirror_descr = {
++ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++ .offs = 4,
++ .len = 4,
++ .veroffs = 20,
++ .maxblocks = 4,
++ .pattern = mirror_pattern
++};
++
++/**
++ * xnandps_calculate_hwecc - Calculate Hardware ECC
++ * @mtd: Pointer to the mtd_info structure
++ * @data: Pointer to the page data
++ * @ecc_code: Pointer to the ECC buffer where ECC data needs to be stored
++ *
++ * This function retrieves the Hardware ECC data from the controller and returns
++ * ECC data back to the MTD subsystem.
++ *
++ * returns: 0 on success or error value on failure
++ **/
++static int
++xnandps_calculate_hwecc(struct mtd_info *mtd, const u8 *data, u8 *ecc_code)
++{
++ u32 ecc_value = 0;
++ u8 ecc_reg, ecc_byte;
++ u32 ecc_status;
++
++ /* Wait till the ECC operation is complete */
++ while (xsmcps_ecc_is_busy())
++ cpu_relax();
++
++ for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) {
++ /* Read ECC value for each block */
++ ecc_value = xsmcps_get_ecc_val(ecc_reg);
++ ecc_status = (ecc_value >> 24) & 0xFF;
++ /* ECC value valid */
++ if (ecc_status & 0x40) {
++ for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) {
++ /* Copy ECC bytes to MTD buffer */
++ *ecc_code = ecc_value & 0xFF;
++ ecc_value = ecc_value >> 8;
++ ecc_code++;
++ }
++ } else {
++ /* TO DO */
++ /* dev_warn(&pdev->dev, "pl350: ecc status failed\n");
++ * */
++ }
++ }
++ return 0;
++}
++
++/**
++ * onehot - onehot function
++ * @value: value to check for onehot
++ *
++ * This function checks whether a value is onehot or not.
++ * onehot is if and only if onebit is set.
++ *
++ **/
++static int onehot(unsigned short value)
++{
++ return ((value & (value-1)) == 0);
++}
++
++/**
++ * xnandps_correct_data - ECC correction function
++ * @mtd: Pointer to the mtd_info structure
++ * @buf: Pointer to the page data
++ * @read_ecc: Pointer to the ECC value read from spare data area
++ * @calc_ecc: Pointer to the calculated ECC value
++ *
++ * This function corrects the ECC single bit errors & detects 2-bit errors.
++ *
++ * returns: 0 if no ECC errors found
++ * 1 if single bit error found and corrected.
++ * -1 if multiple ECC errors found.
++ **/
++static int xnandps_correct_data(struct mtd_info *mtd, unsigned char *buf,
++ unsigned char *read_ecc, unsigned char *calc_ecc)
++{
++ unsigned char bit_addr;
++ unsigned int byte_addr;
++ unsigned short ecc_odd, ecc_even;
++ unsigned short read_ecc_lower, read_ecc_upper;
++ unsigned short calc_ecc_lower, calc_ecc_upper;
++
++ read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff;
++ read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff;
++
++ calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff;
++ calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff;
++
++ ecc_odd = read_ecc_lower ^ calc_ecc_lower;
++ ecc_even = read_ecc_upper ^ calc_ecc_upper;
++
++ if ((ecc_odd == 0) && (ecc_even == 0))
++ return 0; /* no error */
++
++ if (ecc_odd == (~ecc_even & 0xfff)) {
++ /* bits [11:3] of error code is byte offset */
++ byte_addr = (ecc_odd >> 3) & 0x1ff;
++ /* bits [2:0] of error code is bit offset */
++ bit_addr = ecc_odd & 0x7;
++ /* Toggling error bit */
++ buf[byte_addr] ^= (1 << bit_addr);
++ return 1;
++ }
++
++ if (onehot(ecc_odd | ecc_even) == 1)
++ return 1; /* one error in parity */
++
++ return -1; /* Uncorrectable error */
++}
++
++/**
++ * xnandps_read_oob - [REPLACABLE] the most common OOB data read function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @page: page number to read
++ */
++static int xnandps_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ unsigned long data_width = 4;
++ unsigned long data_phase_addr = 0;
++ uint8_t *p;
++
++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++
++ p = chip->oob_poi;
++ chip->read_buf(mtd, p, (mtd->oobsize - data_width));
++ p += (mtd->oobsize - data_width);
++
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
++ data_phase_addr |= XNANDPS_CLEAR_CS;
++ chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
++ chip->read_buf(mtd, p, data_width);
++
++ return 0;
++}
++
++/**
++ * xnandps_write_oob - [REPLACABLE] the most common OOB data write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @page: page number to write
++ */
++static int xnandps_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ int status = 0;
++ const uint8_t *buf = chip->oob_poi;
++ unsigned long data_width = 4;
++ unsigned long data_phase_addr = 0;
++
++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
++
++ chip->write_buf(mtd, buf, (mtd->oobsize - data_width));
++ buf += (mtd->oobsize - data_width);
++
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
++ data_phase_addr |= XNANDPS_CLEAR_CS;
++ data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
++ chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
++ chip->write_buf(mtd, buf, data_width);
++
++ /* Send command to program the OOB data */
++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++ status = chip->waitfunc(mtd, chip);
++
++ return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++/**
++ * xnandps_read_page_raw - [Intern] read raw page data without ecc
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @page: page number to read
++ *
++ */
++static int xnandps_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_required, int page)
++{
++ unsigned long data_width = 4;
++ unsigned long data_phase_addr = 0;
++ uint8_t *p;
++
++ chip->read_buf(mtd, buf, mtd->writesize);
++
++ p = chip->oob_poi;
++ chip->read_buf(mtd, p, (mtd->oobsize - data_width));
++ p += (mtd->oobsize - data_width);
++
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
++ data_phase_addr |= XNANDPS_CLEAR_CS;
++ chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
++
++ chip->read_buf(mtd, p, data_width);
++ return 0;
++}
++
++/**
++ * xnandps_write_page_raw - [Intern] raw page write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ *
++ */
++static int xnandps_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int oob_required)
++{
++ unsigned long data_width = 4;
++ unsigned long data_phase_addr = 0;
++ uint8_t *p;
++
++ chip->write_buf(mtd, buf, mtd->writesize);
++
++ p = chip->oob_poi;
++ chip->write_buf(mtd, p, (mtd->oobsize - data_width));
++ p += (mtd->oobsize - data_width);
++
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
++ data_phase_addr |= XNANDPS_CLEAR_CS;
++ data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
++ chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
++
++ chip->write_buf(mtd, p, data_width);
++
++ return 0;
++}
++
++/**
++ * nand_write_page_hwecc - Hardware ECC based page write function
++ * @mtd: Pointer to the mtd info structure
++ * @chip: Pointer to the NAND chip info structure
++ * @buf: Pointer to the data buffer
++ *
++ * This functions writes data and hardware generated ECC values in to the page.
++ */
++static int xnandps_write_page_hwecc(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf, int oob_required)
++{
++ int i, eccsize = chip->ecc.size;
++ int eccsteps = chip->ecc.steps;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
++ const uint8_t *p = buf;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ unsigned long data_phase_addr = 0;
++ unsigned long data_width = 4;
++ uint8_t *oob_ptr;
++
++ for (; (eccsteps - 1); eccsteps--) {
++ chip->write_buf(mtd, p, eccsize);
++ p += eccsize;
++ }
++ chip->write_buf(mtd, p, (eccsize - data_width));
++ p += (eccsize - data_width);
++
++ /* Set ECC Last bit to 1 */
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
++ data_phase_addr |= XNANDPS_ECC_LAST;
++ chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
++ chip->write_buf(mtd, p, data_width);
++
++ /* Wait for ECC to be calculated and read the error values */
++ p = buf;
++ chip->ecc.calculate(mtd, p, &ecc_calc[0]);
++
++ for (i = 0; i < chip->ecc.total; i++)
++ chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]);
++
++ /* Clear ECC last bit */
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
++ data_phase_addr &= ~XNANDPS_ECC_LAST;
++ chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
++
++ /* Write the spare area with ECC bytes */
++ oob_ptr = chip->oob_poi;
++ chip->write_buf(mtd, oob_ptr, (mtd->oobsize - data_width));
++
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
++ data_phase_addr |= XNANDPS_CLEAR_CS;
++ data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
++ chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
++ oob_ptr += (mtd->oobsize - data_width);
++ chip->write_buf(mtd, oob_ptr, data_width);
++
++ return 0;
++}
++
++/**
++ * xnandps_write_page_swecc - [REPLACABLE] software ecc based page write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ */
++static int xnandps_write_page_swecc(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf, int oob_required)
++{
++ int i, eccsize = chip->ecc.size;
++ int eccbytes = chip->ecc.bytes;
++ int eccsteps = chip->ecc.steps;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
++ const uint8_t *p = buf;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++
++ /* Software ecc calculation */
++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
++ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++ for (i = 0; i < chip->ecc.total; i++)
++ chip->oob_poi[eccpos[i]] = ecc_calc[i];
++
++ chip->ecc.write_page_raw(mtd, chip, buf, 1);
++
++ return 0;
++}
++
++/**
++ * xnandps_read_page_hwecc - Hardware ECC based page read function
++ * @mtd: Pointer to the mtd info structure
++ * @chip: Pointer to the NAND chip info structure
++ * @buf: Pointer to the buffer to store read data
++ * @page: page number to read
++ *
++ * This functions reads data and checks the data integrity by comparing hardware
++ * generated ECC values and read ECC values from spare area.
++ *
++ * returns: 0 always and updates ECC operation status in to MTD structure
++ */
++static int xnandps_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_required, int page)
++{
++ int i, stat, eccsize = chip->ecc.size;
++ int eccbytes = chip->ecc.bytes;
++ int eccsteps = chip->ecc.steps;
++ uint8_t *p = buf;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
++ uint8_t *ecc_code = chip->buffers->ecccode;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ unsigned long data_phase_addr = 0;
++ unsigned long data_width = 4;
++ uint8_t *oob_ptr;
++
++ for (; (eccsteps - 1); eccsteps--) {
++ chip->read_buf(mtd, p, eccsize);
++ p += eccsize;
++ }
++ chip->read_buf(mtd, p, (eccsize - data_width));
++ p += (eccsize - data_width);
++
++ /* Set ECC Last bit to 1 */
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
++ data_phase_addr |= XNANDPS_ECC_LAST;
++ chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
++ chip->read_buf(mtd, p, data_width);
++
++ /* Read the calculated ECC value */
++ p = buf;
++ chip->ecc.calculate(mtd, p, &ecc_calc[0]);
++
++ /* Clear ECC last bit */
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
++ data_phase_addr &= ~XNANDPS_ECC_LAST;
++ chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
++
++ /* Read the stored ECC value */
++ oob_ptr = chip->oob_poi;
++ chip->read_buf(mtd, oob_ptr, (mtd->oobsize - data_width));
++
++ /* de-assert chip select */
++ data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
++ data_phase_addr |= XNANDPS_CLEAR_CS;
++ chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
++
++ oob_ptr += (mtd->oobsize - data_width);
++ chip->read_buf(mtd, oob_ptr, data_width);
++
++ for (i = 0; i < chip->ecc.total; i++)
++ ecc_code[i] = ~(chip->oob_poi[eccpos[i]]);
++
++ eccsteps = chip->ecc.steps;
++ p = buf;
++
++ /* Check ECC error for all blocks and correct if it is correctable */
++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
++ if (stat < 0)
++ mtd->ecc_stats.failed++;
++ else
++ mtd->ecc_stats.corrected += stat;
++ }
++ return 0;
++}
++
++/**
++ * xnandps_read_page_swecc - [REPLACABLE] software ecc based page read function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @page: page number to read
++ */
++static int xnandps_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_required, int page)
++{
++ int i, eccsize = chip->ecc.size;
++ int eccbytes = chip->ecc.bytes;
++ int eccsteps = chip->ecc.steps;
++ uint8_t *p = buf;
++ uint8_t *ecc_calc = chip->buffers->ecccalc;
++ uint8_t *ecc_code = chip->buffers->ecccode;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++
++ chip->ecc.read_page_raw(mtd, chip, buf, page, 1);
++
++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
++ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++ for (i = 0; i < chip->ecc.total; i++)
++ ecc_code[i] = chip->oob_poi[eccpos[i]];
++
++ eccsteps = chip->ecc.steps;
++ p = buf;
++
++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
++ int stat;
++
++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
++ if (stat < 0)
++ mtd->ecc_stats.failed++;
++ else
++ mtd->ecc_stats.corrected += stat;
++ }
++ return 0;
++}
++
++/**
++ * xnandps_select_chip - Select the flash device
++ * @mtd: Pointer to the mtd_info structure
++ * @chip: Chip number to be selected
++ *
++ * This function is empty as the NAND controller handles chip select line
++ * internally based on the chip address passed in command and data phase.
++ **/
++static void xnandps_select_chip(struct mtd_info *mtd, int chip)
++{
++ return;
++}
++
++/**
++ * xnandps_cmd_function - Send command to NAND device
++ * @mtd: Pointer to the mtd_info structure
++ * @command: The command to be sent to the flash device
++ * @column: The column address for this command, -1 if none
++ * @page_addr: The page address for this command, -1 if none
++ */
++static void xnandps_cmd_function(struct mtd_info *mtd, unsigned int command,
++ int column, int page_addr)
++{
++ struct nand_chip *chip = mtd->priv;
++ const struct xnandps_command_format *curr_cmd = NULL;
++ struct xnandps_info *xnand =
++ container_of(mtd, struct xnandps_info, mtd);
++ void __iomem *cmd_addr;
++ unsigned long cmd_data = 0;
++ unsigned long cmd_phase_addr = 0;
++ unsigned long data_phase_addr = 0;
++ unsigned long end_cmd = 0;
++ unsigned long end_cmd_valid = 0;
++ unsigned long i;
++
++ if (xnand->end_cmd_pending) {
++ /* Check for end command if this command request is same as the
++ * pending command then return */
++ if (xnand->end_cmd == command) {
++ xnand->end_cmd = 0;
++ xnand->end_cmd_pending = 0;
++ return;
++ }
++ }
++
++ /* Emulate NAND_CMD_READOOB for large page device */
++ if ((mtd->writesize > XNANDPS_ECC_SIZE) &&
++ (command == NAND_CMD_READOOB)) {
++ column += mtd->writesize;
++ command = NAND_CMD_READ0;
++ }
++
++ /* Get the command format */
++ for (i = 0; (xnandps_commands[i].start_cmd != NAND_CMD_NONE ||
++ xnandps_commands[i].end_cmd != NAND_CMD_NONE); i++) {
++ if (command == xnandps_commands[i].start_cmd)
++ curr_cmd = &xnandps_commands[i];
++ }
++
++ if (curr_cmd == NULL)
++ return;
++
++ /* Clear interrupt */
++ xsmcps_clr_nand_int();
++
++ /* Get the command phase address */
++ if (curr_cmd->end_cmd_valid == XNANDPS_CMD_PHASE)
++ end_cmd_valid = 1;
++
++ if (curr_cmd->end_cmd == NAND_CMD_NONE)
++ end_cmd = 0x0;
++ else
++ end_cmd = curr_cmd->end_cmd;
++
++ cmd_phase_addr = (unsigned long __force)xnand->nand_base |
++ (curr_cmd->addr_cycles << ADDR_CYCLES_SHIFT) |
++ (end_cmd_valid << END_CMD_VALID_SHIFT) |
++ (COMMAND_PHASE) |
++ (end_cmd << END_CMD_SHIFT) |
++ (curr_cmd->start_cmd << START_CMD_SHIFT);
++
++ cmd_addr = (void __iomem * __force)cmd_phase_addr;
++
++ /* Get the data phase address */
++ end_cmd_valid = 0;
++
++ data_phase_addr = (unsigned long __force)xnand->nand_base |
++ (0x0 << CLEAR_CS_SHIFT) |
++ (end_cmd_valid << END_CMD_VALID_SHIFT) |
++ (DATA_PHASE) |
++ (end_cmd << END_CMD_SHIFT) |
++ (0x0 << ECC_LAST_SHIFT);
++
++ chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
++ chip->IO_ADDR_W = chip->IO_ADDR_R;
++
++ /* Command phase AXI write */
++ /* Read & Write */
++ if (column != -1 && page_addr != -1) {
++ /* Adjust columns for 16 bit bus width */
++ if (chip->options & NAND_BUSWIDTH_16)
++ column >>= 1;
++ cmd_data = column;
++ if (mtd->writesize > XNANDPS_ECC_SIZE) {
++ cmd_data |= page_addr << 16;
++ /* Another address cycle for devices > 128MiB */
++ if (chip->chipsize > (128 << 20)) {
++ xnandps_write32(cmd_addr, cmd_data);
++ cmd_data = (page_addr >> 16);
++ }
++ } else {
++ cmd_data |= page_addr << 8;
++ }
++ } else if (page_addr != -1) {
++ /* Erase */
++ cmd_data = page_addr;
++ } else if (column != -1) {
++ /* Change read/write column, read id etc */
++ /* Adjust columns for 16 bit bus width */
++ if ((chip->options & NAND_BUSWIDTH_16) &&
++ ((command == NAND_CMD_READ0) ||
++ (command == NAND_CMD_SEQIN) ||
++ (command == NAND_CMD_RNDOUT) ||
++ (command == NAND_CMD_RNDIN)))
++ column >>= 1;
++ cmd_data = column;
++ }
++
++ xnandps_write32(cmd_addr, cmd_data);
++
++ if (curr_cmd->end_cmd_valid) {
++ xnand->end_cmd = curr_cmd->end_cmd;
++ xnand->end_cmd_pending = 1;
++ }
++
++ ndelay(100);
++
++ if ((command == NAND_CMD_READ0) ||
++ (command == NAND_CMD_RESET) ||
++ (command == NAND_CMD_PARAM) ||
++ (command == NAND_CMD_GET_FEATURES)) {
++
++ while (!chip->dev_ready(mtd))
++ ;
++ return;
++ }
++}
++
++/**
++ * xnandps_read_buf - read chip data into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ *
++ */
++static void xnandps_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++ int i;
++ struct nand_chip *chip = mtd->priv;
++ unsigned long *ptr = (unsigned long *)buf;
++
++ len >>= 2;
++ for (i = 0; i < len; i++)
++ ptr[i] = readl(chip->IO_ADDR_R);
++}
++
++/**
++ * xnandps_write_buf - write buffer to chip
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ *
++ */
++static void xnandps_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++ int i;
++ struct nand_chip *chip = mtd->priv;
++ unsigned long *ptr = (unsigned long *)buf;
++ len >>= 2;
++
++ for (i = 0; i < len; i++)
++ writel(ptr[i], chip->IO_ADDR_W);
++}
++
++/**
++ * xnandps_device_ready - Check device ready/busy line
++ * @mtd: Pointer to the mtd_info structure
++ *
++ * returns: 0 on busy or 1 on ready state
++ **/
++static int xnandps_device_ready(struct mtd_info *mtd)
++{
++ if (xsmcps_get_nand_int_status_raw()) {
++ xsmcps_clr_nand_int();
++ return 1;
++ }
++ return 0;
++}
++
++/**
++ * xnandps_probe - Probe method for the NAND driver
++ * @pdev: Pointer to the platform_device structure
++ *
++ * This function initializes the driver data structures and the hardware.
++ *
++ * returns: 0 on success or error value on failure
++ **/
++static int xnandps_probe(struct platform_device *pdev)
++{
++ struct xnandps_info *xnand;
++ struct mtd_info *mtd;
++ struct nand_chip *nand_chip;
++ struct resource *nand_res;
++ u8 maf_id, dev_id, i;
++ u8 get_feature;
++ u8 set_feature[4] = {0x08, 0x00, 0x00, 0x00};
++ int ondie_ecc_enabled = 0;
++ struct mtd_part_parser_data ppdata;
++ const unsigned int *prop;
++ u32 options = 0;
++
++ xnand = devm_kzalloc(&pdev->dev, sizeof(struct xnandps_info),
++ GFP_KERNEL);
++ if (!xnand)
++ return -ENOMEM;
++
++ /* Map physical address of NAND flash */
++ nand_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ xnand->nand_base = devm_ioremap_resource(&pdev->dev, nand_res);
++ if (IS_ERR(xnand->nand_base)) {
++ dev_err(&pdev->dev, "ioremap for NAND failed\n");
++ return PTR_ERR(xnand->nand_base);
++ }
++
++ /* Get x8 or x16 mode from device tree */
++ prop = of_get_property(pdev->dev.of_node, "xlnx,nand-width", NULL);
++ if (prop) {
++ if (be32_to_cpup(prop) == 16) {
++ options |= NAND_BUSWIDTH_16;
++ } else if (be32_to_cpup(prop) == 8) {
++ options &= ~NAND_BUSWIDTH_16;
++ } else {
++ dev_info(&pdev->dev, "xlnx,nand-width not valid, using 8");
++ options &= ~NAND_BUSWIDTH_16;
++ }
++ } else {
++ dev_info(&pdev->dev, "xlnx,nand-width not in device tree, using 8");
++ options &= ~NAND_BUSWIDTH_16;
++ }
++
++ /* Link the private data with the MTD structure */
++ mtd = &xnand->mtd;
++ nand_chip = &xnand->chip;
++
++ nand_chip->priv = xnand;
++ mtd->priv = nand_chip;
++ mtd->owner = THIS_MODULE;
++ mtd->name = "xilinx_nand";
++
++ /* Set address of NAND IO lines */
++ nand_chip->IO_ADDR_R = xnand->nand_base;
++ nand_chip->IO_ADDR_W = xnand->nand_base;
++
++ /* Set the driver entry points for MTD */
++ nand_chip->cmdfunc = xnandps_cmd_function;
++ nand_chip->dev_ready = xnandps_device_ready;
++ nand_chip->select_chip = xnandps_select_chip;
++
++ /* If we don't set this delay driver sets 20us by default */
++ nand_chip->chip_delay = 30;
++
++ /* Buffer read/write routines */
++ nand_chip->read_buf = xnandps_read_buf;
++ nand_chip->write_buf = xnandps_write_buf;
++
++ /* Set the device option and flash width */
++ nand_chip->options = options;
++ nand_chip->bbt_options = NAND_BBT_USE_FLASH;
++
++ platform_set_drvdata(pdev, xnand);
++
++ /* first scan to find the device and get the page size */
++ if (nand_scan_ident(mtd, 1, NULL)) {
++ dev_err(&pdev->dev, "nand_scan_ident for NAND failed\n");
++ return -ENXIO;
++ }
++
++ /* Check if On-Die ECC flash */
++ nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++ nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
++
++ /* Read manufacturer and device IDs */
++ maf_id = nand_chip->read_byte(mtd);
++ dev_id = nand_chip->read_byte(mtd);
++
++ if ((maf_id == 0x2c) &&
++ ((dev_id == 0xf1) || (dev_id == 0xa1) ||
++ (dev_id == 0xb1) ||
++ (dev_id == 0xaa) || (dev_id == 0xba) ||
++ (dev_id == 0xda) || (dev_id == 0xca) ||
++ (dev_id == 0xac) || (dev_id == 0xbc) ||
++ (dev_id == 0xdc) || (dev_id == 0xcc) ||
++ (dev_id == 0xa3) || (dev_id == 0xb3) ||
++ (dev_id == 0xd3) || (dev_id == 0xc3))) {
++
++ nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
++ ONDIE_ECC_FEATURE_ADDR, -1);
++ get_feature = nand_chip->read_byte(mtd);
++
++ if (get_feature & 0x08) {
++ ondie_ecc_enabled = 1;
++ } else {
++ nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
++ ONDIE_ECC_FEATURE_ADDR, -1);
++ for (i = 0; i < 4; i++)
++ writeb(set_feature[i], nand_chip->IO_ADDR_W);
++
++ ndelay(1000);
++
++ nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
++ ONDIE_ECC_FEATURE_ADDR, -1);
++ get_feature = nand_chip->read_byte(mtd);
++
++ if (get_feature & 0x08)
++ ondie_ecc_enabled = 1;
++ }
++ }
++
++ nand_chip->ecc.mode = NAND_ECC_HW;
++ nand_chip->ecc.read_oob = xnandps_read_oob;
++ nand_chip->ecc.read_page_raw = xnandps_read_page_raw;
++ nand_chip->ecc.strength = 1;
++ nand_chip->ecc.write_oob = xnandps_write_oob;
++ nand_chip->ecc.write_page_raw = xnandps_write_page_raw;
++ if (ondie_ecc_enabled) {
++ /* bypass the controller ECC block */
++ xsmcps_set_ecc_mode(XSMCPS_ECCMODE_BYPASS);
++
++ /* The software ECC routines won't work with the
++ SMC controller */
++ nand_chip->ecc.bytes = 0;
++ nand_chip->ecc.layout = &ondie_nand_oob_64;
++ nand_chip->ecc.read_page = xnandps_read_page_raw;
++ nand_chip->ecc.write_page = xnandps_write_page_raw;
++ nand_chip->ecc.size = mtd->writesize;
++ /* On-Die ECC spare bytes offset 8 is used for ECC codes */
++ /* Use the BBT pattern descriptors */
++ nand_chip->bbt_td = &bbt_main_descr;
++ nand_chip->bbt_md = &bbt_mirror_descr;
++ } else {
++ /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */
++ nand_chip->ecc.bytes = 3;
++ nand_chip->ecc.calculate = xnandps_calculate_hwecc;
++ nand_chip->ecc.correct = xnandps_correct_data;
++ nand_chip->ecc.hwctl = NULL;
++ nand_chip->ecc.read_page = xnandps_read_page_hwecc;
++ nand_chip->ecc.size = XNANDPS_ECC_SIZE;
++ nand_chip->ecc.write_page = xnandps_write_page_hwecc;
++
++ xsmcps_set_ecc_pg_size(mtd->writesize);
++ switch (mtd->writesize) {
++ case 512:
++ case 1024:
++ case 2048:
++ xsmcps_set_ecc_mode(XSMCPS_ECCMODE_APB);
++ break;
++ default:
++ /* The software ECC routines won't work with the
++ SMC controller */
++ nand_chip->ecc.calculate = nand_calculate_ecc;
++ nand_chip->ecc.correct = nand_correct_data;
++ nand_chip->ecc.read_page = xnandps_read_page_swecc;
++ /* nand_chip->ecc.read_subpage = nand_read_subpage; */
++ nand_chip->ecc.write_page = xnandps_write_page_swecc;
++ nand_chip->ecc.size = 256;
++ break;
++ }
++
++ if (mtd->oobsize == 16)
++ nand_chip->ecc.layout = &nand_oob_16;
++ else if (mtd->oobsize == 64)
++ nand_chip->ecc.layout = &nand_oob_64;
++ }
++
++ /* second phase scan */
++ if (nand_scan_tail(mtd)) {
++ dev_err(&pdev->dev, "nand_scan_tail for NAND failed\n");
++ return -ENXIO;
++ }
++
++ ppdata.of_node = pdev->dev.of_node;
++
++ mtd_device_parse_register(&xnand->mtd, NULL, &ppdata,
++ NULL, 0);
++
++ return 0;
++}
++
++/**
++ * xnandps_remove - Remove method for the NAND driver
++ * @pdev: Pointer to the platform_device structure
++ *
++ * This function is called if the driver module is being unloaded. It frees all
++ * resources allocated to the device.
++ *
++ * returns: 0 on success or error value on failure
++ **/
++static int xnandps_remove(struct platform_device *pdev)
++{
++ struct xnandps_info *xnand = platform_get_drvdata(pdev);
++
++ /* Release resources, unregister device */
++ nand_release(&xnand->mtd);
++ /* kfree(NULL) is safe */
++ kfree(xnand->parts);
++
++ return 0;
++}
++
++/* Match table for device tree binding */
++static const struct of_device_id xnandps_of_match[] = {
++ { .compatible = "xlnx,ps7-nand-1.00.a" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, xnandps_of_match);
++
++/*
++ * xnandps_driver - This structure defines the NAND subsystem platform driver
++ */
++static struct platform_driver xnandps_driver = {
++ .probe = xnandps_probe,
++ .remove = xnandps_remove,
++ .driver = {
++ .name = XNANDPS_DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = xnandps_of_match,
++ },
++};
++
++module_platform_driver(xnandps_driver);
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_ALIAS("platform:" XNANDPS_DRIVER_NAME);
++MODULE_DESCRIPTION("Xilinx PS NAND Flash Driver");
++MODULE_LICENSE("GPL");
diff --git a/patches.zynq/0008-watchdog-xilinx-merge-support-for-xilinx-watchdog.patch b/patches.zynq/0008-watchdog-xilinx-merge-support-for-xilinx-watchdog.patch
new file mode 100644
index 00000000000000..4e8af989cceb4a
--- /dev/null
+++ b/patches.zynq/0008-watchdog-xilinx-merge-support-for-xilinx-watchdog.patch
@@ -0,0 +1,619 @@
+From 55f1815cb899dc0bb48c250bf753c12ead069f27 Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Tue, 24 Dec 2013 09:22:35 +0900
+Subject: watchdog: xilinx: merge support for xilinx watchdog
+
+This merges support for the Xilinx watchdong from the Xilinx
+repository (commit efc27505715e64526653f35274717c0fc56491e3 in
+master branch). It has been tested by using the watchdog
+command.
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/watchdog/Kconfig | 11
+ drivers/watchdog/Makefile | 1
+ drivers/watchdog/of_xilinx_wdt.c | 1
+ drivers/watchdog/xilinx_wdtps.c | 545 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 557 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/watchdog/xilinx_wdtps.c
+
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -224,6 +224,7 @@ config DW_WATCHDOG
+ config MPCORE_WATCHDOG
+ tristate "MPcore watchdog"
+ depends on HAVE_ARM_TWD
++ select WATCHDOG_CORE
+ help
+ Watchdog timer embedded into the MPcore system.
+
+@@ -337,6 +338,14 @@ config NUC900_WATCHDOG
+ To compile this driver as a module, choose M here: the
+ module will be called nuc900_wdt.
+
++config XILINX_PS_WATCHDOG
++ tristate "Xilinx PS Watchdog Timer"
++ depends on ARCH_ZYNQ
++ select WATCHDOG_CORE
++ help
++ Say Y here if you want to include support for the watchdog
++ timer in the Xilinx PS.
++
+ config TS72XX_WATCHDOG
+ tristate "TS-72XX SBC Watchdog"
+ depends on MACH_TS72XX
+@@ -976,7 +985,7 @@ config M54xx_WATCHDOG
+
+ config XILINX_WATCHDOG
+ tristate "Xilinx Watchdog timer"
+- depends on MICROBLAZE
++ depends on MICROBLAZE || ARCH_ZYNQ
+ ---help---
+ Watchdog driver for the xps_timebase_wdt ip core.
+
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -50,6 +50,7 @@ obj-$(CONFIG_ORION_WATCHDOG) += orion_wd
+ obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
+ obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
+ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
++obj-$(CONFIG_XILINX_PS_WATCHDOG) += xilinx_wdtps.o
+ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
+ obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+ obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
+--- a/drivers/watchdog/of_xilinx_wdt.c
++++ b/drivers/watchdog/of_xilinx_wdt.c
+@@ -405,3 +405,4 @@ module_platform_driver(xwdt_driver);
+ MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
+ MODULE_DESCRIPTION("Xilinx Watchdog driver");
+ MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+--- /dev/null
++++ b/drivers/watchdog/xilinx_wdtps.c
+@@ -0,0 +1,545 @@
++/*
++ * Xilinx Zynq WDT driver
++ *
++ * Copyright (c) 2010-2013 Xilinx Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
++ * 02139, USA.
++ */
++
++#include <linux/clk.h>
++#include <linux/export.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/reboot.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/watchdog.h>
++
++#define XWDTPS_DEFAULT_TIMEOUT 10
++/* Supports 1 - 516 sec */
++#define XWDTPS_MIN_TIMEOUT 1
++#define XWDTPS_MAX_TIMEOUT 516
++
++static int wdt_timeout = XWDTPS_DEFAULT_TIMEOUT;
++static int nowayout = WATCHDOG_NOWAYOUT;
++
++module_param(wdt_timeout, int, 0);
++MODULE_PARM_DESC(wdt_timeout,
++ "Watchdog time in seconds. (default="
++ __MODULE_STRING(XWDTPS_DEFAULT_TIMEOUT) ")");
++
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout,
++ "Watchdog cannot be stopped once started (default="
++ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
++
++/**
++ * struct xwdtps - Watchdog device structure.
++ * @regs: baseaddress of device.
++ * @busy: flag for the device.
++ *
++ * Structure containing parameters specific to ps watchdog.
++ */
++struct xwdtps {
++ void __iomem *regs; /* Base address */
++ unsigned long busy; /* Device Status */
++ int rst; /* Reset flag */
++ struct clk *clk;
++ u32 prescalar;
++ u32 ctrl_clksel;
++ spinlock_t io_lock;
++};
++static struct xwdtps *wdt;
++
++/*
++ * Info structure used to indicate the features supported by the device
++ * to the upper layers. This is defined in watchdog.h header file.
++ */
++static struct watchdog_info xwdtps_info = {
++ .identity = "xwdtps watchdog",
++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
++ WDIOF_MAGICCLOSE,
++};
++
++/* Write access to Registers */
++#define xwdtps_writereg(val, offset) __raw_writel(val, (wdt->regs) + offset)
++
++/*************************Register Map**************************************/
++
++/* Register Offsets for the WDT */
++#define XWDTPS_ZMR_OFFSET 0x0 /* Zero Mode Register */
++#define XWDTPS_CCR_OFFSET 0x4 /* Counter Control Register */
++#define XWDTPS_RESTART_OFFSET 0x8 /* Restart Register */
++#define XWDTPS_SR_OFFSET 0xC /* Status Register */
++
++/*
++ * Zero Mode Register - This register controls how the time out is indicated
++ * and also contains the access code to allow writes to the register (0xABC).
++ */
++#define XWDTPS_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */
++#define XWDTPS_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */
++#define XWDTPS_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */
++#define XWDTPS_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */
++#define XWDTPS_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */
++/*
++ * Counter Control register - This register controls how fast the timer runs
++ * and the reset value and also contains the access code to allow writes to
++ * the register.
++ */
++#define XWDTPS_CCR_CRV_MASK 0x00003FFC /* Counter reset value */
++
++/**
++ * xwdtps_stop - Stop the watchdog.
++ *
++ * Read the contents of the ZMR register, clear the WDEN bit
++ * in the register and set the access key for successful write.
++ */
++static int xwdtps_stop(struct watchdog_device *wdd)
++{
++ spin_lock(&wdt->io_lock);
++ xwdtps_writereg((XWDTPS_ZMR_ZKEY_VAL & (~XWDTPS_ZMR_WDEN_MASK)),
++ XWDTPS_ZMR_OFFSET);
++ spin_unlock(&wdt->io_lock);
++ return 0;
++}
++
++/**
++ * xwdtps_reload - Reload the watchdog timer (i.e. pat the watchdog).
++ *
++ * Write the restart key value (0x00001999) to the restart register.
++ */
++static int xwdtps_reload(struct watchdog_device *wdd)
++{
++ spin_lock(&wdt->io_lock);
++ xwdtps_writereg(0x00001999, XWDTPS_RESTART_OFFSET);
++ spin_unlock(&wdt->io_lock);
++ return 0;
++}
++
++/**
++ * xwdtps_start - Enable and start the watchdog.
++ *
++ * The counter value is calculated according to the formula:
++ * calculated count = (timeout * clock) / prescalar + 1.
++ * The calculated count is divided by 0x1000 to obtain the field value
++ * to write to counter control register.
++ * Clears the contents of prescalar and counter reset value. Sets the
++ * prescalar to 4096 and the calculated count and access key
++ * to write to CCR Register.
++ * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit)
++ * or Interrupt signal(IRQEN) with a specified cycles and the access
++ * key to write to ZMR Register.
++ */
++static int xwdtps_start(struct watchdog_device *wdd)
++{
++ unsigned int data = 0;
++ unsigned short count;
++ unsigned long clock_f = clk_get_rate(wdt->clk);
++
++ /*
++ * 0x1000 - Counter Value Divide, to obtain the value of counter
++ * reset to write to control register.
++ */
++ count = (wdd->timeout * (clock_f / (wdt->prescalar))) / 0x1000 + 1;
++
++ /* Check for boundary conditions of counter value */
++ if (count > 0xFFF)
++ count = 0xFFF;
++
++ spin_lock(&wdt->io_lock);
++ xwdtps_writereg(XWDTPS_ZMR_ZKEY_VAL, XWDTPS_ZMR_OFFSET);
++
++ /* Shift the count value to correct bit positions */
++ count = (count << 2) & XWDTPS_CCR_CRV_MASK;
++
++ /* 0x00920000 - Counter register key value. */
++ data = (count | 0x00920000 | (wdt->ctrl_clksel));
++ xwdtps_writereg(data, XWDTPS_CCR_OFFSET);
++ data = XWDTPS_ZMR_WDEN_MASK | XWDTPS_ZMR_RSTLEN_16 |
++ XWDTPS_ZMR_ZKEY_VAL;
++
++ /* Reset on timeout if specified in device tree. */
++ if (wdt->rst) {
++ data |= XWDTPS_ZMR_RSTEN_MASK;
++ data &= ~XWDTPS_ZMR_IRQEN_MASK;
++ } else {
++ data &= ~XWDTPS_ZMR_RSTEN_MASK;
++ data |= XWDTPS_ZMR_IRQEN_MASK;
++ }
++ xwdtps_writereg(data, XWDTPS_ZMR_OFFSET);
++ spin_unlock(&wdt->io_lock);
++ xwdtps_writereg(0x00001999, XWDTPS_RESTART_OFFSET);
++ return 0;
++}
++
++/**
++ * xwdtps_settimeout - Set a new timeout value for the watchdog device.
++ *
++ * @new_time: new timeout value that needs to be set.
++ * Returns 0 on success.
++ *
++ * Update the watchdog_device timeout with new value which is used when
++ * xwdtps_start is called.
++ */
++static int xwdtps_settimeout(struct watchdog_device *wdd, unsigned int new_time)
++{
++ wdd->timeout = new_time;
++ return xwdtps_start(wdd);
++}
++
++/**
++ * xwdtps_irq_handler - Notifies of watchdog timeout.
++ *
++ * @irq: interrupt number
++ * @dev_id: pointer to a platform device structure
++ * Returns IRQ_HANDLED
++ *
++ * The handler is invoked when the watchdog times out and a
++ * reset on timeout has not been enabled.
++ */
++static irqreturn_t xwdtps_irq_handler(int irq, void *dev_id)
++{
++ struct platform_device *pdev = dev_id;
++ dev_info(&pdev->dev, "Watchdog timed out.\n");
++ return IRQ_HANDLED;
++}
++
++/* Watchdog Core Ops */
++static struct watchdog_ops xwdtps_ops = {
++ .owner = THIS_MODULE,
++ .start = xwdtps_start,
++ .stop = xwdtps_stop,
++ .ping = xwdtps_reload,
++ .set_timeout = xwdtps_settimeout,
++};
++
++/* Watchdog Core Device */
++static struct watchdog_device xwdtps_device = {
++ .info = &xwdtps_info,
++ .ops = &xwdtps_ops,
++ .timeout = XWDTPS_DEFAULT_TIMEOUT,
++ .min_timeout = XWDTPS_MIN_TIMEOUT,
++ .max_timeout = XWDTPS_MAX_TIMEOUT,
++};
++
++/**
++ * xwdtps_notify_sys - Notifier for reboot or shutdown.
++ *
++ * @this: handle to notifier block.
++ * @code: turn off indicator.
++ * @unused: unused.
++ * Returns NOTIFY_DONE.
++ *
++ * This notifier is invoked whenever the system reboot or shutdown occur
++ * because we need to disable the WDT before system goes down as WDT might
++ * reset on the next boot.
++ */
++static int xwdtps_notify_sys(struct notifier_block *this, unsigned long code,
++ void *unused)
++{
++ if (code == SYS_DOWN || code == SYS_HALT)
++ /* Stop the watchdog */
++ xwdtps_stop(&xwdtps_device);
++ return NOTIFY_DONE;
++}
++
++/* Notifier Structure */
++static struct notifier_block xwdtps_notifier = {
++ .notifier_call = xwdtps_notify_sys,
++};
++
++/************************Platform Operations*****************************/
++/**
++ * xwdtps_probe - Probe call for the device.
++ *
++ * @pdev: handle to the platform device structure.
++ * Returns 0 on success, negative error otherwise.
++ *
++ * It does all the memory allocation and registration for the device.
++ */
++static int xwdtps_probe(struct platform_device *pdev)
++{
++ struct resource *regs;
++ int res;
++ const void *prop;
++ int irq;
++ unsigned long clock_f;
++
++ /* Check whether WDT is in use, just for safety */
++ if (wdt) {
++ dev_err(&pdev->dev,
++ "Device Busy, only 1 xwdtps instance supported.\n");
++ return -EBUSY;
++ }
++
++ /* Get the device base address */
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs) {
++ dev_err(&pdev->dev, "Unable to locate mmio resource\n");
++ return -ENODEV;
++ }
++
++ /* Allocate an instance of the xwdtps structure */
++ wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
++ if (!wdt) {
++ dev_err(&pdev->dev, "No memory for wdt structure\n");
++ return -ENOMEM;
++ }
++
++ wdt->regs = ioremap(regs->start, regs->end - regs->start + 1);
++ if (!wdt->regs) {
++ res = -ENOMEM;
++ dev_err(&pdev->dev, "Could not map I/O memory\n");
++ goto err_free;
++ }
++
++ /* Register the reboot notifier */
++ res = register_reboot_notifier(&xwdtps_notifier);
++ if (res != 0) {
++ dev_err(&pdev->dev, "cannot register reboot notifier err=%d)\n",
++ res);
++ goto err_iounmap;
++ }
++
++ /* Register the interrupt */
++ prop = of_get_property(pdev->dev.of_node, "reset", NULL);
++ wdt->rst = prop ? be32_to_cpup(prop) : 0;
++ irq = platform_get_irq(pdev, 0);
++ if (!wdt->rst && irq >= 0) {
++ res = request_irq(irq, xwdtps_irq_handler, 0, pdev->name, pdev);
++ if (res) {
++ dev_err(&pdev->dev,
++ "cannot register interrupt handler err=%d\n",
++ res);
++ goto err_notifier;
++ }
++ }
++
++ /* Initialize the members of xwdtps structure */
++ xwdtps_device.parent = &pdev->dev;
++ prop = of_get_property(pdev->dev.of_node, "timeout", NULL);
++ if (prop) {
++ xwdtps_device.timeout = be32_to_cpup(prop);
++ } else if (wdt_timeout < XWDTPS_MAX_TIMEOUT &&
++ wdt_timeout > XWDTPS_MIN_TIMEOUT) {
++ xwdtps_device.timeout = wdt_timeout;
++ } else {
++ dev_info(&pdev->dev,
++ "timeout limited to 1 - %d sec, using default=%d\n",
++ XWDTPS_MAX_TIMEOUT, XWDTPS_DEFAULT_TIMEOUT);
++ xwdtps_device.timeout = XWDTPS_DEFAULT_TIMEOUT;
++ }
++
++ watchdog_set_nowayout(&xwdtps_device, nowayout);
++ watchdog_set_drvdata(&xwdtps_device, &wdt);
++
++ wdt->clk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(wdt->clk)) {
++ dev_err(&pdev->dev, "input clock not found\n");
++ res = PTR_ERR(wdt->clk);
++ goto err_irq;
++ }
++
++ res = clk_prepare_enable(wdt->clk);
++ if (res) {
++ dev_err(&pdev->dev, "unable to enable clock\n");
++ goto err_clk_put;
++ }
++
++ clock_f = clk_get_rate(wdt->clk);
++ if (clock_f <= 10000000) {/* For PEEP */
++ wdt->prescalar = 64;
++ wdt->ctrl_clksel = 1;
++ } else if (clock_f <= 75000000) {
++ wdt->prescalar = 256;
++ wdt->ctrl_clksel = 2;
++ } else { /* For Zynq */
++ wdt->prescalar = 4096;
++ wdt->ctrl_clksel = 3;
++ }
++
++ /* Initialize the busy flag to zero */
++ clear_bit(0, &wdt->busy);
++ spin_lock_init(&wdt->io_lock);
++
++ /* Register the WDT */
++ res = watchdog_register_device(&xwdtps_device);
++ if (res) {
++ dev_err(&pdev->dev, "Failed to register wdt device\n");
++ goto err_clk_disable;
++ }
++ platform_set_drvdata(pdev, wdt);
++
++ dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",
++ wdt->regs, xwdtps_device.timeout, nowayout ? ", nowayout" : "");
++
++ return 0;
++
++err_clk_disable:
++ clk_disable_unprepare(wdt->clk);
++err_clk_put:
++ clk_put(wdt->clk);
++err_irq:
++ free_irq(irq, pdev);
++err_notifier:
++ unregister_reboot_notifier(&xwdtps_notifier);
++err_iounmap:
++ iounmap(wdt->regs);
++err_free:
++ kfree(wdt);
++ wdt = NULL;
++ return res;
++}
++
++/**
++ * xwdtps_remove - Probe call for the device.
++ *
++ * @pdev: handle to the platform device structure.
++ * Returns 0 on success, otherwise negative error.
++ *
++ * Unregister the device after releasing the resources.
++ * Stop is allowed only when nowayout is disabled.
++ */
++static int __exit xwdtps_remove(struct platform_device *pdev)
++{
++ int res = 0;
++ int irq;
++
++ if (wdt && !nowayout) {
++ xwdtps_stop(&xwdtps_device);
++ watchdog_unregister_device(&xwdtps_device);
++ unregister_reboot_notifier(&xwdtps_notifier);
++ irq = platform_get_irq(pdev, 0);
++ free_irq(irq, pdev);
++ iounmap(wdt->regs);
++ clk_disable_unprepare(wdt->clk);
++ clk_put(wdt->clk);
++ kfree(wdt);
++ wdt = NULL;
++ platform_set_drvdata(pdev, NULL);
++ } else {
++ dev_err(&pdev->dev, "Cannot stop watchdog, still ticking\n");
++ return -ENOTSUPP;
++ }
++ return res;
++}
++
++/**
++ * xwdtps_shutdown - Stop the device.
++ *
++ * @pdev: handle to the platform structure.
++ *
++ */
++static void xwdtps_shutdown(struct platform_device *pdev)
++{
++ /* Stop the device */
++ xwdtps_stop(&xwdtps_device);
++ clk_disable_unprepare(wdt->clk);
++ clk_put(wdt->clk);
++}
++
++#ifdef CONFIG_PM_SLEEP
++/**
++ * xwdtps_suspend - Stop the device.
++ *
++ * @dev: handle to the device structure.
++ * Returns 0 always.
++ */
++static int xwdtps_suspend(struct device *dev)
++{
++ /* Stop the device */
++ xwdtps_stop(&xwdtps_device);
++ clk_disable(wdt->clk);
++ return 0;
++}
++
++/**
++ * xwdtps_resume - Resume the device.
++ *
++ * @dev: handle to the device structure.
++ * Returns 0 on success, errno otherwise.
++ */
++static int xwdtps_resume(struct device *dev)
++{
++ int ret;
++
++ ret = clk_enable(wdt->clk);
++ if (ret) {
++ dev_err(dev, "unable to enable clock\n");
++ return ret;
++ }
++ /* Start the device */
++ xwdtps_start(&xwdtps_device);
++ return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(xwdtps_pm_ops, xwdtps_suspend, xwdtps_resume);
++
++static struct of_device_id xwdtps_of_match[] = {
++ { .compatible = "xlnx,ps7-wdt-1.00.a", },
++ { /* end of table */}
++};
++MODULE_DEVICE_TABLE(of, xwdtps_of_match);
++
++/* Driver Structure */
++static struct platform_driver xwdtps_driver = {
++ .probe = xwdtps_probe,
++ .remove = xwdtps_remove,
++ .shutdown = xwdtps_shutdown,
++ .driver = {
++ .name = "xwdtps",
++ .owner = THIS_MODULE,
++ .of_match_table = xwdtps_of_match,
++ .pm = &xwdtps_pm_ops,
++ },
++};
++
++/**
++ * xwdtps_init - Register the WDT.
++ *
++ * Returns 0 on success, otherwise negative error.
++ *
++ * If using noway out, the use count will be incremented.
++ * This will prevent unloading the module. An attempt to
++ * unload the module will result in a warning from the kernel.
++ */
++static int __init xwdtps_init(void)
++{
++ int res = platform_driver_register(&xwdtps_driver);
++ if (!res && nowayout)
++ try_module_get(THIS_MODULE);
++ return res;
++}
++
++/**
++ * xwdtps_exit - Unregister the WDT.
++ */
++static void __exit xwdtps_exit(void)
++{
++ platform_driver_unregister(&xwdtps_driver);
++}
++
++module_init(xwdtps_init);
++module_exit(xwdtps_exit);
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_DESCRIPTION("Watchdog driver for PS WDT");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform: xwdtps");
diff --git a/patches.zynq/0009-usb-zynq-merge-usb-support-for-xilinx-zynq-soc.patch b/patches.zynq/0009-usb-zynq-merge-usb-support-for-xilinx-zynq-soc.patch
new file mode 100644
index 00000000000000..bef62e715c2b07
--- /dev/null
+++ b/patches.zynq/0009-usb-zynq-merge-usb-support-for-xilinx-zynq-soc.patch
@@ -0,0 +1,3821 @@
+From 485381435a50c8de2cee2720cee12434437a9354 Mon Sep 17 00:00:00 2001
+From: Michal Simek <michal.simek@xilinx.com>
+Date: Tue, 24 Dec 2013 09:27:30 +0900
+Subject: usb: zynq: merge usb support for xilinx zynq soc
+
+This merges support for the Zynq's USB from the Xilinx repository
+(commit efc27505715e64526653f35274717c0fc56491e3 in master branch).
+It has been tested by connecting a USB storage device into a
+Zynq 702 board.
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/usb/Kconfig | 1
+ drivers/usb/core/hub.c | 4
+ drivers/usb/host/Kconfig | 15
+ drivers/usb/host/Makefile | 1
+ drivers/usb/host/ehci-hcd.c | 52
+ drivers/usb/host/ehci-hub.c | 22
+ drivers/usb/host/ehci-xilinx-of.c | 17
+ drivers/usb/host/ehci-xilinx-usbps.c | 531 ++++++++
+ drivers/usb/host/ehci-xilinx-usbps.h | 33
+ drivers/usb/host/ehci.h | 8
+ drivers/usb/host/xusbps-dr-of.c | 331 +++++
+ drivers/usb/phy/Kconfig | 12
+ drivers/usb/phy/Makefile | 1
+ drivers/usb/phy/phy-zynq-usb.c | 2305 +++++++++++++++++++++++++++++++++++
+ include/linux/usb/xilinx_usbps_otg.h | 216 +++
+ include/linux/xilinx_devices.h | 70 +
+ 16 files changed, 3617 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/usb/host/ehci-xilinx-usbps.c
+ create mode 100644 drivers/usb/host/ehci-xilinx-usbps.h
+ create mode 100644 drivers/usb/host/xusbps-dr-of.c
+ create mode 100644 drivers/usb/phy/phy-zynq-usb.c
+ create mode 100644 include/linux/usb/xilinx_usbps_otg.h
+ create mode 100644 include/linux/xilinx_devices.h
+
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -45,6 +45,7 @@ config USB_ARCH_HAS_EHCI
+ default y if PLAT_S5P
+ default y if ARCH_MSM
+ default y if MICROBLAZE
++ default y if ARCH_ZYNQ
+ default y if SPARC_LEON
+ default y if ARCH_MMP
+ default y if MACH_LOONGSON1
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -1685,7 +1685,11 @@ static int hub_probe(struct usb_interfac
+ pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
+
+ /* Hubs have proper suspend/resume support. */
++#ifdef CONFIG_USB_ZYNQ_PHY
++ usb_disable_autosuspend(hdev);
++#else
+ usb_enable_autosuspend(hdev);
++#endif
+
+ if (hdev->level == MAX_TOPO_LEVEL) {
+ dev_err(&intf->dev,
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -132,6 +132,21 @@ config XPS_USB_HCD_XILINX
+ support both high speed and full speed devices, or high speed
+ devices only.
+
++config USB_XUSBPS_DR_OF
++ tristate
++ select USB_PHY
++ select USB_ULPI
++ select USB_ULPI_VIEWPORT
++
++config USB_EHCI_XUSBPS
++ bool "Support for Xilinx PS EHCI USB controller"
++ depends on USB_EHCI_HCD && ARCH_ZYNQ
++ select USB_EHCI_ROOT_HUB_TT
++ select USB_XUSBPS_DR_OF
++ ---help---
++ Xilinx PS USB host controller core is EHCI compilant and has
++ transaction translator built-in.
++
+ config USB_EHCI_FSL
+ bool "Support for Freescale PPC on-chip EHCI USB controller"
+ depends on FSL_SOC
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -49,6 +49,7 @@ obj-$(CONFIG_USB_ISP1760_HCD) += isp1760
+ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
+ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
+ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
++obj-$(CONFIG_USB_XUSBPS_DR_OF) += xusbps-dr-of.o
+ obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
+ obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
+ obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -335,11 +335,21 @@ static void ehci_turn_off_all_ports(stru
+ */
+ static void ehci_silence_controller(struct ehci_hcd *ehci)
+ {
++#ifdef CONFIG_USB_ZYNQ_PHY
++ struct usb_hcd *hcd = ehci_to_hcd(ehci);
++#endif
++
+ ehci_halt(ehci);
+
+ spin_lock_irq(&ehci->lock);
+ ehci->rh_state = EHCI_RH_HALTED;
++#ifdef CONFIG_USB_ZYNQ_PHY
++ /* turn off for non-otg port */
++ if (!hcd->phy)
++ ehci_turn_off_all_ports(ehci);
++#else
+ ehci_turn_off_all_ports(ehci);
++#endif
+
+ /* make BIOS/etc use companion controller during reboot */
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+@@ -422,7 +432,12 @@ static void ehci_stop (struct usb_hcd *h
+
+ ehci_quiesce(ehci);
+ ehci_silence_controller(ehci);
++#ifdef CONFIG_USB_ZYNQ_PHY
++ if (!hcd->phy)
++ ehci_reset(ehci);
++#else
+ ehci_reset (ehci);
++#endif
+
+ hrtimer_cancel(&ehci->hrtimer);
+ remove_sysfs_files(ehci);
+@@ -569,6 +584,9 @@ static int ehci_run (struct usb_hcd *hcd
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+ u32 temp;
+ u32 hcc_params;
++#if defined(CONFIG_ARCH_ZYNQ)
++ void __iomem *non_ehci = hcd->regs;
++#endif
+
+ hcd->uses_new_polling = 1;
+
+@@ -638,7 +656,11 @@ static int ehci_run (struct usb_hcd *hcd
+
+ ehci_writel(ehci, INTR_MASK,
+ &ehci->regs->intr_enable); /* Turn On Interrupts */
+-
++#if defined(CONFIG_ARCH_ZYNQ)
++ /* Modifying FIFO Burst Threshold value from 2 to 8 */
++ temp = readl(non_ehci + 0x164);
++ ehci_writel(ehci, 0x00080000, non_ehci + 0x164);
++#endif
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+ * since the class device isn't created that early.
+@@ -691,6 +713,29 @@ static irqreturn_t ehci_irq (struct usb_
+
+ status = ehci_readl(ehci, &ehci->regs->status);
+
++#ifdef CONFIG_USB_ZYNQ_PHY
++ if (hcd->phy) {
++ /* A device */
++ if (hcd->phy->otg->default_a &&
++ (hcd->phy->state == OTG_STATE_A_PERIPHERAL)) {
++ spin_unlock(&ehci->lock);
++ return IRQ_NONE;
++ }
++ /* B device */
++ if (!hcd->phy->otg->default_a &&
++ ((hcd->phy->state != OTG_STATE_B_WAIT_ACON) &&
++ (hcd->phy->state != OTG_STATE_B_HOST))) {
++ spin_unlock(&ehci->lock);
++ return IRQ_NONE;
++ }
++ /* If HABA is set and B-disconnect occurs, don't process
++ * that interrupt */
++ if (ehci_is_TDI(ehci) && tdi_in_host_mode(ehci) == 0) {
++ spin_unlock(&ehci->lock);
++ return IRQ_NONE;
++ }
++ }
++#endif
+ /* e.g. cardbus physical eject */
+ if (status == ~(u32) 0) {
+ ehci_dbg (ehci, "device removed\n");
+@@ -1246,6 +1291,11 @@ MODULE_LICENSE ("GPL");
+ #define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
+ #endif
+
++#ifdef CONFIG_USB_EHCI_XUSBPS
++#include "ehci-xilinx-usbps.c"
++#define PLATFORM_DRIVER ehci_xusbps_driver
++#endif
++
+ #ifdef CONFIG_USB_W90X900_EHCI
+ #include "ehci-w90x900.c"
+ #define PLATFORM_DRIVER ehci_hcd_w90x900_driver
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -1018,9 +1018,22 @@ static int ehci_hub_control (
+ * Set appropriate bit thus could put phy into low power
+ * mode if we have hostpc feature
+ */
++#ifdef CONFIG_USB_ZYNQ_PHY
++ if (hcd->phy && (hcd->self.otg_port == (wIndex + 1))
++ && (hcd->self.b_hnp_enable ||
++ hcd->self.is_b_host))
++ ehci->start_hnp(ehci);
++ else {
++ temp &= ~PORT_WKCONN_E;
++ temp |= PORT_WKDISC_E | PORT_WKOC_E;
++ ehci_writel(ehci, temp | PORT_SUSPEND,
++ status_reg);
++ }
++#else
+ temp &= ~PORT_WKCONN_E;
+ temp |= PORT_WKDISC_E | PORT_WKOC_E;
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
++#endif
+ if (ehci->has_hostpc) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ msleep(5);/* 5ms for HCD enter low pwr mode */
+@@ -1036,9 +1049,18 @@ static int ehci_hub_control (
+ set_bit(wIndex, &ehci->suspended_ports);
+ break;
+ case USB_PORT_FEAT_POWER:
++#ifdef CONFIG_USB_ZYNQ_PHY
++ /* Check if otg is enabled */
++ if (!hcd->phy) {
++ if (HCS_PPC(ehci->hcs_params))
++ ehci_writel(ehci, temp | PORT_POWER,
++ status_reg);
++ }
++#else
+ if (HCS_PPC (ehci->hcs_params))
+ ehci_writel(ehci, temp | PORT_POWER,
+ status_reg);
++#endif
+ break;
+ case USB_PORT_FEAT_RESET:
+ if (temp & PORT_RESUME)
+--- a/drivers/usb/host/ehci-xilinx-of.c
++++ b/drivers/usb/host/ehci-xilinx-of.c
+@@ -220,6 +220,21 @@ static int ehci_hcd_xilinx_of_remove(str
+ return 0;
+ }
+
++/**
++ * ehci_hcd_xilinx_of_shutdown - shutdown the hcd
++ * @op: pointer to platform_device structure that is to be removed
++ *
++ * Properly shutdown the hcd, call driver's shutdown routine.
++ */
++static void ehci_hcd_xilinx_of_shutdown(struct platform_device *op)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(op);
++
++ if (hcd->driver->shutdown)
++ hcd->driver->shutdown(hcd);
++}
++
++
+ static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
+ {.compatible = "xlnx,xps-usb-host-1.00.a",},
+ {},
+@@ -229,7 +244,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_
+ static struct platform_driver ehci_hcd_xilinx_of_driver = {
+ .probe = ehci_hcd_xilinx_of_probe,
+ .remove = ehci_hcd_xilinx_of_remove,
+- .shutdown = usb_hcd_platform_shutdown,
++ .shutdown = ehci_hcd_xilinx_of_shutdown,
+ .driver = {
+ .name = "xilinx-of-ehci",
+ .owner = THIS_MODULE,
+--- /dev/null
++++ b/drivers/usb/host/ehci-xilinx-usbps.c
+@@ -0,0 +1,531 @@
++/*
++ * Xilinx PS USB Host Controller Driver.
++ *
++ * Copyright (C) 2011 Xilinx, Inc.
++ *
++ * This file is based on ehci-fsl.c file with few minor modifications
++ * to support Xilinx PS USB controller.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/platform_device.h>
++#include <linux/xilinx_devices.h>
++#include <linux/usb/otg.h>
++#include <linux/usb/xilinx_usbps_otg.h>
++
++#include "ehci-xilinx-usbps.h"
++
++#ifdef CONFIG_USB_ZYNQ_PHY
++/********************************************************************
++ * OTG related functions
++ ********************************************************************/
++static int ehci_xusbps_reinit(struct ehci_hcd *ehci);
++
++/* This connection event is useful when a OTG test device is connected.
++ In that case, the device connect notify event will not be generated
++ since the device will be suspended before complete enumeration.
++*/
++static int ehci_xusbps_update_device(struct usb_hcd *hcd, struct usb_device
++ *udev)
++{
++ struct xusbps_otg *xotg = xceiv_to_xotg(hcd->phy);
++
++ if (udev->portnum == hcd->self.otg_port) {
++ /* HNP test device */
++ if ((le16_to_cpu(udev->descriptor.idVendor) == 0x1a0a &&
++ le16_to_cpu(udev->descriptor.idProduct) == 0xbadd)) {
++ if (xotg->otg.otg->default_a == 1)
++ xotg->hsm.b_conn = 1;
++ else
++ xotg->hsm.a_conn = 1;
++ xusbps_update_transceiver();
++ }
++ }
++ return 0;
++}
++
++static void ehci_xusbps_start_hnp(struct ehci_hcd *ehci)
++{
++ const unsigned port = ehci_to_hcd(ehci)->self.otg_port - 1;
++ struct usb_hcd *hcd = ehci_to_hcd(ehci);
++ unsigned long flags;
++ u32 portsc;
++
++ local_irq_save(flags);
++ portsc = ehci_readl(ehci, &ehci->regs->port_status[port]);
++ portsc |= PORT_SUSPEND;
++ ehci_writel(ehci, portsc, &ehci->regs->port_status[port]);
++ local_irq_restore(flags);
++
++ otg_start_hnp(hcd->phy->otg);
++}
++
++static int ehci_xusbps_otg_start_host(struct usb_phy *otg)
++{
++ struct usb_hcd *hcd = bus_to_hcd(otg->otg->host);
++ struct xusbps_otg *xotg =
++ xceiv_to_xotg(hcd->phy);
++
++ usb_add_hcd(hcd, xotg->irq, IRQF_SHARED);
++ return 0;
++}
++
++static int ehci_xusbps_otg_stop_host(struct usb_phy *otg)
++{
++ struct usb_hcd *hcd = bus_to_hcd(otg->otg->host);
++
++ usb_remove_hcd(hcd);
++ return 0;
++}
++#endif
++
++static int xusbps_ehci_clk_notifier_cb(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++
++ switch (event) {
++ case PRE_RATE_CHANGE:
++ /* if a rate change is announced we need to check whether we can
++ * maintain the current frequency by changing the clock
++ * dividers.
++ */
++ /* fall through */
++ case POST_RATE_CHANGE:
++ return NOTIFY_OK;
++ case ABORT_RATE_CHANGE:
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
++/* configure so an HC device and id are always provided */
++/* always called with process context; sleeping is OK */
++
++/**
++ * usb_hcd_xusbps_probe - initialize XUSBPS-based HCDs
++ * @driver: Driver to be used for this HCD
++ * @pdev: USB Host Controller being probed
++ * Context: !in_interrupt()
++ *
++ * Allocates basic resources for this USB host controller.
++ *
++ */
++static int usb_hcd_xusbps_probe(const struct hc_driver *driver,
++ struct platform_device *pdev)
++{
++ struct xusbps_usb2_platform_data *pdata;
++ struct usb_hcd *hcd;
++ int irq;
++ int retval;
++
++ pr_debug("initializing XUSBPS-SOC USB Controller\n");
++
++ /* Need platform data for setup */
++ pdata = (struct xusbps_usb2_platform_data *)pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev,
++ "No platform data for %s.\n", dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++
++ /*
++ * This is a host mode driver, verify that we're supposed to be
++ * in host mode.
++ */
++ if (!((pdata->operating_mode == XUSBPS_USB2_DR_HOST) ||
++ (pdata->operating_mode == XUSBPS_USB2_MPH_HOST) ||
++ (pdata->operating_mode == XUSBPS_USB2_DR_OTG))) {
++ dev_err(&pdev->dev, "Non Host Mode configured for %s. Wrong \
++ driver linked.\n", dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++
++ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
++ if (!hcd) {
++ retval = -ENOMEM;
++ goto err1;
++ }
++
++ irq = pdata->irq;
++ hcd->regs = pdata->regs;
++
++ if (hcd->regs == NULL) {
++ dev_dbg(&pdev->dev, "error mapping memory\n");
++ retval = -EFAULT;
++ goto err2;
++ }
++
++ retval = clk_prepare_enable(pdata->clk);
++ if (retval) {
++ dev_err(&pdev->dev, "Unable to enable APER clock.\n");
++ goto err2;
++ }
++
++ pdata->clk_rate_change_nb.notifier_call = xusbps_ehci_clk_notifier_cb;
++ pdata->clk_rate_change_nb.next = NULL;
++ if (clk_notifier_register(pdata->clk, &pdata->clk_rate_change_nb))
++ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
++
++
++ /*
++ * do platform specific init: check the clock, grab/config pins, etc.
++ */
++ if (pdata->init && pdata->init(pdev)) {
++ retval = -ENODEV;
++ goto err_out_clk_unreg_notif;
++ }
++
++#ifdef CONFIG_USB_ZYNQ_PHY
++ if (pdata->otg) {
++ struct xusbps_otg *xotg;
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++ hcd->self.otg_port = 1;
++ hcd->phy = pdata->otg;
++ retval = otg_set_host(hcd->phy->otg,
++ &ehci_to_hcd(ehci)->self);
++ if (retval)
++ goto err_out_clk_unreg_notif;
++ xotg = xceiv_to_xotg(hcd->phy);
++ ehci->start_hnp = ehci_xusbps_start_hnp;
++ xotg->start_host = ehci_xusbps_otg_start_host;
++ xotg->stop_host = ehci_xusbps_otg_stop_host;
++ /* inform otg driver about host driver */
++ xusbps_update_transceiver();
++ } else {
++ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
++ if (retval)
++ goto err_out_clk_unreg_notif;
++
++ /*
++ * Enable vbus on ULPI - zedboard requirement
++ * to get host mode to work
++ */
++ if (pdata->ulpi)
++ otg_set_vbus(pdata->ulpi->otg, 1);
++ }
++#else
++ /* Don't need to set host mode here. It will be done by tdi_reset() */
++ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
++ if (retval)
++ goto err_out_clk_unreg_notif;
++#endif
++ return retval;
++
++err_out_clk_unreg_notif:
++ clk_notifier_unregister(pdata->clk, &pdata->clk_rate_change_nb);
++ clk_disable_unprepare(pdata->clk);
++err2:
++ usb_put_hcd(hcd);
++err1:
++ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
++ if (pdata->exit)
++ pdata->exit(pdev);
++
++ return retval;
++}
++
++/* may be called without controller electrically present */
++/* may be called with controller, bus, and devices active */
++
++/**
++ * usb_hcd_xusbps_remove - shutdown processing for XUSBPS-based HCDs
++ * @dev: USB Host Controller being removed
++ * Context: !in_interrupt()
++ *
++ * Reverses the effect of usb_hcd_xusbps_probe().
++ *
++ */
++static void usb_hcd_xusbps_remove(struct usb_hcd *hcd,
++ struct platform_device *pdev)
++{
++ struct xusbps_usb2_platform_data *pdata = pdev->dev.platform_data;
++
++ usb_remove_hcd(hcd);
++
++ /*
++ * do platform specific un-initialization:
++ * release iomux pins, disable clock, etc.
++ */
++ if (pdata->exit)
++ pdata->exit(pdev);
++ usb_put_hcd(hcd);
++ clk_notifier_unregister(pdata->clk, &pdata->clk_rate_change_nb);
++ clk_disable_unprepare(pdata->clk);
++}
++
++static void ehci_xusbps_setup_phy(struct ehci_hcd *ehci,
++ enum xusbps_usb2_phy_modes phy_mode,
++ unsigned int port_offset)
++{
++ u32 portsc;
++
++ portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
++ portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
++
++ switch (phy_mode) {
++ case XUSBPS_USB2_PHY_ULPI:
++ portsc |= PORT_PTS_ULPI;
++ break;
++ case XUSBPS_USB2_PHY_SERIAL:
++ portsc |= PORT_PTS_SERIAL;
++ break;
++ case XUSBPS_USB2_PHY_UTMI_WIDE:
++ portsc |= PORT_PTS_PTW;
++ /* fall through */
++ case XUSBPS_USB2_PHY_UTMI:
++ portsc |= PORT_PTS_UTMI;
++ break;
++ case XUSBPS_USB2_PHY_NONE:
++ break;
++ }
++ ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
++}
++
++static void ehci_xusbps_usb_setup(struct ehci_hcd *ehci)
++{
++ struct usb_hcd *hcd = ehci_to_hcd(ehci);
++ struct xusbps_usb2_platform_data *pdata;
++
++ pdata = hcd->self.controller->platform_data;
++
++ if ((pdata->operating_mode == XUSBPS_USB2_DR_HOST) ||
++ (pdata->operating_mode == XUSBPS_USB2_DR_OTG))
++ ehci_xusbps_setup_phy(ehci, pdata->phy_mode, 0);
++
++ if (pdata->operating_mode == XUSBPS_USB2_MPH_HOST) {
++ if (pdata->port_enables & XUSBPS_USB2_PORT0_ENABLED)
++ ehci_xusbps_setup_phy(ehci, pdata->phy_mode, 0);
++ if (pdata->port_enables & XUSBPS_USB2_PORT1_ENABLED)
++ ehci_xusbps_setup_phy(ehci, pdata->phy_mode, 1);
++ }
++}
++
++/*
++ * FIXME USB: EHCI: remove ehci_port_power() routine
++ *(sha1: c73cee717e7d5da0698acb720ad1219646fe4f46)
++ */
++static void ehci_port_power(struct ehci_hcd *ehci, int is_on)
++{
++ unsigned port;
++
++ if (!HCS_PPC(ehci->hcs_params))
++ return;
++
++ ehci_dbg(ehci, "...power%s ports...\n", is_on ? "up" : "down");
++ for (port = HCS_N_PORTS(ehci->hcs_params); port > 0; )
++ (void) ehci_hub_control(ehci_to_hcd(ehci),
++ is_on ? SetPortFeature : ClearPortFeature,
++ USB_PORT_FEAT_POWER,
++ port--, NULL, 0);
++ /* Flush those writes */
++ ehci_readl(ehci, &ehci->regs->command);
++ msleep(20);
++}
++
++/* called after powerup, by probe or system-pm "wakeup" */
++static int ehci_xusbps_reinit(struct ehci_hcd *ehci)
++{
++#ifdef CONFIG_USB_ZYNQ_PHY
++ struct usb_hcd *hcd = ehci_to_hcd(ehci);
++#endif
++
++ ehci_xusbps_usb_setup(ehci);
++#ifdef CONFIG_USB_ZYNQ_PHY
++ /* Don't turn off port power in OTG mode */
++ if (!hcd->phy)
++#endif
++ ehci_port_power(ehci, 0);
++
++ return 0;
++}
++
++struct ehci_xusbps {
++ struct ehci_hcd ehci;
++
++#ifdef CONFIG_PM
++ /* Saved USB PHY settings, need to restore after deep sleep. */
++ u32 usb_ctrl;
++#endif
++};
++
++/* called during probe() after chip reset completes */
++static int ehci_xusbps_setup(struct usb_hcd *hcd)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ int retval;
++
++ /* EHCI registers start at offset 0x100 */
++ ehci->caps = hcd->regs + 0x100;
++ ehci->regs = hcd->regs + 0x100 +
++ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
++ dbg_hcs_params(ehci, "reset");
++ dbg_hcc_params(ehci, "reset");
++
++ /* cache this readonly data; minimize chip reads */
++ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++ hcd->has_tt = 1;
++
++ /* data structure init */
++ retval = ehci_init(hcd);
++ if (retval)
++ return retval;
++
++ retval = ehci_halt(ehci);
++ if (retval)
++ return retval;
++
++ ehci->sbrn = 0x20;
++
++ ehci_reset(ehci);
++
++ retval = ehci_xusbps_reinit(ehci);
++ return retval;
++}
++
++static void ehci_xusbps_shutdown(struct usb_hcd *hcd)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++ if (ehci->regs)
++ ehci_shutdown(hcd);
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int ehci_xusbps_drv_suspend(struct device *dev)
++{
++ struct usb_hcd *hcd = dev_get_drvdata(dev);
++ struct xusbps_usb2_platform_data *pdata = dev->platform_data;
++
++ ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
++ device_may_wakeup(dev));
++
++ clk_disable(pdata->clk);
++
++ return 0;
++}
++
++static int ehci_xusbps_drv_resume(struct device *dev)
++{
++ struct usb_hcd *hcd = dev_get_drvdata(dev);
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ struct xusbps_usb2_platform_data *pdata = dev->platform_data;
++ int ret;
++
++ ret = clk_enable(pdata->clk);
++ if (ret) {
++ dev_err(dev, "cannot enable clock. resume failed\n");
++ return ret;
++ }
++
++ ehci_prepare_ports_for_controller_resume(ehci);
++
++ usb_root_hub_lost_power(hcd->self.root_hub);
++
++ ehci_reset(ehci);
++ ehci_xusbps_reinit(ehci);
++
++ return 0;
++}
++
++static const struct dev_pm_ops ehci_xusbps_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(ehci_xusbps_drv_suspend, ehci_xusbps_drv_resume)
++};
++#define EHCI_XUSBPS_PM_OPS (&ehci_xusbps_pm_ops)
++
++#else /* ! CONFIG_PM_SLEEP */
++#define EHCI_XUSBPS_PM_OPS NULL
++#endif /* ! CONFIG_PM_SLEEP */
++
++
++static const struct hc_driver ehci_xusbps_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "Xilinx PS USB EHCI Host Controller",
++ .hcd_priv_size = sizeof(struct ehci_xusbps),
++
++ /*
++ * generic hardware linkage
++ */
++ .irq = ehci_irq,
++ .flags = HCD_USB2 | HCD_MEMORY,
++
++ /*
++ * basic lifecycle operations
++ */
++ .reset = ehci_xusbps_setup,
++ .start = ehci_run,
++ .stop = ehci_stop,
++ .shutdown = ehci_xusbps_shutdown,
++
++ /*
++ * managing i/o requests and associated device resources
++ */
++ .urb_enqueue = ehci_urb_enqueue,
++ .urb_dequeue = ehci_urb_dequeue,
++ .endpoint_disable = ehci_endpoint_disable,
++ .endpoint_reset = ehci_endpoint_reset,
++
++ /*
++ * scheduling support
++ */
++ .get_frame_number = ehci_get_frame,
++
++ /*
++ * root hub support
++ */
++ .hub_status_data = ehci_hub_status_data,
++ .hub_control = ehci_hub_control,
++ .bus_suspend = ehci_bus_suspend,
++ .bus_resume = ehci_bus_resume,
++ .relinquish_port = ehci_relinquish_port,
++ .port_handed_over = ehci_port_handed_over,
++
++ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++#ifdef CONFIG_USB_ZYNQ_PHY
++ .update_device = ehci_xusbps_update_device,
++#endif
++};
++
++static int ehci_xusbps_drv_probe(struct platform_device *pdev)
++{
++ if (usb_disabled())
++ return -ENODEV;
++
++ /* FIXME we only want one one probe() not two */
++ return usb_hcd_xusbps_probe(&ehci_xusbps_hc_driver, pdev);
++}
++
++static int ehci_xusbps_drv_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ /* FIXME we only want one one remove() not two */
++ usb_hcd_xusbps_remove(hcd, pdev);
++ return 0;
++}
++
++MODULE_ALIAS("platform:xusbps-ehci");
++
++static struct platform_driver ehci_xusbps_driver = {
++ .probe = ehci_xusbps_drv_probe,
++ .remove = ehci_xusbps_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
++ .driver = {
++ .name = "xusbps-ehci",
++ .pm = EHCI_XUSBPS_PM_OPS,
++ },
++};
+--- /dev/null
++++ b/drivers/usb/host/ehci-xilinx-usbps.h
+@@ -0,0 +1,33 @@
++/*
++ * Xilinx PS USB Host Controller Driver Header file.
++ *
++ * Copyright (C) 2011 Xilinx, Inc.
++ *
++ * This file is based on ehci-fsl.h file with few minor modifications
++ * to support Xilinx PS USB controller.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#ifndef _EHCI_XILINX_XUSBPS_H
++#define _EHCI_XILINX_XUSBPS_H
++
++#include <linux/usb/xilinx_usbps_otg.h>
++
++/* offsets for the non-ehci registers in the XUSBPS SOC USB controller */
++#define XUSBPS_SOC_USB_ULPIVP 0x170
++#define XUSBPS_SOC_USB_PORTSC1 0x184
++#define PORT_PTS_MSK (3<<30)
++#define PORT_PTS_UTMI (0<<30)
++#define PORT_PTS_ULPI (2<<30)
++#define PORT_PTS_SERIAL (3<<30)
++#define PORT_PTS_PTW (1<<28)
++#define XUSBPS_SOC_USB_PORTSC2 0x188
++
++#endif /* _EHCI_XILINX_XUSBPS_H */
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -176,6 +176,14 @@ struct ehci_hcd { /* one per controlle
+ unsigned long resuming_ports; /* which ports have
+ started to resume */
+
++#ifdef CONFIG_USB_ZYNQ_PHY
++ /*
++ * OTG controllers and transceivers need software interaction;
++ * other external transceivers should be software-transparent
++ */
++ void (*start_hnp)(struct ehci_hcd *ehci);
++#endif
++
+ /* per-HC memory pools (could be per-bus, but ...) */
+ struct dma_pool *qh_pool; /* qh per active urb */
+ struct dma_pool *qtd_pool; /* one or more per qh */
+--- /dev/null
++++ b/drivers/usb/host/xusbps-dr-of.c
+@@ -0,0 +1,331 @@
++/*
++ * Xilinx PS USB Driver for device tree support.
++ *
++ * Copyright (C) 2011 Xilinx, Inc.
++ *
++ * This file is based on fsl-mph-dr-of.c file with few minor modifications
++ * to support Xilinx PS USB controller.
++ *
++ * Setup platform devices needed by the dual-role USB controller modules
++ * based on the description in flat device tree.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/xilinx_devices.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/of_platform.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/clk.h>
++#include <linux/usb/ulpi.h>
++
++#include "ehci-xilinx-usbps.h"
++
++static u64 dma_mask = 0xFFFFFFF0;
++
++struct xusbps_dev_data {
++ char *dr_mode; /* controller mode */
++ char *drivers[3]; /* drivers to instantiate for this mode */
++ enum xusbps_usb2_operating_modes op_mode; /* operating mode */
++};
++
++struct xusbps_host_data {
++ struct clk *clk;
++};
++
++static struct xusbps_dev_data dr_mode_data[] = {
++ {
++ .dr_mode = "host",
++ .drivers = { "xusbps-ehci", NULL, NULL, },
++ .op_mode = XUSBPS_USB2_DR_HOST,
++ },
++ {
++ .dr_mode = "otg",
++ .drivers = { "xusbps-otg", "xusbps-ehci", "xusbps-udc", },
++ .op_mode = XUSBPS_USB2_DR_OTG,
++ },
++ {
++ .dr_mode = "peripheral",
++ .drivers = { "xusbps-udc", NULL, NULL, },
++ .op_mode = XUSBPS_USB2_DR_DEVICE,
++ },
++};
++
++static struct xusbps_dev_data *get_dr_mode_data(
++ struct device_node *np)
++{
++ const unsigned char *prop;
++ int i;
++
++ prop = of_get_property(np, "dr_mode", NULL);
++ if (prop) {
++ for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
++ if (!strcmp(prop, dr_mode_data[i].dr_mode))
++ return &dr_mode_data[i];
++ }
++ }
++ pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n",
++ np->full_name);
++ return &dr_mode_data[0]; /* mode not specified, use host */
++}
++
++static enum xusbps_usb2_phy_modes determine_usb_phy(const char *phy_type)
++{
++ if (!phy_type)
++ return XUSBPS_USB2_PHY_NONE;
++ if (!strcasecmp(phy_type, "ulpi"))
++ return XUSBPS_USB2_PHY_ULPI;
++ if (!strcasecmp(phy_type, "utmi"))
++ return XUSBPS_USB2_PHY_UTMI;
++ if (!strcasecmp(phy_type, "utmi_wide"))
++ return XUSBPS_USB2_PHY_UTMI_WIDE;
++ if (!strcasecmp(phy_type, "serial"))
++ return XUSBPS_USB2_PHY_SERIAL;
++
++ return XUSBPS_USB2_PHY_NONE;
++}
++
++static struct platform_device *xusbps_device_register(
++ struct platform_device *ofdev,
++ struct xusbps_usb2_platform_data *pdata,
++ const char *name, int id)
++{
++ struct platform_device *pdev;
++ const struct resource *res = ofdev->resource;
++ unsigned int num = ofdev->num_resources;
++ struct xusbps_usb2_platform_data *pdata1;
++ int retval;
++
++ pdev = platform_device_alloc(name, id);
++ if (!pdev) {
++ retval = -ENOMEM;
++ goto error;
++ }
++
++ pdev->dev.parent = &ofdev->dev;
++
++ pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
++ pdev->dev.dma_mask = &dma_mask;
++
++ retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
++ if (retval)
++ goto error;
++
++ if (num) {
++ retval = platform_device_add_resources(pdev, res, num);
++ if (retval)
++ goto error;
++ }
++
++ retval = platform_device_add(pdev);
++ if (retval)
++ goto error;
++
++ pdata1 = pdev->dev.platform_data;
++ /* Copy the otg transceiver pointer into host/device platform data */
++ if (pdata1->otg)
++ pdata->otg = pdata1->otg;
++
++ return pdev;
++
++error:
++ platform_device_put(pdev);
++ return ERR_PTR(retval);
++}
++
++static int xusbps_dr_of_probe(struct platform_device *ofdev)
++{
++ struct device_node *np = ofdev->dev.of_node;
++ struct platform_device *usb_dev;
++ struct xusbps_usb2_platform_data data, *pdata;
++ struct xusbps_dev_data *dev_data;
++ struct xusbps_host_data *hdata;
++ const unsigned char *prop;
++ static unsigned int idx;
++ struct resource *res;
++ int i, phy_init;
++ int ret;
++
++ pdata = &data;
++ memset(pdata, 0, sizeof(data));
++
++ res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);
++ if (IS_ERR(res)) {
++ dev_err(&ofdev->dev,
++ "IRQ not found\n");
++ return PTR_ERR(res);
++ }
++ pdata->irq = res->start;
++
++ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
++ pdata->regs = devm_ioremap_resource(&ofdev->dev, res);
++ if (IS_ERR(pdata->regs)) {
++ dev_err(&ofdev->dev, "unable to iomap registers\n");
++ return PTR_ERR(pdata->regs);
++ }
++
++ dev_data = get_dr_mode_data(np);
++ pdata->operating_mode = dev_data->op_mode;
++
++ prop = of_get_property(np, "phy_type", NULL);
++ pdata->phy_mode = determine_usb_phy(prop);
++
++ hdata = devm_kzalloc(&ofdev->dev, sizeof(*hdata), GFP_KERNEL);
++ if (!hdata)
++ return -ENOMEM;
++ platform_set_drvdata(ofdev, hdata);
++
++ hdata->clk = devm_clk_get(&ofdev->dev, NULL);
++ if (IS_ERR(hdata->clk)) {
++ dev_err(&ofdev->dev, "input clock not found.\n");
++ return PTR_ERR(hdata->clk);
++ }
++
++ ret = clk_prepare_enable(hdata->clk);
++ if (ret) {
++ dev_err(&ofdev->dev, "Unable to enable APER clock.\n");
++ return ret;
++ }
++
++ pdata->clk = hdata->clk;
++
++ /* If ULPI phy type, set it up */
++ if (pdata->phy_mode == XUSBPS_USB2_PHY_ULPI) {
++ pdata->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops,
++ ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
++ if (pdata->ulpi) {
++ pdata->ulpi->io_priv = pdata->regs +
++ XUSBPS_SOC_USB_ULPIVP;
++
++ phy_init = usb_phy_init(pdata->ulpi);
++ if (phy_init) {
++ dev_err(&ofdev->dev,
++ "Unable to init USB phy, missing?\n");
++ ret = -ENODEV;
++ goto err_out_clk_disable;
++ }
++ } else {
++ dev_err(&ofdev->dev,
++ "Unable to create ULPI transceiver\n");
++ }
++ }
++
++ for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
++ if (!dev_data->drivers[i])
++ continue;
++ usb_dev = xusbps_device_register(ofdev, pdata,
++ dev_data->drivers[i], idx);
++ if (IS_ERR(usb_dev)) {
++ dev_err(&ofdev->dev, "Can't register usb device\n");
++ ret = PTR_ERR(usb_dev);
++ goto err_out_clk_disable;
++ }
++ }
++ idx++;
++ return 0;
++
++err_out_clk_disable:
++ clk_disable_unprepare(hdata->clk);
++
++ return ret;
++}
++
++static int __unregister_subdev(struct device *dev, void *d)
++{
++ platform_device_unregister(to_platform_device(dev));
++ return 0;
++}
++
++static int xusbps_dr_of_remove(struct platform_device *ofdev)
++{
++ struct xusbps_host_data *hdata = platform_get_drvdata(ofdev);
++
++ device_for_each_child(&ofdev->dev, NULL, __unregister_subdev);
++ clk_disable_unprepare(hdata->clk);
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int xusbps_dr_of_suspend(struct device *dev)
++{
++ struct xusbps_host_data *hdata = dev_get_drvdata(dev);
++
++ clk_disable(hdata->clk);
++
++ return 0;
++}
++
++static int xusbps_dr_of_resume(struct device *dev)
++{
++ struct xusbps_host_data *hdata = dev_get_drvdata(dev);
++ int ret;
++
++ ret = clk_enable(hdata->clk);
++ if (ret) {
++ dev_err(dev, "cannot enable clock. resume failed\n");
++ return ret;
++ }
++
++ return 0;
++}
++#endif /* CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(xusbps_pm_ops, xusbps_dr_of_suspend,
++ xusbps_dr_of_resume);
++
++static const struct of_device_id xusbps_dr_of_match[] = {
++ { .compatible = "xlnx,ps7-usb-1.00.a" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, xusbps_dr_of_match);
++
++static struct platform_driver xusbps_dr_driver = {
++ .driver = {
++ .name = "xusbps-dr",
++ .owner = THIS_MODULE,
++ .of_match_table = xusbps_dr_of_match,
++ .pm = &xusbps_pm_ops,
++ },
++ .probe = xusbps_dr_of_probe,
++ .remove = xusbps_dr_of_remove,
++};
++
++#ifdef CONFIG_USB_ZYNQ_PHY
++extern struct platform_driver xusbps_otg_driver;
++
++static int __init xusbps_dr_init(void)
++{
++ int retval;
++
++ /* Register otg driver first */
++ retval = platform_driver_register(&xusbps_otg_driver);
++ if (retval != 0)
++ return retval;
++
++ return platform_driver_register(&xusbps_dr_driver);
++}
++module_init(xusbps_dr_init);
++
++static void __exit xusbps_dr_exit(void)
++{
++ platform_driver_unregister(&xusbps_dr_driver);
++}
++module_exit(xusbps_dr_exit);
++#else
++module_platform_driver(xusbps_dr_driver);
++#endif
++
++MODULE_DESCRIPTION("XUSBPS DR OF devices driver");
++MODULE_AUTHOR("Xilinx");
++MODULE_LICENSE("GPL");
+--- a/drivers/usb/phy/Kconfig
++++ b/drivers/usb/phy/Kconfig
+@@ -210,4 +210,16 @@ config USB_ULPI_VIEWPORT
+ Provides read/write operations to the ULPI phy register set for
+ controllers with a viewport register (e.g. Chipidea/ARC controllers).
+
++config USB_ZYNQ_PHY
++ tristate "Xilinx Zynq USB OTG dual-role support"
++ depends on USB && ARCH_ZYNQ && USB_EHCI_XUSBPS && USB_GADGET_XUSBPS && USB_OTG
++ select USB_OTG_UTILS
++ help
++ Say Y here if you want to build Xilinx USB PS OTG
++ driver in kernel. This driver implements role
++ switch between EHCI host driver and USB gadget driver.
++
++ To compile this driver as a module, choose M here: the
++ module will be called xilinx_usbps_otg.
++
+ endif # USB_PHY
+--- a/drivers/usb/phy/Makefile
++++ b/drivers/usb/phy/Makefile
+@@ -31,3 +31,4 @@ obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-us
+ obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o
+ obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
+ obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
++obj-$(CONFIG_USB_ZYNQ_PHY) += phy-zynq-usb.o
+--- /dev/null
++++ b/drivers/usb/phy/phy-zynq-usb.c
+@@ -0,0 +1,2305 @@
++/*
++ * Xilinx PS USB otg driver.
++ *
++ * Copyright 2011 Xilinx, Inc.
++ *
++ * This file is based on langwell_otg.c file with few minor modifications
++ * to support Xilinx PS USB controller.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* This driver helps to switch Xilinx OTG controller function between host
++ * and peripheral. It works with EHCI driver and Xilinx client controller
++ * driver together.
++ */
++#include <linux/clk.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/moduleparam.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <linux/usb.h>
++#include <linux/usb/otg.h>
++#include <linux/usb/hcd.h>
++#include <linux/notifier.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/io.h>
++
++#include "../core/usb.h"
++
++#include <linux/xilinx_devices.h>
++#include <linux/usb/xilinx_usbps_otg.h>
++
++#define DRIVER_NAME "xusbps-otg"
++
++static const char driver_name[] = DRIVER_NAME;
++
++/* HSM timers */
++static inline struct xusbps_otg_timer *otg_timer_initializer
++(void (*function)(unsigned long), unsigned long expires, unsigned long data)
++{
++ struct xusbps_otg_timer *timer;
++ timer = kmalloc(sizeof(struct xusbps_otg_timer), GFP_KERNEL);
++ if (timer == NULL)
++ return timer;
++
++ timer->function = function;
++ timer->expires = expires;
++ timer->data = data;
++ return timer;
++}
++
++static struct xusbps_otg_timer *a_wait_vrise_tmr, *a_aidl_bdis_tmr,
++ *b_se0_srp_tmr, *b_srp_init_tmr;
++
++static struct list_head active_timers;
++
++static struct xusbps_otg *the_transceiver;
++
++/* host/client notify transceiver when event affects HNP state */
++void xusbps_update_transceiver(void)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ dev_dbg(xotg->dev, "transceiver is updated\n");
++
++ if (!xotg->qwork)
++ return;
++
++ queue_work(xotg->qwork, &xotg->work);
++}
++EXPORT_SYMBOL(xusbps_update_transceiver);
++
++static int xusbps_otg_set_host(struct usb_otg *otg,
++ struct usb_bus *host)
++{
++ otg->host = host;
++
++ if (host) {
++ if (otg->default_a)
++ host->is_b_host = 0;
++ else
++ host->is_b_host = 1;
++ }
++
++ return 0;
++}
++
++static int xusbps_otg_set_peripheral(struct usb_otg *otg,
++ struct usb_gadget *gadget)
++{
++ otg->gadget = gadget;
++
++ if (gadget) {
++ if (otg->default_a)
++ gadget->is_a_peripheral = 1;
++ else
++ gadget->is_a_peripheral = 0;
++ }
++
++ return 0;
++}
++
++static int xusbps_otg_set_power(struct usb_phy *otg,
++ unsigned mA)
++{
++ return 0;
++}
++
++/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/
++static int xusbps_otg_set_vbus(struct usb_otg *otg, bool enabled)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ dev_dbg(xotg->dev, "%s <--- %s\n", __func__, enabled ? "on" : "off");
++
++ /* Enable ulpi VBUS if required */
++ if (xotg->ulpi)
++ otg_set_vbus(xotg->ulpi->otg, enabled);
++
++ val = readl(xotg->base + CI_PORTSC1);
++
++ if (enabled)
++ writel((val | PORTSC_PP), xotg->base + CI_PORTSC1);
++ else
++ writel((val & ~PORTSC_PP), xotg->base + CI_PORTSC1);
++
++ dev_dbg(xotg->dev, "%s --->\n", __func__);
++
++ return 0;
++}
++
++/* Charge vbus for VBUS pulsing in SRP */
++static void xusbps_otg_chrg_vbus(int on)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ val = readl(xotg->base + CI_OTGSC) & ~OTGSC_INTSTS_MASK;
++
++ if (on)
++ /* stop discharging, start charging */
++ val = (val & ~OTGSC_VD) | OTGSC_VC;
++ else
++ /* stop charging */
++ val &= ~OTGSC_VC;
++
++ writel(val, xotg->base + CI_OTGSC);
++}
++
++#if 0
++
++/* Discharge vbus through a resistor to ground */
++static void xusbps_otg_dischrg_vbus(int on)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ val = readl(xotg->base + CI_OTGSC) & ~OTGSC_INTSTS_MASK;
++
++ if (on)
++ /* stop charging, start discharging */
++ val = (val & ~OTGSC_VC) | OTGSC_VD;
++ else
++ val &= ~OTGSC_VD;
++
++ writel(val, xotg->base + CI_OTGSC);
++}
++
++#endif
++
++/* Start SRP */
++static int xusbps_otg_start_srp(struct usb_otg *otg)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ dev_warn(xotg->dev, "Starting SRP...\n");
++ dev_dbg(xotg->dev, "%s --->\n", __func__);
++
++ val = readl(xotg->base + CI_OTGSC);
++
++ writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP,
++ xotg->base + CI_OTGSC);
++
++ /* Check if the data plus is finished or not */
++ msleep(8);
++ val = readl(xotg->base + CI_OTGSC);
++ if (val & (OTGSC_HADP | OTGSC_DP))
++ dev_dbg(xotg->dev, "DataLine SRP Error\n");
++
++ /* If Vbus is valid, then update the hsm */
++ if (val & OTGSC_BSV) {
++ dev_dbg(xotg->dev, "no b_sess_vld interrupt\n");
++
++ xotg->hsm.b_sess_vld = 1;
++ xusbps_update_transceiver();
++ return 0;
++ }
++
++ dev_warn(xotg->dev, "Starting VBUS Pulsing...\n");
++
++ /* Disable interrupt - b_sess_vld */
++ val = readl(xotg->base + CI_OTGSC);
++ val &= (~(OTGSC_BSVIE | OTGSC_BSEIE));
++ writel(val, xotg->base + CI_OTGSC);
++
++ /* Start VBus SRP, drive vbus to generate VBus pulse */
++ xusbps_otg_chrg_vbus(1);
++ msleep(15);
++ xusbps_otg_chrg_vbus(0);
++
++ /* Enable interrupt - b_sess_vld*/
++ val = readl(xotg->base + CI_OTGSC);
++ dev_dbg(xotg->dev, "after VBUS pulse otgsc = %x\n", val);
++
++ val |= (OTGSC_BSVIE | OTGSC_BSEIE);
++ writel(val, xotg->base + CI_OTGSC);
++
++ /* If Vbus is valid, then update the hsm */
++ if (val & OTGSC_BSV) {
++ dev_dbg(xotg->dev, "no b_sess_vld interrupt\n");
++
++ xotg->hsm.b_sess_vld = 1;
++ xusbps_update_transceiver();
++ }
++
++ dev_dbg(xotg->dev, "%s <---\n", __func__);
++ return 0;
++}
++
++/* Start HNP */
++static int xusbps_otg_start_hnp(struct usb_otg *otg)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ unsigned long flag = 0;
++
++ dev_warn(xotg->dev, "Starting HNP...\n");
++ dev_dbg(xotg->dev, "%s --->\n", __func__);
++
++ if (xotg->otg.otg->default_a && xotg->otg.otg->host &&
++ xotg->otg.otg->host->b_hnp_enable) {
++ xotg->hsm.a_suspend_req = 1;
++ flag = 1;
++ }
++
++ if (!xotg->otg.otg->default_a && xotg->otg.otg->host &&
++ xotg->hsm.b_bus_req) {
++ xotg->hsm.b_bus_req = 0;
++ flag = 1;
++ }
++
++ if (flag) {
++ if (spin_trylock(&xotg->wq_lock)) {
++ xusbps_update_transceiver();
++ spin_unlock(&xotg->wq_lock);
++ }
++ } else
++ dev_warn(xotg->dev, "HNP not supported\n");
++
++ dev_dbg(xotg->dev, "%s <---\n", __func__);
++ return 0;
++}
++
++/* stop SOF via bus_suspend */
++static void xusbps_otg_loc_sof(int on)
++{
++ /* Not used */
++}
++
++static void xusbps_otg_phy_low_power(int on)
++{
++ /* Not used */
++}
++
++/* After drv vbus, add 2 ms delay to set PHCD */
++static void xusbps_otg_phy_low_power_wait(int on)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ dev_dbg(xotg->dev, "add 2ms delay before programing PHCD\n");
++
++ mdelay(2);
++ xusbps_otg_phy_low_power(on);
++}
++
++#ifdef CONFIG_PM_SLEEP
++/* Enable/Disable OTG interrupt */
++static void xusbps_otg_intr(int on)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ dev_dbg(xotg->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ val = readl(xotg->base + CI_OTGSC);
++
++ /* OTGSC_INT_MASK doesn't contains 1msInt */
++ if (on) {
++ val = val | (OTGSC_INT_MASK);
++ writel(val, xotg->base + CI_OTGSC);
++ } else {
++ val = val & ~(OTGSC_INT_MASK);
++ writel(val, xotg->base + CI_OTGSC);
++ }
++
++ dev_dbg(xotg->dev, "%s <---\n", __func__);
++}
++#endif
++
++/* set HAAR: Hardware Assist Auto-Reset */
++static void xusbps_otg_HAAR(int on)
++{
++ /* Not used */
++}
++
++/* set HABA: Hardware Assist B-Disconnect to A-Connect */
++static void xusbps_otg_HABA(int on)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ dev_dbg(xotg->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ val = readl(xotg->base + CI_OTGSC);
++ if (on)
++ writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA,
++ xotg->base + CI_OTGSC);
++ else
++ writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA,
++ xotg->base + CI_OTGSC);
++
++ dev_dbg(xotg->dev, "%s <---\n", __func__);
++}
++
++static int xusbps_otg_check_se0_srp(int on)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ int delay_time = TB_SE0_SRP * 10;
++ u32 val;
++
++ dev_dbg(xotg->dev, "%s --->\n", __func__);
++
++ do {
++ udelay(100);
++ if (!delay_time--)
++ break;
++ val = readl(xotg->base + CI_PORTSC1);
++ val &= PORTSC_LS;
++ } while (!val);
++
++ dev_dbg(xotg->dev, "%s <---\n", __func__);
++ return val;
++}
++
++/* The timeout callback function to set time out bit */
++static void set_tmout(unsigned long indicator)
++{
++ *(int *)indicator = 1;
++}
++
++static void xusbps_otg_msg(unsigned long indicator)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ switch (indicator) {
++ case 2:
++ case 4:
++ case 6:
++ case 7:
++ dev_warn(xotg->dev,
++ "OTG:%lu - deivce not responding\n", indicator);
++ break;
++ case 3:
++ dev_warn(xotg->dev,
++ "OTG:%lu - deivce not supported\n", indicator);
++ break;
++ default:
++ dev_warn(xotg->dev, "Do not have this msg\n");
++ break;
++ }
++}
++
++/* Initialize timers */
++static int xusbps_otg_init_timers(struct otg_hsm *hsm)
++{
++ /* HSM used timers */
++ a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
++ (unsigned long)&hsm->a_wait_vrise_tmout);
++ if (a_wait_vrise_tmr == NULL)
++ return -ENOMEM;
++ a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
++ (unsigned long)&hsm->a_aidl_bdis_tmout);
++ if (a_aidl_bdis_tmr == NULL)
++ return -ENOMEM;
++ b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
++ (unsigned long)&hsm->b_se0_srp);
++ if (b_se0_srp_tmr == NULL)
++ return -ENOMEM;
++ b_srp_init_tmr = otg_timer_initializer(&set_tmout, TB_SRP_INIT,
++ (unsigned long)&hsm->b_srp_init_tmout);
++ if (b_srp_init_tmr == NULL)
++ return -ENOMEM;
++
++ return 0;
++}
++
++/* Free timers */
++static void xusbps_otg_free_timers(void)
++{
++ kfree(a_wait_vrise_tmr);
++ kfree(a_aidl_bdis_tmr);
++ kfree(b_se0_srp_tmr);
++ kfree(b_srp_init_tmr);
++}
++
++/* The timeout callback function to set time out bit */
++static void xusbps_otg_timer_fn(unsigned long indicator)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ *(int *)indicator = 1;
++
++ dev_dbg(xotg->dev, "kernel timer - timeout\n");
++
++ xusbps_update_transceiver();
++}
++
++/* kernel timer used instead of HW based interrupt */
++static void xusbps_otg_add_ktimer(enum xusbps_otg_timer_type timers)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ unsigned long j = jiffies;
++ unsigned long data, time;
++
++ switch (timers) {
++ case TA_WAIT_VRISE_TMR:
++ xotg->hsm.a_wait_vrise_tmout = 0;
++ data = (unsigned long)&xotg->hsm.a_wait_vrise_tmout;
++ time = TA_WAIT_VRISE;
++ break;
++ case TA_WAIT_BCON_TMR:
++ xotg->hsm.a_wait_bcon_tmout = 0;
++ data = (unsigned long)&xotg->hsm.a_wait_bcon_tmout;
++ time = TA_WAIT_BCON;
++ break;
++ case TA_AIDL_BDIS_TMR:
++ xotg->hsm.a_aidl_bdis_tmout = 0;
++ data = (unsigned long)&xotg->hsm.a_aidl_bdis_tmout;
++ time = TA_AIDL_BDIS;
++ break;
++ case TB_ASE0_BRST_TMR:
++ xotg->hsm.b_ase0_brst_tmout = 0;
++ data = (unsigned long)&xotg->hsm.b_ase0_brst_tmout;
++ time = TB_ASE0_BRST;
++ break;
++ case TB_SRP_INIT_TMR:
++ xotg->hsm.b_srp_init_tmout = 0;
++ data = (unsigned long)&xotg->hsm.b_srp_init_tmout;
++ time = TB_SRP_INIT;
++ break;
++ case TB_SRP_FAIL_TMR:
++ xotg->hsm.b_srp_fail_tmout = 0;
++ data = (unsigned long)&xotg->hsm.b_srp_fail_tmout;
++ time = TB_SRP_FAIL;
++ break;
++ case TB_BUS_SUSPEND_TMR:
++ xotg->hsm.b_bus_suspend_tmout = 0;
++ data = (unsigned long)&xotg->hsm.b_bus_suspend_tmout;
++ time = TB_BUS_SUSPEND;
++ break;
++ default:
++ dev_dbg(xotg->dev, "unkown timer, cannot enable it\n");
++ return;
++ }
++
++ xotg->hsm_timer.data = data;
++ xotg->hsm_timer.function = xusbps_otg_timer_fn;
++ xotg->hsm_timer.expires = j + time * HZ / 1000; /* milliseconds */
++
++ add_timer(&xotg->hsm_timer);
++
++ dev_dbg(xotg->dev, "add timer successfully\n");
++}
++
++/* Add timer to timer list */
++static void xusbps_otg_add_timer(void *gtimer)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ struct xusbps_otg_timer *timer = (struct xusbps_otg_timer *)gtimer;
++ struct xusbps_otg_timer *tmp_timer;
++ u32 val32;
++
++ /* Check if the timer is already in the active list,
++ * if so update timer count
++ */
++ list_for_each_entry(tmp_timer, &active_timers, list)
++ if (tmp_timer == timer) {
++ timer->count = timer->expires;
++ return;
++ }
++ timer->count = timer->expires;
++
++ if (list_empty(&active_timers)) {
++ val32 = readl(xotg->base + CI_OTGSC);
++ writel(val32 | OTGSC_1MSE, xotg->base + CI_OTGSC);
++ }
++
++ list_add_tail(&timer->list, &active_timers);
++}
++
++/* Remove timer from the timer list; clear timeout status */
++static void xusbps_otg_del_timer(void *gtimer)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ struct xusbps_otg_timer *timer = (struct xusbps_otg_timer *)gtimer;
++ struct xusbps_otg_timer *tmp_timer, *del_tmp;
++ u32 val32;
++
++ list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
++ if (tmp_timer == timer)
++ list_del(&timer->list);
++
++ if (list_empty(&active_timers)) {
++ val32 = readl(xotg->base + CI_OTGSC);
++ writel(val32 & ~OTGSC_1MSE, xotg->base + CI_OTGSC);
++ }
++}
++
++/* Reduce timer count by 1, and find timeout conditions.*/
++static int xusbps_otg_tick_timer(u32 *int_sts)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ struct xusbps_otg_timer *tmp_timer, *del_tmp;
++ int expired = 0;
++
++ list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
++ tmp_timer->count--;
++ /* check if timer expires */
++ if (!tmp_timer->count) {
++ list_del(&tmp_timer->list);
++ tmp_timer->function(tmp_timer->data);
++ expired = 1;
++ }
++ }
++
++ if (list_empty(&active_timers)) {
++ dev_dbg(xotg->dev, "tick timer: disable 1ms int\n");
++ *int_sts = *int_sts & ~OTGSC_1MSE;
++ }
++ return expired;
++}
++
++static void reset_otg(void)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ int delay_time = 1000;
++ u32 val;
++
++ dev_dbg(xotg->dev, "reseting OTG controller ...\n");
++ val = readl(xotg->base + CI_USBCMD);
++ writel(val | USBCMD_RST, xotg->base + CI_USBCMD);
++ do {
++ udelay(100);
++ if (!delay_time--)
++ dev_dbg(xotg->dev, "reset timeout\n");
++ val = readl(xotg->base + CI_USBCMD);
++ val &= USBCMD_RST;
++ } while (val != 0);
++ dev_dbg(xotg->dev, "reset done.\n");
++}
++
++static void set_host_mode(void)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ reset_otg();
++ val = readl(xotg->base + CI_USBMODE);
++ val = (val & (~USBMODE_CM)) | USBMODE_HOST;
++ writel(val, xotg->base + CI_USBMODE);
++}
++
++static void set_client_mode(void)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val;
++
++ reset_otg();
++ val = readl(xotg->base + CI_USBMODE);
++ val = (val & (~USBMODE_CM)) | USBMODE_DEVICE;
++ writel(val, xotg->base + CI_USBMODE);
++}
++
++static void init_hsm(void)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val32;
++
++ /* read OTGSC after reset */
++ val32 = readl(xotg->base + CI_OTGSC);
++
++ /* set init state */
++ if (val32 & OTGSC_ID) {
++ xotg->hsm.id = 1;
++ xotg->otg.otg->default_a = 0;
++ set_client_mode();
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ } else {
++ xotg->hsm.id = 0;
++ xotg->otg.otg->default_a = 1;
++ set_host_mode();
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ }
++
++ /* set session indicator */
++ if (!xotg->otg.otg->default_a) {
++ if (val32 & OTGSC_BSE)
++ xotg->hsm.b_sess_end = 1;
++ if (val32 & OTGSC_BSV)
++ xotg->hsm.b_sess_vld = 1;
++ } else {
++ if (val32 & OTGSC_ASV)
++ xotg->hsm.a_sess_vld = 1;
++ if (val32 & OTGSC_AVV)
++ xotg->hsm.a_vbus_vld = 1;
++ }
++
++ /* defautly power the bus */
++ xotg->hsm.a_bus_req = 0;
++ xotg->hsm.a_bus_drop = 0;
++ /* defautly don't request bus as B device */
++ xotg->hsm.b_bus_req = 0;
++ /* no system error */
++ xotg->hsm.a_clr_err = 0;
++
++ xusbps_otg_phy_low_power_wait(1);
++}
++
++#ifdef CONFIG_PM_SLEEP
++static void update_hsm(void)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ u32 val32;
++
++ /* read OTGSC */
++ val32 = readl(xotg->base + CI_OTGSC);
++
++ xotg->hsm.id = !!(val32 & OTGSC_ID);
++ if (!xotg->otg.otg->default_a) {
++ xotg->hsm.b_sess_end = !!(val32 & OTGSC_BSE);
++ xotg->hsm.b_sess_vld = !!(val32 & OTGSC_BSV);
++ } else {
++ xotg->hsm.a_sess_vld = !!(val32 & OTGSC_ASV);
++ xotg->hsm.a_vbus_vld = !!(val32 & OTGSC_AVV);
++ }
++}
++#endif
++
++static irqreturn_t otg_dummy_irq(int irq, void *_dev)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ void __iomem *reg_base = _dev;
++ u32 val;
++ u32 int_mask = 0;
++
++ val = readl(reg_base + CI_USBMODE);
++ if ((val & USBMODE_CM) != USBMODE_DEVICE)
++ return IRQ_NONE;
++
++ val = readl(reg_base + CI_USBSTS);
++ int_mask = val & INTR_DUMMY_MASK;
++
++ if (int_mask == 0)
++ return IRQ_NONE;
++
++ /* Clear interrupts */
++ writel(int_mask, reg_base + CI_USBSTS);
++
++ /* clear hsm.b_conn here since host driver can't detect it
++ * otg_dummy_irq called means B-disconnect happened.
++ */
++ if (xotg->hsm.b_conn) {
++ xotg->hsm.b_conn = 0;
++ if (spin_trylock(&xotg->wq_lock)) {
++ xusbps_update_transceiver();
++ spin_unlock(&xotg->wq_lock);
++ }
++ }
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t otg_irq(int irq, void *_dev)
++{
++ struct xusbps_otg *xotg = _dev;
++ u32 int_sts, int_en;
++ u32 int_mask = 0;
++ int flag = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&xotg->lock, flags);
++ int_sts = readl(xotg->base + CI_OTGSC);
++ int_en = (int_sts & OTGSC_INTEN_MASK) >> 8;
++ int_mask = int_sts & int_en;
++
++ if (int_mask == 0) {
++ spin_unlock_irqrestore(&xotg->lock, flags);
++ return IRQ_NONE;
++ }
++
++ writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask,
++ xotg->base + CI_OTGSC);
++ if (int_mask & OTGSC_IDIS) {
++ dev_dbg(xotg->dev, "%s: id change int\n", __func__);
++ xotg->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0;
++ dev_dbg(xotg->dev, "id = %d\n", xotg->hsm.id);
++ flag = 1;
++ }
++ if (int_mask & OTGSC_DPIS) {
++ dev_dbg(xotg->dev, "%s: data pulse int\n", __func__);
++ if (xotg->otg.otg->default_a)
++ xotg->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0;
++ dev_dbg(xotg->dev, "data pulse = %d\n", xotg->hsm.a_srp_det);
++ flag = 1;
++ }
++ if (int_mask & OTGSC_BSEIS) {
++ dev_dbg(xotg->dev, "%s: b session end int\n", __func__);
++ if (!xotg->otg.otg->default_a)
++ xotg->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0;
++ dev_dbg(xotg->dev, "b_sess_end = %d\n", xotg->hsm.b_sess_end);
++ flag = 1;
++ }
++ if (int_mask & OTGSC_BSVIS) {
++ dev_dbg(xotg->dev, "%s: b session valid int\n", __func__);
++ if (!xotg->otg.otg->default_a)
++ xotg->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0;
++ dev_dbg(xotg->dev, "b_sess_vld = %d\n", xotg->hsm.b_sess_vld);
++ flag = 1;
++ }
++ if (int_mask & OTGSC_ASVIS) {
++ dev_dbg(xotg->dev, "%s: a session valid int\n", __func__);
++ if (xotg->otg.otg->default_a)
++ xotg->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0;
++ dev_dbg(xotg->dev, "a_sess_vld = %d\n", xotg->hsm.a_sess_vld);
++ flag = 1;
++ }
++ if (int_mask & OTGSC_AVVIS) {
++ dev_dbg(xotg->dev, "%s: a vbus valid int\n", __func__);
++ if (xotg->otg.otg->default_a)
++ xotg->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0;
++ dev_dbg(xotg->dev, "a_vbus_vld = %d\n", xotg->hsm.a_vbus_vld);
++ flag = 1;
++ }
++
++ if (int_mask & OTGSC_1MSS) {
++ /* need to schedule otg_work if any timer is expired */
++ if (xusbps_otg_tick_timer(&int_sts))
++ flag = 1;
++ }
++
++ if (flag)
++ xusbps_update_transceiver();
++
++ spin_unlock_irqrestore(&xotg->lock, flags);
++ return IRQ_HANDLED;
++}
++
++/**
++ * xotg_usbdev_notify - Notifier function called by usb core.
++ * @self: Pointer to notifier_block structure
++ * @action: action which caused the notifier function call.
++ * @dev: Pointer to the usb device structure.
++ *
++ * This function is a call back function used by usb core to notify
++ * device attach/detach events. This is used by OTG state machine.
++ *
++ * returns: Always returns NOTIFY_OK.
++ **/
++static int xotg_usbdev_notify(struct notifier_block *self,
++ unsigned long action, void *dev)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ struct usb_phy *otg = &xotg->otg;
++ unsigned long otg_port;
++ struct usb_device *udev_otg = NULL;
++ struct usb_device *udev;
++ u32 flag;
++
++ udev = (struct usb_device *)dev;
++
++ if (!otg->otg->host)
++ return NOTIFY_OK;
++
++ otg_port = otg->otg->host->otg_port;
++
++ if (otg->otg->host->root_hub)
++ udev_otg = usb_hub_find_child(otg->otg->host->root_hub,
++ otg_port - 1);
++
++ /* Not otg device notification */
++ if (udev != udev_otg)
++ return NOTIFY_OK;
++
++ switch (action) {
++ case USB_DEVICE_ADD:
++ if (xotg->otg.otg->default_a == 1)
++ xotg->hsm.b_conn = 1;
++ else
++ xotg->hsm.a_conn = 1;
++ flag = 1;
++ break;
++ case USB_DEVICE_REMOVE:
++ if (xotg->otg.otg->default_a == 1)
++ xotg->hsm.b_conn = 0;
++ else
++ xotg->hsm.a_conn = 0;
++ flag = 1;
++ break;
++ }
++ if (flag)
++ xusbps_update_transceiver();
++
++ return NOTIFY_OK;
++}
++
++static void xusbps_otg_work(struct work_struct *work)
++{
++ struct xusbps_otg *xotg;
++ int retval;
++
++ xotg = container_of(work, struct xusbps_otg, work);
++
++ dev_dbg(xotg->dev, "%s: old state = %s\n", __func__,
++ usb_otg_state_string(xotg->otg.state));
++
++ switch (xotg->otg.state) {
++ case OTG_STATE_UNDEFINED:
++ case OTG_STATE_B_IDLE:
++ if (!xotg->hsm.id) {
++ xusbps_otg_del_timer(b_srp_init_tmr);
++ del_timer_sync(&xotg->hsm_timer);
++
++ xotg->otg.otg->default_a = 1;
++ xotg->hsm.a_srp_det = 0;
++
++ xusbps_otg_chrg_vbus(0);
++ set_host_mode();
++ xusbps_otg_phy_low_power(1);
++
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ xusbps_update_transceiver();
++ } else if (xotg->hsm.b_sess_vld) {
++ xusbps_otg_del_timer(b_srp_init_tmr);
++ del_timer_sync(&xotg->hsm_timer);
++ xotg->hsm.b_bus_req = 0;
++ xotg->hsm.b_sess_end = 0;
++ xotg->hsm.a_bus_suspend = 0;
++ xusbps_otg_chrg_vbus(0);
++
++ if (xotg->start_peripheral) {
++ xotg->start_peripheral(&xotg->otg);
++ xotg->otg.state = OTG_STATE_B_PERIPHERAL;
++ } else
++ dev_dbg(xotg->dev,
++ "client driver not loaded\n");
++ } else if (xotg->hsm.b_srp_init_tmout) {
++ xotg->hsm.b_srp_init_tmout = 0;
++ dev_warn(xotg->dev, "SRP init timeout\n");
++ } else if (xotg->hsm.b_srp_fail_tmout) {
++ xotg->hsm.b_srp_fail_tmout = 0;
++ xotg->hsm.b_bus_req = 0;
++
++ /* No silence failure */
++ xusbps_otg_msg(6);
++ dev_warn(xotg->dev, "SRP failed\n");
++ } else if (xotg->hsm.b_bus_req && xotg->hsm.b_sess_end) {
++ del_timer_sync(&xotg->hsm_timer);
++ /* workaround for b_se0_srp detection */
++ retval = xusbps_otg_check_se0_srp(0);
++ if (retval) {
++ xotg->hsm.b_bus_req = 0;
++ dev_dbg(xotg->dev, "LS isn't SE0, try later\n");
++ } else {
++ /* clear the PHCD before start srp */
++ xusbps_otg_phy_low_power(0);
++
++ /* Start SRP */
++ xusbps_otg_add_timer(b_srp_init_tmr);
++ xotg->otg.otg->start_srp(xotg->otg.otg);
++ xusbps_otg_del_timer(b_srp_init_tmr);
++ xusbps_otg_add_ktimer(TB_SRP_FAIL_TMR);
++
++ /* reset PHY low power mode here */
++ xusbps_otg_phy_low_power_wait(1);
++ }
++ }
++ break;
++ case OTG_STATE_B_SRP_INIT:
++ if (!xotg->hsm.id) {
++ xotg->otg.otg->default_a = 1;
++ xotg->hsm.a_srp_det = 0;
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xusbps_otg_chrg_vbus(0);
++ set_host_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ xusbps_update_transceiver();
++ } else if (xotg->hsm.b_sess_vld) {
++ xusbps_otg_chrg_vbus(0);
++ if (xotg->start_peripheral) {
++ xotg->start_peripheral(&xotg->otg);
++ xotg->otg.state = OTG_STATE_B_PERIPHERAL;
++ } else
++ dev_dbg(xotg->dev,
++ "client driver not loaded\n");
++ }
++ break;
++ case OTG_STATE_B_PERIPHERAL:
++ if (!xotg->hsm.id) {
++ xotg->otg.otg->default_a = 1;
++ xotg->hsm.a_srp_det = 0;
++
++ xusbps_otg_chrg_vbus(0);
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ set_host_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.b_sess_vld) {
++ xotg->hsm.b_hnp_enable = 0;
++ xotg->hsm.b_bus_req = 0;
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ } else if (xotg->hsm.b_bus_req && xotg->otg.otg->gadget &&
++ xotg->otg.otg->gadget->b_hnp_enable &&
++ xotg->hsm.a_bus_suspend) {
++ dev_warn(xotg->dev, "HNP detected\n");
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ xusbps_otg_HAAR(1);
++ xotg->hsm.a_conn = 0;
++
++ xotg->otg.state = OTG_STATE_B_WAIT_ACON;
++ if (xotg->start_host) {
++ xotg->start_host(&xotg->otg);
++ } else
++ dev_dbg(xotg->dev,
++ "host driver not loaded.\n");
++
++ xotg->hsm.a_bus_resume = 0;
++ xusbps_otg_add_ktimer(TB_ASE0_BRST_TMR);
++ }
++ break;
++
++ case OTG_STATE_B_WAIT_ACON:
++ if (!xotg->hsm.id) {
++ /* delete hsm timer for b_ase0_brst_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ xotg->otg.otg->default_a = 1;
++ xotg->hsm.a_srp_det = 0;
++
++ xusbps_otg_chrg_vbus(0);
++
++ xusbps_otg_HAAR(0);
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ set_host_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.b_sess_vld) {
++ /* delete hsm timer for b_ase0_brst_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ xotg->hsm.b_hnp_enable = 0;
++ xotg->hsm.b_bus_req = 0;
++
++ xusbps_otg_chrg_vbus(0);
++ xusbps_otg_HAAR(0);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ set_client_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ } else if (xotg->hsm.a_conn) {
++ /* delete hsm timer for b_ase0_brst_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ xusbps_otg_HAAR(0);
++ xotg->otg.state = OTG_STATE_B_HOST;
++ xusbps_update_transceiver();
++ } else if (xotg->hsm.a_bus_resume ||
++ xotg->hsm.b_ase0_brst_tmout) {
++ dev_warn(xotg->dev, "A device connect failed\n");
++ /* delete hsm timer for b_ase0_brst_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ xusbps_otg_HAAR(0);
++ xusbps_otg_msg(7);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ xotg->hsm.a_bus_suspend = 0;
++ xotg->hsm.b_bus_req = 0;
++ xotg->otg.state = OTG_STATE_B_PERIPHERAL;
++ if (xotg->start_peripheral)
++ xotg->start_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver not loaded.\n");
++ }
++ break;
++
++ case OTG_STATE_B_HOST:
++ if (!xotg->hsm.id) {
++ xotg->otg.otg->default_a = 1;
++ xotg->hsm.a_srp_det = 0;
++
++ xusbps_otg_chrg_vbus(0);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ set_host_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.b_sess_vld) {
++ xotg->hsm.b_hnp_enable = 0;
++ xotg->hsm.b_bus_req = 0;
++
++ xusbps_otg_chrg_vbus(0);
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ set_client_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ } else if ((!xotg->hsm.b_bus_req) ||
++ (!xotg->hsm.a_conn)) {
++ xotg->hsm.b_bus_req = 0;
++ xusbps_otg_loc_sof(0);
++
++ /* Fix: The kernel crash in usb_port_suspend
++ during HNP */
++ msleep(20);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ xotg->hsm.a_bus_suspend = 0;
++ xotg->otg.state = OTG_STATE_B_PERIPHERAL;
++ if (xotg->start_peripheral)
++ xotg->start_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver not loaded.\n");
++ }
++ break;
++
++ case OTG_STATE_A_IDLE:
++ xotg->otg.otg->default_a = 1;
++ if (xotg->hsm.id) {
++ xotg->otg.otg->default_a = 0;
++ xotg->hsm.b_bus_req = 0;
++ xotg->hsm.vbus_srp_up = 0;
++
++ xusbps_otg_chrg_vbus(0);
++ set_client_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.a_bus_drop &&
++ (xotg->hsm.a_srp_det || xotg->hsm.a_bus_req)) {
++ dev_warn(xotg->dev,
++ "SRP detected or User has requested for the Bus\n");
++ xusbps_otg_phy_low_power(0);
++
++ /* Turn on VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, true);
++
++ xotg->hsm.vbus_srp_up = 0;
++ xotg->hsm.a_wait_vrise_tmout = 0;
++ xusbps_otg_add_timer(a_wait_vrise_tmr);
++ xotg->otg.state = OTG_STATE_A_WAIT_VRISE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.a_bus_drop && xotg->hsm.a_sess_vld) {
++ xotg->hsm.vbus_srp_up = 1;
++ } else if (!xotg->hsm.a_sess_vld && xotg->hsm.vbus_srp_up) {
++ msleep(10);
++ xusbps_otg_phy_low_power(0);
++
++ /* Turn on VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, true);
++ xotg->hsm.a_srp_det = 1;
++ xotg->hsm.vbus_srp_up = 0;
++ xotg->hsm.a_wait_vrise_tmout = 0;
++ xusbps_otg_add_timer(a_wait_vrise_tmr);
++ xotg->otg.state = OTG_STATE_A_WAIT_VRISE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.a_sess_vld &&
++ !xotg->hsm.vbus_srp_up) {
++ xusbps_otg_phy_low_power(1);
++ }
++ break;
++ case OTG_STATE_A_WAIT_VRISE:
++ if (xotg->hsm.id) {
++ xusbps_otg_del_timer(a_wait_vrise_tmr);
++ xotg->hsm.b_bus_req = 0;
++ xotg->otg.otg->default_a = 0;
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ set_client_mode();
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ } else if (xotg->hsm.a_vbus_vld) {
++ xusbps_otg_del_timer(a_wait_vrise_tmr);
++ xotg->hsm.b_conn = 0;
++ if (xotg->start_host)
++ xotg->start_host(&xotg->otg);
++ else {
++ dev_dbg(xotg->dev, "host driver not loaded.\n");
++ break;
++ }
++ xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR);
++ xotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ } else if (xotg->hsm.a_wait_vrise_tmout) {
++ xotg->hsm.b_conn = 0;
++ if (xotg->hsm.a_vbus_vld) {
++ if (xotg->start_host)
++ xotg->start_host(&xotg->otg);
++ else {
++ dev_dbg(xotg->dev,
++ "host driver not loaded.\n");
++ break;
++ }
++ xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR);
++ xotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ } else {
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ }
++ }
++ break;
++ case OTG_STATE_A_WAIT_BCON:
++ if (xotg->hsm.id) {
++ /* delete hsm timer for a_wait_bcon_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ xotg->otg.otg->default_a = 0;
++ xotg->hsm.b_bus_req = 0;
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ set_client_mode();
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.a_vbus_vld) {
++ /* delete hsm timer for a_wait_bcon_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ } else if (xotg->hsm.a_bus_drop ||
++ (xotg->hsm.a_wait_bcon_tmout &&
++ !xotg->hsm.a_bus_req)) {
++ dev_warn(xotg->dev, "B connect timeout\n");
++ /* delete hsm timer for a_wait_bcon_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (xotg->hsm.b_conn) {
++ /* delete hsm timer for a_wait_bcon_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ xotg->hsm.a_suspend_req = 0;
++ /* Make it zero as it should not be used by driver */
++ xotg->hsm.a_bus_req = 0;
++ xotg->hsm.a_srp_det = 0;
++ xotg->otg.state = OTG_STATE_A_HOST;
++ }
++ break;
++ case OTG_STATE_A_HOST:
++ if (xotg->hsm.id) {
++ xotg->otg.otg->default_a = 0;
++ xotg->hsm.b_bus_req = 0;
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ set_client_mode();
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ xusbps_update_transceiver();
++ } else if (xotg->hsm.a_bus_drop ||
++ (xotg->otg.otg->host &&
++ !xotg->otg.otg->host->b_hnp_enable &&
++ !xotg->hsm.a_bus_req)) {
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (!xotg->hsm.a_vbus_vld) {
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ } else if (xotg->otg.otg->host &&
++ xotg->otg.otg->host->b_hnp_enable &&
++ (!xotg->hsm.a_bus_req ||
++ xotg->hsm.a_suspend_req)) {
++ /* Set HABA to enable hardware assistance to signal
++ * A-connect after receiver B-disconnect. Hardware
++ * will then set client mode and enable URE, SLE and
++ * PCE after the assistance. otg_dummy_irq is used to
++ * clean these ints when client driver is not resumed.
++ */
++ if (request_irq(xotg->irq, otg_dummy_irq, IRQF_SHARED,
++ driver_name, xotg->base) != 0) {
++ dev_dbg(xotg->dev,
++ "request interrupt %d failed\n",
++ xotg->irq);
++ }
++ /* set HABA */
++ xusbps_otg_HABA(1);
++ xotg->hsm.b_bus_resume = 0;
++ xotg->hsm.a_aidl_bdis_tmout = 0;
++ xusbps_otg_loc_sof(0);
++ /* clear PHCD to enable HW timer */
++ xusbps_otg_phy_low_power(0);
++ xusbps_otg_add_timer(a_aidl_bdis_tmr);
++ xotg->otg.state = OTG_STATE_A_SUSPEND;
++ } else if (!xotg->hsm.b_conn || !xotg->hsm.a_bus_req) {
++ xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR);
++ xotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ }
++ break;
++ case OTG_STATE_A_SUSPEND:
++ if (xotg->hsm.id) {
++ xusbps_otg_del_timer(a_aidl_bdis_tmr);
++ xusbps_otg_HABA(0);
++ free_irq(xotg->irq, xotg->base);
++ xotg->otg.otg->default_a = 0;
++ xotg->hsm.b_bus_req = 0;
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ set_client_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ xusbps_update_transceiver();
++ } else if (xotg->hsm.a_bus_req ||
++ xotg->hsm.b_bus_resume) {
++ xusbps_otg_del_timer(a_aidl_bdis_tmr);
++ xusbps_otg_HABA(0);
++ free_irq(xotg->irq, xotg->base);
++ xotg->hsm.a_suspend_req = 0;
++ xusbps_otg_loc_sof(1);
++ xotg->otg.state = OTG_STATE_A_HOST;
++ } else if (xotg->hsm.a_aidl_bdis_tmout ||
++ xotg->hsm.a_bus_drop) {
++ dev_warn(xotg->dev, "B disconnect timeout\n");
++ xusbps_otg_del_timer(a_aidl_bdis_tmr);
++ xusbps_otg_HABA(0);
++ free_irq(xotg->irq, xotg->base);
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (!xotg->hsm.b_conn && xotg->otg.otg->host &&
++ xotg->otg.otg->host->b_hnp_enable) {
++ xusbps_otg_del_timer(a_aidl_bdis_tmr);
++ xusbps_otg_HABA(0);
++ free_irq(xotg->irq, xotg->base);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ xotg->hsm.b_bus_suspend = 0;
++ xotg->hsm.b_bus_suspend_vld = 0;
++
++ xotg->otg.state = OTG_STATE_A_PERIPHERAL;
++ /* msleep(200); */
++ if (xotg->start_peripheral)
++ xotg->start_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver not loaded.\n");
++ xusbps_otg_add_ktimer(TB_BUS_SUSPEND_TMR);
++ break;
++ } else if (!xotg->hsm.a_vbus_vld) {
++ xusbps_otg_del_timer(a_aidl_bdis_tmr);
++ xusbps_otg_HABA(0);
++ free_irq(xotg->irq, xotg->base);
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ }
++ break;
++ case OTG_STATE_A_PERIPHERAL:
++ if (xotg->hsm.id) {
++ /* delete hsm timer for b_bus_suspend_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++ xotg->otg.otg->default_a = 0;
++ xotg->hsm.b_bus_req = 0;
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ set_client_mode();
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ xusbps_update_transceiver();
++ } else if (!xotg->hsm.a_vbus_vld) {
++ /* delete hsm timer for b_bus_suspend_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xusbps_otg_phy_low_power_wait(1);
++ xotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ } else if (xotg->hsm.a_bus_drop) {
++ /* delete hsm timer for b_bus_suspend_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (xotg->hsm.b_bus_suspend) {
++ dev_warn(xotg->dev, "HNP detected\n");
++ /* delete hsm timer for b_bus_suspend_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ xotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ if (xotg->start_host)
++ xotg->start_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver not loaded.\n");
++ xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR);
++ } else if (xotg->hsm.b_bus_suspend_tmout) {
++ u32 val;
++ val = readl(xotg->base + CI_PORTSC1);
++ if (!(val & PORTSC_SUSP))
++ break;
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "client driver has been removed.\n");
++
++ xotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ if (xotg->start_host)
++ xotg->start_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev,
++ "host driver not loaded.\n");
++ xusbps_otg_add_ktimer(TA_WAIT_BCON_TMR);
++ }
++ break;
++ case OTG_STATE_A_VBUS_ERR:
++ if (xotg->hsm.id) {
++ xotg->otg.otg->default_a = 0;
++ xotg->hsm.a_clr_err = 0;
++ xotg->hsm.a_srp_det = 0;
++ set_client_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ xusbps_update_transceiver();
++ } else if (xotg->hsm.a_clr_err) {
++ xotg->hsm.a_clr_err = 0;
++ xotg->hsm.a_srp_det = 0;
++ reset_otg();
++ init_hsm();
++ if (xotg->otg.state == OTG_STATE_A_IDLE)
++ xusbps_update_transceiver();
++ } else {
++ /* FW will clear PHCD bit when any VBus
++ * event detected. Reset PHCD to 1 again */
++ xusbps_otg_phy_low_power(1);
++ }
++ break;
++ case OTG_STATE_A_WAIT_VFALL:
++ if (xotg->hsm.id) {
++ xotg->otg.otg->default_a = 0;
++ set_client_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ xusbps_update_transceiver();
++ } else if (xotg->hsm.a_bus_req) {
++
++ /* Turn on VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, true);
++ xotg->hsm.a_wait_vrise_tmout = 0;
++ xusbps_otg_add_timer(a_wait_vrise_tmr);
++ xotg->otg.state = OTG_STATE_A_WAIT_VRISE;
++ } else if (!xotg->hsm.a_sess_vld) {
++ xotg->hsm.a_srp_det = 0;
++ set_host_mode();
++ xusbps_otg_phy_low_power(1);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ }
++ break;
++ default:
++ break;
++ }
++
++ dev_dbg(xotg->dev, "%s: new state = %s\n", __func__,
++ usb_otg_state_string(xotg->otg.state));
++}
++
++static ssize_t
++show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size,
++ "\n"
++ "USBCMD = 0x%08x\n"
++ "USBSTS = 0x%08x\n"
++ "USBINTR = 0x%08x\n"
++ "ASYNCLISTADDR = 0x%08x\n"
++ "PORTSC1 = 0x%08x\n"
++ "OTGSC = 0x%08x\n"
++ "USBMODE = 0x%08x\n",
++ readl(xotg->base + 0x140),
++ readl(xotg->base + 0x144),
++ readl(xotg->base + 0x148),
++ readl(xotg->base + 0x158),
++ readl(xotg->base + 0x184),
++ readl(xotg->base + 0x1a4),
++ readl(xotg->base + 0x1a8)
++ );
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
++
++static ssize_t
++show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ if (xotg->otg.otg->host)
++ xotg->hsm.a_set_b_hnp_en = xotg->otg.otg->host->b_hnp_enable;
++
++ if (xotg->otg.otg->gadget)
++ xotg->hsm.b_hnp_enable = xotg->otg.otg->gadget->b_hnp_enable;
++
++ t = scnprintf(next, size,
++ "\n"
++ "current state = %s\n"
++ "a_bus_resume = \t%d\n"
++ "a_bus_suspend = \t%d\n"
++ "a_conn = \t%d\n"
++ "a_sess_vld = \t%d\n"
++ "a_srp_det = \t%d\n"
++ "a_vbus_vld = \t%d\n"
++ "b_bus_resume = \t%d\n"
++ "b_bus_suspend = \t%d\n"
++ "b_conn = \t%d\n"
++ "b_se0_srp = \t%d\n"
++ "b_sess_end = \t%d\n"
++ "b_sess_vld = \t%d\n"
++ "id = \t%d\n"
++ "a_set_b_hnp_en = \t%d\n"
++ "b_srp_done = \t%d\n"
++ "b_hnp_enable = \t%d\n"
++ "a_wait_vrise_tmout = \t%d\n"
++ "a_wait_bcon_tmout = \t%d\n"
++ "a_aidl_bdis_tmout = \t%d\n"
++ "b_ase0_brst_tmout = \t%d\n"
++ "a_bus_drop = \t%d\n"
++ "a_bus_req = \t%d\n"
++ "a_clr_err = \t%d\n"
++ "a_suspend_req = \t%d\n"
++ "b_bus_req = \t%d\n"
++ "b_bus_suspend_tmout = \t%d\n"
++ "b_bus_suspend_vld = \t%d\n",
++ usb_otg_state_string(xotg->otg.state),
++ xotg->hsm.a_bus_resume,
++ xotg->hsm.a_bus_suspend,
++ xotg->hsm.a_conn,
++ xotg->hsm.a_sess_vld,
++ xotg->hsm.a_srp_det,
++ xotg->hsm.a_vbus_vld,
++ xotg->hsm.b_bus_resume,
++ xotg->hsm.b_bus_suspend,
++ xotg->hsm.b_conn,
++ xotg->hsm.b_se0_srp,
++ xotg->hsm.b_sess_end,
++ xotg->hsm.b_sess_vld,
++ xotg->hsm.id,
++ xotg->hsm.a_set_b_hnp_en,
++ xotg->hsm.b_srp_done,
++ xotg->hsm.b_hnp_enable,
++ xotg->hsm.a_wait_vrise_tmout,
++ xotg->hsm.a_wait_bcon_tmout,
++ xotg->hsm.a_aidl_bdis_tmout,
++ xotg->hsm.b_ase0_brst_tmout,
++ xotg->hsm.a_bus_drop,
++ xotg->hsm.a_bus_req,
++ xotg->hsm.a_clr_err,
++ xotg->hsm.a_suspend_req,
++ xotg->hsm.b_bus_req,
++ xotg->hsm.b_bus_suspend_tmout,
++ xotg->hsm.b_bus_suspend_vld
++ );
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL);
++
++static ssize_t
++get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size, "%d", xotg->hsm.a_bus_req);
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static ssize_t
++set_a_bus_req(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ if (!xotg->otg.otg->default_a)
++ return -1;
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '0') {
++ xotg->hsm.a_bus_req = 0;
++ dev_dbg(xotg->dev, "User request: a_bus_req = 0\n");
++ } else if (buf[0] == '1') {
++ /* If a_bus_drop is TRUE, a_bus_req can't be set */
++ if (xotg->hsm.a_bus_drop)
++ return -1;
++ xotg->hsm.a_bus_req = 1;
++ dev_dbg(xotg->dev, "User request: a_bus_req = 1\n");
++ }
++ if (spin_trylock(&xotg->wq_lock)) {
++ xusbps_update_transceiver();
++ spin_unlock(&xotg->wq_lock);
++ }
++ return count;
++}
++static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req);
++
++static ssize_t
++get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size, "%d", xotg->hsm.a_bus_drop);
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static ssize_t
++set_a_bus_drop(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ if (!xotg->otg.otg->default_a)
++ return -1;
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '0') {
++ xotg->hsm.a_bus_drop = 0;
++ dev_dbg(xotg->dev, "User request: a_bus_drop = 0\n");
++ } else if (buf[0] == '1') {
++ xotg->hsm.a_bus_drop = 1;
++ xotg->hsm.a_bus_req = 0;
++ dev_dbg(xotg->dev, "User request: a_bus_drop = 1\n");
++ dev_dbg(xotg->dev, "User request: and a_bus_req = 0\n");
++ }
++ if (spin_trylock(&xotg->wq_lock)) {
++ xusbps_update_transceiver();
++ spin_unlock(&xotg->wq_lock);
++ }
++ return count;
++}
++static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop,
++ set_a_bus_drop);
++
++static ssize_t
++get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size, "%d", xotg->hsm.b_bus_req);
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static ssize_t
++set_b_bus_req(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ if (xotg->otg.otg->default_a)
++ return -1;
++
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '0') {
++ xotg->hsm.b_bus_req = 0;
++ dev_dbg(xotg->dev, "User request: b_bus_req = 0\n");
++ } else if (buf[0] == '1') {
++ xotg->hsm.b_bus_req = 1;
++ dev_dbg(xotg->dev, "User request: b_bus_req = 1\n");
++ }
++ if (spin_trylock(&xotg->wq_lock)) {
++ xusbps_update_transceiver();
++ spin_unlock(&xotg->wq_lock);
++ }
++ return count;
++}
++static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req);
++
++static ssize_t
++set_a_clr_err(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ if (!xotg->otg.otg->default_a)
++ return -1;
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '1') {
++ xotg->hsm.a_clr_err = 1;
++ dev_dbg(xotg->dev, "User request: a_clr_err = 1\n");
++ }
++ if (spin_trylock(&xotg->wq_lock)) {
++ xusbps_update_transceiver();
++ spin_unlock(&xotg->wq_lock);
++ }
++ return count;
++}
++static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
++
++/**
++ * suspend_otg_device - suspend the otg device.
++ *
++ * @otg: Pointer to the otg transceiver structure.
++ *
++ * This function suspends usb devices connected to the otg port
++ * of the host controller.
++ *
++ * returns: 0 on success or error value on failure
++ **/
++static int suspend_otg_device(struct usb_phy *otg)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ unsigned long otg_port = otg->otg->host->otg_port;
++ struct usb_device *udev;
++ int err;
++
++ udev = usb_hub_find_child(otg->otg->host->root_hub, otg_port - 1);
++
++ if (udev) {
++ err = usb_port_suspend(udev, PMSG_SUSPEND);
++ if (err < 0)
++ dev_dbg(xotg->dev, "HNP fail, %d\n", err);
++
++ /* Change the state of the usb device if HNP is successful */
++ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
++ } else {
++ err = -ENODEV;
++ dev_dbg(xotg->dev, "No device connected to roothub\n");
++ }
++ return err;
++}
++
++static ssize_t
++do_hnp(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++ unsigned long ret;
++
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '1') {
++ if (xotg->otg.otg->default_a && xotg->otg.otg->host &&
++ xotg->otg.otg->host->b_hnp_enable &&
++ (xotg->otg.state == OTG_STATE_A_HOST)) {
++ ret = suspend_otg_device(&xotg->otg);
++ if (ret)
++ return -1;
++ }
++
++ if (!xotg->otg.otg->default_a && xotg->otg.otg->host &&
++ xotg->hsm.b_bus_req) {
++ ret = suspend_otg_device(&xotg->otg);
++ if (ret)
++ return -1;
++ }
++ }
++ return count;
++}
++static DEVICE_ATTR(do_hnp, S_IWUSR, NULL, do_hnp);
++
++static int xusbps_otg_clk_notifier_cb(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++
++ switch (event) {
++ case PRE_RATE_CHANGE:
++ /* if a rate change is announced we need to check whether we can
++ * maintain the current frequency by changing the clock
++ * dividers.
++ */
++ /* fall through */
++ case POST_RATE_CHANGE:
++ return NOTIFY_OK;
++ case ABORT_RATE_CHANGE:
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
++static struct attribute *inputs_attrs[] = {
++ &dev_attr_a_bus_req.attr,
++ &dev_attr_a_bus_drop.attr,
++ &dev_attr_b_bus_req.attr,
++ &dev_attr_a_clr_err.attr,
++ &dev_attr_do_hnp.attr,
++ NULL,
++};
++
++static struct attribute_group debug_dev_attr_group = {
++ .name = "inputs",
++ .attrs = inputs_attrs,
++};
++
++static int xusbps_otg_remove(struct platform_device *pdev)
++{
++ struct xusbps_otg *xotg = the_transceiver;
++
++ if (xotg->qwork) {
++ flush_workqueue(xotg->qwork);
++ destroy_workqueue(xotg->qwork);
++ }
++ xusbps_otg_free_timers();
++
++ /* disable OTGSC interrupt as OTGSC doesn't change in reset */
++ writel(0, xotg->base + CI_OTGSC);
++
++ usb_remove_phy(&xotg->otg);
++ sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group);
++ device_remove_file(&pdev->dev, &dev_attr_hsm);
++ device_remove_file(&pdev->dev, &dev_attr_registers);
++ clk_notifier_unregister(xotg->clk, &xotg->clk_rate_change_nb);
++ clk_disable_unprepare(xotg->clk);
++
++ return 0;
++}
++
++static int xusbps_otg_probe(struct platform_device *pdev)
++{
++ int retval;
++ u32 val32;
++ struct xusbps_otg *xotg;
++ char qname[] = "xusbps_otg_queue";
++ struct xusbps_usb2_platform_data *pdata;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata)
++ return -ENODEV;
++
++ dev_dbg(&pdev->dev, "\notg controller is detected.\n");
++
++ xotg = devm_kzalloc(&pdev->dev, sizeof(*xotg), GFP_KERNEL);
++ if (xotg == NULL)
++ return -ENOMEM;
++
++ the_transceiver = xotg;
++
++ /* Setup ulpi phy for OTG */
++ xotg->ulpi = pdata->ulpi;
++
++ xotg->otg.otg = devm_kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
++ if (!xotg->otg.otg)
++ return -ENOMEM;
++
++ xotg->base = pdata->regs;
++ xotg->irq = pdata->irq;
++ if (!xotg->base || !xotg->irq) {
++ retval = -ENODEV;
++ goto err;
++ }
++
++ xotg->qwork = create_singlethread_workqueue(qname);
++ if (!xotg->qwork) {
++ dev_dbg(&pdev->dev, "cannot create workqueue %s\n", qname);
++ retval = -ENOMEM;
++ goto err;
++ }
++ INIT_WORK(&xotg->work, xusbps_otg_work);
++
++ xotg->clk = pdata->clk;
++ retval = clk_prepare_enable(xotg->clk);
++ if (retval) {
++ dev_err(&pdev->dev, "Unable to enable APER clock.\n");
++ goto err;
++ }
++
++ xotg->clk_rate_change_nb.notifier_call = xusbps_otg_clk_notifier_cb;
++ xotg->clk_rate_change_nb.next = NULL;
++ if (clk_notifier_register(xotg->clk, &xotg->clk_rate_change_nb))
++ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
++
++ /* OTG common part */
++ xotg->dev = &pdev->dev;
++ xotg->otg.dev = xotg->dev;
++ xotg->otg.label = driver_name;
++ xotg->otg.otg->set_host = xusbps_otg_set_host;
++ xotg->otg.otg->set_peripheral = xusbps_otg_set_peripheral;
++ xotg->otg.set_power = xusbps_otg_set_power;
++ xotg->otg.otg->set_vbus = xusbps_otg_set_vbus;
++ xotg->otg.otg->start_srp = xusbps_otg_start_srp;
++ xotg->otg.otg->start_hnp = xusbps_otg_start_hnp;
++ xotg->otg.state = OTG_STATE_UNDEFINED;
++
++ if (usb_add_phy(&xotg->otg, USB_PHY_TYPE_USB2)) {
++ dev_dbg(xotg->dev, "can't set transceiver\n");
++ retval = -EBUSY;
++ goto err_out_clk_disable;
++ }
++
++ pdata->otg = &xotg->otg;
++ reset_otg();
++ init_hsm();
++
++ spin_lock_init(&xotg->lock);
++ spin_lock_init(&xotg->wq_lock);
++ INIT_LIST_HEAD(&active_timers);
++ retval = xusbps_otg_init_timers(&xotg->hsm);
++ if (retval) {
++ dev_dbg(&pdev->dev, "Failed to init timers\n");
++ goto err_out_clk_disable;
++ }
++
++ init_timer(&xotg->hsm_timer);
++
++ xotg->xotg_notifier.notifier_call = xotg_usbdev_notify;
++ usb_register_notify((struct notifier_block *)
++ &xotg->xotg_notifier.notifier_call);
++
++ retval = devm_request_irq(&pdev->dev, xotg->irq, otg_irq, IRQF_SHARED,
++ driver_name, xotg);
++ if (retval) {
++ dev_dbg(xotg->dev, "request interrupt %d failed\n", xotg->irq);
++ retval = -EBUSY;
++ goto err_out_clk_disable;
++ }
++
++ /* enable OTGSC int */
++ val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE |
++ OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU;
++ writel(val32, xotg->base + CI_OTGSC);
++
++ retval = device_create_file(&pdev->dev, &dev_attr_registers);
++ if (retval < 0) {
++ dev_dbg(xotg->dev,
++ "Can't register sysfs attribute: %d\n", retval);
++ goto err_out_clk_disable;
++ }
++
++ retval = device_create_file(&pdev->dev, &dev_attr_hsm);
++ if (retval < 0) {
++ dev_dbg(xotg->dev, "Can't hsm sysfs attribute: %d\n", retval);
++ goto err_out_clk_disable;
++ }
++
++ retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group);
++ if (retval < 0) {
++ dev_dbg(xotg->dev,
++ "Can't register sysfs attr group: %d\n", retval);
++ goto err_out_clk_disable;
++ }
++
++ if (xotg->otg.state == OTG_STATE_A_IDLE)
++ xusbps_update_transceiver();
++
++ return 0;
++
++err_out_clk_disable:
++ clk_notifier_unregister(xotg->clk, &xotg->clk_rate_change_nb);
++ clk_disable_unprepare(xotg->clk);
++err:
++ xusbps_otg_remove(pdev);
++
++ return retval;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static void transceiver_suspend(struct platform_device *pdev)
++{
++ xusbps_otg_phy_low_power(1);
++}
++
++static int xusbps_otg_suspend(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct xusbps_otg *xotg = the_transceiver;
++ int ret = 0;
++
++ /* Disbale OTG interrupts */
++ xusbps_otg_intr(0);
++
++ if (xotg->irq)
++ free_irq(xotg->irq, xotg);
++
++ /* Prevent more otg_work */
++ flush_workqueue(xotg->qwork);
++ destroy_workqueue(xotg->qwork);
++ xotg->qwork = NULL;
++
++ /* start actions */
++ switch (xotg->otg.state) {
++ case OTG_STATE_A_WAIT_VFALL:
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ case OTG_STATE_A_IDLE:
++ case OTG_STATE_B_IDLE:
++ case OTG_STATE_A_VBUS_ERR:
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_A_WAIT_VRISE:
++ xusbps_otg_del_timer(a_wait_vrise_tmr);
++ xotg->hsm.a_srp_det = 0;
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_A_WAIT_BCON:
++ del_timer_sync(&xotg->hsm_timer);
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(&pdev->dev, "host driver has been removed.\n");
++
++ xotg->hsm.a_srp_det = 0;
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_A_HOST:
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(&pdev->dev, "host driver has been removed.\n");
++
++ xotg->hsm.a_srp_det = 0;
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_A_SUSPEND:
++ xusbps_otg_del_timer(a_aidl_bdis_tmr);
++ xusbps_otg_HABA(0);
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(xotg->dev, "host driver has been removed.\n");
++ xotg->hsm.a_srp_det = 0;
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_A_PERIPHERAL:
++ del_timer_sync(&xotg->hsm_timer);
++
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(&pdev->dev,
++ "client driver has been removed.\n");
++ xotg->hsm.a_srp_det = 0;
++
++ /* Turn off VBus */
++ xotg->otg.otg->set_vbus(xotg->otg.otg, false);
++ xotg->otg.state = OTG_STATE_A_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_B_HOST:
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(&pdev->dev, "host driver has been removed.\n");
++ xotg->hsm.b_bus_req = 0;
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_B_PERIPHERAL:
++ if (xotg->stop_peripheral)
++ xotg->stop_peripheral(&xotg->otg);
++ else
++ dev_dbg(&pdev->dev,
++ "client driver has been removed.\n");
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ case OTG_STATE_B_WAIT_ACON:
++ /* delete hsm timer for b_ase0_brst_tmr */
++ del_timer_sync(&xotg->hsm_timer);
++
++ xusbps_otg_HAAR(0);
++
++ if (xotg->stop_host)
++ xotg->stop_host(&xotg->otg);
++ else
++ dev_dbg(&pdev->dev, "host driver has been removed.\n");
++ xotg->hsm.b_bus_req = 0;
++ xotg->otg.state = OTG_STATE_B_IDLE;
++ transceiver_suspend(pdev);
++ break;
++ default:
++ dev_dbg(xotg->dev, "error state before suspend\n");
++ break;
++ }
++
++ if (!ret)
++ clk_disable(xotg->clk);
++ return ret;
++}
++
++static void transceiver_resume(struct platform_device *pdev)
++{
++ /* Not used */
++}
++
++static int xusbps_otg_resume(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct xusbps_otg *xotg = the_transceiver;
++ int ret = 0;
++
++ ret = clk_enable(xotg->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot enable clock. resume failed.\n");
++ return ret;
++ }
++
++ transceiver_resume(pdev);
++
++ xotg->qwork = create_singlethread_workqueue("xusbps_otg_queue");
++ if (!xotg->qwork) {
++ dev_dbg(&pdev->dev, "cannot create xusbps otg workqueuen");
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ if (request_irq(xotg->irq, otg_irq, IRQF_SHARED,
++ driver_name, xotg) != 0) {
++ dev_dbg(&pdev->dev, "request interrupt %d failed\n", xotg->irq);
++ ret = -EBUSY;
++ goto error;
++ }
++
++ /* enable OTG interrupts */
++ xusbps_otg_intr(1);
++
++ update_hsm();
++
++ xusbps_update_transceiver();
++
++ return ret;
++error:
++ xusbps_otg_intr(0);
++ transceiver_suspend(pdev);
++ return ret;
++}
++
++static const struct dev_pm_ops xusbps_otg_dev_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(xusbps_otg_suspend, xusbps_otg_resume)
++};
++#define XUSBPS_OTG_PM (&xusbps_otg_dev_pm_ops)
++
++#else /* ! CONFIG_PM_SLEEP */
++#define XUSBPS_OTG_PM NULL
++#endif /* ! CONFIG_PM_SLEEP */
++
++#ifndef CONFIG_USB_XUSBPS_DR_OF
++static struct platform_driver xusbps_otg_driver = {
++#else
++struct platform_driver xusbps_otg_driver = {
++#endif
++ .probe = xusbps_otg_probe,
++ .remove = xusbps_otg_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = DRIVER_NAME,
++ .pm = XUSBPS_OTG_PM,
++ },
++};
++
++#ifndef CONFIG_USB_XUSBPS_DR_OF
++module_platform_driver(xusbps_otg_driver);
++#endif
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_DESCRIPTION("Xilinx PS USB OTG driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRIVER_NAME);
+--- /dev/null
++++ b/include/linux/usb/xilinx_usbps_otg.h
+@@ -0,0 +1,216 @@
++/*
++ * Xilinx PS USB OTG Driver Header file.
++ *
++ * Copyright 2011 Xilinx, Inc.
++ *
++ * This file is based on langwell_otg.h file with few minor modifications
++ * to support Xilinx PS USB controller.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#ifndef __XILINX_XUSBPS_OTG_H
++#define __XILINX_XUSBPS_OTG_H
++
++#define CI_USBCMD 0x140
++# define USBCMD_RST BIT(1)
++# define USBCMD_RS BIT(0)
++#define CI_USBSTS 0x144
++# define USBSTS_SLI BIT(8)
++# define USBSTS_URI BIT(6)
++# define USBSTS_PCI BIT(2)
++#define CI_PORTSC1 0x184
++# define PORTSC_PP BIT(12)
++# define PORTSC_LS (BIT(11) | BIT(10))
++# define PORTSC_SUSP BIT(7)
++# define PORTSC_CCS BIT(0)
++#define CI_OTGSC 0x1a4
++# define OTGSC_DPIE BIT(30)
++# define OTGSC_1MSE BIT(29)
++# define OTGSC_BSEIE BIT(28)
++# define OTGSC_BSVIE BIT(27)
++# define OTGSC_ASVIE BIT(26)
++# define OTGSC_AVVIE BIT(25)
++# define OTGSC_IDIE BIT(24)
++# define OTGSC_DPIS BIT(22)
++# define OTGSC_1MSS BIT(21)
++# define OTGSC_BSEIS BIT(20)
++# define OTGSC_BSVIS BIT(19)
++# define OTGSC_ASVIS BIT(18)
++# define OTGSC_AVVIS BIT(17)
++# define OTGSC_IDIS BIT(16)
++# define OTGSC_DPS BIT(14)
++# define OTGSC_1MST BIT(13)
++# define OTGSC_BSE BIT(12)
++# define OTGSC_BSV BIT(11)
++# define OTGSC_ASV BIT(10)
++# define OTGSC_AVV BIT(9)
++# define OTGSC_ID BIT(8)
++# define OTGSC_HABA BIT(7)
++# define OTGSC_HADP BIT(6)
++# define OTGSC_IDPU BIT(5)
++# define OTGSC_DP BIT(4)
++# define OTGSC_OT BIT(3)
++# define OTGSC_HAAR BIT(2)
++# define OTGSC_VC BIT(1)
++# define OTGSC_VD BIT(0)
++# define OTGSC_INTEN_MASK (0x7f << 24)
++# define OTGSC_INT_MASK (0x5f << 24)
++# define OTGSC_INTSTS_MASK (0x7f << 16)
++#define CI_USBMODE 0x1a8
++# define USBMODE_CM (BIT(1) | BIT(0))
++# define USBMODE_IDLE 0
++# define USBMODE_DEVICE 0x2
++# define USBMODE_HOST 0x3
++
++#define INTR_DUMMY_MASK (USBSTS_SLI | USBSTS_URI | USBSTS_PCI)
++
++enum xusbps_otg_timer_type {
++ TA_WAIT_VRISE_TMR,
++ TA_WAIT_BCON_TMR,
++ TA_AIDL_BDIS_TMR,
++ TB_ASE0_BRST_TMR,
++ TB_SE0_SRP_TMR,
++ TB_SRP_INIT_TMR,
++ TB_SRP_FAIL_TMR,
++ TB_BUS_SUSPEND_TMR
++};
++
++#define TA_WAIT_VRISE 100
++#define TA_WAIT_BCON 30000
++#define TA_AIDL_BDIS 15000
++#define TB_ASE0_BRST 5000
++#define TB_SE0_SRP 2
++#define TB_SRP_INIT 100
++#define TB_SRP_FAIL 5500
++#define TB_BUS_SUSPEND 500
++
++struct xusbps_otg_timer {
++ unsigned long expires; /* Number of count increase to timeout */
++ unsigned long count; /* Tick counter */
++ void (*function)(unsigned long); /* Timeout function */
++ unsigned long data; /* Data passed to function */
++ struct list_head list;
++};
++
++/* This is a common data structure to
++ * save values of the OTG state machine */
++struct otg_hsm {
++ /* Input */
++ int a_bus_resume;
++ int a_bus_suspend;
++ int a_conn;
++ int a_sess_vld;
++ int a_srp_det;
++ int a_vbus_vld;
++ int b_bus_resume;
++ int b_bus_suspend;
++ int b_conn;
++ int b_se0_srp;
++ int b_ssend_srp;
++ int b_sess_end;
++ int b_sess_vld;
++ int id;
++/* id values */
++#define ID_B 0x05
++#define ID_A 0x04
++#define ID_ACA_C 0x03
++#define ID_ACA_B 0x02
++#define ID_ACA_A 0x01
++ int power_up;
++ int adp_change;
++ int test_device;
++
++ /* Internal variables */
++ int a_set_b_hnp_en;
++ int b_srp_done;
++ int b_hnp_enable;
++ int hnp_poll_enable;
++
++ /* Timeout indicator for timers */
++ int a_wait_vrise_tmout;
++ int a_wait_bcon_tmout;
++ int a_aidl_bdis_tmout;
++ int a_bidl_adis_tmout;
++ int a_bidl_adis_tmr;
++ int a_wait_vfall_tmout;
++ int b_ase0_brst_tmout;
++ int b_bus_suspend_tmout;
++ int b_srp_init_tmout;
++ int b_srp_fail_tmout;
++ int b_srp_fail_tmr;
++ int b_adp_sense_tmout;
++
++ /* Informative variables */
++ int a_bus_drop;
++ int a_bus_req;
++ int a_clr_err;
++ int b_bus_req;
++ int a_suspend_req;
++ int b_bus_suspend_vld;
++
++ /* Output */
++ int drv_vbus;
++ int loc_conn;
++ int loc_sof;
++
++ /* Others */
++ int vbus_srp_up;
++};
++
++struct xusbps_otg {
++ struct usb_phy otg;
++ struct usb_phy *ulpi;
++
++ struct otg_hsm hsm;
++
++ /* base address */
++ void __iomem *base;
++
++ /* irq */
++ int irq;
++
++ /* clk */
++ struct clk *clk;
++ struct notifier_block clk_rate_change_nb;
++
++ /* atomic notifier for interrupt context */
++ struct atomic_notifier_head otg_notifier;
++
++ /* start/stop USB Host function */
++ int (*start_host)(struct usb_phy *otg);
++ int (*stop_host)(struct usb_phy *otg);
++
++ /* start/stop USB Peripheral function */
++ int (*start_peripheral)(struct usb_phy *otg);
++ int (*stop_peripheral)(struct usb_phy *otg);
++
++ struct device *dev;
++
++ unsigned region;
++
++ struct work_struct work;
++ struct workqueue_struct *qwork;
++ struct timer_list hsm_timer;
++
++ spinlock_t lock;
++ spinlock_t wq_lock;
++
++ struct notifier_block xotg_notifier;
++};
++
++static inline
++struct xusbps_otg *xceiv_to_xotg(struct usb_phy *otg)
++{
++ return container_of(otg, struct xusbps_otg, otg);
++}
++
++void xusbps_update_transceiver(void);
++
++#endif /* __XILINX_XUSBPS_OTG_H__ */
+--- /dev/null
++++ b/include/linux/xilinx_devices.h
+@@ -0,0 +1,70 @@
++/*
++ * include/linux/xilinx_devices.h
++ *
++ * Definitions for any platform device related flags or structures for
++ * Xilinx EDK IPs
++ *
++ * Author: MontaVista Software, Inc.
++ * source@mvista.com
++ *
++ * 2002-2005 (c) MontaVista Software, Inc. This file is licensed under the
++ * terms of the GNU General Public License version 2. This program is licensed
++ * "as is" without any warranty of any kind, whether express or implied.
++ */
++
++#ifdef __KERNEL__
++#ifndef _XILINX_DEVICE_H_
++#define _XILINX_DEVICE_H_
++
++#include <linux/types.h>
++#include <linux/version.h>
++#include <linux/platform_device.h>
++
++/*- PS USB Controller IP -*/
++enum xusbps_usb2_operating_modes {
++ XUSBPS_USB2_MPH_HOST,
++ XUSBPS_USB2_DR_HOST,
++ XUSBPS_USB2_DR_DEVICE,
++ XUSBPS_USB2_DR_OTG,
++};
++
++enum xusbps_usb2_phy_modes {
++ XUSBPS_USB2_PHY_NONE,
++ XUSBPS_USB2_PHY_ULPI,
++ XUSBPS_USB2_PHY_UTMI,
++ XUSBPS_USB2_PHY_UTMI_WIDE,
++ XUSBPS_USB2_PHY_SERIAL,
++};
++
++struct clk;
++struct platform_device;
++
++struct xusbps_usb2_platform_data {
++ /* board specific information */
++ enum xusbps_usb2_operating_modes operating_mode;
++ enum xusbps_usb2_phy_modes phy_mode;
++ unsigned int port_enables;
++ unsigned int workaround;
++
++ int (*init)(struct platform_device *);
++ void (*exit)(struct platform_device *);
++ void __iomem *regs; /* ioremap'd register base */
++ struct usb_phy *otg;
++ struct usb_phy *ulpi;
++ int irq;
++ struct clk *clk;
++ struct notifier_block clk_rate_change_nb;
++ unsigned big_endian_mmio:1;
++ unsigned big_endian_desc:1;
++ unsigned es:1; /* need USBMODE:ES */
++ unsigned le_setup_buf:1;
++ unsigned have_sysif_regs:1;
++ unsigned invert_drvvbus:1;
++ unsigned invert_pwr_fault:1;
++};
++
++#define XUSBPS_USB2_PORT0_ENABLED 0x00000001
++#define XUSBPS_USB2_PORT1_ENABLED 0x00000002
++
++#endif /* _XILINX_DEVICE_H_ */
++#endif /* __KERNEL__ */
diff --git a/patches.zynq/0010-memory-zynq-merge-driver-for-Zynq-SMC.patch b/patches.zynq/0010-memory-zynq-merge-driver-for-Zynq-SMC.patch
new file mode 100644
index 00000000000000..26639459b9062d
--- /dev/null
+++ b/patches.zynq/0010-memory-zynq-merge-driver-for-Zynq-SMC.patch
@@ -0,0 +1,706 @@
+From 010897260c3b143bb9a958fc4e5eeba9de07bdf2 Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Tue, 24 Dec 2013 10:13:37 +0900
+Subject: memory: zynq: merge driver for Zynq SMC
+
+This adds a driver for Zynq's static memory controller.
+The SMC (compatible with ARM's PL353) supports NAND, NOR and SRAM memory.
+(commit efc27505715e64526653f35274717c0fc56491e3 from master branch)
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ drivers/memory/Kconfig | 7
+ drivers/memory/Makefile | 1
+ drivers/memory/zynq-smc.c | 627 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/memory/zynq-smc.h | 32 ++
+ 4 files changed, 667 insertions(+)
+ create mode 100644 drivers/memory/zynq-smc.c
+ create mode 100644 include/linux/memory/zynq-smc.h
+
+--- a/drivers/memory/Kconfig
++++ b/drivers/memory/Kconfig
+@@ -40,4 +40,11 @@ config TEGRA30_MC
+ analysis, especially for IOMMU/SMMU(System Memory Management
+ Unit) module.
+
++config ZYNQ_SMC
++ bool "Zynq Static Memory Controller(SMC) driver"
++ default y
++ depends on ARCH_ZYNQ
++ help
++ This driver is for the Static Memory Controller(SMC) module available
++ in Zynq SoCs.
+ endif
+--- a/drivers/memory/Makefile
++++ b/drivers/memory/Makefile
+@@ -8,3 +8,4 @@ endif
+ obj-$(CONFIG_TI_EMIF) += emif.o
+ obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
+ obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
++obj-$(CONFIG_ZYNQ_SMC) += zynq-smc.o
+--- /dev/null
++++ b/drivers/memory/zynq-smc.c
+@@ -0,0 +1,627 @@
++/*
++ * Xilinx Zynq SMC Driver
++ *
++ * Copyright (C) 2012 - 2013 Xilinx, Inc.
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ *
++ * Currently only a single SMC instance is supported.
++ */
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/memory/zynq-smc.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++/* Register definitions */
++#define XSMCPS_MEMC_STATUS_OFFS 0 /* Controller status reg, RO */
++#define XSMCPS_CFG_CLR_OFFS 0xC /* Clear config reg, WO */
++#define XSMCPS_DIRECT_CMD_OFFS 0x10 /* Direct command reg, WO */
++#define XSMCPS_SET_CYCLES_OFFS 0x14 /* Set cycles register, WO */
++#define XSMCPS_SET_OPMODE_OFFS 0x18 /* Set opmode register, WO */
++#define XSMCPS_ECC_STATUS_OFFS 0x400 /* ECC status register */
++#define XSMCPS_ECC_MEMCFG_OFFS 0x404 /* ECC mem config reg */
++#define XSMCPS_ECC_MEMCMD1_OFFS 0x408 /* ECC mem cmd1 reg */
++#define XSMCPS_ECC_MEMCMD2_OFFS 0x40C /* ECC mem cmd2 reg */
++#define XSMCPS_ECC_VALUE0_OFFS 0x418 /* ECC value 0 reg */
++
++#define XSMCPS_CFG_CLR_INT_1 0x10
++#define XSMCPS_ECC_STATUS_BUSY (1 << 6)
++#define XSMCPS_DC_UPT_NAND_REGS ((4 << 23) | /* CS: NAND chip */ \
++ (2 << 21)) /* UpdateRegs operation */
++
++#define XNANDPS_ECC_CMD1 ((0x80) | /* Write command */ \
++ (0 << 8) | /* Read command */ \
++ (0x30 << 16) | /* Read End command */ \
++ (1 << 24)) /* Read End command calid */
++
++#define XNANDPS_ECC_CMD2 ((0x85) | /* Write col change cmd */ \
++ (5 << 8) | /* Read col change cmd */ \
++ (0xE0 << 16) | /* Read col change end cmd */ \
++ (1 << 24)) /* Read col change end cmd valid */
++/**
++ * struct xsmcps_data
++ * @devclk Pointer to the peripheral clock
++ * @aperclk Pointer to the APER clock
++ * @clk_rate_change_nb Notifier block for clock frequency change callback
++ */
++struct xsmcps_data {
++ struct clk *devclk;
++ struct clk *aperclk;
++ struct notifier_block clk_rate_change_nb;
++ struct resource *res;
++};
++
++/* SMC virtual register base */
++static void __iomem *xsmcps_base;
++static DEFINE_SPINLOCK(xsmcps_lock);
++
++/**
++ * xsmcps_set_buswidth - Set memory buswidth
++ * @bw Memory buswidth (8 | 16)
++ * Returns 0 on success or negative errno.
++ *
++ * Must be called with xsmcps_lock held.
++ */
++static int xsmcps_set_buswidth(unsigned int bw)
++{
++ u32 reg;
++
++ if (bw != 8 && bw != 16)
++ return -EINVAL;
++
++ reg = readl(xsmcps_base + XSMCPS_SET_OPMODE_OFFS);
++ reg &= ~3;
++ if (bw == 16)
++ reg |= 1;
++ writel(reg, xsmcps_base + XSMCPS_SET_OPMODE_OFFS);
++
++ return 0;
++}
++
++/**
++ * xsmcps_set_cycles - Set memory timing parameters
++ * @t0 t_rc read cycle time
++ * @t1 t_wc write cycle time
++ * @t2 t_rea/t_ceoe output enable assertion delay
++ * @t3 t_wp write enable deassertion delay
++ * @t4 t_clr/t_pc page cycle time
++ * @t5 t_ar/t_ta ID read time/turnaround time
++ * @t6 t_rr busy to RE timing
++ *
++ * Sets NAND chip specific timing parameters.
++ *
++ * Must be called with xsmcps_lock held.
++ */
++static void xsmcps_set_cycles(u32 t0, u32 t1, u32 t2, u32 t3, u32
++ t4, u32 t5, u32 t6)
++{
++ t0 &= 0xf;
++ t1 = (t1 & 0xf) << 4;
++ t2 = (t2 & 7) << 8;
++ t3 = (t3 & 7) << 11;
++ t4 = (t4 & 7) << 14;
++ t5 = (t5 & 7) << 17;
++ t6 = (t6 & 0xf) << 20;
++
++ t0 |= t1 | t2 | t3 | t4 | t5 | t6;
++
++ writel(t0, xsmcps_base + XSMCPS_SET_CYCLES_OFFS);
++}
++
++/**
++ * xsmcps_ecc_is_busy_noirq - Read ecc busy flag
++ * Returns the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle
++ *
++ * Must be called with xsmcps_lock held.
++ */
++static int xsmcps_ecc_is_busy_noirq(void)
++{
++ return !!(readl(xsmcps_base + XSMCPS_ECC_STATUS_OFFS) &
++ XSMCPS_ECC_STATUS_BUSY);
++}
++
++/**
++ * xsmcps_ecc_is_busy - Read ecc busy flag
++ * Returns the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle
++ */
++int xsmcps_ecc_is_busy(void)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ ret = xsmcps_ecc_is_busy_noirq();
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xsmcps_ecc_is_busy);
++
++/**
++ * xsmcps_get_ecc_val - Read ecc_valueN registers
++ * @ecc_reg Index of the ecc_value reg (0..3)
++ * Returns the content of the requested ecc_value register.
++ *
++ * There are four valid ecc_value registers. The argument is truncated to stay
++ * within this valid boundary.
++ */
++u32 xsmcps_get_ecc_val(int ecc_reg)
++{
++ u32 reg;
++ u32 addr;
++ unsigned long flags;
++
++ ecc_reg &= 3;
++ addr = XSMCPS_ECC_VALUE0_OFFS + (ecc_reg << 2);
++
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ reg = readl(xsmcps_base + addr);
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++
++ return reg;
++}
++EXPORT_SYMBOL_GPL(xsmcps_get_ecc_val);
++
++/**
++ * xsmcps_get_nand_int_status_raw - Get NAND interrupt status bit
++ * Returns the raw_int_status1 bit from the memc_status register
++ */
++int xsmcps_get_nand_int_status_raw(void)
++{
++ u32 reg;
++ unsigned long flags;
++
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ reg = readl(xsmcps_base + XSMCPS_MEMC_STATUS_OFFS);
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++
++ reg >>= 6;
++ reg &= 1;
++
++ return reg;
++}
++EXPORT_SYMBOL_GPL(xsmcps_get_nand_int_status_raw);
++
++/**
++ * xsmcps_clr_nand_int - Clear NAND interrupt
++ */
++void xsmcps_clr_nand_int(void)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ writel(XSMCPS_CFG_CLR_INT_1, xsmcps_base + XSMCPS_CFG_CLR_OFFS);
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++}
++EXPORT_SYMBOL_GPL(xsmcps_clr_nand_int);
++
++/**
++ * xsmcps_set_ecc_mode - Set SMC ECC mode
++ * @mode ECC mode (BYPASS, APB, MEM)
++ * Returns 0 on success or negative errno.
++ */
++int xsmcps_set_ecc_mode(enum xsmcps_ecc_mode mode)
++{
++ u32 reg;
++ unsigned long flags;
++ int ret = 0;
++
++ switch (mode) {
++ case XSMCPS_ECCMODE_BYPASS:
++ case XSMCPS_ECCMODE_APB:
++ case XSMCPS_ECCMODE_MEM:
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ reg = readl(xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS);
++ reg &= ~0xc;
++ reg |= mode << 2;
++ writel(reg, xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS);
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(xsmcps_set_ecc_mode);
++
++/**
++ * xsmcps_set_ecc_pg_size - Set SMC ECC page size
++ * @pg_sz ECC page size
++ * Returns 0 on success or negative errno.
++ */
++int xsmcps_set_ecc_pg_size(unsigned int pg_sz)
++{
++ u32 reg;
++ u32 sz;
++ unsigned long flags;
++
++ switch (pg_sz) {
++ case 0:
++ sz = 0;
++ break;
++ case 512:
++ sz = 1;
++ break;
++ case 1024:
++ sz = 2;
++ break;
++ case 2048:
++ sz = 3;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ reg = readl(xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS);
++ reg &= ~3;
++ reg |= sz;
++ writel(reg, xsmcps_base + XSMCPS_ECC_MEMCFG_OFFS);
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xsmcps_set_ecc_pg_size);
++
++static int xsmcps_clk_notifier_cb(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++
++ switch (event) {
++ case PRE_RATE_CHANGE:
++ /*
++ * if a rate change is announced we need to check whether we can
++ * run under the changed conditions
++ */
++ /* fall through */
++ case POST_RATE_CHANGE:
++ return NOTIFY_OK;
++ case ABORT_RATE_CHANGE:
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int xsmcps_suspend(struct device *dev)
++{
++ struct xsmcps_data *xsmcps = dev_get_drvdata(dev);
++
++ clk_disable(xsmcps->devclk);
++ clk_disable(xsmcps->aperclk);
++
++ return 0;
++}
++
++static int xsmcps_resume(struct device *dev)
++{
++ int ret;
++ struct xsmcps_data *xsmcps = dev_get_drvdata(dev);
++
++ ret = clk_enable(xsmcps->aperclk);
++ if (ret) {
++ dev_err(dev, "Cannot enable APER clock.\n");
++ return ret;
++ }
++
++ ret = clk_enable(xsmcps->devclk);
++ if (ret) {
++ dev_err(dev, "Cannot enable device clock.\n");
++ clk_disable(xsmcps->aperclk);
++ return ret;
++ }
++ return ret;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(xsmcps_dev_pm_ops, xsmcps_suspend, xsmcps_resume);
++
++/**
++ * xsmcps_init_nand_interface - Initialize the NAND interface
++ * @pdev Pointer to the platform_device struct
++ * @nand_node Pointer to the xnandps device_node struct
++ */
++static void xsmcps_init_nand_interface(struct platform_device *pdev,
++ struct device_node *nand_node)
++{
++ u32 t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr;
++ unsigned int bw;
++ int err;
++ unsigned long flags;
++
++ err = of_property_read_u32(nand_node, "xlnx,nand-width", &bw);
++ if (err) {
++ dev_warn(&pdev->dev,
++ "xlnx,nand-width not in device tree, using 8");
++ bw = 8;
++ }
++ /* nand-cycle-<X> property is refer to the NAND flash timing
++ * mapping between dts and the NAND flash AC timing
++ * X : AC timing name
++ * t0 : t_rc
++ * t1 : t_wc
++ * t2 : t_rea
++ * t3 : t_wp
++ * t4 : t_clr
++ * t5 : t_ar
++ * t6 : t_rr
++ */
++ err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t0", &t_rc);
++ if (err) {
++ dev_warn(&pdev->dev, "xlnx,nand-cycle-t0 not in device tree");
++ goto default_nand_timing;
++ }
++ err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t1", &t_wc);
++ if (err) {
++ dev_warn(&pdev->dev, "xlnx,nand-cycle-t1 not in device tree");
++ goto default_nand_timing;
++ }
++ err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t2", &t_rea);
++ if (err) {
++ dev_warn(&pdev->dev, "xlnx,nand-cycle-t2 not in device tree");
++ goto default_nand_timing;
++ }
++ err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t3", &t_wp);
++ if (err) {
++ dev_warn(&pdev->dev, "xlnx,nand-cycle-t3 not in device tree");
++ goto default_nand_timing;
++ }
++ err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t4", &t_clr);
++ if (err) {
++ dev_warn(&pdev->dev, "xlnx,nand-cycle-t4 not in device tree");
++ goto default_nand_timing;
++ }
++ err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t5", &t_ar);
++ if (err) {
++ dev_warn(&pdev->dev, "xlnx,nand-cycle-t5 not in device tree");
++ goto default_nand_timing;
++ }
++ err = of_property_read_u32(nand_node, "xlnx,nand-cycle-t6", &t_rr);
++ if (err) {
++ dev_warn(&pdev->dev, "xlnx,nand-cycle-t6 not in device tree");
++ goto default_nand_timing;
++ }
++
++default_nand_timing:
++ if (err) {
++ /* set default NAND flash timing property */
++ dev_warn(&pdev->dev, "Using default timing for");
++ dev_warn(&pdev->dev, "2Gb Numonyx MT29F2G08ABAEAWP NAND flash");
++ dev_warn(&pdev->dev, "t_wp, t_clr, t_ar are set to 4");
++ dev_warn(&pdev->dev, "t_rc, t_wc, t_rr are set to 2");
++ dev_warn(&pdev->dev, "t_rea is set to 1");
++ t_rc = t_wc = t_rr = 4;
++ t_rea = 1;
++ t_wp = t_clr = t_ar = 2;
++ }
++
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ if (xsmcps_set_buswidth(bw)) {
++ dev_warn(&pdev->dev, "xlnx,nand-width not valid, using 8");
++ xsmcps_set_buswidth(8);
++ }
++
++ /*
++ * Default assume 50MHz clock (20ns cycle time) and 3V operation
++ * The SET_CYCLES_REG register value depends on the flash device.
++ * Look in to the device datasheet and change its value, This value
++ * is for 2Gb Numonyx flash.
++ */
++ xsmcps_set_cycles(t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr);
++ writel(XSMCPS_CFG_CLR_INT_1, xsmcps_base + XSMCPS_CFG_CLR_OFFS);
++ writel(XSMCPS_DC_UPT_NAND_REGS, xsmcps_base + XSMCPS_DIRECT_CMD_OFFS);
++ /* Wait till the ECC operation is complete */
++ while (xsmcps_ecc_is_busy_noirq())
++ cpu_relax();
++ /* Set the command1 and command2 register */
++ writel(XNANDPS_ECC_CMD1, xsmcps_base + XSMCPS_ECC_MEMCMD1_OFFS);
++ writel(XNANDPS_ECC_CMD2, xsmcps_base + XSMCPS_ECC_MEMCMD2_OFFS);
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++}
++
++const struct of_device_id matches_nor[] = {
++ {.compatible = "cfi-flash"},
++ {}
++};
++const struct of_device_id matches_nand[] = {
++ {.compatible = "xlnx,ps7-nand-1.00.a"},
++ {}
++};
++
++static int xsmcps_probe(struct platform_device *pdev)
++{
++ struct xsmcps_data *xsmcps;
++ struct device_node *child;
++ unsigned long flags;
++ int err;
++ struct device_node *of_node = pdev->dev.of_node;
++ const struct of_device_id *matches = NULL;
++
++ xsmcps = kzalloc(sizeof(*xsmcps), GFP_KERNEL);
++ if (!xsmcps) {
++ dev_err(&pdev->dev, "unable to allocate memory\n");
++ return -ENOMEM;
++ }
++
++ xsmcps->aperclk = clk_get(&pdev->dev, "aper_clk");
++ if (IS_ERR(xsmcps->aperclk)) {
++ dev_err(&pdev->dev, "aper_clk clock not found.\n");
++ err = PTR_ERR(xsmcps->aperclk);
++ goto out_free;
++ }
++
++ xsmcps->devclk = clk_get(&pdev->dev, "ref_clk");
++ if (IS_ERR(xsmcps->devclk)) {
++ dev_err(&pdev->dev, "ref_clk clock not found.\n");
++ err = PTR_ERR(xsmcps->devclk);
++ goto out_clk_put_aper;
++ }
++
++ err = clk_prepare_enable(xsmcps->aperclk);
++ if (err) {
++ dev_err(&pdev->dev, "Unable to enable APER clock.\n");
++ goto out_clk_put;
++ }
++
++ err = clk_prepare_enable(xsmcps->devclk);
++ if (err) {
++ dev_err(&pdev->dev, "Unable to enable device clock.\n");
++ goto out_clk_dis_aper;
++ }
++
++ platform_set_drvdata(pdev, xsmcps);
++
++ xsmcps->clk_rate_change_nb.notifier_call = xsmcps_clk_notifier_cb;
++ if (clk_notifier_register(xsmcps->devclk, &xsmcps->clk_rate_change_nb))
++ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
++
++ /* Get the NAND controller virtual address */
++ xsmcps->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!xsmcps->res) {
++ err = -ENODEV;
++ dev_err(&pdev->dev, "platform_get_resource failed\n");
++ goto out_clk_disable;
++ }
++ xsmcps->res = request_mem_region(xsmcps->res->start,
++ resource_size(xsmcps->res), pdev->name);
++ if (!xsmcps->res) {
++ err = -ENOMEM;
++ dev_err(&pdev->dev, "request_mem_region failed\n");
++ goto out_clk_disable;
++ }
++
++ xsmcps_base = ioremap(xsmcps->res->start, resource_size(xsmcps->res));
++ if (!xsmcps_base) {
++ err = -EIO;
++ dev_err(&pdev->dev, "ioremap failed\n");
++ goto out_release_mem_region;
++ }
++
++ /* clear interrupts */
++ spin_lock_irqsave(&xsmcps_lock, flags);
++
++ writel(0x52, xsmcps_base + XSMCPS_CFG_CLR_OFFS);
++
++ spin_unlock_irqrestore(&xsmcps_lock, flags);
++
++ /* Find compatible children. Only a single child is supported */
++ for_each_available_child_of_node(of_node, child) {
++ if (of_match_node(matches_nand, child)) {
++ xsmcps_init_nand_interface(pdev, child);
++ if (!matches) {
++ matches = matches_nand;
++ } else {
++ dev_err(&pdev->dev,
++ "incompatible configuration\n");
++ goto out_release_mem_region;
++ }
++ }
++
++ if (of_match_node(matches_nor, child)) {
++ static int counts = 0;
++ if (!matches) {
++ matches = matches_nor;
++ } else {
++ if (matches != matches_nor || counts > 1) {
++ dev_err(&pdev->dev,
++ "incompatible configuration\n");
++ goto out_release_mem_region;
++ }
++ }
++ counts++;
++ }
++ }
++
++ if (matches)
++ of_platform_populate(of_node, matches, NULL, &pdev->dev);
++
++ return 0;
++
++out_release_mem_region:
++ release_mem_region(xsmcps->res->start, resource_size(xsmcps->res));
++ kfree(xsmcps->res);
++out_clk_disable:
++ clk_disable_unprepare(xsmcps->devclk);
++out_clk_dis_aper:
++ clk_disable_unprepare(xsmcps->aperclk);
++out_clk_put:
++ clk_put(xsmcps->devclk);
++out_clk_put_aper:
++ clk_put(xsmcps->aperclk);
++out_free:
++ kfree(xsmcps);
++
++ return err;
++}
++
++static int xsmcps_remove(struct platform_device *pdev)
++{
++ struct xsmcps_data *xsmcps = platform_get_drvdata(pdev);
++
++ clk_notifier_unregister(xsmcps->devclk, &xsmcps->clk_rate_change_nb);
++ release_mem_region(xsmcps->res->start, resource_size(xsmcps->res));
++ kfree(xsmcps->res);
++ iounmap(xsmcps_base);
++ clk_disable_unprepare(xsmcps->devclk);
++ clk_disable_unprepare(xsmcps->aperclk);
++ clk_put(xsmcps->devclk);
++ clk_put(xsmcps->aperclk);
++ kfree(xsmcps);
++
++ return 0;
++}
++
++/* Match table for device tree binding */
++static const struct of_device_id xsmcps_of_match[] = {
++ {.compatible = "xlnx,ps7-smc"},
++ { },
++};
++MODULE_DEVICE_TABLE(of, xsmcps_of_match);
++
++static struct platform_driver xsmcps_driver = {
++ .probe = xsmcps_probe,
++ .remove = xsmcps_remove,
++ .driver = {
++ .name = "xsmcps",
++ .owner = THIS_MODULE,
++ .pm = &xsmcps_dev_pm_ops,
++ .of_match_table = xsmcps_of_match,
++ },
++};
++
++module_platform_driver(xsmcps_driver);
++
++MODULE_AUTHOR("Xilinx, Inc.");
++MODULE_DESCRIPTION("Xilinx PS SMC Driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/include/linux/memory/zynq-smc.h
+@@ -0,0 +1,32 @@
++/*
++ * Xilinx Zynq SMC Driver Header
++ *
++ * Copyright (C) 2012 Xilinx, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef __LINUX_MEMORY_ZYNQ_SMC_H
++#define __LINUX_MEMORY_ZYNQ_SMC_H
++
++enum xsmcps_ecc_mode {
++ XSMCPS_ECCMODE_BYPASS = 0,
++ XSMCPS_ECCMODE_APB = 1,
++ XSMCPS_ECCMODE_MEM = 2
++};
++
++u32 xsmcps_get_ecc_val(int ecc_reg);
++int xsmcps_ecc_is_busy(void);
++int xsmcps_get_nand_int_status_raw(void);
++void xsmcps_clr_nand_int(void);
++int xsmcps_set_ecc_mode(enum xsmcps_ecc_mode mode);
++int xsmcps_set_ecc_pg_size(unsigned int pg_sz);
++
++#endif
diff --git a/patches.zynq/0011-arm-dts-zynq-Merge-zynq-zc702.dts-with-Xilinx-reposi.patch b/patches.zynq/0011-arm-dts-zynq-Merge-zynq-zc702.dts-with-Xilinx-reposi.patch
new file mode 100644
index 00000000000000..5c2182c6907716
--- /dev/null
+++ b/patches.zynq/0011-arm-dts-zynq-Merge-zynq-zc702.dts-with-Xilinx-reposi.patch
@@ -0,0 +1,418 @@
+From 5bf18a6e06c0906459605ebb45077d8ab710ebde Mon Sep 17 00:00:00 2001
+From: Soren Brinkmann <soren.brinkmann@xilinx.com>
+Date: Mon, 13 May 2013 10:46:38 -0700
+Subject: arm: dts: zynq: Merge zynq-zc702.dts with Xilinx repository
+
+This patch updates the zynq zc702 device tree by merging some parts
+from the corresponding file in the Xilinx repository
+(commit efc27505715e64526653f35274717c0fc56491e3 in master branch)
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ arch/arm/boot/dts/zynq-zc702.dts | 389 ++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 366 insertions(+), 23 deletions(-)
+
+--- a/arch/arm/boot/dts/zynq-zc702.dts
++++ b/arch/arm/boot/dts/zynq-zc702.dts
+@@ -1,34 +1,377 @@
+ /*
+- * Copyright (C) 2011 Xilinx
+- * Copyright (C) 2012 National Instruments Corp.
++ * Device Tree Generator version: 1.1
+ *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
++ * (C) Copyright 2007-2013 Xilinx, Inc.
++ * (C) Copyright 2007-2013 Michal Simek
++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd
++ *
++ * Michal SIMEK <monstr@monstr.eu>
++ *
++ * CAUTION: This file is automatically generated by libgen.
++ * Version: Xilinx EDK 14.5 EDK_P.58f
+ *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+ */
+-/dts-v1/;
+-/include/ "zynq-7000.dtsi"
+
++/dts-v1/;
+ / {
+- model = "Zynq ZC702 Development Board";
+- compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";
+-
+- memory {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "xlnx,zynq-7000";
++ model = "Xilinx Zynq";
++ aliases {
++ ethernet0 = &ps7_ethernet_0;
++ i2c0 = &ps7_i2c_0;
++ serial0 = &ps7_uart_1;
++ spi0 = &ps7_qspi_0;
++ } ;
++ chosen {
++ bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 initrd=0x2000000,8M rw rootwait earlyprintk";
++ linux,stdout-path = "/amba@0/serial@e0001000";
++ } ;
++ cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ ps7_cortexa9_0: cpu@0 {
++ bus-handle = <&ps7_axi_interconnect_0>;
++ compatible = "arm,cortex-a9";
++ d-cache-line-size = <0x20>;
++ d-cache-size = <0x8000>;
++ device_type = "cpu";
++ i-cache-line-size = <0x20>;
++ i-cache-size = <0x8000>;
++ interrupt-handle = <&ps7_scugic_0>;
++ reg = <0x0>;
++ } ;
++ ps7_cortexa9_1: cpu@1 {
++ bus-handle = <&ps7_axi_interconnect_0>;
++ compatible = "arm,cortex-a9";
++ d-cache-line-size = <0x20>;
++ d-cache-size = <0x8000>;
++ device_type = "cpu";
++ i-cache-line-size = <0x20>;
++ i-cache-size = <0x8000>;
++ interrupt-handle = <&ps7_scugic_0>;
++ reg = <0x1>;
++ } ;
++ } ;
++ pmu {
++ compatible = "arm,cortex-a9-pmu";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 5 4>, <0 6 4>;
++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>;
++ reg-names = "cpu0", "cpu1";
++ } ;
++ ps7_ddr_0: memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x40000000>;
+- };
++ } ;
++ ps7_axi_interconnect_0: amba@0 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus";
++ ranges ;
++ ps7_dma_s: ps7-dma@f8003000 {
++ #dma-cells = <1>;
++ #dma-channels = <8>;
++ #dma-requests = <4>;
++ arm,primecell-periphid = <0x41330>;
++ clock-names = "apb_pclk";
++ clocks = <&clkc 27>;
++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330";
++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
++ "dma4", "dma5", "dma6", "dma7";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>;
++ reg = <0xf8003000 0x1000>;
++ } ;
++ ps7_ethernet_0: ps7-ethernet@e000b000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-names = "ref_clk", "aper_clk";
++ clocks = <&clkc 13>, <&clkc 30>;
++ compatible = "xlnx,ps7-ethernet-1.00.a";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 22 4>;
++ local-mac-address = [00 0a 35 00 00 00];
++ phy-handle = <&phy0>;
++ phy-mode = "rgmii-id";
++ reg = <0xe000b000 0x1000>;
++ xlnx,enet-reset = "MIO 11";
++ xlnx,eth-mode = <0x1>;
++ xlnx,has-mdio = <0x1>;
++ xlnx,ptp-enet-clock = <111111115>;
++ mdio {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ phy0: phy@7 {
++ compatible = "marvell,88e1116r";
++ device_type = "ethernet-phy";
++ reg = <7>;
++ } ;
++ } ;
++ } ;
++ ps7_gpio_0: ps7-gpio@e000a000 {
++ #gpio-cells = <2>;
++ clocks = <&clkc 42>;
++ compatible = "xlnx,ps7-gpio-1.00.a";
++ emio-gpio-width = <64>;
++ gpio-controller ;
++ gpio-mask-high = <0x0>;
++ gpio-mask-low = <0x5600>;
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 20 4>;
++ reg = <0xe000a000 0x1000>;
++ } ;
++ ps7_i2c_0: ps7-i2c@e0004000 {
++ bus-id = <0>;
++ clocks = <&clkc 38>;
++ compatible = "xlnx,ps7-i2c-1.00.a";
++ i2c-clk = <400000>;
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 25 4>;
++ reg = <0xe0004000 0x1000>;
++ xlnx,has-interrupt = <0x0>;
++ xlnx,i2c-reset = "MIO 13";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ i2cswitch@74 {
++ compatible = "nxp,pca9548";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x74>;
+
+- chosen {
+- bootargs = "console=ttyPS0,115200 earlyprintk";
+- };
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++ osc@5d {
++ compatible = "si570";
++ reg = <0x5d>;
++ factory-fout = <156250000>;
++ initial-fout = <148500000>;
++ };
++ };
++
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++ eeprom@54 {
++ compatible = "at,24c08";
++ reg = <0x54>;
++ };
++ };
++
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++ gpio@21 {
++ compatible = "ti,tca6416";
++ reg = <0x21>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ };
++ };
++
++ i2c@4 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <4>;
++ rtc@54 {
++ compatible = "nxp,pcf8563";
++ reg = <0x51>;
++ };
++ };
++
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++ hwmon@52 {
++ compatible = "pmbus,ucd9248";
++ reg = <52>;
++ };
++ hwmon@53 {
++ compatible = "pmbus,ucd9248";
++ reg = <53>;
++ };
++ hwmon@54 {
++ compatible = "pmbus,ucd9248";
++ reg = <54>;
++ };
++ };
++ };
+
+-};
++ } ;
++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 {
++ compatible = "xlnx,ps7-iop-bus-config-1.00.a";
++ reg = <0xe0200000 0x1000>;
++ } ;
++ ps7_pl310_0: ps7-pl310@f8f02000 {
++ arm,data-latency = <3 2 2>;
++ arm,tag-latency = <2 2 2>;
++ cache-level = <2>;
++ cache-unified ;
++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 2 4>;
++ reg = <0xf8f02000 0x1000>;
++ } ;
++ ps7_qspi_0: ps7-qspi@e000d000 {
++ clock-names = "ref_clk", "aper_clk";
++ clocks = <&clkc 10>, <&clkc 43>;
++ compatible = "xlnx,ps7-qspi-1.00.a";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 19 4>;
++ is-dual = <0>;
++ num-chip-select = <1>;
++ reg = <0xe000d000 0x1000>;
++ xlnx,fb-clk = <0x1>;
++ xlnx,qspi-mode = <0x0>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ flash@0 {
++ compatible = "n25q128";
++ reg = <0x0>;
++ spi-max-frequency = <50000000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ partition@qspi-fsbl-uboot {
++ label = "qspi-fsbl-uboot";
++ reg = <0x0 0x100000>;
++ };
++ partition@qspi-linux {
++ label = "qspi-linux";
++ reg = <0x100000 0x500000>;
++ };
++ partition@qspi-device-tree {
++ label = "qspi-device-tree";
++ reg = <0x600000 0x20000>;
++ };
++ partition@qspi-rootfs {
++ label = "qspi-rootfs";
++ reg = <0x620000 0x5E0000>;
++ };
++ partition@qspi-bitstream {
++ label = "qspi-bitstream";
++ reg = <0xC00000 0x400000>;
++ };
++ };
+
+-&uart1 {
+- status = "okay";
+-};
++ } ;
++ ps7_qspi_linear_0: ps7-qspi-linear@fc000000 {
++ clock-names = "ref_clk", "aper_clk";
++ clocks = <&clkc 10>, <&clkc 43>;
++ compatible = "xlnx,ps7-qspi-linear-1.00.a";
++ reg = <0xfc000000 0x1000000>;
++ } ;
++ ps7_ram_0: ps7-ram@0 {
++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 3 4>;
++ reg = <0xfffc0000 0x40000>;
++ } ;
++ ps7_scugic_0: ps7-scugic@f8f01000 {
++ #address-cells = <2>;
++ #interrupt-cells = <3>;
++ #size-cells = <1>;
++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic";
++ interrupt-controller ;
++ num_cpus = <2>;
++ num_interrupts = <96>;
++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>;
++ } ;
++ ps7_scutimer_0: ps7-scutimer@f8f00600 {
++ clocks = <&clkc 4>;
++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <1 13 0x301>;
++ reg = <0xf8f00600 0x20>;
++ } ;
++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 {
++ clocks = <&clkc 4>;
++ compatible = "xlnx,ps7-scuwdt-1.00.a";
++ device_type = "watchdog";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <1 14 0x301>;
++ reg = <0xf8f00620 0xe0>;
++ } ;
++ ps7_sd_0: ps7-sdio@e0100000 {
++ clock-frequency = <50000000>;
++ clock-names = "clk_xin", "clk_ahb";
++ clocks = <&clkc 21>, <&clkc 32>;
++ compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci-8.9a";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 24 4>;
++ reg = <0xe0100000 0x1000>;
++ xlnx,has-cd = <0x1>;
++ xlnx,has-power = <0x0>;
++ xlnx,has-wp = <0x1>;
++ } ;
++ ps7_slcr_0: ps7-slcr@f8000000 {
++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr";
++ reg = <0xf8000000 0x1000>;
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clkc: clkc {
++ #clock-cells = <1>;
++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x",
++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci",
++ "lqspi", "smc", "pcap", "gem0", "gem1",
++ "fclk0", "fclk1", "fclk2", "fclk3", "can0",
++ "can1", "sdio0", "sdio1", "uart0", "uart1",
++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper",
++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper",
++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper",
++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper",
++ "swdt", "dbg_trc", "dbg_apb";
++ compatible = "xlnx,ps7-clkc";
++ fclk-enable = <0xf>;
++ ps-clk-frequency = <33333333>;
++ } ;
++ } ;
++ } ;
++ ps7_ttc_0: ps7-ttc@f8001000 {
++ clocks = <&clkc 6>;
++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc";
++ interrupt-names = "ttc0", "ttc1", "ttc2";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
++ reg = <0xf8001000 0x1000>;
++ } ;
++ ps7_uart_1: serial@e0001000 {
++ clock-names = "ref_clk", "aper_clk";
++ clocks = <&clkc 24>, <&clkc 41>;
++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps";
++ current-speed = <115200>;
++ device_type = "serial";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 50 4>;
++ port-number = <0>;
++ reg = <0xe0001000 0x1000>;
++ xlnx,has-modem = <0x0>;
++ } ;
++ ps7_usb_0: ps7-usb@e0002000 {
++ clocks = <&clkc 28>;
++ compatible = "xlnx,ps7-usb-1.00.a";
++ dr_mode = "host";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 21 4>;
++ phy_type = "ulpi";
++ reg = <0xe0002000 0x1000>;
++ xlnx,usb-reset = "MIO 7";
++ } ;
++ ps7_wdt_0: ps7-wdt@f8005000 {
++ clocks = <&clkc 45>;
++ compatible = "xlnx,ps7-wdt-1.00.a";
++ device_type = "watchdog";
++ interrupt-parent = <&ps7_scugic_0>;
++ interrupts = <0 9 1>;
++ reg = <0xf8005000 0x1000>;
++ reset = <0>;
++ timeout = <10>;
++ } ;
++ } ;
++} ;
diff --git a/patches.zynq/0012-defconfig-zynq-merge-xilinx-zynq-defconfig-from-xili.patch b/patches.zynq/0012-defconfig-zynq-merge-xilinx-zynq-defconfig-from-xili.patch
new file mode 100644
index 00000000000000..9fa92971048adb
--- /dev/null
+++ b/patches.zynq/0012-defconfig-zynq-merge-xilinx-zynq-defconfig-from-xili.patch
@@ -0,0 +1,2477 @@
+From cda1e37742c76b3dc9ca4154279c517c669dd1ba Mon Sep 17 00:00:00 2001
+From: Michal Simek <michal.simek@xilinx.com>
+Date: Tue, 24 Dec 2013 09:47:53 +0900
+Subject: defconfig: zynq: merge xilinx zynq defconfig from xilinx branch
+
+Copy the xilinx zynq defconfig from the Xilinx repository (commit
+efc27505715e64526653f35274717c0fc56491e3 in master branch) and select
+a few options for the LTSI 3.10.y kernel, such as the asaran SDCard
+driver. We have tested it on the Zynq 702 board.
+
+Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp>
+Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp>
+---
+ arch/arm/configs/xilinx_zynq702_defconfig | 2457 ++++++++++++++++++++++++++++++
+ 1 file changed, 2457 insertions(+)
+ create mode 100644 arch/arm/configs/xilinx_zynq702_defconfig
+
+--- /dev/null
++++ b/arch/arm/configs/xilinx_zynq702_defconfig
+@@ -0,0 +1,2457 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.10.24 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_NO_IOPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_ARM_PATCH_PHYS_VIRT=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++CONFIG_LOCALVERSION="-xilinx"
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_FHANDLE is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_CHIP=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_IRQ_DOMAIN_DEBUG=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_RCU_USER_QS is not set
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++# CONFIG_RCU_NOCB_CPU is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++# CONFIG_NAMESPACES is not set
++CONFIG_UIDGID_CONVERTED=y
++# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_HOTPLUG=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_ARCH_TRACEHOOK=y
++CONFIG_HAVE_DMA_ATTRS=y
++CONFIG_HAVE_DMA_CONTIGUOUS=y
++CONFIG_USE_GENERIC_SMP_HELPERS=y
++CONFIG_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_HW_BREAKPOINT=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++# CONFIG_MODULES is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_EFI_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_UNINLINE_SPIN_UNLOCK=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++CONFIG_ARCH_MULTIPLATFORM=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C24XX is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP1 is not set
++
++#
++# Multiple platform selection
++#
++
++#
++# CPU Core family selection
++#
++# CONFIG_ARCH_MULTI_V6 is not set
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_MULTI_V6_V7=y
++# CONFIG_ARCH_MULTI_CPU_AUTO is not set
++# CONFIG_ARCH_MVEBU is not set
++# CONFIG_ARCH_BCM is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_KEYBOARD_GPIO_POLLED is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_OMAP2PLUS is not set
++# CONFIG_ARCH_SOCFPGA is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_SUNXI is not set
++# CONFIG_ARCH_SIRF is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_U8500 is not set
++CONFIG_ARCH_VEXPRESS=y
++
++#
++# Versatile Express platform type
++#
++CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y
++# CONFIG_ARCH_VEXPRESS_CA9X4 is not set
++CONFIG_PLAT_VERSATILE_CLCD=y
++CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y
++# CONFIG_ARCH_VIRT is not set
++# CONFIG_ARCH_WM8850 is not set
++CONFIG_ARCH_ZYNQ=y
++CONFIG_PLAT_VERSATILE=y
++CONFIG_ARM_TIMER_SP804=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_ARM_VIRT_EXT=y
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_KUSER_HELPERS=y
++CONFIG_OUTER_CACHE=y
++CONFIG_OUTER_CACHE_SYNC=y
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++CONFIG_CACHE_L2X0=y
++CONFIG_CACHE_PL310=y
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_ARM_NR_BANKS=8
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++CONFIG_PL310_ERRATA_588369=y
++# CONFIG_ARM_ERRATA_643719 is not set
++CONFIG_ARM_ERRATA_720789=y
++CONFIG_PL310_ERRATA_727915=y
++CONFIG_PL310_ERRATA_753970=y
++CONFIG_ARM_ERRATA_754322=y
++CONFIG_ARM_ERRATA_754327=y
++CONFIG_ARM_ERRATA_764369=y
++CONFIG_PL310_ERRATA_769419=y
++CONFIG_ARM_ERRATA_775420=y
++# CONFIG_ARM_ERRATA_798181 is not set
++CONFIG_ICST=y
++
++#
++# Bus support
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_HAVE_SMP=y
++CONFIG_SMP=y
++CONFIG_SMP_ON_UP=y
++CONFIG_ARM_CPU_TOPOLOGY=y
++CONFIG_SCHED_MC=y
++CONFIG_SCHED_SMT=y
++CONFIG_HAVE_ARM_SCU=y
++# CONFIG_HAVE_ARM_ARCH_TIMER is not set
++CONFIG_HAVE_ARM_TWD=y
++# CONFIG_MCPM is not set
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_ARM_PSCI is not set
++CONFIG_LOCAL_TIMERS=y
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_SCHED_HRTICK=y
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HIGHMEM=y
++# CONFIG_HIGHPTE is not set
++CONFIG_HW_PERF_EVENTS=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_MEMORY_ISOLATION=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++CONFIG_FORCE_MAX_ZONEORDER=11
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_XEN is not set
++
++#
++# Boot options
++#
++CONFIG_USE_OF=y
++CONFIG_ATAGS=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++# CONFIG_ARM_APPENDED_DTB is not set
++CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++CONFIG_AUTO_ZRELADDR=y
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_VFP=y
++CONFIG_VFPv3=y
++CONFIG_NEON=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++CONFIG_PM_RUNTIME=y
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_CLK=y
++CONFIG_CPU_PM=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_DIAG is not set
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++CONFIG_NET_IPIP=y
++# CONFIG_NET_IPGRE_DEMUX is not set
++CONFIG_NET_IP_TUNNEL=y
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++CONFIG_INET_TUNNEL=y
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++CONFIG_IPV6=y
++# CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_IPV6_OPTIMISTIC_DAD is not set
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=y
++CONFIG_INET6_XFRM_MODE_TUNNEL=y
++CONFIG_INET6_XFRM_MODE_BEET=y
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=y
++# CONFIG_IPV6_SIT_6RD is not set
++CONFIG_IPV6_NDISC_NODETYPE=y
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_GRE is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_IPV6_MROUTE is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++CONFIG_HAVE_NET_DSA=y
++CONFIG_VLAN_8021Q=y
++# CONFIG_VLAN_8021Q_GVRP is not set
++# CONFIG_VLAN_8021Q_MVRP is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++# CONFIG_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++CONFIG_HAVE_BPF_JIT=y
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++CONFIG_FW_LOADER_USER_HELPER=y
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CMA=y
++# CONFIG_CMA_DEBUG is not set
++
++#
++# Default contiguous memory area size:
++#
++CONFIG_CMA_SIZE_MBYTES=16
++CONFIG_CMA_SIZE_SEL_MBYTES=y
++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
++# CONFIG_CMA_SIZE_SEL_MIN is not set
++# CONFIG_CMA_SIZE_SEL_MAX is not set
++CONFIG_CMA_ALIGNMENT=8
++CONFIG_CMA_AREAS=7
++
++#
++# Bus devices
++#
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_OF_PARTS=y
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++# CONFIG_MTD_PHYSMAP_COMPAT is not set
++CONFIG_MTD_PHYSMAP_OF=y
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++CONFIG_MTD_M25P80=y
++# CONFIG_M25PXX_USE_FAST_READ is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_DENALI is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_DOCG4 is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++CONFIG_MTD_NAND_XILINX_PS=y
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++
++#
++# Device Tree and Open Firmware support
++#
++CONFIG_PROC_DEVICETREE=y
++# CONFIG_OF_SELFTEST is not set
++CONFIG_OF_FLATTREE=y
++CONFIG_OF_EARLY_FLATTREE=y
++CONFIG_OF_ADDRESS=y
++CONFIG_OF_IRQ=y
++CONFIG_OF_DEVICE=y
++CONFIG_OF_I2C=y
++CONFIG_OF_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_MTD=y
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ATMEL_PWM is not set
++# CONFIG_DUMMY_IRQ is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ATMEL_SSC is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_ARM_CHARLCD is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++CONFIG_SI570=y
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++CONFIG_SRAM=y
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++CONFIG_EEPROM_AT24=y
++CONFIG_EEPROM_AT25=y
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_SCSI_UFSHCD is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HAVE_PATA_PLATFORM=y
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++
++#
++# Distributed Switch Architecture drivers
++#
++# CONFIG_NET_DSA_MV88E6XXX is not set
++# CONFIG_NET_DSA_MV88E6060 is not set
++# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
++# CONFIG_NET_DSA_MV88E6131 is not set
++# CONFIG_NET_DSA_MV88E6123_61_65 is not set
++CONFIG_ETHERNET=y
++CONFIG_NET_CADENCE=y
++# CONFIG_ARM_AT91_ETHER is not set
++CONFIG_MACB=y
++CONFIG_NET_VENDOR_BROADCOM=y
++# CONFIG_B44 is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++CONFIG_NET_VENDOR_INTEL=y
++CONFIG_NET_VENDOR_I825XX=y
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_NET_VENDOR_XILINX=y
++CONFIG_XILINX_EMACLITE=y
++CONFIG_XILINX_AXI_EMAC=y
++CONFIG_XILINX_PS_EMAC=y
++# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++CONFIG_MARVELL_PHY=y
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++CONFIG_VITESSE_PHY=y
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++CONFIG_MDIO_BITBANG=y
++# CONFIG_MDIO_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_RTL8152 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_WL_TI is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++CONFIG_INPUT_SPARSEKMAP=y
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_GPIO is not set
++# CONFIG_KEYBOARD_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 is not set
++# CONFIG_KEYBOARD_MATRIX is not set
++# CONFIG_KEYBOARD_LM8333 is not set
++# CONFIG_KEYBOARD_MAX7359 is not set
++# CONFIG_KEYBOARD_MCS is not set
++# CONFIG_KEYBOARD_MPR121 is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_OPENCORES is not set
++# CONFIG_KEYBOARD_SAMSUNG is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_CYPRESS=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_ELANTECH is not set
++# CONFIG_MOUSE_PS2_SENTELIC is not set
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_AMBAKMI is not set
++CONFIG_SERIO_LIBPS2=y
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_SERIO_APBPS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++# CONFIG_DEVKMEM is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++# CONFIG_SERIAL_AMBA_PL011 is not set
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX310X is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++CONFIG_SERIAL_XILINX_PS_UART=y
++CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++CONFIG_I2C_MUX_PCA954x=y
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_NOMADIK is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_VERSATILE is not set
++CONFIG_I2C_XILINX_PS=y
++CONFIG_I2C_XILINX=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++CONFIG_SPI_BITBANG=y
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PL022 is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_SC18IS602 is not set
++# CONFIG_SPI_XCOMM is not set
++CONFIG_SPI_XILINX=y
++CONFIG_SPI_XILINX_PS_QSPI=y
++# CONFIG_SPI_XILINX_PS_QSPI_DUAL_STACKED is not set
++CONFIG_SPI_XILINX_PS_SPI=y
++# CONFIG_SPI_DESIGNWARE is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# Qualcomm MSM SSBI bus support
++#
++# CONFIG_SSBI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++CONFIG_PPS=y
++# CONFIG_PPS_DEBUG is not set
++
++#
++# PPS clients support
++#
++# CONFIG_PPS_CLIENT_KTIMER is not set
++# CONFIG_PPS_CLIENT_LDISC is not set
++# CONFIG_PPS_CLIENT_GPIO is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++CONFIG_PTP_1588_CLOCK=y
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++# CONFIG_PTP_1588_CLOCK_PCH is not set
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_GPIOLIB=y
++CONFIG_OF_GPIO=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_EM is not set
++# CONFIG_GPIO_PL061 is not set
++# CONFIG_GPIO_RCAR is not set
++# CONFIG_GPIO_TS5500 is not set
++CONFIG_GPIO_XILINX=y
++CONFIG_GPIO_XILINX_PS=y
++# CONFIG_GPIO_GRGPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_ISP1704 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++# CONFIG_BATTERY_GOLDFISH is not set
++CONFIG_POWER_RESET=y
++# CONFIG_POWER_RESET_GPIO is not set
++# CONFIG_POWER_RESET_RESTART is not set
++CONFIG_POWER_RESET_VEXPRESS=y
++# CONFIG_POWER_AVS is not set
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Native drivers
++#
++# CONFIG_SENSORS_AD7314 is not set
++# CONFIG_SENSORS_AD7414 is not set
++# CONFIG_SENSORS_AD7418 is not set
++# CONFIG_SENSORS_ADCXX is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1029 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ADT7310 is not set
++# CONFIG_SENSORS_ADT7410 is not set
++# CONFIG_SENSORS_ADT7411 is not set
++# CONFIG_SENSORS_ADT7462 is not set
++# CONFIG_SENSORS_ADT7470 is not set
++# CONFIG_SENSORS_ADT7475 is not set
++# CONFIG_SENSORS_ASC7621 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS620 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_F71882FG is not set
++# CONFIG_SENSORS_F75375S is not set
++# CONFIG_SENSORS_G760A is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_GPIO_FAN is not set
++# CONFIG_SENSORS_HIH6130 is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_JC42 is not set
++# CONFIG_SENSORS_LINEAGE is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM70 is not set
++# CONFIG_SENSORS_LM73 is not set
++# CONFIG_SENSORS_LM75 is not set
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_LM93 is not set
++# CONFIG_SENSORS_LTC4151 is not set
++# CONFIG_SENSORS_LTC4215 is not set
++# CONFIG_SENSORS_LTC4245 is not set
++# CONFIG_SENSORS_LTC4261 is not set
++# CONFIG_SENSORS_LM95234 is not set
++# CONFIG_SENSORS_LM95241 is not set
++# CONFIG_SENSORS_LM95245 is not set
++# CONFIG_SENSORS_MAX1111 is not set
++# CONFIG_SENSORS_MAX16065 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_MAX1668 is not set
++# CONFIG_SENSORS_MAX197 is not set
++# CONFIG_SENSORS_MAX6639 is not set
++# CONFIG_SENSORS_MAX6642 is not set
++# CONFIG_SENSORS_MAX6650 is not set
++# CONFIG_SENSORS_MAX6697 is not set
++# CONFIG_SENSORS_MCP3021 is not set
++# CONFIG_SENSORS_NCT6775 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_PC87427 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_PMBUS is not set
++# CONFIG_SENSORS_SHT15 is not set
++# CONFIG_SENSORS_SHT21 is not set
++# CONFIG_SENSORS_SMM665 is not set
++# CONFIG_SENSORS_DME1737 is not set
++# CONFIG_SENSORS_EMC1403 is not set
++# CONFIG_SENSORS_EMC2103 is not set
++# CONFIG_SENSORS_EMC6W201 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_SCH56XX_COMMON is not set
++# CONFIG_SENSORS_SCH5627 is not set
++# CONFIG_SENSORS_SCH5636 is not set
++# CONFIG_SENSORS_ADS1015 is not set
++# CONFIG_SENSORS_ADS7828 is not set
++# CONFIG_SENSORS_ADS7871 is not set
++# CONFIG_SENSORS_AMC6821 is not set
++# CONFIG_SENSORS_INA209 is not set
++# CONFIG_SENSORS_INA2XX is not set
++# CONFIG_SENSORS_THMC50 is not set
++# CONFIG_SENSORS_TMP102 is not set
++# CONFIG_SENSORS_TMP401 is not set
++# CONFIG_SENSORS_TMP421 is not set
++# CONFIG_SENSORS_VEXPRESS is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83795 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83L786NG is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_CORE=y
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_ARM_SP805_WATCHDOG is not set
++# CONFIG_DW_WATCHDOG is not set
++CONFIG_MPCORE_WATCHDOG=y
++CONFIG_XILINX_PS_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++CONFIG_XILINX_WATCHDOG=y
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX77686 is not set
++# CONFIG_MFD_MAX77693 is not set
++# CONFIG_MFD_MAX8907 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_SYSCON is not set
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_VEXPRESS_CONFIG=y
++# CONFIG_REGULATOR is not set
++CONFIG_MEDIA_SUPPORT=y
++
++#
++# Multimedia core support
++#
++# CONFIG_MEDIA_CAMERA_SUPPORT is not set
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++
++#
++# Customise DVB Frontends
++#
++# CONFIG_DVB_TUNER_DIB0070 is not set
++# CONFIG_DVB_TUNER_DIB0090 is not set
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_TEGRA_HOST1X is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_ARMCLCD is not set
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_GOLDFISH is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_EXYNOS_VIDEO is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
++CONFIG_FONTS=y
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_7x14 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++# CONFIG_FONT_ACORN_8x8 is not set
++# CONFIG_FONT_MINI_4x6 is not set
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_10x18 is not set
++# CONFIG_LOGO is not set
++# CONFIG_FB_SSD1307 is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO_TPKBD is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MAGICMOUSE is not set
++CONFIG_HID_MICROSOFT=y
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_PS3REMOTE is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TIVO is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
++CONFIG_USB_XUSBPS_DR_OF=y
++CONFIG_USB_EHCI_XUSBPS=y
++# CONFIG_USB_EHCI_HCD_PLATFORM is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_RENESAS_USBHS is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++CONFIG_USB_PHY=y
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_OMAP_CONTROL_USB is not set
++# CONFIG_OMAP_USB3 is not set
++# CONFIG_SAMSUNG_USBPHY is not set
++# CONFIG_SAMSUNG_USB2PHY is not set
++# CONFIG_SAMSUNG_USB3PHY is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_RCAR_PHY is not set
++CONFIG_USB_ULPI=y
++CONFIG_USB_ULPI_VIEWPORT=y
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++# CONFIG_USB_GADGET_DEBUG_FS is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FUSB300 is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=y
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_ETH=y
++CONFIG_USB_ETH_RNDIS=y
++# CONFIG_USB_ETH_EEM is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++# CONFIG_USB_MASS_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_SDHCI_OF_ARASAN=y
++# CONFIG_MMC_SDHCI_PXAV3 is not set
++# CONFIG_MMC_SDHCI_PXAV2 is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_EDAC=y
++CONFIG_EDAC_LEGACY_SYSFS=y
++# CONFIG_EDAC_DEBUG is not set
++CONFIG_EDAC_MM_EDAC=y
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_SYSTOHC=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8523 is not set
++CONFIG_RTC_DRV_PCF8563=y
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++# CONFIG_RTC_DRV_RX4581 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++# CONFIG_RTC_DRV_DS2404 is not set
++
++#
++# on-CPU RTC drivers
++#
++# CONFIG_RTC_DRV_PL030 is not set
++# CONFIG_RTC_DRV_PL031 is not set
++# CONFIG_RTC_DRV_SNVS is not set
++
++#
++# HID Sensor RTC drivers
++#
++# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_AMBA_PL08X is not set
++# CONFIG_DW_DMAC is not set
++# CONFIG_TIMB_DMA is not set
++CONFIG_PL330_DMA=y
++CONFIG_DMA_ENGINE=y
++CONFIG_DMA_OF=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++CONFIG_UIO=y
++# CONFIG_UIO_PDRV is not set
++CONFIG_UIO_PDRV_GENIRQ=y
++# CONFIG_UIO_DMEM_GENIRQ is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++CONFIG_COMMON_CLK_DEBUG=y
++CONFIG_COMMON_CLK_VERSATILE=y
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_AXI_CLKGEN is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_MMIO=y
++CONFIG_CADENCE_TTC_TIMER=y
++# CONFIG_MAILBOX is not set
++CONFIG_IOMMU_SUPPORT=y
++CONFIG_OF_IOMMU=y
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++# CONFIG_PM_DEVFREQ is not set
++# CONFIG_EXTCON is not set
++CONFIG_MEMORY=y
++# CONFIG_IIO is not set
++# CONFIG_PWM is not set
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++# CONFIG_IPACK_BUS is not set
++# CONFIG_RESET_CONTROLLER is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_EXT4_FS=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=y
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++CONFIG_JFFS2_SUMMARY=y
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX6FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_F2FS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_SWAP is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_SUNRPC_DEBUG is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_MAC_ROMAN is not set
++# CONFIG_NLS_MAC_CELTIC is not set
++# CONFIG_NLS_MAC_CENTEURO is not set
++# CONFIG_NLS_MAC_CROATIAN is not set
++# CONFIG_NLS_MAC_CYRILLIC is not set
++# CONFIG_NLS_MAC_GAELIC is not set
++# CONFIG_NLS_MAC_GREEK is not set
++# CONFIG_NLS_MAC_ICELAND is not set
++# CONFIG_NLS_MAC_INUIT is not set
++# CONFIG_NLS_MAC_ROMANIAN is not set
++# CONFIG_NLS_MAC_TURKISH is not set
++# CONFIG_NLS_UTF8 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_SCHED_DEBUG is not set
++# CONFIG_SCHEDSTATS is not set
++CONFIG_TIMER_STATS=y
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_PREEMPT is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_PROVE_RCU_DELAY is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_RCU_CPU_STALL_TIMEOUT=60
++# CONFIG_RCU_CPU_STALL_VERBOSE is not set
++# CONFIG_RCU_CPU_STALL_INFO is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_LKDTM is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_DEBUG_PAGEALLOC is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_HAVE_DYNAMIC_FTRACE=y
++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
++CONFIG_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++# CONFIG_FTRACE is not set
++CONFIG_DYNAMIC_DEBUG=y
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++# CONFIG_DEBUG_USER is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ZYNQ_UART0 is not set
++CONFIG_DEBUG_ZYNQ_UART1=y
++# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set
++# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set
++# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set
++# CONFIG_DEBUG_ICEDCC is not set
++# CONFIG_DEBUG_SEMIHOSTING is not set
++CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S"
++CONFIG_DEBUG_UNCOMPRESS=y
++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
++CONFIG_EARLY_PRINTK=y
++# CONFIG_OC_ETM is not set
++# CONFIG_PID_IN_CONTEXTIDR is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_USER is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_PCRYPT is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA1_ARM is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=y
++# CONFIG_CRYPTO_AES_ARM is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++CONFIG_CRYPTO_ANSI_CPRNG=y
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC32_SELFTEST is not set
++CONFIG_CRC32_SLICEBY8=y
++# CONFIG_CRC32_SLICEBY4 is not set
++# CONFIG_CRC32_SARWATE is not set
++# CONFIG_CRC32_BIT is not set
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_VIRTUALIZATION=y
++CONFIG_KVM_ARM_MAX_VCPUS=0
++
++#
++# Virtio drivers
++#
diff --git a/series b/series
index 50c5c550c36625..a2d6c59ae560ae 100644
--- a/series
+++ b/series
@@ -2241,6 +2241,18 @@ patches.zynq/0104-video-xilinxfb-Fix-for-Use-standard-variable-name-co.patch
#patches.zynq/0106-i2c-move-OF-helpers-into-the-core.patch
patches.zynq/0107-i2c-xiic-Remove-casting-the-return-value-which-is-a-.patch
patches.zynq/0108-i2c-Include-linux-of.h-header.patch
+patches.zynq/0001-i2c-xilinx-merge-i2c-driver-from-Xilinx-repository-i.patch
+patches.zynq/0002-i2c-si570-merge-support-for-si570-clock-generator.patch
+patches.zynq/0003-mmc-arasan-add-a-driver-for-Arasan-s-SDHCI-controlle.patch
+patches.zynq/0004-net-ethernet-xilinx-Merge-driver-from-Xilinx-reposit.patch
+patches.zynq/0005-gpio-xilinx-merge-Xilinx-gpio-support-into-LTSI-3.10.patch
+patches.zynq/0006-spi-xilinx-merge-qspi-support-from-xilinx-repository.patch
+patches.zynq/0007-mtd-xilinx-merge-nand-flash-support-from-xilinx-repo.patch
+patches.zynq/0008-watchdog-xilinx-merge-support-for-xilinx-watchdog.patch
+patches.zynq/0009-usb-zynq-merge-usb-support-for-xilinx-zynq-soc.patch
+patches.zynq/0010-memory-zynq-merge-driver-for-Zynq-SMC.patch
+patches.zynq/0011-arm-dts-zynq-Merge-zynq-zc702.dts-with-Xilinx-reposi.patch
+patches.zynq/0012-defconfig-zynq-merge-xilinx-zynq-defconfig-from-xili.patch
#############################################################################