linux/drivers/usb/host/oxu210hp-hcd.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (c) 2008 Rodolfo Giometti <[email protected]>
 * Copyright (c) 2008 Eurotech S.p.A. <[email protected]>
 *
 * This code is *strongly* based on EHCI-HCD code by David Brownell since
 * the chip is a quasi-EHCI compatible.
 */

#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dmapool.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/iopoll.h>

#include <asm/irq.h>
#include <asm/unaligned.h>

#include <linux/irq.h>
#include <linux/platform_device.h>

#define DRIVER_VERSION

#define OXU_DEVICEID
	#define OXU_REV_MASK
	#define OXU_REV_SHIFT
	#define OXU_REV_2100
	#define OXU_BO_SHIFT
	#define OXU_BO_MASK
	#define OXU_MAJ_REV_SHIFT
	#define OXU_MAJ_REV_MASK
	#define OXU_MIN_REV_SHIFT
	#define OXU_MIN_REV_MASK
#define OXU_HOSTIFCONFIG
#define OXU_SOFTRESET
	#define OXU_SRESET

#define OXU_PIOBURSTREADCTRL

#define OXU_CHIPIRQSTATUS
#define OXU_CHIPIRQEN_SET
#define OXU_CHIPIRQEN_CLR
	#define OXU_USBSPHLPWUI
	#define OXU_USBOTGLPWUI
	#define OXU_USBSPHI
	#define OXU_USBOTGI

#define OXU_CLKCTRL_SET
	#define OXU_SYSCLKEN
	#define OXU_USBSPHCLKEN
	#define OXU_USBOTGCLKEN

#define OXU_ASO
	#define OXU_SPHPOEN
	#define OXU_OVRCCURPUPDEN
	#define OXU_ASO_OP
	#define OXU_COMPARATOR

#define OXU_USBMODE
	#define OXU_VBPS
	#define OXU_ES_LITTLE
	#define OXU_CM_HOST_ONLY

/*
 * Proper EHCI structs & defines
 */

/* Magic numbers that can affect system performance */
#define EHCI_TUNE_CERR
#define EHCI_TUNE_RL_HS
#define EHCI_TUNE_RL_TT
#define EHCI_TUNE_MULT_HS
#define EHCI_TUNE_MULT_TT
#define EHCI_TUNE_FLS

struct oxu_hcd;

/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */

/* Section 2.2 Host Controller Capability Registers */
struct ehci_caps {} __packed;


/* Section 2.3 Host Controller Operational Registers */
struct ehci_regs {} __packed;

#define QTD_NEXT(dma)

/*
 * EHCI Specification 0.95 Section 3.5
 * QTD: describe data transfer components (buffer, direction, ...)
 * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
 *
 * These are associated only with "QH" (Queue Head) structures,
 * used with control, bulk, and interrupt transfers.
 */
struct ehci_qtd {} __aligned();

/* mask NakCnt+T in qh->hw_alt_next */
#define QTD_MASK

#define IS_SHORT_READ(token)

/* Type tag from {qh, itd, sitd, fstn}->hw_next */
#define Q_NEXT_TYPE(dma)

/* values for that type tag */
#define Q_TYPE_QH

/* next async queue entry, or pointer to interrupt/periodic QH */
#define QH_NEXT(dma)

/* for periodic/async schedules and qtd lists, mark end of list */
#define EHCI_LIST_END

/*
 * Entries in periodic shadow table are pointers to one of four kinds
 * of data structure.  That's dictated by the hardware; a type tag is
 * encoded in the low bits of the hardware's periodic schedule.  Use
 * Q_NEXT_TYPE to get the tag.
 *
 * For entries in the async schedule, the type tag always says "qh".
 */
ehci_shadow;

/*
 * EHCI Specification 0.95 Section 3.6
 * QH: describes control/bulk/interrupt endpoints
 * See Fig 3-7 "Queue Head Structure Layout".
 *
 * These appear in both the async and (for interrupt) periodic schedules.
 */

struct ehci_qh {} __aligned();

/*
 * Proper OXU210HP structs
 */

#define OXU_OTG_CORE_OFFSET
#define OXU_OTG_CAP_OFFSET
#define OXU_SPH_CORE_OFFSET
#define OXU_SPH_CAP_OFFSET

#define OXU_OTG_MEM
#define OXU_SPH_MEM

/* Only how many elements & element structure are specifies here. */
/* 2 host controllers are enabled - total size <= 28 kbytes */
#define DEFAULT_I_TDPS
#define QHEAD_NUM
#define QTD_NUM
#define SITD_NUM
#define MURB_NUM

#define BUFFER_NUM
#define BUFFER_SIZE

struct oxu_info {};

struct oxu_buf {} __aligned();

struct oxu_onchip_mem {} __aligned();

#define EHCI_MAX_ROOT_PORTS

struct oxu_murb {};

struct oxu_hcd {};

#define EHCI_IAA_JIFFIES
#define EHCI_IO_JIFFIES
#define EHCI_ASYNC_JIFFIES
#define EHCI_SHRINK_JIFFIES

enum ehci_timer_action {};

/*
 * Main defines
 */

#define oxu_dbg(oxu, fmt, args...)
#define oxu_err(oxu, fmt, args...)
#define oxu_info(oxu, fmt, args...)

#ifdef CONFIG_DYNAMIC_DEBUG
#define DEBUG
#endif

static inline struct usb_hcd *oxu_to_hcd(struct oxu_hcd *oxu)
{}

static inline struct oxu_hcd *hcd_to_oxu(struct usb_hcd *hcd)
{}

/*
 * Debug stuff
 */

#undef OXU_URB_TRACE
#undef OXU_VERBOSE_DEBUG

#ifdef OXU_VERBOSE_DEBUG
#define oxu_vdbg
#else
#define oxu_vdbg(oxu, fmt, args...)
#endif

#ifdef DEBUG

static int __attribute__((__unused__))
dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
{}

static int __attribute__((__unused__))
dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
{}

static const char *const fls_strings[] =;

static int dbg_command_buf(char *buf, unsigned len,
				const char *label, u32 command)
{}

static int dbg_port_buf(char *buf, unsigned len, const char *label,
				int port, u32 status)
{}

#else

static inline int __attribute__((__unused__))
dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
{ return 0; }

static inline int __attribute__((__unused__))
dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
{ return 0; }

static inline int __attribute__((__unused__))
dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
{ return 0; }

static inline int __attribute__((__unused__))
dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
{ return 0; }

#endif /* DEBUG */

/* functions have the "wrong" filename when they're output... */
#define dbg_status(oxu, label, status)

#define dbg_cmd(oxu, label, command)

#define dbg_port(oxu, label, port, status)

/*
 * Module parameters
 */

/* Initial IRQ latency: faster than hw default */
static int log2_irq_thresh;			/* 0 to 6 */
module_param(log2_irq_thresh, int, S_IRUGO);
MODULE_PARM_DESC();

/* Initial park setting: slower than hw default */
static unsigned park;
module_param(park, uint, S_IRUGO);
MODULE_PARM_DESC();

/* For flakey hardware, ignore overcurrent indicators */
static bool ignore_oc;
module_param(ignore_oc, bool, S_IRUGO);
MODULE_PARM_DESC();


static void ehci_work(struct oxu_hcd *oxu);
static int oxu_hub_control(struct usb_hcd *hcd,
				u16 typeReq, u16 wValue, u16 wIndex,
				char *buf, u16 wLength);

/*
 * Local functions
 */

/* Low level read/write registers functions */
static inline u32 oxu_readl(void __iomem *base, u32 reg)
{}

static inline void oxu_writel(void __iomem *base, u32 reg, u32 val)
{}

static inline void timer_action_done(struct oxu_hcd *oxu,
					enum ehci_timer_action action)
{}

static inline void timer_action(struct oxu_hcd *oxu,
					enum ehci_timer_action action)
{}

/*
 * handshake - spin reading hc until handshake completes or fails
 * @ptr: address of hc register to be read
 * @mask: bits to look at in result of read
 * @done: value of those bits when handshake succeeds
 * @usec: timeout in microseconds
 *
 * Returns negative errno, or zero on success
 *
 * Success happens when the "mask" bits have the specified value (hardware
 * handshake done).  There are two failure modes:  "usec" have passed (major
 * hardware flakeout), or the register reads as all-ones (hardware removed).
 *
 * That last failure should_only happen in cases like physical cardbus eject
 * before driver shutdown. But it also seems to be caused by bugs in cardbus
 * bridge shutdown:  shutting down the bridge before the devices using it.
 */
static int handshake(struct oxu_hcd *oxu, void __iomem *ptr,
					u32 mask, u32 done, int usec)
{}

/* Force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt(struct oxu_hcd *oxu)
{}

/* Put TDI/ARC silicon into EHCI mode */
static void tdi_reset(struct oxu_hcd *oxu)
{}

/* Reset a non-running (STS_HALT == 1) controller */
static int ehci_reset(struct oxu_hcd *oxu)
{}

/* Idle the controller (from running) */
static void ehci_quiesce(struct oxu_hcd *oxu)
{}

static int check_reset_complete(struct oxu_hcd *oxu, int index,
				u32 __iomem *status_reg, int port_status)
{}

static void ehci_hub_descriptor(struct oxu_hcd *oxu,
				struct usb_hub_descriptor *desc)
{}


/* Allocate an OXU210HP on-chip memory data buffer
 *
 * An on-chip memory data buffer is required for each OXU210HP USB transfer.
 * Each transfer descriptor has one or more on-chip memory data buffers.
 *
 * Data buffers are allocated from a fix sized pool of data blocks.
 * To minimise fragmentation and give reasonable memory utlisation,
 * data buffers are allocated with sizes the power of 2 multiples of
 * the block size, starting on an address a multiple of the allocated size.
 *
 * FIXME: callers of this function require a buffer to be allocated for
 * len=0. This is a waste of on-chip memory and should be fix. Then this
 * function should be changed to not allocate a buffer for len=0.
 */
static int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len)
{}

static void oxu_buf_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
{}

static inline void ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma)
{}

static inline void oxu_qtd_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
{}

static struct ehci_qtd *ehci_qtd_alloc(struct oxu_hcd *oxu)
{}

static void oxu_qh_free(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

static void qh_destroy(struct kref *kref)
{}

static struct ehci_qh *oxu_qh_alloc(struct oxu_hcd *oxu)
{}

/* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_get(struct ehci_qh *qh)
{}

static inline void qh_put(struct ehci_qh *qh)
{}

static void oxu_murb_free(struct oxu_hcd *oxu, struct oxu_murb *murb)
{}

static struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu)

{}

/* The queue heads and transfer descriptors are managed from pools tied
 * to each of the "per device" structures.
 * This is the initialisation and cleanup code.
 */
static void ehci_mem_cleanup(struct oxu_hcd *oxu)
{}

/* Remember to add cleanup code (above) if you add anything here.
 */
static int ehci_mem_init(struct oxu_hcd *oxu, gfp_t flags)
{}

/* Fill a qtd, returning how much of the buffer we were able to queue up.
 */
static int qtd_fill(struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
				int token, int maxpacket)
{}

static inline void qh_update(struct oxu_hcd *oxu,
				struct ehci_qh *qh, struct ehci_qtd *qtd)
{}

/* If it weren't for a common silicon quirk (writing the dummy into the qh
 * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
 * recovery (including urb dequeue) would need software changes to a QH...
 */
static void qh_refresh(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

static void qtd_copy_status(struct oxu_hcd *oxu, struct urb *urb,
				size_t length, u32 token)
{}

static void ehci_urb_done(struct oxu_hcd *oxu, struct urb *urb)
__releases(oxu->lock)
__acquires(oxu->lock)
{}

static void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh);
static void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh);

static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh);

#define HALT_BIT

/* Process and free completed qtds for a qh, returning URBs to drivers.
 * Chases up to qh->hw_current.  Returns number of completions called,
 * indicating how much "real" work we did.
 */
static unsigned qh_completions(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

/* High bandwidth multiplier, as encoded in highspeed endpoint descriptors */
#define hb_mult(wMaxPacketSize)
/* ... and packet size, for any kind of endpoint descriptor */
#define max_packet(wMaxPacketSize)

/* Reverse of qh_urb_transaction: free a list of TDs.
 * used for cleanup after errors, before HC sees an URB's TDs.
 */
static void qtd_list_free(struct oxu_hcd *oxu,
				struct urb *urb, struct list_head *head)
{}

/* Create a list of filled qtds for this URB; won't link into qh.
 */
static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu,
						struct urb *urb,
						struct list_head *head,
						gfp_t flags)
{}

/* Each QH holds a qtd list; a QH is used for everything except iso.
 *
 * For interrupt urbs, the scheduler must set the microframe scheduling
 * mask(s) each time the QH gets scheduled.  For highspeed, that's
 * just one microframe in the s-mask.  For split interrupt transactions
 * there are additional complications: c-mask, maybe FSTNs.
 */
static struct ehci_qh *qh_make(struct oxu_hcd *oxu,
				struct urb *urb, gfp_t flags)
{}

/* Move qh (and its qtds) onto async queue; maybe enable queue.
 */
static void qh_link_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

#define QH_ADDR_MASK

/*
 * For control/bulk/interrupt, return QH with these TDs appended.
 * Allocates and initializes the QH if necessary.
 * Returns null if it can't allocate a QH it needs to.
 * If the QH has TDs (urbs) already, that's great.
 */
static struct ehci_qh *qh_append_tds(struct oxu_hcd *oxu,
				struct urb *urb, struct list_head *qtd_list,
				int epnum, void	**ptr)
{}

static int submit_async(struct oxu_hcd	*oxu, struct urb *urb,
			struct list_head *qtd_list, gfp_t mem_flags)
{}

/* The async qh for the qtds being reclaimed are now unlinked from the HC */

static void end_unlink_async(struct oxu_hcd *oxu)
{}

/* makes sure the async qh will become idle */
/* caller must own oxu->lock */

static void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

static void scan_async(struct oxu_hcd *oxu)
{}

/*
 * periodic_next_shadow - return "next" pointer on shadow list
 * @periodic: host pointer to qh/itd/sitd
 * @tag: hardware tag for type of this record
 */
static union ehci_shadow *periodic_next_shadow(union ehci_shadow *periodic,
						__le32 tag)
{}

/* caller must hold oxu->lock */
static void periodic_unlink(struct oxu_hcd *oxu, unsigned frame, void *ptr)
{}

/* how many of the uframe's 125 usecs are allocated? */
static unsigned short periodic_usecs(struct oxu_hcd *oxu,
					unsigned frame, unsigned uframe)
{}

static int enable_periodic(struct oxu_hcd *oxu)
{}

static int disable_periodic(struct oxu_hcd *oxu)
{}

/* periodic schedule slots have iso tds (normal or split) first, then a
 * sparse tree for active interrupt transfers.
 *
 * this just links in a qh; caller guarantees uframe masks are set right.
 * no FSTN support (yet; oxu 0.96+)
 */
static int qh_link_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

static void qh_unlink_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

static int check_period(struct oxu_hcd *oxu,
			unsigned frame, unsigned uframe,
			unsigned period, unsigned usecs)
{}

static int check_intr_schedule(struct oxu_hcd	*oxu,
				unsigned frame, unsigned uframe,
				const struct ehci_qh *qh, __le32 *c_maskp)
{}

/* "first fit" scheduling policy used the first time through,
 * or when the previous schedule slot can't be re-used.
 */
static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

static int intr_submit(struct oxu_hcd *oxu, struct urb *urb,
			struct list_head *qtd_list, gfp_t mem_flags)
{}

static inline int itd_submit(struct oxu_hcd *oxu, struct urb *urb,
						gfp_t mem_flags)
{}

static inline int sitd_submit(struct oxu_hcd *oxu, struct urb *urb,
						gfp_t mem_flags)
{}

static void scan_periodic(struct oxu_hcd *oxu)
{}

/* On some systems, leaving remote wakeup enabled prevents system shutdown.
 * The firmware seems to think that powering off is a wakeup event!
 * This routine turns off remote wakeup and everything else, on all ports.
 */
static void ehci_turn_off_all_ports(struct oxu_hcd *oxu)
{}

static void ehci_port_power(struct oxu_hcd *oxu, int is_on)
{}

/* Called from some interrupts, timers, and so on.
 * It calls driver completion functions, after dropping oxu->lock.
 */
static void ehci_work(struct oxu_hcd *oxu)
{}

static void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
{}

/*
 * USB host controller methods
 */

static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
{}

static irqreturn_t oxu_irq(struct usb_hcd *hcd)
{}

static void oxu_watchdog(struct timer_list *t)
{}

/* One-time init, only for memory state.
 */
static int oxu_hcd_init(struct usb_hcd *hcd)
{}

/* Called during probe() after chip reset completes.
 */
static int oxu_reset(struct usb_hcd *hcd)
{}

static int oxu_run(struct usb_hcd *hcd)
{}

static void oxu_stop(struct usb_hcd *hcd)
{}

/* Kick in for silicon on any bus (not just pci, etc).
 * This forcibly disables dma and IRQs, helping kexec and other cases
 * where the next system software may expect clean state.
 */
static void oxu_shutdown(struct usb_hcd *hcd)
{}

/* Non-error returns are a promise to giveback() the urb later
 * we drop ownership so next owner (or urb unlink) can get it
 *
 * urb + dev is in hcd.self.controller.urb_list
 * we're queueing TDs onto software and hardware lists
 *
 * hcd-specific init for hcpriv hasn't been done yet
 *
 * NOTE:  control, bulk, and interrupt share the same code to append TDs
 * to a (possibly active) QH, and the same QH scanning code.
 */
static int __oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
				gfp_t mem_flags)
{}

/* This function is responsible for breaking URBs with big data size
 * into smaller size and processing small urbs in sequence.
 */
static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
				gfp_t mem_flags)
{}

/* Remove from hardware lists.
 * Completions normally happen asynchronously
 */
static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{}

/* Bulk qh holds the data toggle */
static void oxu_endpoint_disable(struct usb_hcd *hcd,
					struct usb_host_endpoint *ep)
{}

static int oxu_get_frame(struct usb_hcd *hcd)
{}

/* Build "status change" packet (one or two bytes) from HC registers */
static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf)
{}

/* Returns the speed of a device attached to a port on the root hub. */
static inline unsigned int oxu_port_speed(struct oxu_hcd *oxu,
						unsigned int portsc)
{}

#define PORT_WAKE_BITS
static int oxu_hub_control(struct usb_hcd *hcd, u16 typeReq,
				u16 wValue, u16 wIndex, char *buf, u16 wLength)
{}

#ifdef CONFIG_PM

static int oxu_bus_suspend(struct usb_hcd *hcd)
{}

/* Caller has locked the root hub, and should reset/reinit on error */
static int oxu_bus_resume(struct usb_hcd *hcd)
{}

#else

static int oxu_bus_suspend(struct usb_hcd *hcd)
{
	return 0;
}

static int oxu_bus_resume(struct usb_hcd *hcd)
{
	return 0;
}

#endif	/* CONFIG_PM */

static const struct hc_driver oxu_hc_driver =;

/*
 * Module stuff
 */

static void oxu_configuration(struct platform_device *pdev, void __iomem *base)
{}

static int oxu_verify_id(struct platform_device *pdev, void __iomem *base)
{}

static const struct hc_driver oxu_hc_driver;
static struct usb_hcd *oxu_create(struct platform_device *pdev,
				unsigned long memstart, unsigned long memlen,
				void __iomem *base, int irq, int otg)
{}

static int oxu_init(struct platform_device *pdev,
				unsigned long memstart, unsigned long memlen,
				void __iomem *base, int irq)
{}

static int oxu_drv_probe(struct platform_device *pdev)
{}

static void oxu_remove(struct platform_device *pdev, struct usb_hcd *hcd)
{}

static void oxu_drv_remove(struct platform_device *pdev)
{}

static void oxu_drv_shutdown(struct platform_device *pdev)
{}

#if 0
/* FIXME: TODO */
static int oxu_drv_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct usb_hcd *hcd = dev_get_drvdata(dev);

	return 0;
}

static int oxu_drv_resume(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct usb_hcd *hcd = dev_get_drvdata(dev);

	return 0;
}
#else
#define oxu_drv_suspend
#define oxu_drv_resume
#endif

static struct platform_driver oxu_driver =;

module_platform_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();