1
0
Fork 0

Merge git://www.denx.de/git/u-boot-marvell

utp
Tom Rini 2016-03-25 12:57:18 -04:00
commit a6164205ee
21 changed files with 507 additions and 26 deletions

View File

@ -69,6 +69,7 @@
aliases {
spi0 = &spi0;
spi1 = &spi1;
ethernet0 = &eth0;
};
@ -137,6 +138,26 @@
reg = <0>; /* Chip select 0 */
spi-max-frequency = <27777777>;
};
fpga@1 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "spi-generic-device";
reg = <1>; /* Chip select 1 */
spi-max-frequency = <27777777>;
};
};
spi1: spi@10680 {
status = "okay";
fpga@2 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "spi-generic-device";
reg = <2>; /* Chip select 2 */
spi-max-frequency = <27777777>;
};
};
};
};

View File

@ -19,6 +19,9 @@ struct kwspi_registers {
u32 din; /* 0x1060c */
u32 irq_cause; /* 0x10610 */
u32 irq_mask; /* 0x10614 */
u32 timing1; /* 0x10618 */
u32 timing2; /* 0x1061c */
u32 dw_cfg; /* 0x10620 - Direct Write Configuration */
};
/* They are used to define CONFIG_SYS_KW_SPI_MPP

View File

@ -47,6 +47,9 @@ enum cpu_attrib {
CPU_ATTR_DRAM_CS3 = 0x07,
CPU_ATTR_NANDFLASH = 0x2f,
CPU_ATTR_SPIFLASH = 0x1e,
CPU_ATTR_SPI0_CS0 = 0x1e,
CPU_ATTR_SPI0_CS1 = 0x5e,
CPU_ATTR_SPI1_CS2 = 0x9a,
CPU_ATTR_BOOTROM = 0x1d,
CPU_ATTR_PCIE_IO = 0xe0,
CPU_ATTR_PCIE_MEM = 0xe8,

View File

@ -1,16 +0,0 @@
--------
WARNING:
--------
This file should contain the bin_hdr generated by the original Marvell
U-Boot implementation. As this is currently not included in this
U-Boot version, we have added this placeholder, so that the U-Boot
image can be generated without errors.
If you have a known to be working bin_hdr for your board, then you
just need to replace this text file here with the binary header
and recompile U-Boot.
In a few weeks, mainline U-Boot will get support to generate the
bin_hdr with the DDR training code itself. By implementing this code
as SPL U-Boot. Then this file will not be needed any more and will
get removed.

View File

@ -5,3 +5,4 @@
#
obj-y := theadorable.o
obj-y += fpga.o

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <altera.h>
#include <errno.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <asm/arch-mvebu/spi.h>
#include "theadorable.h"
/*
* FPGA programming support
*/
static int fpga_pre_fn(int cookie)
{
int gpio_config = COOKIE2CONFIG(cookie);
int gpio_done = COOKIE2DONE(cookie);
int ret;
debug("%s (%d): cookie=%08x gpio_config=%d gpio_done=%d\n",
__func__, __LINE__, cookie, gpio_config, gpio_done);
/* Configure config pin */
/* Set to output */
ret = gpio_request(gpio_config, "CONFIG");
if (ret < 0)
return ret;
gpio_direction_output(gpio_config, 1);
/* Configure done pin */
/* Set to input */
ret = gpio_request(gpio_done, "DONE");
if (ret < 0)
return ret;
gpio_direction_input(gpio_done);
return 0;
}
static int fpga_config_fn(int assert, int flush, int cookie)
{
int gpio_config = COOKIE2CONFIG(cookie);
debug("%s (%d): cookie=%08x gpio_config=%d\n",
__func__, __LINE__, cookie, gpio_config);
if (assert)
gpio_set_value(gpio_config, 1);
else
gpio_set_value(gpio_config, 0);
return 0;
}
static int fpga_write_fn(const void *buf, size_t len, int flush, int cookie)
{
int spi_bus = COOKIE2SPI_BUS(cookie);
int spi_dev = COOKIE2SPI_DEV(cookie);
struct kwspi_registers *reg;
u32 control_reg;
u32 config_reg;
void *dst;
/*
* Write data to FPGA attached to SPI bus via SPI direct write.
* This results in the fastest and easiest way to program the
* bitstream into the FPGA.
*/
debug("%s (%d): cookie=%08x spi_bus=%d spi_dev=%d\n",
__func__, __LINE__, cookie, spi_bus, spi_dev);
if (spi_bus == 0) {
reg = (struct kwspi_registers *)MVEBU_REGISTER(0x10600);
dst = (void *)SPI_BUS0_DEV1_BASE;
} else {
reg = (struct kwspi_registers *)MVEBU_REGISTER(0x10680);
dst = (void *)SPI_BUS1_DEV2_BASE;
}
/* Configure SPI controller for direct access mode */
control_reg = readl(&reg->ctrl);
config_reg = readl(&reg->cfg);
writel(0x00000214, &reg->cfg); /* 27MHz clock */
writel(0x00000000, &reg->dw_cfg); /* don't de-asset CS */
writel(KWSPI_CSN_ACT, &reg->ctrl); /* activate CS */
/* Copy data to the SPI direct mapped window */
memcpy(dst, buf, len);
/* Restore original register values */
writel(control_reg, &reg->ctrl);
writel(config_reg, &reg->cfg);
return 0;
}
/* Returns the state of CONF_DONE Pin */
static int fpga_done_fn(int cookie)
{
int gpio_done = COOKIE2DONE(cookie);
unsigned long ts;
debug("%s (%d): cookie=%08x gpio_done=%d\n",
__func__, __LINE__, cookie, gpio_done);
ts = get_timer(0);
do {
if (gpio_get_value(gpio_done))
return 0;
} while (get_timer(ts) < 1000);
/* timeout so return error */
return -ENODEV;
}
static altera_board_specific_func stratixv_fns = {
.pre = fpga_pre_fn,
.config = fpga_config_fn,
.write = fpga_write_fn,
.done = fpga_done_fn,
};
static Altera_desc altera_fpga[] = {
{
/* Family */
Altera_StratixV,
/* Interface type */
passive_serial,
/* No limitation as additional data will be ignored */
-1,
/* Device function table */
(void *)&stratixv_fns,
/* Base interface address specified in driver */
NULL,
/* Cookie implementation */
/*
* In this 32bit word the following information is coded:
* Bit 31 ... Bit 0
* SPI-Bus | SPI-Dev | Config-Pin | Done-Pin
*/
FPGA_COOKIE(0, 1, 26, 7)
},
{
/* Family */
Altera_StratixV,
/* Interface type */
passive_serial,
/* No limitation as additional data will be ignored */
-1,
/* Device function table */
(void *)&stratixv_fns,
/* Base interface address specified in driver */
NULL,
/* Cookie implementation */
/*
* In this 32bit word the following information is coded:
* Bit 31 ... Bit 0
* SPI-Bus | SPI-Dev | Config-Pin | Done-Pin
*/
FPGA_COOKIE(1, 2, 29, 9)
},
};
/* Add device descriptor to FPGA device table */
void board_fpga_add(void)
{
int i;
fpga_init();
for (i = 0; i < ARRAY_SIZE(altera_fpga); i++)
fpga_add(fpga_altera, &altera_fpga[i]);
}

View File

@ -8,9 +8,11 @@
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <linux/mbus.h>
#ifdef CONFIG_NET
#include <netdev.h>
#endif
#include "theadorable.h"
#include "../drivers/ddr/marvell/axp/ddr3_hw_training.h"
#include "../arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h"
@ -136,6 +138,15 @@ int board_init(void)
/* adress of boot parameters */
gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
/*
* Map SPI devices via MBUS so that they can be accessed via
* the SPI direct access mode
*/
mbus_dt_setup_win(&mbus_state, SPI_BUS0_DEV1_BASE, SPI_BUS0_DEV1_SIZE,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI0_CS1);
mbus_dt_setup_win(&mbus_state, SPI_BUS1_DEV2_BASE, SPI_BUS0_DEV1_SIZE,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI1_CS2);
return 0;
}
@ -143,6 +154,8 @@ int checkboard(void)
{
puts("Board: theadorable\n");
board_fpga_add();
return 0;
}

View File

@ -0,0 +1,12 @@
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/* Base addresses for the SPI direct access mode */
#define SPI_BUS0_DEV1_BASE 0xe0000000
#define SPI_BUS0_DEV1_SIZE (1 << 20)
#define SPI_BUS1_DEV2_BASE (SPI_BUS0_DEV1_BASE + SPI_BUS0_DEV1_SIZE)
void board_fpga_add(void);

View File

@ -2,6 +2,7 @@ CONFIG_ARM=y
CONFIG_ARCH_MVEBU=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_TARGET_THEADORABLE=y
CONFIG_DM_GPIO=y
CONFIG_DEFAULT_DEVICE_TREE="armada-xp-theadorable"
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL=y
@ -10,7 +11,7 @@ CONFIG_FIT=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_SF=y
CONFIG_CMD_USB=y
# CONFIG_CMD_FPGA is not set
CONFIG_CMD_GPIO=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_SPL_OF_TRANSLATE=y

View File

@ -2,6 +2,7 @@ CONFIG_ARM=y
CONFIG_ARCH_MVEBU=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_TARGET_THEADORABLE=y
CONFIG_DM_GPIO=y
CONFIG_DEFAULT_DEVICE_TREE="armada-xp-theadorable"
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL=y
@ -9,7 +10,6 @@ CONFIG_FIT=y
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_SF=y
# CONFIG_CMD_FPGA is not set
# CONFIG_CMD_SETEXPR is not set
# CONFIG_CMD_NET is not set
# CONFIG_CMD_NFS is not set

View File

@ -305,8 +305,6 @@ int ddr3_init(void)
SAR1_CPU_CORE_OFFSET;
switch (soc_num) {
case 0x3:
reg_bit_set(CPU_CONFIGURATION_REG(3), CPU_MRVL_ID_OFFSET);
reg_bit_set(CPU_CONFIGURATION_REG(2), CPU_MRVL_ID_OFFSET);
case 0x1:
reg_bit_set(CPU_CONFIGURATION_REG(1), CPU_MRVL_ID_OFFSET);
case 0x0:

View File

@ -17,5 +17,6 @@ obj-y += altera.o
obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o
obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o
endif

View File

@ -37,6 +37,9 @@ static const struct altera_fpga {
{ Altera_StratixII, "StratixII", StratixII_load,
StratixII_dump, StratixII_info },
#endif
#if defined(CONFIG_FPGA_STRATIX_V)
{ Altera_StratixV, "StratixV", stratixv_load, NULL, NULL },
#endif
#if defined(CONFIG_FPGA_SOCFPGA)
{ Altera_SoCFPGA, "SoC FPGA", socfpga_load, NULL, NULL },
#endif

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <altera.h>
#include <spi.h>
#include <asm/io.h>
#include <asm/errno.h>
/* Write the RBF data to FPGA via SPI */
static int program_write(int spi_bus, int spi_dev, const void *rbf_data,
unsigned long rbf_size)
{
struct spi_slave *slave;
int ret;
debug("%s (%d): data=%p size=%ld\n",
__func__, __LINE__, rbf_data, rbf_size);
/* FIXME: How to get the max. SPI clock and SPI mode? */
slave = spi_setup_slave(spi_bus, spi_dev, 27777777, SPI_MODE_3);
if (!slave)
return -1;
if (spi_claim_bus(slave))
return -1;
ret = spi_xfer(slave, rbf_size * 8, rbf_data, (void *)rbf_data,
SPI_XFER_BEGIN | SPI_XFER_END);
spi_release_bus(slave);
return ret;
}
/*
* This is the interface used by FPGA driver.
* Return 0 for sucess, non-zero for error.
*/
int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
{
altera_board_specific_func *pfns = desc->iface_fns;
int cookie = desc->cookie;
int spi_bus;
int spi_dev;
int ret = 0;
if ((u32)rbf_data & 0x3) {
puts("FPGA: Unaligned data, realign to 32bit boundary.\n");
return -EINVAL;
}
/* Run the pre configuration function if there is one */
if (pfns->pre)
(pfns->pre)(cookie);
/* Establish the initial state */
if (pfns->config) {
/* De-assert nCONFIG */
(pfns->config)(false, true, cookie);
/* nConfig minimum low pulse width is 2us */
udelay(200);
/* Assert nCONFIG */
(pfns->config)(true, true, cookie);
/* nCONFIG high to first rising clock on DCLK min 1506 us */
udelay(1600);
}
/* Write the RBF data to FPGA */
if (pfns->write) {
/*
* Use board specific data function to write bitstream
* into the FPGA
*/
ret = (pfns->write)(rbf_data, rbf_size, true, cookie);
} else {
/*
* Use common SPI functions to write bitstream into the
* FPGA
*/
spi_bus = COOKIE2SPI_BUS(cookie);
spi_dev = COOKIE2SPI_DEV(cookie);
ret = program_write(spi_bus, spi_dev, rbf_data, rbf_size);
}
if (ret)
return ret;
/* Check done pin */
if (pfns->done) {
ret = (pfns->done)(cookie);
if (ret)
printf("Error: DONE not set (ret=%d)!\n", ret);
}
return ret;
}

View File

@ -105,4 +105,11 @@ config PIC32_GPIO
help
Say yes here to support Microchip PIC32 GPIOs.
config MVEBU_GPIO
bool "Marvell MVEBU GPIO driver"
depends on DM_GPIO && ARCH_MVEBU
default y
help
Say yes here to support Marvell MVEBU (Armada XP/38x) GPIOs.
endmenu

View File

@ -49,3 +49,4 @@ obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o
obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o
obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o
obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o
obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <errno.h>
DECLARE_GLOBAL_DATA_PTR;
#define MVEBU_GPIOS_PER_BANK 32
struct mvebu_gpio_regs {
u32 data_out;
u32 io_conf;
u32 blink_en;
u32 in_pol;
u32 data_in;
};
struct mvebu_gpio_priv {
struct mvebu_gpio_regs *regs;
char name[2];
};
static int mvebu_gpio_direction_input(struct udevice *dev, unsigned int gpio)
{
struct mvebu_gpio_priv *priv = dev_get_priv(dev);
struct mvebu_gpio_regs *regs = priv->regs;
setbits_le32(&regs->io_conf, BIT(gpio));
return 0;
}
static int mvebu_gpio_direction_output(struct udevice *dev, unsigned gpio,
int value)
{
struct mvebu_gpio_priv *priv = dev_get_priv(dev);
struct mvebu_gpio_regs *regs = priv->regs;
clrbits_le32(&regs->io_conf, BIT(gpio));
return 0;
}
static int mvebu_gpio_get_function(struct udevice *dev, unsigned gpio)
{
struct mvebu_gpio_priv *priv = dev_get_priv(dev);
struct mvebu_gpio_regs *regs = priv->regs;
u32 val;
val = readl(&regs->io_conf) & BIT(gpio);
if (val)
return GPIOF_INPUT;
else
return GPIOF_OUTPUT;
}
static int mvebu_gpio_set_value(struct udevice *dev, unsigned gpio,
int value)
{
struct mvebu_gpio_priv *priv = dev_get_priv(dev);
struct mvebu_gpio_regs *regs = priv->regs;
if (value)
setbits_le32(&regs->data_out, BIT(gpio));
else
clrbits_le32(&regs->data_out, BIT(gpio));
return 0;
}
static int mvebu_gpio_get_value(struct udevice *dev, unsigned gpio)
{
struct mvebu_gpio_priv *priv = dev_get_priv(dev);
struct mvebu_gpio_regs *regs = priv->regs;
return !!(readl(&regs->data_in) & BIT(gpio));
}
static int mvebu_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct mvebu_gpio_priv *priv = dev_get_priv(dev);
priv->regs = (struct mvebu_gpio_regs *)dev_get_addr(dev);
uc_priv->gpio_count = MVEBU_GPIOS_PER_BANK;
priv->name[0] = 'A' + dev->req_seq;
uc_priv->bank_name = priv->name;
return 0;
}
static const struct dm_gpio_ops mvebu_gpio_ops = {
.direction_input = mvebu_gpio_direction_input,
.direction_output = mvebu_gpio_direction_output,
.get_function = mvebu_gpio_get_function,
.get_value = mvebu_gpio_get_value,
.set_value = mvebu_gpio_set_value,
};
static const struct udevice_id mvebu_gpio_ids[] = {
{ .compatible = "marvell,orion-gpio" },
{ }
};
U_BOOT_DRIVER(gpio_mvebu) = {
.name = "gpio_mvebu",
.id = UCLASS_GPIO,
.of_match = mvebu_gpio_ids,
.ops = &mvebu_gpio_ops,
.probe = mvebu_gpio_probe,
.priv_auto_alloc_size = sizeof(struct mvebu_gpio_priv),
};

View File

@ -10,6 +10,19 @@
#ifndef _ALTERA_H_
#define _ALTERA_H_
/*
* For the StratixV FPGA programming via SPI, the following
* information is coded in the 32bit cookie:
* Bit 31 ... Bit 0
* SPI-Bus | SPI-Dev | Config-Pin | Done-Pin
*/
#define FPGA_COOKIE(bus, dev, config, done) \
(((bus) << 24) | ((dev) << 16) | ((config) << 8) | (done))
#define COOKIE2SPI_BUS(c) (((c) >> 24) & 0xff)
#define COOKIE2SPI_DEV(c) (((c) >> 16) & 0xff)
#define COOKIE2CONFIG(c) (((c) >> 8) & 0xff)
#define COOKIE2DONE(c) ((c) & 0xff)
enum altera_iface {
/* insert all new types after this */
min_altera_iface_type,
@ -40,6 +53,8 @@ enum altera_family {
Altera_CYC2,
/* StratixII Family */
Altera_StratixII,
/* StratixV Family */
Altera_StratixV,
/* SoCFPGA Family */
Altera_SoCFPGA,
@ -89,6 +104,7 @@ typedef struct {
Altera_done_fn done;
Altera_clk_fn clk;
Altera_data_fn data;
Altera_write_fn write;
Altera_abort_fn abort;
Altera_post_fn post;
} altera_board_specific_func;
@ -97,4 +113,8 @@ typedef struct {
int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size);
#endif
#ifdef CONFIG_FPGA_STRATIX_V
int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size);
#endif
#endif /* _ALTERA_H_ */

View File

@ -64,12 +64,12 @@
#define CONFIG_MTDPARTS \
"orion_nand:512K(uboot)," \
"512K(env),1M(script),6M(kernel)," \
"12M(ramdisk),4M(spare),-(rootfs)\0"
"512K(env),4M(kernel)," \
"-(rootfs)\0"
#define CONFIG_EXTRA_ENV_SETTINGS "x_bootargs=console" \
"=ttyS0,115200 mtdparts="CONFIG_MTDPARTS \
"x_bootcmd_kernel=nand read 0x6400000 0x100000 0x300000\0" \
"x_bootcmd_kernel=nand read 0x6400000 0x100000 0x400000\0" \
"x_bootcmd_usb=usb start\0" \
"x_bootargs_root=root=/dev/mtdblock3 rw rootfstype=jffs2\0"

View File

@ -114,6 +114,11 @@
#define CONFIG_VGA_AS_SINGLE_DEVICE
#define CONFIG_CMD_BMP
/* FPGA programming support */
#define CONFIG_FPGA
#define CONFIG_FPGA_ALTERA
#define CONFIG_FPGA_STRATIX_V
/*
* mv-common.h should be defined after CMD configs since it used them
* to enable certain macros

View File

@ -76,6 +76,7 @@ static int kwboot_verbose;
static int msg_req_delay = KWBOOT_MSG_REQ_DELAY;
static int msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO;
static int blk_rsp_timeo = KWBOOT_BLK_RSP_TIMEO;
static void
kwboot_printv(const char *fmt, ...)
@ -380,7 +381,7 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block)
break;
do {
rc = kwboot_tty_recv(fd, &c, 1, KWBOOT_BLK_RSP_TIMEO);
rc = kwboot_tty_recv(fd, &c, 1, blk_rsp_timeo);
if (rc)
break;
@ -684,7 +685,7 @@ static void
kwboot_usage(FILE *stream, char *progname)
{
fprintf(stream,
"Usage: %s [-d | -a | -q <req-delay> | -s <resp-timeo> | -b <image> | -D <image> ] [ -t ] [-B <baud> ] <TTY>\n",
"Usage: %s [OPTIONS] [-b <image> | -D <image> ] [-B <baud> ] <TTY>\n",
progname);
fprintf(stream, "\n");
fprintf(stream,
@ -696,6 +697,8 @@ kwboot_usage(FILE *stream, char *progname)
fprintf(stream, " -a: use timings for Armada XP\n");
fprintf(stream, " -q <req-delay>: use specific request-delay\n");
fprintf(stream, " -s <resp-timeo>: use specific response-timeout\n");
fprintf(stream,
" -o <block-timeo>: use specific xmodem block timeout\n");
fprintf(stream, "\n");
fprintf(stream, " -t: mini terminal\n");
fprintf(stream, "\n");
@ -728,7 +731,7 @@ main(int argc, char **argv)
kwboot_verbose = isatty(STDOUT_FILENO);
do {
int c = getopt(argc, argv, "hb:ptaB:dD:q:s:");
int c = getopt(argc, argv, "hb:ptaB:dD:q:s:o:");
if (c < 0)
break;
@ -768,6 +771,10 @@ main(int argc, char **argv)
msg_rsp_timeo = atoi(optarg);
break;
case 'o':
blk_rsp_timeo = atoi(optarg);
break;
case 'B':
speed = kwboot_tty_speed(atoi(optarg));
if (speed == -1)