| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 1 | /* | 
|  | 2 | * ISP116x register declarations and HCD data structures | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee> | 
|  | 5 | * Portions: | 
|  | 6 | * Copyright (C) 2004 Lothar Wassmann | 
|  | 7 | * Copyright (C) 2004 Psion Teklogix | 
|  | 8 | * Copyright (C) 2004 David Brownell | 
|  | 9 | */ | 
|  | 10 |  | 
|  | 11 | /* us of 1ms frame */ | 
|  | 12 | #define  MAX_LOAD_LIMIT		850 | 
|  | 13 |  | 
|  | 14 | /* Full speed: max # of bytes to transfer for a single urb | 
|  | 15 | at a time must be < 1024 && must be multiple of 64. | 
|  | 16 | 832 allows transfering 4kiB within 5 frames. */ | 
|  | 17 | #define MAX_TRANSFER_SIZE_FULLSPEED	832 | 
|  | 18 |  | 
|  | 19 | /* Low speed: there is no reason to schedule in very big | 
|  | 20 | chunks; often the requested long transfers are for | 
|  | 21 | string descriptors containing short strings. */ | 
|  | 22 | #define MAX_TRANSFER_SIZE_LOWSPEED	64 | 
|  | 23 |  | 
|  | 24 | /* Bytetime (us), a rough indication of how much time it | 
|  | 25 | would take to transfer a byte of useful data over USB */ | 
|  | 26 | #define BYTE_TIME_FULLSPEED	1 | 
|  | 27 | #define BYTE_TIME_LOWSPEED	20 | 
|  | 28 |  | 
|  | 29 | /* Buffer sizes */ | 
|  | 30 | #define ISP116x_BUF_SIZE	4096 | 
|  | 31 | #define ISP116x_ITL_BUFSIZE	0 | 
|  | 32 | #define ISP116x_ATL_BUFSIZE	((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE)) | 
|  | 33 |  | 
|  | 34 | #define ISP116x_WRITE_OFFSET	0x80 | 
|  | 35 |  | 
|  | 36 | /*------------ ISP116x registers/bits ------------*/ | 
|  | 37 | #define	HCREVISION	0x00 | 
|  | 38 | #define	HCCONTROL	0x01 | 
|  | 39 | #define		HCCONTROL_HCFS	(3 << 6)	/* host controller | 
|  | 40 | functional state */ | 
|  | 41 | #define		HCCONTROL_USB_RESET	(0 << 6) | 
|  | 42 | #define		HCCONTROL_USB_RESUME	(1 << 6) | 
|  | 43 | #define		HCCONTROL_USB_OPER	(2 << 6) | 
|  | 44 | #define		HCCONTROL_USB_SUSPEND	(3 << 6) | 
|  | 45 | #define		HCCONTROL_RWC	(1 << 9)	/* remote wakeup connected */ | 
|  | 46 | #define		HCCONTROL_RWE	(1 << 10)	/* remote wakeup enable */ | 
|  | 47 | #define	HCCMDSTAT	0x02 | 
|  | 48 | #define		HCCMDSTAT_HCR	(1 << 0)	/* host controller reset */ | 
|  | 49 | #define		HCCMDSTAT_SOC	(3 << 16)	/* scheduling overrun count */ | 
|  | 50 | #define	HCINTSTAT	0x03 | 
|  | 51 | #define		HCINT_SO	(1 << 0)	/* scheduling overrun */ | 
|  | 52 | #define		HCINT_WDH	(1 << 1)	/* writeback of done_head */ | 
|  | 53 | #define		HCINT_SF	(1 << 2)	/* start frame */ | 
|  | 54 | #define		HCINT_RD	(1 << 3)	/* resume detect */ | 
|  | 55 | #define		HCINT_UE	(1 << 4)	/* unrecoverable error */ | 
|  | 56 | #define		HCINT_FNO	(1 << 5)	/* frame number overflow */ | 
|  | 57 | #define		HCINT_RHSC	(1 << 6)	/* root hub status change */ | 
|  | 58 | #define		HCINT_OC	(1 << 30)	/* ownership change */ | 
|  | 59 | #define		HCINT_MIE	(1 << 31)	/* master interrupt enable */ | 
|  | 60 | #define	HCINTENB	0x04 | 
|  | 61 | #define	HCINTDIS	0x05 | 
|  | 62 | #define	HCFMINTVL	0x0d | 
|  | 63 | #define	HCFMREM		0x0e | 
|  | 64 | #define	HCFMNUM		0x0f | 
|  | 65 | #define	HCLSTHRESH	0x11 | 
|  | 66 | #define	HCRHDESCA	0x12 | 
|  | 67 | #define		RH_A_NDP	(0x3 << 0)	/* # downstream ports */ | 
|  | 68 | #define		RH_A_PSM	(1 << 8)	/* power switching mode */ | 
|  | 69 | #define		RH_A_NPS	(1 << 9)	/* no power switching */ | 
|  | 70 | #define		RH_A_DT		(1 << 10)	/* device type (mbz) */ | 
|  | 71 | #define		RH_A_OCPM	(1 << 11)	/* overcurrent protection | 
|  | 72 | mode */ | 
|  | 73 | #define		RH_A_NOCP	(1 << 12)	/* no overcurrent protection */ | 
|  | 74 | #define		RH_A_POTPGT	(0xff << 24)	/* power on -> power good | 
|  | 75 | time */ | 
|  | 76 | #define	HCRHDESCB	0x13 | 
|  | 77 | #define		RH_B_DR		(0xffff << 0)	/* device removable flags */ | 
|  | 78 | #define		RH_B_PPCM	(0xffff << 16)	/* port power control mask */ | 
|  | 79 | #define	HCRHSTATUS	0x14 | 
|  | 80 | #define		RH_HS_LPS	(1 << 0)	/* local power status */ | 
|  | 81 | #define		RH_HS_OCI	(1 << 1)	/* over current indicator */ | 
|  | 82 | #define		RH_HS_DRWE	(1 << 15)	/* device remote wakeup | 
|  | 83 | enable */ | 
|  | 84 | #define		RH_HS_LPSC	(1 << 16)	/* local power status change */ | 
|  | 85 | #define		RH_HS_OCIC	(1 << 17)	/* over current indicator | 
|  | 86 | change */ | 
|  | 87 | #define		RH_HS_CRWE	(1 << 31)	/* clear remote wakeup | 
|  | 88 | enable */ | 
|  | 89 | #define	HCRHPORT1	0x15 | 
|  | 90 | #define		RH_PS_CCS	(1 << 0)	/* current connect status */ | 
|  | 91 | #define		RH_PS_PES	(1 << 1)	/* port enable status */ | 
|  | 92 | #define		RH_PS_PSS	(1 << 2)	/* port suspend status */ | 
|  | 93 | #define		RH_PS_POCI	(1 << 3)	/* port over current | 
|  | 94 | indicator */ | 
|  | 95 | #define		RH_PS_PRS	(1 << 4)	/* port reset status */ | 
|  | 96 | #define		RH_PS_PPS	(1 << 8)	/* port power status */ | 
|  | 97 | #define		RH_PS_LSDA	(1 << 9)	/* low speed device attached */ | 
|  | 98 | #define		RH_PS_CSC	(1 << 16)	/* connect status change */ | 
|  | 99 | #define		RH_PS_PESC	(1 << 17)	/* port enable status change */ | 
|  | 100 | #define		RH_PS_PSSC	(1 << 18)	/* port suspend status | 
|  | 101 | change */ | 
|  | 102 | #define		RH_PS_OCIC	(1 << 19)	/* over current indicator | 
|  | 103 | change */ | 
|  | 104 | #define		RH_PS_PRSC	(1 << 20)	/* port reset status change */ | 
|  | 105 | #define		HCRHPORT_CLRMASK	(0x1f << 16) | 
|  | 106 | #define	HCRHPORT2	0x16 | 
|  | 107 | #define	HCHWCFG		0x20 | 
|  | 108 | #define		HCHWCFG_15KRSEL		(1 << 12) | 
|  | 109 | #define		HCHWCFG_CLKNOTSTOP	(1 << 11) | 
|  | 110 | #define		HCHWCFG_ANALOG_OC	(1 << 10) | 
|  | 111 | #define		HCHWCFG_DACK_MODE	(1 << 8) | 
|  | 112 | #define		HCHWCFG_EOT_POL		(1 << 7) | 
|  | 113 | #define		HCHWCFG_DACK_POL	(1 << 6) | 
|  | 114 | #define		HCHWCFG_DREQ_POL	(1 << 5) | 
|  | 115 | #define		HCHWCFG_DBWIDTH_MASK	(0x03 << 3) | 
|  | 116 | #define		HCHWCFG_DBWIDTH(n)	(((n) << 3) & HCHWCFG_DBWIDTH_MASK) | 
|  | 117 | #define		HCHWCFG_INT_POL		(1 << 2) | 
|  | 118 | #define		HCHWCFG_INT_TRIGGER	(1 << 1) | 
|  | 119 | #define		HCHWCFG_INT_ENABLE	(1 << 0) | 
|  | 120 | #define	HCDMACFG	0x21 | 
|  | 121 | #define		HCDMACFG_BURST_LEN_MASK	(0x03 << 5) | 
|  | 122 | #define		HCDMACFG_BURST_LEN(n)	(((n) << 5) & HCDMACFG_BURST_LEN_MASK) | 
|  | 123 | #define		HCDMACFG_BURST_LEN_1	HCDMACFG_BURST_LEN(0) | 
|  | 124 | #define		HCDMACFG_BURST_LEN_4	HCDMACFG_BURST_LEN(1) | 
|  | 125 | #define		HCDMACFG_BURST_LEN_8	HCDMACFG_BURST_LEN(2) | 
|  | 126 | #define		HCDMACFG_DMA_ENABLE	(1 << 4) | 
|  | 127 | #define		HCDMACFG_BUF_TYPE_MASK	(0x07 << 1) | 
|  | 128 | #define		HCDMACFG_CTR_SEL	(1 << 2) | 
|  | 129 | #define		HCDMACFG_ITLATL_SEL	(1 << 1) | 
|  | 130 | #define		HCDMACFG_DMA_RW_SELECT	(1 << 0) | 
|  | 131 | #define	HCXFERCTR	0x22 | 
|  | 132 | #define	HCuPINT		0x24 | 
|  | 133 | #define		HCuPINT_SOF		(1 << 0) | 
|  | 134 | #define		HCuPINT_ATL		(1 << 1) | 
|  | 135 | #define		HCuPINT_AIIEOT		(1 << 2) | 
|  | 136 | #define		HCuPINT_OPR		(1 << 4) | 
|  | 137 | #define		HCuPINT_SUSP		(1 << 5) | 
|  | 138 | #define		HCuPINT_CLKRDY		(1 << 6) | 
|  | 139 | #define	HCuPINTENB	0x25 | 
|  | 140 | #define	HCCHIPID	0x27 | 
|  | 141 | #define		HCCHIPID_MASK		0xff00 | 
|  | 142 | #define		HCCHIPID_MAGIC		0x6100 | 
|  | 143 | #define	HCSCRATCH	0x28 | 
|  | 144 | #define	HCSWRES		0x29 | 
|  | 145 | #define		HCSWRES_MAGIC		0x00f6 | 
|  | 146 | #define	HCITLBUFLEN	0x2a | 
|  | 147 | #define	HCATLBUFLEN	0x2b | 
|  | 148 | #define	HCBUFSTAT	0x2c | 
|  | 149 | #define		HCBUFSTAT_ITL0_FULL	(1 << 0) | 
|  | 150 | #define		HCBUFSTAT_ITL1_FULL	(1 << 1) | 
|  | 151 | #define		HCBUFSTAT_ATL_FULL	(1 << 2) | 
|  | 152 | #define		HCBUFSTAT_ITL0_DONE	(1 << 3) | 
|  | 153 | #define		HCBUFSTAT_ITL1_DONE	(1 << 4) | 
|  | 154 | #define		HCBUFSTAT_ATL_DONE	(1 << 5) | 
|  | 155 | #define	HCRDITL0LEN	0x2d | 
|  | 156 | #define	HCRDITL1LEN	0x2e | 
|  | 157 | #define	HCITLPORT	0x40 | 
|  | 158 | #define	HCATLPORT	0x41 | 
|  | 159 |  | 
|  | 160 | /* Philips transfer descriptor */ | 
|  | 161 | struct ptd { | 
|  | 162 | u16 count; | 
|  | 163 | #define	PTD_COUNT_MSK	(0x3ff << 0) | 
|  | 164 | #define	PTD_TOGGLE_MSK	(1 << 10) | 
|  | 165 | #define	PTD_ACTIVE_MSK	(1 << 11) | 
|  | 166 | #define	PTD_CC_MSK	(0xf << 12) | 
|  | 167 | u16 mps; | 
|  | 168 | #define	PTD_MPS_MSK	(0x3ff << 0) | 
|  | 169 | #define	PTD_SPD_MSK	(1 << 10) | 
|  | 170 | #define	PTD_LAST_MSK	(1 << 11) | 
|  | 171 | #define	PTD_EP_MSK	(0xf << 12) | 
|  | 172 | u16 len; | 
|  | 173 | #define	PTD_LEN_MSK	(0x3ff << 0) | 
|  | 174 | #define	PTD_DIR_MSK	(3 << 10) | 
|  | 175 | #define	PTD_DIR_SETUP	(0) | 
|  | 176 | #define	PTD_DIR_OUT	(1) | 
|  | 177 | #define	PTD_DIR_IN	(2) | 
|  | 178 | #define	PTD_B5_5_MSK	(1 << 13) | 
|  | 179 | u16 faddr; | 
|  | 180 | #define	PTD_FA_MSK	(0x7f << 0) | 
|  | 181 | #define	PTD_FMT_MSK	(1 << 7) | 
|  | 182 | } __attribute__ ((packed, aligned(2))); | 
|  | 183 |  | 
|  | 184 | /* PTD accessor macros. */ | 
|  | 185 | #define PTD_GET_COUNT(p)	(((p)->count & PTD_COUNT_MSK) >> 0) | 
|  | 186 | #define PTD_COUNT(v)		(((v) << 0) & PTD_COUNT_MSK) | 
|  | 187 | #define PTD_GET_TOGGLE(p)	(((p)->count & PTD_TOGGLE_MSK) >> 10) | 
|  | 188 | #define PTD_TOGGLE(v)		(((v) << 10) & PTD_TOGGLE_MSK) | 
|  | 189 | #define PTD_GET_ACTIVE(p)	(((p)->count & PTD_ACTIVE_MSK) >> 11) | 
|  | 190 | #define PTD_ACTIVE(v)		(((v) << 11) & PTD_ACTIVE_MSK) | 
|  | 191 | #define PTD_GET_CC(p)		(((p)->count & PTD_CC_MSK) >> 12) | 
|  | 192 | #define PTD_CC(v)		(((v) << 12) & PTD_CC_MSK) | 
|  | 193 | #define PTD_GET_MPS(p)		(((p)->mps & PTD_MPS_MSK) >> 0) | 
|  | 194 | #define PTD_MPS(v)		(((v) << 0) & PTD_MPS_MSK) | 
|  | 195 | #define PTD_GET_SPD(p)		(((p)->mps & PTD_SPD_MSK) >> 10) | 
|  | 196 | #define PTD_SPD(v)		(((v) << 10) & PTD_SPD_MSK) | 
|  | 197 | #define PTD_GET_LAST(p)		(((p)->mps & PTD_LAST_MSK) >> 11) | 
|  | 198 | #define PTD_LAST(v)		(((v) << 11) & PTD_LAST_MSK) | 
|  | 199 | #define PTD_GET_EP(p)		(((p)->mps & PTD_EP_MSK) >> 12) | 
|  | 200 | #define PTD_EP(v)		(((v) << 12) & PTD_EP_MSK) | 
|  | 201 | #define PTD_GET_LEN(p)		(((p)->len & PTD_LEN_MSK) >> 0) | 
|  | 202 | #define PTD_LEN(v)		(((v) << 0) & PTD_LEN_MSK) | 
|  | 203 | #define PTD_GET_DIR(p)		(((p)->len & PTD_DIR_MSK) >> 10) | 
|  | 204 | #define PTD_DIR(v)		(((v) << 10) & PTD_DIR_MSK) | 
|  | 205 | #define PTD_GET_B5_5(p)		(((p)->len & PTD_B5_5_MSK) >> 13) | 
|  | 206 | #define PTD_B5_5(v)		(((v) << 13) & PTD_B5_5_MSK) | 
|  | 207 | #define PTD_GET_FA(p)		(((p)->faddr & PTD_FA_MSK) >> 0) | 
|  | 208 | #define PTD_FA(v)		(((v) << 0) & PTD_FA_MSK) | 
|  | 209 | #define PTD_GET_FMT(p)		(((p)->faddr & PTD_FMT_MSK) >> 7) | 
|  | 210 | #define PTD_FMT(v)		(((v) << 7) & PTD_FMT_MSK) | 
|  | 211 |  | 
|  | 212 | /*  Hardware transfer status codes -- CC from ptd->count */ | 
|  | 213 | #define TD_CC_NOERROR      0x00 | 
|  | 214 | #define TD_CC_CRC          0x01 | 
|  | 215 | #define TD_CC_BITSTUFFING  0x02 | 
|  | 216 | #define TD_CC_DATATOGGLEM  0x03 | 
|  | 217 | #define TD_CC_STALL        0x04 | 
|  | 218 | #define TD_DEVNOTRESP      0x05 | 
|  | 219 | #define TD_PIDCHECKFAIL    0x06 | 
|  | 220 | #define TD_UNEXPECTEDPID   0x07 | 
|  | 221 | #define TD_DATAOVERRUN     0x08 | 
|  | 222 | #define TD_DATAUNDERRUN    0x09 | 
|  | 223 | /* 0x0A, 0x0B reserved for hardware */ | 
|  | 224 | #define TD_BUFFEROVERRUN   0x0C | 
|  | 225 | #define TD_BUFFERUNDERRUN  0x0D | 
|  | 226 | /* 0x0E, 0x0F reserved for HCD */ | 
|  | 227 | #define TD_NOTACCESSED     0x0F | 
|  | 228 |  | 
|  | 229 | /* map PTD status codes (CC) to errno values */ | 
|  | 230 | static const int cc_to_error[16] = { | 
|  | 231 | /* No  Error  */ 0, | 
|  | 232 | /* CRC Error  */ -EILSEQ, | 
|  | 233 | /* Bit Stuff  */ -EPROTO, | 
|  | 234 | /* Data Togg  */ -EILSEQ, | 
|  | 235 | /* Stall      */ -EPIPE, | 
| Pete Zaitcev | 38e2bfc | 2006-09-18 22:49:02 -0700 | [diff] [blame] | 236 | /* DevNotResp */ -ETIME, | 
| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 237 | /* PIDCheck   */ -EPROTO, | 
|  | 238 | /* UnExpPID   */ -EPROTO, | 
|  | 239 | /* DataOver   */ -EOVERFLOW, | 
|  | 240 | /* DataUnder  */ -EREMOTEIO, | 
|  | 241 | /* (for hw)   */ -EIO, | 
|  | 242 | /* (for hw)   */ -EIO, | 
|  | 243 | /* BufferOver */ -ECOMM, | 
|  | 244 | /* BuffUnder  */ -ENOSR, | 
|  | 245 | /* (for HCD)  */ -EALREADY, | 
|  | 246 | /* (for HCD)  */ -EALREADY | 
|  | 247 | }; | 
|  | 248 |  | 
|  | 249 | /*--------------------------------------------------------------*/ | 
|  | 250 |  | 
|  | 251 | #define	LOG2_PERIODIC_SIZE	5	/* arbitrary; this matches OHCI */ | 
|  | 252 | #define	PERIODIC_SIZE		(1 << LOG2_PERIODIC_SIZE) | 
|  | 253 |  | 
|  | 254 | struct isp116x { | 
|  | 255 | spinlock_t lock; | 
| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 256 |  | 
|  | 257 | void __iomem *addr_reg; | 
|  | 258 | void __iomem *data_reg; | 
|  | 259 |  | 
|  | 260 | struct isp116x_platform_data *board; | 
|  | 261 |  | 
| Olav Kongas | 959eea2 | 2005-11-03 17:38:14 +0200 | [diff] [blame] | 262 | struct dentry *dentry; | 
| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 263 | unsigned long stat1, stat2, stat4, stat8, stat16; | 
|  | 264 |  | 
|  | 265 | /* HC registers */ | 
|  | 266 | u32 intenb;		/* "OHCI" interrupts */ | 
|  | 267 | u16 irqenb;		/* uP interrupts */ | 
|  | 268 |  | 
|  | 269 | /* Root hub registers */ | 
|  | 270 | u32 rhdesca; | 
|  | 271 | u32 rhdescb; | 
|  | 272 | u32 rhstatus; | 
|  | 273 | u32 rhport[2]; | 
|  | 274 |  | 
|  | 275 | /* async schedule: control, bulk */ | 
|  | 276 | struct list_head async; | 
|  | 277 |  | 
|  | 278 | /* periodic schedule: int */ | 
|  | 279 | u16 load[PERIODIC_SIZE]; | 
|  | 280 | struct isp116x_ep *periodic[PERIODIC_SIZE]; | 
|  | 281 | unsigned periodic_count; | 
|  | 282 | u16 fmindex; | 
|  | 283 |  | 
|  | 284 | /* Schedule for the current frame */ | 
|  | 285 | struct isp116x_ep *atl_active; | 
|  | 286 | int atl_buflen; | 
|  | 287 | int atl_bufshrt; | 
|  | 288 | int atl_last_dir; | 
|  | 289 | atomic_t atl_finishing; | 
|  | 290 | }; | 
|  | 291 |  | 
|  | 292 | static inline struct isp116x *hcd_to_isp116x(struct usb_hcd *hcd) | 
|  | 293 | { | 
|  | 294 | return (struct isp116x *)(hcd->hcd_priv); | 
|  | 295 | } | 
|  | 296 |  | 
|  | 297 | static inline struct usb_hcd *isp116x_to_hcd(struct isp116x *isp116x) | 
|  | 298 | { | 
|  | 299 | return container_of((void *)isp116x, struct usb_hcd, hcd_priv); | 
|  | 300 | } | 
|  | 301 |  | 
|  | 302 | struct isp116x_ep { | 
|  | 303 | struct usb_host_endpoint *hep; | 
|  | 304 | struct usb_device *udev; | 
|  | 305 | struct ptd ptd; | 
|  | 306 |  | 
|  | 307 | u8 maxpacket; | 
|  | 308 | u8 epnum; | 
|  | 309 | u8 nextpid; | 
|  | 310 | u16 error_count; | 
|  | 311 | u16 length;		/* of current packet */ | 
|  | 312 | unsigned char *data;	/* to databuf */ | 
|  | 313 | /* queue of active EP's (the ones scheduled for the | 
|  | 314 | current frame) */ | 
|  | 315 | struct isp116x_ep *active; | 
|  | 316 |  | 
|  | 317 | /* periodic schedule */ | 
|  | 318 | u16 period; | 
|  | 319 | u16 branch; | 
|  | 320 | u16 load; | 
|  | 321 | struct isp116x_ep *next; | 
|  | 322 |  | 
|  | 323 | /* async schedule */ | 
|  | 324 | struct list_head schedule; | 
|  | 325 | }; | 
|  | 326 |  | 
|  | 327 | /*-------------------------------------------------------------------------*/ | 
|  | 328 |  | 
|  | 329 | #ifdef DEBUG | 
|  | 330 | #define DBG(stuff...)		printk(KERN_DEBUG "116x: " stuff) | 
|  | 331 | #else | 
|  | 332 | #define DBG(stuff...)		do{}while(0) | 
|  | 333 | #endif | 
|  | 334 |  | 
|  | 335 | #ifdef VERBOSE | 
|  | 336 | #    define VDBG		DBG | 
|  | 337 | #else | 
|  | 338 | #    define VDBG(stuff...)	do{}while(0) | 
|  | 339 | #endif | 
|  | 340 |  | 
|  | 341 | #define ERR(stuff...)		printk(KERN_ERR "116x: " stuff) | 
|  | 342 | #define WARN(stuff...)		printk(KERN_WARNING "116x: " stuff) | 
|  | 343 | #define INFO(stuff...)		printk(KERN_INFO "116x: " stuff) | 
|  | 344 |  | 
|  | 345 | /* ------------------------------------------------- */ | 
|  | 346 |  | 
|  | 347 | #if defined(USE_PLATFORM_DELAY) | 
|  | 348 | #if defined(USE_NDELAY) | 
|  | 349 | #error USE_PLATFORM_DELAY and USE_NDELAY simultaneously defined. | 
|  | 350 | #endif | 
|  | 351 | #define	isp116x_delay(h,d)	(h)->board->delay(	\ | 
|  | 352 | isp116x_to_hcd(h)->self.controller,d) | 
|  | 353 | #define isp116x_check_platform_delay(h)	((h)->board->delay == NULL) | 
|  | 354 | #elif defined(USE_NDELAY) | 
|  | 355 | #define	isp116x_delay(h,d)	ndelay(d) | 
|  | 356 | #define isp116x_check_platform_delay(h)	0 | 
|  | 357 | #else | 
|  | 358 | #define	isp116x_delay(h,d)	do{}while(0) | 
|  | 359 | #define isp116x_check_platform_delay(h)	0 | 
|  | 360 | #endif | 
|  | 361 |  | 
|  | 362 | #if defined(DEBUG) | 
|  | 363 | #define	IRQ_TEST()	BUG_ON(!irqs_disabled()) | 
|  | 364 | #else | 
|  | 365 | #define	IRQ_TEST()	do{}while(0) | 
|  | 366 | #endif | 
|  | 367 |  | 
|  | 368 | static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg) | 
|  | 369 | { | 
|  | 370 | IRQ_TEST(); | 
|  | 371 | writew(reg & 0xff, isp116x->addr_reg); | 
|  | 372 | isp116x_delay(isp116x, 300); | 
|  | 373 | } | 
|  | 374 |  | 
|  | 375 | static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val) | 
|  | 376 | { | 
|  | 377 | writew(val, isp116x->data_reg); | 
|  | 378 | isp116x_delay(isp116x, 150); | 
|  | 379 | } | 
|  | 380 |  | 
|  | 381 | static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val) | 
|  | 382 | { | 
|  | 383 | __raw_writew(val, isp116x->data_reg); | 
|  | 384 | isp116x_delay(isp116x, 150); | 
|  | 385 | } | 
|  | 386 |  | 
|  | 387 | static inline u16 isp116x_read_data16(struct isp116x *isp116x) | 
|  | 388 | { | 
|  | 389 | u16 val; | 
|  | 390 |  | 
|  | 391 | val = readw(isp116x->data_reg); | 
|  | 392 | isp116x_delay(isp116x, 150); | 
|  | 393 | return val; | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x) | 
|  | 397 | { | 
|  | 398 | u16 val; | 
|  | 399 |  | 
|  | 400 | val = __raw_readw(isp116x->data_reg); | 
|  | 401 | isp116x_delay(isp116x, 150); | 
|  | 402 | return val; | 
|  | 403 | } | 
|  | 404 |  | 
|  | 405 | static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val) | 
|  | 406 | { | 
|  | 407 | writew(val & 0xffff, isp116x->data_reg); | 
|  | 408 | isp116x_delay(isp116x, 150); | 
|  | 409 | writew(val >> 16, isp116x->data_reg); | 
|  | 410 | isp116x_delay(isp116x, 150); | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | static inline u32 isp116x_read_data32(struct isp116x *isp116x) | 
|  | 414 | { | 
|  | 415 | u32 val; | 
|  | 416 |  | 
|  | 417 | val = (u32) readw(isp116x->data_reg); | 
|  | 418 | isp116x_delay(isp116x, 150); | 
|  | 419 | val |= ((u32) readw(isp116x->data_reg)) << 16; | 
|  | 420 | isp116x_delay(isp116x, 150); | 
|  | 421 | return val; | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 | /* Let's keep register access functions out of line. Hint: | 
|  | 425 | we wait at least 150 ns at every access. | 
|  | 426 | */ | 
|  | 427 | static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg) | 
|  | 428 | { | 
|  | 429 | isp116x_write_addr(isp116x, reg); | 
|  | 430 | return isp116x_read_data16(isp116x); | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg) | 
|  | 434 | { | 
|  | 435 | isp116x_write_addr(isp116x, reg); | 
|  | 436 | return isp116x_read_data32(isp116x); | 
|  | 437 | } | 
|  | 438 |  | 
|  | 439 | static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg, | 
|  | 440 | unsigned val) | 
|  | 441 | { | 
|  | 442 | isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); | 
|  | 443 | isp116x_write_data16(isp116x, (u16) (val & 0xffff)); | 
|  | 444 | } | 
|  | 445 |  | 
|  | 446 | static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg, | 
|  | 447 | unsigned val) | 
|  | 448 | { | 
|  | 449 | isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); | 
|  | 450 | isp116x_write_data32(isp116x, (u32) val); | 
|  | 451 | } | 
|  | 452 |  | 
| Olav Kongas | 959eea2 | 2005-11-03 17:38:14 +0200 | [diff] [blame] | 453 | #define isp116x_show_reg_log(d,r,s) {				\ | 
| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 454 | if ((r) < 0x20) {			                \ | 
|  | 455 | DBG("%-12s[%02x]: %08x\n", #r,			\ | 
|  | 456 | r, isp116x_read_reg32(d, r));		\ | 
|  | 457 | } else {						\ | 
|  | 458 | DBG("%-12s[%02x]:     %04x\n", #r,		\ | 
|  | 459 | r, isp116x_read_reg16(d, r));	    	\ | 
|  | 460 | }							\ | 
|  | 461 | } | 
| Olav Kongas | 959eea2 | 2005-11-03 17:38:14 +0200 | [diff] [blame] | 462 | #define isp116x_show_reg_seq(d,r,s) {				\ | 
|  | 463 | if ((r) < 0x20) {					\ | 
|  | 464 | seq_printf(s, "%-12s[%02x]: %08x\n", #r,	\ | 
|  | 465 | r, isp116x_read_reg32(d, r));		\ | 
|  | 466 | } else {						\ | 
|  | 467 | seq_printf(s, "%-12s[%02x]:     %04x\n", #r,	\ | 
|  | 468 | r, isp116x_read_reg16(d, r));		\ | 
|  | 469 | }							\ | 
|  | 470 | } | 
| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 471 |  | 
| Olav Kongas | 959eea2 | 2005-11-03 17:38:14 +0200 | [diff] [blame] | 472 | #define isp116x_show_regs(d,type,s) {			\ | 
|  | 473 | isp116x_show_reg_##type(d, HCREVISION, s);	\ | 
|  | 474 | isp116x_show_reg_##type(d, HCCONTROL, s);	\ | 
|  | 475 | isp116x_show_reg_##type(d, HCCMDSTAT, s);	\ | 
|  | 476 | isp116x_show_reg_##type(d, HCINTSTAT, s);	\ | 
|  | 477 | isp116x_show_reg_##type(d, HCINTENB, s);	\ | 
|  | 478 | isp116x_show_reg_##type(d, HCFMINTVL, s);	\ | 
|  | 479 | isp116x_show_reg_##type(d, HCFMREM, s);		\ | 
|  | 480 | isp116x_show_reg_##type(d, HCFMNUM, s);		\ | 
|  | 481 | isp116x_show_reg_##type(d, HCLSTHRESH, s);	\ | 
|  | 482 | isp116x_show_reg_##type(d, HCRHDESCA, s);	\ | 
|  | 483 | isp116x_show_reg_##type(d, HCRHDESCB, s);	\ | 
|  | 484 | isp116x_show_reg_##type(d, HCRHSTATUS, s);	\ | 
|  | 485 | isp116x_show_reg_##type(d, HCRHPORT1, s);	\ | 
|  | 486 | isp116x_show_reg_##type(d, HCRHPORT2, s);	\ | 
|  | 487 | isp116x_show_reg_##type(d, HCHWCFG, s);		\ | 
|  | 488 | isp116x_show_reg_##type(d, HCDMACFG, s);	\ | 
|  | 489 | isp116x_show_reg_##type(d, HCXFERCTR, s);	\ | 
|  | 490 | isp116x_show_reg_##type(d, HCuPINT, s);		\ | 
|  | 491 | isp116x_show_reg_##type(d, HCuPINTENB, s);	\ | 
|  | 492 | isp116x_show_reg_##type(d, HCCHIPID, s);	\ | 
|  | 493 | isp116x_show_reg_##type(d, HCSCRATCH, s);	\ | 
|  | 494 | isp116x_show_reg_##type(d, HCITLBUFLEN, s);	\ | 
|  | 495 | isp116x_show_reg_##type(d, HCATLBUFLEN, s);	\ | 
|  | 496 | isp116x_show_reg_##type(d, HCBUFSTAT, s);	\ | 
|  | 497 | isp116x_show_reg_##type(d, HCRDITL0LEN, s);	\ | 
|  | 498 | isp116x_show_reg_##type(d, HCRDITL1LEN, s);	\ | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 | /* | 
|  | 502 | Dump registers for debugfs. | 
|  | 503 | */ | 
|  | 504 | static inline void isp116x_show_regs_seq(struct isp116x *isp116x, | 
|  | 505 | struct seq_file *s) | 
| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 506 | { | 
| Olav Kongas | 959eea2 | 2005-11-03 17:38:14 +0200 | [diff] [blame] | 507 | isp116x_show_regs(isp116x, seq, s); | 
|  | 508 | } | 
|  | 509 |  | 
|  | 510 | /* | 
|  | 511 | Dump registers to syslog. | 
|  | 512 | */ | 
|  | 513 | static inline void isp116x_show_regs_log(struct isp116x *isp116x) | 
|  | 514 | { | 
|  | 515 | isp116x_show_regs(isp116x, log, NULL); | 
| Olav Kongas | 4808a1c | 2005-04-09 22:57:39 +0300 | [diff] [blame] | 516 | } | 
|  | 517 |  | 
|  | 518 | #if defined(URB_TRACE) | 
|  | 519 |  | 
|  | 520 | #define PIPETYPE(pipe)  ({ char *__s;			\ | 
|  | 521 | if (usb_pipecontrol(pipe))	__s = "ctrl";	\ | 
|  | 522 | else if (usb_pipeint(pipe))	__s = "int";	\ | 
|  | 523 | else if (usb_pipebulk(pipe))	__s = "bulk";	\ | 
|  | 524 | else				__s = "iso";	\ | 
|  | 525 | __s;}) | 
|  | 526 | #define PIPEDIR(pipe)   ({ usb_pipein(pipe) ? "in" : "out"; }) | 
|  | 527 | #define URB_NOTSHORT(urb) ({ (urb)->transfer_flags & URB_SHORT_NOT_OK ? \ | 
|  | 528 | "short_not_ok" : ""; }) | 
|  | 529 |  | 
|  | 530 | /* print debug info about the URB */ | 
|  | 531 | static void urb_dbg(struct urb *urb, char *msg) | 
|  | 532 | { | 
|  | 533 | unsigned int pipe; | 
|  | 534 |  | 
|  | 535 | if (!urb) { | 
|  | 536 | DBG("%s: zero urb\n", msg); | 
|  | 537 | return; | 
|  | 538 | } | 
|  | 539 | pipe = urb->pipe; | 
|  | 540 | DBG("%s: FA %d ep%d%s %s: len %d/%d %s\n", msg, | 
|  | 541 | usb_pipedevice(pipe), usb_pipeendpoint(pipe), | 
|  | 542 | PIPEDIR(pipe), PIPETYPE(pipe), | 
|  | 543 | urb->transfer_buffer_length, urb->actual_length, URB_NOTSHORT(urb)); | 
|  | 544 | } | 
|  | 545 |  | 
|  | 546 | #else | 
|  | 547 |  | 
|  | 548 | #define  urb_dbg(urb,msg)   do{}while(0) | 
|  | 549 |  | 
|  | 550 | #endif				/* ! defined(URB_TRACE) */ | 
|  | 551 |  | 
|  | 552 | #if defined(PTD_TRACE) | 
|  | 553 |  | 
|  | 554 | #define PTD_DIR_STR(ptd)  ({char __c;		\ | 
|  | 555 | switch(PTD_GET_DIR(ptd)){		\ | 
|  | 556 | case 0:  __c = 's'; break;		\ | 
|  | 557 | case 1:  __c = 'o'; break;		\ | 
|  | 558 | default: __c = 'i'; break;		\ | 
|  | 559 | }; __c;}) | 
|  | 560 |  | 
|  | 561 | /* | 
|  | 562 | Dump PTD info. The code documents the format | 
|  | 563 | perfectly, right :) | 
|  | 564 | */ | 
|  | 565 | static inline void dump_ptd(struct ptd *ptd) | 
|  | 566 | { | 
|  | 567 | printk("td: %x %d%c%d %d,%d,%d  %x %x%x%x\n", | 
|  | 568 | PTD_GET_CC(ptd), PTD_GET_FA(ptd), | 
|  | 569 | PTD_DIR_STR(ptd), PTD_GET_EP(ptd), | 
|  | 570 | PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd), | 
|  | 571 | PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd), | 
|  | 572 | PTD_GET_SPD(ptd), PTD_GET_LAST(ptd)); | 
|  | 573 | } | 
|  | 574 |  | 
|  | 575 | static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf) | 
|  | 576 | { | 
|  | 577 | int k; | 
|  | 578 |  | 
|  | 579 | if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) { | 
|  | 580 | printk("-> "); | 
|  | 581 | for (k = 0; k < PTD_GET_LEN(ptd); ++k) | 
|  | 582 | printk("%02x ", ((u8 *) buf)[k]); | 
|  | 583 | printk("\n"); | 
|  | 584 | } | 
|  | 585 | } | 
|  | 586 |  | 
|  | 587 | static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf) | 
|  | 588 | { | 
|  | 589 | int k; | 
|  | 590 |  | 
|  | 591 | if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) { | 
|  | 592 | printk("<- "); | 
|  | 593 | for (k = 0; k < PTD_GET_COUNT(ptd); ++k) | 
|  | 594 | printk("%02x ", ((u8 *) buf)[k]); | 
|  | 595 | printk("\n"); | 
|  | 596 | } | 
|  | 597 | if (PTD_GET_LAST(ptd)) | 
|  | 598 | printk("-\n"); | 
|  | 599 | } | 
|  | 600 |  | 
|  | 601 | #else | 
|  | 602 |  | 
|  | 603 | #define dump_ptd(ptd)               do{}while(0) | 
|  | 604 | #define dump_ptd_in_data(ptd,buf)   do{}while(0) | 
|  | 605 | #define dump_ptd_out_data(ptd,buf)  do{}while(0) | 
|  | 606 |  | 
|  | 607 | #endif				/* ! defined(PTD_TRACE) */ |