예제 #1
0
void usb_stream_reset(struct usb_stream_config const *config)
{
	config->out_desc->flags = DOEPDMA_RXBYTES(config->tx_size) |
				  DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY |
				  DOEPDMA_IOC;
	config->out_desc->addr = config->rx_ram;
	GR_USB_DOEPDMA(config->endpoint) = (uint32_t)config->out_desc;
	config->in_desc->flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY |
				 DIEPDMA_IOC;
	config->in_desc->addr = config->tx_ram;
	GR_USB_DIEPDMA(config->endpoint) = (uint32_t)config->in_desc;
	GR_USB_DOEPCTL(config->endpoint) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
					   DXEPCTL_EPTYPE_BULK |
					   DXEPCTL_CNAK | DXEPCTL_EPENA;
	GR_USB_DIEPCTL(config->endpoint) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
					   DXEPCTL_EPTYPE_BULK |
					   DXEPCTL_TXFNUM(config->endpoint);
	GR_USB_DAINTMSK |= DAINT_INEP(config->endpoint) |
			   DAINT_OUTEP(config->endpoint);

	*config->is_reset = 1;

	/* Flush any queued data */
	hook_call_deferred(config->deferred_tx, 0);
	hook_call_deferred(config->deferred_rx, 0);
}
예제 #2
0
파일: usb.c 프로젝트: coreboot/chrome-ec
static void showregs(void)
{
	ccprintf("GINTSTS:   0x%08x\n", GR_USB_GINTSTS);
	showbits(GR_USB_GINTSTS);
	ccprintf("GINTMSK:   0x%08x\n", GR_USB_GINTMSK);
	showbits(GR_USB_GINTMSK);
	ccprintf("DAINT:     0x%08x\n", GR_USB_DAINT);
	ccprintf("DAINTMSK:  0x%08x\n", GR_USB_DAINTMSK);
	ccprintf("DOEPMSK:   0x%08x\n", GR_USB_DOEPMSK);
	ccprintf("DIEPMSK:   0x%08x\n", GR_USB_DIEPMSK);
	ccprintf("DCFG:      0x%08x\n", GR_USB_DCFG);
	ccprintf("DOEPCTL0:  0x%08x\n", GR_USB_DOEPCTL(0));
	ccprintf("DIEPCTL0:  0x%08x\n", GR_USB_DIEPCTL(0));
	ccprintf("DOEPCTL1:  0x%08x\n", GR_USB_DOEPCTL(1));
	ccprintf("DIEPCTL1:  0x%08x\n", GR_USB_DIEPCTL(1));
	ccprintf("DOEPCTL2:  0x%08x\n", GR_USB_DOEPCTL(2));
	ccprintf("DIEPCTL2:  0x%08x\n", GR_USB_DIEPCTL(2));
}
예제 #3
0
파일: usb.c 프로젝트: coreboot/chrome-ec
/* No Data phase, just Status phase (which is IN, since Setup is OUT) */
static void expect_status_phase_in(enum table_case tc)
{
	print_later("expect_status_phase_in(%c)", "0ABCDE67"[tc], 0, 0, 0, 0);

	what_am_i_doing = NO_DATA_STAGE;

	/* Expect a zero-length IN for the Status phase */
	(void) load_in_fifo(0, 0);

	/* We apparently have to do this every time we transmit anything */
	flush_in_fifo();

	/* I don't think we have to do this every time, but the Programmer's
	 * Guide says to, so...	*/
	GR_USB_DIEPDMA(0) = (uint32_t)(cur_in_desc);

	/* Blindly following instructions here, too. */
	if (tc == TABLE_CASE_C)
		GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;

	/* The Programmer's Guide instructions for the Normal Two-Stage Control
	 * Transfer leave this next bit out, so we only need it if we intend to
	 * process an Exceptional Two-Stage Control Transfer. Because obviously
	 * we always know in advance what the host is going to do. Idiots. */

	/* Be prepared to get a new Setup packet during the Status phase */
	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* We've already set GR_USB_DOEPDMA(0), so just enable it. */
	if (tc == TABLE_CASE_C)
		GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DOEPCTL(0) = DXEPCTL_EPENA;

	/* Get an interrupt when either IN or OUT arrives */
	GR_USB_DAINTMSK |= (DAINT_OUTEP(0) | DAINT_INEP(0));
}
예제 #4
0
파일: usb.c 프로젝트: coreboot/chrome-ec
/* The TX FIFO buffer is loaded. Start the Data phase. */
static void expect_data_phase_in(enum table_case tc)
{
	print_later("expect_data_phase_in(%c)", "0ABCDE67"[tc], 0, 0, 0, 0);

	what_am_i_doing = DATA_STAGE_IN;

	/* We apparently have to do this every time we transmit anything */
	flush_in_fifo();

	/* I don't think we have to do this every time, but the Programmer's
	 * Guide says to, so...	*/
	GR_USB_DIEPDMA(0) = (uint32_t)(cur_in_desc);

	/* Blindly following instructions here, too. */
	if (tc == TABLE_CASE_C)
		GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;

	/*
	 * When the IN is done, we expect a zero-length OUT for the status
	 * phase but it could be an early SETUP instead. We'll have to deal
	 * with either one when it arrives.
	 */
	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* And here's this jimmy rustler again... */
	if (tc == TABLE_CASE_C)
		GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
	else
		GR_USB_DOEPCTL(0) = DXEPCTL_EPENA;

	/* Get an interrupt when either IN or OUT arrives */
	GR_USB_DAINTMSK |= (DAINT_OUTEP(0) | DAINT_INEP(0));

}
예제 #5
0
/* Let the USB HW OUT-from-host FIFO receive some bytes */
static void usb_enable_rx(int len)
{
	struct dwc_usb_ep *ep = &ep_console_ctl;

	ep->out_data = ep->out_databuffer;
	ep->out_pending = 0;

	GR_USB_DOEPTSIZ(USB_EP_CONSOLE) = 0;
	GR_USB_DOEPTSIZ(USB_EP_CONSOLE) |= DXEPTSIZ_PKTCNT(1);
	GR_USB_DOEPTSIZ(USB_EP_CONSOLE) |= DXEPTSIZ_XFERSIZE(len);
	GR_USB_DOEPDMA(USB_EP_CONSOLE) = (uint32_t)ep->out_data;

	GR_USB_DOEPCTL(USB_EP_CONSOLE) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
예제 #6
0
파일: usb.c 프로젝트: coreboot/chrome-ec
/* The next packet from the host should be a Setup packet. Get ready for it. */
static void expect_setup_packet(void)
{
	print_later("expect_setup_packet()", 0, 0, 0, 0, 0);

	what_am_i_doing = WAITING_FOR_SETUP_PACKET;

	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* We don't care about IN packets right now, only OUT. */
	GR_USB_DAINTMSK |= DAINT_OUTEP(0);
	GR_USB_DAINTMSK &= ~DAINT_INEP(0);

	/* Let it run. We might need CNAK if we just got an OUT for status */
	GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
}
예제 #7
0
파일: usb.c 프로젝트: coreboot/chrome-ec
/* We're complaining about something by stalling both IN and OUT packets,
 * but a SETUP packet will get through anyway, so prepare for it. */
static void stall_both_fifos(void)
{
	print_later("stall_both_fifos()", 0, 0, 0, 0, 0);

	what_am_i_doing = WAITING_FOR_SETUP_PACKET;

	next_out_desc->flags =
		DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE)
		| DOEPDMA_IOC | DOEPDMA_LAST;

	/* We don't care about IN packets right now, only OUT. */
	GR_USB_DAINTMSK |= DAINT_OUTEP(0);
	GR_USB_DAINTMSK &= ~DAINT_INEP(0);

	/* Stall both IN and OUT. The hardware will reset them when the next
	 * SETUP comes along. */
	GR_USB_DOEPCTL(0) = DXEPCTL_STALL | DXEPCTL_EPENA;
	flush_in_fifo();
	GR_USB_DIEPCTL(0) = DXEPCTL_STALL | DXEPCTL_EPENA;
}
예제 #8
0
/* Rx/OUT interrupt handler */
static void con_ep_rx(void)
{
	struct dwc_usb_ep *ep = &ep_console_ctl;

	if (GR_USB_DOEPCTL(USB_EP_CONSOLE) & DXEPCTL_EPENA)
		return;

	/* Bytes received decrement DOEPTSIZ XFERSIZE */
	if (GR_USB_DOEPINT(USB_EP_CONSOLE) & DOEPINT_XFERCOMPL) {
		ep->out_pending =
			ep->max_packet -
			(GR_USB_DOEPTSIZ(USB_EP_CONSOLE) &
			 GC_USB_DOEPTSIZ1_XFERSIZE_MASK);
	}

	/* Wake up the Rx FIFO handler */
	hook_call_deferred(&rx_fifo_handler_data, 0);

	/* clear the RX/OUT interrupts */
	GR_USB_DOEPINT(USB_EP_CONSOLE) = 0xffffffff;
}
예제 #9
0
static void ep_reset(void)
{
	ep_out_desc.flags = DOEPDMA_RXBYTES(USB_MAX_PACKET_SIZE) |
			    DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
	ep_out_desc.addr = ep_buf_rx;
	GR_USB_DOEPDMA(USB_EP_BLOB) = (uint32_t)&ep_out_desc;
	ep_in_desc.flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY | DIEPDMA_IOC;
	ep_in_desc.addr = ep_buf_tx;
	GR_USB_DIEPDMA(USB_EP_BLOB) = (uint32_t)&ep_in_desc;
	GR_USB_DOEPCTL(USB_EP_BLOB) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
					 DXEPCTL_EPTYPE_BULK |
					 DXEPCTL_CNAK | DXEPCTL_EPENA;
	GR_USB_DIEPCTL(USB_EP_BLOB) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
					 DXEPCTL_EPTYPE_BULK |
					 DXEPCTL_TXFNUM(USB_EP_BLOB);
	GR_USB_DAINTMSK |= (1<<USB_EP_BLOB) | (1 << (USB_EP_BLOB+16));

	is_reset = 1;

	/* Flush any queued data */
	hook_call_deferred(tx_fifo_handler, 0);
	hook_call_deferred(rx_fifo_handler, 0);
}
예제 #10
0
파일: usb.c 프로젝트: coreboot/chrome-ec
/* This handles both IN and OUT interrupts for EP0 */
static void ep0_interrupt(uint32_t intr_on_out, uint32_t intr_on_in)
{
	uint32_t doepint, diepint;
	enum table_case tc;
	int sr;

	/* Determine the interrupt cause and clear the bits quickly, but only
	 * if they really apply. I don't think they're trustworthy if we didn't
	 * actually get an interrupt. */
	doepint = GR_USB_DOEPINT(0);
	if (intr_on_out)
		GR_USB_DOEPINT(0) = doepint;
	diepint = GR_USB_DIEPINT(0);
	if (intr_on_in)
		GR_USB_DIEPINT(0) = diepint;

	print_later("doepint%c 0x%08x diepint%c 0x%08x what %d",
		    intr_on_out ? '!' : '_', doepint,
		    intr_on_in ? '!' : '_', diepint,
		    what_am_i_doing);

	/* Update current and pending RX FIFO buffers */
	if (intr_on_out && (doepint & DOEPINT_XFERCOMPL))
		got_RX_packet();

	/* Decode the situation according to Table 10-7 */
	tc = decode_table_10_7(doepint);
	sr = cur_out_desc->flags & DOEPDMA_SR;

	print_later("cur_out_idx %d flags 0x%08x case=%c SR=%d",
		    cur_out_idx, cur_out_desc->flags,
		    "0ABCDE67"[tc], !!sr, 0);

	switch (what_am_i_doing) {
	case WAITING_FOR_SETUP_PACKET:
		if (tc == TABLE_CASE_A || tc == TABLE_CASE_C) {
			if (sr) {
				handle_setup(tc);
			} else {
				report_error(tc);
				print_later("next_out_idx %d flags 0x%08x",
					    next_out_idx, next_out_desc->flags,
					    0, 0, 0);
				expect_setup_packet();
			}
		}
		/* This only happens if we're stalling, so keep doing it. */
		if (tc == TABLE_CASE_B) {
			print_later("Still waiting for Setup...",
				    0, 0, 0, 0, 0);
			stall_both_fifos();
		}
		break;

	case DATA_STAGE_IN:
		if (intr_on_in && (diepint & DIEPINT_XFERCOMPL)) {
			print_later("IN is complete? Maybe? How do we know?",
				    0, 0, 0, 0, 0);
			/* I don't *think* we need to do this, unless we need
			 * to transfer more data. Customer support agrees and
			 * it shouldn't matter if the host is well-behaved, but
			 * it seems like we had issues without it.
			 * TODO: Test this case until we know for sure. */
			GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;

			/*
			 * The Programmer's Guide says (p291) to stall any
			 * further INs, but that's stupid because it'll destroy
			 * the packet we just transferred to SPRAM, so don't do
			 * that (we tried it anyway, and Bad Things happened).
			 * Also don't stop here, but keep looking at stuff.
			 */
		}

		/* But we should ignore the OUT endpoint if we didn't actually
		 * get an OUT interrupt. */
		if (!intr_on_out)
			break;

		if (tc == TABLE_CASE_B) {
			print_later("IN has been detected...", 0, 0, 0, 0, 0);
			/* The first IN packet has been seen. Keep going. */
			GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			break;
		}
		if (tc == TABLE_CASE_A) {
			if (!sr) {
				/* We've handled the Status phase. All done. */
				print_later("Status phase complete",
					    0, 0, 0, 0, 0);
				expect_setup_packet();
				break;
			}
			/* We expected an OUT, but got a Setup. Deal with it. */
			print_later("Early Setup", 0, 0, 0, 0, 0);
			handle_setup(tc);
			break;
		}
		/* From the Exceptional Control Read Transfer section ... */
		if (tc == TABLE_CASE_C) {
			if (sr) {
				print_later("Early Setup w/Data packet seen",
					    0, 0, 0, 0, 0);
				handle_setup(tc);
				break;
			}
			print_later("Status phase complete. I think...",
				    0, 0, 0, 0, 0);
			expect_setup_packet();
			break;
		}

		/* Anything else should be ignorable. Right? */
		break;

	case NO_DATA_STAGE:
		if (intr_on_in && (diepint & DIEPINT_XFERCOMPL)) {
			print_later("IN descriptor processed", 0, 0, 0, 0, 0);
			/* Let the IN proceed */
			GR_USB_DIEPCTL(0) = DXEPCTL_EPENA;
		}

		/* Done unless we got an OUT interrupt */
		if (!intr_on_out)
			break;

		if (tc == TABLE_CASE_B) {
			print_later("IN has been detected...", 0, 0, 0, 0, 0);
			/* Let the IN proceed */
			GR_USB_DIEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			/* Reenable the previously prepared OUT descriptor. */
			GR_USB_DOEPCTL(0) = DXEPCTL_CNAK | DXEPCTL_EPENA;
			break;
		}

		if (tc == TABLE_CASE_A || tc == TABLE_CASE_C) {
			if (sr) {
				/* We expected an IN, but got a Setup. */
				print_later("Early Setup", 0, 0, 0, 0, 0);
				handle_setup(tc);
				break;
			}
		}

		/* Anything else means get ready for a Setup packet */
		print_later("Status phase complete. Maybe.",
			    0, 0, 0, 0, 0);
		expect_setup_packet();
		break;
	}
}
예제 #11
0
/* Let the USB HW OUT-from-host FIFO receive some bytes */
static void usb_enable_rx(struct usb_stream_config const *config, int len)
{
	config->out_desc->flags = DOEPDMA_RXBYTES(len) | DOEPDMA_LAST |
				  DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
	GR_USB_DOEPCTL(config->endpoint) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
예제 #12
0
/* Let the USB HW OUT-from-host FIFO receive some bytes */
static void usb_enable_rx(int len)
{
	ep_out_desc.flags = DOEPDMA_RXBYTES(len) |
			    DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC;
	GR_USB_DOEPCTL(USB_EP_BLOB) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}