Merge branch 'master' of git://git.denx.de/u-boot-dm

This commit is contained in:
Tom Rini
2014-09-13 16:32:52 -04:00
51 changed files with 2544 additions and 151 deletions

View File

@@ -118,7 +118,8 @@ static int driver_check_compatible(const void *blob, int offset,
return -ENOENT;
}
int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
struct udevice **devp)
{
struct driver *driver = ll_entry_start(struct driver, driver);
const int n_ents = ll_entry_count(struct driver, driver);
@@ -130,6 +131,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
int ret = 0;
dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
if (devp)
*devp = NULL;
for (entry = driver; entry != driver + n_ents; entry++) {
ret = driver_check_compatible(blob, offset, entry->of_match);
name = fdt_get_name(blob, offset, NULL);
@@ -149,10 +152,11 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
ret = device_bind(parent, entry, name, NULL, offset, &dev);
if (ret) {
dm_warn("Error binding driver '%s'\n", entry->name);
if (!result || ret != -ENOENT)
result = ret;
return ret;
} else {
found = true;
if (devp)
*devp = dev;
}
break;
}

View File

@@ -91,7 +91,7 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
if (pre_reloc_only &&
!fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
continue;
err = lists_bind_fdt(parent, blob, offset);
err = lists_bind_fdt(parent, blob, offset, NULL);
if (err && !ret)
ret = err;
}

View File

@@ -12,10 +12,17 @@
*/
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <errno.h>
#include <fdtdec.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/arch/tegra.h>
#include <asm/gpio.h>
#include <dm/device-internal.h>
DECLARE_GLOBAL_DATA_PTR;
enum {
TEGRA_CMD_INFO,
@@ -24,14 +31,18 @@ enum {
TEGRA_CMD_INPUT,
};
static struct gpio_names {
char name[GPIO_NAME_SIZE];
} gpio_names[MAX_NUM_GPIOS];
struct tegra_gpio_platdata {
struct gpio_ctlr_bank *bank;
const char *port_name; /* Name of port, e.g. "B" */
int base_gpio; /* Port number for this port (0, 1,.., n-1) */
};
static char *get_name(int i)
{
return *gpio_names[i].name ? gpio_names[i].name : "UNKNOWN";
}
/* Information about each port at run-time */
struct tegra_port_info {
char label[TEGRA_GPIOS_PER_PORT][GPIO_NAME_SIZE];
struct gpio_ctlr_bank *bank;
int base_gpio; /* Port number for this port (0, 1,.., n-1) */
};
/* Return config of pin 'gpio' as GPIO (1) or SFPIO (0) */
static int get_config(unsigned gpio)
@@ -121,38 +132,72 @@ static void set_level(unsigned gpio, int high)
writel(u, &bank->gpio_out[GPIO_PORT(gpio)]);
}
static int check_reserved(struct udevice *dev, unsigned offset,
const char *func)
{
struct tegra_port_info *state = dev_get_priv(dev);
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
if (!*state->label[offset]) {
printf("tegra_gpio: %s: error: gpio %s%d not reserved\n",
func, uc_priv->bank_name, offset);
return -EBUSY;
}
return 0;
}
/* set GPIO pin 'gpio' as an output, with polarity 'value' */
int tegra_spl_gpio_direction_output(int gpio, int value)
{
/* Configure as a GPIO */
set_config(gpio, 1);
/* Configure GPIO output value. */
set_level(gpio, value);
/* Configure GPIO direction as output. */
set_direction(gpio, 1);
return 0;
}
/*
* Generic_GPIO primitives.
*/
int gpio_request(unsigned gpio, const char *label)
static int tegra_gpio_request(struct udevice *dev, unsigned offset,
const char *label)
{
if (gpio >= MAX_NUM_GPIOS)
return -1;
struct tegra_port_info *state = dev_get_priv(dev);
if (label != NULL) {
strncpy(gpio_names[gpio].name, label, GPIO_NAME_SIZE);
gpio_names[gpio].name[GPIO_NAME_SIZE - 1] = '\0';
}
if (*state->label[offset])
return -EBUSY;
strncpy(state->label[offset], label, GPIO_NAME_SIZE);
state->label[offset][GPIO_NAME_SIZE - 1] = '\0';
/* Configure as a GPIO */
set_config(gpio, 1);
set_config(state->base_gpio + offset, 1);
return 0;
}
int gpio_free(unsigned gpio)
static int tegra_gpio_free(struct udevice *dev, unsigned offset)
{
if (gpio >= MAX_NUM_GPIOS)
return -1;
struct tegra_port_info *state = dev_get_priv(dev);
int ret;
ret = check_reserved(dev, offset, __func__);
if (ret)
return ret;
state->label[offset][0] = '\0';
gpio_names[gpio].name[0] = '\0';
/* Do not configure as input or change pin mux here */
return 0;
}
/* read GPIO OUT value of pin 'gpio' */
static int gpio_get_output_value(unsigned gpio)
static int tegra_gpio_get_output_value(unsigned gpio)
{
struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
@@ -166,24 +211,34 @@ static int gpio_get_output_value(unsigned gpio)
return (val >> GPIO_BIT(gpio)) & 1;
}
/* set GPIO pin 'gpio' as an input */
int gpio_direction_input(unsigned gpio)
static int tegra_gpio_direction_input(struct udevice *dev, unsigned offset)
{
debug("gpio_direction_input: pin = %d (port %d:bit %d)\n",
gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio));
struct tegra_port_info *state = dev_get_priv(dev);
int ret;
ret = check_reserved(dev, offset, __func__);
if (ret)
return ret;
/* Configure GPIO direction as input. */
set_direction(gpio, 0);
set_direction(state->base_gpio + offset, 0);
return 0;
}
/* set GPIO pin 'gpio' as an output, with polarity 'value' */
int gpio_direction_output(unsigned gpio, int value)
static int tegra_gpio_direction_output(struct udevice *dev, unsigned offset,
int value)
{
debug("gpio_direction_output: pin = %d (port %d:bit %d) = %s\n",
gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio),
value ? "HIGH" : "LOW");
struct tegra_port_info *state = dev_get_priv(dev);
int gpio = state->base_gpio + offset;
int ret;
ret = check_reserved(dev, offset, __func__);
if (ret)
return ret;
/* Configure GPIO output value. */
set_level(gpio, value);
@@ -195,25 +250,38 @@ int gpio_direction_output(unsigned gpio, int value)
}
/* read GPIO IN value of pin 'gpio' */
int gpio_get_value(unsigned gpio)
static int tegra_gpio_get_value(struct udevice *dev, unsigned offset)
{
struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
struct tegra_port_info *state = dev_get_priv(dev);
int gpio = state->base_gpio + offset;
int ret;
int val;
debug("gpio_get_value: pin = %d (port %d:bit %d)\n",
gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio));
ret = check_reserved(dev, offset, __func__);
if (ret)
return ret;
val = readl(&bank->gpio_in[GPIO_PORT(gpio)]);
debug("%s: pin = %d (port %d:bit %d)\n", __func__,
gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio));
val = readl(&state->bank->gpio_in[GPIO_PORT(gpio)]);
return (val >> GPIO_BIT(gpio)) & 1;
}
/* write GPIO OUT value to pin 'gpio' */
int gpio_set_value(unsigned gpio, int value)
static int tegra_gpio_set_value(struct udevice *dev, unsigned offset, int value)
{
struct tegra_port_info *state = dev_get_priv(dev);
int gpio = state->base_gpio + offset;
int ret;
ret = check_reserved(dev, offset, __func__);
if (ret)
return ret;
debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n",
gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value);
gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value);
/* Configure GPIO output value. */
set_level(gpio, value);
@@ -241,26 +309,175 @@ void gpio_config_table(const struct tegra_gpio_config *config, int len)
}
}
/*
* Display Tegra GPIO information
*/
void gpio_info(void)
static int tegra_gpio_get_function(struct udevice *dev, unsigned offset)
{
unsigned c;
int type;
struct tegra_port_info *state = dev_get_priv(dev);
int gpio = state->base_gpio + offset;
for (c = 0; c < MAX_NUM_GPIOS; c++) {
type = get_config(c); /* GPIO, not SFPIO */
if (type) {
printf("GPIO_%d:\t%s is an %s, ", c,
get_name(c),
get_direction(c) ? "OUTPUT" : "INPUT");
if (get_direction(c))
printf("value = %d", gpio_get_output_value(c));
else
printf("value = %d", gpio_get_value(c));
printf("\n");
} else
continue;
}
if (!*state->label[offset])
return GPIOF_UNUSED;
if (!get_config(gpio))
return GPIOF_FUNC;
else if (get_direction(gpio))
return GPIOF_OUTPUT;
else
return GPIOF_INPUT;
}
static int tegra_gpio_get_state(struct udevice *dev, unsigned int offset,
char *buf, int bufsize)
{
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
struct tegra_port_info *state = dev_get_priv(dev);
int gpio = state->base_gpio + offset;
const char *label;
int is_output;
int is_gpio;
int size;
label = state->label[offset];
is_gpio = get_config(gpio); /* GPIO, not SFPIO */
size = snprintf(buf, bufsize, "%s%d: ",
uc_priv->bank_name ? uc_priv->bank_name : "", offset);
buf += size;
bufsize -= size;
if (is_gpio) {
is_output = get_direction(gpio);
snprintf(buf, bufsize, "%s: %d [%c]%s%s",
is_output ? "out" : " in",
is_output ?
tegra_gpio_get_output_value(gpio) :
tegra_gpio_get_value(dev, offset),
*label ? 'x' : ' ',
*label ? " " : "",
label);
} else {
snprintf(buf, bufsize, "sfpio");
}
return 0;
}
static const struct dm_gpio_ops gpio_tegra_ops = {
.request = tegra_gpio_request,
.free = tegra_gpio_free,
.direction_input = tegra_gpio_direction_input,
.direction_output = tegra_gpio_direction_output,
.get_value = tegra_gpio_get_value,
.set_value = tegra_gpio_set_value,
.get_function = tegra_gpio_get_function,
.get_state = tegra_gpio_get_state,
};
/**
* Returns the name of a GPIO port
*
* GPIOs are named A, B, C, ..., Z, AA, BB, CC, ...
*
* @base_port: Base port number (0, 1..n-1)
* @return allocated string containing the name
*/
static char *gpio_port_name(int base_port)
{
char *name, *s;
name = malloc(3);
if (name) {
s = name;
*s++ = 'A' + (base_port % 26);
if (base_port >= 26)
*s++ = *name;
*s = '\0';
}
return name;
}
static const struct udevice_id tegra_gpio_ids[] = {
{ .compatible = "nvidia,tegra30-gpio" },
{ .compatible = "nvidia,tegra20-gpio" },
{ }
};
static int gpio_tegra_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
struct tegra_port_info *priv = dev->priv;
struct tegra_gpio_platdata *plat = dev->platdata;
/* Only child devices have ports */
if (!plat)
return 0;
priv->bank = plat->bank;
priv->base_gpio = plat->base_gpio;
uc_priv->gpio_count = TEGRA_GPIOS_PER_PORT;
uc_priv->bank_name = plat->port_name;
return 0;
}
/**
* We have a top-level GPIO device with no actual GPIOs. It has a child
* device for each Tegra port.
*/
static int gpio_tegra_bind(struct udevice *parent)
{
struct tegra_gpio_platdata *plat = parent->platdata;
struct gpio_ctlr *ctlr;
int bank_count;
int bank;
int ret;
int len;
/* If this is a child device, there is nothing to do here */
if (plat)
return 0;
/*
* This driver does not make use of interrupts, other than to figure
* out the number of GPIO banks
*/
if (!fdt_getprop(gd->fdt_blob, parent->of_offset, "interrupts", &len))
return -EINVAL;
bank_count = len / 3 / sizeof(u32);
ctlr = (struct gpio_ctlr *)fdtdec_get_addr(gd->fdt_blob,
parent->of_offset, "reg");
for (bank = 0; bank < bank_count; bank++) {
int port;
for (port = 0; port < TEGRA_PORTS_PER_BANK; port++) {
struct tegra_gpio_platdata *plat;
struct udevice *dev;
int base_port;
plat = calloc(1, sizeof(*plat));
if (!plat)
return -ENOMEM;
plat->bank = &ctlr->gpio_bank[bank];
base_port = bank * TEGRA_PORTS_PER_BANK + port;
plat->base_gpio = TEGRA_GPIOS_PER_PORT * base_port;
plat->port_name = gpio_port_name(base_port);
ret = device_bind(parent, parent->driver,
plat->port_name, plat, -1, &dev);
if (ret)
return ret;
dev->of_offset = parent->of_offset;
}
}
return 0;
}
U_BOOT_DRIVER(gpio_tegra) = {
.name = "gpio_tegra",
.id = UCLASS_GPIO,
.of_match = tegra_gpio_ids,
.bind = gpio_tegra_bind,
.probe = gpio_tegra_probe,
.priv_auto_alloc_size = sizeof(struct tegra_port_info),
.ops = &gpio_tegra_ops,
};

View File

@@ -5,7 +5,12 @@
# SPDX-License-Identifier: GPL-2.0+
#
ifdef CONFIG_DM_SERIAL
obj-y += serial-uclass.o
else
obj-y += serial.o
obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
endif
obj-$(CONFIG_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
@@ -16,7 +21,6 @@ obj-$(CONFIG_MCFUART) += mcfuart.o
obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o
obj-$(CONFIG_SYS_NS16550) += ns16550.o
obj-$(CONFIG_S5P) += serial_s5p.o
obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
obj-$(CONFIG_IMX_SERIAL) += serial_imx.o
obj-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o
obj-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
@@ -34,6 +38,7 @@ obj-$(CONFIG_BFIN_SERIAL) += serial_bfin.o
obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o
obj-$(CONFIG_MXS_AUART) += mxs_auart.o
obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_USB_TTY) += usbtty.o

View File

@@ -4,18 +4,26 @@
* modified to use CONFIG_SYS_ISA_MEM and new defines
*/
#include <config.h>
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <ns16550.h>
#include <serial.h>
#include <watchdog.h>
#include <linux/types.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
#define UART_LCRVAL UART_LCR_8N1 /* 8 data, 1 stop, no parity */
#define UART_MCRVAL (UART_MCR_DTR | \
UART_MCR_RTS) /* RTS/DTR */
#define UART_FCRVAL (UART_FCR_FIFO_EN | \
UART_FCR_RXSR | \
UART_FCR_TXSR) /* Clear & enable FIFOs */
#ifndef CONFIG_DM_SERIAL
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
#define serial_out(x, y) outb(x, (ulong)y)
#define serial_in(y) inb((ulong)y)
@@ -29,6 +37,7 @@
#define serial_out(x, y) writeb(x, y)
#define serial_in(y) readb(y)
#endif
#endif /* !CONFIG_DM_SERIAL */
#if defined(CONFIG_SOC_KEYSTONE)
#define UART_REG_VAL_PWREMU_MGMT_UART_DISABLE 0
@@ -45,6 +54,82 @@
#define CONFIG_SYS_NS16550_IER 0x00
#endif /* CONFIG_SYS_NS16550_IER */
#ifdef CONFIG_DM_SERIAL
static void ns16550_writeb(NS16550_t port, int offset, int value)
{
struct ns16550_platdata *plat = port->plat;
unsigned char *addr;
offset *= 1 << plat->reg_shift;
addr = plat->base + offset;
/*
* As far as we know it doesn't make sense to support selection of
* these options at run-time, so use the existing CONFIG options.
*/
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
outb(value, addr);
#elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN)
out_le32(addr, value);
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
out_be32(addr, value);
#elif defined(CONFIG_SYS_BIG_ENDIAN)
writeb(value, addr + (1 << plat->reg_shift) - 1);
#else
writeb(value, addr);
#endif
}
static int ns16550_readb(NS16550_t port, int offset)
{
struct ns16550_platdata *plat = port->plat;
unsigned char *addr;
offset *= 1 << plat->reg_shift;
addr = plat->base + offset;
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
return inb(addr);
#elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN)
return in_le32(addr);
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
return in_be32(addr);
#elif defined(CONFIG_SYS_BIG_ENDIAN)
return readb(addr + (1 << plat->reg_shift) - 1);
#else
return readb(addr);
#endif
}
/* We can clean these up once everything is moved to driver model */
#define serial_out(value, addr) \
ns16550_writeb(com_port, addr - (unsigned char *)com_port, value)
#define serial_in(addr) \
ns16550_readb(com_port, addr - (unsigned char *)com_port)
#endif
int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
{
const unsigned int mode_x_div = 16;
#ifdef CONFIG_OMAP1510
/* If can't cleanly clock 115200 set div to 1 */
if ((clock == 12000000) && (baudrate == 115200)) {
port->osc_12m_sel = OSC_12M_SEL; /* enable 6.5 * divisor */
return 1; /* return 1 for base divisor */
}
port->osc_12m_sel = 0; /* clear if previsouly set */
#endif
return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
}
static void NS16550_setbrg(NS16550_t com_port, int baud_divisor)
{
serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
serial_out(baud_divisor & 0xff, &com_port->dll);
serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
serial_out(UART_LCRVAL, &com_port->lcr);
}
void NS16550_init(NS16550_t com_port, int baud_divisor)
{
#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_OMAP34XX))
@@ -55,10 +140,8 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
*/
if ((serial_in(&com_port->lsr) & (UART_LSR_TEMT | UART_LSR_THRE))
== UART_LSR_THRE) {
serial_out(UART_LCR_DLAB, &com_port->lcr);
serial_out(baud_divisor & 0xff, &com_port->dll);
serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
serial_out(UART_LCRVAL, &com_port->lcr);
if (baud_divisor != -1)
NS16550_setbrg(com_port, baud_divisor);
serial_out(0, &com_port->mdr1);
}
#endif
@@ -71,16 +154,11 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX)
serial_out(0x7, &com_port->mdr1); /* mode select reset TL16C750*/
#endif
serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
serial_out(0, &com_port->dll);
serial_out(0, &com_port->dlm);
serial_out(UART_LCRVAL, &com_port->lcr);
NS16550_setbrg(com_port, 0);
serial_out(UART_MCRVAL, &com_port->mcr);
serial_out(UART_FCRVAL, &com_port->fcr);
serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
serial_out(baud_divisor & 0xff, &com_port->dll);
serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
serial_out(UART_LCRVAL, &com_port->lcr);
if (baud_divisor != -1)
NS16550_setbrg(com_port, baud_divisor);
#if defined(CONFIG_OMAP) || \
defined(CONFIG_AM33XX) || defined(CONFIG_SOC_DA8XX) || \
defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX)
@@ -97,16 +175,10 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
void NS16550_reinit(NS16550_t com_port, int baud_divisor)
{
serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
serial_out(0, &com_port->dll);
serial_out(0, &com_port->dlm);
serial_out(UART_LCRVAL, &com_port->lcr);
NS16550_setbrg(com_port, 0);
serial_out(UART_MCRVAL, &com_port->mcr);
serial_out(UART_FCRVAL, &com_port->fcr);
serial_out(UART_LCR_BKSE, &com_port->lcr);
serial_out(baud_divisor & 0xff, &com_port->dll);
serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
serial_out(UART_LCRVAL, &com_port->lcr);
NS16550_setbrg(com_port, baud_divisor);
}
#endif /* CONFIG_NS16550_MIN_FUNCTIONS */
@@ -145,3 +217,92 @@ int NS16550_tstc(NS16550_t com_port)
}
#endif /* CONFIG_NS16550_MIN_FUNCTIONS */
#ifdef CONFIG_DM_SERIAL
static int ns16550_serial_putc(struct udevice *dev, const char ch)
{
struct NS16550 *const com_port = dev_get_priv(dev);
if (!(serial_in(&com_port->lsr) & UART_LSR_THRE))
return -EAGAIN;
serial_out(ch, &com_port->thr);
/*
* Call watchdog_reset() upon newline. This is done here in putc
* since the environment code uses a single puts() to print the complete
* environment upon "printenv". So we can't put this watchdog call
* in puts().
*/
if (ch == '\n')
WATCHDOG_RESET();
return 0;
}
static int ns16550_serial_pending(struct udevice *dev, bool input)
{
struct NS16550 *const com_port = dev_get_priv(dev);
if (input)
return serial_in(&com_port->lsr) & UART_LSR_DR ? 1 : 0;
else
return serial_in(&com_port->lsr) & UART_LSR_THRE ? 0 : 1;
}
static int ns16550_serial_getc(struct udevice *dev)
{
struct NS16550 *const com_port = dev_get_priv(dev);
if (!serial_in(&com_port->lsr) & UART_LSR_DR)
return -EAGAIN;
return serial_in(&com_port->rbr);
}
static int ns16550_serial_setbrg(struct udevice *dev, int baudrate)
{
struct NS16550 *const com_port = dev_get_priv(dev);
struct ns16550_platdata *plat = com_port->plat;
int clock_divisor;
clock_divisor = ns16550_calc_divisor(com_port, plat->clock, baudrate);
NS16550_setbrg(com_port, clock_divisor);
return 0;
}
int ns16550_serial_probe(struct udevice *dev)
{
struct NS16550 *const com_port = dev_get_priv(dev);
NS16550_init(com_port, -1);
return 0;
}
int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
{
struct NS16550 *const com_port = dev_get_priv(dev);
struct ns16550_platdata *plat = dev->platdata;
fdt_addr_t addr;
addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
plat->base = (unsigned char *)addr;
plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"reg-shift", 1);
com_port->plat = plat;
return 0;
}
const struct dm_serial_ops ns16550_serial_ops = {
.putc = ns16550_serial_putc,
.pending = ns16550_serial_pending,
.getc = ns16550_serial_getc,
.setbrg = ns16550_serial_setbrg,
};
#endif /* CONFIG_DM_SERIAL */

View File

@@ -11,12 +11,16 @@
*/
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
#include <lcd.h>
#include <os.h>
#include <serial.h>
#include <linux/compiler.h>
#include <asm/state.h>
DECLARE_GLOBAL_DATA_PTR;
/*
*
* serial_buf: A buffer that holds keyboard characters for the
@@ -30,27 +34,69 @@ static char serial_buf[16];
static unsigned int serial_buf_write;
static unsigned int serial_buf_read;
static int sandbox_serial_init(void)
struct sandbox_serial_platdata {
int colour; /* Text colour to use for output, -1 for none */
};
struct sandbox_serial_priv {
bool start_of_line;
};
/**
* output_ansi_colour() - Output an ANSI colour code
*
* @colour: Colour to output (0-7)
*/
static void output_ansi_colour(int colour)
{
char ansi_code[] = "\x1b[1;3Xm";
ansi_code[5] = '0' + colour;
os_write(1, ansi_code, sizeof(ansi_code) - 1);
}
static void output_ansi_reset(void)
{
os_write(1, "\x1b[0m", 4);
}
static int sandbox_serial_probe(struct udevice *dev)
{
struct sandbox_state *state = state_get_current();
struct sandbox_serial_priv *priv = dev_get_priv(dev);
if (state->term_raw != STATE_TERM_COOKED)
os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
priv->start_of_line = 0;
return 0;
}
static void sandbox_serial_setbrg(void)
static int sandbox_serial_remove(struct udevice *dev)
{
struct sandbox_serial_platdata *plat = dev->platdata;
if (plat->colour != -1)
output_ansi_reset();
return 0;
}
static void sandbox_serial_putc(const char ch)
static int sandbox_serial_putc(struct udevice *dev, const char ch)
{
struct sandbox_serial_priv *priv = dev_get_priv(dev);
struct sandbox_serial_platdata *plat = dev->platdata;
if (priv->start_of_line && plat->colour != -1) {
priv->start_of_line = false;
output_ansi_colour(plat->colour);
}
os_write(1, &ch, 1);
}
if (ch == '\n')
priv->start_of_line = true;
static void sandbox_serial_puts(const char *str)
{
os_write(1, str, strlen(str));
return 0;
}
static unsigned int increment_buffer_index(unsigned int index)
@@ -58,12 +104,15 @@ static unsigned int increment_buffer_index(unsigned int index)
return (index + 1) % ARRAY_SIZE(serial_buf);
}
static int sandbox_serial_tstc(void)
static int sandbox_serial_pending(struct udevice *dev, bool input)
{
const unsigned int next_index =
increment_buffer_index(serial_buf_write);
ssize_t count;
if (!input)
return 0;
os_usleep(100);
#ifdef CONFIG_LCD
lcd_sync();
@@ -74,38 +123,77 @@ static int sandbox_serial_tstc(void)
count = os_read_no_block(0, &serial_buf[serial_buf_write], 1);
if (count == 1)
serial_buf_write = next_index;
return serial_buf_write != serial_buf_read;
}
static int sandbox_serial_getc(void)
static int sandbox_serial_getc(struct udevice *dev)
{
int result;
while (!sandbox_serial_tstc())
; /* buffer empty */
if (!sandbox_serial_pending(dev, true))
return -EAGAIN; /* buffer empty */
result = serial_buf[serial_buf_read];
serial_buf_read = increment_buffer_index(serial_buf_read);
return result;
}
static struct serial_device sandbox_serial_drv = {
.name = "sandbox_serial",
.start = sandbox_serial_init,
.stop = NULL,
.setbrg = sandbox_serial_setbrg,
.putc = sandbox_serial_putc,
.puts = sandbox_serial_puts,
.getc = sandbox_serial_getc,
.tstc = sandbox_serial_tstc,
static const char * const ansi_colour[] = {
"black", "red", "green", "yellow", "blue", "megenta", "cyan",
"white",
};
void sandbox_serial_initialize(void)
static int sandbox_serial_ofdata_to_platdata(struct udevice *dev)
{
serial_register(&sandbox_serial_drv);
struct sandbox_serial_platdata *plat = dev->platdata;
const char *colour;
int i;
plat->colour = -1;
colour = fdt_getprop(gd->fdt_blob, dev->of_offset,
"sandbox,text-colour", NULL);
if (colour) {
for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
if (!strcmp(colour, ansi_colour[i])) {
plat->colour = i;
break;
}
}
}
return 0;
}
__weak struct serial_device *default_serial_console(void)
{
return &sandbox_serial_drv;
}
static const struct dm_serial_ops sandbox_serial_ops = {
.putc = sandbox_serial_putc,
.pending = sandbox_serial_pending,
.getc = sandbox_serial_getc,
};
static const struct udevice_id sandbox_serial_ids[] = {
{ .compatible = "sandbox,serial" },
{ }
};
U_BOOT_DRIVER(serial_sandbox) = {
.name = "serial_sandbox",
.id = UCLASS_SERIAL,
.of_match = sandbox_serial_ids,
.ofdata_to_platdata = sandbox_serial_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct sandbox_serial_platdata),
.priv_auto_alloc_size = sizeof(struct sandbox_serial_priv),
.probe = sandbox_serial_probe,
.remove = sandbox_serial_remove,
.ops = &sandbox_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
static const struct sandbox_serial_platdata platdata_non_fdt = {
.colour = -1,
};
U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
.name = "serial_sandbox",
.platdata = &platdata_non_fdt,
};

View File

@@ -0,0 +1,213 @@
/*
* Copyright (c) 2014 The Chromium OS Authors.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <os.h>
#include <serial.h>
#include <stdio_dev.h>
#include <dm/lists.h>
#include <dm/device-internal.h>
DECLARE_GLOBAL_DATA_PTR;
/* The currently-selected console serial device */
struct udevice *cur_dev __attribute__ ((section(".data")));
#ifndef CONFIG_SYS_MALLOC_F_LEN
#error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work"
#endif
static void serial_find_console_or_panic(void)
{
int node;
/* Check for a chosen console */
node = fdtdec_get_chosen_node(gd->fdt_blob, "stdout-path");
if (node < 0)
node = fdtdec_get_alias_node(gd->fdt_blob, "console");
if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &cur_dev))
return;
/*
* If the console is not marked to be bound before relocation, bind
* it anyway.
*/
if (node > 0 &&
!lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &cur_dev)) {
if (!device_probe(cur_dev))
return;
cur_dev = NULL;
}
/*
* Failing that, get the device with sequence number 0, or in extremis
* just the first serial device we can find. But we insist on having
* a console (even if it is silent).
*/
if (uclass_get_device_by_seq(UCLASS_SERIAL, 0, &cur_dev) &&
(uclass_first_device(UCLASS_SERIAL, &cur_dev) || !cur_dev))
panic("No serial driver found");
}
/* Called prior to relocation */
int serial_init(void)
{
serial_find_console_or_panic();
gd->flags |= GD_FLG_SERIAL_READY;
return 0;
}
/* Called after relocation */
void serial_initialize(void)
{
serial_find_console_or_panic();
}
void serial_putc(char ch)
{
struct dm_serial_ops *ops = serial_get_ops(cur_dev);
int err;
do {
err = ops->putc(cur_dev, ch);
} while (err == -EAGAIN);
if (ch == '\n')
serial_putc('\r');
}
void serial_setbrg(void)
{
struct dm_serial_ops *ops = serial_get_ops(cur_dev);
if (ops->setbrg)
ops->setbrg(cur_dev, gd->baudrate);
}
void serial_puts(const char *str)
{
while (*str)
serial_putc(*str++);
}
int serial_tstc(void)
{
struct dm_serial_ops *ops = serial_get_ops(cur_dev);
if (ops->pending)
return ops->pending(cur_dev, true);
return 1;
}
int serial_getc(void)
{
struct dm_serial_ops *ops = serial_get_ops(cur_dev);
int err;
do {
err = ops->getc(cur_dev);
} while (err == -EAGAIN);
return err >= 0 ? err : 0;
}
void serial_stdio_init(void)
{
}
void serial_stub_putc(struct stdio_dev *sdev, const char ch)
{
struct udevice *dev = sdev->priv;
struct dm_serial_ops *ops = serial_get_ops(dev);
ops->putc(dev, ch);
}
void serial_stub_puts(struct stdio_dev *sdev, const char *str)
{
while (*str)
serial_stub_putc(sdev, *str++);
}
int serial_stub_getc(struct stdio_dev *sdev)
{
struct udevice *dev = sdev->priv;
struct dm_serial_ops *ops = serial_get_ops(dev);
int err;
do {
err = ops->getc(dev);
} while (err == -EAGAIN);
return err >= 0 ? err : 0;
}
int serial_stub_tstc(struct stdio_dev *sdev)
{
struct udevice *dev = sdev->priv;
struct dm_serial_ops *ops = serial_get_ops(dev);
if (ops->pending)
return ops->pending(dev, true);
return 1;
}
static int serial_post_probe(struct udevice *dev)
{
struct stdio_dev sdev;
struct dm_serial_ops *ops = serial_get_ops(dev);
struct serial_dev_priv *upriv = dev->uclass_priv;
int ret;
/* Set the baud rate */
if (ops->setbrg) {
ret = ops->setbrg(dev, gd->baudrate);
if (ret)
return ret;
}
if (!(gd->flags & GD_FLG_RELOC))
return 0;
memset(&sdev, '\0', sizeof(sdev));
strncpy(sdev.name, dev->name, sizeof(sdev.name));
sdev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
sdev.priv = dev;
sdev.putc = serial_stub_putc;
sdev.puts = serial_stub_puts;
sdev.getc = serial_stub_getc;
sdev.tstc = serial_stub_tstc;
stdio_register_dev(&sdev, &upriv->sdev);
return 0;
}
static int serial_pre_remove(struct udevice *dev)
{
#ifdef CONFIG_SYS_STDIO_DEREGISTER
struct serial_dev_priv *upriv = dev->uclass_priv;
if (stdio_deregister_dev(upriv->sdev))
return -EPERM;
#endif
return 0;
}
UCLASS_DRIVER(serial) = {
.id = UCLASS_SERIAL,
.name = "serial",
.post_probe = serial_post_probe,
.pre_remove = serial_pre_remove,
.per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
};

View File

@@ -320,6 +320,7 @@ void serial_stdio_init(void)
dev.puts = serial_stub_puts;
dev.getc = serial_stub_getc;
dev.tstc = serial_stub_tstc;
dev.priv = s;
stdio_register(&dev);

View File

@@ -81,7 +81,8 @@ static NS16550_t serial_ports[6] = {
static int eserial##port##_init(void) \
{ \
int clock_divisor; \
clock_divisor = calc_divisor(serial_ports[port-1]); \
clock_divisor = ns16550_calc_divisor(serial_ports[port-1], \
CONFIG_SYS_NS16550_CLK, gd->baudrate); \
NS16550_init(serial_ports[port-1], clock_divisor); \
return 0 ; \
} \
@@ -118,14 +119,6 @@ static NS16550_t serial_ports[6] = {
.puts = eserial##port##_puts, \
}
static int calc_divisor (NS16550_t port)
{
const unsigned int mode_x_div = 16;
return DIV_ROUND_CLOSEST(CONFIG_SYS_NS16550_CLK,
mode_x_div * gd->baudrate);
}
void
_serial_putc(const char c,const int port)
{
@@ -167,7 +160,8 @@ _serial_setbrg (const int port)
{
int clock_divisor;
clock_divisor = calc_divisor(PORT);
clock_divisor = ns16550_calc_divisor(PORT, CONFIG_SYS_NS16550_CLK,
gd->baudrate);
NS16550_reinit(PORT, clock_divisor);
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2014 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <ns16550.h>
#include <serial.h>
static const struct udevice_id tegra_serial_ids[] = {
{ .compatible = "nvidia,tegra20-uart" },
{ }
};
static int tegra_serial_ofdata_to_platdata(struct udevice *dev)
{
struct ns16550_platdata *plat = dev_get_platdata(dev);
int ret;
ret = ns16550_serial_ofdata_to_platdata(dev);
if (ret)
return ret;
plat->clock = V_NS16550_CLK;
return 0;
}
U_BOOT_DRIVER(serial_ns16550) = {
.name = "serial_tegra20",
.id = UCLASS_SERIAL,
.of_match = tegra_serial_ids,
.ofdata_to_platdata = tegra_serial_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
.priv_auto_alloc_size = sizeof(struct NS16550),
.probe = ns16550_serial_probe,
.ops = &ns16550_serial_ops,
};