| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 1 | /* | 
 | 2 |  * Standalone EHCI usb debug driver | 
 | 3 |  * | 
 | 4 |  * Originally written by: | 
 | 5 |  *  Eric W. Biederman" <ebiederm@xmission.com> and | 
 | 6 |  *  Yinghai Lu <yhlu.kernel@gmail.com> | 
 | 7 |  * | 
 | 8 |  * Changes for early/late printk and HW errata: | 
 | 9 |  *  Jason Wessel <jason.wessel@windriver.com> | 
 | 10 |  *  Copyright (C) 2009 Wind River Systems, Inc. | 
 | 11 |  * | 
 | 12 |  */ | 
 | 13 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 14 | #include <linux/console.h> | 
 | 15 | #include <linux/errno.h> | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 16 | #include <linux/module.h> | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 17 | #include <linux/pci_regs.h> | 
 | 18 | #include <linux/pci_ids.h> | 
 | 19 | #include <linux/usb/ch9.h> | 
 | 20 | #include <linux/usb/ehci_def.h> | 
 | 21 | #include <linux/delay.h> | 
 | 22 | #include <asm/io.h> | 
 | 23 | #include <asm/pci-direct.h> | 
 | 24 | #include <asm/fixmap.h> | 
 | 25 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 26 | /* The code here is intended to talk directly to the EHCI debug port | 
 | 27 |  * and does not require that you have any kind of USB host controller | 
 | 28 |  * drivers or USB device drivers compiled into the kernel. | 
 | 29 |  * | 
 | 30 |  * If you make a change to anything in here, the following test cases | 
 | 31 |  * need to pass where a USB debug device works in the following | 
 | 32 |  * configurations. | 
 | 33 |  * | 
 | 34 |  * 1. boot args:  earlyprintk=dbgp | 
 | 35 |  *     o kernel compiled with # CONFIG_USB_EHCI_HCD is not set | 
 | 36 |  *     o kernel compiled with CONFIG_USB_EHCI_HCD=y | 
 | 37 |  * 2. boot args: earlyprintk=dbgp,keep | 
 | 38 |  *     o kernel compiled with # CONFIG_USB_EHCI_HCD is not set | 
 | 39 |  *     o kernel compiled with CONFIG_USB_EHCI_HCD=y | 
 | 40 |  * 3. boot args: earlyprintk=dbgp console=ttyUSB0 | 
 | 41 |  *     o kernel has CONFIG_USB_EHCI_HCD=y and | 
 | 42 |  *       CONFIG_USB_SERIAL_DEBUG=y | 
 | 43 |  * 4. boot args: earlyprintk=vga,dbgp | 
 | 44 |  *     o kernel compiled with # CONFIG_USB_EHCI_HCD is not set | 
 | 45 |  *     o kernel compiled with CONFIG_USB_EHCI_HCD=y | 
 | 46 |  * | 
 | 47 |  * For the 4th configuration you can turn on or off the DBGP_DEBUG | 
 | 48 |  * such that you can debug the dbgp device's driver code. | 
 | 49 |  */ | 
 | 50 |  | 
 | 51 | static int dbgp_phys_port = 1; | 
| Jason Wessel | 56faf0f | 2009-08-20 15:39:51 -0500 | [diff] [blame] | 52 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 53 | static struct ehci_caps __iomem *ehci_caps; | 
 | 54 | static struct ehci_regs __iomem *ehci_regs; | 
 | 55 | static struct ehci_dbg_port __iomem *ehci_debug; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 56 | static int dbgp_not_safe; /* Cannot use debug device during ehci reset */ | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 57 | static unsigned int dbgp_endpoint_out; | 
 | 58 |  | 
 | 59 | struct ehci_dev { | 
 | 60 | 	u32 bus; | 
 | 61 | 	u32 slot; | 
 | 62 | 	u32 func; | 
 | 63 | }; | 
 | 64 |  | 
 | 65 | static struct ehci_dev ehci_dev; | 
 | 66 |  | 
 | 67 | #define USB_DEBUG_DEVNUM 127 | 
 | 68 |  | 
 | 69 | #define DBGP_DATA_TOGGLE	0x8800 | 
 | 70 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 71 | #ifdef DBGP_DEBUG | 
 | 72 | #define dbgp_printk printk | 
 | 73 | static void dbgp_ehci_status(char *str) | 
 | 74 | { | 
 | 75 | 	if (!ehci_debug) | 
 | 76 | 		return; | 
 | 77 | 	dbgp_printk("dbgp: %s\n", str); | 
 | 78 | 	dbgp_printk("  Debug control: %08x", readl(&ehci_debug->control)); | 
 | 79 | 	dbgp_printk("  ehci cmd     : %08x", readl(&ehci_regs->command)); | 
 | 80 | 	dbgp_printk("  ehci conf flg: %08x\n", | 
 | 81 | 		    readl(&ehci_regs->configured_flag)); | 
 | 82 | 	dbgp_printk("  ehci status  : %08x", readl(&ehci_regs->status)); | 
 | 83 | 	dbgp_printk("  ehci portsc  : %08x\n", | 
 | 84 | 		    readl(&ehci_regs->port_status[dbgp_phys_port - 1])); | 
 | 85 | } | 
 | 86 | #else | 
 | 87 | static inline void dbgp_ehci_status(char *str) { } | 
 | 88 | static inline void dbgp_printk(const char *fmt, ...) { } | 
 | 89 | #endif | 
 | 90 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 91 | static inline u32 dbgp_pid_update(u32 x, u32 tok) | 
 | 92 | { | 
 | 93 | 	return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff); | 
 | 94 | } | 
 | 95 |  | 
 | 96 | static inline u32 dbgp_len_update(u32 x, u32 len) | 
 | 97 | { | 
 | 98 | 	return (x & ~0x0f) | (len & 0x0f); | 
 | 99 | } | 
 | 100 |  | 
 | 101 | /* | 
 | 102 |  * USB Packet IDs (PIDs) | 
 | 103 |  */ | 
 | 104 |  | 
 | 105 | /* token */ | 
 | 106 | #define USB_PID_OUT		0xe1 | 
 | 107 | #define USB_PID_IN		0x69 | 
 | 108 | #define USB_PID_SOF		0xa5 | 
 | 109 | #define USB_PID_SETUP		0x2d | 
 | 110 | /* handshake */ | 
 | 111 | #define USB_PID_ACK		0xd2 | 
 | 112 | #define USB_PID_NAK		0x5a | 
 | 113 | #define USB_PID_STALL		0x1e | 
 | 114 | #define USB_PID_NYET		0x96 | 
 | 115 | /* data */ | 
 | 116 | #define USB_PID_DATA0		0xc3 | 
 | 117 | #define USB_PID_DATA1		0x4b | 
 | 118 | #define USB_PID_DATA2		0x87 | 
 | 119 | #define USB_PID_MDATA		0x0f | 
 | 120 | /* Special */ | 
 | 121 | #define USB_PID_PREAMBLE	0x3c | 
 | 122 | #define USB_PID_ERR		0x3c | 
 | 123 | #define USB_PID_SPLIT		0x78 | 
 | 124 | #define USB_PID_PING		0xb4 | 
 | 125 | #define USB_PID_UNDEF_0		0xf0 | 
 | 126 |  | 
 | 127 | #define USB_PID_DATA_TOGGLE	0x88 | 
 | 128 | #define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE) | 
 | 129 |  | 
 | 130 | #define PCI_CAP_ID_EHCI_DEBUG	0xa | 
 | 131 |  | 
 | 132 | #define HUB_ROOT_RESET_TIME	50	/* times are in msec */ | 
 | 133 | #define HUB_SHORT_RESET_TIME	10 | 
 | 134 | #define HUB_LONG_RESET_TIME	200 | 
 | 135 | #define HUB_RESET_TIMEOUT	500 | 
 | 136 |  | 
 | 137 | #define DBGP_MAX_PACKET		8 | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 138 | #define DBGP_TIMEOUT		(250 * 1000) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 139 |  | 
 | 140 | static int dbgp_wait_until_complete(void) | 
 | 141 | { | 
 | 142 | 	u32 ctrl; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 143 | 	int loop = DBGP_TIMEOUT; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 144 |  | 
 | 145 | 	do { | 
 | 146 | 		ctrl = readl(&ehci_debug->control); | 
 | 147 | 		/* Stop when the transaction is finished */ | 
 | 148 | 		if (ctrl & DBGP_DONE) | 
 | 149 | 			break; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 150 | 		udelay(1); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 151 | 	} while (--loop > 0); | 
 | 152 |  | 
 | 153 | 	if (!loop) | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 154 | 		return -DBGP_TIMEOUT; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 155 |  | 
 | 156 | 	/* | 
 | 157 | 	 * Now that we have observed the completed transaction, | 
 | 158 | 	 * clear the done bit. | 
 | 159 | 	 */ | 
 | 160 | 	writel(ctrl | DBGP_DONE, &ehci_debug->control); | 
 | 161 | 	return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl); | 
 | 162 | } | 
 | 163 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 164 | static inline void dbgp_mdelay(int ms) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 165 | { | 
 | 166 | 	int i; | 
 | 167 |  | 
 | 168 | 	while (ms--) { | 
 | 169 | 		for (i = 0; i < 1000; i++) | 
 | 170 | 			outb(0x1, 0x80); | 
 | 171 | 	} | 
 | 172 | } | 
 | 173 |  | 
 | 174 | static void dbgp_breath(void) | 
 | 175 | { | 
 | 176 | 	/* Sleep to give the debug port a chance to breathe */ | 
 | 177 | } | 
 | 178 |  | 
 | 179 | static int dbgp_wait_until_done(unsigned ctrl) | 
 | 180 | { | 
 | 181 | 	u32 pids, lpid; | 
 | 182 | 	int ret; | 
 | 183 | 	int loop = 3; | 
 | 184 |  | 
 | 185 | retry: | 
 | 186 | 	writel(ctrl | DBGP_GO, &ehci_debug->control); | 
 | 187 | 	ret = dbgp_wait_until_complete(); | 
 | 188 | 	pids = readl(&ehci_debug->pids); | 
 | 189 | 	lpid = DBGP_PID_GET(pids); | 
 | 190 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 191 | 	if (ret < 0) { | 
 | 192 | 		/* A -DBGP_TIMEOUT failure here means the device has | 
 | 193 | 		 * failed, perhaps because it was unplugged, in which | 
 | 194 | 		 * case we do not want to hang the system so the dbgp | 
 | 195 | 		 * will be marked as unsafe to use.  EHCI reset is the | 
 | 196 | 		 * only way to recover if you unplug the dbgp device. | 
 | 197 | 		 */ | 
 | 198 | 		if (ret == -DBGP_TIMEOUT && !dbgp_not_safe) | 
 | 199 | 			dbgp_not_safe = 1; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 200 | 		return ret; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 201 | 	} | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 202 |  | 
 | 203 | 	/* | 
 | 204 | 	 * If the port is getting full or it has dropped data | 
 | 205 | 	 * start pacing ourselves, not necessary but it's friendly. | 
 | 206 | 	 */ | 
 | 207 | 	if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET)) | 
 | 208 | 		dbgp_breath(); | 
 | 209 |  | 
 | 210 | 	/* If I get a NACK reissue the transmission */ | 
 | 211 | 	if (lpid == USB_PID_NAK) { | 
 | 212 | 		if (--loop > 0) | 
 | 213 | 			goto retry; | 
 | 214 | 	} | 
 | 215 |  | 
 | 216 | 	return ret; | 
 | 217 | } | 
 | 218 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 219 | static inline void dbgp_set_data(const void *buf, int size) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 220 | { | 
 | 221 | 	const unsigned char *bytes = buf; | 
 | 222 | 	u32 lo, hi; | 
 | 223 | 	int i; | 
 | 224 |  | 
 | 225 | 	lo = hi = 0; | 
 | 226 | 	for (i = 0; i < 4 && i < size; i++) | 
 | 227 | 		lo |= bytes[i] << (8*i); | 
 | 228 | 	for (; i < 8 && i < size; i++) | 
 | 229 | 		hi |= bytes[i] << (8*(i - 4)); | 
 | 230 | 	writel(lo, &ehci_debug->data03); | 
 | 231 | 	writel(hi, &ehci_debug->data47); | 
 | 232 | } | 
 | 233 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 234 | static inline void dbgp_get_data(void *buf, int size) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 235 | { | 
 | 236 | 	unsigned char *bytes = buf; | 
 | 237 | 	u32 lo, hi; | 
 | 238 | 	int i; | 
 | 239 |  | 
 | 240 | 	lo = readl(&ehci_debug->data03); | 
 | 241 | 	hi = readl(&ehci_debug->data47); | 
 | 242 | 	for (i = 0; i < 4 && i < size; i++) | 
 | 243 | 		bytes[i] = (lo >> (8*i)) & 0xff; | 
 | 244 | 	for (; i < 8 && i < size; i++) | 
 | 245 | 		bytes[i] = (hi >> (8*(i - 4))) & 0xff; | 
 | 246 | } | 
 | 247 |  | 
| Jason Wessel | 68d2956 | 2009-08-20 15:39:56 -0500 | [diff] [blame] | 248 | static int dbgp_out(u32 addr, const char *bytes, int size) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 249 | { | 
| Jason Wessel | 68d2956 | 2009-08-20 15:39:56 -0500 | [diff] [blame] | 250 | 	u32 pids, ctrl; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 251 |  | 
 | 252 | 	pids = readl(&ehci_debug->pids); | 
 | 253 | 	pids = dbgp_pid_update(pids, USB_PID_OUT); | 
 | 254 |  | 
 | 255 | 	ctrl = readl(&ehci_debug->control); | 
 | 256 | 	ctrl = dbgp_len_update(ctrl, size); | 
 | 257 | 	ctrl |= DBGP_OUT; | 
 | 258 | 	ctrl |= DBGP_GO; | 
 | 259 |  | 
 | 260 | 	dbgp_set_data(bytes, size); | 
 | 261 | 	writel(addr, &ehci_debug->address); | 
 | 262 | 	writel(pids, &ehci_debug->pids); | 
| Jason Wessel | 68d2956 | 2009-08-20 15:39:56 -0500 | [diff] [blame] | 263 | 	return dbgp_wait_until_done(ctrl); | 
 | 264 | } | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 265 |  | 
| Jason Wessel | 68d2956 | 2009-08-20 15:39:56 -0500 | [diff] [blame] | 266 | static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, | 
 | 267 | 			 const char *bytes, int size) | 
 | 268 | { | 
 | 269 | 	int ret; | 
 | 270 | 	int loops = 5; | 
 | 271 | 	u32 addr; | 
 | 272 | 	if (size > DBGP_MAX_PACKET) | 
 | 273 | 		return -1; | 
 | 274 |  | 
 | 275 | 	addr = DBGP_EPADDR(devnum, endpoint); | 
 | 276 | try_again: | 
 | 277 | 	if (loops--) { | 
 | 278 | 		ret = dbgp_out(addr, bytes, size); | 
 | 279 | 		if (ret == -DBGP_ERR_BAD) { | 
 | 280 | 			int try_loops = 3; | 
 | 281 | 			do { | 
 | 282 | 				/* Emit a dummy packet to re-sync communication | 
 | 283 | 				 * with the debug device */ | 
 | 284 | 				if (dbgp_out(addr, "12345678", 8) >= 0) { | 
 | 285 | 					udelay(2); | 
 | 286 | 					goto try_again; | 
 | 287 | 				} | 
 | 288 | 			} while (try_loops--); | 
 | 289 | 		} | 
 | 290 | 	} | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 291 |  | 
 | 292 | 	return ret; | 
 | 293 | } | 
 | 294 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 295 | static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 296 | 				 int size) | 
 | 297 | { | 
 | 298 | 	u32 pids, addr, ctrl; | 
 | 299 | 	int ret; | 
 | 300 |  | 
 | 301 | 	if (size > DBGP_MAX_PACKET) | 
 | 302 | 		return -1; | 
 | 303 |  | 
 | 304 | 	addr = DBGP_EPADDR(devnum, endpoint); | 
 | 305 |  | 
 | 306 | 	pids = readl(&ehci_debug->pids); | 
 | 307 | 	pids = dbgp_pid_update(pids, USB_PID_IN); | 
 | 308 |  | 
 | 309 | 	ctrl = readl(&ehci_debug->control); | 
 | 310 | 	ctrl = dbgp_len_update(ctrl, size); | 
 | 311 | 	ctrl &= ~DBGP_OUT; | 
 | 312 | 	ctrl |= DBGP_GO; | 
 | 313 |  | 
 | 314 | 	writel(addr, &ehci_debug->address); | 
 | 315 | 	writel(pids, &ehci_debug->pids); | 
 | 316 | 	ret = dbgp_wait_until_done(ctrl); | 
 | 317 | 	if (ret < 0) | 
 | 318 | 		return ret; | 
 | 319 |  | 
 | 320 | 	if (size > ret) | 
 | 321 | 		size = ret; | 
 | 322 | 	dbgp_get_data(data, size); | 
 | 323 | 	return ret; | 
 | 324 | } | 
 | 325 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 326 | static int dbgp_control_msg(unsigned devnum, int requesttype, | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 327 | 	int request, int value, int index, void *data, int size) | 
 | 328 | { | 
 | 329 | 	u32 pids, addr, ctrl; | 
 | 330 | 	struct usb_ctrlrequest req; | 
 | 331 | 	int read; | 
 | 332 | 	int ret; | 
 | 333 |  | 
 | 334 | 	read = (requesttype & USB_DIR_IN) != 0; | 
 | 335 | 	if (size > (read ? DBGP_MAX_PACKET:0)) | 
 | 336 | 		return -1; | 
 | 337 |  | 
 | 338 | 	/* Compute the control message */ | 
 | 339 | 	req.bRequestType = requesttype; | 
 | 340 | 	req.bRequest = request; | 
 | 341 | 	req.wValue = cpu_to_le16(value); | 
 | 342 | 	req.wIndex = cpu_to_le16(index); | 
 | 343 | 	req.wLength = cpu_to_le16(size); | 
 | 344 |  | 
 | 345 | 	pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP); | 
 | 346 | 	addr = DBGP_EPADDR(devnum, 0); | 
 | 347 |  | 
 | 348 | 	ctrl = readl(&ehci_debug->control); | 
 | 349 | 	ctrl = dbgp_len_update(ctrl, sizeof(req)); | 
 | 350 | 	ctrl |= DBGP_OUT; | 
 | 351 | 	ctrl |= DBGP_GO; | 
 | 352 |  | 
 | 353 | 	/* Send the setup message */ | 
 | 354 | 	dbgp_set_data(&req, sizeof(req)); | 
 | 355 | 	writel(addr, &ehci_debug->address); | 
 | 356 | 	writel(pids, &ehci_debug->pids); | 
 | 357 | 	ret = dbgp_wait_until_done(ctrl); | 
 | 358 | 	if (ret < 0) | 
 | 359 | 		return ret; | 
 | 360 |  | 
 | 361 | 	/* Read the result */ | 
 | 362 | 	return dbgp_bulk_read(devnum, 0, data, size); | 
 | 363 | } | 
 | 364 |  | 
 | 365 |  | 
 | 366 | /* Find a PCI capability */ | 
 | 367 | static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap) | 
 | 368 | { | 
 | 369 | 	u8 pos; | 
 | 370 | 	int bytes; | 
 | 371 |  | 
 | 372 | 	if (!(read_pci_config_16(num, slot, func, PCI_STATUS) & | 
 | 373 | 		PCI_STATUS_CAP_LIST)) | 
 | 374 | 		return 0; | 
 | 375 |  | 
 | 376 | 	pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST); | 
 | 377 | 	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { | 
 | 378 | 		u8 id; | 
 | 379 |  | 
 | 380 | 		pos &= ~3; | 
 | 381 | 		id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID); | 
 | 382 | 		if (id == 0xff) | 
 | 383 | 			break; | 
 | 384 | 		if (id == cap) | 
 | 385 | 			return pos; | 
 | 386 |  | 
 | 387 | 		pos = read_pci_config_byte(num, slot, func, | 
 | 388 | 						 pos+PCI_CAP_LIST_NEXT); | 
 | 389 | 	} | 
 | 390 | 	return 0; | 
 | 391 | } | 
 | 392 |  | 
 | 393 | static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func) | 
 | 394 | { | 
 | 395 | 	u32 class; | 
 | 396 |  | 
 | 397 | 	class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION); | 
 | 398 | 	if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI) | 
 | 399 | 		return 0; | 
 | 400 |  | 
 | 401 | 	return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG); | 
 | 402 | } | 
 | 403 |  | 
 | 404 | static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc) | 
 | 405 | { | 
 | 406 | 	u32 bus, slot, func; | 
 | 407 |  | 
 | 408 | 	for (bus = 0; bus < 256; bus++) { | 
 | 409 | 		for (slot = 0; slot < 32; slot++) { | 
 | 410 | 			for (func = 0; func < 8; func++) { | 
 | 411 | 				unsigned cap; | 
 | 412 |  | 
 | 413 | 				cap = __find_dbgp(bus, slot, func); | 
 | 414 |  | 
 | 415 | 				if (!cap) | 
 | 416 | 					continue; | 
 | 417 | 				if (ehci_num-- != 0) | 
 | 418 | 					continue; | 
 | 419 | 				*rbus = bus; | 
 | 420 | 				*rslot = slot; | 
 | 421 | 				*rfunc = func; | 
 | 422 | 				return cap; | 
 | 423 | 			} | 
 | 424 | 		} | 
 | 425 | 	} | 
 | 426 | 	return 0; | 
 | 427 | } | 
 | 428 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 429 | static int dbgp_ehci_startup(void) | 
 | 430 | { | 
 | 431 | 	u32 ctrl, cmd, status; | 
 | 432 | 	int loop; | 
 | 433 |  | 
 | 434 | 	/* Claim ownership, but do not enable yet */ | 
 | 435 | 	ctrl = readl(&ehci_debug->control); | 
 | 436 | 	ctrl |= DBGP_OWNER; | 
 | 437 | 	ctrl &= ~(DBGP_ENABLED | DBGP_INUSE); | 
 | 438 | 	writel(ctrl, &ehci_debug->control); | 
 | 439 | 	udelay(1); | 
 | 440 |  | 
 | 441 | 	dbgp_ehci_status("EHCI startup"); | 
 | 442 | 	/* Start the ehci running */ | 
 | 443 | 	cmd = readl(&ehci_regs->command); | 
 | 444 | 	cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET); | 
 | 445 | 	cmd |= CMD_RUN; | 
 | 446 | 	writel(cmd, &ehci_regs->command); | 
 | 447 |  | 
 | 448 | 	/* Ensure everything is routed to the EHCI */ | 
 | 449 | 	writel(FLAG_CF, &ehci_regs->configured_flag); | 
 | 450 |  | 
 | 451 | 	/* Wait until the controller is no longer halted */ | 
 | 452 | 	loop = 10; | 
 | 453 | 	do { | 
 | 454 | 		status = readl(&ehci_regs->status); | 
 | 455 | 		if (!(status & STS_HALT)) | 
 | 456 | 			break; | 
 | 457 | 		udelay(1); | 
 | 458 | 	} while (--loop > 0); | 
 | 459 |  | 
 | 460 | 	if (!loop) { | 
 | 461 | 		dbgp_printk("ehci can not be started\n"); | 
 | 462 | 		return -ENODEV; | 
 | 463 | 	} | 
 | 464 | 	dbgp_printk("ehci started\n"); | 
 | 465 | 	return 0; | 
 | 466 | } | 
 | 467 |  | 
 | 468 | static int dbgp_ehci_controller_reset(void) | 
 | 469 | { | 
 | 470 | 	int loop = 250 * 1000; | 
 | 471 | 	u32 cmd; | 
 | 472 |  | 
 | 473 | 	/* Reset the EHCI controller */ | 
 | 474 | 	cmd = readl(&ehci_regs->command); | 
 | 475 | 	cmd |= CMD_RESET; | 
 | 476 | 	writel(cmd, &ehci_regs->command); | 
 | 477 | 	do { | 
 | 478 | 		cmd = readl(&ehci_regs->command); | 
 | 479 | 	} while ((cmd & CMD_RESET) && (--loop > 0)); | 
 | 480 |  | 
 | 481 | 	if (!loop) { | 
 | 482 | 		dbgp_printk("can not reset ehci\n"); | 
 | 483 | 		return -1; | 
 | 484 | 	} | 
 | 485 | 	dbgp_ehci_status("ehci reset done"); | 
 | 486 | 	return 0; | 
 | 487 | } | 
 | 488 | static int ehci_wait_for_port(int port); | 
 | 489 | /* Return 0 on success | 
 | 490 |  * Return -ENODEV for any general failure | 
 | 491 |  * Return -EIO if wait for port fails | 
 | 492 |  */ | 
 | 493 | int dbgp_external_startup(void) | 
 | 494 | { | 
 | 495 | 	int devnum; | 
 | 496 | 	struct usb_debug_descriptor dbgp_desc; | 
 | 497 | 	int ret; | 
| Jason Wessel | aab2d40 | 2009-08-20 15:39:55 -0500 | [diff] [blame] | 498 | 	u32 ctrl, portsc, cmd; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 499 | 	int dbg_port = dbgp_phys_port; | 
 | 500 | 	int tries = 3; | 
| Jason Wessel | aab2d40 | 2009-08-20 15:39:55 -0500 | [diff] [blame] | 501 | 	int reset_port_tries = 1; | 
 | 502 | 	int try_hard_once = 1; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 503 |  | 
| Jason Wessel | aab2d40 | 2009-08-20 15:39:55 -0500 | [diff] [blame] | 504 | try_port_reset_again: | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 505 | 	ret = dbgp_ehci_startup(); | 
 | 506 | 	if (ret) | 
 | 507 | 		return ret; | 
 | 508 |  | 
 | 509 | 	/* Wait for a device to show up in the debug port */ | 
 | 510 | 	ret = ehci_wait_for_port(dbg_port); | 
 | 511 | 	if (ret < 0) { | 
 | 512 | 		portsc = readl(&ehci_regs->port_status[dbg_port - 1]); | 
| Jason Wessel | aab2d40 | 2009-08-20 15:39:55 -0500 | [diff] [blame] | 513 | 		if (!(portsc & PORT_CONNECT) && try_hard_once) { | 
 | 514 | 			/* Last ditch effort to try to force enable | 
 | 515 | 			 * the debug device by using the packet test | 
 | 516 | 			 * ehci command to try and wake it up. */ | 
 | 517 | 			try_hard_once = 0; | 
 | 518 | 			cmd = readl(&ehci_regs->command); | 
 | 519 | 			cmd &= ~CMD_RUN; | 
 | 520 | 			writel(cmd, &ehci_regs->command); | 
 | 521 | 			portsc = readl(&ehci_regs->port_status[dbg_port - 1]); | 
 | 522 | 			portsc |= PORT_TEST_PKT; | 
 | 523 | 			writel(portsc, &ehci_regs->port_status[dbg_port - 1]); | 
 | 524 | 			dbgp_ehci_status("Trying to force debug port online"); | 
 | 525 | 			mdelay(50); | 
 | 526 | 			dbgp_ehci_controller_reset(); | 
 | 527 | 			goto try_port_reset_again; | 
 | 528 | 		} else if (reset_port_tries--) { | 
 | 529 | 			goto try_port_reset_again; | 
 | 530 | 		} | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 531 | 		dbgp_printk("No device found in debug port\n"); | 
 | 532 | 		return -EIO; | 
 | 533 | 	} | 
 | 534 | 	dbgp_ehci_status("wait for port done"); | 
 | 535 |  | 
 | 536 | 	/* Enable the debug port */ | 
 | 537 | 	ctrl = readl(&ehci_debug->control); | 
 | 538 | 	ctrl |= DBGP_CLAIM; | 
 | 539 | 	writel(ctrl, &ehci_debug->control); | 
 | 540 | 	ctrl = readl(&ehci_debug->control); | 
 | 541 | 	if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) { | 
 | 542 | 		dbgp_printk("No device in debug port\n"); | 
 | 543 | 		writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control); | 
 | 544 | 		return -ENODEV; | 
 | 545 | 	} | 
 | 546 | 	dbgp_ehci_status("debug ported enabled"); | 
 | 547 |  | 
 | 548 | 	/* Completely transfer the debug device to the debug controller */ | 
 | 549 | 	portsc = readl(&ehci_regs->port_status[dbg_port - 1]); | 
 | 550 | 	portsc &= ~PORT_PE; | 
 | 551 | 	writel(portsc, &ehci_regs->port_status[dbg_port - 1]); | 
 | 552 |  | 
 | 553 | 	dbgp_mdelay(100); | 
 | 554 |  | 
 | 555 | try_again: | 
 | 556 | 	/* Find the debug device and make it device number 127 */ | 
 | 557 | 	for (devnum = 0; devnum <= 127; devnum++) { | 
 | 558 | 		ret = dbgp_control_msg(devnum, | 
 | 559 | 			USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | 
 | 560 | 			USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0, | 
 | 561 | 			&dbgp_desc, sizeof(dbgp_desc)); | 
 | 562 | 		if (ret > 0) | 
 | 563 | 			break; | 
 | 564 | 	} | 
 | 565 | 	if (devnum > 127) { | 
 | 566 | 		dbgp_printk("Could not find attached debug device\n"); | 
 | 567 | 		goto err; | 
 | 568 | 	} | 
 | 569 | 	if (ret < 0) { | 
 | 570 | 		dbgp_printk("Attached device is not a debug device\n"); | 
 | 571 | 		goto err; | 
 | 572 | 	} | 
 | 573 | 	dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; | 
 | 574 |  | 
 | 575 | 	/* Move the device to 127 if it isn't already there */ | 
 | 576 | 	if (devnum != USB_DEBUG_DEVNUM) { | 
 | 577 | 		ret = dbgp_control_msg(devnum, | 
 | 578 | 			USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | 
 | 579 | 			USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0); | 
 | 580 | 		if (ret < 0) { | 
 | 581 | 			dbgp_printk("Could not move attached device to %d\n", | 
 | 582 | 				USB_DEBUG_DEVNUM); | 
 | 583 | 			goto err; | 
 | 584 | 		} | 
 | 585 | 		devnum = USB_DEBUG_DEVNUM; | 
 | 586 | 		dbgp_printk("debug device renamed to 127\n"); | 
 | 587 | 	} | 
 | 588 |  | 
 | 589 | 	/* Enable the debug interface */ | 
 | 590 | 	ret = dbgp_control_msg(USB_DEBUG_DEVNUM, | 
 | 591 | 		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | 
 | 592 | 		USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0); | 
 | 593 | 	if (ret < 0) { | 
 | 594 | 		dbgp_printk(" Could not enable the debug device\n"); | 
 | 595 | 		goto err; | 
 | 596 | 	} | 
 | 597 | 	dbgp_printk("debug interface enabled\n"); | 
 | 598 | 	/* Perform a small write to get the even/odd data state in sync | 
 | 599 | 	 */ | 
 | 600 | 	ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1); | 
 | 601 | 	if (ret < 0) { | 
 | 602 | 		dbgp_printk("dbgp_bulk_write failed: %d\n", ret); | 
 | 603 | 		goto err; | 
 | 604 | 	} | 
 | 605 | 	dbgp_printk("small write doned\n"); | 
 | 606 | 	dbgp_not_safe = 0; | 
 | 607 |  | 
 | 608 | 	return 0; | 
 | 609 | err: | 
 | 610 | 	if (tries--) | 
 | 611 | 		goto try_again; | 
 | 612 | 	return -ENODEV; | 
 | 613 | } | 
 | 614 | EXPORT_SYMBOL_GPL(dbgp_external_startup); | 
 | 615 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 616 | static int __init ehci_reset_port(int port) | 
 | 617 | { | 
 | 618 | 	u32 portsc; | 
 | 619 | 	u32 delay_time, delay; | 
 | 620 | 	int loop; | 
 | 621 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 622 | 	dbgp_ehci_status("reset port"); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 623 | 	/* Reset the usb debug port */ | 
 | 624 | 	portsc = readl(&ehci_regs->port_status[port - 1]); | 
 | 625 | 	portsc &= ~PORT_PE; | 
 | 626 | 	portsc |= PORT_RESET; | 
 | 627 | 	writel(portsc, &ehci_regs->port_status[port - 1]); | 
 | 628 |  | 
 | 629 | 	delay = HUB_ROOT_RESET_TIME; | 
 | 630 | 	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; | 
 | 631 | 	     delay_time += delay) { | 
 | 632 | 		dbgp_mdelay(delay); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 633 | 		portsc = readl(&ehci_regs->port_status[port - 1]); | 
| Jason Wessel | 56faf0f | 2009-08-20 15:39:51 -0500 | [diff] [blame] | 634 | 		if (!(portsc & PORT_RESET)) | 
 | 635 | 			break; | 
 | 636 | 	} | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 637 | 		if (portsc & PORT_RESET) { | 
 | 638 | 			/* force reset to complete */ | 
| Jason Wessel | 56faf0f | 2009-08-20 15:39:51 -0500 | [diff] [blame] | 639 | 			loop = 100 * 1000; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 640 | 			writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), | 
 | 641 | 				&ehci_regs->port_status[port - 1]); | 
 | 642 | 			do { | 
| Jason Wessel | 56faf0f | 2009-08-20 15:39:51 -0500 | [diff] [blame] | 643 | 				udelay(1); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 644 | 				portsc = readl(&ehci_regs->port_status[port-1]); | 
 | 645 | 			} while ((portsc & PORT_RESET) && (--loop > 0)); | 
 | 646 | 		} | 
 | 647 |  | 
 | 648 | 		/* Device went away? */ | 
 | 649 | 		if (!(portsc & PORT_CONNECT)) | 
 | 650 | 			return -ENOTCONN; | 
 | 651 |  | 
 | 652 | 		/* bomb out completely if something weird happend */ | 
 | 653 | 		if ((portsc & PORT_CSC)) | 
 | 654 | 			return -EINVAL; | 
 | 655 |  | 
 | 656 | 		/* If we've finished resetting, then break out of the loop */ | 
 | 657 | 		if (!(portsc & PORT_RESET) && (portsc & PORT_PE)) | 
 | 658 | 			return 0; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 659 | 	return -EBUSY; | 
 | 660 | } | 
 | 661 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 662 | static int ehci_wait_for_port(int port) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 663 | { | 
 | 664 | 	u32 status; | 
 | 665 | 	int ret, reps; | 
 | 666 |  | 
| Jason Wessel | 56faf0f | 2009-08-20 15:39:51 -0500 | [diff] [blame] | 667 | 	for (reps = 0; reps < 300; reps++) { | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 668 | 		status = readl(&ehci_regs->status); | 
| Jason Wessel | 56faf0f | 2009-08-20 15:39:51 -0500 | [diff] [blame] | 669 | 		if (status & STS_PCD) | 
 | 670 | 			break; | 
 | 671 | 		dbgp_mdelay(1); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 672 | 	} | 
| Jason Wessel | 56faf0f | 2009-08-20 15:39:51 -0500 | [diff] [blame] | 673 | 	ret = ehci_reset_port(port); | 
 | 674 | 	if (ret == 0) | 
 | 675 | 		return 0; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 676 | 	return -ENOTCONN; | 
 | 677 | } | 
 | 678 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 679 | typedef void (*set_debug_port_t)(int port); | 
 | 680 |  | 
 | 681 | static void __init default_set_debug_port(int port) | 
 | 682 | { | 
 | 683 | } | 
 | 684 |  | 
 | 685 | static set_debug_port_t __initdata set_debug_port = default_set_debug_port; | 
 | 686 |  | 
 | 687 | static void __init nvidia_set_debug_port(int port) | 
 | 688 | { | 
 | 689 | 	u32 dword; | 
 | 690 | 	dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | 
 | 691 | 				 0x74); | 
 | 692 | 	dword &= ~(0x0f<<12); | 
 | 693 | 	dword |= ((port & 0x0f)<<12); | 
 | 694 | 	write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74, | 
 | 695 | 				 dword); | 
 | 696 | 	dbgp_printk("set debug port to %d\n", port); | 
 | 697 | } | 
 | 698 |  | 
 | 699 | static void __init detect_set_debug_port(void) | 
 | 700 | { | 
 | 701 | 	u32 vendorid; | 
 | 702 |  | 
 | 703 | 	vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | 
 | 704 | 		 0x00); | 
 | 705 |  | 
 | 706 | 	if ((vendorid & 0xffff) == 0x10de) { | 
 | 707 | 		dbgp_printk("using nvidia set_debug_port\n"); | 
 | 708 | 		set_debug_port = nvidia_set_debug_port; | 
 | 709 | 	} | 
 | 710 | } | 
 | 711 |  | 
| Jason Wessel | 093344e | 2009-08-20 15:39:50 -0500 | [diff] [blame] | 712 | /* The code in early_ehci_bios_handoff() is derived from the usb pci | 
 | 713 |  * quirk initialization, but altered so as to use the early PCI | 
 | 714 |  * routines. */ | 
 | 715 | #define EHCI_USBLEGSUP_BIOS	(1 << 16)	/* BIOS semaphore */ | 
 | 716 | #define EHCI_USBLEGCTLSTS	4		/* legacy control/status */ | 
 | 717 | static void __init early_ehci_bios_handoff(void) | 
 | 718 | { | 
 | 719 | 	u32 hcc_params = readl(&ehci_caps->hcc_params); | 
 | 720 | 	int offset = (hcc_params >> 8) & 0xff; | 
 | 721 | 	u32 cap; | 
 | 722 | 	int msec; | 
 | 723 |  | 
 | 724 | 	if (!offset) | 
 | 725 | 		return; | 
 | 726 |  | 
 | 727 | 	cap = read_pci_config(ehci_dev.bus, ehci_dev.slot, | 
 | 728 | 			      ehci_dev.func, offset); | 
 | 729 | 	dbgp_printk("dbgp: ehci BIOS state %08x\n", cap); | 
 | 730 |  | 
 | 731 | 	if ((cap & 0xff) == 1 && (cap & EHCI_USBLEGSUP_BIOS)) { | 
 | 732 | 		dbgp_printk("dbgp: BIOS handoff\n"); | 
 | 733 | 		write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, | 
 | 734 | 				      ehci_dev.func, offset + 3, 1); | 
 | 735 | 	} | 
 | 736 |  | 
 | 737 | 	/* if boot firmware now owns EHCI, spin till it hands it over. */ | 
 | 738 | 	msec = 1000; | 
 | 739 | 	while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) { | 
 | 740 | 		mdelay(10); | 
 | 741 | 		msec -= 10; | 
 | 742 | 		cap = read_pci_config(ehci_dev.bus, ehci_dev.slot, | 
 | 743 | 				      ehci_dev.func, offset); | 
 | 744 | 	} | 
 | 745 |  | 
 | 746 | 	if (cap & EHCI_USBLEGSUP_BIOS) { | 
 | 747 | 		/* well, possibly buggy BIOS... try to shut it down, | 
 | 748 | 		 * and hope nothing goes too wrong */ | 
 | 749 | 		dbgp_printk("dbgp: BIOS handoff failed: %08x\n", cap); | 
 | 750 | 		write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, | 
 | 751 | 				      ehci_dev.func, offset + 2, 0); | 
 | 752 | 	} | 
 | 753 |  | 
 | 754 | 	/* just in case, always disable EHCI SMIs */ | 
 | 755 | 	write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | 
 | 756 | 			      offset + EHCI_USBLEGCTLSTS, 0); | 
 | 757 | } | 
 | 758 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 759 | static int __init ehci_setup(void) | 
 | 760 | { | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 761 | 	u32 ctrl, portsc, hcs_params; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 762 | 	u32 debug_port, new_debug_port = 0, n_ports; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 763 | 	int ret, i; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 764 | 	int port_map_tried; | 
 | 765 | 	int playtimes = 3; | 
 | 766 |  | 
| Jason Wessel | 093344e | 2009-08-20 15:39:50 -0500 | [diff] [blame] | 767 | 	early_ehci_bios_handoff(); | 
 | 768 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 769 | try_next_time: | 
 | 770 | 	port_map_tried = 0; | 
 | 771 |  | 
 | 772 | try_next_port: | 
 | 773 |  | 
 | 774 | 	hcs_params = readl(&ehci_caps->hcs_params); | 
 | 775 | 	debug_port = HCS_DEBUG_PORT(hcs_params); | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 776 | 	dbgp_phys_port = debug_port; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 777 | 	n_ports    = HCS_N_PORTS(hcs_params); | 
 | 778 |  | 
 | 779 | 	dbgp_printk("debug_port: %d\n", debug_port); | 
 | 780 | 	dbgp_printk("n_ports:    %d\n", n_ports); | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 781 | 	dbgp_ehci_status(""); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 782 |  | 
 | 783 | 	for (i = 1; i <= n_ports; i++) { | 
 | 784 | 		portsc = readl(&ehci_regs->port_status[i-1]); | 
 | 785 | 		dbgp_printk("portstatus%d: %08x\n", i, portsc); | 
 | 786 | 	} | 
 | 787 |  | 
 | 788 | 	if (port_map_tried && (new_debug_port != debug_port)) { | 
 | 789 | 		if (--playtimes) { | 
 | 790 | 			set_debug_port(new_debug_port); | 
 | 791 | 			goto try_next_time; | 
 | 792 | 		} | 
 | 793 | 		return -1; | 
 | 794 | 	} | 
 | 795 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 796 | 	/* Only reset the controller if it is not already in the | 
 | 797 | 	 * configured state */ | 
 | 798 | 	if (!(readl(&ehci_regs->configured_flag) & FLAG_CF)) { | 
 | 799 | 		if (dbgp_ehci_controller_reset() != 0) | 
 | 800 | 			return -1; | 
 | 801 | 	} else { | 
 | 802 | 		dbgp_ehci_status("ehci skip - already configured"); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 803 | 	} | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 804 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 805 | 	ret = dbgp_external_startup(); | 
 | 806 | 	if (ret == -EIO) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 807 | 		goto next_debug_port; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 808 |  | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 809 | 	if (ret < 0) { | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 810 | 		/* Things didn't work so remove my claim */ | 
 | 811 | 		ctrl = readl(&ehci_debug->control); | 
 | 812 | 		ctrl &= ~(DBGP_CLAIM | DBGP_OUT); | 
 | 813 | 		writel(ctrl, &ehci_debug->control); | 
 | 814 | 		return -1; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 815 | 	} | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 816 | 	return 0; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 817 |  | 
 | 818 | next_debug_port: | 
 | 819 | 	port_map_tried |= (1<<(debug_port - 1)); | 
 | 820 | 	new_debug_port = ((debug_port-1+1)%n_ports) + 1; | 
 | 821 | 	if (port_map_tried != ((1<<n_ports) - 1)) { | 
 | 822 | 		set_debug_port(new_debug_port); | 
 | 823 | 		goto try_next_port; | 
 | 824 | 	} | 
 | 825 | 	if (--playtimes) { | 
 | 826 | 		set_debug_port(new_debug_port); | 
 | 827 | 		goto try_next_time; | 
 | 828 | 	} | 
 | 829 |  | 
 | 830 | 	return -1; | 
 | 831 | } | 
 | 832 |  | 
 | 833 | int __init early_dbgp_init(char *s) | 
 | 834 | { | 
 | 835 | 	u32 debug_port, bar, offset; | 
 | 836 | 	u32 bus, slot, func, cap; | 
 | 837 | 	void __iomem *ehci_bar; | 
 | 838 | 	u32 dbgp_num; | 
 | 839 | 	u32 bar_val; | 
 | 840 | 	char *e; | 
 | 841 | 	int ret; | 
 | 842 | 	u8 byte; | 
 | 843 |  | 
 | 844 | 	if (!early_pci_allowed()) | 
 | 845 | 		return -1; | 
 | 846 |  | 
 | 847 | 	dbgp_num = 0; | 
 | 848 | 	if (*s) | 
 | 849 | 		dbgp_num = simple_strtoul(s, &e, 10); | 
 | 850 | 	dbgp_printk("dbgp_num: %d\n", dbgp_num); | 
 | 851 |  | 
 | 852 | 	cap = find_dbgp(dbgp_num, &bus, &slot, &func); | 
 | 853 | 	if (!cap) | 
 | 854 | 		return -1; | 
 | 855 |  | 
 | 856 | 	dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot, | 
 | 857 | 			 func); | 
 | 858 |  | 
 | 859 | 	debug_port = read_pci_config(bus, slot, func, cap); | 
 | 860 | 	bar = (debug_port >> 29) & 0x7; | 
 | 861 | 	bar = (bar * 4) + 0xc; | 
 | 862 | 	offset = (debug_port >> 16) & 0xfff; | 
 | 863 | 	dbgp_printk("bar: %02x offset: %03x\n", bar, offset); | 
 | 864 | 	if (bar != PCI_BASE_ADDRESS_0) { | 
 | 865 | 		dbgp_printk("only debug ports on bar 1 handled.\n"); | 
 | 866 |  | 
 | 867 | 		return -1; | 
 | 868 | 	} | 
 | 869 |  | 
 | 870 | 	bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); | 
 | 871 | 	dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset); | 
 | 872 | 	if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) { | 
 | 873 | 		dbgp_printk("only simple 32bit mmio bars supported\n"); | 
 | 874 |  | 
 | 875 | 		return -1; | 
 | 876 | 	} | 
 | 877 |  | 
 | 878 | 	/* double check if the mem space is enabled */ | 
 | 879 | 	byte = read_pci_config_byte(bus, slot, func, 0x04); | 
 | 880 | 	if (!(byte & 0x2)) { | 
 | 881 | 		byte  |= 0x02; | 
 | 882 | 		write_pci_config_byte(bus, slot, func, 0x04, byte); | 
 | 883 | 		dbgp_printk("mmio for ehci enabled\n"); | 
 | 884 | 	} | 
 | 885 |  | 
 | 886 | 	/* | 
 | 887 | 	 * FIXME I don't have the bar size so just guess PAGE_SIZE is more | 
 | 888 | 	 * than enough.  1K is the biggest I have seen. | 
 | 889 | 	 */ | 
 | 890 | 	set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK); | 
 | 891 | 	ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE); | 
 | 892 | 	ehci_bar += bar_val & ~PAGE_MASK; | 
 | 893 | 	dbgp_printk("ehci_bar: %p\n", ehci_bar); | 
 | 894 |  | 
 | 895 | 	ehci_caps  = ehci_bar; | 
 | 896 | 	ehci_regs  = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase)); | 
 | 897 | 	ehci_debug = ehci_bar + offset; | 
 | 898 | 	ehci_dev.bus = bus; | 
 | 899 | 	ehci_dev.slot = slot; | 
 | 900 | 	ehci_dev.func = func; | 
 | 901 |  | 
 | 902 | 	detect_set_debug_port(); | 
 | 903 |  | 
 | 904 | 	ret = ehci_setup(); | 
 | 905 | 	if (ret < 0) { | 
 | 906 | 		dbgp_printk("ehci_setup failed\n"); | 
 | 907 | 		ehci_debug = NULL; | 
 | 908 |  | 
 | 909 | 		return -1; | 
 | 910 | 	} | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 911 | 	dbgp_ehci_status("early_init_complete"); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 912 |  | 
 | 913 | 	return 0; | 
 | 914 | } | 
 | 915 |  | 
 | 916 | static void early_dbgp_write(struct console *con, const char *str, u32 n) | 
 | 917 | { | 
 | 918 | 	int chunk, ret; | 
| Jason Wessel | 87a5d15 | 2009-08-20 15:39:49 -0500 | [diff] [blame] | 919 | 	char buf[DBGP_MAX_PACKET]; | 
 | 920 | 	int use_cr = 0; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 921 | 	u32 cmd, ctrl; | 
 | 922 | 	int reset_run = 0; | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 923 |  | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 924 | 	if (!ehci_debug || dbgp_not_safe) | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 925 | 		return; | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 926 |  | 
 | 927 | 	cmd = readl(&ehci_regs->command); | 
 | 928 | 	if (unlikely(!(cmd & CMD_RUN))) { | 
 | 929 | 		/* If the ehci controller is not in the run state do extended | 
 | 930 | 		 * checks to see if the acpi or some other initialization also | 
 | 931 | 		 * reset the ehci debug port */ | 
 | 932 | 		ctrl = readl(&ehci_debug->control); | 
 | 933 | 		if (!(ctrl & DBGP_ENABLED)) { | 
 | 934 | 			dbgp_not_safe = 1; | 
 | 935 | 			dbgp_external_startup(); | 
 | 936 | 		} else { | 
 | 937 | 			cmd |= CMD_RUN; | 
 | 938 | 			writel(cmd, &ehci_regs->command); | 
 | 939 | 			reset_run = 1; | 
 | 940 | 		} | 
 | 941 | 	} | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 942 | 	while (n > 0) { | 
| Jason Wessel | 87a5d15 | 2009-08-20 15:39:49 -0500 | [diff] [blame] | 943 | 		for (chunk = 0; chunk < DBGP_MAX_PACKET && n > 0; | 
 | 944 | 		     str++, chunk++, n--) { | 
 | 945 | 			if (!use_cr && *str == '\n') { | 
 | 946 | 				use_cr = 1; | 
 | 947 | 				buf[chunk] = '\r'; | 
 | 948 | 				str--; | 
 | 949 | 				n++; | 
 | 950 | 				continue; | 
 | 951 | 			} | 
 | 952 | 			if (use_cr) | 
 | 953 | 				use_cr = 0; | 
 | 954 | 			buf[chunk] = *str; | 
 | 955 | 		} | 
| Jason Wessel | 9177782 | 2009-08-20 15:39:53 -0500 | [diff] [blame] | 956 | 		if (chunk > 0) { | 
 | 957 | 			ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, | 
 | 958 | 				      dbgp_endpoint_out, buf, chunk); | 
 | 959 | 		} | 
 | 960 | 	} | 
 | 961 | 	if (unlikely(reset_run)) { | 
 | 962 | 		cmd = readl(&ehci_regs->command); | 
 | 963 | 		cmd &= ~CMD_RUN; | 
 | 964 | 		writel(cmd, &ehci_regs->command); | 
| Jason Wessel | df6c516 | 2009-08-20 15:39:48 -0500 | [diff] [blame] | 965 | 	} | 
 | 966 | } | 
 | 967 |  | 
 | 968 | struct console early_dbgp_console = { | 
 | 969 | 	.name =		"earlydbg", | 
 | 970 | 	.write =	early_dbgp_write, | 
 | 971 | 	.flags =	CON_PRINTBUFFER, | 
 | 972 | 	.index =	-1, | 
 | 973 | }; | 
| Jason Wessel | 8d053c7 | 2009-08-20 15:39:54 -0500 | [diff] [blame] | 974 |  | 
 | 975 | int dbgp_reset_prep(void) | 
 | 976 | { | 
 | 977 | 	u32 ctrl; | 
 | 978 |  | 
 | 979 | 	dbgp_not_safe = 1; | 
 | 980 | 	if (!ehci_debug) | 
 | 981 | 		return 0; | 
 | 982 |  | 
 | 983 | 	if (early_dbgp_console.index != -1 && | 
 | 984 | 		!(early_dbgp_console.flags & CON_BOOT)) | 
 | 985 | 		return 1; | 
 | 986 | 	/* This means the console is not initialized, or should get | 
 | 987 | 	 * shutdown so as to allow for reuse of the usb device, which | 
 | 988 | 	 * means it is time to shutdown the usb debug port. */ | 
 | 989 | 	ctrl = readl(&ehci_debug->control); | 
 | 990 | 	if (ctrl & DBGP_ENABLED) { | 
 | 991 | 		ctrl &= ~(DBGP_CLAIM); | 
 | 992 | 		writel(ctrl, &ehci_debug->control); | 
 | 993 | 	} | 
 | 994 | 	return 0; | 
 | 995 | } | 
 | 996 | EXPORT_SYMBOL_GPL(dbgp_reset_prep); |