mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-28 07:03:31 +08:00
Merge git://git.denx.de/u-boot-dm
Conflicts: drivers/serial/serial-uclass.c Signed-off-by: Tom Rini <trini@ti.com>
This commit is contained in:
commit
1739564e75
119
README
119
README
@ -623,6 +623,120 @@ The following options need to be configured:
|
||||
exists, unlike the similar options in the Linux kernel. Do not
|
||||
set these options unless they apply!
|
||||
|
||||
- Driver Model
|
||||
Driver model is a new framework for devices in U-Boot
|
||||
introduced in early 2014. U-Boot is being progressively
|
||||
moved over to this. It offers a consistent device structure,
|
||||
supports grouping devices into classes and has built-in
|
||||
handling of platform data and device tree.
|
||||
|
||||
To enable transition to driver model in a relatively
|
||||
painful fashion, each subsystem can be independently
|
||||
switched between the legacy/ad-hoc approach and the new
|
||||
driver model using the options below. Also, many uclass
|
||||
interfaces include compatibility features which may be
|
||||
removed once the conversion of that subsystem is complete.
|
||||
As a result, the API provided by the subsystem may in fact
|
||||
not change with driver model.
|
||||
|
||||
See doc/driver-model/README.txt for more information.
|
||||
|
||||
CONFIG_DM
|
||||
|
||||
Enable driver model. This brings in the core support,
|
||||
including scanning of platform data on start-up. If
|
||||
CONFIG_OF_CONTROL is enabled, the device tree will be
|
||||
scanned also when available.
|
||||
|
||||
CONFIG_CMD_DM
|
||||
|
||||
Enable driver model test commands. These allow you to print
|
||||
out the driver model tree and the uclasses.
|
||||
|
||||
CONFIG_DM_DEMO
|
||||
|
||||
Enable some demo devices and the 'demo' command. These are
|
||||
really only useful for playing around while trying to
|
||||
understand driver model in sandbox.
|
||||
|
||||
CONFIG_SPL_DM
|
||||
|
||||
Enable driver model in SPL. You will need to provide a
|
||||
suitable malloc() implementation. If you are not using the
|
||||
full malloc() enabled by CONFIG_SYS_SPL_MALLOC_START,
|
||||
consider using CONFIG_SYS_MALLOC_SIMPLE. In that case you
|
||||
must provide CONFIG_SYS_MALLOC_F_LEN to set the size.
|
||||
In most cases driver model will only allocate a few uclasses
|
||||
and devices in SPL, so 1KB should be enable. See
|
||||
CONFIG_SYS_MALLOC_F_LEN for more details on how to enable
|
||||
it.
|
||||
|
||||
CONFIG_DM_SERIAL
|
||||
|
||||
Enable driver model for serial. This replaces
|
||||
drivers/serial/serial.c with the serial uclass, which
|
||||
implements serial_putc() etc. The uclass interface is
|
||||
defined in include/serial.h.
|
||||
|
||||
CONFIG_DM_GPIO
|
||||
|
||||
Enable driver model for GPIO access. The standard GPIO
|
||||
interface (gpio_get_value(), etc.) is then implemented by
|
||||
the GPIO uclass. Drivers provide methods to query the
|
||||
particular GPIOs that they provide. The uclass interface
|
||||
is defined in include/asm-generic/gpio.h.
|
||||
|
||||
CONFIG_DM_SPI
|
||||
|
||||
Enable driver model for SPI. The SPI slave interface
|
||||
(spi_setup_slave(), spi_xfer(), etc.) is then implemented by
|
||||
the SPI uclass. Drivers provide methods to access the SPI
|
||||
buses that they control. The uclass interface is defined in
|
||||
include/spi.h. The existing spi_slave structure is attached
|
||||
as 'parent data' to every slave on each bus. Slaves
|
||||
typically use driver-private data instead of extending the
|
||||
spi_slave structure.
|
||||
|
||||
CONFIG_DM_SPI_FLASH
|
||||
|
||||
Enable driver model for SPI flash. This SPI flash interface
|
||||
(spi_flash_probe(), spi_flash_write(), etc.) is then
|
||||
implemented by the SPI flash uclass. There is one standard
|
||||
SPI flash driver which knows how to probe most chips
|
||||
supported by U-Boot. The uclass interface is defined in
|
||||
include/spi_flash.h, but is currently fully compatible
|
||||
with the old interface to avoid confusion and duplication
|
||||
during the transition parent. SPI and SPI flash must be
|
||||
enabled together (it is not possible to use driver model
|
||||
for one and not the other).
|
||||
|
||||
CONFIG_DM_CROS_EC
|
||||
|
||||
Enable driver model for the Chrome OS EC interface. This
|
||||
allows the cros_ec SPI driver to operate with CONFIG_DM_SPI
|
||||
but otherwise makes few changes. Since cros_ec also supports
|
||||
I2C and LPC (which don't support driver model yet), a full
|
||||
conversion is not yet possible.
|
||||
|
||||
|
||||
** Code size options: The following options are enabled by
|
||||
default except in SPL. Enable them explicitly to get these
|
||||
features in SPL.
|
||||
|
||||
CONFIG_DM_WARN
|
||||
|
||||
Enable the dm_warn() function. This can use up quite a bit
|
||||
of space for its strings.
|
||||
|
||||
CONFIG_DM_STDIO
|
||||
|
||||
Enable registering a serial device with the stdio library.
|
||||
|
||||
CONFIG_DM_DEVICE_REMOVE
|
||||
|
||||
Enable removing of devices.
|
||||
|
||||
|
||||
- Linux Kernel Interface:
|
||||
CONFIG_CLOCKS_IN_MHZ
|
||||
|
||||
@ -3870,6 +3984,11 @@ Configuration Settings:
|
||||
Pre-relocation malloc() is only supported on ARM and sandbox
|
||||
at present but is fairly easy to enable for other archs.
|
||||
|
||||
- CONFIG_SYS_MALLOC_SIMPLE
|
||||
Provides a simple and small malloc() and calloc() for those
|
||||
boards which do not use the full malloc in SPL (which is
|
||||
enabled with CONFIG_SYS_SPL_MALLOC_START).
|
||||
|
||||
- CONFIG_SYS_BOOTM_LEN:
|
||||
Normally compressed uImages are limited to an
|
||||
uncompressed size of 8 MBytes. If this is not enough,
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/at91sam9260_matrix.h>
|
||||
#include <asm/arch/at91_common.h>
|
||||
@ -229,3 +230,16 @@ void at91_sdram_hw_init(void)
|
||||
at91_set_a_periph(AT91_PIO_PORTC, 30, 0);
|
||||
at91_set_a_periph(AT91_PIO_PORTC, 31, 0);
|
||||
}
|
||||
|
||||
/* Platform data for the GPIOs */
|
||||
static const struct at91_port_platdata at91sam9260_plat[] = {
|
||||
{ ATMEL_BASE_PIOA, "PA" },
|
||||
{ ATMEL_BASE_PIOB, "PB" },
|
||||
{ ATMEL_BASE_PIOC, "PC" },
|
||||
};
|
||||
|
||||
U_BOOT_DEVICES(at91sam9260_gpios) = {
|
||||
{ "gpio_at91", &at91sam9260_plat[0] },
|
||||
{ "gpio_at91", &at91sam9260_plat[1] },
|
||||
{ "gpio_at91", &at91sam9260_plat[2] },
|
||||
};
|
||||
|
@ -34,6 +34,13 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
|
||||
. = .;
|
||||
#ifdef CONFIG_SPL_DM
|
||||
.u_boot_list : {
|
||||
KEEP(*(SORT(.u_boot_list_*_driver_*)));
|
||||
KEEP(*(SORT(.u_boot_list_*_uclass_*)));
|
||||
}
|
||||
#endif
|
||||
. = ALIGN(4);
|
||||
|
||||
__image_copy_end = .;
|
||||
|
||||
|
@ -136,9 +136,11 @@
|
||||
/*
|
||||
* Other misc defines
|
||||
*/
|
||||
#ifndef CONFIG_DM_GPIO
|
||||
#define ATMEL_PIO_PORTS 3 /* these SoCs have 3 PIO */
|
||||
#define ATMEL_PMC_UHP AT91SAM926x_PMC_UHP
|
||||
#define ATMEL_BASE_PIO ATMEL_BASE_PIOA
|
||||
#endif
|
||||
#define ATMEL_PMC_UHP AT91SAM926x_PMC_UHP
|
||||
|
||||
/*
|
||||
* SoC specific defines
|
||||
|
15
arch/arm/include/asm/arch-at91/atmel_serial.h
Normal file
15
arch/arm/include/asm/arch-at91/atmel_serial.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _ATMEL_SERIAL_H
|
||||
#define _ATMEL_SERIAL_H
|
||||
|
||||
/* Information about a serial port */
|
||||
struct atmel_serial_platdata {
|
||||
uint32_t base_addr;
|
||||
};
|
||||
|
||||
#endif
|
@ -253,4 +253,10 @@ static inline unsigned at91_gpio_to_pin(unsigned gpio)
|
||||
return gpio % 32;
|
||||
}
|
||||
|
||||
/* Platform data for each GPIO port */
|
||||
struct at91_port_platdata {
|
||||
uint32_t base_addr;
|
||||
const char *bank_name;
|
||||
};
|
||||
|
||||
#endif /* __ASM_ARCH_AT91_GPIO_H */
|
||||
|
@ -78,7 +78,7 @@ clr_gd:
|
||||
strlo r0, [r1] /* clear 32-bit GD word */
|
||||
addlo r1, r1, #4 /* move to next */
|
||||
blo clr_gd
|
||||
#if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD)
|
||||
#if defined(CONFIG_SYS_MALLOC_F_LEN)
|
||||
sub sp, sp, #CONFIG_SYS_MALLOC_F_LEN
|
||||
str sp, [r9, #GD_MALLOC_BASE]
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
SNAPPER9260 BOARD
|
||||
M: Ryan Mallon <ryan@bluewatersys.com>
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
F: board/bluewater/snapper9260/
|
||||
F: include/configs/snapper9260.h
|
||||
|
@ -9,12 +9,15 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/arch/at91sam9260_matrix.h>
|
||||
#include <asm/arch/at91sam9_smc.h>
|
||||
#include <asm/arch/at91_common.h>
|
||||
#include <asm/arch/at91_pmc.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/atmel_serial.h>
|
||||
#include <net.h>
|
||||
#include <netdev.h>
|
||||
#include <i2c.h>
|
||||
@ -95,10 +98,12 @@ static void nand_hw_init(void)
|
||||
&smc->cs[3].mode);
|
||||
|
||||
/* Configure RDY/BSY */
|
||||
at91_set_gpio_input(CONFIG_SYS_NAND_READY_PIN, 1);
|
||||
gpio_request(CONFIG_SYS_NAND_READY_PIN, "nand_rdy");
|
||||
gpio_direction_input(CONFIG_SYS_NAND_READY_PIN);
|
||||
|
||||
/* Enable NandFlash */
|
||||
at91_set_gpio_output(CONFIG_SYS_NAND_ENABLE_PIN, 1);
|
||||
gpio_request(CONFIG_SYS_NAND_ENABLE_PIN, "nand_ce");
|
||||
gpio_direction_output(CONFIG_SYS_NAND_ENABLE_PIN, 1);
|
||||
}
|
||||
|
||||
int board_init(void)
|
||||
@ -140,3 +145,12 @@ int dram_init(void)
|
||||
void reset_phy(void)
|
||||
{
|
||||
}
|
||||
|
||||
static struct atmel_serial_platdata at91sam9260_serial_plat = {
|
||||
.base_addr = ATMEL_BASE_DBGU,
|
||||
};
|
||||
|
||||
U_BOOT_DEVICE(at91sam9260_serial) = {
|
||||
.name = "serial_atmel",
|
||||
.platdata = &at91sam9260_serial_plat,
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <ns16550.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/io.h>
|
||||
@ -43,6 +44,13 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
/* TODO(sjg@chromium.org): Remove once SPL supports device tree */
|
||||
U_BOOT_DEVICE(tegra_gpios) = {
|
||||
"gpio_tegra"
|
||||
};
|
||||
#endif
|
||||
|
||||
const struct tegra_sysinfo sysinfo = {
|
||||
CONFIG_TEGRA_BOARD_STRING
|
||||
};
|
||||
|
@ -252,6 +252,9 @@ obj-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o
|
||||
obj-y += console.o
|
||||
obj-$(CONFIG_CROS_EC) += cros_ec.o
|
||||
obj-y += dlmalloc.o
|
||||
ifdef CONFIG_SYS_MALLOC_F_LEN
|
||||
obj-y += malloc_simple.o
|
||||
endif
|
||||
obj-y += image.o
|
||||
obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
|
||||
obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
|
||||
|
@ -99,7 +99,8 @@ static int initr_trace(void)
|
||||
|
||||
static int initr_reloc(void)
|
||||
{
|
||||
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
|
||||
/* tell others: relocation done */
|
||||
gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;
|
||||
bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");
|
||||
|
||||
return 0;
|
||||
|
@ -198,6 +198,19 @@ static uint get_alen(char *arg)
|
||||
return alen;
|
||||
}
|
||||
|
||||
enum i2c_err_op {
|
||||
I2C_ERR_READ,
|
||||
I2C_ERR_WRITE,
|
||||
};
|
||||
|
||||
static int i2c_report_err(int ret, enum i2c_err_op op)
|
||||
{
|
||||
printf("Error %s the chip: %d\n",
|
||||
op == I2C_ERR_READ ? "reading" : "writing", ret);
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_i2c_read() - Handle the "i2c read" command-line command
|
||||
* @cmdtp: Command data struct pointer
|
||||
@ -245,7 +258,7 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
|
||||
memaddr = (u_char *)simple_strtoul(argv[4], NULL, 16);
|
||||
|
||||
if (i2c_read(chip, devaddr, alen, memaddr, length) != 0) {
|
||||
puts ("Error reading the chip.\n");
|
||||
i2c_report_err(-1, I2C_ERR_READ);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -286,8 +299,7 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
|
||||
|
||||
while (length-- > 0) {
|
||||
if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) {
|
||||
puts("Error writing to the chip.\n");
|
||||
return 1;
|
||||
return i2c_report_err(-1, I2C_ERR_WRITE);
|
||||
}
|
||||
/*
|
||||
* No write delay with FRAM devices.
|
||||
@ -370,7 +382,7 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
|
||||
linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
|
||||
|
||||
if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0)
|
||||
puts ("Error reading the chip.\n");
|
||||
i2c_report_err(-1, I2C_ERR_READ);
|
||||
else {
|
||||
printf("%04x:", addr);
|
||||
cp = linebuf;
|
||||
@ -452,7 +464,7 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
|
||||
|
||||
while (count-- > 0) {
|
||||
if (i2c_write(chip, addr++, alen, &byte, 1) != 0)
|
||||
puts ("Error writing the chip.\n");
|
||||
i2c_report_err(-1, I2C_ERR_WRITE);
|
||||
/*
|
||||
* Wait for the write to complete. The write can take
|
||||
* up to 10mSec (we allow a little more time).
|
||||
@ -528,7 +540,7 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
|
||||
addr++;
|
||||
}
|
||||
if (err > 0)
|
||||
puts ("Error reading the chip,\n");
|
||||
i2c_report_err(-1, I2C_ERR_READ);
|
||||
else
|
||||
printf ("%08lx\n", crc);
|
||||
|
||||
@ -601,7 +613,7 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
|
||||
do {
|
||||
printf("%08lx:", addr);
|
||||
if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0)
|
||||
puts ("\nError reading the chip,\n");
|
||||
i2c_report_err(-1, I2C_ERR_READ);
|
||||
else {
|
||||
data = cpu_to_be32(data);
|
||||
if (size == 1)
|
||||
@ -644,7 +656,7 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
|
||||
*/
|
||||
bootretry_reset_cmd_timeout();
|
||||
if (i2c_write(chip, addr, alen, (uchar *)&data, size) != 0)
|
||||
puts ("Error writing the chip.\n");
|
||||
i2c_report_err(-1, I2C_ERR_WRITE);
|
||||
#ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
|
||||
udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
|
||||
#endif
|
||||
@ -783,7 +795,7 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
|
||||
*/
|
||||
while (1) {
|
||||
if (i2c_read(chip, addr, alen, bytes, length) != 0)
|
||||
puts ("Error reading the chip.\n");
|
||||
i2c_report_err(-1, I2C_ERR_READ);
|
||||
udelay(delay);
|
||||
}
|
||||
|
||||
@ -1341,7 +1353,7 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
|
||||
chip = simple_strtoul(argv[1], NULL, 16);
|
||||
if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) {
|
||||
puts("Error reading EDID content.\n");
|
||||
i2c_report_err(-1, I2C_ERR_READ);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2184,17 +2184,8 @@ Void_t* mALLOc(bytes) size_t bytes;
|
||||
INTERNAL_SIZE_T nb;
|
||||
|
||||
#ifdef CONFIG_SYS_MALLOC_F_LEN
|
||||
if (gd && !(gd->flags & GD_FLG_RELOC)) {
|
||||
ulong new_ptr;
|
||||
void *ptr;
|
||||
|
||||
new_ptr = gd->malloc_ptr + bytes;
|
||||
if (new_ptr > gd->malloc_limit)
|
||||
panic("Out of pre-reloc memory");
|
||||
ptr = map_sysmem(gd->malloc_base + gd->malloc_ptr, bytes);
|
||||
gd->malloc_ptr = ALIGN(new_ptr, sizeof(new_ptr));
|
||||
return ptr;
|
||||
}
|
||||
if (gd && !(gd->flags & GD_FLG_FULL_MALLOC_INIT))
|
||||
return malloc_simple(bytes);
|
||||
#endif
|
||||
|
||||
/* check if mem_malloc_init() was run */
|
||||
@ -2462,7 +2453,7 @@ void fREe(mem) Void_t* mem;
|
||||
|
||||
#ifdef CONFIG_SYS_MALLOC_F_LEN
|
||||
/* free() is a no-op - all the memory will be freed on relocation */
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
|
||||
return;
|
||||
#endif
|
||||
|
||||
@ -2618,7 +2609,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
|
||||
if (oldmem == NULL) return mALLOc(bytes);
|
||||
|
||||
#ifdef CONFIG_SYS_MALLOC_F_LEN
|
||||
if (!(gd->flags & GD_FLG_RELOC)) {
|
||||
if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
|
||||
/* This is harder to support and should not be needed */
|
||||
panic("pre-reloc realloc() is not supported");
|
||||
}
|
||||
@ -2970,7 +2961,7 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
|
||||
else
|
||||
{
|
||||
#ifdef CONFIG_SYS_MALLOC_F_LEN
|
||||
if (!(gd->flags & GD_FLG_RELOC)) {
|
||||
if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
|
||||
MALLOC_ZERO(mem, sz);
|
||||
return mem;
|
||||
}
|
||||
|
39
common/malloc_simple.c
Normal file
39
common/malloc_simple.c
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Simple malloc implementation
|
||||
*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void *malloc_simple(size_t bytes)
|
||||
{
|
||||
ulong new_ptr;
|
||||
void *ptr;
|
||||
|
||||
new_ptr = gd->malloc_ptr + bytes;
|
||||
if (new_ptr > gd->malloc_limit)
|
||||
panic("Out of pre-reloc memory");
|
||||
ptr = map_sysmem(gd->malloc_base + gd->malloc_ptr, bytes);
|
||||
gd->malloc_ptr = ALIGN(new_ptr, sizeof(new_ptr));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MALLOC_SIMPLE
|
||||
void *calloc(size_t nmemb, size_t elem_size)
|
||||
{
|
||||
size_t size = nmemb * elem_size;
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
memset(ptr, '\0', size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
@ -7,6 +7,7 @@
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <spl.h>
|
||||
#include <asm/u-boot.h>
|
||||
#include <nand.h>
|
||||
@ -15,6 +16,7 @@
|
||||
#include <i2c.h>
|
||||
#include <image.h>
|
||||
#include <malloc.h>
|
||||
#include <dm/root.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
@ -139,9 +141,16 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||
u32 boot_device;
|
||||
debug(">>spl:board_init_r()\n");
|
||||
|
||||
#ifdef CONFIG_SYS_SPL_MALLOC_START
|
||||
#if defined(CONFIG_SYS_SPL_MALLOC_START)
|
||||
mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
|
||||
CONFIG_SYS_SPL_MALLOC_SIZE);
|
||||
gd->flags |= GD_FLG_FULL_MALLOC_INIT;
|
||||
#elif defined(CONFIG_SYS_MALLOC_F_LEN)
|
||||
gd->malloc_limit = gd->malloc_base + CONFIG_SYS_MALLOC_F_LEN;
|
||||
gd->malloc_ptr = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_SPL_DM
|
||||
dm_init_and_scan(true);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_PPC
|
||||
@ -240,6 +249,11 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||
default:
|
||||
debug("Unsupported OS image.. Jumping nevertheless..\n");
|
||||
}
|
||||
#if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SYS_SPL_MALLOC_SIZE)
|
||||
debug("SPL malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
|
||||
gd->malloc_ptr / 1024);
|
||||
#endif
|
||||
|
||||
jump_to_image_no_args(&spl_image);
|
||||
}
|
||||
|
||||
|
@ -750,20 +750,44 @@ device pointers, but this is not currently implemented (the root device
|
||||
pointer is saved but not made available through the driver model API).
|
||||
|
||||
|
||||
SPL Support
|
||||
-----------
|
||||
|
||||
Driver model can operate in SPL. Its efficient implementation and small code
|
||||
size provide for a small overhead which is acceptable for all but the most
|
||||
constrained systems.
|
||||
|
||||
To enable driver model in SPL, define CONFIG_SPL_DM. You might want to
|
||||
consider the following option also. See the main README for more details.
|
||||
|
||||
- CONFIG_SYS_MALLOC_SIMPLE
|
||||
- CONFIG_DM_WARN
|
||||
- CONFIG_DM_DEVICE_REMOVE
|
||||
- CONFIG_DM_STDIO
|
||||
|
||||
|
||||
Enabling Driver Model
|
||||
---------------------
|
||||
|
||||
Driver model is being brought into U-Boot gradually. As each subsystems gets
|
||||
support, a uclass is created and a CONFIG to enable use of driver model for
|
||||
that subsystem.
|
||||
|
||||
For example CONFIG_DM_SERIAL enables driver model for serial. With that
|
||||
defined, the old serial support is not enabled, and your serial driver must
|
||||
conform to driver model. With that undefined, the old serial support is
|
||||
enabled and driver model is not available for serial. This means that when
|
||||
you convert a driver, you must either convert all its boards, or provide for
|
||||
the driver to be compiled both with and without driver model (generally this
|
||||
is not very hard).
|
||||
|
||||
See the main README for full details of the available driver model CONFIG
|
||||
options.
|
||||
|
||||
|
||||
Things to punt for later
|
||||
------------------------
|
||||
|
||||
- SPL support - this will have to be present before many drivers can be
|
||||
converted, but it seems like we can add it once we are happy with the
|
||||
core implementation.
|
||||
|
||||
That is not to say that no thinking has gone into this - in fact there
|
||||
is quite a lot there. However, getting these right is non-trivial and
|
||||
there is a high cost associated with going down the wrong path.
|
||||
|
||||
For SPL, it may be possible to fit in a simplified driver model with only
|
||||
bind and probe methods, to reduce size.
|
||||
|
||||
Uclasses are statically numbered at compile time. It would be possible to
|
||||
change this to dynamic numbering, but then we would require some sort of
|
||||
lookup service, perhaps searching by name. This is slightly less efficient
|
||||
|
@ -4,5 +4,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y := device.o lists.o root.o uclass.o util.o
|
||||
obj-$(CONFIG_DM) += device.o lists.o root.o uclass.o util.o
|
||||
obj-$(CONFIG_OF_CONTROL) += simple-bus.o
|
||||
obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o
|
||||
|
187
drivers/core/device-remove.c
Normal file
187
drivers/core/device-remove.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Device manager
|
||||
*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
*
|
||||
* (C) Copyright 2012
|
||||
* Pavel Herrmann <morpheus.ibis@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
#include <dm/util.h>
|
||||
|
||||
/**
|
||||
* device_chld_unbind() - Unbind all device's children from the device
|
||||
*
|
||||
* On error, the function continues to unbind all children, and reports the
|
||||
* first error.
|
||||
*
|
||||
* @dev: The device that is to be stripped of its children
|
||||
* @return 0 on success, -ve on error
|
||||
*/
|
||||
static int device_chld_unbind(struct udevice *dev)
|
||||
{
|
||||
struct udevice *pos, *n;
|
||||
int ret, saved_ret = 0;
|
||||
|
||||
assert(dev);
|
||||
|
||||
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
|
||||
ret = device_unbind(pos);
|
||||
if (ret && !saved_ret)
|
||||
saved_ret = ret;
|
||||
}
|
||||
|
||||
return saved_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_chld_remove() - Stop all device's children
|
||||
* @dev: The device whose children are to be removed
|
||||
* @return 0 on success, -ve on error
|
||||
*/
|
||||
static int device_chld_remove(struct udevice *dev)
|
||||
{
|
||||
struct udevice *pos, *n;
|
||||
int ret;
|
||||
|
||||
assert(dev);
|
||||
|
||||
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
|
||||
ret = device_remove(pos);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int device_unbind(struct udevice *dev)
|
||||
{
|
||||
struct driver *drv;
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->flags & DM_FLAG_ACTIVATED)
|
||||
return -EINVAL;
|
||||
|
||||
drv = dev->driver;
|
||||
assert(drv);
|
||||
|
||||
if (drv->unbind) {
|
||||
ret = drv->unbind(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_chld_unbind(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = uclass_unbind_device(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dev->parent)
|
||||
list_del(&dev->sibling_node);
|
||||
free(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_free() - Free memory buffers allocated by a device
|
||||
* @dev: Device that is to be started
|
||||
*/
|
||||
void device_free(struct udevice *dev)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (dev->driver->priv_auto_alloc_size) {
|
||||
free(dev->priv);
|
||||
dev->priv = NULL;
|
||||
}
|
||||
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
|
||||
free(dev->platdata);
|
||||
dev->platdata = NULL;
|
||||
}
|
||||
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
|
||||
if (size) {
|
||||
free(dev->uclass_priv);
|
||||
dev->uclass_priv = NULL;
|
||||
}
|
||||
if (dev->parent) {
|
||||
size = dev->parent->driver->per_child_auto_alloc_size;
|
||||
if (size) {
|
||||
free(dev->parent_priv);
|
||||
dev->parent_priv = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int device_remove(struct udevice *dev)
|
||||
{
|
||||
struct driver *drv;
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(dev->flags & DM_FLAG_ACTIVATED))
|
||||
return 0;
|
||||
|
||||
drv = dev->driver;
|
||||
assert(drv);
|
||||
|
||||
ret = uclass_pre_remove_device(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_chld_remove(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (drv->remove) {
|
||||
ret = drv->remove(dev);
|
||||
if (ret)
|
||||
goto err_remove;
|
||||
}
|
||||
|
||||
if (dev->parent && dev->parent->driver->child_post_remove) {
|
||||
ret = dev->parent->driver->child_post_remove(dev);
|
||||
if (ret) {
|
||||
dm_warn("%s: Device '%s' failed child_post_remove()",
|
||||
__func__, dev->name);
|
||||
}
|
||||
}
|
||||
|
||||
device_free(dev);
|
||||
|
||||
dev->seq = -1;
|
||||
dev->flags &= ~DM_FLAG_ACTIVATED;
|
||||
|
||||
return ret;
|
||||
|
||||
err_remove:
|
||||
/* We can't put the children back */
|
||||
dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
|
||||
__func__, dev->name);
|
||||
err:
|
||||
ret = uclass_post_probe_device(dev);
|
||||
if (ret) {
|
||||
dm_warn("%s: Device '%s' failed to post_probe on error path\n",
|
||||
__func__, dev->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -24,52 +24,6 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/**
|
||||
* device_chld_unbind() - Unbind all device's children from the device
|
||||
*
|
||||
* On error, the function continues to unbind all children, and reports the
|
||||
* first error.
|
||||
*
|
||||
* @dev: The device that is to be stripped of its children
|
||||
* @return 0 on success, -ve on error
|
||||
*/
|
||||
static int device_chld_unbind(struct udevice *dev)
|
||||
{
|
||||
struct udevice *pos, *n;
|
||||
int ret, saved_ret = 0;
|
||||
|
||||
assert(dev);
|
||||
|
||||
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
|
||||
ret = device_unbind(pos);
|
||||
if (ret && !saved_ret)
|
||||
saved_ret = ret;
|
||||
}
|
||||
|
||||
return saved_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_chld_remove() - Stop all device's children
|
||||
* @dev: The device whose children are to be removed
|
||||
* @return 0 on success, -ve on error
|
||||
*/
|
||||
static int device_chld_remove(struct udevice *dev)
|
||||
{
|
||||
struct udevice *pos, *n;
|
||||
int ret;
|
||||
|
||||
assert(dev);
|
||||
|
||||
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
|
||||
ret = device_remove(pos);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int device_bind(struct udevice *parent, struct driver *drv, const char *name,
|
||||
void *platdata, int of_offset, struct udevice **devp)
|
||||
{
|
||||
@ -167,71 +121,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
||||
-1, devp);
|
||||
}
|
||||
|
||||
int device_unbind(struct udevice *dev)
|
||||
{
|
||||
struct driver *drv;
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->flags & DM_FLAG_ACTIVATED)
|
||||
return -EINVAL;
|
||||
|
||||
drv = dev->driver;
|
||||
assert(drv);
|
||||
|
||||
if (drv->unbind) {
|
||||
ret = drv->unbind(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_chld_unbind(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = uclass_unbind_device(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dev->parent)
|
||||
list_del(&dev->sibling_node);
|
||||
free(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_free() - Free memory buffers allocated by a device
|
||||
* @dev: Device that is to be started
|
||||
*/
|
||||
static void device_free(struct udevice *dev)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (dev->driver->priv_auto_alloc_size) {
|
||||
free(dev->priv);
|
||||
dev->priv = NULL;
|
||||
}
|
||||
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
|
||||
free(dev->platdata);
|
||||
dev->platdata = NULL;
|
||||
}
|
||||
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
|
||||
if (size) {
|
||||
free(dev->uclass_priv);
|
||||
dev->uclass_priv = NULL;
|
||||
}
|
||||
if (dev->parent) {
|
||||
size = dev->parent->driver->per_child_auto_alloc_size;
|
||||
if (size) {
|
||||
free(dev->parent_priv);
|
||||
dev->parent_priv = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int device_probe_child(struct udevice *dev, void *parent_priv)
|
||||
{
|
||||
struct driver *drv;
|
||||
@ -342,63 +231,6 @@ int device_probe(struct udevice *dev)
|
||||
return device_probe_child(dev, NULL);
|
||||
}
|
||||
|
||||
int device_remove(struct udevice *dev)
|
||||
{
|
||||
struct driver *drv;
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(dev->flags & DM_FLAG_ACTIVATED))
|
||||
return 0;
|
||||
|
||||
drv = dev->driver;
|
||||
assert(drv);
|
||||
|
||||
ret = uclass_pre_remove_device(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_chld_remove(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (drv->remove) {
|
||||
ret = drv->remove(dev);
|
||||
if (ret)
|
||||
goto err_remove;
|
||||
}
|
||||
|
||||
if (dev->parent && dev->parent->driver->child_post_remove) {
|
||||
ret = dev->parent->driver->child_post_remove(dev);
|
||||
if (ret) {
|
||||
dm_warn("%s: Device '%s' failed child_post_remove()",
|
||||
__func__, dev->name);
|
||||
}
|
||||
}
|
||||
|
||||
device_free(dev);
|
||||
|
||||
dev->seq = -1;
|
||||
dev->flags &= ~DM_FLAG_ACTIVATED;
|
||||
|
||||
return ret;
|
||||
|
||||
err_remove:
|
||||
/* We can't put the children back */
|
||||
dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
|
||||
__func__, dev->name);
|
||||
err:
|
||||
ret = uclass_post_probe_device(dev);
|
||||
if (ret) {
|
||||
dm_warn("%s: Device '%s' failed to post_probe on error path\n",
|
||||
__func__, dev->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *dev_get_platdata(struct udevice *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
@ -548,3 +380,13 @@ int device_find_next_child(struct udevice **devp)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct udevice *dev_get_parent(struct udevice *child)
|
||||
{
|
||||
return child->parent;
|
||||
}
|
||||
|
||||
ulong dev_get_of_data(struct udevice *dev)
|
||||
{
|
||||
return dev->of_id->data;
|
||||
}
|
||||
|
@ -25,9 +25,6 @@ struct driver *lists_driver_lookup_name(const char *name)
|
||||
const int n_ents = ll_entry_count(struct driver, driver);
|
||||
struct driver *entry;
|
||||
|
||||
if (!drv || !n_ents)
|
||||
return NULL;
|
||||
|
||||
for (entry = drv; entry != drv + n_ents; entry++) {
|
||||
if (!strcmp(name, entry->name))
|
||||
return entry;
|
||||
@ -44,9 +41,6 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
|
||||
const int n_ents = ll_entry_count(struct uclass_driver, uclass);
|
||||
struct uclass_driver *entry;
|
||||
|
||||
if ((id == UCLASS_INVALID) || !uclass)
|
||||
return NULL;
|
||||
|
||||
for (entry = uclass; entry != uclass + n_ents; entry++) {
|
||||
if (entry->id == id)
|
||||
return entry;
|
||||
@ -77,34 +71,60 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
|
||||
return result;
|
||||
}
|
||||
|
||||
int device_bind_driver(struct udevice *parent, const char *drv_name,
|
||||
const char *dev_name, struct udevice **devp)
|
||||
{
|
||||
struct driver *drv;
|
||||
int ret;
|
||||
|
||||
drv = lists_driver_lookup_name(drv_name);
|
||||
if (!drv) {
|
||||
printf("Cannot find driver '%s'\n", drv_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
ret = device_bind(parent, drv, dev_name, NULL, -1, devp);
|
||||
if (ret) {
|
||||
printf("Cannot create device named '%s' (err=%d)\n",
|
||||
dev_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
/**
|
||||
* driver_check_compatible() - Check if a driver is compatible with this node
|
||||
*
|
||||
* @param blob: Device tree pointer
|
||||
* @param offset: Offset of node in device tree
|
||||
* @param of_matchL List of compatible strings to match
|
||||
* @param of_match: List of compatible strings to match
|
||||
* @param of_idp: Returns the match that was found
|
||||
* @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node
|
||||
* does not have a compatible string, other error <0 if there is a device
|
||||
* tree error
|
||||
*/
|
||||
static int driver_check_compatible(const void *blob, int offset,
|
||||
const struct udevice_id *of_match)
|
||||
const struct udevice_id *of_match,
|
||||
const struct udevice_id **of_idp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*of_idp = NULL;
|
||||
if (!of_match)
|
||||
return -ENOENT;
|
||||
|
||||
while (of_match->compatible) {
|
||||
ret = fdt_node_check_compatible(blob, offset,
|
||||
of_match->compatible);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
*of_idp = of_match;
|
||||
return 0;
|
||||
else if (ret == -FDT_ERR_NOTFOUND)
|
||||
} else if (ret == -FDT_ERR_NOTFOUND) {
|
||||
return -ENODEV;
|
||||
else if (ret < 0)
|
||||
} else if (ret < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
of_match++;
|
||||
}
|
||||
|
||||
@ -116,6 +136,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
|
||||
{
|
||||
struct driver *driver = ll_entry_start(struct driver, driver);
|
||||
const int n_ents = ll_entry_count(struct driver, driver);
|
||||
const struct udevice_id *id;
|
||||
struct driver *entry;
|
||||
struct udevice *dev;
|
||||
bool found = false;
|
||||
@ -127,7 +148,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
|
||||
if (devp)
|
||||
*devp = NULL;
|
||||
for (entry = driver; entry != driver + n_ents; entry++) {
|
||||
ret = driver_check_compatible(blob, offset, entry->of_match);
|
||||
ret = driver_check_compatible(blob, offset, entry->of_match,
|
||||
&id);
|
||||
name = fdt_get_name(blob, offset, NULL);
|
||||
if (ret == -ENOENT) {
|
||||
continue;
|
||||
@ -136,8 +158,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
|
||||
break;
|
||||
} else if (ret) {
|
||||
dm_warn("Device tree error at offset %d\n", offset);
|
||||
if (!result || ret != -ENOENT)
|
||||
result = ret;
|
||||
result = ret;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -147,6 +168,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
|
||||
dm_warn("Error binding driver '%s'\n", entry->name);
|
||||
return ret;
|
||||
} else {
|
||||
dev->of_id = id;
|
||||
found = true;
|
||||
if (devp)
|
||||
*devp = dev;
|
||||
|
@ -73,10 +73,8 @@ int dm_scan_platdata(bool pre_reloc_only)
|
||||
dm_warn("Some drivers were not found\n");
|
||||
ret = 0;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
|
@ -10,11 +10,14 @@
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/at91_pio.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
|
||||
#define GPIO_PER_BANK 32
|
||||
|
||||
static struct at91_port *at91_pio_get_port(unsigned port)
|
||||
{
|
||||
@ -39,19 +42,25 @@ static struct at91_port *at91_pio_get_port(unsigned port)
|
||||
}
|
||||
}
|
||||
|
||||
static void at91_set_port_pullup(struct at91_port *at91_port, unsigned offset,
|
||||
int use_pullup)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
mask = 1 << offset;
|
||||
if (use_pullup)
|
||||
writel(mask, &at91_port->puer);
|
||||
else
|
||||
writel(mask, &at91_port->pudr);
|
||||
writel(mask, &at91_port->per);
|
||||
}
|
||||
|
||||
int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup)
|
||||
{
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
mask = 1 << pin;
|
||||
if (use_pullup)
|
||||
writel(1 << pin, &at91_port->puer);
|
||||
else
|
||||
writel(1 << pin, &at91_port->pudr);
|
||||
writel(mask, &at91_port->per);
|
||||
}
|
||||
if (at91_port && (pin < GPIO_PER_BANK))
|
||||
at91_set_port_pullup(at91_port, pin, use_pullup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -64,7 +73,7 @@ int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->idr);
|
||||
at91_set_pio_pullup(port, pin, use_pullup);
|
||||
@ -82,7 +91,7 @@ int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->idr);
|
||||
at91_set_pio_pullup(port, pin, use_pullup);
|
||||
@ -108,7 +117,7 @@ int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->idr);
|
||||
at91_set_pio_pullup(port, pin, use_pullup);
|
||||
@ -135,7 +144,7 @@ int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->idr);
|
||||
at91_set_pio_pullup(port, pin, use_pullup);
|
||||
@ -157,7 +166,7 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->idr);
|
||||
at91_set_pio_pullup(port, pin, use_pullup);
|
||||
@ -172,6 +181,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_GPIO
|
||||
static bool at91_get_port_output(struct at91_port *at91_port, int offset)
|
||||
{
|
||||
u32 mask, val;
|
||||
|
||||
mask = 1 << offset;
|
||||
val = readl(&at91_port->osr);
|
||||
return val & mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void at91_set_port_input(struct at91_port *at91_port, int offset,
|
||||
int use_pullup)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
mask = 1 << offset;
|
||||
writel(mask, &at91_port->idr);
|
||||
at91_set_port_pullup(at91_port, offset, use_pullup);
|
||||
writel(mask, &at91_port->odr);
|
||||
writel(mask, &at91_port->per);
|
||||
}
|
||||
|
||||
/*
|
||||
* mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
|
||||
* configure it for an input.
|
||||
@ -179,19 +211,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup)
|
||||
int at91_set_pio_input(unsigned port, u32 pin, int use_pullup)
|
||||
{
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->idr);
|
||||
at91_set_pio_pullup(port, pin, use_pullup);
|
||||
writel(mask, &at91_port->odr);
|
||||
writel(mask, &at91_port->per);
|
||||
}
|
||||
if (at91_port && (pin < GPIO_PER_BANK))
|
||||
at91_set_port_input(at91_port, pin, use_pullup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at91_set_port_output(struct at91_port *at91_port, int offset,
|
||||
int value)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
mask = 1 << offset;
|
||||
writel(mask, &at91_port->idr);
|
||||
writel(mask, &at91_port->pudr);
|
||||
if (value)
|
||||
writel(mask, &at91_port->sodr);
|
||||
else
|
||||
writel(mask, &at91_port->codr);
|
||||
writel(mask, &at91_port->oer);
|
||||
writel(mask, &at91_port->per);
|
||||
}
|
||||
|
||||
/*
|
||||
* mux the pin to the gpio controller (instead of "A" or "B" peripheral),
|
||||
* and configure it for an output.
|
||||
@ -199,19 +241,9 @@ int at91_set_pio_input(unsigned port, u32 pin, int use_pullup)
|
||||
int at91_set_pio_output(unsigned port, u32 pin, int value)
|
||||
{
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (port < ATMEL_PIO_PORTS) && (pin < 32)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->idr);
|
||||
writel(mask, &at91_port->pudr);
|
||||
if (value)
|
||||
writel(mask, &at91_port->sodr);
|
||||
else
|
||||
writel(mask, &at91_port->codr);
|
||||
writel(mask, &at91_port->oer);
|
||||
writel(mask, &at91_port->per);
|
||||
}
|
||||
if (at91_port && (pin < GPIO_PER_BANK))
|
||||
at91_set_port_output(at91_port, pin, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -224,7 +256,7 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
if (is_on) {
|
||||
#if defined(CPU_HAS_PIO3)
|
||||
@ -248,7 +280,7 @@ int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
if (is_on) {
|
||||
writel(mask, &at91_port->ifscer);
|
||||
@ -271,7 +303,7 @@ int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
writel(mask, &at91_port->pudr);
|
||||
if (is_on)
|
||||
@ -291,7 +323,7 @@ int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
writel(readl(&at91_port->schmitt) | mask,
|
||||
&at91_port->schmitt);
|
||||
@ -310,7 +342,7 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on)
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
if (at91_port && (pin < GPIO_PER_BANK)) {
|
||||
mask = 1 << pin;
|
||||
if (is_on)
|
||||
writel(mask, &at91_port->mder);
|
||||
@ -321,41 +353,54 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at91_set_port_value(struct at91_port *at91_port, int offset,
|
||||
int value)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
mask = 1 << offset;
|
||||
if (value)
|
||||
writel(mask, &at91_port->sodr);
|
||||
else
|
||||
writel(mask, &at91_port->codr);
|
||||
}
|
||||
|
||||
/*
|
||||
* assuming the pin is muxed as a gpio output, set its value.
|
||||
*/
|
||||
int at91_set_pio_value(unsigned port, unsigned pin, int value)
|
||||
{
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
mask = 1 << pin;
|
||||
if (value)
|
||||
writel(mask, &at91_port->sodr);
|
||||
else
|
||||
writel(mask, &at91_port->codr);
|
||||
}
|
||||
if (at91_port && (pin < GPIO_PER_BANK))
|
||||
at91_set_port_value(at91_port, pin, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_get_port_value(struct at91_port *at91_port, int offset)
|
||||
{
|
||||
u32 pdsr = 0, mask;
|
||||
|
||||
mask = 1 << offset;
|
||||
pdsr = readl(&at91_port->pdsr) & mask;
|
||||
|
||||
return pdsr != 0;
|
||||
}
|
||||
/*
|
||||
* read the pin's value (works even if it's not muxed as a gpio).
|
||||
*/
|
||||
int at91_get_pio_value(unsigned port, unsigned pin)
|
||||
{
|
||||
struct at91_port *at91_port = at91_pio_get_port(port);
|
||||
u32 pdsr = 0, mask;
|
||||
|
||||
if (at91_port && (pin < 32)) {
|
||||
mask = 1 << pin;
|
||||
pdsr = readl(&at91_port->pdsr) & mask;
|
||||
}
|
||||
if (at91_port && (pin < GPIO_PER_BANK))
|
||||
return at91_get_port_value(at91_port, pin);
|
||||
|
||||
return pdsr != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_GPIO
|
||||
/* Common GPIO API */
|
||||
|
||||
int gpio_request(unsigned gpio, const char *label)
|
||||
@ -395,3 +440,91 @@ int gpio_set_value(unsigned gpio, int value)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_GPIO
|
||||
|
||||
struct at91_port_priv {
|
||||
struct at91_port *regs;
|
||||
};
|
||||
|
||||
/* set GPIO pin 'gpio' as an input */
|
||||
static int at91_gpio_direction_input(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct at91_port_priv *port = dev_get_platdata(dev);
|
||||
|
||||
at91_set_port_input(port->regs, offset, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set GPIO pin 'gpio' as an output, with polarity 'value' */
|
||||
static int at91_gpio_direction_output(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct at91_port_priv *port = dev_get_platdata(dev);
|
||||
|
||||
at91_set_port_output(port->regs, offset, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read GPIO IN value of pin 'gpio' */
|
||||
static int at91_gpio_get_value(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct at91_port_priv *port = dev_get_platdata(dev);
|
||||
|
||||
return at91_get_port_value(port->regs, offset);
|
||||
}
|
||||
|
||||
/* write GPIO OUT value to pin 'gpio' */
|
||||
static int at91_gpio_set_value(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct at91_port_priv *port = dev_get_platdata(dev);
|
||||
|
||||
at91_set_port_value(port->regs, offset, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct at91_port_priv *port = dev_get_platdata(dev);
|
||||
|
||||
/* GPIOF_FUNC is not implemented yet */
|
||||
if (at91_get_port_output(port->regs, offset))
|
||||
return GPIOF_OUTPUT;
|
||||
else
|
||||
return GPIOF_INPUT;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gpio_at91_ops = {
|
||||
.direction_input = at91_gpio_direction_input,
|
||||
.direction_output = at91_gpio_direction_output,
|
||||
.get_value = at91_gpio_get_value,
|
||||
.set_value = at91_gpio_set_value,
|
||||
.get_function = at91_gpio_get_function,
|
||||
};
|
||||
|
||||
static int at91_gpio_probe(struct udevice *dev)
|
||||
{
|
||||
struct at91_port_priv *port = dev_get_priv(dev);
|
||||
struct at91_port_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
|
||||
|
||||
uc_priv->bank_name = plat->bank_name;
|
||||
uc_priv->gpio_count = GPIO_PER_BANK;
|
||||
port->regs = (struct at91_port *)plat->base_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(gpio_at91) = {
|
||||
.name = "gpio_at91",
|
||||
.id = UCLASS_GPIO,
|
||||
.ops = &gpio_at91_ops,
|
||||
.probe = at91_gpio_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct at91_port_priv),
|
||||
};
|
||||
#endif
|
||||
|
@ -701,6 +701,7 @@ static int cros_ec_check_version(struct cros_ec_dev *dev)
|
||||
|
||||
/* Try sending a version 3 packet */
|
||||
dev->protocol_version = 3;
|
||||
req.in_data = 0;
|
||||
if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
|
||||
(uint8_t **)&resp, sizeof(*resp)) > 0) {
|
||||
return 0;
|
||||
|
@ -602,14 +602,14 @@ static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum,
|
||||
spec, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = device_find_child_by_seq(bus, cs, true, &slave);
|
||||
ret = spi_find_chip_select(bus, cs, &slave);
|
||||
if (!ret) {
|
||||
printf("Chip select %d already exists for spec '%s'\n", cs,
|
||||
spec);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave);
|
||||
ret = device_bind_driver(bus, "spi_flash_std", spec, &slave);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -7,11 +7,16 @@
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <watchdog.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
#include <asm/arch/atmel_serial.h>
|
||||
#endif
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
|
||||
@ -19,9 +24,9 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static void atmel_serial_setbrg(void)
|
||||
static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id,
|
||||
int baudrate)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
|
||||
unsigned long divisor;
|
||||
unsigned long usart_hz;
|
||||
|
||||
@ -30,15 +35,13 @@ static void atmel_serial_setbrg(void)
|
||||
* Baud Rate = --------------
|
||||
* 16 * CD
|
||||
*/
|
||||
usart_hz = get_usart_clk_rate(CONFIG_USART_ID);
|
||||
divisor = (usart_hz / 16 + gd->baudrate / 2) / gd->baudrate;
|
||||
usart_hz = get_usart_clk_rate(id);
|
||||
divisor = (usart_hz / 16 + baudrate / 2) / baudrate;
|
||||
writel(USART3_BF(CD, divisor), &usart->brgr);
|
||||
}
|
||||
|
||||
static int atmel_serial_init(void)
|
||||
static void atmel_serial_init_internal(atmel_usart3_t *usart)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
|
||||
|
||||
/*
|
||||
* Just in case: drain transmitter register
|
||||
* 1000us is enough for baudrate >= 9600
|
||||
@ -47,9 +50,10 @@ static int atmel_serial_init(void)
|
||||
__udelay(1000);
|
||||
|
||||
writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
|
||||
}
|
||||
|
||||
serial_setbrg();
|
||||
|
||||
static void atmel_serial_activate(atmel_usart3_t *usart)
|
||||
{
|
||||
writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL)
|
||||
| USART3_BF(USCLKS, USART3_USCLKS_MCK)
|
||||
| USART3_BF(CHRL, USART3_CHRL_8)
|
||||
@ -59,6 +63,22 @@ static int atmel_serial_init(void)
|
||||
writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
|
||||
/* 100us is enough for the new settings to be settled */
|
||||
__udelay(100);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_SERIAL
|
||||
static void atmel_serial_setbrg(void)
|
||||
{
|
||||
atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE,
|
||||
CONFIG_USART_ID, gd->baudrate);
|
||||
}
|
||||
|
||||
static int atmel_serial_init(void)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
|
||||
|
||||
atmel_serial_init_internal(usart);
|
||||
serial_setbrg();
|
||||
atmel_serial_activate(usart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -109,3 +129,81 @@ __weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
return &atmel_serial_drv;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
|
||||
struct atmel_serial_priv {
|
||||
atmel_usart3_t *usart;
|
||||
};
|
||||
|
||||
int atmel_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
atmel_serial_setbrg_internal(priv->usart, 0 /* ignored */, baudrate);
|
||||
atmel_serial_activate(priv->usart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!(readl(&priv->usart->csr) & USART3_BIT(RXRDY)))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&priv->usart->rhr);
|
||||
}
|
||||
|
||||
static int atmel_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!(readl(&priv->usart->csr) & USART3_BIT(TXRDY)))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, &priv->usart->thr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
uint32_t csr = readl(&priv->usart->csr);
|
||||
|
||||
if (input)
|
||||
return csr & USART3_BIT(RXRDY) ? 1 : 0;
|
||||
else
|
||||
return csr & USART3_BIT(TXEMPTY) ? 0 : 1;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops atmel_serial_ops = {
|
||||
.putc = atmel_serial_putc,
|
||||
.pending = atmel_serial_pending,
|
||||
.getc = atmel_serial_getc,
|
||||
.setbrg = atmel_serial_setbrg,
|
||||
};
|
||||
|
||||
static int atmel_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct atmel_serial_platdata *plat = dev->platdata;
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->usart = (atmel_usart3_t *)plat->base_addr;
|
||||
atmel_serial_init_internal(priv->usart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(serial_atmel) = {
|
||||
.name = "serial_atmel",
|
||||
.id = UCLASS_SERIAL,
|
||||
.probe = atmel_serial_probe,
|
||||
.ops = &atmel_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
.priv_auto_alloc_size = sizeof(struct atmel_serial_priv),
|
||||
};
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <environment.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <os.h>
|
||||
@ -19,6 +20,11 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* Table with supported baudrates (defined in config_xyz.h)
|
||||
*/
|
||||
static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
|
||||
|
||||
#ifndef CONFIG_SYS_MALLOC_F_LEN
|
||||
#error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work"
|
||||
#endif
|
||||
@ -160,10 +166,12 @@ void serial_stdio_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_STDIO
|
||||
static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
|
||||
{
|
||||
_serial_putc(sdev->priv, ch);
|
||||
}
|
||||
#endif
|
||||
|
||||
void serial_stub_puts(struct stdio_dev *sdev, const char *str)
|
||||
{
|
||||
@ -180,11 +188,74 @@ int serial_stub_tstc(struct stdio_dev *sdev)
|
||||
return _serial_tstc(sdev->priv);
|
||||
}
|
||||
|
||||
/**
|
||||
* on_baudrate() - Update the actual baudrate when the env var changes
|
||||
*
|
||||
* This will check for a valid baudrate and only apply it if valid.
|
||||
*/
|
||||
static int on_baudrate(const char *name, const char *value, enum env_op op,
|
||||
int flags)
|
||||
{
|
||||
int i;
|
||||
int baudrate;
|
||||
|
||||
switch (op) {
|
||||
case env_op_create:
|
||||
case env_op_overwrite:
|
||||
/*
|
||||
* Switch to new baudrate if new baudrate is supported
|
||||
*/
|
||||
baudrate = simple_strtoul(value, NULL, 10);
|
||||
|
||||
/* Not actually changing */
|
||||
if (gd->baudrate == baudrate)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
|
||||
if (baudrate == baudrate_table[i])
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(baudrate_table)) {
|
||||
if ((flags & H_FORCE) == 0)
|
||||
printf("## Baudrate %d bps not supported\n",
|
||||
baudrate);
|
||||
return 1;
|
||||
}
|
||||
if ((flags & H_INTERACTIVE) != 0) {
|
||||
printf("## Switch baudrate to %d bps and press ENTER ...\n",
|
||||
baudrate);
|
||||
udelay(50000);
|
||||
}
|
||||
|
||||
gd->baudrate = baudrate;
|
||||
|
||||
serial_setbrg();
|
||||
|
||||
udelay(50000);
|
||||
|
||||
if ((flags & H_INTERACTIVE) != 0)
|
||||
while (1) {
|
||||
if (getc() == '\r')
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case env_op_delete:
|
||||
printf("## Baudrate may not be deleted\n");
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
|
||||
|
||||
static int serial_post_probe(struct udevice *dev)
|
||||
{
|
||||
struct stdio_dev sdev;
|
||||
struct dm_serial_ops *ops = serial_get_ops(dev);
|
||||
#ifdef CONFIG_DM_STDIO
|
||||
struct serial_dev_priv *upriv = dev->uclass_priv;
|
||||
struct stdio_dev sdev;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
/* Set the baud rate */
|
||||
@ -194,9 +265,9 @@ static int serial_post_probe(struct udevice *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_STDIO
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return 0;
|
||||
|
||||
memset(&sdev, '\0', sizeof(sdev));
|
||||
|
||||
strncpy(sdev.name, dev->name, sizeof(sdev.name));
|
||||
@ -207,7 +278,7 @@ static int serial_post_probe(struct udevice *dev)
|
||||
sdev.getc = serial_stub_getc;
|
||||
sdev.tstc = serial_stub_tstc;
|
||||
stdio_register_dev(&sdev, &upriv->sdev);
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <ns16550.h>
|
||||
#include <serial.h>
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
static const struct udevice_id tegra_serial_ids[] = {
|
||||
{ .compatible = "nvidia,tegra20-uart" },
|
||||
{ }
|
||||
@ -26,13 +27,28 @@ static int tegra_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
struct ns16550_platdata tegra_serial = {
|
||||
.base = CONFIG_SYS_NS16550_COM1,
|
||||
.reg_shift = 2,
|
||||
.clock = V_NS16550_CLK,
|
||||
};
|
||||
|
||||
U_BOOT_DEVICE(ns16550_serial) = {
|
||||
"serial_tegra20", &tegra_serial
|
||||
};
|
||||
#endif
|
||||
|
||||
U_BOOT_DRIVER(serial_ns16550) = {
|
||||
.name = "serial_tegra20",
|
||||
.id = UCLASS_SERIAL,
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
.of_match = tegra_serial_ids,
|
||||
.ofdata_to_platdata = tegra_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
|
||||
#endif
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.probe = ns16550_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
|
@ -115,16 +115,7 @@ int spi_chip_select(struct udevice *dev)
|
||||
return slave ? slave->cs : -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_find_chip_select() - Find the slave attached to chip select
|
||||
*
|
||||
* @bus: SPI bus to search
|
||||
* @cs: Chip select to look for
|
||||
* @devp: Returns the slave device if found
|
||||
* @return 0 if found, -ENODEV on error
|
||||
*/
|
||||
static int spi_find_chip_select(struct udevice *bus, int cs,
|
||||
struct udevice **devp)
|
||||
int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
@ -197,27 +188,6 @@ int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
|
||||
const char *dev_name, struct udevice **devp)
|
||||
{
|
||||
struct driver *drv;
|
||||
int ret;
|
||||
|
||||
drv = lists_driver_lookup_name(drv_name);
|
||||
if (!drv) {
|
||||
printf("Cannot find driver '%s'\n", drv_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
ret = device_bind(bus, drv, dev_name, NULL, -1, devp);
|
||||
if (ret) {
|
||||
printf("Cannot create device named '%s' (err=%d)\n",
|
||||
dev_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
|
||||
struct udevice **devp)
|
||||
{
|
||||
@ -264,7 +234,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
|
||||
if (ret == -ENODEV && drv_name) {
|
||||
debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
|
||||
__func__, dev_name, busnum, cs, drv_name);
|
||||
ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev);
|
||||
ret = device_bind_driver(bus, drv_name, dev_name, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
created = true;
|
||||
|
@ -108,5 +108,6 @@ typedef struct global_data {
|
||||
#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
|
||||
#define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */
|
||||
#define GD_FLG_SERIAL_READY 0x00100 /* Pre-reloc serial console ready */
|
||||
#define GD_FLG_FULL_MALLOC_INIT 0x00200 /* Full malloc() is ready */
|
||||
|
||||
#endif /* __ASM_GENERIC_GBL_DATA_H */
|
||||
|
@ -20,4 +20,10 @@
|
||||
#define CONFIG_ZLIB 1
|
||||
#define CONFIG_PARTITIONS 1
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
#define CONFIG_DM_WARN
|
||||
#define CONFIG_DM_DEVICE_REMOVE
|
||||
#define CONFIG_DM_STDIO
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -15,11 +15,17 @@
|
||||
#include <asm/hardware.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#define CONFIG_SYS_TEXT_BASE 0x20000000
|
||||
#define CONFIG_SYS_TEXT_BASE 0x21f00000
|
||||
|
||||
/* ARM asynchronous clock */
|
||||
#define CONFIG_SYS_AT91_MAIN_CLOCK 18432000 /* External Crystal, in Hz */
|
||||
#define CONFIG_SYS_AT91_SLOW_CLOCK 32768
|
||||
#define CONFIG_SYS_GENERIC_BOARD
|
||||
#define CONFIG_DM
|
||||
#define CONFIG_CMD_DM
|
||||
#define CONFIG_DM_GPIO
|
||||
#define CONFIG_DM_SERIAL
|
||||
#define CONFIG_SYS_MALLOC_F_LEN (1 << 10)
|
||||
|
||||
/* CPU */
|
||||
#define CONFIG_ARCH_CPU_INIT
|
||||
@ -84,8 +90,10 @@
|
||||
|
||||
/* UARTs/Serial console */
|
||||
#define CONFIG_ATMEL_USART
|
||||
#ifndef CONFIG_DM_SERIAL
|
||||
#define CONFIG_USART_BASE ATMEL_BASE_DBGU
|
||||
#define CONFIG_USART_ID ATMEL_ID_SYS
|
||||
#endif
|
||||
#define CONFIG_BAUDRATE 115200
|
||||
#define CONFIG_SYS_PROMPT "Snapper> "
|
||||
|
||||
@ -159,7 +167,7 @@
|
||||
#define CONFIG_CMD_DHCP
|
||||
#define CONFIG_CMD_FAT
|
||||
#define CONFIG_CMD_I2C
|
||||
#undef CONFIG_CMD_GPIO
|
||||
#define CONFIG_CMD_GPIO
|
||||
#define CONFIG_CMD_USB
|
||||
#define CONFIG_CMD_MII
|
||||
#define CONFIG_CMD_NAND
|
||||
|
@ -118,7 +118,9 @@
|
||||
#define CONFIG_SYS_MEMTEST_START (NV_PA_SDRC_CS0 + 0x600000)
|
||||
#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + 0x100000)
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
#define CONFIG_USE_ARCH_MEMCPY
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Physical Memory Map
|
||||
|
@ -87,7 +87,11 @@ int device_probe_child(struct udevice *dev, void *parent_priv);
|
||||
* @dev: Pointer to device to remove
|
||||
* @return 0 if OK, -ve on error (an error here is normally a very bad thing)
|
||||
*/
|
||||
#ifdef CONFIG_DM_DEVICE_REMOVE
|
||||
int device_remove(struct udevice *dev);
|
||||
#else
|
||||
static inline int device_remove(struct udevice *dev) { return 0; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* device_unbind() - Unbind a device, destroying it
|
||||
@ -99,6 +103,12 @@ int device_remove(struct udevice *dev);
|
||||
*/
|
||||
int device_unbind(struct udevice *dev);
|
||||
|
||||
#ifdef CONFIG_DM_DEVICE_REMOVE
|
||||
void device_free(struct udevice *dev);
|
||||
#else
|
||||
static inline void device_free(struct udevice *dev) {}
|
||||
#endif
|
||||
|
||||
/* Cast away any volatile pointer */
|
||||
#define DM_ROOT_NON_CONST (((gd_t *)gd)->dm_root)
|
||||
#define DM_UCLASS_ROOT_NON_CONST (((gd_t *)gd)->uclass_root)
|
||||
|
@ -47,6 +47,7 @@ struct driver_info;
|
||||
* @name: Name of device, typically the FDT node name
|
||||
* @platdata: Configuration data for this device
|
||||
* @of_offset: Device tree node offset for this device (- for none)
|
||||
* @of_id: Pointer to the udevice_id structure which created the device
|
||||
* @parent: Parent of this device, or NULL for the top level device
|
||||
* @priv: Private data for this device
|
||||
* @uclass: Pointer to uclass for this device
|
||||
@ -65,6 +66,7 @@ struct udevice {
|
||||
const char *name;
|
||||
void *platdata;
|
||||
int of_offset;
|
||||
const struct udevice_id *of_id;
|
||||
struct udevice *parent;
|
||||
void *priv;
|
||||
struct uclass *uclass;
|
||||
@ -205,6 +207,23 @@ void *dev_get_parentdata(struct udevice *dev);
|
||||
*/
|
||||
void *dev_get_priv(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* struct dev_get_parent() - Get the parent of a device
|
||||
*
|
||||
* @child: Child to check
|
||||
* @return parent of child, or NULL if this is the root device
|
||||
*/
|
||||
struct udevice *dev_get_parent(struct udevice *child);
|
||||
|
||||
/**
|
||||
* dev_get_of_data() - get the device tree data used to bind a device
|
||||
*
|
||||
* When a device is bound using a device tree node, it matches a
|
||||
* particular compatible string as in struct udevice_id. This function
|
||||
* returns the associated data value for that compatible string
|
||||
*/
|
||||
ulong dev_get_of_data(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* device_get_child() - Get the child of a device by index
|
||||
*
|
||||
|
@ -60,4 +60,17 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only);
|
||||
int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
|
||||
struct udevice **devp);
|
||||
|
||||
/**
|
||||
* device_bind_driver() - bind a device to a driver
|
||||
*
|
||||
* This binds a new device to a driver.
|
||||
*
|
||||
* @parent: Parent device
|
||||
* @drv_name: Name of driver to attach to this parent
|
||||
* @dev_name: Name of the new device thus created
|
||||
* @devp: Returns the newly bound device
|
||||
*/
|
||||
int device_bind_driver(struct udevice *parent, const char *drv_name,
|
||||
const char *dev_name, struct udevice **devp);
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,13 @@
|
||||
#ifndef __DM_UTIL_H
|
||||
#define __DM_UTIL_H
|
||||
|
||||
#ifdef CONFIG_DM_WARN
|
||||
void dm_warn(const char *fmt, ...);
|
||||
#else
|
||||
static inline void dm_warn(const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
void dm_dbg(const char *fmt, ...);
|
||||
|
@ -872,33 +872,46 @@ extern Void_t* sbrk();
|
||||
|
||||
#else
|
||||
|
||||
#ifdef USE_DL_PREFIX
|
||||
#define cALLOc dlcalloc
|
||||
#define fREe dlfree
|
||||
#define mALLOc dlmalloc
|
||||
#define mEMALIGn dlmemalign
|
||||
#define rEALLOc dlrealloc
|
||||
#define vALLOc dlvalloc
|
||||
#define pvALLOc dlpvalloc
|
||||
#define mALLINFo dlmallinfo
|
||||
#define mALLOPt dlmallopt
|
||||
#else /* USE_DL_PREFIX */
|
||||
#define cALLOc calloc
|
||||
#define fREe free
|
||||
#define mALLOc malloc
|
||||
#define mEMALIGn memalign
|
||||
#define rEALLOc realloc
|
||||
#define vALLOc valloc
|
||||
#define pvALLOc pvalloc
|
||||
#define mALLINFo mallinfo
|
||||
#define mALLOPt mallopt
|
||||
#endif /* USE_DL_PREFIX */
|
||||
#ifdef CONFIG_SYS_MALLOC_SIMPLE
|
||||
#define malloc malloc_simple
|
||||
#define realloc realloc_simple
|
||||
#define memalign memalign_simple
|
||||
static inline void free(void *ptr) {}
|
||||
void *calloc(size_t nmemb, size_t size);
|
||||
void *memalign_simple(size_t alignment, size_t bytes);
|
||||
void *realloc_simple(void *ptr, size_t size);
|
||||
#else
|
||||
|
||||
# ifdef USE_DL_PREFIX
|
||||
# define cALLOc dlcalloc
|
||||
# define fREe dlfree
|
||||
# define mALLOc dlmalloc
|
||||
# define mEMALIGn dlmemalign
|
||||
# define rEALLOc dlrealloc
|
||||
# define vALLOc dlvalloc
|
||||
# define pvALLOc dlpvalloc
|
||||
# define mALLINFo dlmallinfo
|
||||
# define mALLOPt dlmallopt
|
||||
# else /* USE_DL_PREFIX */
|
||||
# define cALLOc calloc
|
||||
# define fREe free
|
||||
# define mALLOc malloc
|
||||
# define mEMALIGn memalign
|
||||
# define rEALLOc realloc
|
||||
# define vALLOc valloc
|
||||
# define pvALLOc pvalloc
|
||||
# define mALLINFo mallinfo
|
||||
# define mALLOPt mallopt
|
||||
# endif /* USE_DL_PREFIX */
|
||||
|
||||
#endif
|
||||
|
||||
/* Public routines */
|
||||
|
||||
#if __STD_C
|
||||
/* Simple versions which can be used when space is tight */
|
||||
void *malloc_simple(size_t size);
|
||||
|
||||
# if __STD_C
|
||||
|
||||
Void_t* mALLOc(size_t);
|
||||
void fREe(Void_t*);
|
||||
@ -913,7 +926,7 @@ size_t malloc_usable_size(Void_t*);
|
||||
void malloc_stats(void);
|
||||
int mALLOPt(int, int);
|
||||
struct mallinfo mALLINFo(void);
|
||||
#else
|
||||
# else
|
||||
Void_t* mALLOc();
|
||||
void fREe();
|
||||
Void_t* rEALLOc();
|
||||
@ -927,6 +940,7 @@ size_t malloc_usable_size();
|
||||
void malloc_stats();
|
||||
int mALLOPt();
|
||||
struct mallinfo mALLINFo();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -534,18 +534,14 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
|
||||
int spi_chip_select(struct udevice *slave);
|
||||
|
||||
/**
|
||||
* spi_bind_device() - bind a device to a bus's chip select
|
||||
*
|
||||
* This binds a new device to an given chip select (which must be unused).
|
||||
* spi_find_chip_select() - Find the slave attached to chip select
|
||||
*
|
||||
* @bus: SPI bus to search
|
||||
* @cs: Chip select to attach to
|
||||
* @drv_name: Name of driver to attach to this chip select
|
||||
* @dev_name: Name of the new device thus created
|
||||
* @devp: Returns the newly bound device
|
||||
* @cs: Chip select to look for
|
||||
* @devp: Returns the slave device if found
|
||||
* @return 0 if found, -ENODEV on error
|
||||
*/
|
||||
int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
|
||||
const char *dev_name, struct udevice **devp);
|
||||
int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* spi_ofdata_to_platdata() - decode standard SPI platform data
|
||||
|
@ -357,9 +357,9 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
|
||||
slash = strrchr(prop, '/');
|
||||
if (strcmp(slash + 1, find_name))
|
||||
continue;
|
||||
for (p = name; *p; p++) {
|
||||
if (isdigit(*p)) {
|
||||
*seqp = simple_strtoul(p, NULL, 10);
|
||||
for (p = name + strlen(name) - 1; p > name; p--) {
|
||||
if (!isdigit(*p)) {
|
||||
*seqp = simple_strtoul(p + 1, NULL, 10);
|
||||
debug("Found seq %d\n", *seqp);
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
|
||||
libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
|
||||
libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/
|
||||
libs-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/
|
||||
libs-$(CONFIG_SPL_DM) += drivers/core/
|
||||
libs-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/
|
||||
libs-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/
|
||||
libs-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/
|
||||
|
Loading…
Reference in New Issue
Block a user