Ejemplo n.º 1
2
static const struct baudentry *round_baud(unsigned int baud)
{
	int i;
	/* Round baud rate to next lower entry in sp_baudtable if it exists, else use the lowest entry. */
	for (i = ARRAY_SIZE(sp_baudtable) - 2; i >= 0 ; i--) {
		if (sp_baudtable[i].baud == baud)
			return &sp_baudtable[i];

		if (sp_baudtable[i].baud < baud) {
			msg_pwarn("Warning: given baudrate %d rounded down to %d.\n",
				  baud, sp_baudtable[i].baud);
			return &sp_baudtable[i];
		}
	}
	msg_pinfo("Using slowest possible baudrate: %d.\n", sp_baudtable[0].baud);
	return &sp_baudtable[0];
}
Ejemplo n.º 2
0
int jlink_spi_init(void)
{
	char *arg;
	unsigned long speed = 0;

	register_shutdown(jlink_spi_shutdown, NULL);

	arg = extract_programmer_param("spispeed");

	if (arg) {
		char *endptr;

		errno = 0;
		speed = strtoul(arg, &endptr, 10);

		if (*endptr != '\0' || errno != 0) {
			msg_perr("Invalid SPI speed specified: %s.\n", arg);
			free(arg);
			return 1;
		}

		if (speed < 1) {
			msg_perr("SPI speed must be at least 1 kHz.\n");
			free(arg);
			return 1;
		}
	}

	free(arg);

	int ret;
	bool use_serial_number;
	uint32_t serial_number;

	arg = extract_programmer_param("serial");

	if (arg) {
		if (!strlen(arg)) {
			msg_perr("Emptpy serial number specified.\n");
			free(arg);
			return 1;
		}

		ret = jaylink_parse_serial_number(arg, &serial_number);

		if (ret == JAYLINK_ERR) {
			msg_perr("Invalid serial number specified: %s.\n", arg);
			free(arg);
			return 1;
		} if (ret != JAYLINK_OK) {
			msg_perr("jaylink_parse_serial_number() failed: %s.\n", jaylink_strerror(ret));
			free(arg);
			return 1;
		}

		use_serial_number = true;
	} else {
		use_serial_number = false;
	}

	free(arg);

	reset_cs = true;
	arg = extract_programmer_param("cs");

	if (arg) {
		if (!strcasecmp(arg, "reset")) {
			reset_cs = true;
		} else if (!strcasecmp(arg, "trst")) {
			reset_cs = false;
		} else {
			msg_perr("Invalid chip select pin specified: '%s'.\n", arg);
			free(arg);
			return 1;
		}
	}

	free(arg);

	if (reset_cs)
		msg_pdbg("Using RESET as chip select signal.\n");
	else
		msg_pdbg("Using TRST as chip select signal.\n");

	ret = jaylink_init(&jaylink_ctx);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_init() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	ret = jaylink_discovery_scan(jaylink_ctx, 0);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_discover_scan() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	struct jaylink_device **devs;

	ret = jaylink_get_devices(jaylink_ctx, &devs, NULL);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_get_devices() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	if (!use_serial_number)
		msg_pdbg("No device selected, using first device.\n");

	size_t i;
	struct jaylink_device *dev;
	bool device_found = false;

	for (i = 0; devs[i]; i++) {
		if (use_serial_number) {
			uint32_t tmp;

			ret = jaylink_device_get_serial_number(devs[i], &tmp);

			if (ret == JAYLINK_ERR_NOT_AVAILABLE) {
				continue;
			} else if (ret != JAYLINK_OK) {
				msg_pwarn("jaylink_device_get_serial_number() failed: %s.\n",
					jaylink_strerror(ret));
				continue;
			}

			if (serial_number != tmp)
				continue;
		}

		ret = jaylink_open(devs[i], &jaylink_devh);

		if (ret == JAYLINK_OK) {
			dev = devs[i];
			device_found = true;
			break;
		}

		jaylink_devh = NULL;
	}

	jaylink_free_devices(devs, true);

	if (!device_found) {
		msg_perr("No J-Link device found.\n");
		return 1;
	}

	size_t length;
	char *firmware_version;

	ret = jaylink_get_firmware_version(jaylink_devh, &firmware_version,
		&length);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_get_firmware_version() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	} else if (length > 0) {
		msg_pdbg("Firmware: %s\n", firmware_version);
		free(firmware_version);
	}

	ret = jaylink_device_get_serial_number(dev, &serial_number);

	if (ret == JAYLINK_OK) {
		msg_pdbg("S/N: %" PRIu32 "\n", serial_number);
	} else if (ret == JAYLINK_ERR_NOT_AVAILABLE) {
		msg_pdbg("S/N: N/A\n");
	} else {
		msg_perr("jaylink_device_get_serial_number() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE];

	memset(caps, 0, sizeof(caps));
	ret = jaylink_get_caps(jaylink_devh, caps);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_get_caps() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_EXT_CAPS)) {
		ret = jaylink_get_extended_caps(jaylink_devh, caps);

		if (ret != JAYLINK_OK) {
			msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret));
			return 1;
		}
	}

	uint32_t ifaces;

	ret = jaylink_get_available_interfaces(jaylink_devh, &ifaces);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	if (!(ifaces & (1 << JAYLINK_TIF_JTAG))) {
		msg_perr("Device does not support JTAG interface.\n");
		return 1;
	}

	ret = jaylink_select_interface(jaylink_devh, JAYLINK_TIF_JTAG, NULL);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_select_interface() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	struct jaylink_hardware_status hwstat;

	ret = jaylink_get_hardware_status(jaylink_devh, &hwstat);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_get_hardware_status() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	msg_pdbg("VTarget: %u.%03u V\n", hwstat.target_voltage / 1000,
		hwstat.target_voltage % 1000);

	if (hwstat.target_voltage < MIN_TARGET_VOLTAGE) {
		msg_perr("Target voltage is below %u.%03u V. You need to attach VTref to the I/O voltage of "
			"the chip.\n", MIN_TARGET_VOLTAGE / 1000, MIN_TARGET_VOLTAGE % 1000);
		return 1;
	}

	struct jaylink_speed device_speeds;

	device_speeds.freq = DEFAULT_FREQ;
	device_speeds.div = DEFAULT_FREQ_DIV;

	if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) {
		ret = jaylink_get_speeds(jaylink_devh, &device_speeds);

		if (ret != JAYLINK_OK) {
			msg_perr("jaylink_get_speeds() failed: %s.\n", jaylink_strerror(ret));
			return 1;
		}
	}

	device_speeds.freq /= 1000;

	msg_pdbg("Maximum SPI speed: %" PRIu32 " kHz\n", device_speeds.freq / device_speeds.div);

	if (!speed) {
		speed = device_speeds.freq / device_speeds.div;
		msg_pdbg("SPI speed not specified, using %lu kHz.\n", speed);
	}

	if (speed > (device_speeds.freq / device_speeds.div)) {
		msg_perr("Specified SPI speed of %lu kHz is too high. Maximum is %" PRIu32 " kHz.\n", speed,
			device_speeds.freq / device_speeds.div);
		return 1;
	}

	ret = jaylink_set_speed(jaylink_devh, speed);

	if (ret != JAYLINK_OK) {
		msg_perr("jaylink_set_speed() failed: %s.\n", jaylink_strerror(ret));
		return 1;
	}

	msg_pdbg("SPI speed: %lu kHz\n", speed);

	/* Ensure that the CS signal is not active initially. */
	if (!deassert_cs())
		return 1;

	register_spi_master(&spi_master_jlink_spi);

	return 0;
}
Ejemplo n.º 3
0
int serialport_config(fdtype fd, int baud)
{
	if (fd == SER_INV_FD) {
		msg_perr("%s: File descriptor is invalid.\n", __func__);
		return 1;
	}

#if IS_WINDOWS
	DCB dcb;
	if (!GetCommState(fd, &dcb)) {
		msg_perr_strerror("Could not fetch original serial port configuration: ");
		return 1;
	}
	if (baud >= 0) {
		dcb.BaudRate = baud;
	}
	dcb.ByteSize = 8;
	dcb.Parity = NOPARITY;
	dcb.StopBits = ONESTOPBIT;
	if (!SetCommState(fd, &dcb)) {
		msg_perr_strerror("Could not change serial port configuration: ");
		return 1;
	}
	if (!GetCommState(fd, &dcb)) {
		msg_perr_strerror("Could not fetch new serial port configuration: ");
		return 1;
	}
	msg_pdbg("Baud rate is %ld.\n", dcb.BaudRate);
#else
	struct termios wanted, observed;
	if (tcgetattr(fd, &observed) != 0) {
		msg_perr_strerror("Could not fetch original serial port configuration: ");
		return 1;
	}
	wanted = observed;
	if (baud >= 0) {
		const struct baudentry *entry = round_baud(baud);
		if (cfsetispeed(&wanted, entry->flag) != 0 || cfsetospeed(&wanted, entry->flag) != 0) {
			msg_perr_strerror("Could not set serial baud rate: ");
			return 1;
		}
	}
	wanted.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
	wanted.c_cflag |= (CS8 | CLOCAL | CREAD);
	wanted.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	wanted.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
	wanted.c_oflag &= ~OPOST;
	if (tcsetattr(fd, TCSANOW, &wanted) != 0) {
		msg_perr_strerror("Could not change serial port configuration: ");
		return 1;
	}
	if (tcgetattr(fd, &observed) != 0) {
		msg_perr_strerror("Could not fetch new serial port configuration: ");
		return 1;
	}
	if (observed.c_cflag != wanted.c_cflag ||
	    observed.c_lflag != wanted.c_lflag ||
	    observed.c_iflag != wanted.c_iflag ||
	    observed.c_oflag != wanted.c_oflag) {
		msg_pwarn("Some requested serial options did not stick, continuing anyway.\n");
		msg_pdbg("          observed    wanted\n"
			 "c_cflag:  0x%08lX  0x%08lX\n"
			 "c_lflag:  0x%08lX  0x%08lX\n"
			 "c_iflag:  0x%08lX  0x%08lX\n"
			 "c_oflag:  0x%08lX  0x%08lX\n",
			 (long)observed.c_cflag, (long)wanted.c_cflag,
			 (long)observed.c_lflag, (long)wanted.c_lflag,
			 (long)observed.c_iflag, (long)wanted.c_iflag,
			 (long)observed.c_oflag, (long)wanted.c_oflag
			);
	}
	if (cfgetispeed(&observed) != cfgetispeed(&wanted) ||
	    cfgetospeed(&observed) != cfgetospeed(&wanted)) {
		msg_pwarn("Could not set baud rates exactly.\n");
		msg_pdbg("Actual baud flags are: ispeed: 0x%08lX, ospeed: 0x%08lX\n",
			  (long)cfgetispeed(&observed), (long)cfgetospeed(&observed));
	}
	// FIXME: display actual baud rate - at least if none was specified by the user.
#endif
	return 0;
}
Ejemplo n.º 4
0
static void determine_generation(struct pci_dev *dev)
{
	amd_gen = CHIPSET_AMD_UNKNOWN;
	msg_pdbg2("Trying to determine the generation of the SPI interface... ");
	if (dev->device_id == 0x438d) {
		amd_gen = CHIPSET_SB6XX;
		msg_pdbg("SB6xx detected.\n");
	} else if (dev->device_id == 0x439d) {
		struct pci_dev *smbus_dev = pci_dev_find(0x1002, 0x4385);
		if (smbus_dev == NULL)
			return;
		uint8_t rev = pci_read_byte(smbus_dev, PCI_REVISION_ID);
		if (rev >= 0x39 && rev <= 0x3D) {
			amd_gen = CHIPSET_SB7XX;
			msg_pdbg("SB7xx/SP5100 detected.\n");
		} else if (rev >= 0x40 && rev <= 0x42) {
			amd_gen = CHIPSET_SB89XX;
			msg_pdbg("SB8xx/SB9xx/Hudson-1 detected.\n");
		} else {
			msg_pwarn("SB device found but SMBus revision 0x%02x does not match known values.\n"
				  "Assuming SB8xx/SB9xx/Hudson-1. Please send a log to [email protected]\n",
				   rev);
			amd_gen = CHIPSET_SB89XX;
		}
	} else if (dev->device_id == 0x780e) {
		/* The PCI ID of the LPC bridge doesn't change between Hudson-2/3/4 and Yangtze (Kabini/Temash)
		 * although they use different SPI interfaces. */
#ifdef USE_YANGTZE_HEURISTICS
		/* This heuristic accesses the SPI interface MMIO BAR at locations beyond those supported by
		 * Hudson in the hope of getting 0xff readback on older chipsets and non-0xff readback on
		 * Yangtze (and newer, compatible chipsets). */
		int i;
		msg_pdbg("Checking for AMD Yangtze (Kabini/Temash) or later... ");
		for (i = 0x20; i <= 0x4f; i++) {
			if (mmio_readb(sb600_spibar + i) != 0xff) {
				amd_gen = CHIPSET_YANGTZE;
				msg_pdbg("found.\n");
				return;
			}
		}
		msg_pdbg("not found. Assuming Hudson.\n");
		amd_gen = CHIPSET_HUDSON234;
#else
		struct pci_dev *smbus_dev = pci_dev_find(0x1022, 0x780B);
		if (smbus_dev == NULL) {
			msg_pdbg("No SMBus device with ID 1022:780B found.\n");
			return;
		}
		uint8_t rev = pci_read_byte(smbus_dev, PCI_REVISION_ID);
		if (rev >= 0x11 && rev <= 0x15) {
			amd_gen = CHIPSET_HUDSON234;
			msg_pdbg("Hudson-2/3/4 detected.\n");
		} else if (rev >= 0x39 && rev <= 0x3A) {
			amd_gen = CHIPSET_YANGTZE;
			msg_pdbg("Yangtze detected.\n");
		} else {
			msg_pwarn("FCH device found but SMBus revision 0x%02x does not match known values.\n"
				  "Please report this to [email protected] and include this log and\n"
				  "the output of lspci -nnvx, thanks!.\n", rev);
		}
#endif
	} else
		msg_pwarn("%s: Unknown LPC device %" PRIx16 ":%" PRIx16 ".\n"
			  "Please report this to [email protected] and include this log and\n"
			  "the output of lspci -nnvx, thanks!\n",
			  __func__, dev->vendor_id, dev->device_id);
}
Ejemplo n.º 5
0
int internal_init(void)
{
#if __FLASHROM_LITTLE_ENDIAN__
	int ret = 0;
#endif
	int force_laptop = 0;
	int not_a_laptop = 0;
	const char *board_vendor = NULL;
	const char *board_model = NULL;
#if defined (__i386__) || defined (__x86_64__) || defined (__arm__)
	const char *cb_vendor = NULL;
	const char *cb_model = NULL;
#endif
	char *arg;

	arg = extract_programmer_param("boardenable");
	if (arg && !strcmp(arg,"force")) {
		force_boardenable = 1;
	} else if (arg && !strlen(arg)) {
		msg_perr("Missing argument for boardenable.\n");
		free(arg);
		return 1;
	} else if (arg) {
		msg_perr("Unknown argument for boardenable: %s\n", arg);
		free(arg);
		return 1;
	}
	free(arg);

	arg = extract_programmer_param("boardmismatch");
	if (arg && !strcmp(arg,"force")) {
		force_boardmismatch = 1;
	} else if (arg && !strlen(arg)) {
		msg_perr("Missing argument for boardmismatch.\n");
		free(arg);
		return 1;
	} else if (arg) {
		msg_perr("Unknown argument for boardmismatch: %s\n", arg);
		free(arg);
		return 1;
	}
	free(arg);

	arg = extract_programmer_param("laptop");
	if (arg && !strcmp(arg, "force_I_want_a_brick"))
		force_laptop = 1;
	else if (arg && !strcmp(arg, "this_is_not_a_laptop"))
		not_a_laptop = 1;
	else if (arg && !strlen(arg)) {
		msg_perr("Missing argument for laptop.\n");
		free(arg);
		return 1;
	} else if (arg) {
		msg_perr("Unknown argument for laptop: %s\n", arg);
		free(arg);
		return 1;
	}
	free(arg);

	arg = extract_programmer_param("mainboard");
	if (arg && strlen(arg)) {
		if (board_parse_parameter(arg, &board_vendor, &board_model)) {
			free(arg);
			return 1;
		}
	} else if (arg && !strlen(arg)) {
		msg_perr("Missing argument for mainboard.\n");
		free(arg);
		return 1;
	}
	free(arg);

	if (rget_io_perms())
		return 1;
	if (register_shutdown(internal_shutdown, NULL))
		return 1;

	/* Default to Parallel/LPC/FWH flash devices. If a known host controller
	 * is found, the host controller init routine sets the
	 * internal_buses_supported bitfield.
	 */
	internal_buses_supported = BUS_NONSPI;

	/* Initialize PCI access for flash enables */
	if (pci_init_common() != 0)
		return 1;

	if (processor_flash_enable()) {
		msg_perr("Processor detection/init failed.\n"
			 "Aborting.\n");
		return 1;
	}

#if defined(__i386__) || defined(__x86_64__) || defined (__arm__)
	if ((cb_parse_table(&cb_vendor, &cb_model) == 0) && (board_vendor != NULL) && (board_model != NULL)) {
		if (strcasecmp(board_vendor, cb_vendor) || strcasecmp(board_model, cb_model)) {
			msg_pwarn("Warning: The mainboard IDs set by -p internal:mainboard (%s:%s) do not\n"
				  "         match the current coreboot IDs of the mainboard (%s:%s).\n",
				  board_vendor, board_model, cb_vendor, cb_model);
			if (!force_boardmismatch)
				return 1;
			msg_pinfo("Continuing anyway.\n");
		}
	}
#endif

#if defined(__i386__) || defined(__x86_64__)
	dmi_init();

	/* In case Super I/O probing would cause pretty explosions. */
	board_handle_before_superio();

	/* Probe for the Super I/O chip and fill global struct superio. */
	probe_superio();
#else
	/* FIXME: Enable cbtable searching on all non-x86 platforms supported
	 *        by coreboot.
	 * FIXME: Find a replacement for DMI on non-x86.
	 * FIXME: Enable Super I/O probing once port I/O is possible.
	 */
#endif

	/* Check laptop whitelist. */
	board_handle_before_laptop();

	/* Warn if a non-whitelisted laptop is detected. */
	if (is_laptop && !laptop_ok) {
		msg_perr("========================================================================\n");
		if (is_laptop == 1) {
			msg_perr("WARNING! You seem to be running flashrom on an unsupported laptop.\n");
		} else {
			msg_perr("WARNING! You may be running flashrom on an unsupported laptop. We could\n"
				 "not detect this for sure because your vendor has not setup the SMBIOS\n"
				 "tables correctly. You can enforce execution by adding\n"
				 "'-p internal:laptop=this_is_not_a_laptop' to the command line, but\n"
				 "please read the following warning if you are not sure.\n\n");
		}
		msg_perr("Laptops, notebooks and netbooks are difficult to support and we\n"
			 "recommend to use the vendor flashing utility. The embedded controller\n"
			 "(EC) in these machines often interacts badly with flashing.\n"
			 "See the manpage and http://www.flashrom.org/Laptops for details.\n\n"
			 "If flash is shared with the EC, erase is guaranteed to brick your laptop\n"
			 "and write may brick your laptop.\n"
			 "Read and probe may irritate your EC and cause fan failure, backlight\n"
			 "failure and sudden poweroff.\n"
			 "You have been warned.\n"
			 "========================================================================\n");

		if (force_laptop || (not_a_laptop && (is_laptop == 2))) {
			msg_perr("Proceeding anyway because user forced us to.\n");
		} else {
			msg_perr("Aborting.\n");
			return 1;
		}
	}

#if __FLASHROM_LITTLE_ENDIAN__
	/* try to enable it. Failure IS an option, since not all motherboards
	 * really need this to be done, etc., etc.
	 */
	ret = chipset_flash_enable();
	if (ret == -2) {
		msg_perr("WARNING: No chipset found. Flash detection "
			 "will most likely fail.\n");
	} else if (ret == ERROR_FATAL)
		return ret;

#if defined(__i386__) || defined(__x86_64__)
	/* Probe unconditionally for ITE Super I/O chips. This enables LPC->SPI translation on IT87* and
	 * parallel writes on IT8705F. Also, this handles the manual chip select for Gigabyte's DualBIOS. */
	init_superio_ite();
#endif

	if (board_flash_enable(board_vendor, board_model, cb_vendor, cb_model)) {
		msg_perr("Aborting to be safe.\n");
		return 1;
	}

#if defined(__i386__) || defined(__x86_64__) || defined (__mips)
	register_par_master(&par_master_internal, internal_buses_supported);
	return 0;
#else
	msg_perr("Your platform is not supported yet for the internal "
		 "programmer due to missing\n"
		 "flash_base and top/bottom alignment information.\n"
		 "Aborting.\n");
	return 1;
#endif
#else
	/* FIXME: Remove this unconditional abort once all PCI drivers are
	 * converted to use little-endian accesses for memory BARs.
	 */
	msg_perr("Your platform is not supported yet for the internal "
		 "programmer because it has\n"
		 "not been converted from native endian to little endian "
		 "access yet.\n"
		 "Aborting.\n");
	return 1;
#endif
}