usb-v1.c (12839B)
1 /* usb.c 2 * 3 * Copyright 2011 Brian Swetland <swetland@frotz.net> 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <fw/types.h> 19 #include <fw/lib.h> 20 #include <fw/io.h> 21 22 #include <arch/hardware.h> 23 #include <arch/cpu.h> 24 #include <protocol/usb.h> 25 26 #include "usb-v1.h" 27 28 #if CONFIG_USB_TRACE 29 #define P(x...) printx(x) 30 #else 31 #define P(x...) 32 #endif 33 34 #ifndef CONFIG_USB_USE_IRQS 35 #define enable_interrupts() do {} while (0) 36 #define disable_interrupts() do {} while (0) 37 #endif 38 39 static volatile unsigned msec_counter = 0; 40 41 void usb_handle_irq(void); 42 43 static u8 _dev00[] = { 44 18, /* size */ 45 DSC_DEVICE, 46 0x10, 0x01, /* version */ 47 0xFF, /* class */ 48 0x00, /* subclass */ 49 0x00, /* protocol */ 50 0x40, /* maxpacket0 */ 51 0xd1, 0x18, /* VID */ 52 0x02, 0x65, /* PID */ 53 0x10, 0x01, /* version */ 54 0x00, /* manufacturer string */ 55 0x00, /* product string */ 56 0x00, /* serialno string */ 57 0x01, /* configurations */ 58 }; 59 60 static u8 _cfg00[] = { 61 9, 62 DSC_CONFIG, 63 #if CONFIG_USB_2ND_IFC 64 0x37, 0x00, /* total length */ 65 0x02, /* ifc count */ 66 #else 67 0x20, 0x00, /* total length */ 68 0x01, /* ifc count */ 69 #endif 70 0x01, /* configuration value */ 71 0x00, /* configuration string */ 72 0x80, /* attributes */ 73 50, /* mA/2 */ 74 75 9, 76 DSC_INTERFACE, 77 0x00, /* interface number */ 78 0x00, /* alt setting */ 79 0x02, /* ept count */ 80 0xFF, /* class */ 81 0x00, /* subclass */ 82 0x00, /* protocol */ 83 0x00, /* interface string */ 84 85 7, 86 DSC_ENDPOINT, 87 0x81, /* address */ 88 0x02, /* bulk */ 89 0x40, 0x00, /* max packet size */ 90 0x00, /* interval */ 91 92 7, 93 DSC_ENDPOINT, 94 0x01, /* address */ 95 0x02, /* bulk */ 96 0x40, 0x00, /* max packet size */ 97 0x00, /* interval */ 98 99 #if CONFIG_USB_2ND_IFC 100 9, 101 DSC_INTERFACE, 102 0x01, /* interface number */ 103 0x00, /* alt setting */ 104 0x02, /* ept count */ 105 0xFF, /* class */ 106 0x00, /* subclass */ 107 0x00, /* protocol */ 108 0x00, /* interface string */ 109 110 7, 111 DSC_ENDPOINT, 112 0x82, /* address */ 113 0x02, /* bulk */ 114 0x40, 0x00, /* max packet size */ 115 0x00, /* interval */ 116 117 7, 118 DSC_ENDPOINT, 119 0x02, /* address */ 120 0x02, /* bulk */ 121 0x40, 0x00, /* max packet size */ 122 0x00, /* interval */ 123 #endif 124 }; 125 126 #if CONFIG_USB_STRINGS 127 const static u8 lang_id[] = { 128 4, 129 DSC_STRING, 130 0x09, 0x04 131 }; 132 133 static u16 mfg_string[24] = { 134 }; 135 136 static u16 prod_string[24] = { 137 }; 138 #endif 139 140 static void write_sie_cmd(unsigned cmd) { 141 writel(USB_INT_CC_EMPTY, USB_INT_CLEAR); 142 writel(cmd | USB_OP_COMMAND, USB_CMD_CODE); 143 while (!(readl(USB_INT_STATUS) & USB_INT_CC_EMPTY)) ; 144 writel(USB_INT_CC_EMPTY, USB_INT_CLEAR); 145 } 146 147 static void write_sie(unsigned cmd, unsigned data) { 148 write_sie_cmd(cmd); 149 writel((data << 16) | USB_OP_WRITE, USB_CMD_CODE); 150 while (!(readl(USB_INT_STATUS) & USB_INT_CC_EMPTY)) ; 151 writel(USB_INT_CC_EMPTY, USB_INT_CLEAR); 152 } 153 154 static unsigned read_sie(unsigned cmd) { 155 unsigned n; 156 write_sie_cmd(cmd); 157 writel(cmd | USB_OP_READ, USB_CMD_CODE); 158 while (!(readl(USB_INT_STATUS) & USB_INT_CD_FULL)) ; 159 n = readl(USB_CMD_DATA); 160 writel(USB_INT_CC_EMPTY | USB_INT_CD_FULL, USB_INT_CLEAR); 161 return n; 162 } 163 164 static void usb_ep0_send(const void *_data, int len, int rlen) { 165 const u32 *data = _data; 166 167 if (len > rlen) 168 len = rlen; 169 writel(USB_CTRL_WR_EN | USB_CTRL_EP_NUM(0), USB_CTRL); 170 writel(len, USB_TX_PLEN); 171 while (len > 0) { 172 writel(*data++, USB_TX_DATA); 173 len -= 4; 174 } 175 writel(0, USB_CTRL); 176 write_sie_cmd(USB_CC_SEL_EPT(1)); 177 write_sie_cmd(USB_CC_VAL_BUFFER); 178 } 179 180 static void usb_ep0_send0(void) { 181 writel(USB_CTRL_WR_EN | USB_CTRL_EP_NUM(0), USB_CTRL); 182 writel(0, USB_TX_PLEN); 183 writel(0, USB_CTRL); 184 write_sie_cmd(USB_CC_SEL_EPT(1)); 185 write_sie_cmd(USB_CC_VAL_BUFFER); 186 } 187 188 #define EP0_TX_ACK_ADDR 0 /* sending ACK, then changing address */ 189 #define EP0_TX_ACK 1 /* sending ACK */ 190 #define EP0_RX_ACK 2 /* receiving ACK */ 191 #define EP0_TX 3 /* sending data */ 192 #define EP0_RX 4 /* receiving data */ 193 #define EP0_IDLE 5 /* waiting for SETUP */ 194 195 static u8 ep0state; 196 static u8 newaddr; 197 198 static volatile int _usb_online = 0; 199 200 static void usb_ep0_rx_setup(void) { 201 unsigned c,n; 202 u16 req, val, idx, len; 203 204 do { 205 writel(USB_CTRL_RD_EN | USB_CTRL_EP_NUM(0), USB_CTRL); 206 /* to ensure PLEN is valid */ 207 asm("nop"); asm("nop"); asm("nop"); 208 asm("nop"); asm("nop"); asm("nop"); 209 c = readl(USB_RX_PLEN) & 0x1FF; 210 n = readl(USB_RX_DATA); 211 req = n; 212 val = n >> 16; 213 n = readl(USB_RX_DATA); 214 idx = n; 215 len = n >> 16; 216 writel(0, USB_CTRL); 217 /* bit 1 will be set if another SETUP arrived... */ 218 n = read_sie(USB_CC_CLR_BUFFER); 219 } while (n & 1); 220 221 switch (req) { 222 case GET_STATUS: { 223 u16 status = 0; 224 usb_ep0_send(&status, sizeof(status), len); 225 ep0state = EP0_RX; 226 break; 227 } 228 case GET_DESCRIPTOR: 229 if (val == 0x0100) { 230 usb_ep0_send(_dev00, sizeof(_dev00), len); 231 } else if (val == 0x0200) { 232 usb_ep0_send(_cfg00, sizeof(_cfg00), len); 233 #if CONFIG_USB_STRINGS 234 } else if (val == 0x0300) { 235 usb_ep0_send(lang_id, sizeof(lang_id), len); 236 } else if (val == 0x0301) { 237 usb_ep0_send(mfg_string, mfg_string[0] & 0xff, len); 238 } else if (val == 0x0302) { 239 usb_ep0_send(prod_string, prod_string[0] & 0xff, len); 240 #endif 241 } else { 242 goto stall; 243 } 244 ep0state = EP0_RX; 245 break; 246 case SET_ADDRESS: 247 usb_ep0_send0(); 248 ep0state = EP0_TX_ACK_ADDR; 249 newaddr = val & 0x7F; 250 break; 251 case SET_CONFIGURATION: 252 write_sie(USB_CC_CONFIG_DEV, (val == 1) ? 1 : 0); 253 _usb_online = (val == 1); 254 usb_ep0_send0(); 255 if (usb_online_cb) 256 usb_online_cb(_usb_online); 257 ep0state = EP0_TX_ACK; 258 break; 259 default: 260 goto stall; 261 } 262 263 return; 264 265 stall: 266 /* stall */ 267 write_sie(USB_CC_SET_EPT(0), 0x80); 268 //P("? %h %h %h %h\n", req, val, idx, len); 269 } 270 271 static void usb_ep0_rx(void) { 272 unsigned n; 273 n = read_sie(USB_CC_CLR_EPT(0)); 274 if (n & 1) { 275 usb_ep0_rx_setup(); 276 } else { 277 } 278 } 279 280 void usb_ep0_tx(void) { 281 unsigned n; 282 n = read_sie(USB_CC_CLR_EPT(1)); 283 if (ep0state == EP0_TX_ACK_ADDR) { 284 write_sie(USB_CC_SET_ADDR, 0x80 | newaddr); 285 write_sie(USB_CC_SET_ADDR, 0x80 | newaddr); 286 } 287 ep0state = EP0_IDLE; 288 } 289 290 int usb_recv(void *_data, int count) { 291 return usb_recv_timeout(_data, count, 0); 292 } 293 294 int usb_online(void) { 295 usb_handle_irq(); 296 return _usb_online; 297 } 298 299 static int usb_epN_read(unsigned ep, void *_data, int len) { 300 unsigned n; 301 int sz; 302 u32 *data; 303 304 if (len > 64) 305 return -EFAIL; 306 if (!_usb_online) 307 return -ENODEV; 308 309 data = _data; 310 311 disable_interrupts(); 312 313 n = read_sie(USB_CC_CLR_EPT(ep << 1)); 314 if (!(n & 1)) { 315 enable_interrupts(); 316 return -EBUSY; 317 } 318 319 writel(USB_CTRL_RD_EN | USB_CTRL_EP_NUM(ep), USB_CTRL); 320 /* to ensure PLEN is valid */ 321 asm("nop"); asm("nop"); asm("nop"); 322 asm("nop"); asm("nop"); asm("nop"); 323 sz = readl(USB_RX_PLEN) & 0x1FF; 324 325 if (sz > len) 326 sz = len; 327 328 while (len > 0) { 329 *data++ = readl(USB_RX_DATA); 330 len -= 4; 331 } 332 333 writel(0, USB_CTRL); 334 n = read_sie(USB_CC_CLR_BUFFER); 335 336 enable_interrupts(); 337 338 return sz; 339 } 340 341 int usb_ep1_read(void *_data, int len) { 342 return usb_epN_read(1, _data, len); 343 } 344 345 #if CONFIG_USB_2ND_IFC 346 int usb_ep2_read(void *_data, int len) { 347 return usb_epN_read(2, _data, len); 348 } 349 #endif 350 351 int usb_recv_timeout(void *_data, int count, unsigned timeout) { 352 int r, rx; 353 u8 *data; 354 355 data = _data; 356 rx = 0; 357 msec_counter = 0; 358 359 /* if offline, wait for us to go online */ 360 while (!_usb_online) 361 usb_handle_irq(); 362 363 while (count > 0) { 364 r = usb_ep1_read(data, (count > 64) ? 64 : count); 365 366 if (r >= 0) { 367 rx += r; 368 data += r; 369 count -= r; 370 /* terminate on short packet */ 371 if (r != 64) 372 break; 373 } else if (r == -EBUSY) { 374 if (timeout && (msec_counter > timeout)) 375 return -ETIMEOUT; 376 usb_handle_irq(); 377 } else { 378 return r; 379 } 380 } 381 return rx; 382 } 383 384 static int usb_epN_write(unsigned ep, void *_data, int len) { 385 unsigned n; 386 u32 *data; 387 388 if (len > 64) 389 return -EFAIL; 390 if (!_usb_online) 391 return -ENODEV; 392 393 disable_interrupts(); 394 395 data = _data; 396 n = read_sie(USB_CC_CLR_EPT((ep << 1) + 1)); 397 if (n & 1) { 398 enable_interrupts(); 399 return -EBUSY; 400 } 401 402 writel(USB_CTRL_WR_EN | USB_CTRL_EP_NUM(ep), USB_CTRL); 403 writel(len, USB_TX_PLEN); 404 while (len > 0) { 405 writel(*data++, USB_TX_DATA); 406 len -= 4; 407 } 408 writel(0, USB_CTRL); 409 410 n = read_sie(USB_CC_SEL_EPT((ep << 1) + 1)); 411 n = read_sie(USB_CC_VAL_BUFFER); 412 413 enable_interrupts(); 414 415 return 0; 416 } 417 418 int usb_ep1_write(void *_data, int len) { 419 return usb_epN_write(1, _data, len); 420 } 421 422 #if CONFIG_USB_2ND_IFC 423 int usb_ep2_write(void *_data, int len) { 424 return usb_epN_write(2, _data, len); 425 } 426 #endif 427 428 int usb_xmit(void *_data, int len) { 429 int r, tx, xfer; 430 u8 *data; 431 432 data = _data; 433 tx = 0; 434 435 while (len > 0) { 436 xfer = (len > 64) ? 64 : len; 437 r = usb_ep1_write(data, xfer); 438 if (r < 0) { 439 if (r == -EBUSY) { 440 usb_handle_irq(); 441 continue; 442 } 443 return r; 444 } 445 tx += xfer; 446 len -= xfer; 447 data += xfer; 448 } 449 return tx; 450 } 451 452 void usb_init(unsigned vid, unsigned pid, const char *mfg, const char *prod) { 453 unsigned n; 454 455 ep0state = EP0_IDLE; 456 457 _dev00[8] = vid; 458 _dev00[9] = vid >> 8; 459 _dev00[10] = pid; 460 _dev00[11] = pid >> 8; 461 462 #if CONFIG_USB_STRINGS 463 if (mfg) { 464 int i; 465 for (i = 0; mfg[i] != 0 && i < ((sizeof(mfg_string) / 2) - 1); i++) { 466 mfg_string[i+1] = mfg[i]; 467 } 468 mfg_string[0] = (DSC_STRING << 8) | ((i * 2) + 2); 469 470 _dev00[14] = 1; 471 } 472 if (prod) { 473 int i; 474 for (i = 0; prod[i] != 0 && i < ((sizeof(prod_string) / 2) - 1); i++) { 475 prod_string[i+1] = prod[i]; 476 } 477 prod_string[0] = (DSC_STRING << 8) | ((i * 2) + 2); 478 479 _dev00[15] = 2; 480 } 481 #endif 482 483 /* SYSCLK to USB REG domain */ 484 writel(readl(SYS_CLK_CTRL) | SYS_CLK_USB_REG, SYS_CLK_CTRL); 485 486 /* power on USB PHY and USB PLL */ 487 writel(readl(0x40048238) & (~(1 << 10)), 0x40048238); 488 writel(readl(0x40048238) & (~(1 << 8)), 0x40048238); 489 490 /* wait for power */ 491 for (n = 0; n < 10000; n++) asm("nop"); 492 493 /* configure external IO mapping */ 494 writel(IOCON_FUNC_1 | IOCON_DIGITAL, IOCON_PIO0_3); /* USB_VBUS */ 495 writel(IOCON_FUNC_1 | IOCON_DIGITAL, IOCON_PIO0_6); /* USB_CONNECTn */ 496 497 write_sie(USB_CC_SET_ADDR, 0x80); /* ADDR=0, EN=1 */ 498 write_sie(USB_CC_SET_DEV_STATUS, 0x01); /* CONNECT */ 499 500 writel(USB_INT_EP0 | USB_INT_EP1, USB_INT_ENABLE); 501 } 502 503 void usb_stop(void) { 504 write_sie(USB_CC_SET_ADDR, 0); 505 write_sie(USB_CC_SET_DEV_STATUS, 0); 506 } 507 508 void usb_mask_ep1_rx_full(void) { 509 disable_interrupts(); 510 writel(readl(USB_INT_ENABLE) & (~USB_INT_EP2), USB_INT_ENABLE); 511 enable_interrupts(); 512 } 513 void usb_unmask_ep1_rx_full(void) { 514 disable_interrupts(); 515 writel(readl(USB_INT_ENABLE) | USB_INT_EP2, USB_INT_ENABLE); 516 enable_interrupts(); 517 } 518 519 void usb_mask_ep1_tx_empty(void) { 520 disable_interrupts(); 521 writel(readl(USB_INT_ENABLE) & (~USB_INT_EP3), USB_INT_ENABLE); 522 enable_interrupts(); 523 } 524 void usb_unmask_ep1_tx_empty(void) { 525 disable_interrupts(); 526 writel(readl(USB_INT_ENABLE) | USB_INT_EP3, USB_INT_ENABLE); 527 enable_interrupts(); 528 } 529 530 #if CONFIG_USB_2ND_IFC 531 void usb_mask_ep2_rx_full(void) { 532 disable_interrupts(); 533 writel(readl(USB_INT_ENABLE) & (~USB_INT_EP4), USB_INT_ENABLE); 534 enable_interrupts(); 535 } 536 void usb_unmask_ep2_rx_full(void) { 537 disable_interrupts(); 538 writel(readl(USB_INT_ENABLE) | USB_INT_EP4, USB_INT_ENABLE); 539 enable_interrupts(); 540 } 541 542 void usb_mask_ep2_tx_empty(void) { 543 disable_interrupts(); 544 writel(readl(USB_INT_ENABLE) & (~USB_INT_EP5), USB_INT_ENABLE); 545 enable_interrupts(); 546 } 547 void usb_unmask_ep2_tx_empty(void) { 548 disable_interrupts(); 549 writel(readl(USB_INT_ENABLE) | USB_INT_EP5, USB_INT_ENABLE); 550 enable_interrupts(); 551 } 552 #endif 553 554 void (*usb_ep1_rx_full_cb)(void); 555 void (*usb_ep1_tx_empty_cb)(void); 556 #if CONFIG_USB_2ND_IFC 557 void (*usb_ep2_rx_full_cb)(void); 558 void (*usb_ep2_tx_empty_cb)(void); 559 #endif 560 void (*usb_online_cb)(int online); 561 562 volatile int USB_IRQ_COUNT = 0; 563 564 void usb_handle_irq(void) { 565 unsigned n; 566 567 USB_IRQ_COUNT++; 568 569 // P("usb %x\n", USB_IRQ_COUNT); 570 571 n = readl(USB_INT_STATUS); 572 //writel(n & (USB_INT_EP0 | USB_INT_EP1), USB_INT_CLEAR); 573 writel(n, USB_INT_CLEAR); 574 if (n & USB_INT_FRAME) 575 msec_counter++; 576 if (n & USB_INT_EP0) 577 usb_ep0_rx(); 578 if (n & USB_INT_EP1) 579 usb_ep0_tx(); 580 581 /* ignore masked interrupts */ 582 n &= readl(USB_INT_ENABLE); 583 584 if (n & ~(USB_INT_FRAME)) { 585 // P("usb n 0x%x\n", n); 586 } 587 588 if ((n & USB_INT_EP2) && usb_ep1_rx_full_cb) 589 usb_ep1_rx_full_cb(); 590 if ((n & USB_INT_EP3) && usb_ep1_tx_empty_cb) 591 usb_ep1_tx_empty_cb(); 592 #if CONFIG_USB_2ND_IFC 593 if ((n & USB_INT_EP4) && usb_ep2_rx_full_cb) 594 usb_ep2_rx_full_cb(); 595 if ((n & USB_INT_EP5) && usb_ep2_tx_empty_cb) 596 usb_ep2_tx_empty_cb(); 597 #endif 598 } 599 600 #if CONFIG_USB_USE_IRQS 601 void handle_irq_usb_irq(void) { 602 usb_handle_irq(void) { 603 } 604 #endif