mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 13:11:31 +00:00
Merge git://git.denx.de/u-boot-dm
This commit is contained in:
commit
02ffb580e6
67 changed files with 1741 additions and 647 deletions
|
@ -45,11 +45,6 @@ void __udelay(unsigned long usec)
|
|||
os_usleep(usec);
|
||||
}
|
||||
|
||||
unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
|
||||
{
|
||||
return os_get_nsec() / 1000;
|
||||
}
|
||||
|
||||
int cleanup_before_linux(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <asm/sections.h>
|
||||
#include <asm/state.h>
|
||||
#include <os.h>
|
||||
#include <rtc_def.h>
|
||||
|
||||
/* Operating System Interface */
|
||||
|
||||
|
@ -537,3 +538,20 @@ int os_jump_to_image(const void *dest, int size)
|
|||
|
||||
return unlink(fname);
|
||||
}
|
||||
|
||||
void os_localtime(struct rtc_time *rt)
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
struct tm *tm;
|
||||
|
||||
tm = localtime(&t);
|
||||
rt->tm_sec = tm->tm_sec;
|
||||
rt->tm_min = tm->tm_min;
|
||||
rt->tm_hour = tm->tm_hour;
|
||||
rt->tm_mday = tm->tm_mday;
|
||||
rt->tm_mon = tm->tm_mon + 1;
|
||||
rt->tm_year = tm->tm_year + 1900;
|
||||
rt->tm_wday = tm->tm_wday;
|
||||
rt->tm_yday = tm->tm_yday;
|
||||
rt->tm_isdst = tm->tm_isdst;
|
||||
}
|
||||
|
|
|
@ -77,12 +77,18 @@ int sandbox_main_loop_init(void)
|
|||
struct sandbox_state *state = state_get_current();
|
||||
|
||||
/* Execute command if required */
|
||||
if (state->cmd) {
|
||||
int retval;
|
||||
if (state->cmd || state->run_distro_boot) {
|
||||
int retval = 0;
|
||||
|
||||
cli_init();
|
||||
|
||||
retval = run_command_list(state->cmd, -1, 0);
|
||||
if (state->cmd)
|
||||
retval = run_command_list(state->cmd, -1, 0);
|
||||
|
||||
if (state->run_distro_boot)
|
||||
retval = cli_simple_run_command("run distro_bootcmd",
|
||||
0);
|
||||
|
||||
if (!state->interactive)
|
||||
os_exit(retval);
|
||||
}
|
||||
|
@ -90,6 +96,14 @@ int sandbox_main_loop_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_cmdline_cb_boot(struct sandbox_state *state,
|
||||
const char *arg)
|
||||
{
|
||||
state->run_distro_boot = true;
|
||||
return 0;
|
||||
}
|
||||
SANDBOX_CMDLINE_OPT_SHORT(boot, 'b', 0, "Run distro boot commands");
|
||||
|
||||
static int sandbox_cmdline_cb_command(struct sandbox_state *state,
|
||||
const char *arg)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
aliases {
|
||||
eth5 = "/eth@90000000";
|
||||
i2c0 = &i2c_0;
|
||||
pci0 = &pci;
|
||||
rtc0 = &rtc_0;
|
||||
};
|
||||
|
||||
chosen {
|
||||
|
@ -90,7 +92,7 @@
|
|||
num-gpios = <10>;
|
||||
};
|
||||
|
||||
i2c@0 {
|
||||
i2c_0: i2c@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0 0>;
|
||||
|
@ -105,6 +107,14 @@
|
|||
sandbox,size = <128>;
|
||||
};
|
||||
};
|
||||
|
||||
rtc_0: rtc@43 {
|
||||
reg = <0x43>;
|
||||
compatible = "sandbox-rtc";
|
||||
emul {
|
||||
compatible = "sandbox,i2c-rtc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
spi@0 {
|
||||
|
|
|
@ -12,4 +12,6 @@
|
|||
|
||||
void sandbox_eth_disable_response(int index, bool disable);
|
||||
|
||||
void sandbox_eth_skip_timeout(void);
|
||||
|
||||
#endif /* __ETH_H */
|
||||
|
|
28
arch/sandbox/include/asm/rtc.h
Normal file
28
arch/sandbox/include/asm/rtc.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Simulate an I2C real time clock
|
||||
*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __asm_rtc_h
|
||||
#define __asm_rtc_h
|
||||
|
||||
/* Register numbers in the sandbox RTC */
|
||||
enum {
|
||||
REG_SEC = 5,
|
||||
REG_MIN,
|
||||
REG_HOUR,
|
||||
REG_MDAY,
|
||||
REG_MON,
|
||||
REG_YEAR,
|
||||
REG_WDAY,
|
||||
|
||||
REG_RESET = 0x20,
|
||||
|
||||
REG_COUNT = 0x80,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -42,6 +42,7 @@ struct sandbox_spi_info {
|
|||
struct sandbox_state {
|
||||
const char *cmd; /* Command to execute */
|
||||
bool interactive; /* Enable cmdline after execute */
|
||||
bool run_distro_boot; /* Automatically run distro bootcommands */
|
||||
const char *fdt_fname; /* Filename of FDT binary */
|
||||
const char *parse_err; /* Error to report from parsing */
|
||||
int argc; /* Program arguments */
|
||||
|
|
|
@ -17,6 +17,16 @@
|
|||
#define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM
|
||||
#define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
|
||||
|
||||
/**
|
||||
* sandbox_i2c_set_test_mode() - set test mode for running unit tests
|
||||
*
|
||||
* See sandbox_i2c_xfer() for the behaviour changes.
|
||||
*
|
||||
* @bus: sandbox I2C bus to adjust
|
||||
* @test_mode: true to select test mode, false to run normally
|
||||
*/
|
||||
void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode);
|
||||
|
||||
enum sandbox_i2c_eeprom_test_mode {
|
||||
SIE_TEST_MODE_NONE,
|
||||
/* Permits read/write of only one byte per I2C transaction */
|
||||
|
@ -28,4 +38,33 @@ void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
|
|||
|
||||
void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len);
|
||||
|
||||
/*
|
||||
* sandbox_timer_add_offset()
|
||||
*
|
||||
* Allow tests to add to the time reported through lib/time.c functions
|
||||
* offset: number of milliseconds to advance the system time
|
||||
*/
|
||||
void sandbox_timer_add_offset(unsigned long offset);
|
||||
|
||||
/**
|
||||
* sandbox_i2c_rtc_set_offset() - set the time offset from system/base time
|
||||
*
|
||||
* @dev: RTC device to adjust
|
||||
* @use_system_time: true to use system time, false to use @base_time
|
||||
* @offset: RTC offset from current system/base time (-1 for no
|
||||
* change)
|
||||
* @return old value of RTC offset
|
||||
*/
|
||||
long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
|
||||
int offset);
|
||||
|
||||
/**
|
||||
* sandbox_i2c_rtc_get_set_base_time() - get and set the base time
|
||||
*
|
||||
* @dev: RTC device to adjust
|
||||
* @base_time: New base system time (set to -1 for no change)
|
||||
* @return old base time
|
||||
*/
|
||||
long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <cros_ec.h>
|
||||
#include <dm.h>
|
||||
#include <os.h>
|
||||
#include <asm/test.h>
|
||||
#include <asm/u-boot-sandbox.h>
|
||||
|
||||
/*
|
||||
|
@ -25,9 +26,17 @@ void flush_cache(unsigned long start, unsigned long size)
|
|||
{
|
||||
}
|
||||
|
||||
/* system timer offset in ms */
|
||||
static unsigned long sandbox_timer_offset;
|
||||
|
||||
void sandbox_timer_add_offset(unsigned long offset)
|
||||
{
|
||||
sandbox_timer_offset += offset;
|
||||
}
|
||||
|
||||
unsigned long timer_read_counter(void)
|
||||
{
|
||||
return os_get_nsec() / 1000;
|
||||
return os_get_nsec() / 1000 + sandbox_timer_offset * 1000;
|
||||
}
|
||||
|
||||
int dram_init(void)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <rtc.h>
|
||||
#include <i2c.h>
|
||||
|
||||
|
@ -33,10 +34,18 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
{
|
||||
struct rtc_time tm;
|
||||
int rcode = 0;
|
||||
int old_bus;
|
||||
int old_bus __maybe_unused;
|
||||
|
||||
/* switch to correct I2C bus */
|
||||
#ifdef CONFIG_SYS_I2C
|
||||
#ifdef CONFIG_DM_I2C
|
||||
struct udevice *dev;
|
||||
|
||||
rcode = uclass_get_device(UCLASS_RTC, 0, &dev);
|
||||
if (rcode) {
|
||||
printf("Cannot find RTC: err=%d\n", rcode);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
#elif defined(CONFIG_SYS_I2C)
|
||||
old_bus = i2c_get_bus_num();
|
||||
i2c_set_bus_num(CONFIG_SYS_RTC_BUS_NUM);
|
||||
#else
|
||||
|
@ -48,32 +57,50 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
case 2: /* set date & time */
|
||||
if (strcmp(argv[1],"reset") == 0) {
|
||||
puts ("Reset RTC...\n");
|
||||
rtc_reset ();
|
||||
#ifdef CONFIG_DM_I2C
|
||||
rcode = dm_rtc_reset(dev);
|
||||
if (!rcode)
|
||||
rcode = dm_rtc_set(dev, &default_tm);
|
||||
#else
|
||||
rtc_reset();
|
||||
rcode = rtc_set(&default_tm);
|
||||
#endif
|
||||
if (rcode)
|
||||
puts("## Failed to set date after RTC reset\n");
|
||||
} else {
|
||||
/* initialize tm with current time */
|
||||
rcode = rtc_get (&tm);
|
||||
|
||||
if(!rcode) {
|
||||
#ifdef CONFIG_DM_I2C
|
||||
rcode = dm_rtc_get(dev, &tm);
|
||||
#else
|
||||
rcode = rtc_get(&tm);
|
||||
#endif
|
||||
if (!rcode) {
|
||||
/* insert new date & time */
|
||||
if (mk_date (argv[1], &tm) != 0) {
|
||||
if (mk_date(argv[1], &tm) != 0) {
|
||||
puts ("## Bad date format\n");
|
||||
break;
|
||||
}
|
||||
/* and write to RTC */
|
||||
rcode = rtc_set (&tm);
|
||||
if(rcode)
|
||||
puts("## Set date failed\n");
|
||||
#ifdef CONFIG_DM_I2C
|
||||
rcode = dm_rtc_set(dev, &tm);
|
||||
#else
|
||||
rcode = rtc_set(&tm);
|
||||
#endif
|
||||
if (rcode) {
|
||||
printf("## Set date failed: err=%d\n",
|
||||
rcode);
|
||||
}
|
||||
} else {
|
||||
puts("## Get date failed\n");
|
||||
}
|
||||
}
|
||||
/* FALL TROUGH */
|
||||
case 1: /* get date & time */
|
||||
rcode = rtc_get (&tm);
|
||||
|
||||
#ifdef CONFIG_DM_I2C
|
||||
rcode = dm_rtc_get(dev, &tm);
|
||||
#else
|
||||
rcode = rtc_get(&tm);
|
||||
#endif
|
||||
if (rcode) {
|
||||
puts("## Get date failed\n");
|
||||
break;
|
||||
|
@ -93,11 +120,11 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
/* switch back to original I2C bus */
|
||||
#ifdef CONFIG_SYS_I2C
|
||||
i2c_set_bus_num(old_bus);
|
||||
#else
|
||||
#elif !defined(CONFIG_DM_I2C)
|
||||
I2C_SET_BUS(old_bus);
|
||||
#endif
|
||||
|
||||
return rcode;
|
||||
return rcode ? CMD_RET_FAILURE : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -201,7 +228,7 @@ int mk_date (const char *datestr, struct rtc_time *tmp)
|
|||
tmp->tm_min = val;
|
||||
|
||||
/* calculate day of week */
|
||||
GregorianDay (tmp);
|
||||
rtc_calc_weekday(tmp);
|
||||
|
||||
return (0);
|
||||
default:
|
||||
|
|
|
@ -1533,7 +1533,7 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
snprintf(name, sizeof(name), "framebuffer@%llx", base_address);
|
||||
snprintf(name, sizeof(name), "framebuffer@%" PRIx64, base_address);
|
||||
ret = fdt_set_name(fdt, node, name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
@ -533,7 +533,7 @@ void genimg_print_time(time_t timestamp)
|
|||
#ifndef USE_HOSTCC
|
||||
struct rtc_time tm;
|
||||
|
||||
to_tm(timestamp, &tm);
|
||||
rtc_to_tm(timestamp, &tm);
|
||||
printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n",
|
||||
tm.tm_year, tm.tm_mon, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
|
17
common/usb.c
17
common/usb.c
|
@ -946,13 +946,18 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
|
|||
* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is
|
||||
* only 18 bytes long, this will terminate with a short packet. But if
|
||||
* the maxpacket size is 8 or 16 the device may be waiting to transmit
|
||||
* some more, or keeps on retransmitting the 8 byte header. */
|
||||
* some more, or keeps on retransmitting the 8 byte header.
|
||||
*/
|
||||
|
||||
dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */
|
||||
/* Default to 64 byte max packet size */
|
||||
dev->maxpacketsize = PACKET_SIZE_64;
|
||||
dev->epmaxpacketin[0] = 64;
|
||||
dev->epmaxpacketout[0] = 64;
|
||||
if (dev->speed == USB_SPEED_LOW) {
|
||||
dev->descriptor.bMaxPacketSize0 = 8;
|
||||
dev->maxpacketsize = PACKET_SIZE_8;
|
||||
} else {
|
||||
dev->descriptor.bMaxPacketSize0 = 64;
|
||||
dev->maxpacketsize = PACKET_SIZE_64;
|
||||
}
|
||||
dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
|
||||
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
|
||||
|
||||
if (do_read) {
|
||||
int err;
|
||||
|
|
|
@ -26,3 +26,5 @@ CONFIG_TPM_TIS_SANDBOX=y
|
|||
CONFIG_SOUND=y
|
||||
CONFIG_CMD_SOUND=y
|
||||
CONFIG_SOUND_SANDBOX=y
|
||||
CONFIG_DM_RTC=y
|
||||
CONFIG_CMD_UT_TIME=y
|
||||
|
|
|
@ -41,18 +41,19 @@ static int i2c_gpio_sda_get(struct gpio_desc *sda)
|
|||
|
||||
static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
|
||||
{
|
||||
if (bit) {
|
||||
if (bit)
|
||||
dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
|
||||
} else {
|
||||
else
|
||||
dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
|
||||
dm_gpio_set_value(sda, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
|
||||
{
|
||||
dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
|
||||
dm_gpio_set_value(scl, bit);
|
||||
ulong flags = GPIOD_IS_OUT;
|
||||
|
||||
if (bit)
|
||||
flags |= GPIOD_IS_OUT_ACTIVE;
|
||||
dm_gpio_set_dir_flags(scl, flags);
|
||||
}
|
||||
|
||||
static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
|
||||
|
|
|
@ -186,6 +186,25 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
|
|||
}
|
||||
}
|
||||
|
||||
int dm_i2c_reg_read(struct udevice *dev, uint offset)
|
||||
{
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
ret = dm_i2c_read(dev, offset, &val, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)
|
||||
{
|
||||
uint8_t val = value;
|
||||
|
||||
return dm_i2c_write(dev, offset, &val, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_probe_chip() - probe for a chip on a bus
|
||||
*
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct dm_sandbox_i2c_emul_priv {
|
||||
struct udevice *emul;
|
||||
struct sandbox_i2c_priv {
|
||||
bool test_mode;
|
||||
};
|
||||
|
||||
static int get_emul(struct udevice *dev, struct udevice **devp,
|
||||
|
@ -47,17 +47,25 @@ static int get_emul(struct udevice *dev, struct udevice **devp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
|
||||
{
|
||||
struct sandbox_i2c_priv *priv = dev_get_priv(bus);
|
||||
|
||||
priv->test_mode = test_mode;
|
||||
}
|
||||
|
||||
static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
|
||||
int nmsgs)
|
||||
{
|
||||
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
|
||||
struct sandbox_i2c_priv *priv = dev_get_priv(bus);
|
||||
struct dm_i2c_ops *ops;
|
||||
struct udevice *emul, *dev;
|
||||
bool is_read;
|
||||
int ret;
|
||||
|
||||
/* Special test code to return success but with no emulation */
|
||||
if (msg->addr == SANDBOX_I2C_TEST_ADDR)
|
||||
if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
|
||||
return 0;
|
||||
|
||||
ret = i2c_get_chip(bus, msg->addr, 1, &dev);
|
||||
|
@ -68,13 +76,18 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* For testing, don't allow writing above 100KHz for writes and
|
||||
* 400KHz for reads
|
||||
*/
|
||||
is_read = nmsgs > 1;
|
||||
if (i2c->speed_hz > (is_read ? 400000 : 100000))
|
||||
return -EINVAL;
|
||||
if (priv->test_mode) {
|
||||
/*
|
||||
* For testing, don't allow writing above 100KHz for writes and
|
||||
* 400KHz for reads.
|
||||
*/
|
||||
is_read = nmsgs > 1;
|
||||
if (i2c->speed_hz > (is_read ? 400000 : 100000)) {
|
||||
debug("%s: Max speed exceeded\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return ops->xfer(emul, msg, nmsgs);
|
||||
}
|
||||
|
||||
|
@ -92,4 +105,5 @@ U_BOOT_DRIVER(i2c_sandbox) = {
|
|||
.id = UCLASS_I2C,
|
||||
.of_match = sandbox_i2c_ids,
|
||||
.ops = &sandbox_i2c_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv),
|
||||
};
|
||||
|
|
|
@ -986,7 +986,8 @@ int cros_ec_register(struct udevice *dev)
|
|||
}
|
||||
|
||||
/* Remember this device for use by the cros_ec command */
|
||||
debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
|
||||
debug("Google Chrome EC v%d CROS-EC driver ready, id '%s'\n",
|
||||
cdev->protocol_version, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
|
|||
{
|
||||
struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
|
||||
struct spi_slave *slave = dev_get_parentdata(dev->dev);
|
||||
ulong start;
|
||||
uint8_t byte;
|
||||
int rv;
|
||||
|
||||
/* Do the transfer */
|
||||
|
@ -33,10 +35,25 @@ int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
|
|||
return -1;
|
||||
}
|
||||
|
||||
rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8,
|
||||
dev->dout, dev->din,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
rv = spi_xfer(slave, out_bytes * 8, dev->dout, NULL, SPI_XFER_BEGIN);
|
||||
if (rv)
|
||||
goto done;
|
||||
start = get_timer(0);
|
||||
while (1) {
|
||||
rv = spi_xfer(slave, 8, NULL, &byte, 0);
|
||||
if (byte == SPI_PREAMBLE_END_BYTE)
|
||||
break;
|
||||
if (rv)
|
||||
goto done;
|
||||
if (get_timer(start) > 100) {
|
||||
rv = -ETIMEDOUT;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
rv = spi_xfer(slave, in_bytes * 8, NULL, dev->din, 0);
|
||||
done:
|
||||
spi_xfer(slave, 0, NULL, NULL, SPI_XFER_END);
|
||||
spi_release_bus(slave);
|
||||
|
||||
if (rv) {
|
||||
|
|
|
@ -53,10 +53,10 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
|
|||
{
|
||||
struct spi_slave *slave;
|
||||
struct udevice *bus;
|
||||
char name[20], *str;
|
||||
char name[30], *str;
|
||||
int ret;
|
||||
|
||||
snprintf(name, sizeof(name), "%d:%d", busnum, cs);
|
||||
snprintf(name, sizeof(name), "spi_flash@%d:%d", busnum, cs);
|
||||
str = strdup(name);
|
||||
ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode,
|
||||
"spi_flash_std", str, &bus, &slave);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <dm.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
|
@ -30,6 +31,7 @@ struct eth_sandbox_priv {
|
|||
};
|
||||
|
||||
static bool disabled[8] = {false};
|
||||
static bool skip_timeout;
|
||||
|
||||
/*
|
||||
* sandbox_eth_disable_response()
|
||||
|
@ -42,6 +44,16 @@ void sandbox_eth_disable_response(int index, bool disable)
|
|||
disabled[index] = disable;
|
||||
}
|
||||
|
||||
/*
|
||||
* sandbox_eth_skip_timeout()
|
||||
*
|
||||
* When the first packet read is attempted, fast-forward time
|
||||
*/
|
||||
void sandbox_eth_skip_timeout(void)
|
||||
{
|
||||
skip_timeout = true;
|
||||
}
|
||||
|
||||
static int sb_eth_start(struct udevice *dev)
|
||||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
@ -144,6 +156,11 @@ static int sb_eth_recv(struct udevice *dev, uchar **packetp)
|
|||
{
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (skip_timeout) {
|
||||
sandbox_timer_add_offset(10000UL);
|
||||
skip_timeout = false;
|
||||
}
|
||||
|
||||
if (priv->recv_packet_length) {
|
||||
int lcl_recv_packet_length = priv->recv_packet_length;
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
config DM_RTC
|
||||
bool "Enable Driver Model for RTC drivers"
|
||||
depends on DM
|
||||
help
|
||||
Enable drver model for real-time-clock drivers. The RTC uclass
|
||||
then provides the rtc_get()/rtc_set() interface, delegating to
|
||||
drivers to perform the actual functions. See rtc.h for a
|
||||
description of the API.
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#ccflags-y += -DDEBUG
|
||||
|
||||
obj-$(CONFIG_DM_RTC) += rtc-uclass.o
|
||||
|
||||
obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
|
||||
obj-$(CONFIG_RTC_BFIN) += bfin_rtc.o
|
||||
obj-y += date.o
|
||||
|
@ -24,6 +26,7 @@ obj-$(CONFIG_RTC_DS164x) += ds164x.o
|
|||
obj-$(CONFIG_RTC_DS174x) += ds174x.o
|
||||
obj-$(CONFIG_RTC_DS3231) += ds3231.o
|
||||
obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o
|
||||
obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o
|
||||
obj-$(CONFIG_RTC_IMXDI) += imxdi.o
|
||||
obj-$(CONFIG_RTC_ISL1208) += isl1208.o
|
||||
obj-$(CONFIG_RTC_M41T11) += m41t11.o
|
||||
|
@ -49,4 +52,5 @@ obj-$(CONFIG_RTC_RTC4543) += rtc4543.o
|
|||
obj-$(CONFIG_RTC_RV3029) += rv3029.o
|
||||
obj-$(CONFIG_RTC_RX8025) += rx8025.o
|
||||
obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
|
||||
obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
|
||||
obj-$(CONFIG_RTC_X1205) += x1205.o
|
||||
|
|
|
@ -44,7 +44,7 @@ int rtc_get (struct rtc_time *tmp)
|
|||
} while (tim!=tim2);
|
||||
off = readl(&gpbr->reg[AT91_GPBR_INDEX_TIMEOFF]);
|
||||
/* off==0 means time is invalid, but we ignore that */
|
||||
to_tm (tim+off, tmp);
|
||||
rtc_to_tm(tim+off, tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,7 @@ int rtc_set (struct rtc_time *tmp)
|
|||
at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
|
||||
ulong tim;
|
||||
|
||||
tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
tim = rtc_mktime(tmp);
|
||||
|
||||
/* clear alarm, set prescaler to 32768, clear counter */
|
||||
writel(32768+AT91_RTT_RTTRST, &rtt->mr);
|
||||
|
|
|
@ -67,8 +67,7 @@ int rtc_set(struct rtc_time *tmp)
|
|||
wait_for_complete();
|
||||
|
||||
/* Calculate number of seconds this incoming time represents */
|
||||
remain = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
remain = rtc_mktime(tmp);
|
||||
|
||||
/* Figure out how many days since epoch */
|
||||
days = remain / NUM_SECS_IN_DAY;
|
||||
|
@ -114,7 +113,7 @@ int rtc_get(struct rtc_time *tmp)
|
|||
|
||||
/* Calculate the total number of seconds since epoch */
|
||||
time_in_sec = (tm_sec) + MIN_TO_SECS(tm_min) + HRS_TO_SECS(tm_hr) + DAYS_TO_SECS(tm_day);
|
||||
to_tm(time_in_sec, tmp);
|
||||
rtc_to_tm(time_in_sec, tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <errno.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
|
||||
|
@ -30,13 +31,15 @@ static int month_days[12] = {
|
|||
/*
|
||||
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
|
||||
*/
|
||||
void GregorianDay(struct rtc_time * tm)
|
||||
int rtc_calc_weekday(struct rtc_time *tm)
|
||||
{
|
||||
int leapsToDate;
|
||||
int lastYear;
|
||||
int day;
|
||||
int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
|
||||
|
||||
if (tm->tm_year < 1753)
|
||||
return -EINVAL;
|
||||
lastYear=tm->tm_year-1;
|
||||
|
||||
/*
|
||||
|
@ -64,9 +67,11 @@ void GregorianDay(struct rtc_time * tm)
|
|||
day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
|
||||
|
||||
tm->tm_wday=day%7;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void to_tm(int tim, struct rtc_time * tm)
|
||||
int rtc_to_tm(int tim, struct rtc_time *tm)
|
||||
{
|
||||
register int i;
|
||||
register long hms, day;
|
||||
|
@ -98,10 +103,14 @@ void to_tm(int tim, struct rtc_time * tm)
|
|||
/* Days are what is left over (+1) from all that. */
|
||||
tm->tm_mday = day + 1;
|
||||
|
||||
/* Zero unused fields */
|
||||
tm->tm_yday = 0;
|
||||
tm->tm_isdst = 0;
|
||||
|
||||
/*
|
||||
* Determine the day of week
|
||||
*/
|
||||
GregorianDay(tm);
|
||||
return rtc_calc_weekday(tm);
|
||||
}
|
||||
|
||||
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
|
||||
|
@ -119,22 +128,23 @@ void to_tm(int tim, struct rtc_time * tm)
|
|||
* machines were long is 32-bit! (However, as time_t is signed, we
|
||||
* will already get problems at other places on 2038-01-19 03:14:08)
|
||||
*/
|
||||
unsigned long
|
||||
mktime (unsigned int year, unsigned int mon,
|
||||
unsigned int day, unsigned int hour,
|
||||
unsigned int min, unsigned int sec)
|
||||
unsigned long rtc_mktime(const struct rtc_time *tm)
|
||||
{
|
||||
if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
|
||||
int mon = tm->tm_mon;
|
||||
int year = tm->tm_year;
|
||||
int days, hours;
|
||||
|
||||
mon -= 2;
|
||||
if (0 >= (int)mon) { /* 1..12 -> 11,12,1..10 */
|
||||
mon += 12; /* Puts Feb last since it has leap day */
|
||||
year -= 1;
|
||||
}
|
||||
|
||||
return (((
|
||||
(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
|
||||
year*365 - 719499
|
||||
)*24 + hour /* now have hours */
|
||||
)*60 + min /* now have minutes */
|
||||
)*60 + sec; /* finally seconds */
|
||||
days = (unsigned long)(year / 4 - year / 100 + year / 400 +
|
||||
367 * mon / 12 + tm->tm_mday) +
|
||||
year * 365 - 719499;
|
||||
hours = days * 24 + tm->tm_hour;
|
||||
return (hours * 60 + tm->tm_min) * 60 + tm->tm_sec;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -110,7 +110,7 @@ int rtc_get (struct rtc_time *tmp)
|
|||
immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
|
||||
udelay (10);
|
||||
|
||||
GregorianDay (tmp); /* Determine the day of week */
|
||||
rtc_calc_weekday(tmp); /* Determine the day of week */
|
||||
|
||||
debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
|
||||
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
|
||||
|
@ -180,8 +180,7 @@ int rtc_set (struct rtc_time *tmp)
|
|||
{
|
||||
ulong tim;
|
||||
|
||||
tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
tim = rtc_mktime(tmp);
|
||||
|
||||
immap->im_sitk.sitk_rtck = KAPWR_KEY;
|
||||
immap->im_sit.sit_rtc = tim;
|
||||
|
|
|
@ -118,7 +118,7 @@ int rtc_get (struct rtc_time *tm){
|
|||
|
||||
DEBUGR ("Get RTC s since 1.1.1970: %ld\n", time1);
|
||||
|
||||
to_tm(time1, tm); /* To Gregorian Date */
|
||||
rtc_to_tm(time1, tm); /* To Gregorian Date */
|
||||
|
||||
if (rtc_read(RTC_SR_ADDR) & RTC_SR_BIT_OSF) {
|
||||
printf ("### Warning: RTC oscillator has stopped\n");
|
||||
|
@ -147,9 +147,7 @@ int rtc_set (struct rtc_time *tmp){
|
|||
if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
|
||||
printf("WARNING: year should be between 1970 and 2069!\n");
|
||||
|
||||
time = mktime(tmp->tm_year, tmp->tm_mon,
|
||||
tmp->tm_mday, tmp->tm_hour,
|
||||
tmp->tm_min, tmp->tm_sec);
|
||||
time = rtc_mktime(tmp);
|
||||
|
||||
DEBUGR ("Set RTC s since 1.1.1970: %ld (0x%02lx)\n", time, time);
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ int rtc_get(struct rtc_time *tmp)
|
|||
now = ftrtc010_time() + readl(&rtc->record);
|
||||
#endif
|
||||
|
||||
to_tm(now, tmp);
|
||||
rtc_to_tm(now, tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,8 +104,7 @@ int rtc_set(struct rtc_time *tmp)
|
|||
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
|
||||
new = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour,
|
||||
tmp->tm_min, tmp->tm_sec);
|
||||
new = rtc_mktime(tmp);
|
||||
|
||||
now = ftrtc010_time();
|
||||
|
||||
|
|
236
drivers/rtc/i2c_rtc_emul.c
Normal file
236
drivers/rtc/i2c_rtc_emul.c
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Simulate an I2C real time clock
|
||||
*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a test driver. It starts off with the current time of the machine,
|
||||
* but also supports setting the time, using an offset from the current
|
||||
* clock. This driver is only intended for testing, not accurate
|
||||
* time-keeping. It does not change the system time.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <i2c.h>
|
||||
#include <os.h>
|
||||
#include <rtc.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug_buffer print_buffer
|
||||
#else
|
||||
#define debug_buffer(x, ...)
|
||||
#endif
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/**
|
||||
* struct sandbox_i2c_rtc_plat_data - platform data for the RTC
|
||||
*
|
||||
* @base_time: Base system time when RTC device was bound
|
||||
* @offset: RTC offset from current system time
|
||||
* @use_system_time: true to use system time, false to use @base_time
|
||||
* @reg: Register values
|
||||
*/
|
||||
struct sandbox_i2c_rtc_plat_data {
|
||||
long base_time;
|
||||
long offset;
|
||||
bool use_system_time;
|
||||
u8 reg[REG_COUNT];
|
||||
};
|
||||
|
||||
struct sandbox_i2c_rtc {
|
||||
unsigned int offset_secs;
|
||||
};
|
||||
|
||||
long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
|
||||
int offset)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
|
||||
long old_offset;
|
||||
|
||||
old_offset = plat->offset;
|
||||
plat->use_system_time = use_system_time;
|
||||
if (offset != -1)
|
||||
plat->offset = offset;
|
||||
|
||||
return old_offset;
|
||||
}
|
||||
|
||||
long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
|
||||
long old_base_time;
|
||||
|
||||
old_base_time = plat->base_time;
|
||||
if (base_time != -1)
|
||||
plat->base_time = base_time;
|
||||
|
||||
return old_base_time;
|
||||
}
|
||||
|
||||
static void reset_time(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
|
||||
struct rtc_time now;
|
||||
|
||||
os_localtime(&now);
|
||||
plat->base_time = rtc_mktime(&now);
|
||||
plat->offset = 0;
|
||||
plat->use_system_time = true;
|
||||
}
|
||||
|
||||
static int sandbox_i2c_rtc_get(struct udevice *dev, struct rtc_time *time)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
|
||||
struct rtc_time tm_now;
|
||||
long now;
|
||||
|
||||
if (plat->use_system_time) {
|
||||
os_localtime(&tm_now);
|
||||
now = rtc_mktime(&tm_now);
|
||||
} else {
|
||||
now = plat->base_time;
|
||||
}
|
||||
|
||||
return rtc_to_tm(now + plat->offset, time);
|
||||
}
|
||||
|
||||
static int sandbox_i2c_rtc_set(struct udevice *dev, const struct rtc_time *time)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
|
||||
struct rtc_time tm_now;
|
||||
long now;
|
||||
|
||||
if (plat->use_system_time) {
|
||||
os_localtime(&tm_now);
|
||||
now = rtc_mktime(&tm_now);
|
||||
} else {
|
||||
now = plat->base_time;
|
||||
}
|
||||
plat->offset = rtc_mktime(time) - now;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update the current time in the registers */
|
||||
static int sandbox_i2c_rtc_prepare_read(struct udevice *emul)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
|
||||
struct rtc_time time;
|
||||
int ret;
|
||||
|
||||
ret = sandbox_i2c_rtc_get(emul, &time);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
plat->reg[REG_SEC] = time.tm_sec;
|
||||
plat->reg[REG_MIN] = time.tm_min;
|
||||
plat->reg[REG_HOUR] = time.tm_hour;
|
||||
plat->reg[REG_MDAY] = time.tm_mday;
|
||||
plat->reg[REG_MON] = time.tm_mon;
|
||||
plat->reg[REG_YEAR] = time.tm_year - 1900;
|
||||
plat->reg[REG_WDAY] = time.tm_wday;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_i2c_rtc_complete_write(struct udevice *emul)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
|
||||
struct rtc_time time;
|
||||
int ret;
|
||||
|
||||
time.tm_sec = plat->reg[REG_SEC];
|
||||
time.tm_min = plat->reg[REG_MIN];
|
||||
time.tm_hour = plat->reg[REG_HOUR];
|
||||
time.tm_mday = plat->reg[REG_MDAY];
|
||||
time.tm_mon = plat->reg[REG_MON];
|
||||
time.tm_year = plat->reg[REG_YEAR] + 1900;
|
||||
time.tm_wday = plat->reg[REG_WDAY];
|
||||
|
||||
ret = sandbox_i2c_rtc_set(emul, &time);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_i2c_rtc_xfer(struct udevice *emul, struct i2c_msg *msg,
|
||||
int nmsgs)
|
||||
{
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
|
||||
uint offset = 0;
|
||||
int ret;
|
||||
|
||||
debug("\n%s\n", __func__);
|
||||
ret = sandbox_i2c_rtc_prepare_read(emul);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (; nmsgs > 0; nmsgs--, msg++) {
|
||||
int len;
|
||||
u8 *ptr;
|
||||
|
||||
len = msg->len;
|
||||
debug(" %s: msg->len=%d",
|
||||
msg->flags & I2C_M_RD ? "read" : "write",
|
||||
msg->len);
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
debug(", offset %x, len %x: ", offset, len);
|
||||
|
||||
/* Read the register */
|
||||
memcpy(msg->buf, plat->reg + offset, len);
|
||||
memset(msg->buf + len, '\xff', msg->len - len);
|
||||
debug_buffer(0, msg->buf, 1, msg->len, 0);
|
||||
} else if (len >= 1) {
|
||||
ptr = msg->buf;
|
||||
offset = *ptr++ & (REG_COUNT - 1);
|
||||
len--;
|
||||
debug(", set offset %x: ", offset);
|
||||
debug_buffer(0, msg->buf, 1, msg->len, 0);
|
||||
|
||||
/* Write the register */
|
||||
memcpy(plat->reg + offset, ptr, len);
|
||||
if (offset == REG_RESET)
|
||||
reset_time(emul);
|
||||
}
|
||||
}
|
||||
ret = sandbox_i2c_rtc_complete_write(emul);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = {
|
||||
.xfer = sandbox_i2c_rtc_xfer,
|
||||
};
|
||||
|
||||
static int sandbox_i2c_rtc_bind(struct udevice *dev)
|
||||
{
|
||||
reset_time(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sandbox_i2c_rtc_ids[] = {
|
||||
{ .compatible = "sandbox,i2c-rtc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sandbox_i2c_rtc_emul) = {
|
||||
.name = "sandbox_i2c_rtc_emul",
|
||||
.id = UCLASS_I2C_EMUL,
|
||||
.of_match = sandbox_i2c_rtc_ids,
|
||||
.bind = sandbox_i2c_rtc_bind,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_i2c_rtc),
|
||||
.platdata_auto_alloc_size = sizeof(struct sandbox_i2c_rtc_plat_data),
|
||||
.ops = &sandbox_i2c_rtc_emul_ops,
|
||||
};
|
|
@ -192,7 +192,7 @@ int rtc_get(struct rtc_time *tmp)
|
|||
}
|
||||
|
||||
now = __raw_readl(&data.regs->dtcmr);
|
||||
to_tm(now, tmp);
|
||||
rtc_to_tm(now, tmp);
|
||||
|
||||
err:
|
||||
return rc;
|
||||
|
@ -209,8 +209,7 @@ int rtc_set(struct rtc_time *tmp)
|
|||
goto err;
|
||||
}
|
||||
|
||||
now = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
now = rtc_mktime(tmp);
|
||||
/* zero the fractional part first */
|
||||
rc = DI_WRITE_WAIT(0, dtclr);
|
||||
if (rc == 0)
|
||||
|
|
|
@ -36,7 +36,7 @@ int rtc_get(struct rtc_time *rtc)
|
|||
|
||||
tim = day1 * 86400 + time;
|
||||
|
||||
to_tm(tim, rtc);
|
||||
rtc_to_tm(tim, rtc);
|
||||
|
||||
rtc->tm_yday = 0;
|
||||
rtc->tm_isdst = 0;
|
||||
|
@ -51,8 +51,7 @@ int rtc_set(struct rtc_time *rtc)
|
|||
if (!p)
|
||||
return -1;
|
||||
|
||||
time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday,
|
||||
rtc->tm_hour, rtc->tm_min, rtc->tm_sec);
|
||||
time = rtc_mktime(rtc);
|
||||
day = time / 86400;
|
||||
time %= 86400;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ int rtc_get(struct rtc_time *tmp)
|
|||
tim = (tim * 60) + rtc_mins;
|
||||
tim = (tim * 60) + rtc->seconds;
|
||||
|
||||
to_tm(tim, tmp);
|
||||
rtc_to_tm(tim, tmp);
|
||||
|
||||
tmp->tm_yday = 0;
|
||||
tmp->tm_isdst = 0;
|
||||
|
|
|
@ -26,7 +26,7 @@ int rtc_get (struct rtc_time *tmp)
|
|||
|
||||
tim = immr->im_sit.sit_rtc;
|
||||
|
||||
to_tm (tim, tmp);
|
||||
rtc_to_tm(tim, tmp);
|
||||
|
||||
debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
|
||||
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
|
||||
|
@ -44,8 +44,7 @@ int rtc_set (struct rtc_time *tmp)
|
|||
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
|
||||
tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
tim = rtc_mktime(tmp);
|
||||
|
||||
immr->im_sitk.sitk_rtck = KAPWR_KEY;
|
||||
immr->im_sit.sit_rtc = tim;
|
||||
|
|
|
@ -30,7 +30,7 @@ int rtc_get(struct rtc_time *time)
|
|||
|
||||
sec += min * 60 + hour * 3600 + day * 24 * 3600;
|
||||
|
||||
to_tm(sec, time);
|
||||
rtc_to_tm(sec, time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -40,8 +40,7 @@ int rtc_set(struct rtc_time *time)
|
|||
struct rtc_regs *rtc_regs = (struct rtc_regs *)IMX_RTC_BASE;
|
||||
uint32_t day, hour, min, sec;
|
||||
|
||||
sec = mktime(time->tm_year, time->tm_mon, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
sec = rtc_mktime(time);
|
||||
|
||||
day = sec / (24 * 3600);
|
||||
sec = sec % (24 * 3600);
|
||||
|
|
|
@ -43,7 +43,7 @@ int rtc_get(struct rtc_time *time)
|
|||
uint32_t secs;
|
||||
|
||||
secs = readl(&rtc_regs->hw_rtc_seconds);
|
||||
to_tm(secs, time);
|
||||
rtc_to_tm(secs, time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -52,8 +52,7 @@ int rtc_set(struct rtc_time *time)
|
|||
{
|
||||
uint32_t secs;
|
||||
|
||||
secs = mktime(time->tm_year, time->tm_mon, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
secs = rtc_mktime(time);
|
||||
|
||||
return mxs_rtc_set_time(secs);
|
||||
}
|
||||
|
|
|
@ -72,8 +72,7 @@ int rtc_set(struct rtc_time *tmp)
|
|||
}
|
||||
|
||||
/* Calculate number of seconds this incoming time represents */
|
||||
tim = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
tim = rtc_mktime(tmp);
|
||||
|
||||
RTC_WRITE_REG(RTC_LR, tim);
|
||||
|
||||
|
@ -97,7 +96,7 @@ int rtc_get(struct rtc_time *tmp)
|
|||
|
||||
tim = RTC_READ_REG(RTC_DR);
|
||||
|
||||
to_tm (tim, tmp);
|
||||
rtc_to_tm(tim, tmp);
|
||||
|
||||
debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
|
||||
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
|
||||
|
|
96
drivers/rtc/rtc-uclass.c
Normal file
96
drivers/rtc/rtc-uclass.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* (C) Copyright 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <rtc.h>
|
||||
|
||||
int dm_rtc_get(struct udevice *dev, struct rtc_time *time)
|
||||
{
|
||||
struct rtc_ops *ops = rtc_get_ops(dev);
|
||||
|
||||
assert(ops);
|
||||
if (!ops->get)
|
||||
return -ENOSYS;
|
||||
return ops->get(dev, time);
|
||||
}
|
||||
|
||||
int dm_rtc_set(struct udevice *dev, struct rtc_time *time)
|
||||
{
|
||||
struct rtc_ops *ops = rtc_get_ops(dev);
|
||||
|
||||
assert(ops);
|
||||
if (!ops->set)
|
||||
return -ENOSYS;
|
||||
return ops->set(dev, time);
|
||||
}
|
||||
|
||||
int dm_rtc_reset(struct udevice *dev)
|
||||
{
|
||||
struct rtc_ops *ops = rtc_get_ops(dev);
|
||||
|
||||
assert(ops);
|
||||
if (!ops->reset)
|
||||
return -ENOSYS;
|
||||
return ops->reset(dev);
|
||||
}
|
||||
|
||||
int rtc_read8(struct udevice *dev, unsigned int reg)
|
||||
{
|
||||
struct rtc_ops *ops = rtc_get_ops(dev);
|
||||
|
||||
assert(ops);
|
||||
if (!ops->read8)
|
||||
return -ENOSYS;
|
||||
return ops->read8(dev, reg);
|
||||
}
|
||||
|
||||
int rtc_write8(struct udevice *dev, unsigned int reg, int val)
|
||||
{
|
||||
struct rtc_ops *ops = rtc_get_ops(dev);
|
||||
|
||||
assert(ops);
|
||||
if (!ops->write8)
|
||||
return -ENOSYS;
|
||||
return ops->write8(dev, reg, val);
|
||||
}
|
||||
|
||||
int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep)
|
||||
{
|
||||
u32 value = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(value); i++) {
|
||||
ret = rtc_read8(dev, reg + i);
|
||||
if (ret)
|
||||
return ret;
|
||||
value |= ret << (i << 3);
|
||||
}
|
||||
|
||||
*valuep = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_write32(struct udevice *dev, unsigned int reg, u32 value)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < sizeof(value); i++) {
|
||||
ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(rtc) = {
|
||||
.name = "rtc",
|
||||
.id = UCLASS_RTC,
|
||||
};
|
106
drivers/rtc/sandbox_rtc.c
Normal file
106
drivers/rtc/sandbox_rtc.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* (C) Copyright 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <i2c.h>
|
||||
#include <rtc.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
#define REG_COUNT 0x80
|
||||
|
||||
static int sandbox_rtc_get(struct udevice *dev, struct rtc_time *time)
|
||||
{
|
||||
time->tm_sec = dm_i2c_reg_read(dev, REG_SEC);
|
||||
if (time->tm_sec < 0)
|
||||
return time->tm_sec;
|
||||
time->tm_min = dm_i2c_reg_read(dev, REG_MIN);
|
||||
if (time->tm_min < 0)
|
||||
return time->tm_min;
|
||||
time->tm_hour = dm_i2c_reg_read(dev, REG_HOUR);
|
||||
if (time->tm_hour < 0)
|
||||
return time->tm_hour;
|
||||
time->tm_mday = dm_i2c_reg_read(dev, REG_MDAY);
|
||||
if (time->tm_mday < 0)
|
||||
return time->tm_mday;
|
||||
time->tm_mon = dm_i2c_reg_read(dev, REG_MON);
|
||||
if (time->tm_mon < 0)
|
||||
return time->tm_mon;
|
||||
time->tm_year = dm_i2c_reg_read(dev, REG_YEAR);
|
||||
if (time->tm_year < 0)
|
||||
return time->tm_year;
|
||||
time->tm_year += 1900;
|
||||
time->tm_wday = dm_i2c_reg_read(dev, REG_WDAY);
|
||||
if (time->tm_wday < 0)
|
||||
return time->tm_wday;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_rtc_set(struct udevice *dev, const struct rtc_time *time)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dm_i2c_reg_write(dev, REG_SEC, time->tm_sec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dm_i2c_reg_write(dev, REG_MIN, time->tm_min);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dm_i2c_reg_write(dev, REG_HOUR, time->tm_hour);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dm_i2c_reg_write(dev, REG_MDAY, time->tm_mday);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dm_i2c_reg_write(dev, REG_MON, time->tm_mon);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dm_i2c_reg_write(dev, REG_YEAR, time->tm_year - 1900);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dm_i2c_reg_write(dev, REG_WDAY, time->tm_wday);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_rtc_reset(struct udevice *dev)
|
||||
{
|
||||
return dm_i2c_reg_write(dev, REG_RESET, 0);
|
||||
}
|
||||
|
||||
static int sandbox_rtc_read8(struct udevice *dev, unsigned int reg)
|
||||
{
|
||||
return dm_i2c_reg_read(dev, reg);
|
||||
}
|
||||
|
||||
static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val)
|
||||
{
|
||||
return dm_i2c_reg_write(dev, reg, val);
|
||||
}
|
||||
|
||||
static const struct rtc_ops sandbox_rtc_ops = {
|
||||
.get = sandbox_rtc_get,
|
||||
.set = sandbox_rtc_set,
|
||||
.reset = sandbox_rtc_reset,
|
||||
.read8 = sandbox_rtc_read8,
|
||||
.write8 = sandbox_rtc_write8,
|
||||
};
|
||||
|
||||
static const struct udevice_id sandbox_rtc_ids[] = {
|
||||
{ .compatible = "sandbox-rtc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rtc_sandbox) = {
|
||||
.name = "rtc-sandbox",
|
||||
.id = UCLASS_RTC,
|
||||
.of_match = sandbox_rtc_ids,
|
||||
.ops = &sandbox_rtc_ops,
|
||||
};
|
|
@ -63,9 +63,12 @@ int spi_claim_bus(struct spi_slave *slave)
|
|||
}
|
||||
if (!speed)
|
||||
speed = 100000;
|
||||
ret = spi_set_speed_mode(bus, speed, slave->mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (speed != slave->speed) {
|
||||
ret = spi_set_speed_mode(bus, speed, slave->mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
slave->speed = speed;
|
||||
}
|
||||
|
||||
return ops->claim_bus ? ops->claim_bus(dev) : 0;
|
||||
}
|
||||
|
|
|
@ -25,14 +25,12 @@
|
|||
/* Declare global data pointer */
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
struct exynos_ehci_platdata {
|
||||
struct usb_platdata usb_plat;
|
||||
fdt_addr_t hcd_base;
|
||||
fdt_addr_t phy_base;
|
||||
struct gpio_desc vbus_gpio;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Contains pointers to register base addresses
|
||||
|
@ -42,16 +40,8 @@ struct exynos_ehci {
|
|||
struct ehci_ctrl ctrl;
|
||||
struct exynos_usb_phy *usb;
|
||||
struct ehci_hccr *hcd;
|
||||
#ifndef CONFIG_DM_USB
|
||||
struct gpio_desc vbus_gpio;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
static struct exynos_ehci exynos;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
|
||||
|
@ -91,55 +81,6 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
|
||||
{
|
||||
fdt_addr_t addr;
|
||||
unsigned int node;
|
||||
int depth;
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_EHCI);
|
||||
if (node <= 0) {
|
||||
debug("EHCI: Can't get device node for ehci\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the base address for EHCI controller from the device node
|
||||
*/
|
||||
addr = fdtdec_get_addr(blob, node, "reg");
|
||||
if (addr == FDT_ADDR_T_NONE) {
|
||||
debug("Can't get the EHCI register address\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
exynos->hcd = (struct ehci_hccr *)addr;
|
||||
|
||||
/* Vbus gpio */
|
||||
gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
|
||||
&exynos->vbus_gpio, GPIOD_IS_OUT);
|
||||
|
||||
depth = 0;
|
||||
node = fdtdec_next_compatible_subnode(blob, node,
|
||||
COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
|
||||
if (node <= 0) {
|
||||
debug("EHCI: Can't get device node for usb-phy controller\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the base address for usbphy from the device node
|
||||
*/
|
||||
exynos->usb = (struct exynos_usb_phy *)fdtdec_get_addr(blob, node,
|
||||
"reg");
|
||||
if (exynos->usb == NULL) {
|
||||
debug("Can't get the usbphy register address\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void exynos5_setup_usb_phy(struct exynos_usb_phy *usb)
|
||||
{
|
||||
|
@ -270,63 +211,6 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
|
|||
set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
/*
|
||||
* EHCI-initialization
|
||||
* Create the appropriate control structures to manage
|
||||
* a new EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_init(int index, enum usb_init_type init,
|
||||
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
|
||||
{
|
||||
struct exynos_ehci *ctx = &exynos;
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
if (exynos_usb_parse_dt(gd->fdt_blob, ctx)) {
|
||||
debug("Unable to parse device tree for ehci-exynos\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
#else
|
||||
ctx->usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy();
|
||||
ctx->hcd = (struct ehci_hccr *)samsung_get_base_usb_ehci();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
/* setup the Vbus gpio here */
|
||||
if (dm_gpio_is_valid(&ctx->vbus_gpio))
|
||||
dm_gpio_set_value(&ctx->vbus_gpio, 1);
|
||||
#endif
|
||||
|
||||
setup_usb_phy(ctx->usb);
|
||||
|
||||
board_usb_init(index, init);
|
||||
|
||||
*hccr = ctx->hcd;
|
||||
*hcor = (struct ehci_hcor *)((uint32_t) *hccr
|
||||
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
|
||||
|
||||
debug("Exynos5-ehci: init hccr %x and hcor %x hc_length %d\n",
|
||||
(uint32_t)*hccr, (uint32_t)*hcor,
|
||||
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the appropriate control structures corresponding
|
||||
* the EHCI host controller.
|
||||
*/
|
||||
int ehci_hcd_stop(int index)
|
||||
{
|
||||
struct exynos_ehci *ctx = &exynos;
|
||||
|
||||
reset_usb_phy(ctx->usb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
static int ehci_usb_probe(struct udevice *dev)
|
||||
{
|
||||
struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
|
||||
|
@ -377,4 +261,3 @@ U_BOOT_DRIVER(usb_ehci) = {
|
|||
.platdata_auto_alloc_size = sizeof(struct exynos_ehci_platdata),
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -125,14 +125,7 @@ static struct descriptor {
|
|||
static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev)
|
||||
{
|
||||
#ifdef CONFIG_DM_USB
|
||||
struct udevice *dev;
|
||||
|
||||
/* Find the USB controller */
|
||||
for (dev = udev->dev;
|
||||
device_get_uclass_id(dev) != UCLASS_USB;
|
||||
dev = dev->parent)
|
||||
;
|
||||
return dev_get_priv(dev);
|
||||
return dev_get_priv(usb_get_bus(udev->dev));
|
||||
#else
|
||||
return udev->controller;
|
||||
#endif
|
||||
|
@ -310,23 +303,33 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
|
|||
* in the tree before that one!
|
||||
*/
|
||||
#ifdef CONFIG_DM_USB
|
||||
/*
|
||||
* When called from usb-uclass.c: usb_scan_device() udev->dev points
|
||||
* to the parent udevice, not the actual udevice belonging to the
|
||||
* udev as the device is not instantiated yet. So when searching
|
||||
* for the first usb-2 parent start with udev->dev not
|
||||
* udev->dev->parent .
|
||||
*/
|
||||
struct udevice *parent;
|
||||
struct usb_device *uparent;
|
||||
|
||||
for (ttdev = udev; ; ) {
|
||||
struct udevice *dev = ttdev->dev;
|
||||
ttdev = udev;
|
||||
parent = udev->dev;
|
||||
uparent = dev_get_parentdata(parent);
|
||||
|
||||
if (dev->parent &&
|
||||
device_get_uclass_id(dev->parent) == UCLASS_USB_HUB)
|
||||
parent = dev->parent;
|
||||
else
|
||||
parent = NULL;
|
||||
if (!parent)
|
||||
while (uparent->speed != USB_SPEED_HIGH) {
|
||||
struct udevice *dev = parent;
|
||||
|
||||
if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
|
||||
printf("ehci: Error cannot find high speed parent of usb-1 device\n");
|
||||
return;
|
||||
ttdev = dev_get_parentdata(parent);
|
||||
if (!ttdev->speed != USB_SPEED_HIGH)
|
||||
break;
|
||||
}
|
||||
|
||||
ttdev = dev_get_parentdata(dev);
|
||||
parent = dev->parent;
|
||||
uparent = dev_get_parentdata(parent);
|
||||
}
|
||||
parent_devnum = ttdev->devnum;
|
||||
parent_devnum = uparent->devnum;
|
||||
#else
|
||||
ttdev = udev;
|
||||
while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH)
|
||||
|
@ -1576,12 +1579,15 @@ int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
|
|||
struct ehci_hcor *hcor, const struct ehci_ops *ops,
|
||||
uint tweaks, enum usb_init_type init)
|
||||
{
|
||||
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
|
||||
struct ehci_ctrl *ctrl = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__,
|
||||
dev->name, ctrl, hccr, hcor, init);
|
||||
|
||||
priv->desc_before_addr = true;
|
||||
|
||||
ehci_setup_ops(ctrl, ops);
|
||||
ctrl->hccr = hccr;
|
||||
ctrl->hcor = hcor;
|
||||
|
|
|
@ -103,16 +103,91 @@ static struct pci_device_id ehci_pci_ids[] = {
|
|||
# define m32_swap(x) cpu_to_le32(x)
|
||||
#endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
/*
|
||||
* We really should do proper cache flushing everywhere, but for now we only
|
||||
* do it for new (driver-model) usb code to avoid regressions.
|
||||
*/
|
||||
#define flush_dcache_buffer(addr, size) \
|
||||
flush_dcache_range((unsigned long)(addr), \
|
||||
ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
|
||||
#define invalidate_dcache_buffer(addr, size) \
|
||||
invalidate_dcache_range((unsigned long)(addr), \
|
||||
ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
|
||||
#else
|
||||
#define flush_dcache_buffer(addr, size)
|
||||
#define invalidate_dcache_buffer(addr, size)
|
||||
#endif
|
||||
|
||||
/* Do not use sizeof(ed / td) as our ed / td structs contain extra members */
|
||||
#define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16)
|
||||
#define flush_dcache_td(addr) flush_dcache_buffer(addr, 16)
|
||||
#define flush_dcache_iso_td(addr) flush_dcache_buffer(addr, 32)
|
||||
#define flush_dcache_hcca(addr) flush_dcache_buffer(addr, 256)
|
||||
#define invalidate_dcache_ed(addr) invalidate_dcache_buffer(addr, 16)
|
||||
#define invalidate_dcache_td(addr) invalidate_dcache_buffer(addr, 16)
|
||||
#define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32)
|
||||
#define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256)
|
||||
|
||||
/* global ohci_t */
|
||||
static ohci_t gohci;
|
||||
/* this must be aligned to a 256 byte boundary */
|
||||
struct ohci_hcca ghcca[1];
|
||||
/* a pointer to the aligned storage */
|
||||
struct ohci_hcca *phcca;
|
||||
/* this allocates EDs for all possible endpoints */
|
||||
struct ohci_device ohci_dev;
|
||||
/* device which was disconnected */
|
||||
struct usb_device *devgone;
|
||||
|
||||
/* mapping of the OHCI CC status to error codes */
|
||||
static int cc_to_error[16] = {
|
||||
/* No Error */ 0,
|
||||
/* CRC Error */ USB_ST_CRC_ERR,
|
||||
/* Bit Stuff */ USB_ST_BIT_ERR,
|
||||
/* Data Togg */ USB_ST_CRC_ERR,
|
||||
/* Stall */ USB_ST_STALLED,
|
||||
/* DevNotResp */ -1,
|
||||
/* PIDCheck */ USB_ST_BIT_ERR,
|
||||
/* UnExpPID */ USB_ST_BIT_ERR,
|
||||
/* DataOver */ USB_ST_BUF_ERR,
|
||||
/* DataUnder */ USB_ST_BUF_ERR,
|
||||
/* reservd */ -1,
|
||||
/* reservd */ -1,
|
||||
/* BufferOver */ USB_ST_BUF_ERR,
|
||||
/* BuffUnder */ USB_ST_BUF_ERR,
|
||||
/* Not Access */ -1,
|
||||
/* Not Access */ -1
|
||||
};
|
||||
|
||||
static const char *cc_to_string[16] = {
|
||||
"No Error",
|
||||
"CRC: Last data packet from endpoint contained a CRC error.",
|
||||
"BITSTUFFING: Last data packet from endpoint contained a bit " \
|
||||
"stuffing violation",
|
||||
"DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
|
||||
"that did not match the expected value.",
|
||||
"STALL: TD was moved to the Done Queue because the endpoint returned" \
|
||||
" a STALL PID",
|
||||
"DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
|
||||
"not provide a handshake (OUT)",
|
||||
"PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
|
||||
"(IN) or handshake (OUT)",
|
||||
"UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
|
||||
"value is not defined.",
|
||||
"DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
|
||||
"either the size of the maximum data packet allowed\n" \
|
||||
"from the endpoint (found in MaximumPacketSize field\n" \
|
||||
"of ED) or the remaining buffer size.",
|
||||
"DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
|
||||
"and that amount was not sufficient to fill the\n" \
|
||||
"specified buffer",
|
||||
"reserved1",
|
||||
"reserved2",
|
||||
"BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
|
||||
"than it could be written to system memory",
|
||||
"BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
|
||||
"system memory fast enough to keep up with data USB " \
|
||||
"data rate.",
|
||||
"NOT ACCESSED: This code is set by software before the TD is placed" \
|
||||
"on a list to be processed by the HC.(1)",
|
||||
"NOT ACCESSED: This code is set by software before the TD is placed" \
|
||||
"on a list to be processed by the HC.(2)",
|
||||
};
|
||||
|
||||
static inline u32 roothub_a(struct ohci *hc)
|
||||
{ return ohci_readl(&hc->regs->roothub.a); }
|
||||
|
@ -124,11 +199,42 @@ static inline u32 roothub_portstatus(struct ohci *hc, int i)
|
|||
{ return ohci_readl(&hc->regs->roothub.portstatus[i]); }
|
||||
|
||||
/* forward declaration */
|
||||
static int hc_interrupt(void);
|
||||
static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len,
|
||||
static int hc_interrupt(ohci_t *ohci);
|
||||
static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
|
||||
unsigned long pipe, void *buffer, int transfer_len,
|
||||
struct devrequest *setup, urb_priv_t *urb,
|
||||
int interval);
|
||||
static int ep_link(ohci_t * ohci, ed_t * ed);
|
||||
static int ep_unlink(ohci_t * ohci, ed_t * ed);
|
||||
static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
|
||||
unsigned long pipe, int interval, int load);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* TDs ... */
|
||||
static struct td *td_alloc(ohci_dev_t *ohci_dev, struct usb_device *usb_dev)
|
||||
{
|
||||
int i;
|
||||
struct td *td;
|
||||
|
||||
td = NULL;
|
||||
for (i = 0; i < NUM_TD; i++)
|
||||
{
|
||||
if (ohci_dev->tds[i].usb_dev == NULL)
|
||||
{
|
||||
td = &ohci_dev->tds[i];
|
||||
td->usb_dev = usb_dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return td;
|
||||
}
|
||||
|
||||
static inline void ed_free(struct ed *ed)
|
||||
{
|
||||
ed->usb_dev = NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*
|
||||
* URB support functions
|
||||
|
@ -158,18 +264,18 @@ static void urb_free_priv(urb_priv_t *urb)
|
|||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef DEBUG
|
||||
static int sohci_get_current_frame_number(struct usb_device *dev);
|
||||
static int sohci_get_current_frame_number(ohci_t *ohci);
|
||||
|
||||
/* debug| print the main components of an URB
|
||||
* small: 0) header + data packets 1) just header */
|
||||
|
||||
static void pkt_print(urb_priv_t *purb, struct usb_device *dev,
|
||||
static void pkt_print(ohci_t *ohci, urb_priv_t *purb, struct usb_device *dev,
|
||||
unsigned long pipe, void *buffer, int transfer_len,
|
||||
struct devrequest *setup, char *str, int small)
|
||||
{
|
||||
dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx",
|
||||
str,
|
||||
sohci_get_current_frame_number(dev),
|
||||
sohci_get_current_frame_number(ohci),
|
||||
usb_pipedevice(pipe),
|
||||
usb_pipeendpoint(pipe),
|
||||
usb_pipeout(pipe)? 'O': 'I',
|
||||
|
@ -213,9 +319,11 @@ void ep_print_int_eds(ohci_t *ohci, char *str)
|
|||
ed_p = &(ohci->hcca->int_table [i]);
|
||||
if (*ed_p == 0)
|
||||
continue;
|
||||
invalidate_dcache_ed(ed_p);
|
||||
printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
|
||||
while (*ed_p != 0 && j--) {
|
||||
ed_t *ed = (ed_t *)m32_swap(ed_p);
|
||||
invalidate_dcache_ed(ed);
|
||||
printf(" ed: %4x;", ed->hwINFO);
|
||||
ed_p = &ed->hwNextED;
|
||||
}
|
||||
|
@ -246,6 +354,7 @@ static void maybe_print_eds(char *label, __u32 value)
|
|||
|
||||
if (value) {
|
||||
dbg("%s %08x", label, value);
|
||||
invalidate_dcache_ed(edp);
|
||||
dbg("%08x", edp->hwINFO);
|
||||
dbg("%08x", edp->hwTailP);
|
||||
dbg("%08x", edp->hwHeadP);
|
||||
|
@ -380,6 +489,7 @@ static void ohci_dump(ohci_t *controller, int verbose)
|
|||
ohci_dump_status(controller);
|
||||
if (verbose)
|
||||
ep_print_int_eds(controller, "hcca");
|
||||
invalidate_dcache_hcca(controller->hcca);
|
||||
dbg("hcca frame #%04x", controller->hcca->frame_no);
|
||||
ohci_dump_roothub(controller, 1);
|
||||
}
|
||||
|
@ -391,9 +501,9 @@ static void ohci_dump(ohci_t *controller, int verbose)
|
|||
|
||||
/* get a transfer request */
|
||||
|
||||
int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
||||
int sohci_submit_job(ohci_t *ohci, ohci_dev_t *ohci_dev, urb_priv_t *urb,
|
||||
struct devrequest *setup)
|
||||
{
|
||||
ohci_t *ohci;
|
||||
ed_t *ed;
|
||||
urb_priv_t *purb_priv = urb;
|
||||
int i, size = 0;
|
||||
|
@ -403,8 +513,6 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|||
int transfer_len = urb->transfer_buffer_length;
|
||||
int interval = urb->interval;
|
||||
|
||||
ohci = &gohci;
|
||||
|
||||
/* when controller's hung, permit only roothub cleanup attempts
|
||||
* such as powering down ports */
|
||||
if (ohci->disabled) {
|
||||
|
@ -417,7 +525,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|||
urb->finished = 0;
|
||||
|
||||
/* every endpoint has a ed, locate and fill it */
|
||||
ed = ep_add_ed(dev, pipe, interval, 1);
|
||||
ed = ep_add_ed(ohci_dev, dev, pipe, interval, 1);
|
||||
if (!ed) {
|
||||
err("sohci_submit_job: ENOMEM");
|
||||
return -1;
|
||||
|
@ -453,7 +561,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|||
/* allocate the TDs */
|
||||
/* note that td[0] was allocated in ep_add_ed */
|
||||
for (i = 0; i < size; i++) {
|
||||
purb_priv->td[i] = td_alloc(dev);
|
||||
purb_priv->td[i] = td_alloc(ohci_dev, dev);
|
||||
if (!purb_priv->td[i]) {
|
||||
purb_priv->length = i;
|
||||
urb_free_priv(purb_priv);
|
||||
|
@ -473,7 +581,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|||
ep_link(ohci, ed);
|
||||
|
||||
/* fill the TDs and link it to the ed */
|
||||
td_submit_job(dev, pipe, buffer, transfer_len,
|
||||
td_submit_job(ohci, dev, pipe, buffer, transfer_len,
|
||||
setup, purb_priv, interval);
|
||||
|
||||
return 0;
|
||||
|
@ -495,7 +603,7 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
|
|||
ohci_readl(®s->intrdisable); /* PCI posting flush */
|
||||
}
|
||||
urb->actual_length = 0;
|
||||
td_submit_job(
|
||||
td_submit_job( hc,
|
||||
urb->dev,
|
||||
urb->pipe,
|
||||
urb->transfer_buffer,
|
||||
|
@ -517,11 +625,9 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
|
|||
|
||||
#ifdef DEBUG
|
||||
/* tell us the current USB frame number */
|
||||
|
||||
static int sohci_get_current_frame_number(struct usb_device *usb_dev)
|
||||
static int sohci_get_current_frame_number(ohci_t *ohci)
|
||||
{
|
||||
ohci_t *ohci = &gohci;
|
||||
|
||||
invalidate_dcache_hcca(ohci->hcca);
|
||||
return m16_swap(ohci->hcca->frame_no);
|
||||
}
|
||||
#endif
|
||||
|
@ -600,6 +706,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|||
switch (ed->type) {
|
||||
case PIPE_CONTROL:
|
||||
ed->hwNextED = 0;
|
||||
flush_dcache_ed(ed);
|
||||
if (ohci->ed_controltail == NULL)
|
||||
ohci_writel(ed, &ohci->regs->ed_controlhead);
|
||||
else
|
||||
|
@ -617,6 +724,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|||
|
||||
case PIPE_BULK:
|
||||
ed->hwNextED = 0;
|
||||
flush_dcache_ed(ed);
|
||||
if (ohci->ed_bulktail == NULL)
|
||||
ohci_writel(ed, &ohci->regs->ed_bulkhead);
|
||||
else
|
||||
|
@ -649,7 +757,9 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|||
inter = ep_rev(6,
|
||||
((ed_t *)ed_p)->int_interval);
|
||||
ed->hwNextED = *ed_p;
|
||||
flush_dcache_ed(ed);
|
||||
*ed_p = m32_swap((unsigned long)ed);
|
||||
flush_dcache_hcca(ohci->hcca);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -662,6 +772,8 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|||
static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
|
||||
unsigned index, unsigned period)
|
||||
{
|
||||
__maybe_unused unsigned long aligned_ed_p;
|
||||
|
||||
for (; index < NUM_INTS; index += period) {
|
||||
__u32 *ed_p = &ohci->hcca->int_table [index];
|
||||
|
||||
|
@ -670,6 +782,12 @@ static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
|
|||
if (((struct ed *)
|
||||
m32_swap((unsigned long)ed_p)) == ed) {
|
||||
*ed_p = ed->hwNextED;
|
||||
#ifdef CONFIG_DM_USB
|
||||
aligned_ed_p = (unsigned long)ed_p;
|
||||
aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1);
|
||||
flush_dcache_range(aligned_ed_p,
|
||||
aligned_ed_p + ARCH_DMA_MINALIGN);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
ed_p = &(((struct ed *)
|
||||
|
@ -689,6 +807,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|||
int i;
|
||||
|
||||
ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
|
||||
flush_dcache_ed(ed);
|
||||
|
||||
switch (ed->type) {
|
||||
case PIPE_CONTROL:
|
||||
|
@ -702,6 +821,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|||
&ohci->regs->ed_controlhead);
|
||||
} else {
|
||||
ed->ed_prev->hwNextED = ed->hwNextED;
|
||||
flush_dcache_ed(ed->ed_prev);
|
||||
}
|
||||
if (ohci->ed_controltail == ed) {
|
||||
ohci->ed_controltail = ed->ed_prev;
|
||||
|
@ -722,6 +842,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|||
&ohci->regs->ed_bulkhead);
|
||||
} else {
|
||||
ed->ed_prev->hwNextED = ed->hwNextED;
|
||||
flush_dcache_ed(ed->ed_prev);
|
||||
}
|
||||
if (ohci->ed_bulktail == ed) {
|
||||
ohci->ed_bulktail = ed->ed_prev;
|
||||
|
@ -751,14 +872,14 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|||
* info fields are setted anyway even though most of them should not
|
||||
* change
|
||||
*/
|
||||
static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
|
||||
int interval, int load)
|
||||
static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
|
||||
unsigned long pipe, int interval, int load)
|
||||
{
|
||||
td_t *td;
|
||||
ed_t *ed_ret;
|
||||
volatile ed_t *ed;
|
||||
|
||||
ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) |
|
||||
ed = ed_ret = &ohci_dev->ed[(usb_pipeendpoint(pipe) << 1) |
|
||||
(usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))];
|
||||
|
||||
if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
|
||||
|
@ -769,12 +890,12 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
|
|||
|
||||
if (ed->state == ED_NEW) {
|
||||
/* dummy td; end of td list for ed */
|
||||
td = td_alloc(usb_dev);
|
||||
td = td_alloc(ohci_dev, usb_dev);
|
||||
ed->hwTailP = m32_swap((unsigned long)td);
|
||||
ed->hwHeadP = ed->hwTailP;
|
||||
ed->state = ED_UNLINK;
|
||||
ed->type = usb_pipetype(pipe);
|
||||
ohci_dev.ed_cnt++;
|
||||
ohci_dev->ed_cnt++;
|
||||
}
|
||||
|
||||
ed->hwINFO = m32_swap(usb_pipedevice(pipe)
|
||||
|
@ -790,6 +911,8 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
|
|||
ed->int_load = load;
|
||||
}
|
||||
|
||||
flush_dcache_ed(ed);
|
||||
|
||||
return ed_ret;
|
||||
}
|
||||
|
||||
|
@ -815,6 +938,7 @@ static void td_fill(ohci_t *ohci, unsigned int info,
|
|||
/* use this td as the next dummy */
|
||||
td_pt = urb_priv->td [index];
|
||||
td_pt->hwNextTD = 0;
|
||||
flush_dcache_td(td_pt);
|
||||
|
||||
/* fill the old dummy TD */
|
||||
td = urb_priv->td [index] =
|
||||
|
@ -842,27 +966,30 @@ static void td_fill(ohci_t *ohci, unsigned int info,
|
|||
td->hwBE = 0;
|
||||
|
||||
td->hwNextTD = m32_swap((unsigned long)td_pt);
|
||||
flush_dcache_td(td);
|
||||
|
||||
/* append to queue */
|
||||
td->ed->hwTailP = td->hwNextTD;
|
||||
flush_dcache_ed(td->ed);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* prepare all TDs of a transfer */
|
||||
|
||||
static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len,
|
||||
static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
|
||||
unsigned long pipe, void *buffer, int transfer_len,
|
||||
struct devrequest *setup, urb_priv_t *urb,
|
||||
int interval)
|
||||
{
|
||||
ohci_t *ohci = &gohci;
|
||||
int data_len = transfer_len;
|
||||
void *data;
|
||||
int cnt = 0;
|
||||
__u32 info = 0;
|
||||
unsigned int toggle = 0;
|
||||
|
||||
flush_dcache_buffer(buffer, data_len);
|
||||
|
||||
/* OHCI handles the DATA-toggles itself, we just use the USB-toggle
|
||||
* bits for reseting */
|
||||
if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
|
||||
|
@ -902,6 +1029,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
|||
case PIPE_CONTROL:
|
||||
/* Setup phase */
|
||||
info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
|
||||
flush_dcache_buffer(setup, 8);
|
||||
td_fill(ohci, info, setup, 8, dev, cnt++, urb);
|
||||
|
||||
/* Optional Data phase */
|
||||
|
@ -914,7 +1042,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
|||
}
|
||||
|
||||
/* Status phase */
|
||||
info = usb_pipeout(pipe)?
|
||||
info = (usb_pipeout(pipe) || data_len == 0) ?
|
||||
TD_CC | TD_DP_IN | TD_T_DATA1:
|
||||
TD_CC | TD_DP_OUT | TD_T_DATA1;
|
||||
td_fill(ohci, info, data, 0, dev, cnt++, urb);
|
||||
|
@ -973,6 +1101,7 @@ static void check_status(td_t *td_list)
|
|||
if (cc) {
|
||||
err(" USB-error: %s (%x)", cc_to_string[cc], cc);
|
||||
|
||||
invalidate_dcache_ed(td_list->ed);
|
||||
if (*phwHeadP & m32_swap(0x1)) {
|
||||
if (lurb_priv &&
|
||||
((td_list->index + 1) < urb_len)) {
|
||||
|
@ -985,9 +1114,11 @@ static void check_status(td_t *td_list)
|
|||
td_list->index - 1;
|
||||
} else
|
||||
*phwHeadP &= m32_swap(0xfffffff2);
|
||||
flush_dcache_ed(td_list->ed);
|
||||
}
|
||||
#ifdef CONFIG_MPC5200
|
||||
td_list->hwNextTD = 0;
|
||||
flush_dcache_td(td_list);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -1000,11 +1131,14 @@ static td_t *dl_reverse_done_list(ohci_t *ohci)
|
|||
td_t *td_rev = NULL;
|
||||
td_t *td_list = NULL;
|
||||
|
||||
invalidate_dcache_hcca(ohci->hcca);
|
||||
td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
|
||||
ohci->hcca->done_head = 0;
|
||||
flush_dcache_hcca(ohci->hcca);
|
||||
|
||||
while (td_list_hc) {
|
||||
td_list = (td_t *)td_list_hc;
|
||||
invalidate_dcache_td(td_list);
|
||||
check_status(td_list);
|
||||
td_list->next_dl_td = td_rev;
|
||||
td_rev = td_list;
|
||||
|
@ -1039,6 +1173,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list)
|
|||
urb_priv_t *lurb_priv;
|
||||
__u32 tdINFO, edHeadP, edTailP;
|
||||
|
||||
invalidate_dcache_td(td_list);
|
||||
tdINFO = m32_swap(td_list->hwINFO);
|
||||
|
||||
ed = td_list->ed;
|
||||
|
@ -1064,6 +1199,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list)
|
|||
lurb_priv->td_cnt, lurb_priv->length);
|
||||
|
||||
if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
|
||||
invalidate_dcache_ed(ed);
|
||||
edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
|
||||
edTailP = m32_swap(ed->hwTailP);
|
||||
|
||||
|
@ -1100,16 +1236,16 @@ static int dl_done_list(ohci_t *ohci)
|
|||
#define OK(x) len = (x); break
|
||||
#ifdef DEBUG
|
||||
#define WR_RH_STAT(x) {info("WR:status %#8x", (x)); ohci_writel((x), \
|
||||
&gohci.regs->roothub.status); }
|
||||
&ohci->regs->roothub.status); }
|
||||
#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, \
|
||||
(x)); ohci_writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); }
|
||||
(x)); ohci_writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); }
|
||||
#else
|
||||
#define WR_RH_STAT(x) ohci_writel((x), &gohci.regs->roothub.status)
|
||||
#define WR_RH_STAT(x) ohci_writel((x), &ohci->regs->roothub.status)
|
||||
#define WR_RH_PORTSTAT(x) ohci_writel((x), \
|
||||
&gohci.regs->roothub.portstatus[wIndex-1])
|
||||
&ohci->regs->roothub.portstatus[wIndex-1])
|
||||
#endif
|
||||
#define RD_RH_STAT roothub_status(&gohci)
|
||||
#define RD_RH_PORTSTAT roothub_portstatus(&gohci, wIndex-1)
|
||||
#define RD_RH_STAT roothub_status(ohci)
|
||||
#define RD_RH_PORTSTAT roothub_portstatus(ohci, wIndex-1)
|
||||
|
||||
/* request to virtual root hub */
|
||||
|
||||
|
@ -1137,8 +1273,9 @@ int rh_check_port_status(ohci_t *controller)
|
|||
return res;
|
||||
}
|
||||
|
||||
static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len, struct devrequest *cmd)
|
||||
static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev,
|
||||
unsigned long pipe, void *buffer, int transfer_len,
|
||||
struct devrequest *cmd)
|
||||
{
|
||||
void *data = buffer;
|
||||
int leni = transfer_len;
|
||||
|
@ -1151,7 +1288,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
|||
ALLOC_ALIGN_BUFFER(__u8, databuf, 16, sizeof(u32));
|
||||
|
||||
#ifdef DEBUG
|
||||
pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
||||
pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
|
||||
cmd, "SUB(rh)", usb_pipein(pipe));
|
||||
#else
|
||||
mdelay(1);
|
||||
|
@ -1245,7 +1382,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|||
break;
|
||||
|
||||
case RH_SET_ADDRESS:
|
||||
gohci.rh.devnum = wValue;
|
||||
ohci->rh.devnum = wValue;
|
||||
OK(0);
|
||||
|
||||
case RH_GET_DESCRIPTOR:
|
||||
|
@ -1290,7 +1427,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|||
|
||||
case RH_GET_DESCRIPTOR | RH_CLASS:
|
||||
{
|
||||
__u32 temp = roothub_a(&gohci);
|
||||
__u32 temp = roothub_a(ohci);
|
||||
|
||||
databuf[0] = 9; /* min length; */
|
||||
databuf[1] = 0x29;
|
||||
|
@ -1309,7 +1446,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|||
databuf[4] = 0;
|
||||
databuf[5] = (temp & RH_A_POTPGT) >> 24;
|
||||
databuf[6] = 0;
|
||||
temp = roothub_b(&gohci);
|
||||
temp = roothub_b(ohci);
|
||||
databuf[7] = temp & RH_B_DR;
|
||||
if (databuf[2] < 7) {
|
||||
databuf[8] = 0xff;
|
||||
|
@ -1338,7 +1475,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
ohci_dump_roothub(&gohci, 1);
|
||||
ohci_dump_roothub(ohci, 1);
|
||||
#else
|
||||
mdelay(1);
|
||||
#endif
|
||||
|
@ -1350,7 +1487,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|||
dev->status = stat;
|
||||
|
||||
#ifdef DEBUG
|
||||
pkt_print(NULL, dev, pipe, buffer,
|
||||
pkt_print(ohci, NULL, dev, pipe, buffer,
|
||||
transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
|
||||
#else
|
||||
mdelay(1);
|
||||
|
@ -1363,8 +1500,9 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|||
|
||||
/* common code for handling submit messages - used for all but root hub */
|
||||
/* accesses. */
|
||||
int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int transfer_len, struct devrequest *setup, int interval)
|
||||
static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
|
||||
unsigned long pipe, void *buffer, int transfer_len,
|
||||
struct devrequest *setup, int interval)
|
||||
{
|
||||
int stat = 0;
|
||||
int maxsize = usb_maxpacket(dev, pipe);
|
||||
|
@ -1380,15 +1518,9 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
urb->transfer_buffer_length = transfer_len;
|
||||
urb->interval = interval;
|
||||
|
||||
/* device pulled? Shortcut the action. */
|
||||
if (devgone == dev) {
|
||||
dev->status = USB_ST_CRC_ERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
urb->actual_length = 0;
|
||||
pkt_print(urb, dev, pipe, buffer, transfer_len,
|
||||
pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
|
||||
setup, "SUB", usb_pipein(pipe));
|
||||
#else
|
||||
mdelay(1);
|
||||
|
@ -1399,14 +1531,14 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (sohci_submit_job(urb, setup) < 0) {
|
||||
if (sohci_submit_job(ohci, &ohci->ohci_dev, urb, setup) < 0) {
|
||||
err("sohci_submit_job failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
mdelay(10);
|
||||
/* ohci_dump_status(&gohci); */
|
||||
/* ohci_dump_status(ohci); */
|
||||
#endif
|
||||
|
||||
timeout = USB_TIMEOUT_MS(pipe);
|
||||
|
@ -1414,7 +1546,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
/* wait for it to complete */
|
||||
for (;;) {
|
||||
/* check whether the controller is done */
|
||||
stat = hc_interrupt();
|
||||
stat = hc_interrupt(ohci);
|
||||
if (stat < 0) {
|
||||
stat = USB_ST_CRC_ERR;
|
||||
break;
|
||||
|
@ -1440,7 +1572,8 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
dbg("*");
|
||||
|
||||
} else {
|
||||
err("CTL:TIMEOUT ");
|
||||
if (!usb_pipeint(pipe))
|
||||
err("CTL:TIMEOUT ");
|
||||
dbg("submit_common_msg: TO status %x\n", stat);
|
||||
urb->finished = 1;
|
||||
stat = USB_ST_CRC_ERR;
|
||||
|
@ -1451,8 +1584,11 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
dev->status = stat;
|
||||
dev->act_len = urb->actual_length;
|
||||
|
||||
if (usb_pipein(pipe) && dev->status == 0 && dev->act_len)
|
||||
invalidate_dcache_buffer(buffer, dev->act_len);
|
||||
|
||||
#ifdef DEBUG
|
||||
pkt_print(urb, dev, pipe, buffer, transfer_len,
|
||||
pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
|
||||
setup, "RET(ctlr)", usb_pipein(pipe));
|
||||
#else
|
||||
mdelay(1);
|
||||
|
@ -1469,17 +1605,27 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
int transfer_len)
|
||||
{
|
||||
info("submit_bulk_msg");
|
||||
return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
|
||||
return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int transfer_len, struct devrequest *setup)
|
||||
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int transfer_len, int interval)
|
||||
{
|
||||
info("submit_int_msg");
|
||||
return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, NULL,
|
||||
interval);
|
||||
}
|
||||
|
||||
static int _ohci_submit_control_msg(ohci_t *ohci, struct usb_device *dev,
|
||||
unsigned long pipe, void *buffer, int transfer_len,
|
||||
struct devrequest *setup)
|
||||
{
|
||||
int maxsize = usb_maxpacket(dev, pipe);
|
||||
|
||||
info("submit_control_msg");
|
||||
#ifdef DEBUG
|
||||
pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
||||
pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
|
||||
setup, "SUB", usb_pipein(pipe));
|
||||
#else
|
||||
mdelay(1);
|
||||
|
@ -1489,22 +1635,15 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
pipe);
|
||||
return -1;
|
||||
}
|
||||
if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
|
||||
gohci.rh.dev = dev;
|
||||
if (((pipe >> 8) & 0x7f) == ohci->rh.devnum) {
|
||||
ohci->rh.dev = dev;
|
||||
/* root hub - redirect */
|
||||
return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
|
||||
setup);
|
||||
return ohci_submit_rh_msg(ohci, dev, pipe, buffer,
|
||||
transfer_len, setup);
|
||||
}
|
||||
|
||||
return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
|
||||
}
|
||||
|
||||
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int transfer_len, int interval)
|
||||
{
|
||||
info("submit_int_msg");
|
||||
return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
|
||||
interval);
|
||||
return submit_common_msg(ohci, dev, pipe, buffer, transfer_len,
|
||||
setup, 0);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*
|
||||
|
@ -1648,13 +1787,14 @@ static int hc_start(ohci_t *ohci)
|
|||
|
||||
/* an interrupt happens */
|
||||
|
||||
static int hc_interrupt(void)
|
||||
static int hc_interrupt(ohci_t *ohci)
|
||||
{
|
||||
ohci_t *ohci = &gohci;
|
||||
struct ohci_regs *regs = ohci->regs;
|
||||
int ints;
|
||||
int stat = -1;
|
||||
|
||||
invalidate_dcache_hcca(ohci->hcca);
|
||||
|
||||
if ((ohci->hcca->done_head != 0) &&
|
||||
!(m32_swap(ohci->hcca->done_head) & 0x01)) {
|
||||
ints = OHCI_INTR_WDH;
|
||||
|
@ -1702,7 +1842,7 @@ static int hc_interrupt(void)
|
|||
mdelay(1);
|
||||
ohci_writel(OHCI_INTR_WDH, ®s->intrdisable);
|
||||
(void)ohci_readl(®s->intrdisable); /* flush */
|
||||
stat = dl_done_list(&gohci);
|
||||
stat = dl_done_list(ohci);
|
||||
ohci_writel(OHCI_INTR_WDH, ®s->intrenable);
|
||||
(void)ohci_readl(®s->intrdisable); /* flush */
|
||||
}
|
||||
|
@ -1772,21 +1912,9 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
|
|||
err("HCCA not aligned!!");
|
||||
return -1;
|
||||
}
|
||||
phcca = &ghcca[0];
|
||||
info("aligned ghcca %p", phcca);
|
||||
memset(&ohci_dev, 0, sizeof(struct ohci_device));
|
||||
if ((__u32)&ohci_dev.ed[0] & 0x7) {
|
||||
err("EDs not aligned!!");
|
||||
return -1;
|
||||
}
|
||||
memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
|
||||
if ((__u32)gtd & 0x7) {
|
||||
err("TDs not aligned!!");
|
||||
return -1;
|
||||
}
|
||||
ptd = gtd;
|
||||
gohci.hcca = phcca;
|
||||
memset(phcca, 0, sizeof(struct ohci_hcca));
|
||||
gohci.hcca = &ghcca[0];
|
||||
info("aligned ghcca %p", gohci.hcca);
|
||||
memset(gohci.hcca, 0, sizeof(struct ohci_hcca));
|
||||
|
||||
gohci.disabled = 1;
|
||||
gohci.sleeping = 0;
|
||||
|
@ -1880,3 +2008,10 @@ int usb_lowlevel_stop(int index)
|
|||
ohci_inited = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int transfer_len, struct devrequest *setup)
|
||||
{
|
||||
return _ohci_submit_control_msg(&gohci, dev, pipe, buffer,
|
||||
transfer_len, setup);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,18 @@
|
|||
# define ohci_writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
|
||||
#endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */
|
||||
|
||||
#if defined CONFIG_DM_USB && ARCH_DMA_MINALIGN > 16
|
||||
#define ED_ALIGNMENT ARCH_DMA_MINALIGN
|
||||
#else
|
||||
#define ED_ALIGNMENT 16
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_DM_USB && ARCH_DMA_MINALIGN > 32
|
||||
#define TD_ALIGNMENT ARCH_DMA_MINALIGN
|
||||
#else
|
||||
#define TD_ALIGNMENT 32
|
||||
#endif
|
||||
|
||||
/* functions for doing board or CPU specific setup/cleanup */
|
||||
int usb_board_stop(void);
|
||||
|
||||
|
@ -25,64 +37,7 @@ int usb_cpu_init(void);
|
|||
int usb_cpu_stop(void);
|
||||
int usb_cpu_init_fail(void);
|
||||
|
||||
static int cc_to_error[16] = {
|
||||
|
||||
/* mapping of the OHCI CC status to error codes */
|
||||
/* No Error */ 0,
|
||||
/* CRC Error */ USB_ST_CRC_ERR,
|
||||
/* Bit Stuff */ USB_ST_BIT_ERR,
|
||||
/* Data Togg */ USB_ST_CRC_ERR,
|
||||
/* Stall */ USB_ST_STALLED,
|
||||
/* DevNotResp */ -1,
|
||||
/* PIDCheck */ USB_ST_BIT_ERR,
|
||||
/* UnExpPID */ USB_ST_BIT_ERR,
|
||||
/* DataOver */ USB_ST_BUF_ERR,
|
||||
/* DataUnder */ USB_ST_BUF_ERR,
|
||||
/* reservd */ -1,
|
||||
/* reservd */ -1,
|
||||
/* BufferOver */ USB_ST_BUF_ERR,
|
||||
/* BuffUnder */ USB_ST_BUF_ERR,
|
||||
/* Not Access */ -1,
|
||||
/* Not Access */ -1
|
||||
};
|
||||
|
||||
static const char *cc_to_string[16] = {
|
||||
"No Error",
|
||||
"CRC: Last data packet from endpoint contained a CRC error.",
|
||||
"BITSTUFFING: Last data packet from endpoint contained a bit " \
|
||||
"stuffing violation",
|
||||
"DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
|
||||
"that did not match the expected value.",
|
||||
"STALL: TD was moved to the Done Queue because the endpoint returned" \
|
||||
" a STALL PID",
|
||||
"DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
|
||||
"not provide a handshake (OUT)",
|
||||
"PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
|
||||
"(IN) or handshake (OUT)",
|
||||
"UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
|
||||
"value is not defined.",
|
||||
"DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
|
||||
"either the size of the maximum data packet allowed\n" \
|
||||
"from the endpoint (found in MaximumPacketSize field\n" \
|
||||
"of ED) or the remaining buffer size.",
|
||||
"DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
|
||||
"and that amount was not sufficient to fill the\n" \
|
||||
"specified buffer",
|
||||
"reserved1",
|
||||
"reserved2",
|
||||
"BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
|
||||
"than it could be written to system memory",
|
||||
"BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
|
||||
"system memory fast enough to keep up with data USB " \
|
||||
"data rate.",
|
||||
"NOT ACCESSED: This code is set by software before the TD is placed" \
|
||||
"on a list to be processed by the HC.(1)",
|
||||
"NOT ACCESSED: This code is set by software before the TD is placed" \
|
||||
"on a list to be processed by the HC.(2)",
|
||||
};
|
||||
|
||||
/* ED States */
|
||||
|
||||
#define ED_NEW 0x00
|
||||
#define ED_UNLINK 0x01
|
||||
#define ED_OPER 0x02
|
||||
|
@ -109,7 +64,7 @@ struct ed {
|
|||
struct usb_device *usb_dev;
|
||||
void *purb;
|
||||
__u32 unused[2];
|
||||
} __attribute__((aligned(16)));
|
||||
} __attribute__((aligned(ED_ALIGNMENT)));
|
||||
typedef struct ed ed_t;
|
||||
|
||||
|
||||
|
@ -169,7 +124,7 @@ struct td {
|
|||
__u32 data;
|
||||
|
||||
__u32 unused2[2];
|
||||
} __attribute__((aligned(32)));
|
||||
} __attribute__((aligned(TD_ALIGNMENT)));
|
||||
typedef struct td td_t;
|
||||
|
||||
#define OHCI_ED_SKIP (1 << 14)
|
||||
|
@ -408,6 +363,16 @@ typedef struct
|
|||
} urb_priv_t;
|
||||
#define URB_DEL 1
|
||||
|
||||
#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
|
||||
|
||||
#define NUM_TD 64 /* we need more TDs than EDs */
|
||||
|
||||
typedef struct ohci_device {
|
||||
ed_t ed[NUM_EDS] __aligned(ED_ALIGNMENT);
|
||||
td_t tds[NUM_TD] __aligned(TD_ALIGNMENT);
|
||||
int ed_cnt;
|
||||
} ohci_dev_t;
|
||||
|
||||
/*
|
||||
* This is the full ohci controller description
|
||||
*
|
||||
|
@ -417,6 +382,8 @@ typedef struct
|
|||
|
||||
|
||||
typedef struct ohci {
|
||||
/* this allocates EDs for all possible endpoints */
|
||||
struct ohci_device ohci_dev __aligned(TD_ALIGNMENT);
|
||||
struct ohci_hcca *hcca; /* hcca */
|
||||
/*dma_addr_t hcca_dma;*/
|
||||
|
||||
|
@ -438,54 +405,3 @@ typedef struct ohci {
|
|||
|
||||
const char *slot_name;
|
||||
} ohci_t;
|
||||
|
||||
#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
|
||||
|
||||
struct ohci_device {
|
||||
ed_t ed[NUM_EDS];
|
||||
int ed_cnt;
|
||||
};
|
||||
|
||||
/* hcd */
|
||||
/* endpoint */
|
||||
static int ep_link(ohci_t * ohci, ed_t * ed);
|
||||
static int ep_unlink(ohci_t * ohci, ed_t * ed);
|
||||
static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
|
||||
int interval, int load);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* we need more TDs than EDs */
|
||||
#define NUM_TD 64
|
||||
|
||||
/* +1 so we can align the storage */
|
||||
td_t gtd[NUM_TD+1];
|
||||
/* pointers to aligned storage */
|
||||
td_t *ptd;
|
||||
|
||||
/* TDs ... */
|
||||
static inline struct td *
|
||||
td_alloc (struct usb_device *usb_dev)
|
||||
{
|
||||
int i;
|
||||
struct td *td;
|
||||
|
||||
td = NULL;
|
||||
for (i = 0; i < NUM_TD; i++)
|
||||
{
|
||||
if (ptd[i].usb_dev == NULL)
|
||||
{
|
||||
td = &ptd[i];
|
||||
td->usb_dev = usb_dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return td;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ed_free (struct ed *ed)
|
||||
{
|
||||
ed->usb_dev = NULL;
|
||||
}
|
||||
|
|
|
@ -145,9 +145,8 @@ int usb_init(void)
|
|||
|
||||
uclass_foreach_dev(bus, uc) {
|
||||
/* init low_level USB */
|
||||
printf("USB%d: ", count);
|
||||
count++;
|
||||
printf("USB");
|
||||
printf("%d: ", bus->seq);
|
||||
ret = device_probe(bus);
|
||||
if (ret == -ENODEV) { /* No such device. */
|
||||
puts("Port not available.\n");
|
||||
|
@ -477,9 +476,7 @@ int usb_scan_device(struct udevice *parent, int port,
|
|||
|
||||
*devp = NULL;
|
||||
memset(udev, '\0', sizeof(*udev));
|
||||
ret = usb_get_bus(parent, &udev->controller_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
udev->controller_dev = usb_get_bus(parent);
|
||||
priv = dev_get_uclass_priv(udev->controller_dev);
|
||||
|
||||
/*
|
||||
|
@ -536,11 +533,7 @@ int usb_scan_device(struct udevice *parent, int port,
|
|||
plat = dev_get_parent_platdata(dev);
|
||||
debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat);
|
||||
plat->devnum = udev->devnum;
|
||||
plat->speed = udev->speed;
|
||||
plat->slot_id = udev->slot_id;
|
||||
plat->portnr = port;
|
||||
debug("** device '%s': stashing slot_id=%d\n", dev->name,
|
||||
plat->slot_id);
|
||||
plat->udev = udev;
|
||||
priv->next_addr++;
|
||||
ret = device_probe(dev);
|
||||
if (ret) {
|
||||
|
@ -579,45 +572,55 @@ int usb_child_post_bind(struct udevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int usb_get_bus(struct udevice *dev, struct udevice **busp)
|
||||
struct udevice *usb_get_bus(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus;
|
||||
|
||||
*busp = NULL;
|
||||
for (bus = dev; bus && device_get_uclass_id(bus) != UCLASS_USB; )
|
||||
bus = bus->parent;
|
||||
if (!bus) {
|
||||
/* By design this cannot happen */
|
||||
assert(bus);
|
||||
debug("USB HUB '%s' does not have a controller\n", dev->name);
|
||||
return -EXDEV;
|
||||
}
|
||||
*busp = bus;
|
||||
|
||||
return 0;
|
||||
return bus;
|
||||
}
|
||||
|
||||
int usb_child_pre_probe(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus;
|
||||
struct usb_device *udev = dev_get_parentdata(dev);
|
||||
struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = usb_get_bus(dev, &bus);
|
||||
if (ret)
|
||||
return ret;
|
||||
udev->controller_dev = bus;
|
||||
udev->dev = dev;
|
||||
udev->devnum = plat->devnum;
|
||||
udev->slot_id = plat->slot_id;
|
||||
udev->portnr = plat->portnr;
|
||||
udev->speed = plat->speed;
|
||||
debug("** device '%s': getting slot_id=%d\n", dev->name, plat->slot_id);
|
||||
if (plat->udev) {
|
||||
/*
|
||||
* Copy over all the values set in the on stack struct
|
||||
* usb_device in usb_scan_device() to our final struct
|
||||
* usb_device for this dev.
|
||||
*/
|
||||
*udev = *(plat->udev);
|
||||
/* And clear plat->udev as it will not be valid for long */
|
||||
plat->udev = NULL;
|
||||
udev->dev = dev;
|
||||
} else {
|
||||
/*
|
||||
* This happens with devices which are explicitly bound
|
||||
* instead of being discovered through usb_scan_device()
|
||||
* such as sandbox emul devices.
|
||||
*/
|
||||
udev->dev = dev;
|
||||
udev->controller_dev = usb_get_bus(dev);
|
||||
udev->devnum = plat->devnum;
|
||||
|
||||
ret = usb_select_config(udev);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* udev did not go through usb_scan_device(), so we need to
|
||||
* select the config and read the config descriptors.
|
||||
*/
|
||||
ret = usb_select_config(udev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,36 +33,24 @@
|
|||
/* Declare global data pointer */
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
struct exynos_xhci_platdata {
|
||||
fdt_addr_t hcd_base;
|
||||
fdt_addr_t phy_base;
|
||||
struct gpio_desc vbus_gpio;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Contains pointers to register base addresses
|
||||
* for the usb controller.
|
||||
*/
|
||||
struct exynos_xhci {
|
||||
#ifdef CONFIG_DM_USB
|
||||
struct usb_platdata usb_plat;
|
||||
#endif
|
||||
struct xhci_ctrl ctrl;
|
||||
struct exynos_usb3_phy *usb3_phy;
|
||||
struct xhci_hccr *hcd;
|
||||
struct dwc3 *dwc3_reg;
|
||||
#ifndef CONFIG_DM_USB
|
||||
struct gpio_desc vbus_gpio;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
static struct exynos_xhci exynos;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
|
||||
|
@ -102,54 +90,6 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
|
||||
{
|
||||
fdt_addr_t addr;
|
||||
unsigned int node;
|
||||
int depth;
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI);
|
||||
if (node <= 0) {
|
||||
debug("XHCI: Can't get device node for xhci\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the base address for XHCI controller from the device node
|
||||
*/
|
||||
addr = fdtdec_get_addr(blob, node, "reg");
|
||||
if (addr == FDT_ADDR_T_NONE) {
|
||||
debug("Can't get the XHCI register base address\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
exynos->hcd = (struct xhci_hccr *)addr;
|
||||
|
||||
/* Vbus gpio */
|
||||
gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
|
||||
&exynos->vbus_gpio, GPIOD_IS_OUT);
|
||||
|
||||
depth = 0;
|
||||
node = fdtdec_next_compatible_subnode(blob, node,
|
||||
COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth);
|
||||
if (node <= 0) {
|
||||
debug("XHCI: Can't get device node for usb3-phy controller\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the base address for usbphy from the device node
|
||||
*/
|
||||
exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
|
||||
"reg");
|
||||
if (exynos->usb3_phy == NULL) {
|
||||
debug("Can't get the usbphy register address\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
|
||||
{
|
||||
|
@ -340,53 +280,6 @@ static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
|
|||
exynos5_usb3_phy_exit(exynos->usb3_phy);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
|
||||
{
|
||||
struct exynos_xhci *ctx = &exynos;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
exynos_usb3_parse_dt(gd->fdt_blob, ctx);
|
||||
#else
|
||||
ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy();
|
||||
ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci();
|
||||
#endif
|
||||
|
||||
ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
/* setup the Vbus gpio here */
|
||||
if (dm_gpio_is_valid(&ctx->vbus_gpio))
|
||||
dm_gpio_set_value(&ctx->vbus_gpio, 1);
|
||||
#endif
|
||||
|
||||
ret = exynos_xhci_core_init(ctx);
|
||||
if (ret) {
|
||||
puts("XHCI: failed to initialize controller\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*hccr = (ctx->hcd);
|
||||
*hcor = (struct xhci_hcor *)((uint32_t) *hccr
|
||||
+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
|
||||
|
||||
debug("Exynos5-xhci: init hccr %x and hcor %x hc_length %d\n",
|
||||
(uint32_t)*hccr, (uint32_t)*hcor,
|
||||
(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xhci_hcd_stop(int index)
|
||||
{
|
||||
struct exynos_xhci *ctx = &exynos;
|
||||
|
||||
exynos_xhci_core_exit(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
static int xhci_usb_probe(struct udevice *dev)
|
||||
{
|
||||
struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
|
||||
|
@ -443,4 +336,3 @@ U_BOOT_DRIVER(usb_xhci) = {
|
|||
.priv_auto_alloc_size = sizeof(struct exynos_xhci),
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -10,14 +10,12 @@
|
|||
#ifndef _BCD_H
|
||||
#define _BCD_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
static inline unsigned int bcd2bin(u8 val)
|
||||
static inline unsigned int bcd2bin(unsigned int val)
|
||||
{
|
||||
return ((val) & 0x0f) + ((val) >> 4) * 10;
|
||||
return ((val) & 0x0f) + ((val & 0xff) >> 4) * 10;
|
||||
}
|
||||
|
||||
static inline u8 bin2bcd (unsigned int val)
|
||||
static inline unsigned int bin2bcd(unsigned int val)
|
||||
{
|
||||
return (((val / 10) << 4) | (val % 10));
|
||||
}
|
||||
|
|
|
@ -125,6 +125,8 @@
|
|||
func(HOST, host, 1) \
|
||||
func(HOST, host, 0)
|
||||
|
||||
#define CONFIG_BOOTCOMMAND ""
|
||||
|
||||
#include <config_distro_bootcmd.h>
|
||||
|
||||
#define CONFIG_KEEP_SERVERADDR
|
||||
|
@ -207,5 +209,6 @@
|
|||
|
||||
#define CONFIG_CMD_LZMADEC
|
||||
#define CONFIG_CMD_USB
|
||||
#define CONFIG_CMD_DATE
|
||||
|
||||
#endif
|
||||
|
|
|
@ -46,6 +46,7 @@ enum uclass_id {
|
|||
UCLASS_USB_DEV_GENERIC, /* USB generic device */
|
||||
UCLASS_MASS_STORAGE, /* Mass storage device */
|
||||
UCLASS_CPU, /* CPU, typically part of an SoC */
|
||||
UCLASS_RTC, /* Real time clock device */
|
||||
|
||||
UCLASS_COUNT,
|
||||
UCLASS_INVALID = -1,
|
||||
|
|
|
@ -145,8 +145,6 @@ enum fdt_compat_id {
|
|||
COMPAT_SAMSUNG_EXYNOS5_SOUND, /* Exynos Sound */
|
||||
COMPAT_WOLFSON_WM8994_CODEC, /* Wolfson WM8994 Sound Codec */
|
||||
COMPAT_GOOGLE_CROS_EC_KEYB, /* Google CROS_EC Keyboard */
|
||||
COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */
|
||||
COMPAT_SAMSUNG_EXYNOS5_XHCI, /* Exynos5 XHCI controller */
|
||||
COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */
|
||||
COMPAT_SAMSUNG_EXYNOS5_USB3_PHY,/* Exynos phy controller for usb3.0 */
|
||||
COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */
|
||||
|
|
|
@ -54,6 +54,7 @@ struct dm_i2c_chip {
|
|||
uint flags;
|
||||
#ifdef CONFIG_SANDBOX
|
||||
struct udevice *emul;
|
||||
bool test_mode;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -123,6 +124,27 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
|
|||
int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
|
||||
struct udevice **devp);
|
||||
|
||||
/**
|
||||
* dm_i2c_reg_read() - Read a value from an I2C register
|
||||
*
|
||||
* This reads a single value from the given address in an I2C chip
|
||||
*
|
||||
* @addr: Address to read from
|
||||
* @return value read, or -ve on error
|
||||
*/
|
||||
int dm_i2c_reg_read(struct udevice *dev, uint offset);
|
||||
|
||||
/**
|
||||
* dm_i2c_reg_write() - Write a value to an I2C register
|
||||
*
|
||||
* This writes a single value to the given address in an I2C chip
|
||||
*
|
||||
* @addr: Address to write to
|
||||
* @val: Value to write (normally a byte)
|
||||
* @return 0 on success, -ve on error
|
||||
*/
|
||||
int dm_i2c_reg_write(struct udevice *dev, uint offset, unsigned int val);
|
||||
|
||||
/**
|
||||
* dm_i2c_set_bus_speed() - set the speed of a bus
|
||||
*
|
||||
|
|
11
include/os.h
11
include/os.h
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct rtc_time;
|
||||
struct sandbox_state;
|
||||
|
||||
/**
|
||||
|
@ -277,4 +278,14 @@ int os_read_ram_buf(const char *fname);
|
|||
*/
|
||||
int os_jump_to_image(const void *dest, int size);
|
||||
|
||||
/**
|
||||
* Read the current system time
|
||||
*
|
||||
* This reads the current Local Time and places it into the provided
|
||||
* structure.
|
||||
*
|
||||
* @param rt Place to put system time
|
||||
*/
|
||||
void os_localtime(struct rtc_time *rt);
|
||||
|
||||
#endif
|
||||
|
|
195
include/rtc.h
195
include/rtc.h
|
@ -15,41 +15,143 @@
|
|||
* it there instead of in evey single driver */
|
||||
|
||||
#include <bcd.h>
|
||||
#include <rtc_def.h>
|
||||
|
||||
/*
|
||||
* The struct used to pass data from the generic interface code to
|
||||
* the hardware dependend low-level code ande vice versa. Identical
|
||||
* to struct rtc_time used by the Linux kernel.
|
||||
*
|
||||
* Note that there are small but significant differences to the
|
||||
* common "struct time":
|
||||
*
|
||||
* struct time: struct rtc_time:
|
||||
* tm_mon 0 ... 11 1 ... 12
|
||||
* tm_year years since 1900 years since 0
|
||||
*/
|
||||
#ifdef CONFIG_DM_RTC
|
||||
|
||||
struct rtc_time {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
struct rtc_ops {
|
||||
/**
|
||||
* get() - get the current time
|
||||
*
|
||||
* Returns the current time read from the RTC device. The driver
|
||||
* is responsible for setting up every field in the structure.
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @time: Place to put the time that is read
|
||||
*/
|
||||
int (*get)(struct udevice *dev, struct rtc_time *time);
|
||||
|
||||
/**
|
||||
* set() - set the current time
|
||||
*
|
||||
* Sets the time in the RTC device. The driver can expect every
|
||||
* field to be set correctly.
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @time: Time to write
|
||||
*/
|
||||
int (*set)(struct udevice *dev, const struct rtc_time *time);
|
||||
|
||||
/**
|
||||
* reset() - reset the RTC to a known-good state
|
||||
*
|
||||
* This function resets the RTC to a known-good state. The time may
|
||||
* be unset by this method, so should be set after this method is
|
||||
* called.
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*reset)(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* read8() - Read an 8-bit register
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @reg: Register to read
|
||||
* @return value read, or -ve on error
|
||||
*/
|
||||
int (*read8)(struct udevice *dev, unsigned int reg);
|
||||
|
||||
/**
|
||||
* write8() - Write an 8-bit register
|
||||
*
|
||||
* @dev: Device to write to
|
||||
* @reg: Register to write
|
||||
* @value: Value to write
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*write8)(struct udevice *dev, unsigned int reg, int val);
|
||||
};
|
||||
|
||||
/* Access the operations for an RTC device */
|
||||
#define rtc_get_ops(dev) ((struct rtc_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* dm_rtc_get() - Read the time from an RTC
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @time: Place to put the current time
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dm_rtc_get(struct udevice *dev, struct rtc_time *time);
|
||||
|
||||
/**
|
||||
* dm_rtc_put() - Write a time to an RTC
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @time: Time to write into the RTC
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dm_rtc_set(struct udevice *dev, struct rtc_time *time);
|
||||
|
||||
/**
|
||||
* dm_rtc_reset() - reset the RTC to a known-good state
|
||||
*
|
||||
* If the RTC appears to be broken (e.g. it is not counting up in seconds)
|
||||
* it may need to be reset to a known good state. This function achieves this.
|
||||
* After resetting the RTC the time should then be set to a known value by
|
||||
* the caller.
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dm_rtc_reset(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* rtc_read8() - Read an 8-bit register
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @reg: Register to read
|
||||
* @return value read, or -ve on error
|
||||
*/
|
||||
int rtc_read8(struct udevice *dev, unsigned int reg);
|
||||
|
||||
/**
|
||||
* rtc_write8() - Write an 8-bit register
|
||||
*
|
||||
* @dev: Device to write to
|
||||
* @reg: Register to write
|
||||
* @value: Value to write
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int rtc_write8(struct udevice *dev, unsigned int reg, int val);
|
||||
|
||||
/**
|
||||
* rtc_read32() - Read a 32-bit value from the RTC
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @reg: Offset to start reading from
|
||||
* @valuep: Place to put the value that is read
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep);
|
||||
|
||||
/**
|
||||
* rtc_write32() - Write a 32-bit value to the RTC
|
||||
*
|
||||
* @dev: Device to write to
|
||||
* @reg: Register to start writing to
|
||||
* @value: Value to write
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int rtc_write32(struct udevice *dev, unsigned int reg, u32 value);
|
||||
|
||||
#else
|
||||
int rtc_get (struct rtc_time *);
|
||||
int rtc_set (struct rtc_time *);
|
||||
void rtc_reset (void);
|
||||
|
||||
void GregorianDay (struct rtc_time *);
|
||||
void to_tm (int, struct rtc_time *);
|
||||
unsigned long mktime (unsigned int, unsigned int, unsigned int,
|
||||
unsigned int, unsigned int, unsigned int);
|
||||
|
||||
/**
|
||||
* rtc_read8() - Read an 8-bit register
|
||||
*
|
||||
|
@ -86,5 +188,44 @@ void rtc_write32(int reg, u32 value);
|
|||
* rtc_init() - Set up the real time clock ready for use
|
||||
*/
|
||||
void rtc_init(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* rtc_calc_weekday() - Work out the weekday from a time
|
||||
*
|
||||
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK).
|
||||
* It sets time->tm_wdaay to the correct day of the week.
|
||||
*
|
||||
* @time: Time to inspect. tm_wday is updated
|
||||
* @return 0 if OK, -EINVAL if the weekday could not be determined
|
||||
*/
|
||||
int rtc_calc_weekday(struct rtc_time *time);
|
||||
|
||||
/**
|
||||
* rtc_to_tm() - Convert a time_t value into a broken-out time
|
||||
*
|
||||
* The following fields are set up by this function:
|
||||
* tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday
|
||||
*
|
||||
* Note that tm_yday and tm_isdst are set to 0.
|
||||
*
|
||||
* @time_t: Number of seconds since 1970-01-01 00:00:00
|
||||
* @time: Place to put the broken-out time
|
||||
* @return 0 if OK, -EINVAL if the weekday could not be determined
|
||||
*/
|
||||
int rtc_to_tm(int time_t, struct rtc_time *time);
|
||||
|
||||
/**
|
||||
* rtc_mktime() - Convert a broken-out time into a time_t value
|
||||
*
|
||||
* The following fields need to be valid for this function to work:
|
||||
* tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year
|
||||
*
|
||||
* Note that tm_wday and tm_yday are ignored.
|
||||
*
|
||||
* @time: Broken-out time to convert
|
||||
* @return corresponding time_t value, seconds since 1970-01-01 00:00:00
|
||||
*/
|
||||
unsigned long rtc_mktime(const struct rtc_time *time);
|
||||
|
||||
#endif /* _RTC_H_ */
|
||||
|
|
36
include/rtc_def.h
Normal file
36
include/rtc_def.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* (C) Copyright 2001
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __rtc_def_h
|
||||
#define __rtc_def_h
|
||||
|
||||
/*
|
||||
* The struct used to pass data from the generic interface code to
|
||||
* the hardware dependend low-level code ande vice versa. Identical
|
||||
* to struct rtc_time used by the Linux kernel.
|
||||
*
|
||||
* Note that there are small but significant differences to the
|
||||
* common "struct time":
|
||||
*
|
||||
* struct time: struct rtc_time:
|
||||
* tm_mon 0 ... 11 1 ... 12
|
||||
* tm_year years since 1900 years since 0
|
||||
*/
|
||||
|
||||
struct rtc_time {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -100,6 +100,8 @@ struct dm_spi_slave_platdata {
|
|||
* @dev: SPI slave device
|
||||
* @max_hz: Maximum speed for this slave
|
||||
* @mode: SPI mode to use for this slave (see SPI mode flags)
|
||||
* @speed: Current bus speed. This is 0 until the bus is first
|
||||
* claimed.
|
||||
* @bus: ID of the bus that the slave is attached to. For
|
||||
* driver model this is the sequence number of the SPI
|
||||
* bus (bus->seq) so does not need to be stored
|
||||
|
@ -117,6 +119,7 @@ struct spi_slave {
|
|||
#ifdef CONFIG_DM_SPI
|
||||
struct udevice *dev; /* struct spi_slave is dev->parentdata */
|
||||
uint max_hz;
|
||||
uint speed;
|
||||
uint mode;
|
||||
#else
|
||||
unsigned int bus;
|
||||
|
@ -613,7 +616,7 @@ int sandbox_spi_get_emul(struct sandbox_state *state,
|
|||
struct udevice *bus, struct udevice *slave,
|
||||
struct udevice **emulp);
|
||||
|
||||
/* Access the serial operations for a device */
|
||||
/* Access the operations for a SPI device */
|
||||
#define spi_get_ops(dev) ((struct dm_spi_ops *)(dev)->driver->ops)
|
||||
#define spi_emul_get_ops(dev) ((struct dm_spi_emul_ops *)(dev)->driver->ops)
|
||||
#endif /* CONFIG_DM_SPI */
|
||||
|
|
|
@ -571,20 +571,23 @@ struct usb_platdata {
|
|||
* This is used by sandbox to provide emulation data also.
|
||||
*
|
||||
* @id: ID used to match this device
|
||||
* @speed: Stores the speed associated with a USB device
|
||||
* @devnum: Device address on the USB bus
|
||||
* @slot_id: USB3 slot ID, which is separate from the device address
|
||||
* @portnr: Port number of this device on its parent hub, numbered from 1
|
||||
* (0 mean this device is the root hub)
|
||||
* @udev: usb-uclass internal use only do NOT use
|
||||
* @strings: List of descriptor strings (for sandbox emulation purposes)
|
||||
* @desc_list: List of descriptors (for sandbox emulation purposes)
|
||||
*/
|
||||
struct usb_dev_platdata {
|
||||
struct usb_device_id id;
|
||||
enum usb_device_speed speed;
|
||||
int devnum;
|
||||
int slot_id;
|
||||
int portnr; /* Hub port number, 1..n */
|
||||
/*
|
||||
* This pointer is used to pass the usb_device used in usb_scan_device,
|
||||
* to get the usb descriptors before the driver is known, to the
|
||||
* actual udevice once the driver is known and the udevice is created.
|
||||
* This will be NULL except during probe, do NOT use.
|
||||
*
|
||||
* This should eventually go away.
|
||||
*/
|
||||
struct usb_device *udev;
|
||||
#ifdef CONFIG_SANDBOX
|
||||
struct usb_string *strings;
|
||||
/* NULL-terminated list of descriptor pointers */
|
||||
|
@ -742,11 +745,10 @@ int usb_scan_device(struct udevice *parent, int port,
|
|||
* will be a device with uclass UCLASS_USB.
|
||||
*
|
||||
* @dev: Device to check
|
||||
* @busp: Returns bus, or NULL if not found
|
||||
* @return 0 if OK, -EXDEV is somehow this bus does not have a controller (this
|
||||
* indicates a critical error in the USB stack
|
||||
* @return The bus, or NULL if not found (this indicates a critical error in
|
||||
* the USB stack
|
||||
*/
|
||||
int usb_get_bus(struct udevice *dev, struct udevice **busp);
|
||||
struct udevice *usb_get_bus(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* usb_select_config() - Set up a device ready for use
|
||||
|
|
|
@ -44,8 +44,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
|
|||
COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
|
||||
COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
|
||||
COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
|
||||
COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
|
||||
COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"),
|
||||
COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
|
||||
COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
|
||||
COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
|
||||
|
|
14
net/sntp.c
14
net/sntp.c
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <net.h>
|
||||
#include <rtc.h>
|
||||
|
||||
|
@ -68,9 +69,20 @@ static void sntp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
|
|||
*/
|
||||
memcpy(&seconds, &rpktp->transmit_timestamp, sizeof(ulong));
|
||||
|
||||
to_tm(ntohl(seconds) - 2208988800UL + net_ntp_time_offset, &tm);
|
||||
rtc_to_tm(ntohl(seconds) - 2208988800UL + net_ntp_time_offset, &tm);
|
||||
#if defined(CONFIG_CMD_DATE)
|
||||
# ifdef CONFIG_DM_RTC
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device(UCLASS_RTC, 0, &dev);
|
||||
if (ret)
|
||||
printf("SNTP: cannot find RTC: err=%d\n", ret);
|
||||
else
|
||||
dm_rtc_set(dev, &tm);
|
||||
# else
|
||||
rtc_set(&tm);
|
||||
# endif
|
||||
#endif
|
||||
printf("Date: %4d-%02d-%02d Time: %2d:%02d:%02d\n",
|
||||
tm.tm_year, tm.tm_mon, tm.tm_mday,
|
||||
|
|
|
@ -59,11 +59,10 @@ static int rtc_post_skip (ulong * diff)
|
|||
|
||||
static void rtc_post_restore (struct rtc_time *tm, unsigned int sec)
|
||||
{
|
||||
time_t t = mktime (tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
|
||||
tm->tm_min, tm->tm_sec) + sec;
|
||||
time_t t = rtc_mktime(tm) + sec;
|
||||
struct rtc_time ntm;
|
||||
|
||||
to_tm (t, &ntm);
|
||||
rtc_to_tm(t, &ntm);
|
||||
|
||||
rtc_set (&ntm);
|
||||
}
|
||||
|
@ -116,10 +115,17 @@ int rtc_post_test (int flags)
|
|||
rtc_get (&svtm);
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
time_t t = mktime (ynl, i + 1, daysnl[i], 23, 59, 59);
|
||||
time_t t;
|
||||
struct rtc_time tm;
|
||||
|
||||
to_tm (t, &tm);
|
||||
tm.tm_year = ynl;
|
||||
tm.tm_mon = i + 1;
|
||||
tm.tm_mday = daysnl[i];
|
||||
tm.tm_hour = 23;
|
||||
tm.tm_min = 59;
|
||||
tm.tm_sec = 59;
|
||||
t = rtc_mktime(&tm);
|
||||
rtc_to_tm(t, &tm);
|
||||
rtc_set (&tm);
|
||||
|
||||
skipped++;
|
||||
|
@ -140,10 +146,18 @@ int rtc_post_test (int flags)
|
|||
}
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
time_t t = mktime (yl, i + 1, daysl[i], 23, 59, 59);
|
||||
time_t t;
|
||||
struct rtc_time tm;
|
||||
|
||||
to_tm (t, &tm);
|
||||
tm.tm_year = yl;
|
||||
tm.tm_mon = i + 1;
|
||||
tm.tm_mday = daysl[i];
|
||||
tm.tm_hour = 23;
|
||||
tm.tm_min = 59;
|
||||
tm.tm_sec = 59;
|
||||
t = rtc_mktime(&tm);
|
||||
|
||||
rtc_to_tm(t, &tm);
|
||||
rtc_set (&tm);
|
||||
|
||||
skipped++;
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
config CMD_UT_TIME
|
||||
bool "Unit tests for time functions"
|
||||
help
|
||||
Enables the 'ut_time' command which tests that the time functions
|
||||
work correctly. The test is fairly simple and will not catch all
|
||||
problems. But if you are having problems with udelay() and the like,
|
||||
this is a good place to start.
|
||||
|
||||
source "test/dm/Kconfig"
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
|
||||
obj-$(CONFIG_SANDBOX) += command_ut.o
|
||||
obj-$(CONFIG_SANDBOX) += compression.o
|
||||
obj-$(CONFIG_CMD_UT_TIME) += time_ut.o
|
||||
|
|
|
@ -21,6 +21,7 @@ obj-$(CONFIG_DM_ETH) += eth.o
|
|||
obj-$(CONFIG_DM_GPIO) += gpio.o
|
||||
obj-$(CONFIG_DM_I2C) += i2c.o
|
||||
obj-$(CONFIG_DM_PCI) += pci.o
|
||||
obj-$(CONFIG_DM_RTC) += rtc.o
|
||||
obj-$(CONFIG_DM_SPI_FLASH) += sf.o
|
||||
obj-$(CONFIG_DM_SPI) += spi.o
|
||||
obj-$(CONFIG_DM_USB) += usb.o
|
||||
|
|
|
@ -135,6 +135,7 @@ static int dm_test_net_retry(struct dm_test_state *dms)
|
|||
sandbox_eth_disable_response(1, true);
|
||||
setenv("ethact", "eth@10004000");
|
||||
setenv("netretry", "yes");
|
||||
sandbox_eth_skip_timeout();
|
||||
ut_assertok(net_loop(PING));
|
||||
ut_asserteq_str("eth@10002000", getenv("ethact"));
|
||||
|
||||
|
@ -144,6 +145,7 @@ static int dm_test_net_retry(struct dm_test_state *dms)
|
|||
*/
|
||||
setenv("ethact", "eth@10004000");
|
||||
setenv("netretry", "no");
|
||||
sandbox_eth_skip_timeout();
|
||||
ut_asserteq(-ETIMEDOUT, net_loop(PING));
|
||||
ut_asserteq_str("eth@10004000", getenv("ethact"));
|
||||
|
||||
|
|
|
@ -66,6 +66,9 @@ static int dm_test_i2c_speed(struct dm_test_state *dms)
|
|||
uint8_t buf[5];
|
||||
|
||||
ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
|
||||
|
||||
/* Use test mode so we create the required errors for invalid speeds */
|
||||
sandbox_i2c_set_test_mode(bus, true);
|
||||
ut_assertok(i2c_get_chip(bus, chip, 1, &dev));
|
||||
ut_assertok(dm_i2c_set_bus_speed(bus, 100000));
|
||||
ut_assertok(dm_i2c_read(dev, 0, buf, 5));
|
||||
|
@ -73,6 +76,7 @@ static int dm_test_i2c_speed(struct dm_test_state *dms)
|
|||
ut_asserteq(400000, dm_i2c_get_bus_speed(bus));
|
||||
ut_assertok(dm_i2c_read(dev, 0, buf, 5));
|
||||
ut_asserteq(-EINVAL, dm_i2c_write(dev, 0, buf, 5));
|
||||
sandbox_i2c_set_test_mode(bus, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -100,7 +104,11 @@ static int dm_test_i2c_probe_empty(struct dm_test_state *dms)
|
|||
struct udevice *bus, *dev;
|
||||
|
||||
ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
|
||||
|
||||
/* Use test mode so that this chip address will always probe */
|
||||
sandbox_i2c_set_test_mode(bus, true);
|
||||
ut_assertok(dm_i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev));
|
||||
sandbox_i2c_set_test_mode(bus, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
175
test/dm/rtc.c
Normal file
175
test/dm/rtc.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <rtc.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/test.h>
|
||||
#include <dm/ut.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
/* Simple RTC sanity check */
|
||||
static int dm_test_rtc_base(struct dm_test_state *dms)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_RTC, 2, &dev));
|
||||
ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
|
||||
ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_rtc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
static void show_time(const char *msg, struct rtc_time *time)
|
||||
{
|
||||
printf("%s: %02d/%02d/%04d %02d:%02d:%02d\n", msg,
|
||||
time->tm_mday, time->tm_mon, time->tm_year,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
}
|
||||
|
||||
static int cmp_times(struct rtc_time *expect, struct rtc_time *time, bool show)
|
||||
{
|
||||
bool same;
|
||||
|
||||
same = expect->tm_sec == time->tm_sec;
|
||||
same &= expect->tm_min == time->tm_min;
|
||||
same &= expect->tm_hour == time->tm_hour;
|
||||
same &= expect->tm_mday == time->tm_mday;
|
||||
same &= expect->tm_mon == time->tm_mon;
|
||||
same &= expect->tm_year == time->tm_year;
|
||||
if (!same && show) {
|
||||
show_time("expected", expect);
|
||||
show_time("actual", time);
|
||||
}
|
||||
|
||||
return same ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/* Set and get the time */
|
||||
static int dm_test_rtc_set_get(struct dm_test_state *dms)
|
||||
{
|
||||
struct rtc_time now, time, cmp;
|
||||
struct udevice *dev, *emul;
|
||||
long offset, old_offset, old_base_time;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
|
||||
ut_assertok(dm_rtc_get(dev, &now));
|
||||
|
||||
ut_assertok(device_find_first_child(dev, &emul));
|
||||
ut_assert(emul != NULL);
|
||||
|
||||
/* Tell the RTC to go into manual mode */
|
||||
old_offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
|
||||
old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
|
||||
|
||||
memset(&time, '\0', sizeof(time));
|
||||
time.tm_mday = 25;
|
||||
time.tm_mon = 8;
|
||||
time.tm_year = 2004;
|
||||
time.tm_sec = 0;
|
||||
time.tm_min = 18;
|
||||
time.tm_hour = 18;
|
||||
ut_assertok(dm_rtc_set(dev, &time));
|
||||
|
||||
memset(&cmp, '\0', sizeof(cmp));
|
||||
ut_assertok(dm_rtc_get(dev, &cmp));
|
||||
ut_assertok(cmp_times(&time, &cmp, true));
|
||||
|
||||
/* Increment by 1 second */
|
||||
offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
|
||||
sandbox_i2c_rtc_set_offset(emul, false, offset + 1);
|
||||
|
||||
memset(&cmp, '\0', sizeof(cmp));
|
||||
ut_assertok(dm_rtc_get(dev, &cmp));
|
||||
ut_asserteq(1, cmp.tm_sec);
|
||||
|
||||
/* Check against original offset */
|
||||
sandbox_i2c_rtc_set_offset(emul, false, old_offset);
|
||||
ut_assertok(dm_rtc_get(dev, &cmp));
|
||||
ut_assertok(cmp_times(&now, &cmp, true));
|
||||
|
||||
/* Back to the original offset */
|
||||
sandbox_i2c_rtc_set_offset(emul, false, 0);
|
||||
memset(&cmp, '\0', sizeof(cmp));
|
||||
ut_assertok(dm_rtc_get(dev, &cmp));
|
||||
ut_assertok(cmp_times(&now, &cmp, true));
|
||||
|
||||
/* Increment the base time by 1 emul */
|
||||
sandbox_i2c_rtc_get_set_base_time(emul, old_base_time + 1);
|
||||
memset(&cmp, '\0', sizeof(cmp));
|
||||
ut_assertok(dm_rtc_get(dev, &cmp));
|
||||
if (now.tm_sec == 59) {
|
||||
ut_asserteq(0, cmp.tm_sec);
|
||||
} else {
|
||||
ut_asserteq(now.tm_sec + 1, cmp.tm_sec);
|
||||
}
|
||||
|
||||
old_offset = sandbox_i2c_rtc_set_offset(emul, true, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_rtc_set_get, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
/* Reset the time */
|
||||
static int dm_test_rtc_reset(struct dm_test_state *dms)
|
||||
{
|
||||
struct rtc_time now;
|
||||
struct udevice *dev, *emul;
|
||||
long old_base_time, base_time;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
|
||||
ut_assertok(dm_rtc_get(dev, &now));
|
||||
|
||||
ut_assertok(device_find_first_child(dev, &emul));
|
||||
ut_assert(emul != NULL);
|
||||
|
||||
old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0);
|
||||
|
||||
ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1));
|
||||
|
||||
/* Resetting the RTC should put he base time back to normal */
|
||||
ut_assertok(dm_rtc_reset(dev));
|
||||
base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
|
||||
ut_asserteq(old_base_time, base_time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_rtc_reset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
/* Check that two RTC devices can be used independently */
|
||||
static int dm_test_rtc_dual(struct dm_test_state *dms)
|
||||
{
|
||||
struct rtc_time now1, now2, cmp;
|
||||
struct udevice *dev1, *dev2;
|
||||
struct udevice *emul1, *emul2;
|
||||
long offset;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev1));
|
||||
ut_assertok(dm_rtc_get(dev1, &now1));
|
||||
ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev2));
|
||||
ut_assertok(dm_rtc_get(dev2, &now2));
|
||||
|
||||
ut_assertok(device_find_first_child(dev1, &emul1));
|
||||
ut_assert(emul1 != NULL);
|
||||
ut_assertok(device_find_first_child(dev2, &emul2));
|
||||
ut_assert(emul2 != NULL);
|
||||
|
||||
offset = sandbox_i2c_rtc_set_offset(emul1, false, -1);
|
||||
sandbox_i2c_rtc_set_offset(emul2, false, offset + 1);
|
||||
memset(&cmp, '\0', sizeof(cmp));
|
||||
ut_assertok(dm_rtc_get(dev2, &cmp));
|
||||
ut_asserteq(-EINVAL, cmp_times(&now1, &cmp, false));
|
||||
|
||||
memset(&cmp, '\0', sizeof(cmp));
|
||||
ut_assertok(dm_rtc_get(dev1, &cmp));
|
||||
ut_assertok(cmp_times(&now1, &cmp, true));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_rtc_dual, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
|
@ -8,18 +8,20 @@
|
|||
|
||||
aliases {
|
||||
console = &uart0;
|
||||
eth0 = "/eth@10002000";
|
||||
eth5 = ð_5;
|
||||
i2c0 = "/i2c@0";
|
||||
spi0 = "/spi@0";
|
||||
pci0 = &pci;
|
||||
testfdt6 = "/e-test";
|
||||
spi0 = "/spi@0";
|
||||
testbus3 = "/some-bus";
|
||||
testfdt0 = "/some-bus/c-test@0";
|
||||
testfdt1 = "/some-bus/c-test@1";
|
||||
testfdt3 = "/b-test";
|
||||
testfdt5 = "/some-bus/c-test@5";
|
||||
testfdt6 = "/e-test";
|
||||
testfdt8 = "/a-test";
|
||||
eth0 = "/eth@10002000";
|
||||
eth5 = ð_5;
|
||||
rtc0 = &rtc_0;
|
||||
rtc1 = &rtc_1;
|
||||
usb0 = &usb_0;
|
||||
usb1 = &usb_1;
|
||||
usb2 = &usb_2;
|
||||
|
@ -139,6 +141,22 @@
|
|||
sandbox,size = <256>;
|
||||
};
|
||||
};
|
||||
|
||||
rtc_0: rtc@43 {
|
||||
reg = <0x43>;
|
||||
compatible = "sandbox-rtc";
|
||||
emul {
|
||||
compatible = "sandbox,i2c-rtc";
|
||||
};
|
||||
};
|
||||
|
||||
rtc_1: rtc@61 {
|
||||
reg = <0x61>;
|
||||
compatible = "sandbox-rtc";
|
||||
emul {
|
||||
compatible = "sandbox,i2c-rtc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pci: pci-controller {
|
||||
|
|
137
test/time_ut.c
Normal file
137
test/time_ut.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <errno.h>
|
||||
|
||||
static int test_get_timer(void)
|
||||
{
|
||||
ulong base, start, next, diff;
|
||||
int iter;
|
||||
|
||||
base = get_timer(0);
|
||||
start = get_timer(0);
|
||||
for (iter = 0; iter < 10; iter++) {
|
||||
do {
|
||||
next = get_timer(0);
|
||||
} while (start == next);
|
||||
|
||||
if (start + 1 != next) {
|
||||
printf("%s: iter=%d, start=%lu, next=%lu, expected a difference of 1\n",
|
||||
__func__, iter, start, next);
|
||||
return -EINVAL;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that get_timer(base) matches our elapsed time, allowing that
|
||||
* an extra millisecond may have passed.
|
||||
*/
|
||||
diff = get_timer(base);
|
||||
if (diff != iter && diff != iter + 1) {
|
||||
printf("%s: expected get_timer(base) to match elapsed time: diff=%lu, expected=%d\n",
|
||||
__func__, diff, iter);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_timer_get_us(void)
|
||||
{
|
||||
ulong prev, next, min = 1000000;
|
||||
long delta;
|
||||
int iter;
|
||||
|
||||
/* Find the minimum delta we can measure, in microseconds */
|
||||
prev = timer_get_us();
|
||||
for (iter = 0; iter < 100; ) {
|
||||
next = timer_get_us();
|
||||
if (next != prev) {
|
||||
delta = next - prev;
|
||||
if (delta < 0) {
|
||||
printf("%s: timer_get_us() went backwards from %lu to %lu\n",
|
||||
__func__, prev, next);
|
||||
return -EINVAL;
|
||||
} else if (delta != 0) {
|
||||
if (delta < min)
|
||||
min = delta;
|
||||
prev = next;
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (min != 1) {
|
||||
printf("%s: Minimum microsecond delta should be 1 but is %lu\n",
|
||||
__func__, min);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_time_comparison(void)
|
||||
{
|
||||
ulong start_us, end_us, delta_us;
|
||||
long error;
|
||||
ulong start;
|
||||
|
||||
start = get_timer(0);
|
||||
start_us = timer_get_us();
|
||||
while (get_timer(start) < 1000)
|
||||
;
|
||||
end_us = timer_get_us();
|
||||
delta_us = end_us - start_us;
|
||||
error = delta_us - 1000000;
|
||||
printf("%s: Microsecond time for 1 second: %lu, error = %ld\n",
|
||||
__func__, delta_us, error);
|
||||
if (abs(error) > 1000)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_udelay(void)
|
||||
{
|
||||
long error;
|
||||
ulong start, delta;
|
||||
int iter;
|
||||
|
||||
start = get_timer(0);
|
||||
for (iter = 0; iter < 1000; iter++)
|
||||
udelay(1000);
|
||||
delta = get_timer(start);
|
||||
error = delta - 1000;
|
||||
printf("%s: Delay time for 1000 udelay(1000): %lu ms, error = %ld\n",
|
||||
__func__, delta, error);
|
||||
if (abs(error) > 100)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret |= test_get_timer();
|
||||
ret |= test_timer_get_us();
|
||||
ret |= test_time_comparison();
|
||||
ret |= test_udelay();
|
||||
|
||||
printf("Test %s\n", ret ? "failed" : "passed");
|
||||
|
||||
return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
ut_time, 1, 1, do_ut_time,
|
||||
"Very basic test of time functions",
|
||||
""
|
||||
);
|
Loading…
Add table
Reference in a new issue