net2280.h 11.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 * NetChip 2280 high/full speed USB device controller.
 * Unlike many such controllers, this one talks PCI.
 */

/*
 * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
 * Copyright (C) 2003 David Brownell
9
 * Copyright (C) 2014 Ricardo Ribalda - Qtechnology/AS
L
Linus Torvalds 已提交
10 11 12 13 14 15 16
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

17
#include <linux/usb/net2280.h>
18
#include <linux/usb/usb338x.h>
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27

/*-------------------------------------------------------------------------*/

#ifdef	__KERNEL__

/* indexed registers [11.10] are accessed indirectly
 * caller must own the device lock.
 */

28
static inline u32 get_idx_reg(struct net2280_regs __iomem *regs, u32 index)
L
Linus Torvalds 已提交
29
{
30
	writel(index, &regs->idxaddr);
L
Linus Torvalds 已提交
31
	/* NOTE:  synchs device/cpu memory views */
32
	return readl(&regs->idxdata);
L
Linus Torvalds 已提交
33 34 35
}

static inline void
36
set_idx_reg(struct net2280_regs __iomem *regs, u32 index, u32 value)
L
Linus Torvalds 已提交
37
{
38 39
	writel(index, &regs->idxaddr);
	writel(value, &regs->idxdata);
L
Linus Torvalds 已提交
40 41 42 43 44
	/* posted, may not be visible yet */
}

#endif	/* __KERNEL__ */

45
#define PCI_VENDOR_ID_PLX_LEGACY 0x17cc
L
Linus Torvalds 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

#define REG_DIAG		0x0
#define     RETRY_COUNTER                                       16
#define     FORCE_PCI_SERR                                      11
#define     FORCE_PCI_INTERRUPT                                 10
#define     FORCE_USB_INTERRUPT                                 9
#define     FORCE_CPU_INTERRUPT                                 8
#define     ILLEGAL_BYTE_ENABLES                                5
#define     FAST_TIMES                                          4
#define     FORCE_RECEIVE_ERROR                                 2
#define     FORCE_TRANSMIT_CRC_ERROR                            0
#define REG_FRAME		0x02	/* from last sof */
#define REG_CHIPREV		0x03	/* in bcd */
#define	REG_HS_NAK_RATE		0x0a	/* NAK per N uframes */

#define	CHIPREV_1	0x0100
#define	CHIPREV_1A	0x0110

64 65 66
/* DEFECT 7374 */
#define DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS         200
#define DEFECT_7374_PROCESSOR_WAIT_TIME             10
L
Linus Torvalds 已提交
67

68 69 70 71
/* ep0 max packet size */
#define EP0_SS_MAX_PACKET_SIZE  0x200
#define EP0_HS_MAX_PACKET_SIZE  0x40
#ifdef	__KERNEL__
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82

/*-------------------------------------------------------------------------*/

/* [8.3] for scatter/gather i/o
 * use struct net2280_dma_regs bitfields
 */
struct net2280_dma {
	__le32		dmacount;
	__le32		dmaaddr;		/* the buffer */
	__le32		dmadesc;		/* next dma descriptor */
	__le32		_reserved;
83
} __aligned(16);
L
Linus Torvalds 已提交
84 85 86 87 88 89 90

/*-------------------------------------------------------------------------*/

/* DRIVER DATA STRUCTURES and UTILITIES */

struct net2280_ep {
	struct usb_ep				ep;
91
	struct net2280_ep_regs __iomem *cfg;
L
Linus Torvalds 已提交
92 93 94
	struct net2280_ep_regs			__iomem *regs;
	struct net2280_dma_regs			__iomem *dma;
	struct net2280_dma			*dummy;
95
	struct usb338x_fifo_regs __iomem *fiforegs;
L
Linus Torvalds 已提交
96 97 98
	dma_addr_t				td_dma;	/* of dummy */
	struct net2280				*dev;
	unsigned long				irqs;
99
	unsigned is_halt:1, dma_started:1;
L
Linus Torvalds 已提交
100 101 102 103 104 105 106 107 108

	/* analogous to a host-side qh */
	struct list_head			queue;
	const struct usb_endpoint_descriptor	*desc;
	unsigned				num : 8,
						fifo_size : 12,
						in_fifo_validate : 1,
						out_overflow : 1,
						stopped : 1,
109
						wedged : 1,
L
Linus Torvalds 已提交
110
						is_in : 1,
111 112
						is_iso : 1,
						responded : 1;
L
Linus Torvalds 已提交
113 114
};

115
static inline void allow_status(struct net2280_ep *ep)
L
Linus Torvalds 已提交
116 117
{
	/* ep0 only */
118 119 120
	writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
		BIT(CLEAR_NAK_OUT_PACKETS) |
		BIT(CLEAR_NAK_OUT_PACKETS_MODE)
L
Linus Torvalds 已提交
121 122 123 124
		, &ep->regs->ep_rsp);
	ep->stopped = 1;
}

125
static void allow_status_338x(struct net2280_ep *ep)
L
Linus Torvalds 已提交
126
{
127 128 129 130 131
	/*
	 * Control Status Phase Handshake was set by the chip when the setup
	 * packet arrived. While set, the chip automatically NAKs the host's
	 * Status Phase tokens.
	 */
132
	writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE), &ep->regs->ep_rsp);
133 134 135 136 137

	ep->stopped = 1;

	/* TD 9.9 Halt Endpoint test.  TD 9.22 set feature test. */
	ep->responded = 0;
L
Linus Torvalds 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
}

struct net2280_request {
	struct usb_request		req;
	struct net2280_dma		*td;
	dma_addr_t			td_dma;
	struct list_head		queue;
	unsigned			mapped : 1,
					valid : 1;
};

struct net2280 {
	/* each pci device provides one gadget, several endpoints */
	struct usb_gadget		gadget;
	spinlock_t			lock;
153
	struct net2280_ep		ep[9];
154
	struct usb_gadget_driver	*driver;
L
Linus Torvalds 已提交
155 156 157 158
	unsigned			enabled : 1,
					protocol_stall : 1,
					softconnect : 1,
					got_irq : 1,
159 160 161 162 163 164 165
					region:1,
					u1_enable:1,
					u2_enable:1,
					ltm_enable:1,
					wakeup_enable:1,
					selfpowered:1,
					addressed_state:1;
L
Linus Torvalds 已提交
166
	u16				chiprev;
167 168
	int enhanced_mode;
	int n_ep;
L
Linus Torvalds 已提交
169 170 171 172 173

	/* pci state used to access those endpoints */
	struct pci_dev			*pdev;
	struct net2280_regs		__iomem *regs;
	struct net2280_usb_regs		__iomem *usb;
174
	struct usb338x_usb_ext_regs	__iomem *usb_ext;
L
Linus Torvalds 已提交
175 176 177 178
	struct net2280_pci_regs		__iomem *pci;
	struct net2280_dma_regs		__iomem *dma;
	struct net2280_dep_regs		__iomem *dep;
	struct net2280_ep_regs		__iomem *epregs;
179 180 181 182 183 184
	struct usb338x_fifo_regs	__iomem *fiforegs;
	struct usb338x_ll_regs		__iomem *llregs;
	struct usb338x_ll_lfps_regs	__iomem *ll_lfps_regs;
	struct usb338x_ll_tsn_regs	__iomem *ll_tsn_regs;
	struct usb338x_ll_chi_regs	__iomem *ll_chicken_reg;
	struct usb338x_pl_regs		__iomem *plregs;
L
Linus Torvalds 已提交
185 186

	struct pci_pool			*requests;
187
	/* statistics...*/
L
Linus Torvalds 已提交
188 189
};

190
static inline void set_halt(struct net2280_ep *ep)
L
Linus Torvalds 已提交
191 192
{
	/* ep0 and bulk/intr endpoints */
193 194 195 196 197
	writel(BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
		/* set NAK_OUT for erratum 0114 */
		((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) |
		BIT(SET_ENDPOINT_HALT),
		&ep->regs->ep_rsp);
L
Linus Torvalds 已提交
198 199
}

200
static inline void clear_halt(struct net2280_ep *ep)
L
Linus Torvalds 已提交
201 202
{
	/* ep0 and bulk/intr endpoints */
203 204 205 206
	writel(BIT(CLEAR_ENDPOINT_HALT) |
		BIT(CLEAR_ENDPOINT_TOGGLE) |
		    /*
		     * unless the gadget driver left a short packet in the
L
Linus Torvalds 已提交
207 208
		     * fifo, this reverses the erratum 0114 workaround.
		     */
209 210
		((ep->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS),
		&ep->regs->ep_rsp);
L
Linus Torvalds 已提交
211 212
}

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
/*
 * FSM value for Defect 7374 (U1U2 Test) is managed in
 * chip's SCRATCH register:
 */
#define DEFECT7374_FSM_FIELD    28

/* Waiting for Control Read:
 *  - A transition to this state indicates a fresh USB connection,
 *    before the first Setup Packet. The connection speed is not
 *    known. Firmware is waiting for the first Control Read.
 *  - Starting state: This state can be thought of as the FSM's typical
 *    starting state.
 *  - Tip: Upon the first SS Control Read the FSM never
 *    returns to this state.
 */
228
#define DEFECT7374_FSM_WAITING_FOR_CONTROL_READ BIT(DEFECT7374_FSM_FIELD)
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

/* Non-SS Control Read:
 *  - A transition to this state indicates detection of the first HS
 *    or FS Control Read.
 *  - Tip: Upon the first SS Control Read the FSM never
 *    returns to this state.
 */
#define	DEFECT7374_FSM_NON_SS_CONTROL_READ (2 << DEFECT7374_FSM_FIELD)

/* SS Control Read:
 *  - A transition to this state indicates detection of the
 *    first SS Control Read.
 *  - This state indicates workaround completion. Workarounds no longer
 *    need to be applied (as long as the chip remains powered up).
 *  - Tip: Once in this state the FSM state does not change (until
 *    the chip's power is lost and restored).
 *  - This can be thought of as the final state of the FSM;
 *    the FSM 'locks-up' in this state until the chip loses power.
 */
#define DEFECT7374_FSM_SS_CONTROL_READ (3 << DEFECT7374_FSM_FIELD)

L
Linus Torvalds 已提交
250 251
#ifdef USE_RDK_LEDS

252
static inline void net2280_led_init(struct net2280 *dev)
L
Linus Torvalds 已提交
253 254
{
	/* LED3 (green) is on during USB activity. note erratum 0113. */
255 256 257 258 259 260
	writel(BIT(GPIO3_LED_SELECT) |
		BIT(GPIO3_OUTPUT_ENABLE) |
		BIT(GPIO2_OUTPUT_ENABLE) |
		BIT(GPIO1_OUTPUT_ENABLE) |
		BIT(GPIO0_OUTPUT_ENABLE),
		&dev->regs->gpioctl);
L
Linus Torvalds 已提交
261 262 263 264
}

/* indicate speed with bi-color LED 0/1 */
static inline
265
void net2280_led_speed(struct net2280 *dev, enum usb_device_speed speed)
L
Linus Torvalds 已提交
266
{
267
	u32	val = readl(&dev->regs->gpioctl);
L
Linus Torvalds 已提交
268
	switch (speed) {
269
	case USB_SPEED_SUPER:		/* green + red */
270
		val |= BIT(GPIO0_DATA) | BIT(GPIO1_DATA);
271
		break;
L
Linus Torvalds 已提交
272
	case USB_SPEED_HIGH:		/* green */
273 274
		val &= ~BIT(GPIO0_DATA);
		val |= BIT(GPIO1_DATA);
L
Linus Torvalds 已提交
275 276
		break;
	case USB_SPEED_FULL:		/* red */
277 278
		val &= ~BIT(GPIO1_DATA);
		val |= BIT(GPIO0_DATA);
L
Linus Torvalds 已提交
279 280
		break;
	default:			/* (off/black) */
281
		val &= ~(BIT(GPIO1_DATA) | BIT(GPIO0_DATA));
L
Linus Torvalds 已提交
282 283
		break;
	}
284
	writel(val, &dev->regs->gpioctl);
L
Linus Torvalds 已提交
285 286 287
}

/* indicate power with LED 2 */
288
static inline void net2280_led_active(struct net2280 *dev, int is_active)
L
Linus Torvalds 已提交
289
{
290
	u32	val = readl(&dev->regs->gpioctl);
L
Linus Torvalds 已提交
291

292
	/* FIXME this LED never seems to turn on.*/
L
Linus Torvalds 已提交
293 294 295 296
	if (is_active)
		val |= GPIO2_DATA;
	else
		val &= ~GPIO2_DATA;
297
	writel(val, &dev->regs->gpioctl);
L
Linus Torvalds 已提交
298
}
299 300

static inline void net2280_led_shutdown(struct net2280 *dev)
L
Linus Torvalds 已提交
301 302
{
	/* turn off all four GPIO*_DATA bits */
303
	writel(readl(&dev->regs->gpioctl) & ~0x0f,
L
Linus Torvalds 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316
			&dev->regs->gpioctl);
}

#else

#define net2280_led_init(dev)		do { } while (0)
#define net2280_led_speed(dev, speed)	do { } while (0)
#define net2280_led_shutdown(dev)	do { } while (0)

#endif

/*-------------------------------------------------------------------------*/

317 318 319
#define xprintk(dev, level, fmt, args...) \
	printk(level "%s %s: " fmt, driver_name, \
			pci_name(dev->pdev), ## args)
L
Linus Torvalds 已提交
320 321 322

#ifdef DEBUG
#undef DEBUG
323 324
#define DEBUG(dev, fmt, args...) \
	xprintk(dev, KERN_DEBUG, fmt, ## args)
L
Linus Torvalds 已提交
325
#else
326
#define DEBUG(dev, fmt, args...) \
L
Linus Torvalds 已提交
327
	do { } while (0)
328
#endif /* DEBUG*/
L
Linus Torvalds 已提交
329 330 331 332

#ifdef VERBOSE
#define VDEBUG DEBUG
#else
333
#define VDEBUG(dev, fmt, args...) \
L
Linus Torvalds 已提交
334 335 336
	do { } while (0)
#endif	/* VERBOSE */

337 338 339 340 341 342
#define ERROR(dev, fmt, args...) \
	xprintk(dev, KERN_ERR, fmt, ## args)
#define WARNING(dev, fmt, args...) \
	xprintk(dev, KERN_WARNING, fmt, ## args)
#define INFO(dev, fmt, args...) \
	xprintk(dev, KERN_INFO, fmt, ## args)
L
Linus Torvalds 已提交
343 344 345

/*-------------------------------------------------------------------------*/

346 347 348 349 350 351 352 353 354 355 356
static inline void set_fifo_bytecount(struct net2280_ep *ep, unsigned count)
{
	if (ep->dev->pdev->vendor == 0x17cc)
		writeb(count, 2 + (u8 __iomem *) &ep->regs->ep_cfg);
	else{
		u32 tmp = readl(&ep->cfg->ep_cfg) &
					(~(0x07 << EP_FIFO_BYTE_COUNT));
		writel(tmp | (count << EP_FIFO_BYTE_COUNT), &ep->cfg->ep_cfg);
	}
}

357
static inline void start_out_naking(struct net2280_ep *ep)
L
Linus Torvalds 已提交
358 359
{
	/* NOTE:  hardware races lurk here, and PING protocol issues */
360
	writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
L
Linus Torvalds 已提交
361
	/* synch with device */
362
	readl(&ep->regs->ep_rsp);
L
Linus Torvalds 已提交
363 364 365
}

#ifdef DEBUG
366
static inline void assert_out_naking(struct net2280_ep *ep, const char *where)
L
Linus Torvalds 已提交
367
{
368
	u32	tmp = readl(&ep->regs->ep_stat);
L
Linus Torvalds 已提交
369

370
	if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
371
		DEBUG(ep->dev, "%s %s %08x !NAK\n",
L
Linus Torvalds 已提交
372
				ep->ep.name, where, tmp);
373
		writel(BIT(SET_NAK_OUT_PACKETS),
L
Linus Torvalds 已提交
374 375 376
			&ep->regs->ep_rsp);
	}
}
377
#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
L
Linus Torvalds 已提交
378 379 380 381
#else
#define ASSERT_OUT_NAKING(ep) do {} while (0)
#endif

382
static inline void stop_out_naking(struct net2280_ep *ep)
L
Linus Torvalds 已提交
383 384 385
{
	u32	tmp;

386
	tmp = readl(&ep->regs->ep_stat);
387 388
	if ((tmp & BIT(NAK_OUT_PACKETS)) != 0)
		writel(BIT(CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
L
Linus Torvalds 已提交
389 390
}

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408

static inline void set_max_speed(struct net2280_ep *ep, u32 max)
{
	u32 reg;
	static const u32 ep_enhanced[9] = { 0x10, 0x60, 0x30, 0x80,
					  0x50, 0x20, 0x70, 0x40, 0x90 };

	if (ep->dev->enhanced_mode)
		reg = ep_enhanced[ep->num];
	else{
		reg = (ep->num + 1) * 0x10;
		if (ep->dev->gadget.speed != USB_SPEED_HIGH)
			reg += 1;
	}

	set_idx_reg(ep->dev->regs, reg, max);
}

L
Linus Torvalds 已提交
409
#endif	/* __KERNEL__ */