1
0
Fork 0

Merge git://git.denx.de/u-boot-dm

utp
Tom Rini 2015-05-08 10:46:59 -04:00
commit 02ffb580e6
67 changed files with 1741 additions and 647 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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 {

View File

@ -12,4 +12,6 @@
void sandbox_eth_disable_response(int index, bool disable);
void sandbox_eth_skip_timeout(void);
#endif /* __ETH_H */

View 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

View File

@ -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 */

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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
*

View File

@ -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),
};

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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();

View 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,
};

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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,

View 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,
};

View 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,
};

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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(&regs->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, &regs->intrdisable);
(void)ohci_readl(&regs->intrdisable); /* flush */
stat = dl_done_list(&gohci);
stat = dl_done_list(ohci);
ohci_writel(OHCI_INTR_WDH, &regs->intrenable);
(void)ohci_readl(&regs->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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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));
}

View File

@ -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

View File

@ -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,

View File

@ -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 */

View File

@ -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
*

View File

@ -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

View File

@ -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 100644
View 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

View File

@ -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 */

View File

@ -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

View File

@ -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"),

View File

@ -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,

View File

@ -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++;

View File

@ -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"

View File

@ -6,3 +6,4 @@
obj-$(CONFIG_SANDBOX) += command_ut.o
obj-$(CONFIG_SANDBOX) += compression.o
obj-$(CONFIG_CMD_UT_TIME) += time_ut.o

View File

@ -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

View File

@ -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"));

View File

@ -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 100644
View 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);

View File

@ -8,18 +8,20 @@
aliases {
console = &uart0;
eth0 = "/eth@10002000";
eth5 = &eth_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 = &eth_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 100644
View 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",
""
);