aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h')
-rw-r--r--drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h399
1 files changed, 399 insertions, 0 deletions
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
new file mode 100644
index 000000000000..537cc237b4bc
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
@@ -0,0 +1,399 @@
+/*
+ * dwc_otg_fiq_fsm.h - Finite state machine FIQ header definitions
+ *
+ * Copyright (c) 2013 Raspberry Pi Foundation
+ *
+ * Author: Jonathan Bell <jonathan@raspberrypi.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Raspberry Pi nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This FIQ implements functionality that performs split transactions on
+ * the dwc_otg hardware without any outside intervention. A split transaction
+ * is "queued" by nominating a specific host channel to perform the entirety
+ * of a split transaction. This FIQ will then perform the microframe-precise
+ * scheduling required in each phase of the transaction until completion.
+ *
+ * The FIQ functionality has been surgically implanted into the Synopsys
+ * vendor-provided driver.
+ *
+ */
+
+#ifndef DWC_OTG_FIQ_FSM_H_
+#define DWC_OTG_FIQ_FSM_H_
+
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+#include "dwc_otg_hcd.h"
+#include <linux/kernel.h>
+#include <linux/irqflags.h>
+#include <linux/string.h>
+#include <asm/barrier.h>
+
+#if 0
+#define FLAME_ON(x) \
+do { \
+ int gpioreg; \
+ \
+ gpioreg = readl(__io_address(0x20200000+0x8)); \
+ gpioreg &= ~(7 << (x-20)*3); \
+ gpioreg |= 0x1 << (x-20)*3; \
+ writel(gpioreg, __io_address(0x20200000+0x8)); \
+ \
+ writel(1<<x, __io_address(0x20200000+(0x1C))); \
+} while (0)
+
+#define FLAME_OFF(x) \
+do { \
+ writel(1<<x, __io_address(0x20200000+(0x28))); \
+} while (0)
+#else
+#define FLAME_ON(x) do { } while (0)
+#define FLAME_OFF(X) do { } while (0)
+#endif
+
+/* This is a quick-and-dirty arch-specific register read/write. We know that
+ * writes to a peripheral on BCM2835 will always arrive in-order, also that
+ * reads and writes are executed in-order therefore the need for memory barriers
+ * is obviated if we're only talking to USB.
+ */
+#define FIQ_WRITE(_addr_,_data_) (*(volatile unsigned int *) (_addr_) = (_data_))
+#define FIQ_READ(_addr_) (*(volatile unsigned int *) (_addr_))
+
+/* FIQ-ified register definitions. Offsets are from dwc_regs_base. */
+#define GINTSTS 0x014
+#define GINTMSK 0x018
+/* Debug register. Poll the top of the received packets FIFO. */
+#define GRXSTSR 0x01C
+#define HFNUM 0x408
+#define HAINT 0x414
+#define HAINTMSK 0x418
+#define HPRT0 0x440
+
+/* HC_regs start from an offset of 0x500 */
+#define HC_START 0x500
+#define HC_OFFSET 0x020
+
+#define HC_DMA 0x14
+
+#define HCCHAR 0x00
+#define HCSPLT 0x04
+#define HCINT 0x08
+#define HCINTMSK 0x0C
+#define HCTSIZ 0x10
+
+#define ISOC_XACTPOS_ALL 0b11
+#define ISOC_XACTPOS_BEGIN 0b10
+#define ISOC_XACTPOS_MID 0b00
+#define ISOC_XACTPOS_END 0b01
+
+#define DWC_PID_DATA2 0b01
+#define DWC_PID_MDATA 0b11
+#define DWC_PID_DATA1 0b10
+#define DWC_PID_DATA0 0b00
+
+typedef struct {
+ volatile void* base;
+ volatile void* ctrl;
+ volatile void* outdda;
+ volatile void* outddb;
+ volatile void* intstat;
+ volatile void* swirq_set;
+ volatile void* swirq_clr;
+} mphi_regs_t;
+
+enum fiq_debug_level {
+ FIQDBG_SCHED = (1 << 0),
+ FIQDBG_INT = (1 << 1),
+ FIQDBG_ERR = (1 << 2),
+ FIQDBG_PORTHUB = (1 << 3),
+};
+
+#ifdef CONFIG_ARM64
+
+typedef spinlock_t fiq_lock_t;
+
+#else
+
+typedef struct {
+ union {
+ uint32_t slock;
+ struct _tickets {
+ uint16_t owner;
+ uint16_t next;
+ } tickets;
+ };
+} fiq_lock_t;
+
+#endif
+
+struct fiq_state;
+
+extern void _fiq_print (enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...);
+#if 0
+#define fiq_print _fiq_print
+#else
+#define fiq_print(x, y, ...)
+#endif
+
+extern bool fiq_enable, fiq_fsm_enable;
+extern ushort nak_holdoff;
+
+/**
+ * enum fiq_fsm_state - The FIQ FSM states.
+ *
+ * This is the "core" of the FIQ FSM. Broadly, the FSM states follow the
+ * USB2.0 specification for host responses to various transaction states.
+ * There are modifications to this host state machine because of a variety of
+ * quirks and limitations in the dwc_otg hardware.
+ *
+ * The fsm state is also used to communicate back to the driver on completion of
+ * a split transaction. The end states are used in conjunction with the interrupts
+ * raised by the final transaction.
+ */
+enum fiq_fsm_state {
+ /* FIQ isn't enabled for this host channel */
+ FIQ_PASSTHROUGH = 0,
+ /* For the first interrupt received for this channel,
+ * the FIQ has to ack any interrupts indicating success. */
+ FIQ_PASSTHROUGH_ERRORSTATE = 31,
+ /* Nonperiodic state groups */
+ FIQ_NP_SSPLIT_STARTED = 1,
+ FIQ_NP_SSPLIT_RETRY = 2,
+ /* TT contention - working around hub bugs */
+ FIQ_NP_SSPLIT_PENDING = 33,
+ FIQ_NP_OUT_CSPLIT_RETRY = 3,
+ FIQ_NP_IN_CSPLIT_RETRY = 4,
+ FIQ_NP_SPLIT_DONE = 5,
+ FIQ_NP_SPLIT_LS_ABORTED = 6,
+ /* This differentiates a HS transaction error from a LS one
+ * (handling the hub state is different) */
+ FIQ_NP_SPLIT_HS_ABORTED = 7,
+
+ /* Periodic state groups */
+ /* Periodic transactions are either started directly by the IRQ handler
+ * or deferred if the TT is already in use.
+ */
+ FIQ_PER_SSPLIT_QUEUED = 8,
+ FIQ_PER_SSPLIT_STARTED = 9,
+ FIQ_PER_SSPLIT_LAST = 10,
+
+
+ FIQ_PER_ISO_OUT_PENDING = 11,
+ FIQ_PER_ISO_OUT_ACTIVE = 12,
+ FIQ_PER_ISO_OUT_LAST = 13,
+ FIQ_PER_ISO_OUT_DONE = 27,
+
+ FIQ_PER_CSPLIT_WAIT = 14,
+ FIQ_PER_CSPLIT_NYET1 = 15,
+ FIQ_PER_CSPLIT_BROKEN_NYET1 = 28,
+ FIQ_PER_CSPLIT_NYET_FAFF = 29,
+ /* For multiple CSPLITs (large isoc IN, or delayed interrupt) */
+ FIQ_PER_CSPLIT_POLL = 16,
+ /* The last CSPLIT for a transaction has been issued, differentiates
+ * for the state machine to queue the next packet.
+ */
+ FIQ_PER_CSPLIT_LAST = 17,
+
+ FIQ_PER_SPLIT_DONE = 18,
+ FIQ_PER_SPLIT_LS_ABORTED = 19,
+ FIQ_PER_SPLIT_HS_ABORTED = 20,
+ FIQ_PER_SPLIT_NYET_ABORTED = 21,
+ /* Frame rollover has occurred without the transaction finishing. */
+ FIQ_PER_SPLIT_TIMEOUT = 22,
+
+ /* FIQ-accelerated HS Isochronous state groups */
+ FIQ_HS_ISOC_TURBO = 23,
+ /* For interval > 1, SOF wakes up the isochronous FSM */
+ FIQ_HS_ISOC_SLEEPING = 24,
+ FIQ_HS_ISOC_DONE = 25,
+ FIQ_HS_ISOC_ABORTED = 26,
+ FIQ_DEQUEUE_ISSUED = 30,
+ FIQ_TEST = 32,
+};
+
+struct fiq_stack {
+ int magic1;
+ uint8_t stack[2048];
+ int magic2;
+};
+
+
+/**
+ * struct fiq_dma_info - DMA bounce buffer utilisation information (per-channel)
+ * @index: Number of slots reported used for IN transactions / number of slots
+ * transmitted for an OUT transaction
+ * @slot_len[6]: Number of actual transfer bytes in each slot (255 if unused)
+ *
+ * Split transaction transfers can have variable length depending on other bus
+ * traffic. The OTG core DMA engine requires 4-byte aligned addresses therefore
+ * each transaction needs a guaranteed aligned address. A maximum of 6 split transfers
+ * can happen per-frame.
+ */
+struct fiq_dma_info {
+ u8 index;
+ u8 slot_len[6];
+};
+
+struct __attribute__((packed)) fiq_split_dma_slot {
+ u8 buf[188];
+};
+
+struct fiq_dma_channel {
+ struct __attribute__((packed)) fiq_split_dma_slot index[6];
+};
+
+struct fiq_dma_blob {
+ struct __attribute__((packed)) fiq_dma_channel channel[0];
+};
+
+/**
+ * struct fiq_hs_isoc_info - USB2.0 isochronous data
+ * @iso_frame: Pointer to the array of OTG URB iso_frame_descs.
+ * @nrframes: Total length of iso_frame_desc array
+ * @index: Current index (FIQ-maintained)
+ * @stride: Interval in uframes between HS isoc transactions
+ */
+struct fiq_hs_isoc_info {
+ struct dwc_otg_hcd_iso_packet_desc *iso_desc;
+ unsigned int nrframes;
+ unsigned int index;
+ unsigned int stride;
+};
+
+/**
+ * struct fiq_channel_state - FIQ state machine storage
+ * @fsm: Current state of the channel as understood by the FIQ
+ * @nr_errors: Number of transaction errors on this split-transaction
+ * @hub_addr: SSPLIT/CSPLIT destination hub
+ * @port_addr: SSPLIT/CSPLIT destination port - always 1 if single TT hub
+ * @nrpackets: For isoc OUT, the number of split-OUT packets to transmit. For
+ * split-IN, number of CSPLIT data packets that were received.
+ * @hcchar_copy:
+ * @hcsplt_copy:
+ * @hcintmsk_copy:
+ * @hctsiz_copy: Copies of the host channel registers.
+ * For use as scratch, or for returning state.
+ *
+ * The fiq_channel_state is state storage between interrupts for a host channel. The
+ * FSM state is stored here. Members of this structure must only be set up by the
+ * driver prior to enabling the FIQ for this host channel, and not touched until the FIQ
+ * has updated the state to either a COMPLETE state group or ABORT state group.
+ */
+
+struct fiq_channel_state {
+ enum fiq_fsm_state fsm;
+ unsigned int nr_errors;
+ unsigned int hub_addr;
+ unsigned int port_addr;
+ /* Hardware bug workaround: sometimes channel halt interrupts are
+ * delayed until the next SOF. Keep track of when we expected to get interrupted. */
+ unsigned int expected_uframe;
+ /* number of uframes remaining (for interval > 1 HS isoc transfers) before next transfer */
+ unsigned int uframe_sleeps;
+ /* in/out for communicating number of dma buffers used, or number of ISOC to do */
+ unsigned int nrpackets;
+ struct fiq_dma_info dma_info;
+ struct fiq_hs_isoc_info hs_isoc_info;
+ /* Copies of HC registers - in/out communication from/to IRQ handler
+ * and for ease of channel setup. A bit of mungeing is performed - for
+ * example the hctsiz.b.maxp is _always_ the max packet size of the endpoint.
+ */
+ hcchar_data_t hcchar_copy;
+ hcsplt_data_t hcsplt_copy;
+ hcint_data_t hcint_copy;
+ hcintmsk_data_t hcintmsk_copy;
+ hctsiz_data_t hctsiz_copy;
+ hcdma_data_t hcdma_copy;
+};
+
+/**
+ * struct fiq_state - top-level FIQ state machine storage
+ * @mphi_regs: virtual address of the MPHI peripheral register file
+ * @dwc_regs_base: virtual address of the base of the DWC core register file
+ * @dma_base: physical address for the base of the DMA bounce buffers
+ * @dummy_send: Scratch area for sending a fake message to the MPHI peripheral
+ * @gintmsk_saved: Top-level mask of interrupts that the FIQ has not handled.
+ * Used for determining which interrupts fired to set off the IRQ handler.
+ * @haintmsk_saved: Mask of interrupts from host channels that the FIQ did not handle internally.
+ * @np_count: Non-periodic transactions in the active queue
+ * @np_sent: Count of non-periodic transactions that have completed
+ * @next_sched_frame: For periodic transactions handled by the driver's SOF-driven queuing mechanism,
+ * this is the next frame on which a SOF interrupt is required. Used to hold off
+ * passing SOF through to the driver until necessary.
+ * @channel[n]: Per-channel FIQ state. Allocated during init depending on the number of host
+ * channels configured into the core logic.
+ *
+ * This is passed as the first argument to the dwc_otg_fiq_fsm top-level FIQ handler from the asm stub.
+ * It contains top-level state information.
+ */
+struct fiq_state {
+ fiq_lock_t lock;
+ mphi_regs_t mphi_regs;
+ void *dwc_regs_base;
+ dma_addr_t dma_base;
+ struct fiq_dma_blob *fiq_dmab;
+ void *dummy_send;
+ dma_addr_t dummy_send_dma;
+ gintmsk_data_t gintmsk_saved;
+ haintmsk_data_t haintmsk_saved;
+ int mphi_int_count;
+ unsigned int fiq_done;
+ unsigned int kick_np_queues;
+ unsigned int next_sched_frame;
+#ifdef FIQ_DEBUG
+ char * buffer;
+ unsigned int bufsiz;
+#endif
+ struct fiq_channel_state channel[0];
+};
+
+#ifdef CONFIG_ARM64
+
+#ifdef local_fiq_enable
+#undef local_fiq_enable
+#endif
+
+#ifdef local_fiq_disable
+#undef local_fiq_disable
+#endif
+
+extern void local_fiq_enable(void);
+
+extern void local_fiq_disable(void);
+
+#endif
+
+extern void fiq_fsm_spin_lock(fiq_lock_t *lock);
+
+extern void fiq_fsm_spin_unlock(fiq_lock_t *lock);
+
+extern int fiq_fsm_too_late(struct fiq_state *st, int n);
+
+extern int fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n);
+
+extern void dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels);
+
+extern void dwc_otg_fiq_nop(struct fiq_state *state);
+
+#endif /* DWC_OTG_FIQ_FSM_H_ */