more zynq patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Jan 2014 21:43:22 +0000 (13:43 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Jan 2014 21:43:22 +0000 (13:43 -0800)
13 files changed:
patches.zynq/0001-i2c-xilinx-merge-i2c-driver-from-Xilinx-repository-i.patch [new file with mode: 0644]
patches.zynq/0002-i2c-si570-merge-support-for-si570-clock-generator.patch [new file with mode: 0644]
patches.zynq/0003-mmc-arasan-add-a-driver-for-Arasan-s-SDHCI-controlle.patch [new file with mode: 0644]
patches.zynq/0004-net-ethernet-xilinx-Merge-driver-from-Xilinx-reposit.patch [new file with mode: 0644]
patches.zynq/0005-gpio-xilinx-merge-Xilinx-gpio-support-into-LTSI-3.10.patch [new file with mode: 0644]
patches.zynq/0006-spi-xilinx-merge-qspi-support-from-xilinx-repository.patch [new file with mode: 0644]
patches.zynq/0007-mtd-xilinx-merge-nand-flash-support-from-xilinx-repo.patch [new file with mode: 0644]
patches.zynq/0008-watchdog-xilinx-merge-support-for-xilinx-watchdog.patch [new file with mode: 0644]
patches.zynq/0009-usb-zynq-merge-usb-support-for-xilinx-zynq-soc.patch [new file with mode: 0644]
patches.zynq/0010-memory-zynq-merge-driver-for-Zynq-SMC.patch [new file with mode: 0644]
patches.zynq/0011-arm-dts-zynq-Merge-zynq-zc702.dts-with-Xilinx-reposi.patch [new file with mode: 0644]
patches.zynq/0012-defconfig-zynq-merge-xilinx-zynq-defconfig-from-xili.patch [new file with mode: 0644]
series

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 (file)
index 0000000..ab31681
--- /dev/null
@@ -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 (file)
index 0000000..19e78b8
--- /dev/null
@@ -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 (file)
index 0000000..e312ac4
--- /dev/null
@@ -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 (file)
index 0000000..8021561
--- /dev/null
@@ -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 (file)
index 0000000..f7d7d0d
--- /dev/null
@@ -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 (file)
index 0000000..bb8e527
--- /dev/null
@@ -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 (file)
index 0000000..2f1c62f
--- /dev/null
@@ -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 (file)
index 0000000..4e8af98
--- /dev/null
@@ -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 (file)
index 0000000..bef62e7
--- /dev/null
@@ -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 (file)
index 0000000..2663945
--- /dev/null
@@ -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 (file)
index 0000000..5c2182c
--- /dev/null
@@ -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 (file)
index 0000000..9fa9297
--- /dev/null
@@ -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 50c5c550c36625fbfbda5ac9dca45eff0ba3c2e4..a2d6c59ae560ae3b7f3322ae77d3cdc233e7932e 100644 (file)
--- 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
 
 
 #############################################################################