162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for the NXP ISP1760 chip
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * However, the code might contain some bugs. What doesn't work for sure is:
662306a36Sopenharmony_ci * - ISO
762306a36Sopenharmony_ci * - OTG
862306a36Sopenharmony_ci e The interrupt line is configured as active low, level.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/list.h>
2262306a36Sopenharmony_ci#include <linux/usb.h>
2362306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2462306a36Sopenharmony_ci#include <linux/debugfs.h>
2562306a36Sopenharmony_ci#include <linux/uaccess.h>
2662306a36Sopenharmony_ci#include <linux/io.h>
2762306a36Sopenharmony_ci#include <linux/iopoll.h>
2862306a36Sopenharmony_ci#include <linux/mm.h>
2962306a36Sopenharmony_ci#include <linux/timer.h>
3062306a36Sopenharmony_ci#include <asm/unaligned.h>
3162306a36Sopenharmony_ci#include <asm/cacheflush.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include "isp1760-core.h"
3462306a36Sopenharmony_ci#include "isp1760-hcd.h"
3562306a36Sopenharmony_ci#include "isp1760-regs.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic struct kmem_cache *qtd_cachep;
3862306a36Sopenharmony_cistatic struct kmem_cache *qh_cachep;
3962306a36Sopenharmony_cistatic struct kmem_cache *urb_listitem_cachep;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_citypedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
4262306a36Sopenharmony_ci		struct isp1760_qtd *qtd);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	return *(struct isp1760_hcd **)hcd->hcd_priv;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define dw_to_le32(x)	(cpu_to_le32((__force u32)x))
5062306a36Sopenharmony_ci#define le32_to_dw(x)	((__force __dw)(le32_to_cpu(x)))
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* urb state*/
5362306a36Sopenharmony_ci#define DELETE_URB		(0x0008)
5462306a36Sopenharmony_ci#define NO_TRANSFER_ACTIVE	(0xffffffff)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Philips Proprietary Transfer Descriptor (PTD) */
5762306a36Sopenharmony_citypedef __u32 __bitwise __dw;
5862306a36Sopenharmony_cistruct ptd {
5962306a36Sopenharmony_ci	__dw dw0;
6062306a36Sopenharmony_ci	__dw dw1;
6162306a36Sopenharmony_ci	__dw dw2;
6262306a36Sopenharmony_ci	__dw dw3;
6362306a36Sopenharmony_ci	__dw dw4;
6462306a36Sopenharmony_ci	__dw dw5;
6562306a36Sopenharmony_ci	__dw dw6;
6662306a36Sopenharmony_ci	__dw dw7;
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct ptd_le32 {
7062306a36Sopenharmony_ci	__le32 dw0;
7162306a36Sopenharmony_ci	__le32 dw1;
7262306a36Sopenharmony_ci	__le32 dw2;
7362306a36Sopenharmony_ci	__le32 dw3;
7462306a36Sopenharmony_ci	__le32 dw4;
7562306a36Sopenharmony_ci	__le32 dw5;
7662306a36Sopenharmony_ci	__le32 dw6;
7762306a36Sopenharmony_ci	__le32 dw7;
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define PTD_OFFSET		0x0400
8162306a36Sopenharmony_ci#define ISO_PTD_OFFSET		0x0400
8262306a36Sopenharmony_ci#define INT_PTD_OFFSET		0x0800
8362306a36Sopenharmony_ci#define ATL_PTD_OFFSET		0x0c00
8462306a36Sopenharmony_ci#define PAYLOAD_OFFSET		0x1000
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define ISP_BANK_0		0x00
8762306a36Sopenharmony_ci#define ISP_BANK_1		0x01
8862306a36Sopenharmony_ci#define ISP_BANK_2		0x02
8962306a36Sopenharmony_ci#define ISP_BANK_3		0x03
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define TO_DW(x)	((__force __dw)x)
9262306a36Sopenharmony_ci#define TO_U32(x)	((__force u32)x)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci /* ATL */
9562306a36Sopenharmony_ci /* DW0 */
9662306a36Sopenharmony_ci#define DW0_VALID_BIT			TO_DW(1)
9762306a36Sopenharmony_ci#define FROM_DW0_VALID(x)		(TO_U32(x) & 0x01)
9862306a36Sopenharmony_ci#define TO_DW0_LENGTH(x)		TO_DW((((u32)x) << 3))
9962306a36Sopenharmony_ci#define TO_DW0_MAXPACKET(x)		TO_DW((((u32)x) << 18))
10062306a36Sopenharmony_ci#define TO_DW0_MULTI(x)			TO_DW((((u32)x) << 29))
10162306a36Sopenharmony_ci#define TO_DW0_ENDPOINT(x)		TO_DW((((u32)x) << 31))
10262306a36Sopenharmony_ci/* DW1 */
10362306a36Sopenharmony_ci#define TO_DW1_DEVICE_ADDR(x)		TO_DW((((u32)x) << 3))
10462306a36Sopenharmony_ci#define TO_DW1_PID_TOKEN(x)		TO_DW((((u32)x) << 10))
10562306a36Sopenharmony_ci#define DW1_TRANS_BULK			TO_DW(((u32)2 << 12))
10662306a36Sopenharmony_ci#define DW1_TRANS_INT			TO_DW(((u32)3 << 12))
10762306a36Sopenharmony_ci#define DW1_TRANS_SPLIT			TO_DW(((u32)1 << 14))
10862306a36Sopenharmony_ci#define DW1_SE_USB_LOSPEED		TO_DW(((u32)2 << 16))
10962306a36Sopenharmony_ci#define TO_DW1_PORT_NUM(x)		TO_DW((((u32)x) << 18))
11062306a36Sopenharmony_ci#define TO_DW1_HUB_NUM(x)		TO_DW((((u32)x) << 25))
11162306a36Sopenharmony_ci/* DW2 */
11262306a36Sopenharmony_ci#define TO_DW2_DATA_START_ADDR(x)	TO_DW((((u32)x) << 8))
11362306a36Sopenharmony_ci#define TO_DW2_RL(x)			TO_DW(((x) << 25))
11462306a36Sopenharmony_ci#define FROM_DW2_RL(x)			((TO_U32(x) >> 25) & 0xf)
11562306a36Sopenharmony_ci/* DW3 */
11662306a36Sopenharmony_ci#define FROM_DW3_NRBYTESTRANSFERRED(x)		TO_U32((x) & 0x3fff)
11762306a36Sopenharmony_ci#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x)	TO_U32((x) & 0x07ff)
11862306a36Sopenharmony_ci#define TO_DW3_NAKCOUNT(x)		TO_DW(((x) << 19))
11962306a36Sopenharmony_ci#define FROM_DW3_NAKCOUNT(x)		((TO_U32(x) >> 19) & 0xf)
12062306a36Sopenharmony_ci#define TO_DW3_CERR(x)			TO_DW(((x) << 23))
12162306a36Sopenharmony_ci#define FROM_DW3_CERR(x)		((TO_U32(x) >> 23) & 0x3)
12262306a36Sopenharmony_ci#define TO_DW3_DATA_TOGGLE(x)		TO_DW(((x) << 25))
12362306a36Sopenharmony_ci#define FROM_DW3_DATA_TOGGLE(x)		((TO_U32(x) >> 25) & 0x1)
12462306a36Sopenharmony_ci#define TO_DW3_PING(x)			TO_DW(((x) << 26))
12562306a36Sopenharmony_ci#define FROM_DW3_PING(x)		((TO_U32(x) >> 26) & 0x1)
12662306a36Sopenharmony_ci#define DW3_ERROR_BIT			TO_DW((1 << 28))
12762306a36Sopenharmony_ci#define DW3_BABBLE_BIT			TO_DW((1 << 29))
12862306a36Sopenharmony_ci#define DW3_HALT_BIT			TO_DW((1 << 30))
12962306a36Sopenharmony_ci#define DW3_ACTIVE_BIT			TO_DW((1 << 31))
13062306a36Sopenharmony_ci#define FROM_DW3_ACTIVE(x)		((TO_U32(x) >> 31) & 0x01)
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define INT_UNDERRUN			(1 << 2)
13362306a36Sopenharmony_ci#define INT_BABBLE			(1 << 1)
13462306a36Sopenharmony_ci#define INT_EXACT			(1 << 0)
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define SETUP_PID	(2)
13762306a36Sopenharmony_ci#define IN_PID		(1)
13862306a36Sopenharmony_ci#define OUT_PID		(0)
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* Errata 1 */
14162306a36Sopenharmony_ci#define RL_COUNTER	(0)
14262306a36Sopenharmony_ci#define NAK_COUNTER	(0)
14362306a36Sopenharmony_ci#define ERR_COUNTER	(3)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistruct isp1760_qtd {
14662306a36Sopenharmony_ci	u8 packet_type;
14762306a36Sopenharmony_ci	void *data_buffer;
14862306a36Sopenharmony_ci	u32 payload_addr;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* the rest is HCD-private */
15162306a36Sopenharmony_ci	struct list_head qtd_list;
15262306a36Sopenharmony_ci	struct urb *urb;
15362306a36Sopenharmony_ci	size_t length;
15462306a36Sopenharmony_ci	size_t actual_length;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* QTD_ENQUEUED:	waiting for transfer (inactive) */
15762306a36Sopenharmony_ci	/* QTD_PAYLOAD_ALLOC:	chip mem has been allocated for payload */
15862306a36Sopenharmony_ci	/* QTD_XFER_STARTED:	valid ptd has been written to isp176x - only
15962306a36Sopenharmony_ci				interrupt handler may touch this qtd! */
16062306a36Sopenharmony_ci	/* QTD_XFER_COMPLETE:	payload has been transferred successfully */
16162306a36Sopenharmony_ci	/* QTD_RETIRE:		transfer error/abort qtd */
16262306a36Sopenharmony_ci#define QTD_ENQUEUED		0
16362306a36Sopenharmony_ci#define QTD_PAYLOAD_ALLOC	1
16462306a36Sopenharmony_ci#define QTD_XFER_STARTED	2
16562306a36Sopenharmony_ci#define QTD_XFER_COMPLETE	3
16662306a36Sopenharmony_ci#define QTD_RETIRE		4
16762306a36Sopenharmony_ci	u32 status;
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* Queue head, one for each active endpoint */
17162306a36Sopenharmony_cistruct isp1760_qh {
17262306a36Sopenharmony_ci	struct list_head qh_list;
17362306a36Sopenharmony_ci	struct list_head qtd_list;
17462306a36Sopenharmony_ci	u32 toggle;
17562306a36Sopenharmony_ci	u32 ping;
17662306a36Sopenharmony_ci	int slot;
17762306a36Sopenharmony_ci	int tt_buffer_dirty;	/* See USB2.0 spec section 11.17.5 */
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistruct urb_listitem {
18162306a36Sopenharmony_ci	struct list_head urb_list;
18262306a36Sopenharmony_ci	struct urb *urb;
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic const u32 isp176x_hc_portsc1_fields[] = {
18662306a36Sopenharmony_ci	[PORT_OWNER]		= BIT(13),
18762306a36Sopenharmony_ci	[PORT_POWER]		= BIT(12),
18862306a36Sopenharmony_ci	[PORT_LSTATUS]		= BIT(10),
18962306a36Sopenharmony_ci	[PORT_RESET]		= BIT(8),
19062306a36Sopenharmony_ci	[PORT_SUSPEND]		= BIT(7),
19162306a36Sopenharmony_ci	[PORT_RESUME]		= BIT(6),
19262306a36Sopenharmony_ci	[PORT_PE]		= BIT(2),
19362306a36Sopenharmony_ci	[PORT_CSC]		= BIT(1),
19462306a36Sopenharmony_ci	[PORT_CONNECT]		= BIT(0),
19562306a36Sopenharmony_ci};
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/*
19862306a36Sopenharmony_ci * Access functions for isp176x registers regmap fields
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_cistatic u32 isp1760_hcd_read(struct usb_hcd *hcd, u32 field)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return isp1760_field_read(priv->fields, field);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/*
20862306a36Sopenharmony_ci * We need, in isp176x, to write directly the values to the portsc1
20962306a36Sopenharmony_ci * register so it will make the other values to trigger.
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_cistatic void isp1760_hcd_portsc1_set_clear(struct isp1760_hcd *priv, u32 field,
21262306a36Sopenharmony_ci					  u32 val)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	u32 bit = isp176x_hc_portsc1_fields[field];
21562306a36Sopenharmony_ci	u16 portsc1_reg = priv->is_isp1763 ? ISP1763_HC_PORTSC1 :
21662306a36Sopenharmony_ci		ISP176x_HC_PORTSC1;
21762306a36Sopenharmony_ci	u32 port_status = readl(priv->base + portsc1_reg);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (val)
22062306a36Sopenharmony_ci		writel(port_status | bit, priv->base + portsc1_reg);
22162306a36Sopenharmony_ci	else
22262306a36Sopenharmony_ci		writel(port_status & ~bit, priv->base + portsc1_reg);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void isp1760_hcd_write(struct usb_hcd *hcd, u32 field, u32 val)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (unlikely((field >= PORT_OWNER && field <= PORT_CONNECT)))
23062306a36Sopenharmony_ci		return isp1760_hcd_portsc1_set_clear(priv, field, val);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	isp1760_field_write(priv->fields, field, val);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void isp1760_hcd_set(struct usb_hcd *hcd, u32 field)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	isp1760_hcd_write(hcd, field, 0xFFFFFFFF);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic void isp1760_hcd_clear(struct usb_hcd *hcd, u32 field)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	isp1760_hcd_write(hcd, field, 0);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int isp1760_hcd_set_and_wait(struct usb_hcd *hcd, u32 field,
24662306a36Sopenharmony_ci				    u32 timeout_us)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
24962306a36Sopenharmony_ci	u32 val;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	isp1760_hcd_set(hcd, field);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	return regmap_field_read_poll_timeout(priv->fields[field], val,
25462306a36Sopenharmony_ci					      val, 0, timeout_us);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int isp1760_hcd_set_and_wait_swap(struct usb_hcd *hcd, u32 field,
25862306a36Sopenharmony_ci					 u32 timeout_us)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
26162306a36Sopenharmony_ci	u32 val;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	isp1760_hcd_set(hcd, field);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return regmap_field_read_poll_timeout(priv->fields[field], val,
26662306a36Sopenharmony_ci					      !val, 0, timeout_us);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int isp1760_hcd_clear_and_wait(struct usb_hcd *hcd, u32 field,
27062306a36Sopenharmony_ci				      u32 timeout_us)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
27362306a36Sopenharmony_ci	u32 val;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, field);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return regmap_field_read_poll_timeout(priv->fields[field], val,
27862306a36Sopenharmony_ci					      !val, 0, timeout_us);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	return !!isp1760_hcd_read(hcd, field);
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic bool isp1760_hcd_ppc_is_set(struct usb_hcd *hcd)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (priv->is_isp1763)
29162306a36Sopenharmony_ci		return true;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return isp1760_hcd_is_set(hcd, HCS_PPC);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic u32 isp1760_hcd_n_ports(struct usb_hcd *hcd)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (priv->is_isp1763)
30162306a36Sopenharmony_ci		return 1;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	return isp1760_hcd_read(hcd, HCS_N_PORTS);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/*
30762306a36Sopenharmony_ci * Access functions for isp176x memory (offset >= 0x0400).
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * bank_reads8() reads memory locations prefetched by an earlier write to
31062306a36Sopenharmony_ci * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
31162306a36Sopenharmony_ci * bank optimizations, you should use the more generic mem_read() below.
31262306a36Sopenharmony_ci *
31362306a36Sopenharmony_ci * For access to ptd memory, use the specialized ptd_read() and ptd_write()
31462306a36Sopenharmony_ci * below.
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * These functions copy via MMIO data to/from the device. memcpy_{to|from}io()
31762306a36Sopenharmony_ci * doesn't quite work because some people have to enforce 32-bit access
31862306a36Sopenharmony_ci */
31962306a36Sopenharmony_cistatic void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
32062306a36Sopenharmony_ci							__u32 *dst, u32 bytes)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	__u32 __iomem *src;
32362306a36Sopenharmony_ci	u32 val;
32462306a36Sopenharmony_ci	__u8 *src_byteptr;
32562306a36Sopenharmony_ci	__u8 *dst_byteptr;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	src = src_base + (bank_addr | src_offset);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (src_offset < PAYLOAD_OFFSET) {
33062306a36Sopenharmony_ci		while (bytes >= 4) {
33162306a36Sopenharmony_ci			*dst = readl_relaxed(src);
33262306a36Sopenharmony_ci			bytes -= 4;
33362306a36Sopenharmony_ci			src++;
33462306a36Sopenharmony_ci			dst++;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci	} else {
33762306a36Sopenharmony_ci		while (bytes >= 4) {
33862306a36Sopenharmony_ci			*dst = __raw_readl(src);
33962306a36Sopenharmony_ci			bytes -= 4;
34062306a36Sopenharmony_ci			src++;
34162306a36Sopenharmony_ci			dst++;
34262306a36Sopenharmony_ci		}
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (!bytes)
34662306a36Sopenharmony_ci		return;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
34962306a36Sopenharmony_ci	 * allocated.
35062306a36Sopenharmony_ci	 */
35162306a36Sopenharmony_ci	if (src_offset < PAYLOAD_OFFSET)
35262306a36Sopenharmony_ci		val = readl_relaxed(src);
35362306a36Sopenharmony_ci	else
35462306a36Sopenharmony_ci		val = __raw_readl(src);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	dst_byteptr = (void *) dst;
35762306a36Sopenharmony_ci	src_byteptr = (void *) &val;
35862306a36Sopenharmony_ci	while (bytes > 0) {
35962306a36Sopenharmony_ci		*dst_byteptr = *src_byteptr;
36062306a36Sopenharmony_ci		dst_byteptr++;
36162306a36Sopenharmony_ci		src_byteptr++;
36262306a36Sopenharmony_ci		bytes--;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic void isp1760_mem_read(struct usb_hcd *hcd, u32 src_offset, void *dst,
36762306a36Sopenharmony_ci			     u32 bytes)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	isp1760_reg_write(priv->regs, ISP176x_HC_MEMORY, src_offset);
37262306a36Sopenharmony_ci	ndelay(100);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	bank_reads8(priv->base, src_offset, ISP_BANK_0, dst, bytes);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/*
37862306a36Sopenharmony_ci * ISP1763 does not have the banks direct host controller memory access,
37962306a36Sopenharmony_ci * needs to use the HC_DATA register. Add data read/write according to this,
38062306a36Sopenharmony_ci * and also adjust 16bit access.
38162306a36Sopenharmony_ci */
38262306a36Sopenharmony_cistatic void isp1763_mem_read(struct usb_hcd *hcd, u16 srcaddr,
38362306a36Sopenharmony_ci			     u16 *dstptr, u32 bytes)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* Write the starting device address to the hcd memory register */
38862306a36Sopenharmony_ci	isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, srcaddr);
38962306a36Sopenharmony_ci	ndelay(100); /* Delay between consecutive access */
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* As long there are at least 16-bit to read ... */
39262306a36Sopenharmony_ci	while (bytes >= 2) {
39362306a36Sopenharmony_ci		*dstptr = __raw_readw(priv->base + ISP1763_HC_DATA);
39462306a36Sopenharmony_ci		bytes -= 2;
39562306a36Sopenharmony_ci		dstptr++;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* If there are no more bytes to read, return */
39962306a36Sopenharmony_ci	if (bytes <= 0)
40062306a36Sopenharmony_ci		return;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	*((u8 *)dstptr) = (u8)(readw(priv->base + ISP1763_HC_DATA) & 0xFF);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic void mem_read(struct usb_hcd *hcd, u32 src_offset, __u32 *dst,
40662306a36Sopenharmony_ci		     u32 bytes)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (!priv->is_isp1763)
41162306a36Sopenharmony_ci		return isp1760_mem_read(hcd, src_offset, (u16 *)dst, bytes);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	isp1763_mem_read(hcd, (u16)src_offset, (u16 *)dst, bytes);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic void isp1760_mem_write(void __iomem *dst_base, u32 dst_offset,
41762306a36Sopenharmony_ci			      __u32 const *src, u32 bytes)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	__u32 __iomem *dst;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	dst = dst_base + dst_offset;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (dst_offset < PAYLOAD_OFFSET) {
42462306a36Sopenharmony_ci		while (bytes >= 4) {
42562306a36Sopenharmony_ci			writel_relaxed(*src, dst);
42662306a36Sopenharmony_ci			bytes -= 4;
42762306a36Sopenharmony_ci			src++;
42862306a36Sopenharmony_ci			dst++;
42962306a36Sopenharmony_ci		}
43062306a36Sopenharmony_ci	} else {
43162306a36Sopenharmony_ci		while (bytes >= 4) {
43262306a36Sopenharmony_ci			__raw_writel(*src, dst);
43362306a36Sopenharmony_ci			bytes -= 4;
43462306a36Sopenharmony_ci			src++;
43562306a36Sopenharmony_ci			dst++;
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (!bytes)
44062306a36Sopenharmony_ci		return;
44162306a36Sopenharmony_ci	/* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the
44262306a36Sopenharmony_ci	 * extra bytes should not be read by the HW.
44362306a36Sopenharmony_ci	 */
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (dst_offset < PAYLOAD_OFFSET)
44662306a36Sopenharmony_ci		writel_relaxed(*src, dst);
44762306a36Sopenharmony_ci	else
44862306a36Sopenharmony_ci		__raw_writel(*src, dst);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic void isp1763_mem_write(struct usb_hcd *hcd, u16 dstaddr, u16 *src,
45262306a36Sopenharmony_ci			      u32 bytes)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/* Write the starting device address to the hcd memory register */
45762306a36Sopenharmony_ci	isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, dstaddr);
45862306a36Sopenharmony_ci	ndelay(100); /* Delay between consecutive access */
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	while (bytes >= 2) {
46162306a36Sopenharmony_ci		/* Get and write the data; then adjust the data ptr and len */
46262306a36Sopenharmony_ci		__raw_writew(*src, priv->base + ISP1763_HC_DATA);
46362306a36Sopenharmony_ci		bytes -= 2;
46462306a36Sopenharmony_ci		src++;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* If there are no more bytes to process, return */
46862306a36Sopenharmony_ci	if (bytes <= 0)
46962306a36Sopenharmony_ci		return;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/*
47262306a36Sopenharmony_ci	 * The only way to get here is if there is a single byte left,
47362306a36Sopenharmony_ci	 * get it and write it to the data reg;
47462306a36Sopenharmony_ci	 */
47562306a36Sopenharmony_ci	writew(*((u8 *)src), priv->base + ISP1763_HC_DATA);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void mem_write(struct usb_hcd *hcd, u32 dst_offset, __u32 *src,
47962306a36Sopenharmony_ci		      u32 bytes)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (!priv->is_isp1763)
48462306a36Sopenharmony_ci		return isp1760_mem_write(priv->base, dst_offset, src, bytes);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	isp1763_mem_write(hcd, dst_offset, (u16 *)src, bytes);
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/*
49062306a36Sopenharmony_ci * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
49162306a36Sopenharmony_ci * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_cistatic void isp1760_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
49462306a36Sopenharmony_ci			     struct ptd *ptd)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	u16 src_offset = ptd_offset + slot * sizeof(*ptd);
49762306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	isp1760_reg_write(priv->regs, ISP176x_HC_MEMORY, src_offset);
50062306a36Sopenharmony_ci	ndelay(90);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	bank_reads8(priv->base, src_offset, ISP_BANK_0, (void *)ptd,
50362306a36Sopenharmony_ci		    sizeof(*ptd));
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic void isp1763_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
50762306a36Sopenharmony_ci			     struct ptd *ptd)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	u16 src_offset = ptd_offset + slot * sizeof(*ptd);
51062306a36Sopenharmony_ci	struct ptd_le32 le32_ptd;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	isp1763_mem_read(hcd, src_offset, (u16 *)&le32_ptd, sizeof(le32_ptd));
51362306a36Sopenharmony_ci	/* Normalize the data obtained */
51462306a36Sopenharmony_ci	ptd->dw0 = le32_to_dw(le32_ptd.dw0);
51562306a36Sopenharmony_ci	ptd->dw1 = le32_to_dw(le32_ptd.dw1);
51662306a36Sopenharmony_ci	ptd->dw2 = le32_to_dw(le32_ptd.dw2);
51762306a36Sopenharmony_ci	ptd->dw3 = le32_to_dw(le32_ptd.dw3);
51862306a36Sopenharmony_ci	ptd->dw4 = le32_to_dw(le32_ptd.dw4);
51962306a36Sopenharmony_ci	ptd->dw5 = le32_to_dw(le32_ptd.dw5);
52062306a36Sopenharmony_ci	ptd->dw6 = le32_to_dw(le32_ptd.dw6);
52162306a36Sopenharmony_ci	ptd->dw7 = le32_to_dw(le32_ptd.dw7);
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic void ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
52562306a36Sopenharmony_ci		     struct ptd *ptd)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (!priv->is_isp1763)
53062306a36Sopenharmony_ci		return isp1760_ptd_read(hcd, ptd_offset, slot, ptd);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	isp1763_ptd_read(hcd, ptd_offset, slot, ptd);
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic void isp1763_ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
53662306a36Sopenharmony_ci			      struct ptd *cpu_ptd)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	u16 dst_offset = ptd_offset + slot * sizeof(*cpu_ptd);
53962306a36Sopenharmony_ci	struct ptd_le32 ptd;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	ptd.dw0 = dw_to_le32(cpu_ptd->dw0);
54262306a36Sopenharmony_ci	ptd.dw1 = dw_to_le32(cpu_ptd->dw1);
54362306a36Sopenharmony_ci	ptd.dw2 = dw_to_le32(cpu_ptd->dw2);
54462306a36Sopenharmony_ci	ptd.dw3 = dw_to_le32(cpu_ptd->dw3);
54562306a36Sopenharmony_ci	ptd.dw4 = dw_to_le32(cpu_ptd->dw4);
54662306a36Sopenharmony_ci	ptd.dw5 = dw_to_le32(cpu_ptd->dw5);
54762306a36Sopenharmony_ci	ptd.dw6 = dw_to_le32(cpu_ptd->dw6);
54862306a36Sopenharmony_ci	ptd.dw7 = dw_to_le32(cpu_ptd->dw7);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	isp1763_mem_write(hcd, dst_offset,  (u16 *)&ptd.dw0,
55162306a36Sopenharmony_ci			  8 * sizeof(ptd.dw0));
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic void isp1760_ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
55562306a36Sopenharmony_ci			      struct ptd *ptd)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	u32 dst_offset = ptd_offset + slot * sizeof(*ptd);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/*
56062306a36Sopenharmony_ci	 * Make sure dw0 gets written last (after other dw's and after payload)
56162306a36Sopenharmony_ci	 *  since it contains the enable bit
56262306a36Sopenharmony_ci	 */
56362306a36Sopenharmony_ci	isp1760_mem_write(base, dst_offset + sizeof(ptd->dw0),
56462306a36Sopenharmony_ci			  (__force u32 *)&ptd->dw1, 7 * sizeof(ptd->dw1));
56562306a36Sopenharmony_ci	wmb();
56662306a36Sopenharmony_ci	isp1760_mem_write(base, dst_offset, (__force u32 *)&ptd->dw0,
56762306a36Sopenharmony_ci			  sizeof(ptd->dw0));
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic void ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
57162306a36Sopenharmony_ci		      struct ptd *ptd)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (!priv->is_isp1763)
57662306a36Sopenharmony_ci		return isp1760_ptd_write(priv->base, ptd_offset, slot, ptd);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	isp1763_ptd_write(hcd, ptd_offset, slot, ptd);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
58262306a36Sopenharmony_cistatic void init_memory(struct isp1760_hcd *priv)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem = priv->memory_layout;
58562306a36Sopenharmony_ci	int i, j, curr;
58662306a36Sopenharmony_ci	u32 payload_addr;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	payload_addr = PAYLOAD_OFFSET;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	for (i = 0, curr = 0; i < ARRAY_SIZE(mem->blocks); i++, curr += j) {
59162306a36Sopenharmony_ci		for (j = 0; j < mem->blocks[i]; j++) {
59262306a36Sopenharmony_ci			priv->memory_pool[curr + j].start = payload_addr;
59362306a36Sopenharmony_ci			priv->memory_pool[curr + j].size = mem->blocks_size[i];
59462306a36Sopenharmony_ci			priv->memory_pool[curr + j].free = 1;
59562306a36Sopenharmony_ci			payload_addr += priv->memory_pool[curr + j].size;
59662306a36Sopenharmony_ci		}
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	WARN_ON(payload_addr - priv->memory_pool[0].start >
60062306a36Sopenharmony_ci		mem->payload_area_size);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
60662306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem = priv->memory_layout;
60762306a36Sopenharmony_ci	int i;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	WARN_ON(qtd->payload_addr);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (!qtd->length)
61262306a36Sopenharmony_ci		return;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	for (i = 0; i < mem->payload_blocks; i++) {
61562306a36Sopenharmony_ci		if (priv->memory_pool[i].size >= qtd->length &&
61662306a36Sopenharmony_ci				priv->memory_pool[i].free) {
61762306a36Sopenharmony_ci			priv->memory_pool[i].free = 0;
61862306a36Sopenharmony_ci			qtd->payload_addr = priv->memory_pool[i].start;
61962306a36Sopenharmony_ci			return;
62062306a36Sopenharmony_ci		}
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
62762306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem = priv->memory_layout;
62862306a36Sopenharmony_ci	int i;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!qtd->payload_addr)
63162306a36Sopenharmony_ci		return;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	for (i = 0; i < mem->payload_blocks; i++) {
63462306a36Sopenharmony_ci		if (priv->memory_pool[i].start == qtd->payload_addr) {
63562306a36Sopenharmony_ci			WARN_ON(priv->memory_pool[i].free);
63662306a36Sopenharmony_ci			priv->memory_pool[i].free = 1;
63762306a36Sopenharmony_ci			qtd->payload_addr = 0;
63862306a36Sopenharmony_ci			return;
63962306a36Sopenharmony_ci		}
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n",
64362306a36Sopenharmony_ci						__func__, qtd->payload_addr);
64462306a36Sopenharmony_ci	WARN_ON(1);
64562306a36Sopenharmony_ci	qtd->payload_addr = 0;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci/* reset a non-running (STS_HALT == 1) controller */
64962306a36Sopenharmony_cistatic int ehci_reset(struct usb_hcd *hcd)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	hcd->state = HC_STATE_HALT;
65462306a36Sopenharmony_ci	priv->next_statechange = jiffies;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return isp1760_hcd_set_and_wait_swap(hcd, CMD_RESET, 250 * 1000);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic struct isp1760_qh *qh_alloc(gfp_t flags)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	struct isp1760_qh *qh;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	qh = kmem_cache_zalloc(qh_cachep, flags);
66462306a36Sopenharmony_ci	if (!qh)
66562306a36Sopenharmony_ci		return NULL;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	INIT_LIST_HEAD(&qh->qh_list);
66862306a36Sopenharmony_ci	INIT_LIST_HEAD(&qh->qtd_list);
66962306a36Sopenharmony_ci	qh->slot = -1;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return qh;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic void qh_free(struct isp1760_qh *qh)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	WARN_ON(!list_empty(&qh->qtd_list));
67762306a36Sopenharmony_ci	WARN_ON(qh->slot > -1);
67862306a36Sopenharmony_ci	kmem_cache_free(qh_cachep, qh);
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci/* one-time init, only for memory state */
68262306a36Sopenharmony_cistatic int priv_init(struct usb_hcd *hcd)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
68562306a36Sopenharmony_ci	u32 isoc_cache;
68662306a36Sopenharmony_ci	u32 isoc_thres;
68762306a36Sopenharmony_ci	int i;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	spin_lock_init(&priv->lock);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	for (i = 0; i < QH_END; i++)
69262306a36Sopenharmony_ci		INIT_LIST_HEAD(&priv->qh_list[i]);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	/*
69562306a36Sopenharmony_ci	 * hw default: 1K periodic list heads, one per frame.
69662306a36Sopenharmony_ci	 * periodic_size can shrink by USBCMD update if hcc_params allows.
69762306a36Sopenharmony_ci	 */
69862306a36Sopenharmony_ci	priv->periodic_size = DEFAULT_I_TDPS;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (priv->is_isp1763) {
70162306a36Sopenharmony_ci		priv->i_thresh = 2;
70262306a36Sopenharmony_ci		return 0;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* controllers may cache some of the periodic schedule ... */
70662306a36Sopenharmony_ci	isoc_cache = isp1760_hcd_read(hcd, HCC_ISOC_CACHE);
70762306a36Sopenharmony_ci	isoc_thres = isp1760_hcd_read(hcd, HCC_ISOC_THRES);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* full frame cache */
71062306a36Sopenharmony_ci	if (isoc_cache)
71162306a36Sopenharmony_ci		priv->i_thresh = 8;
71262306a36Sopenharmony_ci	else /* N microframes cached */
71362306a36Sopenharmony_ci		priv->i_thresh = 2 + isoc_thres;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return 0;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic int isp1760_hc_setup(struct usb_hcd *hcd)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
72162306a36Sopenharmony_ci	u32 atx_reset;
72262306a36Sopenharmony_ci	int result;
72362306a36Sopenharmony_ci	u32 scratch;
72462306a36Sopenharmony_ci	u32 pattern;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (priv->is_isp1763)
72762306a36Sopenharmony_ci		pattern = 0xcafe;
72862306a36Sopenharmony_ci	else
72962306a36Sopenharmony_ci		pattern = 0xdeadcafe;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	isp1760_hcd_write(hcd, HC_SCRATCH, pattern);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	/*
73462306a36Sopenharmony_ci	 * we do not care about the read value here we just want to
73562306a36Sopenharmony_ci	 * change bus pattern.
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci	isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
73862306a36Sopenharmony_ci	scratch = isp1760_hcd_read(hcd, HC_SCRATCH);
73962306a36Sopenharmony_ci	if (scratch != pattern) {
74062306a36Sopenharmony_ci		dev_err(hcd->self.controller, "Scratch test failed. 0x%08x\n",
74162306a36Sopenharmony_ci			scratch);
74262306a36Sopenharmony_ci		return -ENODEV;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/*
74662306a36Sopenharmony_ci	 * The RESET_HC bit in the SW_RESET register is supposed to reset the
74762306a36Sopenharmony_ci	 * host controller without touching the CPU interface registers, but at
74862306a36Sopenharmony_ci	 * least on the ISP1761 it seems to behave as the RESET_ALL bit and
74962306a36Sopenharmony_ci	 * reset the whole device. We thus can't use it here, so let's reset
75062306a36Sopenharmony_ci	 * the host controller through the EHCI USB Command register. The device
75162306a36Sopenharmony_ci	 * has been reset in core code anyway, so this shouldn't matter.
75262306a36Sopenharmony_ci	 */
75362306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, ISO_BUF_FILL);
75462306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, INT_BUF_FILL);
75562306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, ATL_BUF_FILL);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
75862306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
75962306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	result = ehci_reset(hcd);
76262306a36Sopenharmony_ci	if (result)
76362306a36Sopenharmony_ci		return result;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/* Step 11 passed */
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	/* ATL reset */
76862306a36Sopenharmony_ci	if (priv->is_isp1763)
76962306a36Sopenharmony_ci		atx_reset = SW_RESET_RESET_ATX;
77062306a36Sopenharmony_ci	else
77162306a36Sopenharmony_ci		atx_reset = ALL_ATX_RESET;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	isp1760_hcd_set(hcd, atx_reset);
77462306a36Sopenharmony_ci	mdelay(10);
77562306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, atx_reset);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if (priv->is_isp1763) {
77862306a36Sopenharmony_ci		isp1760_hcd_set(hcd, HW_OTG_DISABLE);
77962306a36Sopenharmony_ci		isp1760_hcd_set(hcd, HW_SW_SEL_HC_DC_CLEAR);
78062306a36Sopenharmony_ci		isp1760_hcd_set(hcd, HW_HC_2_DIS_CLEAR);
78162306a36Sopenharmony_ci		mdelay(10);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		isp1760_hcd_set(hcd, HW_INTF_LOCK);
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
78762306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	return priv_init(hcd);
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic u32 base_to_chip(u32 base)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	return ((base - 0x400) >> 3);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	struct urb *urb;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
80262306a36Sopenharmony_ci		return 1;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	urb = qtd->urb;
80562306a36Sopenharmony_ci	qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list);
80662306a36Sopenharmony_ci	return (qtd->urb != urb);
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci/* magic numbers that can affect system performance */
81062306a36Sopenharmony_ci#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
81162306a36Sopenharmony_ci#define	EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */
81262306a36Sopenharmony_ci#define	EHCI_TUNE_RL_TT		0
81362306a36Sopenharmony_ci#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
81462306a36Sopenharmony_ci#define	EHCI_TUNE_MULT_TT	1
81562306a36Sopenharmony_ci#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic void create_ptd_atl(struct isp1760_qh *qh,
81862306a36Sopenharmony_ci			struct isp1760_qtd *qtd, struct ptd *ptd)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	u32 maxpacket;
82162306a36Sopenharmony_ci	u32 multi;
82262306a36Sopenharmony_ci	u32 rl = RL_COUNTER;
82362306a36Sopenharmony_ci	u32 nak = NAK_COUNTER;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	memset(ptd, 0, sizeof(*ptd));
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* according to 3.6.2, max packet len can not be > 0x400 */
82862306a36Sopenharmony_ci	maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe);
82962306a36Sopenharmony_ci	multi =  1 + ((maxpacket >> 11) & 0x3);
83062306a36Sopenharmony_ci	maxpacket &= 0x7ff;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	/* DW0 */
83362306a36Sopenharmony_ci	ptd->dw0 = DW0_VALID_BIT;
83462306a36Sopenharmony_ci	ptd->dw0 |= TO_DW0_LENGTH(qtd->length);
83562306a36Sopenharmony_ci	ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket);
83662306a36Sopenharmony_ci	ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/* DW1 */
83962306a36Sopenharmony_ci	ptd->dw1 = TO_DW((usb_pipeendpoint(qtd->urb->pipe) >> 1));
84062306a36Sopenharmony_ci	ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
84162306a36Sopenharmony_ci	ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (usb_pipebulk(qtd->urb->pipe))
84462306a36Sopenharmony_ci		ptd->dw1 |= DW1_TRANS_BULK;
84562306a36Sopenharmony_ci	else if  (usb_pipeint(qtd->urb->pipe))
84662306a36Sopenharmony_ci		ptd->dw1 |= DW1_TRANS_INT;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (qtd->urb->dev->speed != USB_SPEED_HIGH) {
84962306a36Sopenharmony_ci		/* split transaction */
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		ptd->dw1 |= DW1_TRANS_SPLIT;
85262306a36Sopenharmony_ci		if (qtd->urb->dev->speed == USB_SPEED_LOW)
85362306a36Sopenharmony_ci			ptd->dw1 |= DW1_SE_USB_LOSPEED;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci		ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport);
85662306a36Sopenharmony_ci		ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci		/* SE bit for Split INT transfers */
85962306a36Sopenharmony_ci		if (usb_pipeint(qtd->urb->pipe) &&
86062306a36Sopenharmony_ci				(qtd->urb->dev->speed == USB_SPEED_LOW))
86162306a36Sopenharmony_ci			ptd->dw1 |= DW1_SE_USB_LOSPEED;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		rl = 0;
86462306a36Sopenharmony_ci		nak = 0;
86562306a36Sopenharmony_ci	} else {
86662306a36Sopenharmony_ci		ptd->dw0 |= TO_DW0_MULTI(multi);
86762306a36Sopenharmony_ci		if (usb_pipecontrol(qtd->urb->pipe) ||
86862306a36Sopenharmony_ci						usb_pipebulk(qtd->urb->pipe))
86962306a36Sopenharmony_ci			ptd->dw3 |= TO_DW3_PING(qh->ping);
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci	/* DW2 */
87262306a36Sopenharmony_ci	ptd->dw2 = 0;
87362306a36Sopenharmony_ci	ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr));
87462306a36Sopenharmony_ci	ptd->dw2 |= TO_DW2_RL(rl);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* DW3 */
87762306a36Sopenharmony_ci	ptd->dw3 |= TO_DW3_NAKCOUNT(nak);
87862306a36Sopenharmony_ci	ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle);
87962306a36Sopenharmony_ci	if (usb_pipecontrol(qtd->urb->pipe)) {
88062306a36Sopenharmony_ci		if (qtd->data_buffer == qtd->urb->setup_packet)
88162306a36Sopenharmony_ci			ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1);
88262306a36Sopenharmony_ci		else if (last_qtd_of_urb(qtd, qh))
88362306a36Sopenharmony_ci			ptd->dw3 |= TO_DW3_DATA_TOGGLE(1);
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	ptd->dw3 |= DW3_ACTIVE_BIT;
88762306a36Sopenharmony_ci	/* Cerr */
88862306a36Sopenharmony_ci	ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER);
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic void transform_add_int(struct isp1760_qh *qh,
89262306a36Sopenharmony_ci			struct isp1760_qtd *qtd, struct ptd *ptd)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	u32 usof;
89562306a36Sopenharmony_ci	u32 period;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/*
89862306a36Sopenharmony_ci	 * Most of this is guessing. ISP1761 datasheet is quite unclear, and
89962306a36Sopenharmony_ci	 * the algorithm from the original Philips driver code, which was
90062306a36Sopenharmony_ci	 * pretty much used in this driver before as well, is quite horrendous
90162306a36Sopenharmony_ci	 * and, i believe, incorrect. The code below follows the datasheet and
90262306a36Sopenharmony_ci	 * USB2.0 spec as far as I can tell, and plug/unplug seems to be much
90362306a36Sopenharmony_ci	 * more reliable this way (fingers crossed...).
90462306a36Sopenharmony_ci	 */
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	if (qtd->urb->dev->speed == USB_SPEED_HIGH) {
90762306a36Sopenharmony_ci		/* urb->interval is in units of microframes (1/8 ms) */
90862306a36Sopenharmony_ci		period = qtd->urb->interval >> 3;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		if (qtd->urb->interval > 4)
91162306a36Sopenharmony_ci			usof = 0x01; /* One bit set =>
91262306a36Sopenharmony_ci						interval 1 ms * uFrame-match */
91362306a36Sopenharmony_ci		else if (qtd->urb->interval > 2)
91462306a36Sopenharmony_ci			usof = 0x22; /* Two bits set => interval 1/2 ms */
91562306a36Sopenharmony_ci		else if (qtd->urb->interval > 1)
91662306a36Sopenharmony_ci			usof = 0x55; /* Four bits set => interval 1/4 ms */
91762306a36Sopenharmony_ci		else
91862306a36Sopenharmony_ci			usof = 0xff; /* All bits set => interval 1/8 ms */
91962306a36Sopenharmony_ci	} else {
92062306a36Sopenharmony_ci		/* urb->interval is in units of frames (1 ms) */
92162306a36Sopenharmony_ci		period = qtd->urb->interval;
92262306a36Sopenharmony_ci		usof = 0x0f;		/* Execute Start Split on any of the
92362306a36Sopenharmony_ci					   four first uFrames */
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		/*
92662306a36Sopenharmony_ci		 * First 8 bits in dw5 is uSCS and "specifies which uSOF the
92762306a36Sopenharmony_ci		 * complete split needs to be sent. Valid only for IN." Also,
92862306a36Sopenharmony_ci		 * "All bits can be set to one for every transfer." (p 82,
92962306a36Sopenharmony_ci		 * ISP1761 data sheet.) 0x1c is from Philips driver. Where did
93062306a36Sopenharmony_ci		 * that number come from? 0xff seems to work fine...
93162306a36Sopenharmony_ci		 */
93262306a36Sopenharmony_ci		/* ptd->dw5 = 0x1c; */
93362306a36Sopenharmony_ci		ptd->dw5 = TO_DW(0xff); /* Execute Complete Split on any uFrame */
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	period = period >> 1;/* Ensure equal or shorter period than requested */
93762306a36Sopenharmony_ci	period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	ptd->dw2 |= TO_DW(period);
94062306a36Sopenharmony_ci	ptd->dw4 = TO_DW(usof);
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic void create_ptd_int(struct isp1760_qh *qh,
94462306a36Sopenharmony_ci			struct isp1760_qtd *qtd, struct ptd *ptd)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	create_ptd_atl(qh, qtd, ptd);
94762306a36Sopenharmony_ci	transform_add_int(qh, qtd, ptd);
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)
95162306a36Sopenharmony_ci__releases(priv->lock)
95262306a36Sopenharmony_ci__acquires(priv->lock)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (!urb->unlinked) {
95762306a36Sopenharmony_ci		if (urb->status == -EINPROGRESS)
95862306a36Sopenharmony_ci			urb->status = 0;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
96262306a36Sopenharmony_ci		void *ptr;
96362306a36Sopenharmony_ci		for (ptr = urb->transfer_buffer;
96462306a36Sopenharmony_ci		     ptr < urb->transfer_buffer + urb->transfer_buffer_length;
96562306a36Sopenharmony_ci		     ptr += PAGE_SIZE)
96662306a36Sopenharmony_ci			flush_dcache_page(virt_to_page(ptr));
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	/* complete() can reenter this HCD */
97062306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(hcd, urb);
97162306a36Sopenharmony_ci	spin_unlock(&priv->lock);
97262306a36Sopenharmony_ci	usb_hcd_giveback_urb(hcd, urb, urb->status);
97362306a36Sopenharmony_ci	spin_lock(&priv->lock);
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_cistatic struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
97762306a36Sopenharmony_ci								u8 packet_type)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	struct isp1760_qtd *qtd;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	qtd = kmem_cache_zalloc(qtd_cachep, flags);
98262306a36Sopenharmony_ci	if (!qtd)
98362306a36Sopenharmony_ci		return NULL;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	INIT_LIST_HEAD(&qtd->qtd_list);
98662306a36Sopenharmony_ci	qtd->urb = urb;
98762306a36Sopenharmony_ci	qtd->packet_type = packet_type;
98862306a36Sopenharmony_ci	qtd->status = QTD_ENQUEUED;
98962306a36Sopenharmony_ci	qtd->actual_length = 0;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	return qtd;
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_cistatic void qtd_free(struct isp1760_qtd *qtd)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	WARN_ON(qtd->payload_addr);
99762306a36Sopenharmony_ci	kmem_cache_free(qtd_cachep, qtd);
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
100162306a36Sopenharmony_ci				struct isp1760_slotinfo *slots,
100262306a36Sopenharmony_ci				struct isp1760_qtd *qtd, struct isp1760_qh *qh,
100362306a36Sopenharmony_ci				struct ptd *ptd)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
100662306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem = priv->memory_layout;
100762306a36Sopenharmony_ci	int skip_map;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	WARN_ON((slot < 0) || (slot > mem->slot_num - 1));
101062306a36Sopenharmony_ci	WARN_ON(qtd->length && !qtd->payload_addr);
101162306a36Sopenharmony_ci	WARN_ON(slots[slot].qtd);
101262306a36Sopenharmony_ci	WARN_ON(slots[slot].qh);
101362306a36Sopenharmony_ci	WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (priv->is_isp1763)
101662306a36Sopenharmony_ci		ndelay(100);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* Make sure done map has not triggered from some unlinked transfer */
101962306a36Sopenharmony_ci	if (ptd_offset == ATL_PTD_OFFSET) {
102062306a36Sopenharmony_ci		skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
102162306a36Sopenharmony_ci		isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP,
102262306a36Sopenharmony_ci				  skip_map | (1 << slot));
102362306a36Sopenharmony_ci		priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
102462306a36Sopenharmony_ci		priv->atl_done_map &= ~(1 << slot);
102562306a36Sopenharmony_ci	} else {
102662306a36Sopenharmony_ci		skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
102762306a36Sopenharmony_ci		isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP,
102862306a36Sopenharmony_ci				  skip_map | (1 << slot));
102962306a36Sopenharmony_ci		priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
103062306a36Sopenharmony_ci		priv->int_done_map &= ~(1 << slot);
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	skip_map &= ~(1 << slot);
103462306a36Sopenharmony_ci	qh->slot = slot;
103562306a36Sopenharmony_ci	qtd->status = QTD_XFER_STARTED;
103662306a36Sopenharmony_ci	slots[slot].timestamp = jiffies;
103762306a36Sopenharmony_ci	slots[slot].qtd = qtd;
103862306a36Sopenharmony_ci	slots[slot].qh = qh;
103962306a36Sopenharmony_ci	ptd_write(hcd, ptd_offset, slot, ptd);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	if (ptd_offset == ATL_PTD_OFFSET)
104262306a36Sopenharmony_ci		isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
104362306a36Sopenharmony_ci	else
104462306a36Sopenharmony_ci		isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_cistatic int is_short_bulk(struct isp1760_qtd *qtd)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	return (usb_pipebulk(qtd->urb->pipe) &&
105062306a36Sopenharmony_ci					(qtd->actual_length < qtd->length));
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
105462306a36Sopenharmony_ci						struct list_head *urb_list)
105562306a36Sopenharmony_ci{
105662306a36Sopenharmony_ci	struct isp1760_qtd *qtd, *qtd_next;
105762306a36Sopenharmony_ci	struct urb_listitem *urb_listitem;
105862306a36Sopenharmony_ci	int last_qtd;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
106162306a36Sopenharmony_ci		if (qtd->status < QTD_XFER_COMPLETE)
106262306a36Sopenharmony_ci			break;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci		last_qtd = last_qtd_of_urb(qtd, qh);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci		if ((!last_qtd) && (qtd->status == QTD_RETIRE))
106762306a36Sopenharmony_ci			qtd_next->status = QTD_RETIRE;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		if (qtd->status == QTD_XFER_COMPLETE) {
107062306a36Sopenharmony_ci			if (qtd->actual_length) {
107162306a36Sopenharmony_ci				switch (qtd->packet_type) {
107262306a36Sopenharmony_ci				case IN_PID:
107362306a36Sopenharmony_ci					mem_read(hcd, qtd->payload_addr,
107462306a36Sopenharmony_ci						 qtd->data_buffer,
107562306a36Sopenharmony_ci						 qtd->actual_length);
107662306a36Sopenharmony_ci					fallthrough;
107762306a36Sopenharmony_ci				case OUT_PID:
107862306a36Sopenharmony_ci					qtd->urb->actual_length +=
107962306a36Sopenharmony_ci							qtd->actual_length;
108062306a36Sopenharmony_ci					fallthrough;
108162306a36Sopenharmony_ci				case SETUP_PID:
108262306a36Sopenharmony_ci					break;
108362306a36Sopenharmony_ci				}
108462306a36Sopenharmony_ci			}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci			if (is_short_bulk(qtd)) {
108762306a36Sopenharmony_ci				if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
108862306a36Sopenharmony_ci					qtd->urb->status = -EREMOTEIO;
108962306a36Sopenharmony_ci				if (!last_qtd)
109062306a36Sopenharmony_ci					qtd_next->status = QTD_RETIRE;
109162306a36Sopenharmony_ci			}
109262306a36Sopenharmony_ci		}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci		if (qtd->payload_addr)
109562306a36Sopenharmony_ci			free_mem(hcd, qtd);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci		if (last_qtd) {
109862306a36Sopenharmony_ci			if ((qtd->status == QTD_RETIRE) &&
109962306a36Sopenharmony_ci					(qtd->urb->status == -EINPROGRESS))
110062306a36Sopenharmony_ci				qtd->urb->status = -EPIPE;
110162306a36Sopenharmony_ci			/* Defer calling of urb_done() since it releases lock */
110262306a36Sopenharmony_ci			urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
110362306a36Sopenharmony_ci								GFP_ATOMIC);
110462306a36Sopenharmony_ci			if (unlikely(!urb_listitem))
110562306a36Sopenharmony_ci				break; /* Try again on next call */
110662306a36Sopenharmony_ci			urb_listitem->urb = qtd->urb;
110762306a36Sopenharmony_ci			list_add_tail(&urb_listitem->urb_list, urb_list);
110862306a36Sopenharmony_ci		}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		list_del(&qtd->qtd_list);
111162306a36Sopenharmony_ci		qtd_free(qtd);
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci#define ENQUEUE_DEPTH	2
111662306a36Sopenharmony_cistatic void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
111962306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem = priv->memory_layout;
112062306a36Sopenharmony_ci	int slot_num = mem->slot_num;
112162306a36Sopenharmony_ci	int ptd_offset;
112262306a36Sopenharmony_ci	struct isp1760_slotinfo *slots;
112362306a36Sopenharmony_ci	int curr_slot, free_slot;
112462306a36Sopenharmony_ci	int n;
112562306a36Sopenharmony_ci	struct ptd ptd;
112662306a36Sopenharmony_ci	struct isp1760_qtd *qtd;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (unlikely(list_empty(&qh->qtd_list))) {
112962306a36Sopenharmony_ci		WARN_ON(1);
113062306a36Sopenharmony_ci		return;
113162306a36Sopenharmony_ci	}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* Make sure this endpoint's TT buffer is clean before queueing ptds */
113462306a36Sopenharmony_ci	if (qh->tt_buffer_dirty)
113562306a36Sopenharmony_ci		return;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
113862306a36Sopenharmony_ci							qtd_list)->urb->pipe)) {
113962306a36Sopenharmony_ci		ptd_offset = INT_PTD_OFFSET;
114062306a36Sopenharmony_ci		slots = priv->int_slots;
114162306a36Sopenharmony_ci	} else {
114262306a36Sopenharmony_ci		ptd_offset = ATL_PTD_OFFSET;
114362306a36Sopenharmony_ci		slots = priv->atl_slots;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	free_slot = -1;
114762306a36Sopenharmony_ci	for (curr_slot = 0; curr_slot < slot_num; curr_slot++) {
114862306a36Sopenharmony_ci		if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
114962306a36Sopenharmony_ci			free_slot = curr_slot;
115062306a36Sopenharmony_ci		if (slots[curr_slot].qh == qh)
115162306a36Sopenharmony_ci			break;
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	n = 0;
115562306a36Sopenharmony_ci	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
115662306a36Sopenharmony_ci		if (qtd->status == QTD_ENQUEUED) {
115762306a36Sopenharmony_ci			WARN_ON(qtd->payload_addr);
115862306a36Sopenharmony_ci			alloc_mem(hcd, qtd);
115962306a36Sopenharmony_ci			if ((qtd->length) && (!qtd->payload_addr))
116062306a36Sopenharmony_ci				break;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci			if (qtd->length && (qtd->packet_type == SETUP_PID ||
116362306a36Sopenharmony_ci					    qtd->packet_type == OUT_PID)) {
116462306a36Sopenharmony_ci				mem_write(hcd, qtd->payload_addr,
116562306a36Sopenharmony_ci					  qtd->data_buffer, qtd->length);
116662306a36Sopenharmony_ci			}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci			qtd->status = QTD_PAYLOAD_ALLOC;
116962306a36Sopenharmony_ci		}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		if (qtd->status == QTD_PAYLOAD_ALLOC) {
117262306a36Sopenharmony_ci/*
117362306a36Sopenharmony_ci			if ((curr_slot > 31) && (free_slot == -1))
117462306a36Sopenharmony_ci				dev_dbg(hcd->self.controller, "%s: No slot "
117562306a36Sopenharmony_ci					"available for transfer\n", __func__);
117662306a36Sopenharmony_ci*/
117762306a36Sopenharmony_ci			/* Start xfer for this endpoint if not already done */
117862306a36Sopenharmony_ci			if ((curr_slot > slot_num - 1) && (free_slot > -1)) {
117962306a36Sopenharmony_ci				if (usb_pipeint(qtd->urb->pipe))
118062306a36Sopenharmony_ci					create_ptd_int(qh, qtd, &ptd);
118162306a36Sopenharmony_ci				else
118262306a36Sopenharmony_ci					create_ptd_atl(qh, qtd, &ptd);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci				start_bus_transfer(hcd, ptd_offset, free_slot,
118562306a36Sopenharmony_ci							slots, qtd, qh, &ptd);
118662306a36Sopenharmony_ci				curr_slot = free_slot;
118762306a36Sopenharmony_ci			}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci			n++;
119062306a36Sopenharmony_ci			if (n >= ENQUEUE_DEPTH)
119162306a36Sopenharmony_ci				break;
119262306a36Sopenharmony_ci		}
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_cistatic void schedule_ptds(struct usb_hcd *hcd)
119762306a36Sopenharmony_ci{
119862306a36Sopenharmony_ci	struct isp1760_hcd *priv;
119962306a36Sopenharmony_ci	struct isp1760_qh *qh, *qh_next;
120062306a36Sopenharmony_ci	struct list_head *ep_queue;
120162306a36Sopenharmony_ci	LIST_HEAD(urb_list);
120262306a36Sopenharmony_ci	struct urb_listitem *urb_listitem, *urb_listitem_next;
120362306a36Sopenharmony_ci	int i;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (!hcd) {
120662306a36Sopenharmony_ci		WARN_ON(1);
120762306a36Sopenharmony_ci		return;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	priv = hcd_to_priv(hcd);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/*
121362306a36Sopenharmony_ci	 * check finished/retired xfers, transfer payloads, call urb_done()
121462306a36Sopenharmony_ci	 */
121562306a36Sopenharmony_ci	for (i = 0; i < QH_END; i++) {
121662306a36Sopenharmony_ci		ep_queue = &priv->qh_list[i];
121762306a36Sopenharmony_ci		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
121862306a36Sopenharmony_ci			collect_qtds(hcd, qh, &urb_list);
121962306a36Sopenharmony_ci			if (list_empty(&qh->qtd_list))
122062306a36Sopenharmony_ci				list_del(&qh->qh_list);
122162306a36Sopenharmony_ci		}
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
122562306a36Sopenharmony_ci								urb_list) {
122662306a36Sopenharmony_ci		isp1760_urb_done(hcd, urb_listitem->urb);
122762306a36Sopenharmony_ci		kmem_cache_free(urb_listitem_cachep, urb_listitem);
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	/*
123162306a36Sopenharmony_ci	 * Schedule packets for transfer.
123262306a36Sopenharmony_ci	 *
123362306a36Sopenharmony_ci	 * According to USB2.0 specification:
123462306a36Sopenharmony_ci	 *
123562306a36Sopenharmony_ci	 * 1st prio: interrupt xfers, up to 80 % of bandwidth
123662306a36Sopenharmony_ci	 * 2nd prio: control xfers
123762306a36Sopenharmony_ci	 * 3rd prio: bulk xfers
123862306a36Sopenharmony_ci	 *
123962306a36Sopenharmony_ci	 * ... but let's use a simpler scheme here (mostly because ISP1761 doc
124062306a36Sopenharmony_ci	 * is very unclear on how to prioritize traffic):
124162306a36Sopenharmony_ci	 *
124262306a36Sopenharmony_ci	 * 1) Enqueue any queued control transfers, as long as payload chip mem
124362306a36Sopenharmony_ci	 *    and PTD ATL slots are available.
124462306a36Sopenharmony_ci	 * 2) Enqueue any queued INT transfers, as long as payload chip mem
124562306a36Sopenharmony_ci	 *    and PTD INT slots are available.
124662306a36Sopenharmony_ci	 * 3) Enqueue any queued bulk transfers, as long as payload chip mem
124762306a36Sopenharmony_ci	 *    and PTD ATL slots are available.
124862306a36Sopenharmony_ci	 *
124962306a36Sopenharmony_ci	 * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between
125062306a36Sopenharmony_ci	 * conservation of chip mem and performance.
125162306a36Sopenharmony_ci	 *
125262306a36Sopenharmony_ci	 * I'm sure this scheme could be improved upon!
125362306a36Sopenharmony_ci	 */
125462306a36Sopenharmony_ci	for (i = 0; i < QH_END; i++) {
125562306a36Sopenharmony_ci		ep_queue = &priv->qh_list[i];
125662306a36Sopenharmony_ci		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
125762306a36Sopenharmony_ci			enqueue_qtds(hcd, qh);
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci#define PTD_STATE_QTD_DONE	1
126262306a36Sopenharmony_ci#define PTD_STATE_QTD_RELOAD	2
126362306a36Sopenharmony_ci#define PTD_STATE_URB_RETIRE	3
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
126662306a36Sopenharmony_ci								struct urb *urb)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	u32 dw4;
126962306a36Sopenharmony_ci	int i;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	dw4 = TO_U32(ptd->dw4);
127262306a36Sopenharmony_ci	dw4 >>= 8;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	/* FIXME: ISP1761 datasheet does not say what to do with these. Do we
127562306a36Sopenharmony_ci	   need to handle these errors? Is it done in hardware? */
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	if (ptd->dw3 & DW3_HALT_BIT) {
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci		urb->status = -EPROTO; /* Default unknown error */
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
128262306a36Sopenharmony_ci			switch (dw4 & 0x7) {
128362306a36Sopenharmony_ci			case INT_UNDERRUN:
128462306a36Sopenharmony_ci				dev_dbg(hcd->self.controller, "%s: underrun "
128562306a36Sopenharmony_ci						"during uFrame %d\n",
128662306a36Sopenharmony_ci						__func__, i);
128762306a36Sopenharmony_ci				urb->status = -ECOMM; /* Could not write data */
128862306a36Sopenharmony_ci				break;
128962306a36Sopenharmony_ci			case INT_EXACT:
129062306a36Sopenharmony_ci				dev_dbg(hcd->self.controller, "%s: transaction "
129162306a36Sopenharmony_ci						"error during uFrame %d\n",
129262306a36Sopenharmony_ci						__func__, i);
129362306a36Sopenharmony_ci				urb->status = -EPROTO; /* timeout, bad CRC, PID
129462306a36Sopenharmony_ci							  error etc. */
129562306a36Sopenharmony_ci				break;
129662306a36Sopenharmony_ci			case INT_BABBLE:
129762306a36Sopenharmony_ci				dev_dbg(hcd->self.controller, "%s: babble "
129862306a36Sopenharmony_ci						"error during uFrame %d\n",
129962306a36Sopenharmony_ci						__func__, i);
130062306a36Sopenharmony_ci				urb->status = -EOVERFLOW;
130162306a36Sopenharmony_ci				break;
130262306a36Sopenharmony_ci			}
130362306a36Sopenharmony_ci			dw4 >>= 3;
130462306a36Sopenharmony_ci		}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci		return PTD_STATE_URB_RETIRE;
130762306a36Sopenharmony_ci	}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	return PTD_STATE_QTD_DONE;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
131362306a36Sopenharmony_ci								struct urb *urb)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	WARN_ON(!ptd);
131662306a36Sopenharmony_ci	if (ptd->dw3 & DW3_HALT_BIT) {
131762306a36Sopenharmony_ci		if (ptd->dw3 & DW3_BABBLE_BIT)
131862306a36Sopenharmony_ci			urb->status = -EOVERFLOW;
131962306a36Sopenharmony_ci		else if (FROM_DW3_CERR(ptd->dw3))
132062306a36Sopenharmony_ci			urb->status = -EPIPE;  /* Stall */
132162306a36Sopenharmony_ci		else
132262306a36Sopenharmony_ci			urb->status = -EPROTO; /* Unknown */
132362306a36Sopenharmony_ci/*
132462306a36Sopenharmony_ci		dev_dbg(hcd->self.controller, "%s: ptd error:\n"
132562306a36Sopenharmony_ci			"        dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n"
132662306a36Sopenharmony_ci			"        dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n",
132762306a36Sopenharmony_ci			__func__,
132862306a36Sopenharmony_ci			ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3,
132962306a36Sopenharmony_ci			ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7);
133062306a36Sopenharmony_ci*/
133162306a36Sopenharmony_ci		return PTD_STATE_URB_RETIRE;
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
133562306a36Sopenharmony_ci		/* Transfer Error, *but* active and no HALT -> reload */
133662306a36Sopenharmony_ci		dev_dbg(hcd->self.controller, "PID error; reloading ptd\n");
133762306a36Sopenharmony_ci		return PTD_STATE_QTD_RELOAD;
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
134162306a36Sopenharmony_ci		/*
134262306a36Sopenharmony_ci		 * NAKs are handled in HW by the chip. Usually if the
134362306a36Sopenharmony_ci		 * device is not able to send data fast enough.
134462306a36Sopenharmony_ci		 * This happens mostly on slower hardware.
134562306a36Sopenharmony_ci		 */
134662306a36Sopenharmony_ci		return PTD_STATE_QTD_RELOAD;
134762306a36Sopenharmony_ci	}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	return PTD_STATE_QTD_DONE;
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic void handle_done_ptds(struct usb_hcd *hcd)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
135562306a36Sopenharmony_ci	struct ptd ptd;
135662306a36Sopenharmony_ci	struct isp1760_qh *qh;
135762306a36Sopenharmony_ci	int slot;
135862306a36Sopenharmony_ci	int state;
135962306a36Sopenharmony_ci	struct isp1760_slotinfo *slots;
136062306a36Sopenharmony_ci	u32 ptd_offset;
136162306a36Sopenharmony_ci	struct isp1760_qtd *qtd;
136262306a36Sopenharmony_ci	int modified;
136362306a36Sopenharmony_ci	int skip_map;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
136662306a36Sopenharmony_ci	priv->int_done_map &= ~skip_map;
136762306a36Sopenharmony_ci	skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
136862306a36Sopenharmony_ci	priv->atl_done_map &= ~skip_map;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	modified = priv->int_done_map || priv->atl_done_map;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	while (priv->int_done_map || priv->atl_done_map) {
137362306a36Sopenharmony_ci		if (priv->int_done_map) {
137462306a36Sopenharmony_ci			/* INT ptd */
137562306a36Sopenharmony_ci			slot = __ffs(priv->int_done_map);
137662306a36Sopenharmony_ci			priv->int_done_map &= ~(1 << slot);
137762306a36Sopenharmony_ci			slots = priv->int_slots;
137862306a36Sopenharmony_ci			/* This should not trigger, and could be removed if
137962306a36Sopenharmony_ci			   noone have any problems with it triggering: */
138062306a36Sopenharmony_ci			if (!slots[slot].qh) {
138162306a36Sopenharmony_ci				WARN_ON(1);
138262306a36Sopenharmony_ci				continue;
138362306a36Sopenharmony_ci			}
138462306a36Sopenharmony_ci			ptd_offset = INT_PTD_OFFSET;
138562306a36Sopenharmony_ci			ptd_read(hcd, INT_PTD_OFFSET, slot, &ptd);
138662306a36Sopenharmony_ci			state = check_int_transfer(hcd, &ptd,
138762306a36Sopenharmony_ci							slots[slot].qtd->urb);
138862306a36Sopenharmony_ci		} else {
138962306a36Sopenharmony_ci			/* ATL ptd */
139062306a36Sopenharmony_ci			slot = __ffs(priv->atl_done_map);
139162306a36Sopenharmony_ci			priv->atl_done_map &= ~(1 << slot);
139262306a36Sopenharmony_ci			slots = priv->atl_slots;
139362306a36Sopenharmony_ci			/* This should not trigger, and could be removed if
139462306a36Sopenharmony_ci			   noone have any problems with it triggering: */
139562306a36Sopenharmony_ci			if (!slots[slot].qh) {
139662306a36Sopenharmony_ci				WARN_ON(1);
139762306a36Sopenharmony_ci				continue;
139862306a36Sopenharmony_ci			}
139962306a36Sopenharmony_ci			ptd_offset = ATL_PTD_OFFSET;
140062306a36Sopenharmony_ci			ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
140162306a36Sopenharmony_ci			state = check_atl_transfer(hcd, &ptd,
140262306a36Sopenharmony_ci							slots[slot].qtd->urb);
140362306a36Sopenharmony_ci		}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		qtd = slots[slot].qtd;
140662306a36Sopenharmony_ci		slots[slot].qtd = NULL;
140762306a36Sopenharmony_ci		qh = slots[slot].qh;
140862306a36Sopenharmony_ci		slots[slot].qh = NULL;
140962306a36Sopenharmony_ci		qh->slot = -1;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci		WARN_ON(qtd->status != QTD_XFER_STARTED);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci		switch (state) {
141462306a36Sopenharmony_ci		case PTD_STATE_QTD_DONE:
141562306a36Sopenharmony_ci			if ((usb_pipeint(qtd->urb->pipe)) &&
141662306a36Sopenharmony_ci				       (qtd->urb->dev->speed != USB_SPEED_HIGH))
141762306a36Sopenharmony_ci				qtd->actual_length =
141862306a36Sopenharmony_ci				       FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3);
141962306a36Sopenharmony_ci			else
142062306a36Sopenharmony_ci				qtd->actual_length =
142162306a36Sopenharmony_ci					FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci			qtd->status = QTD_XFER_COMPLETE;
142462306a36Sopenharmony_ci			if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
142562306a36Sopenharmony_ci			    is_short_bulk(qtd))
142662306a36Sopenharmony_ci				qtd = NULL;
142762306a36Sopenharmony_ci			else
142862306a36Sopenharmony_ci				qtd = list_entry(qtd->qtd_list.next,
142962306a36Sopenharmony_ci							typeof(*qtd), qtd_list);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
143262306a36Sopenharmony_ci			qh->ping = FROM_DW3_PING(ptd.dw3);
143362306a36Sopenharmony_ci			break;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */
143662306a36Sopenharmony_ci			qtd->status = QTD_PAYLOAD_ALLOC;
143762306a36Sopenharmony_ci			ptd.dw0 |= DW0_VALID_BIT;
143862306a36Sopenharmony_ci			/* RL counter = ERR counter */
143962306a36Sopenharmony_ci			ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf);
144062306a36Sopenharmony_ci			ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2));
144162306a36Sopenharmony_ci			ptd.dw3 &= ~TO_DW3_CERR(3);
144262306a36Sopenharmony_ci			ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER);
144362306a36Sopenharmony_ci			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
144462306a36Sopenharmony_ci			qh->ping = FROM_DW3_PING(ptd.dw3);
144562306a36Sopenharmony_ci			break;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci		case PTD_STATE_URB_RETIRE:
144862306a36Sopenharmony_ci			qtd->status = QTD_RETIRE;
144962306a36Sopenharmony_ci			if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
145062306a36Sopenharmony_ci					(qtd->urb->status != -EPIPE) &&
145162306a36Sopenharmony_ci					(qtd->urb->status != -EREMOTEIO)) {
145262306a36Sopenharmony_ci				qh->tt_buffer_dirty = 1;
145362306a36Sopenharmony_ci				if (usb_hub_clear_tt_buffer(qtd->urb))
145462306a36Sopenharmony_ci					/* Clear failed; let's hope things work
145562306a36Sopenharmony_ci					   anyway */
145662306a36Sopenharmony_ci					qh->tt_buffer_dirty = 0;
145762306a36Sopenharmony_ci			}
145862306a36Sopenharmony_ci			qtd = NULL;
145962306a36Sopenharmony_ci			qh->toggle = 0;
146062306a36Sopenharmony_ci			qh->ping = 0;
146162306a36Sopenharmony_ci			break;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		default:
146462306a36Sopenharmony_ci			WARN_ON(1);
146562306a36Sopenharmony_ci			continue;
146662306a36Sopenharmony_ci		}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci		if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) {
146962306a36Sopenharmony_ci			if (slots == priv->int_slots) {
147062306a36Sopenharmony_ci				if (state == PTD_STATE_QTD_RELOAD)
147162306a36Sopenharmony_ci					dev_err(hcd->self.controller,
147262306a36Sopenharmony_ci						"%s: PTD_STATE_QTD_RELOAD on "
147362306a36Sopenharmony_ci						"interrupt packet\n", __func__);
147462306a36Sopenharmony_ci				if (state != PTD_STATE_QTD_RELOAD)
147562306a36Sopenharmony_ci					create_ptd_int(qh, qtd, &ptd);
147662306a36Sopenharmony_ci			} else {
147762306a36Sopenharmony_ci				if (state != PTD_STATE_QTD_RELOAD)
147862306a36Sopenharmony_ci					create_ptd_atl(qh, qtd, &ptd);
147962306a36Sopenharmony_ci			}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci			start_bus_transfer(hcd, ptd_offset, slot, slots, qtd,
148262306a36Sopenharmony_ci				qh, &ptd);
148362306a36Sopenharmony_ci		}
148462306a36Sopenharmony_ci	}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (modified)
148762306a36Sopenharmony_ci		schedule_ptds(hcd);
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic irqreturn_t isp1760_irq(struct usb_hcd *hcd)
149162306a36Sopenharmony_ci{
149262306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
149362306a36Sopenharmony_ci	irqreturn_t irqret = IRQ_NONE;
149462306a36Sopenharmony_ci	u32 int_reg;
149562306a36Sopenharmony_ci	u32 imask;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	spin_lock(&priv->lock);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	if (!(hcd->state & HC_STATE_RUNNING))
150062306a36Sopenharmony_ci		goto leave;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	imask = isp1760_hcd_read(hcd, HC_INTERRUPT);
150362306a36Sopenharmony_ci	if (unlikely(!imask))
150462306a36Sopenharmony_ci		goto leave;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	int_reg = priv->is_isp1763 ? ISP1763_HC_INTERRUPT :
150762306a36Sopenharmony_ci		ISP176x_HC_INTERRUPT;
150862306a36Sopenharmony_ci	isp1760_reg_write(priv->regs, int_reg, imask);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
151162306a36Sopenharmony_ci	priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	handle_done_ptds(hcd);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	irqret = IRQ_HANDLED;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_cileave:
151862306a36Sopenharmony_ci	spin_unlock(&priv->lock);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	return irqret;
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci/*
152462306a36Sopenharmony_ci * Workaround for problem described in chip errata 2:
152562306a36Sopenharmony_ci *
152662306a36Sopenharmony_ci * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
152762306a36Sopenharmony_ci * One solution suggested in the errata is to use SOF interrupts _instead_of_
152862306a36Sopenharmony_ci * ATL done interrupts (the "instead of" might be important since it seems
152962306a36Sopenharmony_ci * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
153062306a36Sopenharmony_ci * to set the PTD's done bit in addition to not generating an interrupt!).
153162306a36Sopenharmony_ci *
153262306a36Sopenharmony_ci * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
153362306a36Sopenharmony_ci * done bit is not being set. This is bad - it blocks the endpoint until reboot.
153462306a36Sopenharmony_ci *
153562306a36Sopenharmony_ci * If we use SOF interrupts only, we get latency between ptd completion and the
153662306a36Sopenharmony_ci * actual handling. This is very noticeable in testusb runs which takes several
153762306a36Sopenharmony_ci * minutes longer without ATL interrupts.
153862306a36Sopenharmony_ci *
153962306a36Sopenharmony_ci * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
154062306a36Sopenharmony_ci * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
154162306a36Sopenharmony_ci * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
154262306a36Sopenharmony_ci * completed and its done map bit is set.
154362306a36Sopenharmony_ci *
154462306a36Sopenharmony_ci * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
154562306a36Sopenharmony_ci * not to cause too much lag when this HW bug occurs, while still hopefully
154662306a36Sopenharmony_ci * ensuring that the check does not falsely trigger.
154762306a36Sopenharmony_ci */
154862306a36Sopenharmony_ci#define SLOT_TIMEOUT 300
154962306a36Sopenharmony_ci#define SLOT_CHECK_PERIOD 200
155062306a36Sopenharmony_cistatic struct timer_list errata2_timer;
155162306a36Sopenharmony_cistatic struct usb_hcd *errata2_timer_hcd;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_cistatic void errata2_function(struct timer_list *unused)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci	struct usb_hcd *hcd = errata2_timer_hcd;
155662306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
155762306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem = priv->memory_layout;
155862306a36Sopenharmony_ci	int slot;
155962306a36Sopenharmony_ci	struct ptd ptd;
156062306a36Sopenharmony_ci	unsigned long spinflags;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, spinflags);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	for (slot = 0; slot < mem->slot_num; slot++)
156562306a36Sopenharmony_ci		if (priv->atl_slots[slot].qh && time_after(jiffies,
156662306a36Sopenharmony_ci					priv->atl_slots[slot].timestamp +
156762306a36Sopenharmony_ci					msecs_to_jiffies(SLOT_TIMEOUT))) {
156862306a36Sopenharmony_ci			ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
156962306a36Sopenharmony_ci			if (!FROM_DW0_VALID(ptd.dw0) &&
157062306a36Sopenharmony_ci					!FROM_DW3_ACTIVE(ptd.dw3))
157162306a36Sopenharmony_ci				priv->atl_done_map |= 1 << slot;
157262306a36Sopenharmony_ci		}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	if (priv->atl_done_map)
157562306a36Sopenharmony_ci		handle_done_ptds(hcd);
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, spinflags);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
158062306a36Sopenharmony_ci	add_timer(&errata2_timer);
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_cistatic int isp1763_run(struct usb_hcd *hcd)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
158662306a36Sopenharmony_ci	int retval;
158762306a36Sopenharmony_ci	u32 chipid_h;
158862306a36Sopenharmony_ci	u32 chipid_l;
158962306a36Sopenharmony_ci	u32 chip_rev;
159062306a36Sopenharmony_ci	u32 ptd_atl_int;
159162306a36Sopenharmony_ci	u32 ptd_iso;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	hcd->uses_new_polling = 1;
159462306a36Sopenharmony_ci	hcd->state = HC_STATE_RUNNING;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
159762306a36Sopenharmony_ci	chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
159862306a36Sopenharmony_ci	chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
159962306a36Sopenharmony_ci	dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
160062306a36Sopenharmony_ci		 chipid_h, chipid_l, chip_rev);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, ISO_BUF_FILL);
160362306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, INT_BUF_FILL);
160462306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, ATL_BUF_FILL);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
160762306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
160862306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
160962306a36Sopenharmony_ci	ndelay(100);
161062306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_ATL_PTD_DONEMAP);
161162306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_INT_PTD_DONEMAP);
161262306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_ISO_PTD_DONEMAP);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HW_OTG_DISABLE);
161562306a36Sopenharmony_ci	isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(7));
161662306a36Sopenharmony_ci	isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(15));
161762306a36Sopenharmony_ci	mdelay(10);
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
162062306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
162562306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
162662306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
162962306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
163062306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	ptd_atl_int = 0x8000;
163362306a36Sopenharmony_ci	ptd_iso = 0x0001;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
163662306a36Sopenharmony_ci	isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
163762306a36Sopenharmony_ci	isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	isp1760_hcd_set(hcd, ATL_BUF_FILL);
164062306a36Sopenharmony_ci	isp1760_hcd_set(hcd, INT_BUF_FILL);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, CMD_LRESET);
164362306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, CMD_RESET);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
164662306a36Sopenharmony_ci	if (retval)
164762306a36Sopenharmony_ci		return retval;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	down_write(&ehci_cf_port_reset_rwsem);
165062306a36Sopenharmony_ci	retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
165162306a36Sopenharmony_ci	up_write(&ehci_cf_port_reset_rwsem);
165262306a36Sopenharmony_ci	if (retval)
165362306a36Sopenharmony_ci		return retval;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	return 0;
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_cistatic int isp1760_run(struct usb_hcd *hcd)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
166162306a36Sopenharmony_ci	int retval;
166262306a36Sopenharmony_ci	u32 chipid_h;
166362306a36Sopenharmony_ci	u32 chipid_l;
166462306a36Sopenharmony_ci	u32 chip_rev;
166562306a36Sopenharmony_ci	u32 ptd_atl_int;
166662306a36Sopenharmony_ci	u32 ptd_iso;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	/*
166962306a36Sopenharmony_ci	 * ISP1763 have some differences in the setup and order to enable
167062306a36Sopenharmony_ci	 * the ports, disable otg, setup buffers, and ATL, INT, ISO status.
167162306a36Sopenharmony_ci	 * So, just handle it a separate sequence.
167262306a36Sopenharmony_ci	 */
167362306a36Sopenharmony_ci	if (priv->is_isp1763)
167462306a36Sopenharmony_ci		return isp1763_run(hcd);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	hcd->uses_new_polling = 1;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	hcd->state = HC_STATE_RUNNING;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	/* Set PTD interrupt AND & OR maps */
168162306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
168262306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
168362306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
168662306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
168762306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	/* step 23 passed */
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, CMD_LRESET);
169462306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, CMD_RESET);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
169762306a36Sopenharmony_ci	if (retval)
169862306a36Sopenharmony_ci		return retval;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	/*
170162306a36Sopenharmony_ci	 * XXX
170262306a36Sopenharmony_ci	 * Spec says to write FLAG_CF as last config action, priv code grabs
170362306a36Sopenharmony_ci	 * the semaphore while doing so.
170462306a36Sopenharmony_ci	 */
170562306a36Sopenharmony_ci	down_write(&ehci_cf_port_reset_rwsem);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
170862306a36Sopenharmony_ci	up_write(&ehci_cf_port_reset_rwsem);
170962306a36Sopenharmony_ci	if (retval)
171062306a36Sopenharmony_ci		return retval;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	errata2_timer_hcd = hcd;
171362306a36Sopenharmony_ci	timer_setup(&errata2_timer, errata2_function, 0);
171462306a36Sopenharmony_ci	errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
171562306a36Sopenharmony_ci	add_timer(&errata2_timer);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
171862306a36Sopenharmony_ci	chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
171962306a36Sopenharmony_ci	chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
172062306a36Sopenharmony_ci	dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
172162306a36Sopenharmony_ci		 chipid_h, chipid_l, chip_rev);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	/* PTD Register Init Part 2, Step 28 */
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	/* Setup registers controlling PTD checking */
172662306a36Sopenharmony_ci	ptd_atl_int = 0x80000000;
172762306a36Sopenharmony_ci	ptd_iso = 0x00000001;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
173062306a36Sopenharmony_ci	isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
173162306a36Sopenharmony_ci	isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
173462306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
173562306a36Sopenharmony_ci	isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	isp1760_hcd_set(hcd, ATL_BUF_FILL);
173862306a36Sopenharmony_ci	isp1760_hcd_set(hcd, INT_BUF_FILL);
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	/* GRR this is run-once init(), being done every time the HC starts.
174162306a36Sopenharmony_ci	 * So long as they're part of class devices, we can't do it init()
174262306a36Sopenharmony_ci	 * since the class device isn't created that early.
174362306a36Sopenharmony_ci	 */
174462306a36Sopenharmony_ci	return 0;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cistatic int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	qtd->data_buffer = databuffer;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	qtd->length = len;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	return qtd->length;
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_cistatic void qtd_list_free(struct list_head *qtd_list)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	struct isp1760_qtd *qtd, *qtd_next;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) {
176162306a36Sopenharmony_ci		list_del(&qtd->qtd_list);
176262306a36Sopenharmony_ci		qtd_free(qtd);
176362306a36Sopenharmony_ci	}
176462306a36Sopenharmony_ci}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci/*
176762306a36Sopenharmony_ci * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
176862306a36Sopenharmony_ci * Also calculate the PID type (SETUP/IN/OUT) for each packet.
176962306a36Sopenharmony_ci */
177062306a36Sopenharmony_cistatic void packetize_urb(struct usb_hcd *hcd,
177162306a36Sopenharmony_ci		struct urb *urb, struct list_head *head, gfp_t flags)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
177462306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem = priv->memory_layout;
177562306a36Sopenharmony_ci	struct isp1760_qtd *qtd;
177662306a36Sopenharmony_ci	void *buf;
177762306a36Sopenharmony_ci	int len, maxpacketsize;
177862306a36Sopenharmony_ci	u8 packet_type;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	/*
178162306a36Sopenharmony_ci	 * URBs map to sequences of QTDs:  one logical transaction
178262306a36Sopenharmony_ci	 */
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	if (!urb->transfer_buffer && urb->transfer_buffer_length) {
178562306a36Sopenharmony_ci		/* XXX This looks like usb storage / SCSI bug */
178662306a36Sopenharmony_ci		dev_err(hcd->self.controller,
178762306a36Sopenharmony_ci				"buf is null, dma is %08lx len is %d\n",
178862306a36Sopenharmony_ci				(long unsigned)urb->transfer_dma,
178962306a36Sopenharmony_ci				urb->transfer_buffer_length);
179062306a36Sopenharmony_ci		WARN_ON(1);
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (usb_pipein(urb->pipe))
179462306a36Sopenharmony_ci		packet_type = IN_PID;
179562306a36Sopenharmony_ci	else
179662306a36Sopenharmony_ci		packet_type = OUT_PID;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	if (usb_pipecontrol(urb->pipe)) {
179962306a36Sopenharmony_ci		qtd = qtd_alloc(flags, urb, SETUP_PID);
180062306a36Sopenharmony_ci		if (!qtd)
180162306a36Sopenharmony_ci			goto cleanup;
180262306a36Sopenharmony_ci		qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));
180362306a36Sopenharmony_ci		list_add_tail(&qtd->qtd_list, head);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci		/* for zero length DATA stages, STATUS is always IN */
180662306a36Sopenharmony_ci		if (urb->transfer_buffer_length == 0)
180762306a36Sopenharmony_ci			packet_type = IN_PID;
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	maxpacketsize = usb_maxpacket(urb->dev, urb->pipe);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	/*
181362306a36Sopenharmony_ci	 * buffer gets wrapped in one or more qtds;
181462306a36Sopenharmony_ci	 * last one may be "short" (including zero len)
181562306a36Sopenharmony_ci	 * and may serve as a control status ack
181662306a36Sopenharmony_ci	 */
181762306a36Sopenharmony_ci	buf = urb->transfer_buffer;
181862306a36Sopenharmony_ci	len = urb->transfer_buffer_length;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	for (;;) {
182162306a36Sopenharmony_ci		int this_qtd_len;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		qtd = qtd_alloc(flags, urb, packet_type);
182462306a36Sopenharmony_ci		if (!qtd)
182562306a36Sopenharmony_ci			goto cleanup;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci		if (len > mem->blocks_size[ISP176x_BLOCK_NUM - 1])
182862306a36Sopenharmony_ci			this_qtd_len = mem->blocks_size[ISP176x_BLOCK_NUM - 1];
182962306a36Sopenharmony_ci		else
183062306a36Sopenharmony_ci			this_qtd_len = len;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci		this_qtd_len = qtd_fill(qtd, buf, this_qtd_len);
183362306a36Sopenharmony_ci		list_add_tail(&qtd->qtd_list, head);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci		len -= this_qtd_len;
183662306a36Sopenharmony_ci		buf += this_qtd_len;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci		if (len <= 0)
183962306a36Sopenharmony_ci			break;
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	/*
184362306a36Sopenharmony_ci	 * control requests may need a terminating data "status" ack;
184462306a36Sopenharmony_ci	 * bulk ones may need a terminating short packet (zero length).
184562306a36Sopenharmony_ci	 */
184662306a36Sopenharmony_ci	if (urb->transfer_buffer_length != 0) {
184762306a36Sopenharmony_ci		int one_more = 0;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci		if (usb_pipecontrol(urb->pipe)) {
185062306a36Sopenharmony_ci			one_more = 1;
185162306a36Sopenharmony_ci			if (packet_type == IN_PID)
185262306a36Sopenharmony_ci				packet_type = OUT_PID;
185362306a36Sopenharmony_ci			else
185462306a36Sopenharmony_ci				packet_type = IN_PID;
185562306a36Sopenharmony_ci		} else if (usb_pipebulk(urb->pipe) && maxpacketsize
185662306a36Sopenharmony_ci				&& (urb->transfer_flags & URB_ZERO_PACKET)
185762306a36Sopenharmony_ci				&& !(urb->transfer_buffer_length %
185862306a36Sopenharmony_ci							maxpacketsize)) {
185962306a36Sopenharmony_ci			one_more = 1;
186062306a36Sopenharmony_ci		}
186162306a36Sopenharmony_ci		if (one_more) {
186262306a36Sopenharmony_ci			qtd = qtd_alloc(flags, urb, packet_type);
186362306a36Sopenharmony_ci			if (!qtd)
186462306a36Sopenharmony_ci				goto cleanup;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci			/* never any data in such packets */
186762306a36Sopenharmony_ci			qtd_fill(qtd, NULL, 0);
186862306a36Sopenharmony_ci			list_add_tail(&qtd->qtd_list, head);
186962306a36Sopenharmony_ci		}
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	return;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cicleanup:
187562306a36Sopenharmony_ci	qtd_list_free(head);
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_cistatic int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
187962306a36Sopenharmony_ci		gfp_t mem_flags)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
188262306a36Sopenharmony_ci	struct list_head *ep_queue;
188362306a36Sopenharmony_ci	struct isp1760_qh *qh, *qhit;
188462306a36Sopenharmony_ci	unsigned long spinflags;
188562306a36Sopenharmony_ci	LIST_HEAD(new_qtds);
188662306a36Sopenharmony_ci	int retval;
188762306a36Sopenharmony_ci	int qh_in_queue;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
189062306a36Sopenharmony_ci	case PIPE_CONTROL:
189162306a36Sopenharmony_ci		ep_queue = &priv->qh_list[QH_CONTROL];
189262306a36Sopenharmony_ci		break;
189362306a36Sopenharmony_ci	case PIPE_BULK:
189462306a36Sopenharmony_ci		ep_queue = &priv->qh_list[QH_BULK];
189562306a36Sopenharmony_ci		break;
189662306a36Sopenharmony_ci	case PIPE_INTERRUPT:
189762306a36Sopenharmony_ci		if (urb->interval < 0)
189862306a36Sopenharmony_ci			return -EINVAL;
189962306a36Sopenharmony_ci		/* FIXME: Check bandwidth  */
190062306a36Sopenharmony_ci		ep_queue = &priv->qh_list[QH_INTERRUPT];
190162306a36Sopenharmony_ci		break;
190262306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
190362306a36Sopenharmony_ci		dev_err(hcd->self.controller, "%s: isochronous USB packets "
190462306a36Sopenharmony_ci							"not yet supported\n",
190562306a36Sopenharmony_ci							__func__);
190662306a36Sopenharmony_ci		return -EPIPE;
190762306a36Sopenharmony_ci	default:
190862306a36Sopenharmony_ci		dev_err(hcd->self.controller, "%s: unknown pipe type\n",
190962306a36Sopenharmony_ci							__func__);
191062306a36Sopenharmony_ci		return -EPIPE;
191162306a36Sopenharmony_ci	}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (usb_pipein(urb->pipe))
191462306a36Sopenharmony_ci		urb->actual_length = 0;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	packetize_urb(hcd, urb, &new_qtds, mem_flags);
191762306a36Sopenharmony_ci	if (list_empty(&new_qtds))
191862306a36Sopenharmony_ci		return -ENOMEM;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, spinflags);
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
192362306a36Sopenharmony_ci		retval = -ESHUTDOWN;
192462306a36Sopenharmony_ci		qtd_list_free(&new_qtds);
192562306a36Sopenharmony_ci		goto out;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci	retval = usb_hcd_link_urb_to_ep(hcd, urb);
192862306a36Sopenharmony_ci	if (retval) {
192962306a36Sopenharmony_ci		qtd_list_free(&new_qtds);
193062306a36Sopenharmony_ci		goto out;
193162306a36Sopenharmony_ci	}
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	qh = urb->ep->hcpriv;
193462306a36Sopenharmony_ci	if (qh) {
193562306a36Sopenharmony_ci		qh_in_queue = 0;
193662306a36Sopenharmony_ci		list_for_each_entry(qhit, ep_queue, qh_list) {
193762306a36Sopenharmony_ci			if (qhit == qh) {
193862306a36Sopenharmony_ci				qh_in_queue = 1;
193962306a36Sopenharmony_ci				break;
194062306a36Sopenharmony_ci			}
194162306a36Sopenharmony_ci		}
194262306a36Sopenharmony_ci		if (!qh_in_queue)
194362306a36Sopenharmony_ci			list_add_tail(&qh->qh_list, ep_queue);
194462306a36Sopenharmony_ci	} else {
194562306a36Sopenharmony_ci		qh = qh_alloc(GFP_ATOMIC);
194662306a36Sopenharmony_ci		if (!qh) {
194762306a36Sopenharmony_ci			retval = -ENOMEM;
194862306a36Sopenharmony_ci			usb_hcd_unlink_urb_from_ep(hcd, urb);
194962306a36Sopenharmony_ci			qtd_list_free(&new_qtds);
195062306a36Sopenharmony_ci			goto out;
195162306a36Sopenharmony_ci		}
195262306a36Sopenharmony_ci		list_add_tail(&qh->qh_list, ep_queue);
195362306a36Sopenharmony_ci		urb->ep->hcpriv = qh;
195462306a36Sopenharmony_ci	}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	list_splice_tail(&new_qtds, &qh->qtd_list);
195762306a36Sopenharmony_ci	schedule_ptds(hcd);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ciout:
196062306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, spinflags);
196162306a36Sopenharmony_ci	return retval;
196262306a36Sopenharmony_ci}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_cistatic void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
196562306a36Sopenharmony_ci		struct isp1760_qh *qh)
196662306a36Sopenharmony_ci{
196762306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
196862306a36Sopenharmony_ci	int skip_map;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	WARN_ON(qh->slot == -1);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	/* We need to forcefully reclaim the slot since some transfers never
197362306a36Sopenharmony_ci	   return, e.g. interrupt transfers and NAKed bulk transfers. */
197462306a36Sopenharmony_ci	if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
197562306a36Sopenharmony_ci		if (qh->slot != -1) {
197662306a36Sopenharmony_ci			skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
197762306a36Sopenharmony_ci			skip_map |= (1 << qh->slot);
197862306a36Sopenharmony_ci			isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
197962306a36Sopenharmony_ci			ndelay(100);
198062306a36Sopenharmony_ci		}
198162306a36Sopenharmony_ci		priv->atl_slots[qh->slot].qh = NULL;
198262306a36Sopenharmony_ci		priv->atl_slots[qh->slot].qtd = NULL;
198362306a36Sopenharmony_ci	} else {
198462306a36Sopenharmony_ci		if (qh->slot != -1) {
198562306a36Sopenharmony_ci			skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
198662306a36Sopenharmony_ci			skip_map |= (1 << qh->slot);
198762306a36Sopenharmony_ci			isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
198862306a36Sopenharmony_ci		}
198962306a36Sopenharmony_ci		priv->int_slots[qh->slot].qh = NULL;
199062306a36Sopenharmony_ci		priv->int_slots[qh->slot].qtd = NULL;
199162306a36Sopenharmony_ci	}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	qh->slot = -1;
199462306a36Sopenharmony_ci}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci/*
199762306a36Sopenharmony_ci * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
199862306a36Sopenharmony_ci * any active transfer belonging to the urb in the process.
199962306a36Sopenharmony_ci */
200062306a36Sopenharmony_cistatic void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
200162306a36Sopenharmony_ci						struct isp1760_qtd *qtd)
200262306a36Sopenharmony_ci{
200362306a36Sopenharmony_ci	struct urb *urb;
200462306a36Sopenharmony_ci	int urb_was_running;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	urb = qtd->urb;
200762306a36Sopenharmony_ci	urb_was_running = 0;
200862306a36Sopenharmony_ci	list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
200962306a36Sopenharmony_ci		if (qtd->urb != urb)
201062306a36Sopenharmony_ci			break;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci		if (qtd->status >= QTD_XFER_STARTED)
201362306a36Sopenharmony_ci			urb_was_running = 1;
201462306a36Sopenharmony_ci		if (last_qtd_of_urb(qtd, qh) &&
201562306a36Sopenharmony_ci					(qtd->status >= QTD_XFER_COMPLETE))
201662306a36Sopenharmony_ci			urb_was_running = 0;
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci		if (qtd->status == QTD_XFER_STARTED)
201962306a36Sopenharmony_ci			kill_transfer(hcd, urb, qh);
202062306a36Sopenharmony_ci		qtd->status = QTD_RETIRE;
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
202462306a36Sopenharmony_ci		qh->tt_buffer_dirty = 1;
202562306a36Sopenharmony_ci		if (usb_hub_clear_tt_buffer(urb))
202662306a36Sopenharmony_ci			/* Clear failed; let's hope things work anyway */
202762306a36Sopenharmony_ci			qh->tt_buffer_dirty = 0;
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_cistatic int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
203262306a36Sopenharmony_ci		int status)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
203562306a36Sopenharmony_ci	unsigned long spinflags;
203662306a36Sopenharmony_ci	struct isp1760_qh *qh;
203762306a36Sopenharmony_ci	struct isp1760_qtd *qtd;
203862306a36Sopenharmony_ci	int retval = 0;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, spinflags);
204162306a36Sopenharmony_ci	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
204262306a36Sopenharmony_ci	if (retval)
204362306a36Sopenharmony_ci		goto out;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	qh = urb->ep->hcpriv;
204662306a36Sopenharmony_ci	if (!qh) {
204762306a36Sopenharmony_ci		retval = -EINVAL;
204862306a36Sopenharmony_ci		goto out;
204962306a36Sopenharmony_ci	}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
205262306a36Sopenharmony_ci		if (qtd->urb == urb) {
205362306a36Sopenharmony_ci			dequeue_urb_from_qtd(hcd, qh, qtd);
205462306a36Sopenharmony_ci			list_move(&qtd->qtd_list, &qh->qtd_list);
205562306a36Sopenharmony_ci			break;
205662306a36Sopenharmony_ci		}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	urb->status = status;
205962306a36Sopenharmony_ci	schedule_ptds(hcd);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ciout:
206262306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, spinflags);
206362306a36Sopenharmony_ci	return retval;
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cistatic void isp1760_endpoint_disable(struct usb_hcd *hcd,
206762306a36Sopenharmony_ci		struct usb_host_endpoint *ep)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
207062306a36Sopenharmony_ci	unsigned long spinflags;
207162306a36Sopenharmony_ci	struct isp1760_qh *qh, *qh_iter;
207262306a36Sopenharmony_ci	int i;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, spinflags);
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	qh = ep->hcpriv;
207762306a36Sopenharmony_ci	if (!qh)
207862306a36Sopenharmony_ci		goto out;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	WARN_ON(!list_empty(&qh->qtd_list));
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	for (i = 0; i < QH_END; i++)
208362306a36Sopenharmony_ci		list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
208462306a36Sopenharmony_ci			if (qh_iter == qh) {
208562306a36Sopenharmony_ci				list_del(&qh_iter->qh_list);
208662306a36Sopenharmony_ci				i = QH_END;
208762306a36Sopenharmony_ci				break;
208862306a36Sopenharmony_ci			}
208962306a36Sopenharmony_ci	qh_free(qh);
209062306a36Sopenharmony_ci	ep->hcpriv = NULL;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	schedule_ptds(hcd);
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ciout:
209562306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, spinflags);
209662306a36Sopenharmony_ci}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_cistatic int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
209962306a36Sopenharmony_ci{
210062306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
210162306a36Sopenharmony_ci	u32 status = 0;
210262306a36Sopenharmony_ci	int retval = 1;
210362306a36Sopenharmony_ci	unsigned long flags;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	/* if !PM, root hub timers won't get shut down ... */
210662306a36Sopenharmony_ci	if (!HC_IS_RUNNING(hcd->state))
210762306a36Sopenharmony_ci		return 0;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	/* init status to no-changes */
211062306a36Sopenharmony_ci	buf[0] = 0;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, flags);
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	if (isp1760_hcd_is_set(hcd, PORT_OWNER) &&
211562306a36Sopenharmony_ci	    isp1760_hcd_is_set(hcd, PORT_CSC)) {
211662306a36Sopenharmony_ci		isp1760_hcd_clear(hcd, PORT_CSC);
211762306a36Sopenharmony_ci		goto done;
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	/*
212162306a36Sopenharmony_ci	 * Return status information even for ports with OWNER set.
212262306a36Sopenharmony_ci	 * Otherwise hub_wq wouldn't see the disconnect event when a
212362306a36Sopenharmony_ci	 * high-speed device is switched over to the companion
212462306a36Sopenharmony_ci	 * controller by the user.
212562306a36Sopenharmony_ci	 */
212662306a36Sopenharmony_ci	if (isp1760_hcd_is_set(hcd, PORT_CSC) ||
212762306a36Sopenharmony_ci	    (isp1760_hcd_is_set(hcd, PORT_RESUME) &&
212862306a36Sopenharmony_ci	     time_after_eq(jiffies, priv->reset_done))) {
212962306a36Sopenharmony_ci		buf [0] |= 1 << (0 + 1);
213062306a36Sopenharmony_ci		status = STS_PCD;
213162306a36Sopenharmony_ci	}
213262306a36Sopenharmony_ci	/* FIXME autosuspend idle root hubs */
213362306a36Sopenharmony_cidone:
213462306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, flags);
213562306a36Sopenharmony_ci	return status ? retval : 0;
213662306a36Sopenharmony_ci}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_cistatic void isp1760_hub_descriptor(struct isp1760_hcd *priv,
213962306a36Sopenharmony_ci		struct usb_hub_descriptor *desc)
214062306a36Sopenharmony_ci{
214162306a36Sopenharmony_ci	int ports;
214262306a36Sopenharmony_ci	u16 temp;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	ports = isp1760_hcd_n_ports(priv->hcd);
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	desc->bDescriptorType = USB_DT_HUB;
214762306a36Sopenharmony_ci	/* priv 1.0, 2.3.9 says 20ms max */
214862306a36Sopenharmony_ci	desc->bPwrOn2PwrGood = 10;
214962306a36Sopenharmony_ci	desc->bHubContrCurrent = 0;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	desc->bNbrPorts = ports;
215262306a36Sopenharmony_ci	temp = 1 + (ports / 8);
215362306a36Sopenharmony_ci	desc->bDescLength = 7 + 2 * temp;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
215662306a36Sopenharmony_ci	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
215762306a36Sopenharmony_ci	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	/* per-port overcurrent reporting */
216062306a36Sopenharmony_ci	temp = HUB_CHAR_INDV_PORT_OCPM;
216162306a36Sopenharmony_ci	if (isp1760_hcd_ppc_is_set(priv->hcd))
216262306a36Sopenharmony_ci		/* per-port power control */
216362306a36Sopenharmony_ci		temp |= HUB_CHAR_INDV_PORT_LPSM;
216462306a36Sopenharmony_ci	else
216562306a36Sopenharmony_ci		/* no power switching */
216662306a36Sopenharmony_ci		temp |= HUB_CHAR_NO_LPSM;
216762306a36Sopenharmony_ci	desc->wHubCharacteristics = cpu_to_le16(temp);
216862306a36Sopenharmony_ci}
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_cistatic void check_reset_complete(struct usb_hcd *hcd, int index)
217362306a36Sopenharmony_ci{
217462306a36Sopenharmony_ci	if (!(isp1760_hcd_is_set(hcd, PORT_CONNECT)))
217562306a36Sopenharmony_ci		return;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	/* if reset finished and it's still not enabled -- handoff */
217862306a36Sopenharmony_ci	if (!isp1760_hcd_is_set(hcd, PORT_PE)) {
217962306a36Sopenharmony_ci		dev_info(hcd->self.controller,
218062306a36Sopenharmony_ci			 "port %d full speed --> companion\n", index + 1);
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci		isp1760_hcd_set(hcd, PORT_OWNER);
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci		isp1760_hcd_clear(hcd, PORT_CSC);
218562306a36Sopenharmony_ci	} else {
218662306a36Sopenharmony_ci		dev_info(hcd->self.controller, "port %d high speed\n",
218762306a36Sopenharmony_ci			 index + 1);
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	return;
219162306a36Sopenharmony_ci}
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_cistatic int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
219462306a36Sopenharmony_ci		u16 wValue, u16 wIndex, char *buf, u16 wLength)
219562306a36Sopenharmony_ci{
219662306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
219762306a36Sopenharmony_ci	u32 status;
219862306a36Sopenharmony_ci	unsigned long flags;
219962306a36Sopenharmony_ci	int retval = 0;
220062306a36Sopenharmony_ci	int ports;
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	ports = isp1760_hcd_n_ports(hcd);
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	/*
220562306a36Sopenharmony_ci	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
220662306a36Sopenharmony_ci	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
220762306a36Sopenharmony_ci	 * (track current state ourselves) ... blink for diagnostics,
220862306a36Sopenharmony_ci	 * power, "this is the one", etc.  EHCI spec supports this.
220962306a36Sopenharmony_ci	 */
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, flags);
221262306a36Sopenharmony_ci	switch (typeReq) {
221362306a36Sopenharmony_ci	case ClearHubFeature:
221462306a36Sopenharmony_ci		switch (wValue) {
221562306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
221662306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
221762306a36Sopenharmony_ci			/* no hub-wide feature/status flags */
221862306a36Sopenharmony_ci			break;
221962306a36Sopenharmony_ci		default:
222062306a36Sopenharmony_ci			goto error;
222162306a36Sopenharmony_ci		}
222262306a36Sopenharmony_ci		break;
222362306a36Sopenharmony_ci	case ClearPortFeature:
222462306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
222562306a36Sopenharmony_ci			goto error;
222662306a36Sopenharmony_ci		wIndex--;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci		/*
222962306a36Sopenharmony_ci		 * Even if OWNER is set, so the port is owned by the
223062306a36Sopenharmony_ci		 * companion controller, hub_wq needs to be able to clear
223162306a36Sopenharmony_ci		 * the port-change status bits (especially
223262306a36Sopenharmony_ci		 * USB_PORT_STAT_C_CONNECTION).
223362306a36Sopenharmony_ci		 */
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci		switch (wValue) {
223662306a36Sopenharmony_ci		case USB_PORT_FEAT_ENABLE:
223762306a36Sopenharmony_ci			isp1760_hcd_clear(hcd, PORT_PE);
223862306a36Sopenharmony_ci			break;
223962306a36Sopenharmony_ci		case USB_PORT_FEAT_C_ENABLE:
224062306a36Sopenharmony_ci			/* XXX error? */
224162306a36Sopenharmony_ci			break;
224262306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
224362306a36Sopenharmony_ci			if (isp1760_hcd_is_set(hcd, PORT_RESET))
224462306a36Sopenharmony_ci				goto error;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci			if (isp1760_hcd_is_set(hcd, PORT_SUSPEND)) {
224762306a36Sopenharmony_ci				if (!isp1760_hcd_is_set(hcd, PORT_PE))
224862306a36Sopenharmony_ci					goto error;
224962306a36Sopenharmony_ci				/* resume signaling for 20 msec */
225062306a36Sopenharmony_ci				isp1760_hcd_clear(hcd, PORT_CSC);
225162306a36Sopenharmony_ci				isp1760_hcd_set(hcd, PORT_RESUME);
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci				priv->reset_done = jiffies +
225462306a36Sopenharmony_ci					msecs_to_jiffies(USB_RESUME_TIMEOUT);
225562306a36Sopenharmony_ci			}
225662306a36Sopenharmony_ci			break;
225762306a36Sopenharmony_ci		case USB_PORT_FEAT_C_SUSPEND:
225862306a36Sopenharmony_ci			/* we auto-clear this feature */
225962306a36Sopenharmony_ci			break;
226062306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
226162306a36Sopenharmony_ci			if (isp1760_hcd_ppc_is_set(hcd))
226262306a36Sopenharmony_ci				isp1760_hcd_clear(hcd, PORT_POWER);
226362306a36Sopenharmony_ci			break;
226462306a36Sopenharmony_ci		case USB_PORT_FEAT_C_CONNECTION:
226562306a36Sopenharmony_ci			isp1760_hcd_set(hcd, PORT_CSC);
226662306a36Sopenharmony_ci			break;
226762306a36Sopenharmony_ci		case USB_PORT_FEAT_C_OVER_CURRENT:
226862306a36Sopenharmony_ci			/* XXX error ?*/
226962306a36Sopenharmony_ci			break;
227062306a36Sopenharmony_ci		case USB_PORT_FEAT_C_RESET:
227162306a36Sopenharmony_ci			/* GetPortStatus clears reset */
227262306a36Sopenharmony_ci			break;
227362306a36Sopenharmony_ci		default:
227462306a36Sopenharmony_ci			goto error;
227562306a36Sopenharmony_ci		}
227662306a36Sopenharmony_ci		isp1760_hcd_read(hcd, CMD_RUN);
227762306a36Sopenharmony_ci		break;
227862306a36Sopenharmony_ci	case GetHubDescriptor:
227962306a36Sopenharmony_ci		isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
228062306a36Sopenharmony_ci			buf);
228162306a36Sopenharmony_ci		break;
228262306a36Sopenharmony_ci	case GetHubStatus:
228362306a36Sopenharmony_ci		/* no hub-wide feature/status flags */
228462306a36Sopenharmony_ci		memset(buf, 0, 4);
228562306a36Sopenharmony_ci		break;
228662306a36Sopenharmony_ci	case GetPortStatus:
228762306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
228862306a36Sopenharmony_ci			goto error;
228962306a36Sopenharmony_ci		wIndex--;
229062306a36Sopenharmony_ci		status = 0;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci		/* wPortChange bits */
229362306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_CSC))
229462306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_CONNECTION << 16;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci		/* whoever resumes must GetPortStatus to complete it!! */
229762306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_RESUME)) {
229862306a36Sopenharmony_ci			dev_err(hcd->self.controller, "Port resume should be skipped.\n");
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci			/* Remote Wakeup received? */
230162306a36Sopenharmony_ci			if (!priv->reset_done) {
230262306a36Sopenharmony_ci				/* resume signaling for 20 msec */
230362306a36Sopenharmony_ci				priv->reset_done = jiffies
230462306a36Sopenharmony_ci						+ msecs_to_jiffies(20);
230562306a36Sopenharmony_ci				/* check the port again */
230662306a36Sopenharmony_ci				mod_timer(&hcd->rh_timer, priv->reset_done);
230762306a36Sopenharmony_ci			}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci			/* resume completed? */
231062306a36Sopenharmony_ci			else if (time_after_eq(jiffies,
231162306a36Sopenharmony_ci					priv->reset_done)) {
231262306a36Sopenharmony_ci				status |= USB_PORT_STAT_C_SUSPEND << 16;
231362306a36Sopenharmony_ci				priv->reset_done = 0;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci				/* stop resume signaling */
231662306a36Sopenharmony_ci				isp1760_hcd_clear(hcd, PORT_CSC);
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci				retval = isp1760_hcd_clear_and_wait(hcd,
231962306a36Sopenharmony_ci							  PORT_RESUME, 2000);
232062306a36Sopenharmony_ci				if (retval != 0) {
232162306a36Sopenharmony_ci					dev_err(hcd->self.controller,
232262306a36Sopenharmony_ci						"port %d resume error %d\n",
232362306a36Sopenharmony_ci						wIndex + 1, retval);
232462306a36Sopenharmony_ci					goto error;
232562306a36Sopenharmony_ci				}
232662306a36Sopenharmony_ci			}
232762306a36Sopenharmony_ci		}
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		/* whoever resets must GetPortStatus to complete it!! */
233062306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_RESET) &&
233162306a36Sopenharmony_ci		    time_after_eq(jiffies, priv->reset_done)) {
233262306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_RESET << 16;
233362306a36Sopenharmony_ci			priv->reset_done = 0;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci			/* force reset to complete */
233662306a36Sopenharmony_ci			/* REVISIT:  some hardware needs 550+ usec to clear
233762306a36Sopenharmony_ci			 * this bit; seems too long to spin routinely...
233862306a36Sopenharmony_ci			 */
233962306a36Sopenharmony_ci			retval = isp1760_hcd_clear_and_wait(hcd, PORT_RESET,
234062306a36Sopenharmony_ci							    750);
234162306a36Sopenharmony_ci			if (retval != 0) {
234262306a36Sopenharmony_ci				dev_err(hcd->self.controller, "port %d reset error %d\n",
234362306a36Sopenharmony_ci					wIndex + 1, retval);
234462306a36Sopenharmony_ci				goto error;
234562306a36Sopenharmony_ci			}
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci			/* see what we found out */
234862306a36Sopenharmony_ci			check_reset_complete(hcd, wIndex);
234962306a36Sopenharmony_ci		}
235062306a36Sopenharmony_ci		/*
235162306a36Sopenharmony_ci		 * Even if OWNER is set, there's no harm letting hub_wq
235262306a36Sopenharmony_ci		 * see the wPortStatus values (they should all be 0 except
235362306a36Sopenharmony_ci		 * for PORT_POWER anyway).
235462306a36Sopenharmony_ci		 */
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_OWNER))
235762306a36Sopenharmony_ci			dev_err(hcd->self.controller, "PORT_OWNER is set\n");
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_CONNECT)) {
236062306a36Sopenharmony_ci			status |= USB_PORT_STAT_CONNECTION;
236162306a36Sopenharmony_ci			/* status may be from integrated TT */
236262306a36Sopenharmony_ci			status |= USB_PORT_STAT_HIGH_SPEED;
236362306a36Sopenharmony_ci		}
236462306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_PE))
236562306a36Sopenharmony_ci			status |= USB_PORT_STAT_ENABLE;
236662306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_SUSPEND) &&
236762306a36Sopenharmony_ci		    isp1760_hcd_is_set(hcd, PORT_RESUME))
236862306a36Sopenharmony_ci			status |= USB_PORT_STAT_SUSPEND;
236962306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_RESET))
237062306a36Sopenharmony_ci			status |= USB_PORT_STAT_RESET;
237162306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_POWER))
237262306a36Sopenharmony_ci			status |= USB_PORT_STAT_POWER;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
237562306a36Sopenharmony_ci		break;
237662306a36Sopenharmony_ci	case SetHubFeature:
237762306a36Sopenharmony_ci		switch (wValue) {
237862306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
237962306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
238062306a36Sopenharmony_ci			/* no hub-wide feature/status flags */
238162306a36Sopenharmony_ci			break;
238262306a36Sopenharmony_ci		default:
238362306a36Sopenharmony_ci			goto error;
238462306a36Sopenharmony_ci		}
238562306a36Sopenharmony_ci		break;
238662306a36Sopenharmony_ci	case SetPortFeature:
238762306a36Sopenharmony_ci		wIndex &= 0xff;
238862306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
238962306a36Sopenharmony_ci			goto error;
239062306a36Sopenharmony_ci		wIndex--;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci		if (isp1760_hcd_is_set(hcd, PORT_OWNER))
239362306a36Sopenharmony_ci			break;
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci		switch (wValue) {
239662306a36Sopenharmony_ci		case USB_PORT_FEAT_ENABLE:
239762306a36Sopenharmony_ci			isp1760_hcd_set(hcd, PORT_PE);
239862306a36Sopenharmony_ci			break;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
240162306a36Sopenharmony_ci			if (!isp1760_hcd_is_set(hcd, PORT_PE) ||
240262306a36Sopenharmony_ci			    isp1760_hcd_is_set(hcd, PORT_RESET))
240362306a36Sopenharmony_ci				goto error;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci			isp1760_hcd_set(hcd, PORT_SUSPEND);
240662306a36Sopenharmony_ci			break;
240762306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
240862306a36Sopenharmony_ci			if (isp1760_hcd_ppc_is_set(hcd))
240962306a36Sopenharmony_ci				isp1760_hcd_set(hcd, PORT_POWER);
241062306a36Sopenharmony_ci			break;
241162306a36Sopenharmony_ci		case USB_PORT_FEAT_RESET:
241262306a36Sopenharmony_ci			if (isp1760_hcd_is_set(hcd, PORT_RESUME))
241362306a36Sopenharmony_ci				goto error;
241462306a36Sopenharmony_ci			/* line status bits may report this as low speed,
241562306a36Sopenharmony_ci			 * which can be fine if this root hub has a
241662306a36Sopenharmony_ci			 * transaction translator built in.
241762306a36Sopenharmony_ci			 */
241862306a36Sopenharmony_ci			if ((isp1760_hcd_is_set(hcd, PORT_CONNECT) &&
241962306a36Sopenharmony_ci			     !isp1760_hcd_is_set(hcd, PORT_PE)) &&
242062306a36Sopenharmony_ci			    (isp1760_hcd_read(hcd, PORT_LSTATUS) == 1)) {
242162306a36Sopenharmony_ci				isp1760_hcd_set(hcd, PORT_OWNER);
242262306a36Sopenharmony_ci			} else {
242362306a36Sopenharmony_ci				isp1760_hcd_set(hcd, PORT_RESET);
242462306a36Sopenharmony_ci				isp1760_hcd_clear(hcd, PORT_PE);
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci				/*
242762306a36Sopenharmony_ci				 * caller must wait, then call GetPortStatus
242862306a36Sopenharmony_ci				 * usb 2.0 spec says 50 ms resets on root
242962306a36Sopenharmony_ci				 */
243062306a36Sopenharmony_ci				priv->reset_done = jiffies +
243162306a36Sopenharmony_ci					msecs_to_jiffies(50);
243262306a36Sopenharmony_ci			}
243362306a36Sopenharmony_ci			break;
243462306a36Sopenharmony_ci		default:
243562306a36Sopenharmony_ci			goto error;
243662306a36Sopenharmony_ci		}
243762306a36Sopenharmony_ci		break;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	default:
244062306a36Sopenharmony_cierror:
244162306a36Sopenharmony_ci		/* "stall" on error */
244262306a36Sopenharmony_ci		retval = -EPIPE;
244362306a36Sopenharmony_ci	}
244462306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, flags);
244562306a36Sopenharmony_ci	return retval;
244662306a36Sopenharmony_ci}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cistatic int isp1760_get_frame(struct usb_hcd *hcd)
244962306a36Sopenharmony_ci{
245062306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
245162306a36Sopenharmony_ci	u32 fr;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	fr = isp1760_hcd_read(hcd, HC_FRINDEX);
245462306a36Sopenharmony_ci	return (fr >> 3) % priv->periodic_size;
245562306a36Sopenharmony_ci}
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_cistatic void isp1760_stop(struct usb_hcd *hcd)
245862306a36Sopenharmony_ci{
245962306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	del_timer(&errata2_timer);
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER,	1,
246462306a36Sopenharmony_ci			NULL, 0);
246562306a36Sopenharmony_ci	msleep(20);
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	spin_lock_irq(&priv->lock);
246862306a36Sopenharmony_ci	ehci_reset(hcd);
246962306a36Sopenharmony_ci	/* Disable IRQ */
247062306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
247162306a36Sopenharmony_ci	spin_unlock_irq(&priv->lock);
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, FLAG_CF);
247462306a36Sopenharmony_ci}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_cistatic void isp1760_shutdown(struct usb_hcd *hcd)
247762306a36Sopenharmony_ci{
247862306a36Sopenharmony_ci	isp1760_stop(hcd);
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	isp1760_hcd_clear(hcd, CMD_RUN);
248362306a36Sopenharmony_ci}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_cistatic void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
248662306a36Sopenharmony_ci						struct usb_host_endpoint *ep)
248762306a36Sopenharmony_ci{
248862306a36Sopenharmony_ci	struct isp1760_hcd *priv = hcd_to_priv(hcd);
248962306a36Sopenharmony_ci	struct isp1760_qh *qh = ep->hcpriv;
249062306a36Sopenharmony_ci	unsigned long spinflags;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	if (!qh)
249362306a36Sopenharmony_ci		return;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, spinflags);
249662306a36Sopenharmony_ci	qh->tt_buffer_dirty = 0;
249762306a36Sopenharmony_ci	schedule_ptds(hcd);
249862306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, spinflags);
249962306a36Sopenharmony_ci}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_cistatic const struct hc_driver isp1760_hc_driver = {
250362306a36Sopenharmony_ci	.description		= "isp1760-hcd",
250462306a36Sopenharmony_ci	.product_desc		= "NXP ISP1760 USB Host Controller",
250562306a36Sopenharmony_ci	.hcd_priv_size		= sizeof(struct isp1760_hcd *),
250662306a36Sopenharmony_ci	.irq			= isp1760_irq,
250762306a36Sopenharmony_ci	.flags			= HCD_MEMORY | HCD_USB2,
250862306a36Sopenharmony_ci	.reset			= isp1760_hc_setup,
250962306a36Sopenharmony_ci	.start			= isp1760_run,
251062306a36Sopenharmony_ci	.stop			= isp1760_stop,
251162306a36Sopenharmony_ci	.shutdown		= isp1760_shutdown,
251262306a36Sopenharmony_ci	.urb_enqueue		= isp1760_urb_enqueue,
251362306a36Sopenharmony_ci	.urb_dequeue		= isp1760_urb_dequeue,
251462306a36Sopenharmony_ci	.endpoint_disable	= isp1760_endpoint_disable,
251562306a36Sopenharmony_ci	.get_frame_number	= isp1760_get_frame,
251662306a36Sopenharmony_ci	.hub_status_data	= isp1760_hub_status_data,
251762306a36Sopenharmony_ci	.hub_control		= isp1760_hub_control,
251862306a36Sopenharmony_ci	.clear_tt_buffer_complete	= isp1760_clear_tt_buffer_complete,
251962306a36Sopenharmony_ci};
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ciint __init isp1760_init_kmem_once(void)
252262306a36Sopenharmony_ci{
252362306a36Sopenharmony_ci	urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
252462306a36Sopenharmony_ci			sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
252562306a36Sopenharmony_ci			SLAB_MEM_SPREAD, NULL);
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (!urb_listitem_cachep)
252862306a36Sopenharmony_ci		return -ENOMEM;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	qtd_cachep = kmem_cache_create("isp1760_qtd",
253162306a36Sopenharmony_ci			sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
253262306a36Sopenharmony_ci			SLAB_MEM_SPREAD, NULL);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	if (!qtd_cachep)
253562306a36Sopenharmony_ci		goto destroy_urb_listitem;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
253862306a36Sopenharmony_ci			0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	if (!qh_cachep)
254162306a36Sopenharmony_ci		goto destroy_qtd;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	return 0;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_cidestroy_qtd:
254662306a36Sopenharmony_ci	kmem_cache_destroy(qtd_cachep);
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_cidestroy_urb_listitem:
254962306a36Sopenharmony_ci	kmem_cache_destroy(urb_listitem_cachep);
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	return -ENOMEM;
255262306a36Sopenharmony_ci}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_civoid isp1760_deinit_kmem_cache(void)
255562306a36Sopenharmony_ci{
255662306a36Sopenharmony_ci	kmem_cache_destroy(qtd_cachep);
255762306a36Sopenharmony_ci	kmem_cache_destroy(qh_cachep);
255862306a36Sopenharmony_ci	kmem_cache_destroy(urb_listitem_cachep);
255962306a36Sopenharmony_ci}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ciint isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
256262306a36Sopenharmony_ci			 int irq, unsigned long irqflags,
256362306a36Sopenharmony_ci			 struct device *dev)
256462306a36Sopenharmony_ci{
256562306a36Sopenharmony_ci	const struct isp1760_memory_layout *mem_layout = priv->memory_layout;
256662306a36Sopenharmony_ci	struct usb_hcd *hcd;
256762306a36Sopenharmony_ci	int ret;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
257062306a36Sopenharmony_ci	if (!hcd)
257162306a36Sopenharmony_ci		return -ENOMEM;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	*(struct isp1760_hcd **)hcd->hcd_priv = priv;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	priv->hcd = hcd;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	priv->atl_slots = kcalloc(mem_layout->slot_num,
257862306a36Sopenharmony_ci				  sizeof(struct isp1760_slotinfo), GFP_KERNEL);
257962306a36Sopenharmony_ci	if (!priv->atl_slots) {
258062306a36Sopenharmony_ci		ret = -ENOMEM;
258162306a36Sopenharmony_ci		goto put_hcd;
258262306a36Sopenharmony_ci	}
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	priv->int_slots = kcalloc(mem_layout->slot_num,
258562306a36Sopenharmony_ci				  sizeof(struct isp1760_slotinfo), GFP_KERNEL);
258662306a36Sopenharmony_ci	if (!priv->int_slots) {
258762306a36Sopenharmony_ci		ret = -ENOMEM;
258862306a36Sopenharmony_ci		goto free_atl_slots;
258962306a36Sopenharmony_ci	}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	init_memory(priv);
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	hcd->irq = irq;
259462306a36Sopenharmony_ci	hcd->rsrc_start = mem->start;
259562306a36Sopenharmony_ci	hcd->rsrc_len = resource_size(mem);
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	/* This driver doesn't support wakeup requests */
259862306a36Sopenharmony_ci	hcd->cant_recv_wakeups = 1;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	ret = usb_add_hcd(hcd, irq, irqflags);
260162306a36Sopenharmony_ci	if (ret)
260262306a36Sopenharmony_ci		goto free_int_slots;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	device_wakeup_enable(hcd->self.controller);
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	return 0;
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_cifree_int_slots:
260962306a36Sopenharmony_ci	kfree(priv->int_slots);
261062306a36Sopenharmony_cifree_atl_slots:
261162306a36Sopenharmony_ci	kfree(priv->atl_slots);
261262306a36Sopenharmony_ciput_hcd:
261362306a36Sopenharmony_ci	usb_put_hcd(hcd);
261462306a36Sopenharmony_ci	return ret;
261562306a36Sopenharmony_ci}
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_civoid isp1760_hcd_unregister(struct isp1760_hcd *priv)
261862306a36Sopenharmony_ci{
261962306a36Sopenharmony_ci	if (!priv->hcd)
262062306a36Sopenharmony_ci		return;
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	usb_remove_hcd(priv->hcd);
262362306a36Sopenharmony_ci	usb_put_hcd(priv->hcd);
262462306a36Sopenharmony_ci	kfree(priv->atl_slots);
262562306a36Sopenharmony_ci	kfree(priv->int_slots);
262662306a36Sopenharmony_ci}
2627