m3dev

cortex m3 debug tools -- superceded by mdebug
git clone http://frotz.net/git/m3dev.git
Log | Files | Refs | README | LICENSE

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