usb: isp1760: Move PORT1 configuration to core code
[cascardo/linux.git] / drivers / usb / host / isp1760-hcd.c
index 395649f..568446c 100644 (file)
@@ -11,6 +11,7 @@
  * (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
  *
  */
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
-#include <linux/gpio.h>
 
+#include "isp1760-core.h"
 #include "isp1760-hcd.h"
+#include "isp1760-regs.h"
 
 static struct kmem_cache *qtd_cachep;
 static struct kmem_cache *qh_cachep;
 static struct kmem_cache *urb_listitem_cachep;
 
-enum queue_head_types {
-       QH_CONTROL,
-       QH_BULK,
-       QH_INTERRUPT,
-       QH_END
-};
-
-struct isp1760_hcd {
-       u32 hcs_params;
-       spinlock_t              lock;
-       struct slotinfo         atl_slots[32];
-       int                     atl_done_map;
-       struct slotinfo         int_slots[32];
-       int                     int_done_map;
-       struct memory_chunk memory_pool[BLOCKS];
-       struct list_head        qh_list[QH_END];
-
-       /* periodic schedule support */
-#define        DEFAULT_I_TDPS          1024
-       unsigned                periodic_size;
-       unsigned                i_thresh;
-       unsigned long           reset_done;
-       unsigned long           next_statechange;
-       unsigned int            devflags;
-
-       int                     rst_gpio;
-};
+typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
+               struct isp1760_qtd *qtd);
 
 static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
 {
-       return (struct isp1760_hcd *) (hcd->hcd_priv);
+       return *(struct isp1760_hcd **)hcd->hcd_priv;
 }
 
-/* Section 2.2 Host Controller Capability Registers */
-#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
-#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
-#define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
-#define HCS_PPC(p)             ((p)&(1 << 4))  /* true: port power control */
-#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
-#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
-
-/* Section 2.3 Host Controller Operational Registers */
-#define CMD_LRESET     (1<<7)          /* partial reset (no ports, etc) */
-#define CMD_RESET      (1<<1)          /* reset HC not bus */
-#define CMD_RUN                (1<<0)          /* start/stop HC */
-#define STS_PCD                (1<<2)          /* port change detect */
-#define FLAG_CF                (1<<0)          /* true: we'll support "high speed" */
-
-#define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
-#define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
-#define PORT_RESET     (1<<8)          /* reset port */
-#define PORT_SUSPEND   (1<<7)          /* suspend port */
-#define PORT_RESUME    (1<<6)          /* resume it */
-#define PORT_PE                (1<<2)          /* port enable */
-#define PORT_CSC       (1<<1)          /* connect status change */
-#define PORT_CONNECT   (1<<0)          /* device connected */
-#define PORT_RWC_BITS   (PORT_CSC)
+/* urb state*/
+#define DELETE_URB             (0x0008)
+#define NO_TRANSFER_ACTIVE     (0xffffffff)
+
+/* Philips Proprietary Transfer Descriptor (PTD) */
+typedef __u32 __bitwise __dw;
+struct ptd {
+       __dw dw0;
+       __dw dw1;
+       __dw dw2;
+       __dw dw3;
+       __dw dw4;
+       __dw dw5;
+       __dw dw6;
+       __dw dw7;
+};
+#define PTD_OFFSET             0x0400
+#define ISO_PTD_OFFSET         0x0400
+#define INT_PTD_OFFSET         0x0800
+#define ATL_PTD_OFFSET         0x0c00
+#define PAYLOAD_OFFSET         0x1000
+
+
+/* ATL */
+/* DW0 */
+#define DW0_VALID_BIT                  1
+#define FROM_DW0_VALID(x)              ((x) & 0x01)
+#define TO_DW0_LENGTH(x)               (((u32) x) << 3)
+#define TO_DW0_MAXPACKET(x)            (((u32) x) << 18)
+#define TO_DW0_MULTI(x)                        (((u32) x) << 29)
+#define TO_DW0_ENDPOINT(x)             (((u32) x) << 31)
+/* DW1 */
+#define TO_DW1_DEVICE_ADDR(x)          (((u32) x) << 3)
+#define TO_DW1_PID_TOKEN(x)            (((u32) x) << 10)
+#define DW1_TRANS_BULK                 ((u32) 2 << 12)
+#define DW1_TRANS_INT                  ((u32) 3 << 12)
+#define DW1_TRANS_SPLIT                        ((u32) 1 << 14)
+#define DW1_SE_USB_LOSPEED             ((u32) 2 << 16)
+#define TO_DW1_PORT_NUM(x)             (((u32) x) << 18)
+#define TO_DW1_HUB_NUM(x)              (((u32) x) << 25)
+/* DW2 */
+#define TO_DW2_DATA_START_ADDR(x)      (((u32) x) << 8)
+#define TO_DW2_RL(x)                   ((x) << 25)
+#define FROM_DW2_RL(x)                 (((x) >> 25) & 0xf)
+/* DW3 */
+#define FROM_DW3_NRBYTESTRANSFERRED(x)         ((x) & 0x7fff)
+#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x)     ((x) & 0x07ff)
+#define TO_DW3_NAKCOUNT(x)             ((x) << 19)
+#define FROM_DW3_NAKCOUNT(x)           (((x) >> 19) & 0xf)
+#define TO_DW3_CERR(x)                 ((x) << 23)
+#define FROM_DW3_CERR(x)               (((x) >> 23) & 0x3)
+#define TO_DW3_DATA_TOGGLE(x)          ((x) << 25)
+#define FROM_DW3_DATA_TOGGLE(x)                (((x) >> 25) & 0x1)
+#define TO_DW3_PING(x)                 ((x) << 26)
+#define FROM_DW3_PING(x)               (((x) >> 26) & 0x1)
+#define DW3_ERROR_BIT                  (1 << 28)
+#define DW3_BABBLE_BIT                 (1 << 29)
+#define DW3_HALT_BIT                   (1 << 30)
+#define DW3_ACTIVE_BIT                 (1 << 31)
+#define FROM_DW3_ACTIVE(x)             (((x) >> 31) & 0x01)
+
+#define INT_UNDERRUN                   (1 << 2)
+#define INT_BABBLE                     (1 << 1)
+#define INT_EXACT                      (1 << 0)
+
+#define SETUP_PID      (2)
+#define IN_PID         (1)
+#define OUT_PID                (0)
+
+/* Errata 1 */
+#define RL_COUNTER     (0)
+#define NAK_COUNTER    (0)
+#define ERR_COUNTER    (2)
 
 struct isp1760_qtd {
        u8 packet_type;
@@ -137,12 +161,12 @@ struct urb_listitem {
  */
 static u32 reg_read32(void __iomem *base, u32 reg)
 {
-       return readl(base + reg);
+       return isp1760_read32(base, reg);
 }
 
 static void reg_write32(void __iomem *base, u32 reg, u32 val)
 {
-       writel(val, base + reg);
+       isp1760_write32(base, reg, val);
 }
 
 /*
@@ -443,42 +467,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
        int result;
        u32 scratch, hwmode;
 
-       /* low-level chip reset */
-       if (gpio_is_valid(priv->rst_gpio)) {
-               unsigned int rst_lvl;
-
-               rst_lvl = (priv->devflags &
-                          ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
-
-               gpio_set_value(priv->rst_gpio, rst_lvl);
-               mdelay(50);
-               gpio_set_value(priv->rst_gpio, !rst_lvl);
-       }
-
-       /* Setup HW Mode Control: This assumes a level active-low interrupt */
-       hwmode = HW_DATA_BUS_32BIT;
-
-       if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16)
-               hwmode &= ~HW_DATA_BUS_32BIT;
-       if (priv->devflags & ISP1760_FLAG_ANALOG_OC)
-               hwmode |= HW_ANA_DIGI_OC;
-       if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH)
-               hwmode |= HW_DACK_POL_HIGH;
-       if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
-               hwmode |= HW_DREQ_POL_HIGH;
-       if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH)
-               hwmode |= HW_INTR_HIGH_ACT;
-       if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
-               hwmode |= HW_INTR_EDGE_TRIG;
-
-       /*
-        * We have to set this first in case we're in 16-bit mode.
-        * Write it twice to ensure correct upper bits if switching
-        * to 16-bit mode.
-        */
-       reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
-       reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
-
        reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
        /* Change bus pattern */
        scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
@@ -488,46 +476,33 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
                return -ENODEV;
        }
 
-       /* pre reset */
+       /*
+        * The RESET_HC bit in the SW_RESET register is supposed to reset the
+        * host controller without touching the CPU interface registers, but at
+        * least on the ISP1761 it seems to behave as the RESET_ALL bit and
+        * reset the whole device. We thus can't use it here, so let's reset
+        * the host controller through the EHCI USB Command register. The device
+        * has been reset in core code anyway, so this shouldn't matter.
+        */
        reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
        reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
        reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
        reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
 
-       /* reset */
-       reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
-       mdelay(100);
-
-       reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC);
-       mdelay(100);
-
        result = ehci_reset(hcd);
        if (result)
                return result;
 
        /* Step 11 passed */
 
-       dev_info(hcd->self.controller, "bus width: %d, oc: %s\n",
-                          (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ?
-                          16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
-                          "analog" : "digital");
-
        /* ATL reset */
+       hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
        reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
        mdelay(10);
        reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
 
        reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
 
-       /*
-        * PORT 1 Control register of the ISP1760 is the OTG control
-        * register on ISP1761. Since there is no OTG or device controller
-        * support in this driver, we use port 1 as a "normal" USB host port on
-        * both chips.
-        */
-       reg_write32(hcd->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2);
-       mdelay(10);
-
        priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
 
        return priv_init(hcd);
@@ -743,8 +718,9 @@ static void qtd_free(struct isp1760_qtd *qtd)
 }
 
 static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
-                               struct slotinfo *slots, struct isp1760_qtd *qtd,
-                               struct isp1760_qh *qh, struct ptd *ptd)
+                               struct isp1760_slotinfo *slots,
+                               struct isp1760_qtd *qtd, struct isp1760_qh *qh,
+                               struct ptd *ptd)
 {
        struct isp1760_hcd *priv = hcd_to_priv(hcd);
        int skip_map;
@@ -857,7 +833,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
 {
        struct isp1760_hcd *priv = hcd_to_priv(hcd);
        int ptd_offset;
-       struct slotinfo *slots;
+       struct isp1760_slotinfo *slots;
        int curr_slot, free_slot;
        int n;
        struct ptd ptd;
@@ -1097,7 +1073,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
        struct isp1760_qh *qh;
        int slot;
        int state;
-       struct slotinfo *slots;
+       struct isp1760_slotinfo *slots;
        u32 ptd_offset;
        struct isp1760_qtd *qtd;
        int modified;
@@ -2163,7 +2139,7 @@ static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
 static const struct hc_driver isp1760_hc_driver = {
        .description            = "isp1760-hcd",
        .product_desc           = "NXP ISP1760 USB Host Controller",
-       .hcd_priv_size          = sizeof(struct isp1760_hcd),
+       .hcd_priv_size          = sizeof(struct isp1760_hcd *),
        .irq                    = isp1760_irq,
        .flags                  = HCD_MEMORY | HCD_USB2,
        .reset                  = isp1760_hc_setup,
@@ -2179,7 +2155,7 @@ static const struct hc_driver isp1760_hc_driver = {
        .clear_tt_buffer_complete       = isp1760_clear_tt_buffer_complete,
 };
 
-int __init init_kmem_once(void)
+int __init isp1760_init_kmem_once(void)
 {
        urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
                        sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
@@ -2206,63 +2182,50 @@ int __init init_kmem_once(void)
        return 0;
 }
 
-void deinit_kmem_cache(void)
+void isp1760_deinit_kmem_cache(void)
 {
        kmem_cache_destroy(qtd_cachep);
        kmem_cache_destroy(qh_cachep);
        kmem_cache_destroy(urb_listitem_cachep);
 }
 
-struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
-                                int irq, unsigned long irqflags,
-                                int rst_gpio,
-                                struct device *dev, const char *busname,
-                                unsigned int devflags)
+int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+                        struct resource *mem, int irq, unsigned long irqflags,
+                        struct device *dev)
 {
        struct usb_hcd *hcd;
-       struct isp1760_hcd *priv;
        int ret;
 
-       if (usb_disabled())
-               return ERR_PTR(-ENODEV);
-
-       /* prevent usb-core allocating DMA pages */
-       dev->dma_mask = NULL;
-
        hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
        if (!hcd)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
+
+       *(struct isp1760_hcd **)hcd->hcd_priv = priv;
+
+       priv->hcd = hcd;
 
-       priv = hcd_to_priv(hcd);
-       priv->devflags = devflags;
-       priv->rst_gpio = rst_gpio;
        init_memory(priv);
-       hcd->regs = ioremap(res_start, res_len);
-       if (!hcd->regs) {
-               ret = -EIO;
-               goto err_put;
-       }
 
        hcd->irq = irq;
-       hcd->rsrc_start = res_start;
-       hcd->rsrc_len = res_len;
+       hcd->regs = regs;
+       hcd->rsrc_start = mem->start;
+       hcd->rsrc_len = resource_size(mem);
 
        ret = usb_add_hcd(hcd, irq, irqflags);
        if (ret)
-               goto err_unmap;
-       device_wakeup_enable(hcd->self.controller);
+               goto error;
 
-       return hcd;
-
-err_unmap:
-        iounmap(hcd->regs);
+       device_wakeup_enable(hcd->self.controller);
 
-err_put:
-        usb_put_hcd(hcd);
+       return 0;
 
-        return ERR_PTR(ret);
+error:
+       usb_put_hcd(hcd);
+       return ret;
 }
 
-MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
-MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
-MODULE_LICENSE("GPL v2");
+void isp1760_hcd_unregister(struct isp1760_hcd *priv)
+{
+       usb_remove_hcd(priv->hcd);
+       usb_put_hcd(priv->hcd);
+}