int flash_info_read(uint32_t offset, uint32_t *dst)
{
	int retval;

	/* Make sure flash controller is awake. */
	retval = _check_flash_is_awake();
	if (retval)
		return retval;

	GWRITE_FIELD(FLASH, FSH_TRANS, OFFSET, offset);
	GWRITE_FIELD(FLASH, FSH_TRANS, MAINB, 1);
	GWRITE_FIELD(FLASH, FSH_TRANS, SIZE, 1);

	retval = _flash_cmd(1, FSH_OP_READ);
	if (retval)
		return retval;

	if (_flash_error())
		return E_FL_ERROR;

	if (!retval)
		*dst = GREG32(FLASH, FSH_DOUT_VAL1);

	return retval;
}
示例#2
0
文件: rbox.c 项目: fishbaoz/chrome-ec
void rbox_init(void)
{
	/* Enable RBOX */
	clock_enable_module(MODULE_RBOX, 1);

	/* Clear existing interrupts */
	GWRITE(RBOX, WAKEUP_CLEAR, 1);
	GWRITE(RBOX, INT_STATE, 1);

	/* Make sure fuse override is not already enabled */
	GWRITE(RBOX, FUSE_CTRL, 0);

	/* Block output from key0 and 1 when power button is pressed */
	GWRITE_FIELD(RBOX, DEBUG_BLOCK_OUTPUT, KEY0_SEL, 1);
	GWRITE_FIELD(RBOX, DEBUG_BLOCK_OUTPUT, KEY1_SEL, 1);

	/* Increase debounce */
	GWRITE_FIELD(RBOX, DEBUG_DEBOUNCE, PERIOD, 15);

	/* Enable debug override */
	GWRITE_FIELD(RBOX, FUSE_CTRL, OVERRIDE_FUSE, 1);
	GWRITE_FIELD(RBOX, FUSE_CTRL, OVERRIDE_FUSE_READY, 1);

#ifdef CONFIG_RBOX_DEBUG
	enable_interrupts();
#endif
}
示例#3
0
文件: sps.c 项目: fourier49/BZ_DEV_EC
/** Configure the data transmission format
 *
 *  @param mode Clock polarity and phase mode (0 - 3)
 *
 */
static void sps_configure(enum sps_mode mode, enum spi_clock_mode clk_mode)
{
	/* Disable All Interrupts */
	GREG32(SPS, ICTRL) = 0;

	GWRITE_FIELD(SPS, CTRL, MODE, mode);
	GWRITE_FIELD(SPS, CTRL, IDLE_LVL, 0);
	GWRITE_FIELD(SPS, CTRL, CPHA, clk_mode & 1);
	GWRITE_FIELD(SPS, CTRL, CPOL, (clk_mode >> 1) & 1);
	GWRITE_FIELD(SPS, CTRL, TXBITOR, 1); /* MSB first */
	GWRITE_FIELD(SPS, CTRL, RXBITOR, 1); /* MSB first */
	/* xfer 0xff when tx fifo is empty */
	GREG32(SPS, DUMMY_WORD) = GC_SPS_DUMMY_WORD_DEFAULT;

	/* [5,4,3]           [2,1,0]
	 * RX{DIS, EN, RST} TX{DIS, EN, RST}
	 */
	GREG32(SPS, FIFO_CTRL) = 0x9;

	/* wait for reset to self clear. */
	while (GREG32(SPS, FIFO_CTRL) & 9)
		;

	/* Do not enable TX FIFO until we have something to send. */
	GWRITE_FIELD(SPS, FIFO_CTRL, RXFIFO_EN, 1);

	GREG32(SPS, RXFIFO_THRESHOLD) = 8;

	GWRITE_FIELD(SPS, ICTRL, RXFIFO_LVL, 1);

	/* Use CS_DEASSERT to retrieve all remaining bytes from RX FIFO. */
	GWRITE_FIELD(SPS, ISTATE_CLR, CS_DEASSERT, 1);
	GWRITE_FIELD(SPS, ICTRL, CS_DEASSERT, 1);
}
示例#4
0
文件: sps.c 项目: fourier49/BZ_DEV_EC
static void sps_cs_deassert_interrupt(uint32_t port)
{
	/* Make sure the receive FIFO is drained. */
	sps_rx_interrupt(port, 1);
	GWRITE_FIELD(SPS, ISTATE_CLR, CS_DEASSERT, 1);
	GWRITE_FIELD(SPS, FIFO_CTRL, TXFIFO_EN, 0);

	/*
	 * And transmit FIFO is emptied, so the next transaction doesn't start
	 * by clocking out any bytes left over from this one.
	 */
	GREG32(SPS, TXFIFO_WPTR) = GREG32(SPS, TXFIFO_RPTR);
}
void unlockFlashForRW(void)
{
	uint32_t text_end = ((uint32_t)(&__ro_end) +
			     (uint32_t)(&__data_end) -
			     (uint32_t)(&__data_start) +
			     CONFIG_FLASH_BANK_SIZE)
		& ~(CONFIG_FLASH_BANK_SIZE - 1);

	GREG32(GLOBALSEC, FLASH_REGION1_BASE_ADDR) = text_end;
	GREG32(GLOBALSEC, FLASH_REGION1_SIZE) =
		CONFIG_FLASH_SIZE - text_end - 1;
	GWRITE_FIELD(GLOBALSEC, FLASH_REGION1_CTRL, EN, 1);
	GWRITE_FIELD(GLOBALSEC, FLASH_REGION1_CTRL, RD_EN, 1);
	GWRITE_FIELD(GLOBALSEC, FLASH_REGION1_CTRL, WR_EN, 0);
}
示例#6
0
void usb_spi_board_enable(struct usb_spi_config const *config)
{
	hook_call_deferred(&update_finished_data, -1);
	update_in_progress = 1;

	disable_ec_ap_spi();

	if (config->state->enabled_host == USB_SPI_EC)
		enable_ec_spi();
	else if (config->state->enabled_host == USB_SPI_AP)
		enable_ap_spi();
	else {
		CPRINTS("DEVICE NOT SUPPORTED");
		return;
	}

	/* Connect DIO A4, A8, and A14 to the SPI peripheral */
	GWRITE(PINMUX, DIOA4_SEL, 0); /* SPI_MOSI */
	GWRITE(PINMUX, DIOA8_SEL, 0); /* SPI_CS_L */
	GWRITE(PINMUX, DIOA14_SEL, 0); /* SPI_CLK */
	/* Set SPI_CS to be an internal pull up */
	GWRITE_FIELD(PINMUX, DIOA14_CTL, PU, 1);

	CPRINTS("usb_spi enable %s",
		gpio_get_level(GPIO_AP_FLASH_SELECT) ? "AP" : "EC");

	spi_enable(CONFIG_SPI_FLASH_PORT, 1);
}
示例#7
0
void usb_spi_board_disable(struct usb_spi_config const *config)
{
	CPRINTS("usb_spi disable");
	spi_enable(CONFIG_SPI_FLASH_PORT, 0);
	disable_ec_ap_spi();

	/* Disconnect SPI peripheral to tri-state pads */
	/* Disable internal pull up */
	GWRITE_FIELD(PINMUX, DIOA14_CTL, PU, 0);
	/* TODO: Implement way to get the gpio */
	ASSERT(GREAD(PINMUX, GPIO0_GPIO7_SEL) == GC_PINMUX_DIOA4_SEL);
	ASSERT(GREAD(PINMUX, GPIO0_GPIO8_SEL) == GC_PINMUX_DIOA8_SEL);
	ASSERT(GREAD(PINMUX, GPIO0_GPIO9_SEL) == GC_PINMUX_DIOA14_SEL);

	/* Set SPI MOSI, CLK, and CS_L as inputs */
	GWRITE(PINMUX, DIOA4_SEL, GC_PINMUX_GPIO0_GPIO7_SEL);
	GWRITE(PINMUX, DIOA8_SEL, GC_PINMUX_GPIO0_GPIO8_SEL);
	GWRITE(PINMUX, DIOA14_SEL, GC_PINMUX_GPIO0_GPIO9_SEL);

	/*
	 * TODO(crosbug.com/p/52366): remove once sys_rst just resets the TPM
	 * instead of cr50.
	 * Resetting the EC and AP cause sys_rst to be asserted currently that
	 * will cause cr50 to do a soft reset. Delay the end of the transaction
	 * to prevent cr50 from resetting during a series of usb_spi calls.
	 */
	hook_call_deferred(&update_finished_data, 1 * SECOND);
}
示例#8
0
void init_jittery_clock(int highsec)
{
	unsigned trimfast = GR_FUSE(RC_JTR_OSC60_CC_TRIM);
	unsigned trim48 = GR_FUSE(RC_JTR_OSC48_CC_TRIM);
	unsigned delta = (trim48 - trimfast);
	/* For metastability reasons, avoid clk_jtr ~= clk_timer, make
	 * a keepout region around 24MHz of about 0.75MHz, about 3/16 of the
	 * the delta from trimfast and trim48 */
	unsigned skiplow = (trim48 << 4) - (delta * 6);
	unsigned skiphigh = (trim48 << 4) + (delta * 6);
	unsigned setting = trimfast << 4;
	unsigned stepx16;
	unsigned bankval;
	int bank;

	if (highsec)
		stepx16 = 0xff - trimfast;
	else
		stepx16 = 2 * (trim48 - trimfast);

	for (bank = 0; bank < 16; bank++) {
		/* saturate at 0xff */
		bankval = (setting > 0xfff) ? 0xff : (setting >> 4);

		GR_XO_JTR_JITTERY_TRIM_BANK(bank) = bankval;

		setting += stepx16;
		if ((setting > skiplow) && (setting < skiphigh))
			setting = skiphigh;
	}

	GWRITE_FIELD(XO, CLK_JTR_TRIM_CTRL, RC_COARSE_TRIM_SRC, 2);
	GWRITE_FIELD(XO, CLK_JTR_TRIM_CTRL, RC_INITIAL_TRIM_PERIOD, 100);
	GWRITE_FIELD(XO, CLK_JTR_TRIM_CTRL, RC_TRIM_EN, 1);
	GREG32(XO, CLK_JTR_JITTERY_TRIM_EN) = 1;
	GREG32(XO, CLK_JTR_SYNC_CONTENTS) = 0;

	/* Writing any value locks things until the next hard reboot */
	GREG32(XO, CFG_WR_EN) = 0;
	GREG32(XO, JTR_CTRL_EN) = 0;
}
void disarmRAMGuards(void)
{
	GWRITE_FIELD(GLOBALSEC, CPU0_D_REGION0_CTRL, EN, 1);
	GWRITE_FIELD(GLOBALSEC, CPU0_D_REGION0_CTRL, RD_EN, 1);
	GWRITE_FIELD(GLOBALSEC, CPU0_D_REGION0_CTRL, WR_EN, 1);
	GWRITE_FIELD(GLOBALSEC, CPU0_D_REGION1_CTRL, EN, 1);
	GWRITE_FIELD(GLOBALSEC, CPU0_D_REGION1_CTRL, RD_EN, 1);
	GWRITE_FIELD(GLOBALSEC, CPU0_D_REGION1_CTRL, WR_EN, 1);
}
示例#10
0
文件: usb.c 项目: coreboot/chrome-ec
static void usb_reset(void)
{
	CPRINTS("%s, status %x", __func__, GR_USB_GINTSTS);
	print_later("usb_reset()", 0, 0, 0, 0, 0);

	/* Clear our internal state */
	device_state = DS_DEFAULT;
	configuration_value = 0;

	/* Clear the device address */
	GWRITE_FIELD(USB, DCFG, DEVADDR, 0);

	/* Reinitialize all the endpoints */
	usb_init_endpoints();
}
示例#11
0
static int do_flash_op(enum flash_op op, int is_info_bank,
		       int byte_offset, int words)
{
	volatile uint32_t *fsh_pe_control;
	uint32_t opcode, tmp, errors;
	int retry_count, max_attempts, extra_prog_pulse, i;
	int timedelay_us = 100;
	uint32_t prev_error = 0;

	/* Make sure the smart program/erase algorithms are enabled. */
	if (!GREAD(FLASH, FSH_TIMING_PROG_SMART_ALGO_ON) ||
	    !GREAD(FLASH, FSH_TIMING_ERASE_SMART_ALGO_ON)) {
		CPRINTF("%s:%d\n", __func__, __LINE__);
		return EC_ERROR_UNIMPLEMENTED;
	}

	/* Error status is self-clearing. Read it until it does (we hope). */
	for (i = 0; i < 50; i++) {
		tmp = GREAD(FLASH, FSH_ERROR);
		if (!tmp)
			break;
		usleep(timedelay_us);
	}
	/* If we can't clear the error status register then something is wrong.
	 */
	if (tmp) {
		CPRINTF("%s:%d\n", __func__, __LINE__);
		return EC_ERROR_UNKNOWN;
	}

	/* We have two flash banks. Adjust offset and registers accordingly. */
	if (is_info_bank) {
		/* Only INFO bank operations are supported. */
		fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL1);
	} else if (byte_offset >= CFG_FLASH_HALF) {
		byte_offset -= CFG_FLASH_HALF;
		fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL1);
	} else {
		fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL0);
	}

	/* What are we doing? */
	switch (op) {
	case OP_ERASE_BLOCK:
		if (is_info_bank)
			/* Erasing the INFO bank from the RW section is
			 * unsupported. */
			return EC_ERROR_INVAL;
		opcode = 0x31415927;
		words = 0;			/* don't care, really */
		/* This number is based on the TSMC spec Nme=Terase/Tsme */
		max_attempts = 45;
		break;
	case OP_WRITE_BLOCK:
		opcode = 0x27182818;
		words--;		     /* count register is zero-based */
		/* This number is based on the TSMC spec Nmp=Tprog/Tsmp */
		max_attempts = 9;
		break;
	case OP_READ_BLOCK:
		if (!is_info_bank)
			/* This code path only supports reading from
			 * the INFO bank.
			 */
			return EC_ERROR_INVAL;
		opcode = 0x16021765;
		words = 1;
		max_attempts = 9;
		break;
	default:
		return EC_ERROR_INVAL;
	}

	/*
	 * Set the parameters. For writes, we assume the write buffer is
	 * already filled before we call this function.
	 */
	GWRITE_FIELD(FLASH, FSH_TRANS, OFFSET,
		     byte_offset / 4);		  /* word offset */
	GWRITE_FIELD(FLASH, FSH_TRANS, MAINB, is_info_bank ? 1 : 0);
	GWRITE_FIELD(FLASH, FSH_TRANS, SIZE, words);

	/* TODO: Make sure this function isn't getting called "too often" in
	 * between erases.
	 */
	extra_prog_pulse = 0;
	for (retry_count = 0; retry_count < max_attempts; retry_count++) {
		/* Kick it off */
		GWRITE(FLASH, FSH_PE_EN, 0xb11924e1);
		*fsh_pe_control = opcode;

		/* Wait for completion. 150ms should be enough
		 * (crosbug.com/p/45366).
		 */
		for (i = 0; i < 1500; i++) {
			tmp = *fsh_pe_control;
			if (!tmp)
				break;
			usleep(timedelay_us);
		}

		/* Timed out waiting for control register to clear */
		if (tmp) {
			CPRINTF("%s:%d\n", __func__, __LINE__);
			return EC_ERROR_UNKNOWN;
		}
		/* Check error status */
		errors = GREAD(FLASH, FSH_ERROR);

		if (errors && (errors != prev_error)) {
			prev_error = errors;
			CPRINTF("%s:%d errors %x fsh_pe_control %p\n",
				__func__, __LINE__, errors, fsh_pe_control);
		}
		/* Error status is self-clearing. Read it until it does
		 * (we hope).
		 */
		for (i = 0; i < 50; i++) {
			tmp = GREAD(FLASH, FSH_ERROR);
			if (!tmp)
				break;
			usleep(timedelay_us);
		}
		/* If we can't clear the error status register then something
		 * is wrong.
		 */
		if (tmp) {
			CPRINTF("%s:%d\n", __func__, __LINE__);
			return EC_ERROR_UNKNOWN;
		}
		/* The operation was successful. */
		if (!errors) {
			/* From the spec:
			 * "In addition, one more program pulse is needed after
			 * program verification is passed."
			 */
			if (op == OP_WRITE_BLOCK && !extra_prog_pulse) {
				extra_prog_pulse = 1;
				max_attempts++;
				continue;
			}
			return EC_SUCCESS;
		}
		/* If there were errors after completion retry. */
		watchdog_reload();
	}
	CPRINTF("%s:%d, retry count %d\n", __func__, __LINE__, retry_count);
	return EC_ERROR_UNKNOWN;
}
示例#12
0
文件: sps.c 项目: fourier49/BZ_DEV_EC
/*
 * Push data to the SPS TX FIFO
 * @param data Pointer to 8-bit data
 * @param data_size Number of bytes to transmit
 * @return : actual number of bytes placed into tx fifo
 */
int sps_transmit(uint8_t *data, size_t data_size)
{
	volatile uint32_t *sps_tx_fifo;
	uint32_t rptr;
	uint32_t wptr;
	uint32_t fifo_room;
	int bytes_sent;
	int inst = 0;

	if (GREAD_FIELD_I(SPS, inst, ISTATE, TXFIFO_EMPTY))
		tx_empty_count++; /* Inside packet this means underrun. */

	sps_tx_fifo = (volatile uint32_t *)SPS_TX_FIFO_BASE_ADDR;

	wptr = GREG32_I(SPS, inst, TXFIFO_WPTR);
	rptr = GREG32_I(SPS, inst, TXFIFO_RPTR);
	fifo_room = (rptr - wptr - 1) & SPS_FIFO_MASK;

	if (fifo_room < data_size) {
		bytes_sent = fifo_room;
		data_size = fifo_room;
	} else {
		bytes_sent = data_size;
	}

	sps_tx_fifo += (wptr & SPS_FIFO_MASK) / sizeof(*sps_tx_fifo);

	while (data_size) {

		if ((wptr & 3) || (data_size < 4) || ((uintptr_t)data & 3)) {
			/*
			 * Either we have less then 4 bytes to send, or one of
			 * the pointers is not 4 byte aligned. Need to go byte
			 * by byte.
			 */
			uint32_t fifo_contents;
			int bit_shift;

			fifo_contents = *sps_tx_fifo;
			do {
				/*
				 * CR50 SPS controller does not allow byte
				 * accesses for writes into the FIFO, so read
				 * modify/write is requred. Tracked uder
				 * http://b/20894727
				 */
				bit_shift = 8 * (wptr & 3);
				fifo_contents &= ~(0xff << bit_shift);
				fifo_contents |=
					(((uint32_t)(*data++)) << bit_shift);
				data_size--;
				wptr++;

			} while (data_size && (wptr & 3));

			*sps_tx_fifo++ = fifo_contents;
		} else {
			/*
			 * Both fifo wptr and data are aligned and there is
			 * plenty to send.
			 */
			*sps_tx_fifo++ = *((uint32_t *)data);
			data += 4;
			data_size -= 4;
			wptr += 4;
		}
		GREG32_I(SPS, inst, TXFIFO_WPTR) = wptr & SPS_FIFO_PTR_MASK;

		/* Make sure FIFO pointer wraps along with the index. */
		if (!(wptr & SPS_FIFO_MASK))
			sps_tx_fifo = (volatile uint32_t *)
				SPS_TX_FIFO_BASE_ADDR;
	}

	/*
	 * Start TX if necessary. This happens after FIFO is primed, which
	 * helps aleviate TX underrun problems but introduces delay before
	 * data starts coming out.
	 */
	if (!GREAD_FIELD(SPS, FIFO_CTRL, TXFIFO_EN))
		GWRITE_FIELD(SPS, FIFO_CTRL, TXFIFO_EN, 1);

	sps_tx_count += bytes_sent;
	return bytes_sent;
}
示例#13
0
void init_sof_clock(void)
{
	/* Copy fuse value into software registers, both coarse and fine */
	unsigned coarseTrimVal = GR_FUSE(RC_TIMER_OSC48_CC_TRIM);
	unsigned fineTrimVal = GR_FUSE(RC_TIMER_OSC48_FC_TRIM);

	/* We think SOF toggle happens once every mS, or ~24000 clock ticks */
	unsigned targetCnt = PCLK_FREQ / 1000;

	/* The possible operations of a particular calibration bucket */
	unsigned binaryDnOp = 0x1 | 0x1 << 4;
	unsigned binaryUpOp = 0x1 | 0x0 << 4;
	unsigned subOp      = 0x3 | 0x1 << 4;
	unsigned addOp      = 0x2 | 0x1 << 4;
	unsigned nop        = 0;

	GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM) = coarseTrimVal;
	GREG32(XO, CLK_TIMER_RC_FINE_ATE_TRIM) = fineTrimVal;

	/* Coarse trim values come from software */
	GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_COARSE_TRIM_SRC, 0);

	/* enable error interrupts
	 * This enables underrun and overflow interrupts */
	GREG32(XO, DXO_INT_ENABLE) = 0xC;

	/* Setup SOF calibration buckets and associated operations */
	GREG32(XO, CLK_TIMER_SLOW_CALIB0) = targetCnt * 70 / 100;
	GREG32(XO, CLK_TIMER_SLOW_CALIB1) = targetCnt * 80 / 100;
	GREG32(XO, CLK_TIMER_SLOW_CALIB2) = targetCnt * 90 / 100;
	GREG32(XO, CLK_TIMER_SLOW_CALIB3) =
		targetCnt * (1000000 - 1250) / 1000000;
	GREG32(XO, CLK_TIMER_SLOW_CALIB4) = targetCnt;
	GREG32(XO, CLK_TIMER_SLOW_CALIB5) =
		targetCnt * (1000000 + 1250) / 1000000;
	GREG32(XO, CLK_TIMER_SLOW_CALIB6) = targetCnt * 110 / 100;
	GREG32(XO, CLK_TIMER_SLOW_CALIB7) = targetCnt * 120 / 100;

	/* This is a work-around for the screwy SOF */
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL0) = nop;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL1) = binaryDnOp;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL2) = binaryDnOp;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL3) = subOp;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL4) = nop;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL5) = nop;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL6) = addOp;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL7) = binaryUpOp;
	GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL8) = binaryUpOp;

	/* Set the calibration mode */
	GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, ENABLE_FAST, 0);
	GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, ENABLE_SLOW, 1);
	GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, SLOW_MODE_SEL, 0); /* SOF */
	GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, MAX_TRIM_SEL, 1);
	/* Don't stop when a NOP operation is seen, keep on calibrating */
	GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, STOP_ON_NOP, 0);

	/* Set source of trim codes:
	 * coarse trim comes from software
	 * fine trim comes from calibration engine */
	GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_COARSE_TRIM_SRC, 0);
	GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_FINE_TRIM_SRC, 1);

	/* Enable dynamic trim */
	GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_TRIM_EN, 1);

	/* Sync everything! */
	GREG32(XO, CLK_TIMER_SYNC_CONTENTS) = 1;

	/* Enable interrupts */
	task_enable_irq(GC_IRQNUM_XO0_SLOW_CALIB_UNDERRUN_INT);
	task_enable_irq(GC_IRQNUM_XO0_SLOW_CALIB_OVERFLOW_INT);
}
示例#14
0
文件: usb.c 项目: coreboot/chrome-ec
/* Some Setup packets don't have a data stage at all. */
static int handle_setup_with_no_data_stage(enum table_case tc,
					   struct usb_setup_packet *req)
{
	uint8_t set_addr;

	print_later("handle_setup_with_no_data_stage(%c)", "0ABCDE67"[tc],
		    0, 0, 0, 0);

	switch (req->bRequest) {
	case USB_REQ_SET_ADDRESS:
		/*
		 * Set the address after the IN packet handshake.
		 *
		 * From the USB 2.0 spec, section 9.4.6:
		 *
		 * As noted elsewhere, requests actually may result in
		 * up to three stages. In the first stage, the Setup
		 * packet is sent to the device. In the optional second
		 * stage, data is transferred between the host and the
		 * device. In the final stage, status is transferred
		 * between the host and the device. The direction of
		 * data and status transfer depends on whether the host
		 * is sending data to the device or the device is
		 * sending data to the host. The Status stage transfer
		 * is always in the opposite direction of the Data
		 * stage. If there is no Data stage, the Status stage
		 * is from the device to the host.
		 *
		 * Stages after the initial Setup packet assume the
		 * same device address as the Setup packet. The USB
		 * device does not change its device address until
		 * after the Status stage of this request is completed
		 * successfully. Note that this is a difference between
		 * this request and all other requests. For all other
		 * requests, the operation indicated must be completed
		 * before the Status stage
		 */
		set_addr = req->wValue & 0xff;
		/*
		 * NOTE: Now that we've said that, we don't do it. The
		 * hardware for this SoC knows that an IN packet will
		 * be following the SET ADDRESS, so it waits until it
		 * sees that happen before the address change takes
		 * effect. If we wait until after the IN packet to
		 * change the register, the hardware gets confused and
		 * doesn't respond to anything.
		 */
		GWRITE_FIELD(USB, DCFG, DEVADDR, set_addr);
		CPRINTS("SETAD 0x%02x (%d)", set_addr, set_addr);
		print_later("SETAD 0x%02x (%d)", set_addr, set_addr, 0, 0, 0);
		device_state = DS_ADDRESS;
		processed_update_counter = 1;
		break;

	case USB_REQ_SET_CONFIGURATION:
		print_later("SETCFG 0x%x", req->wValue, 0, 0, 0, 0);
		switch (req->wValue) {
		case 0:
			configuration_value = req->wValue;
			device_state = DS_ADDRESS;
			break;
		case 1:	    /* Caution: Only one config descriptor TODAY */
			/* TODO: All endpoints set to DATA0 toggle state */
			configuration_value = req->wValue;
			device_state = DS_CONFIGURED;
			break;
		default:
			/* Nope. That's a paddlin. */
			return -1;
		}
		break;

	case USB_REQ_CLEAR_FEATURE:
	case USB_REQ_SET_FEATURE:
		/* TODO: Handle DEVICE_REMOTE_WAKEUP, ENDPOINT_HALT? */
		print_later("SET_FEATURE/CLEAR_FEATURE. Whatever...",
			    0, 0, 0, 0, 0);
		break;

	default:
		/* Anything else is unsupported */
		return -1;
	}

	/* No data to transfer, go straight to the Status phase. */
	return 0;
}