linux/drivers/usb/isp1760/isp1760-hcd.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Driver for the NXP ISP1760 chip
 *
 * However, the code might contain some bugs. What doesn't work for sure is:
 * - ISO
 * - OTG
 e The interrupt line is configured as active low, level.
 *
 * (c) 2007 Sebastian Siewior <[email protected]>
 *
 * (c) 2011 Arvid Brodin <[email protected]>
 *
 * Copyright 2021 Linaro, Rui Miguel Silva <[email protected]>
 *
 */
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <asm/unaligned.h>
#include <asm/cacheflush.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;

packet_enqueue;

static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
{}

#define dw_to_le32(x)
#define le32_to_dw(x)

/* urb state*/
#define DELETE_URB
#define NO_TRANSFER_ACTIVE

/* Philips Proprietary Transfer Descriptor (PTD) */
__dw;
struct ptd {};

struct ptd_le32 {};

#define PTD_OFFSET
#define ISO_PTD_OFFSET
#define INT_PTD_OFFSET
#define ATL_PTD_OFFSET
#define PAYLOAD_OFFSET

#define ISP_BANK_0
#define ISP_BANK_1
#define ISP_BANK_2
#define ISP_BANK_3

#define TO_DW(x)
#define TO_U32(x)

 /* ATL */
 /* DW0 */
#define DW0_VALID_BIT
#define FROM_DW0_VALID(x)
#define TO_DW0_LENGTH(x)
#define TO_DW0_MAXPACKET(x)
#define TO_DW0_MULTI(x)
#define TO_DW0_ENDPOINT(x)
/* DW1 */
#define TO_DW1_DEVICE_ADDR(x)
#define TO_DW1_PID_TOKEN(x)
#define DW1_TRANS_BULK
#define DW1_TRANS_INT
#define DW1_TRANS_SPLIT
#define DW1_SE_USB_LOSPEED
#define TO_DW1_PORT_NUM(x)
#define TO_DW1_HUB_NUM(x)
/* DW2 */
#define TO_DW2_DATA_START_ADDR(x)
#define TO_DW2_RL(x)
#define FROM_DW2_RL(x)
/* DW3 */
#define FROM_DW3_NRBYTESTRANSFERRED(x)
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x)
#define TO_DW3_NAKCOUNT(x)
#define FROM_DW3_NAKCOUNT(x)
#define TO_DW3_CERR(x)
#define FROM_DW3_CERR(x)
#define TO_DW3_DATA_TOGGLE(x)
#define FROM_DW3_DATA_TOGGLE(x)
#define TO_DW3_PING(x)
#define FROM_DW3_PING(x)
#define DW3_ERROR_BIT
#define DW3_BABBLE_BIT
#define DW3_HALT_BIT
#define DW3_ACTIVE_BIT
#define FROM_DW3_ACTIVE(x)

#define INT_UNDERRUN
#define INT_BABBLE
#define INT_EXACT

#define SETUP_PID
#define IN_PID
#define OUT_PID

/* Errata 1 */
#define RL_COUNTER
#define NAK_COUNTER
#define ERR_COUNTER

struct isp1760_qtd {};

/* Queue head, one for each active endpoint */
struct isp1760_qh {};

struct urb_listitem {};

static const u32 isp176x_hc_portsc1_fields[] =;

/*
 * Access functions for isp176x registers regmap fields
 */
static u32 isp1760_hcd_read(struct usb_hcd *hcd, u32 field)
{}

/*
 * We need, in isp176x, to write directly the values to the portsc1
 * register so it will make the other values to trigger.
 */
static void isp1760_hcd_portsc1_set_clear(struct isp1760_hcd *priv, u32 field,
					  u32 val)
{}

static void isp1760_hcd_write(struct usb_hcd *hcd, u32 field, u32 val)
{}

static void isp1760_hcd_set(struct usb_hcd *hcd, u32 field)
{}

static void isp1760_hcd_clear(struct usb_hcd *hcd, u32 field)
{}

static int isp1760_hcd_set_and_wait(struct usb_hcd *hcd, u32 field,
				    u32 timeout_us)
{}

static int isp1760_hcd_set_and_wait_swap(struct usb_hcd *hcd, u32 field,
					 u32 timeout_us)
{}

static int isp1760_hcd_clear_and_wait(struct usb_hcd *hcd, u32 field,
				      u32 timeout_us)
{}

static bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field)
{}

static bool isp1760_hcd_ppc_is_set(struct usb_hcd *hcd)
{}

static u32 isp1760_hcd_n_ports(struct usb_hcd *hcd)
{}

/*
 * Access functions for isp176x memory (offset >= 0x0400).
 *
 * bank_reads8() reads memory locations prefetched by an earlier write to
 * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
 * bank optimizations, you should use the more generic mem_read() below.
 *
 * For access to ptd memory, use the specialized ptd_read() and ptd_write()
 * below.
 *
 * These functions copy via MMIO data to/from the device. memcpy_{to|from}io()
 * doesn't quite work because some people have to enforce 32-bit access
 */
static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
							__u32 *dst, u32 bytes)
{}

static void isp1760_mem_read(struct usb_hcd *hcd, u32 src_offset, void *dst,
			     u32 bytes)
{}

/*
 * ISP1763 does not have the banks direct host controller memory access,
 * needs to use the HC_DATA register. Add data read/write according to this,
 * and also adjust 16bit access.
 */
static void isp1763_mem_read(struct usb_hcd *hcd, u16 srcaddr,
			     u16 *dstptr, u32 bytes)
{}

static void mem_read(struct usb_hcd *hcd, u32 src_offset, __u32 *dst,
		     u32 bytes)
{}

static void isp1760_mem_write(void __iomem *dst_base, u32 dst_offset,
			      __u32 const *src, u32 bytes)
{}

static void isp1763_mem_write(struct usb_hcd *hcd, u16 dstaddr, u16 *src,
			      u32 bytes)
{}

static void mem_write(struct usb_hcd *hcd, u32 dst_offset, __u32 *src,
		      u32 bytes)
{}

/*
 * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
 * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
 */
static void isp1760_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
			     struct ptd *ptd)
{}

static void isp1763_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
			     struct ptd *ptd)
{}

static void ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
		     struct ptd *ptd)
{}

static void isp1763_ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
			      struct ptd *cpu_ptd)
{}

static void isp1760_ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
			      struct ptd *ptd)
{}

static void ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
		      struct ptd *ptd)
{}

/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
static void init_memory(struct isp1760_hcd *priv)
{}

static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
{}

static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
{}

/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset(struct usb_hcd *hcd)
{}

static struct isp1760_qh *qh_alloc(gfp_t flags)
{}

static void qh_free(struct isp1760_qh *qh)
{}

/* one-time init, only for memory state */
static int priv_init(struct usb_hcd *hcd)
{}

static int isp1760_hc_setup(struct usb_hcd *hcd)
{}

static u32 base_to_chip(u32 base)
{}

static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)
{}

/* 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

static void create_ptd_atl(struct isp1760_qh *qh,
			struct isp1760_qtd *qtd, struct ptd *ptd)
{}

static void transform_add_int(struct isp1760_qh *qh,
			struct isp1760_qtd *qtd, struct ptd *ptd)
{}

static void create_ptd_int(struct isp1760_qh *qh,
			struct isp1760_qtd *qtd, struct ptd *ptd)
{}

static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)
__releases(priv->lock)
__acquires(priv->lock)
{}

static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
								u8 packet_type)
{}

static void qtd_free(struct isp1760_qtd *qtd)
{}

static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
				struct isp1760_slotinfo *slots,
				struct isp1760_qtd *qtd, struct isp1760_qh *qh,
				struct ptd *ptd)
{}

static int is_short_bulk(struct isp1760_qtd *qtd)
{}

static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
						struct list_head *urb_list)
{}

#define ENQUEUE_DEPTH
static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
{}

static void schedule_ptds(struct usb_hcd *hcd)
{}

#define PTD_STATE_QTD_DONE
#define PTD_STATE_QTD_RELOAD
#define PTD_STATE_URB_RETIRE

static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
								struct urb *urb)
{}

static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
								struct urb *urb)
{}

static void handle_done_ptds(struct usb_hcd *hcd)
{}

static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
{}

/*
 * Workaround for problem described in chip errata 2:
 *
 * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
 * One solution suggested in the errata is to use SOF interrupts _instead_of_
 * ATL done interrupts (the "instead of" might be important since it seems
 * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
 * to set the PTD's done bit in addition to not generating an interrupt!).
 *
 * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
 * done bit is not being set. This is bad - it blocks the endpoint until reboot.
 *
 * If we use SOF interrupts only, we get latency between ptd completion and the
 * actual handling. This is very noticeable in testusb runs which takes several
 * minutes longer without ATL interrupts.
 *
 * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
 * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
 * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
 * completed and its done map bit is set.
 *
 * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
 * not to cause too much lag when this HW bug occurs, while still hopefully
 * ensuring that the check does not falsely trigger.
 */
#define SLOT_TIMEOUT
#define SLOT_CHECK_PERIOD
static struct timer_list errata2_timer;
static struct usb_hcd *errata2_timer_hcd;

static void errata2_function(struct timer_list *unused)
{}

static int isp1763_run(struct usb_hcd *hcd)
{}

static int isp1760_run(struct usb_hcd *hcd)
{}

static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
{}

static void qtd_list_free(struct list_head *qtd_list)
{}

/*
 * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
 * Also calculate the PID type (SETUP/IN/OUT) for each packet.
 */
static void packetize_urb(struct usb_hcd *hcd,
		struct urb *urb, struct list_head *head, gfp_t flags)
{}

static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
		gfp_t mem_flags)
{}

static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
		struct isp1760_qh *qh)
{}

/*
 * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
 * any active transfer belonging to the urb in the process.
 */
static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
						struct isp1760_qtd *qtd)
{}

static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
		int status)
{}

static void isp1760_endpoint_disable(struct usb_hcd *hcd,
		struct usb_host_endpoint *ep)
{}

static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
{}

static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
		struct usb_hub_descriptor *desc)
{}

#define PORT_WAKE_BITS

static void check_reset_complete(struct usb_hcd *hcd, int index)
{}

static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
		u16 wValue, u16 wIndex, char *buf, u16 wLength)
{}

static int isp1760_get_frame(struct usb_hcd *hcd)
{}

static void isp1760_stop(struct usb_hcd *hcd)
{}

static void isp1760_shutdown(struct usb_hcd *hcd)
{}

static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
						struct usb_host_endpoint *ep)
{}


static const struct hc_driver isp1760_hc_driver =;

int __init isp1760_init_kmem_once(void)
{}

void isp1760_deinit_kmem_cache(void)
{}

int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
			 int irq, unsigned long irqflags,
			 struct device *dev)
{}

void isp1760_hcd_unregister(struct isp1760_hcd *priv)
{}