coreboot-kgpe-d16/src/drivers/usb/ehci_debug.c

712 lines
18 KiB
C
Raw Normal View History

/*
* This file is part of the coreboot project.
*
* Copyright (C) 2006 Eric Biederman (ebiederm@xmission.com)
* Copyright (C) 2007 AMD
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stddef.h>
#include <console/console.h>
#include <console/usb.h>
#include <arch/io.h>
#include <arch/early_variables.h>
#include <string.h>
#include <cbmem.h>
#include "ehci_debug.h"
#include "usb_ch9.h"
#include "ehci.h"
struct ehci_debug_info {
void *ehci_base;
void *ehci_debug;
struct dbgp_pipe ep_pipe[DBGP_MAX_ENDPOINTS];
};
#if IS_ENABLED(CONFIG_DEBUG_USBDEBUG)
static void dbgp_print_data(struct ehci_dbg_port *ehci_debug);
static int dbgp_enabled(void);
# define dprintk(LEVEL, args...) \
do { if (!dbgp_enabled()) printk(LEVEL, ##args); } while (0)
#else
# define dbgp_print_data(x) do {} while (0)
# define dprintk(LEVEL, args...) do {} while (0)
#endif
#define DBGP_LEN_UPDATE(x, len) (((x) & ~0x0f) | ((len) & 0x0f))
#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
#define HUB_LONG_RESET_TIME 200
#define HUB_RESET_TIMEOUT 500
#define DBGP_MICROFRAME_TIMEOUT_LOOPS 1000
#define DBGP_MICROFRAME_RETRIES 10
#define DBGP_MAX_PACKET 8
static struct ehci_debug_info glob_dbg_info CAR_GLOBAL;
static struct ehci_debug_info * glob_dbg_info_p CAR_GLOBAL;
static inline struct ehci_debug_info *dbgp_ehci_info(void)
{
if (car_get_var(glob_dbg_info_p) == NULL)
car_set_var(glob_dbg_info_p, &glob_dbg_info);
return car_get_var(glob_dbg_info_p);
}
static int dbgp_wait_until_complete(struct ehci_dbg_port *ehci_debug)
{
u32 ctrl;
int loop = 0;
do {
ctrl = read32(&ehci_debug->control);
/* Stop when the transaction is finished */
if (ctrl & DBGP_DONE)
break;
} while (++loop < DBGP_MICROFRAME_TIMEOUT_LOOPS);
if (! (ctrl & DBGP_DONE)) {
dprintk(BIOS_ERR, "dbgp_wait_until_complete: retry timeout.\n");
return -DBGP_ERR_SIGNAL;
}
/* Now that we have observed the completed transaction,
* clear the done bit.
*/
write32(&ehci_debug->control, ctrl | DBGP_DONE);
return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
}
static void dbgp_breath(void)
{
/* Sleep to give the debug port a chance to breathe */
}
static int dbgp_wait_until_done(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe,
unsigned ctrl, const int timeout)
{
u32 rd_ctrl, rd_pids;
u32 ctrl_prev = 0, pids_prev = 0;
u8 lpid;
int ret, host_retries;
int loop;
loop = 0;
device_retry:
host_retries = 0;
if (loop++ >= timeout)
return -DBGP_ERR_BAD;
host_retry:
if (host_retries++ >= DBGP_MICROFRAME_RETRIES)
return -DBGP_ERR_BAD;
if (loop == 1 || host_retries > 1)
dprintk(BIOS_SPEW, "dbgp: start (@ %3d,%d) ctrl=%08x\n",
loop, host_retries, ctrl | DBGP_GO);
write32(&ehci_debug->control, ctrl | DBGP_GO);
ret = dbgp_wait_until_complete(ehci_debug);
rd_ctrl = read32(&ehci_debug->control);
rd_pids = read32(&ehci_debug->pids);
if (rd_ctrl != ctrl_prev || rd_pids != pids_prev || (ret<0)) {
ctrl_prev = rd_ctrl;
pids_prev = rd_pids;
dprintk(BIOS_SPEW, "dbgp: status (@ %3d,%d) ctrl=%08x pids=%08x ret=%d\n",
loop, host_retries, rd_ctrl, rd_pids, ret);
}
/* Controller hardware failure. */
if (ret == -DBGP_ERR_SIGNAL) {
return ret;
/* Bus failure (corrupted microframe). */
} else if (ret == -DBGP_ERR_BAD) {
goto host_retry;
}
lpid = DBGP_PID_GET(rd_pids);
/* If I get an ACK or in-sync DATA PID, we are done. */
if ((lpid == USB_PID_ACK) || (lpid == pipe->pid)) {
pipe->pid ^= USB_PID_DATA_TOGGLE;
}
/* If the port is getting full or it has dropped data
* start pacing ourselves, not necessary but it's friendly.
*/
else if (lpid == USB_PID_NYET) {
dbgp_breath();
goto device_retry;
}
/* If I get a NACK or out-of-sync DATA PID, reissue the transmission. */
else if ((lpid == USB_PID_NAK) || (lpid == (pipe->pid ^ USB_PID_DATA_TOGGLE))) {
goto device_retry;
}
/* Abort on STALL handshake for endpoint 0.*/
else if ((lpid == USB_PID_STALL) && (pipe->endpoint == 0x0)) {
ret = -DBGP_ERR_BAD;
}
dbgp_print_data(ehci_debug);
return ret;
}
static void dbgp_set_data(struct ehci_dbg_port *ehci_debug, const void *buf, int size)
{
const unsigned char *bytes = buf;
u32 lo, hi;
int i;
lo = hi = 0;
for (i = 0; i < 4 && i < size; i++)
lo |= bytes[i] << (8*i);
for (; i < 8 && i < size; i++)
hi |= bytes[i] << (8*(i - 4));
write32(&ehci_debug->data03, lo);
write32(&ehci_debug->data47, hi);
}
static void dbgp_get_data(struct ehci_dbg_port *ehci_debug, void *buf, int size)
{
unsigned char *bytes = buf;
u32 lo, hi;
int i;
lo = read32(&ehci_debug->data03);
hi = read32(&ehci_debug->data47);
for (i = 0; i < 4 && i < size; i++)
bytes[i] = (lo >> (8*i)) & 0xff;
for (; i < 8 && i < size; i++)
bytes[i] = (hi >> (8*(i - 4))) & 0xff;
}
#if IS_ENABLED(CONFIG_DEBUG_USBDEBUG)
static void dbgp_print_data(struct ehci_dbg_port *ehci_debug)
{
u32 ctrl = read32(&ehci_debug->control);
u32 lo = read32(&ehci_debug->data03);
u32 hi = read32(&ehci_debug->data47);
int len = DBGP_LEN(ctrl);
if (len) {
int i;
dprintk(BIOS_SPEW, "dbgp: buf:");
for (i = 0; i < 4 && i < len; i++)
dprintk(BIOS_SPEW, " %02x", (lo >> (8*i)) & 0xff);
for (; i < 8 && i < len; i++)
dprintk(BIOS_SPEW, " %02x", (hi >> (8*(i - 4))) & 0xff);
dprintk(BIOS_SPEW, "\n");
}
}
#endif
static int dbgp_bulk_write(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe,
const char *bytes, int size)
{
u32 pids, addr, ctrl;
int ret;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(pipe->devnum, pipe->endpoint);
pids = DBGP_PID_SET(pipe->pid, USB_PID_OUT);
ctrl = read32(&ehci_debug->control);
ctrl = DBGP_LEN_UPDATE(ctrl, size);
ctrl |= DBGP_OUT;
dbgp_set_data(ehci_debug, bytes, size);
write32(&ehci_debug->address, addr);
write32(&ehci_debug->pids, pids);
ret = dbgp_wait_until_done(ehci_debug, pipe, ctrl, pipe->timeout);
return ret;
}
int dbgp_bulk_write_x(struct dbgp_pipe *pipe, const char *bytes, int size)
{
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
return dbgp_bulk_write(dbg_info->ehci_debug, pipe, bytes, size);
}
static int dbgp_bulk_read(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe,
void *data, int size)
{
u32 pids, addr, ctrl;
int ret;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(pipe->devnum, pipe->endpoint);
pids = DBGP_PID_SET(pipe->pid, USB_PID_IN);
ctrl = read32(&ehci_debug->control);
ctrl = DBGP_LEN_UPDATE(ctrl, size);
ctrl &= ~DBGP_OUT;
write32(&ehci_debug->address, addr);
write32(&ehci_debug->pids, pids);
ret = dbgp_wait_until_done(ehci_debug, pipe, ctrl, pipe->timeout);
if (ret < 0)
return ret;
if (size > ret)
size = ret;
dbgp_get_data(ehci_debug, data, size);
return ret;
}
int dbgp_bulk_read_x(struct dbgp_pipe *pipe, void *data, int size)
{
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
return dbgp_bulk_read(dbg_info->ehci_debug, pipe, data, size);
}
void dbgp_mdelay(int ms)
{
int i;
while (ms--) {
for (i = 0; i < 1000; i++)
inb(0x80);
}
}
int dbgp_control_msg(struct ehci_dbg_port *ehci_debug, unsigned devnum, int requesttype,
int request, int value, int index, void *data, int size)
{
struct ehci_debug_info *info = dbgp_ehci_info();
struct dbgp_pipe *pipe = &info->ep_pipe[DBGP_SETUP_EP0];
u32 pids, addr, ctrl;
struct usb_ctrlrequest req;
int read;
int ret, ret2;
read = (requesttype & USB_DIR_IN) != 0;
if (size > DBGP_MAX_PACKET)
return -1;
/* Compute the control message */
req.bRequestType = requesttype;
req.bRequest = request;
req.wValue = cpu_to_le16(value);
req.wIndex = cpu_to_le16(index);
req.wLength = cpu_to_le16(size);
pipe->devnum = devnum;
pipe->endpoint = 0;
pipe->pid = USB_PID_DATA0;
pipe->timeout = 1000;
addr = DBGP_EPADDR(pipe->devnum, pipe->endpoint);
pids = DBGP_PID_SET(pipe->pid, USB_PID_SETUP);
ctrl = read32(&ehci_debug->control);
ctrl = DBGP_LEN_UPDATE(ctrl, sizeof(req));
ctrl |= DBGP_OUT;
/* Setup stage */
dbgp_set_data(ehci_debug, &req, sizeof(req));
write32(&ehci_debug->address, addr);
write32(&ehci_debug->pids, pids);
ret = dbgp_wait_until_done(ehci_debug, pipe, ctrl, 1);
if (ret < 0)
return ret;
/* Data stage (optional) */
if (read && size)
ret = dbgp_bulk_read(ehci_debug, pipe, data, size);
else if (!read && size)
ret = dbgp_bulk_write(ehci_debug, pipe, data, size);
/* Status stage in opposite direction */
pipe->pid = USB_PID_DATA1;
ctrl = read32(&ehci_debug->control);
ctrl = DBGP_LEN_UPDATE(ctrl, 0);
if (read) {
pids = DBGP_PID_SET(pipe->pid, USB_PID_OUT);
ctrl |= DBGP_OUT;
} else {
pids = DBGP_PID_SET(pipe->pid, USB_PID_IN);
ctrl &= ~DBGP_OUT;
}
write32(&ehci_debug->pids, pids);
ret2 = dbgp_wait_until_done(ehci_debug, pipe, ctrl, pipe->timeout);
if (ret2 < 0)
return ret2;
return ret;
}
static int ehci_reset_port(struct ehci_regs *ehci_regs, int port)
{
u32 portsc;
int loop;
/* Reset the usb debug port */
portsc = read32(&ehci_regs->port_status[port - 1]);
portsc &= ~PORT_PE;
portsc |= PORT_RESET;
write32(&ehci_regs->port_status[port - 1], portsc);
dbgp_mdelay(HUB_ROOT_RESET_TIME);
portsc = read32(&ehci_regs->port_status[port - 1]);
write32(&ehci_regs->port_status[port - 1],
portsc & ~(PORT_RWC_BITS | PORT_RESET));
loop = 100;
do {
dbgp_mdelay(1);
portsc = read32(&ehci_regs->port_status[port - 1]);
} while ((portsc & PORT_RESET) && (--loop > 0));
/* Device went away? */
if (!(portsc & PORT_CONNECT))
return -1; //-ENOTCONN;
/* bomb out completely if something weird happened */
if ((portsc & PORT_CSC))
return -2; //-EINVAL;
/* If we've finished resetting, then break out of the loop */
if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
return 0;
return -3; //-EBUSY;
}
static int ehci_wait_for_port(struct ehci_regs *ehci_regs, int port)
{
u32 status;
int ret, reps;
for (reps = 0; reps < 3; reps++) {
dbgp_mdelay(100);
status = read32(&ehci_regs->status);
if (status & STS_PCD) {
ret = ehci_reset_port(ehci_regs, port);
if (ret == 0)
return 0;
}
}
return -1; //-ENOTCONN;
}
static int usbdebug_init_(unsigned ehci_bar, unsigned offset, struct ehci_debug_info *info)
{
struct ehci_caps *ehci_caps;
struct ehci_regs *ehci_regs;
u32 cmd, ctrl, status, portsc, hcs_params;
u32 debug_port, new_debug_port = 0, n_ports;
int ret, i;
int loop;
int port_map_tried;
int playtimes = 3;
/* Keep all endpoints disabled before any printk() call. */
memset(info, 0, sizeof (*info));
info->ehci_base = (void *)ehci_bar;
info->ehci_debug = (void *)(ehci_bar + offset);
dprintk(BIOS_INFO, "ehci_bar: 0x%x debug_offset 0x%x\n", ehci_bar, offset);
ehci_caps = (struct ehci_caps *)ehci_bar;
ehci_regs = (struct ehci_regs *)(ehci_bar +
HC_LENGTH(read32(&ehci_caps->hc_capbase)));
struct ehci_dbg_port *ehci_debug = info->ehci_debug;
if (CONFIG_USBDEBUG_DEFAULT_PORT > 0)
ehci_debug_select_port(CONFIG_USBDEBUG_DEFAULT_PORT);
else
ehci_debug_select_port(1);
try_next_time:
port_map_tried = 0;
try_next_port:
hcs_params = read32(&ehci_caps->hcs_params);
debug_port = HCS_DEBUG_PORT(hcs_params);
n_ports = HCS_N_PORTS(hcs_params);
dprintk(BIOS_INFO, "debug_port: %d\n", debug_port);
dprintk(BIOS_INFO, "n_ports: %d\n", n_ports);
for (i = 1; i <= n_ports; i++) {
portsc = read32(&ehci_regs->port_status[i-1]);
dprintk(BIOS_INFO, "PORTSC #%d: %08x\n", i, portsc);
}
if (port_map_tried && (new_debug_port != debug_port)) {
if (--playtimes) {
ehci_debug_select_port(debug_port);
goto try_next_time;
}
return -1;
}
/* Wait until the controller is halted */
status = read32(&ehci_regs->status);
if (!(status & STS_HALT)) {
cmd = read32(&ehci_regs->command);
cmd &= ~CMD_RUN;
write32(&ehci_regs->command, cmd);
loop = 100;
do {
dbgp_mdelay(10);
status = read32(&ehci_regs->status);
} while (!(status & STS_HALT) && (--loop > 0));
if (status & STS_HALT)
dprintk(BIOS_INFO, "EHCI controller halted successfully.\n");
else
dprintk(BIOS_INFO, "EHCI controller is not halted. Reset may fail.\n");
}
loop = 100;
/* Reset the EHCI controller */
cmd = read32(&ehci_regs->command);
cmd |= CMD_RESET;
write32(&ehci_regs->command, cmd);
do {
dbgp_mdelay(10);
cmd = read32(&ehci_regs->command);
} while ((cmd & CMD_RESET) && (--loop > 0));
if (!loop) {
dprintk(BIOS_INFO, "Could not reset EHCI controller.\n");
// on some systems it works without succeeding here.
// return -2;
} else {
dprintk(BIOS_INFO, "EHCI controller reset successfully.\n");
}
/* Claim ownership, but do not enable yet */
ctrl = read32(&ehci_debug->control);
ctrl |= DBGP_OWNER;
ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
write32(&ehci_debug->control, ctrl);
/* Start EHCI controller */
cmd = read32(&ehci_regs->command);
cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
cmd |= CMD_RUN;
write32(&ehci_regs->command, cmd);
/* Ensure everything is routed to the EHCI */
write32(&ehci_regs->configured_flag, FLAG_CF);
/* Wait until the controller is no longer halted */
loop = 10;
do {
dbgp_mdelay(10);
status = read32(&ehci_regs->status);
} while ((status & STS_HALT) && (--loop > 0));
if (!loop) {
dprintk(BIOS_INFO, "EHCI could not be started.\n");
return -3;
}
dprintk(BIOS_INFO, "EHCI started.\n");
/* Wait for a device to show up in the debug port */
ret = ehci_wait_for_port(ehci_regs, debug_port);
if (ret < 0) {
dprintk(BIOS_INFO, "No device found in debug port %d\n", debug_port);
goto next_debug_port;
}
dprintk(BIOS_INFO, "EHCI done waiting for port.\n");
/* Enable the debug port */
ctrl = read32(&ehci_debug->control);
ctrl |= DBGP_CLAIM;
write32(&ehci_debug->control, ctrl);
ctrl = read32(&ehci_debug->control);
if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
dprintk(BIOS_INFO, "No device in EHCI debug port.\n");
write32(&ehci_debug->control, ctrl & ~DBGP_CLAIM);
ret = -4;
goto err;
}
dprintk(BIOS_INFO, "EHCI debug port enabled.\n");
#if 0
/* Completely transfer the debug device to the debug controller */
portsc = read32(&ehci_regs->port_status[debug_port - 1]);
portsc &= ~PORT_PE;
write32(&ehci_regs->port_status[debug_port - 1], portsc);
#endif
dbgp_mdelay(100);
ret = dbgp_probe_gadget(info->ehci_debug, &info->ep_pipe[0]);
if (ret < 0) {
dprintk(BIOS_INFO, "Could not probe gadget on debug port.\n");
ret = -6;
goto err;
}
return 0;
err:
/* Things didn't work so remove my claim */
ctrl = read32(&ehci_debug->control);
ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
write32(&ehci_debug->control, ctrl);
//return ret;
next_debug_port:
#if CONFIG_USBDEBUG_DEFAULT_PORT == 0
port_map_tried |= (1 << (debug_port - 1));
new_debug_port = ((debug_port-1 + 1) % n_ports) + 1;
if (port_map_tried != ((1 << n_ports) - 1)) {
ehci_debug_select_port(new_debug_port);
goto try_next_port;
}
if (--playtimes) {
ehci_debug_select_port(new_debug_port);
goto try_next_time;
}
#else
if (0)
goto try_next_port;
if (--playtimes)
goto try_next_time;
#endif
return -10;
}
#if IS_ENABLED(CONFIG_DEBUG_USBDEBUG)
static int dbgp_enabled(void)
{
struct dbgp_pipe *globals = &dbgp_ehci_info()->ep_pipe[DBGP_SETUP_EP0];
return (globals->status & DBGP_EP_ENABLED);
}
#endif
int dbgp_try_get(struct dbgp_pipe *pipe)
{
struct dbgp_pipe *globals = &dbgp_ehci_info()->ep_pipe[DBGP_SETUP_EP0];
if (!dbgp_ep_is_active(pipe) || (globals->status & DBGP_EP_BUSY))
return 0;
globals->status |= DBGP_EP_BUSY;
pipe->status |= DBGP_EP_BUSY;
return 1;
}
void dbgp_put(struct dbgp_pipe *pipe)
{
struct dbgp_pipe *globals = &dbgp_ehci_info()->ep_pipe[DBGP_SETUP_EP0];
globals->status &= ~DBGP_EP_BUSY;
pipe->status &= ~DBGP_EP_BUSY;
}
#if !defined(__PRE_RAM__) && !defined(__SMM__)
void usbdebug_re_enable(unsigned ehci_base)
{
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
unsigned diff;
int i;
diff = (unsigned)dbg_info->ehci_base - ehci_base;
dbg_info->ehci_debug -= diff;
dbg_info->ehci_base = (void*)ehci_base;
for (i=0; i<DBGP_MAX_ENDPOINTS; i++)
if (dbg_info->ep_pipe[i].status & DBGP_EP_VALID)
dbg_info->ep_pipe[i].status |= DBGP_EP_ENABLED;
}
void usbdebug_disable(void)
{
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
int i;
for (i=0; i<DBGP_MAX_ENDPOINTS; i++)
dbg_info->ep_pipe[i].status &= ~DBGP_EP_ENABLED;
}
#endif
#if !defined(__PRE_RAM__) && !defined(__SMM__)
static int get_usbdebug_from_cbmem(struct ehci_debug_info *info)
{
struct ehci_debug_info *dbg_info_cbmem;
dbg_info_cbmem = cbmem_find(CBMEM_ID_EHCI_DEBUG);
if (dbg_info_cbmem == NULL)
return -1;
memcpy(info, dbg_info_cbmem, sizeof (*info));
printk(BIOS_DEBUG, "EHCI debug port found in CBMEM.\n");
return 0;
}
#elif defined(__PRE_RAM__)
static void migrate_ehci_debug(int is_recovery)
{
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
struct ehci_debug_info *dbg_info_cbmem;
dbg_info_cbmem = cbmem_add(CBMEM_ID_EHCI_DEBUG, sizeof(*dbg_info));
if (dbg_info_cbmem == NULL)
return;
memcpy(dbg_info_cbmem, dbg_info, sizeof(*dbg_info));
car_set_var(glob_dbg_info_p, dbg_info_cbmem);
}
cbmem: Unify CBMEM init tasks with CBMEM_INIT_HOOK() API Squashed and adjusted two changes from chromium.git. Covers CBMEM init for ROMTAGE and RAMSTAGE. cbmem: Unify random on-CBMEM-init tasks under common CBMEM_INIT_HOOK() API There are several use cases for performing a certain task when CBMEM is first set up (usually to migrate some data into it that was previously kept in BSS/SRAM/hammerspace), and unfortunately we handle each of them differently: timestamp migration is called explicitly from cbmem_initialize(), certain x86-chipset-specific tasks use the CAR_MIGRATION() macro to register a hook, and the CBMEM console is migrated through a direct call from romstage (on non-x86 and SandyBridge boards). This patch decouples the CAR_MIGRATION() hook mechanism from cache-as-RAM and rechristens it to CBMEM_INIT_HOOK(), which is a clearer description of what it really does. All of the above use cases are ported to this new, consistent model, allowing us to have one less line of boilerplate in non-CAR romstages. BRANCH=None BUG=None TEST=Built and booted on Nyan_Blaze and Falco with and without CONFIG_CBMEM_CONSOLE. Confirmed that 'cbmem -c' shows the full log after boot (and the resume log after S3 resume on Falco). Compiled for Parrot, Stout and Lumpy. Original-Change-Id: I1681b372664f5a1f15c3733cbd32b9b11f55f8ea Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/232612 Reviewed-by: Aaron Durbin <adurbin@chromium.org> cbmem: Extend hooks to ramstage, fix timestamp synching Commit 7dd5bbd71 (cbmem: Unify random on-CBMEM-init tasks under common CBMEM_INIT_HOOK() API) inadvertently broke ramstage timestamps since timestamp_sync() was no longer called there. Oops. This patch fixes the issue by extending the CBMEM_INIT_HOOK() mechanism to the cbmem_initialize() call in ramstage. The macro is split into explicit ROMSTAGE_/RAMSTAGE_ versions to make the behavior as clear as possible and prevent surprises (although just using a single macro and relying on the Makefiles to link an object into all appropriate stages would also work). This allows us to get rid of the explicit cbmemc_reinit() in ramstage (which I somehow accounted for in the last patch without realizing that timestamps work exactly the same way...), and replace the older and less flexible cbmem_arch_init() mechanism. Also added a size assertion for the pre-RAM CBMEM console to memlayout that could prevent a very unlikely buffer overflow I just noticed. BRANCH=None BUG=None TEST=Booted on Pinky and Falco, confirmed that ramstage timestamps once again show up. Compile-tested for Rambi and Samus. Original-Change-Id: If907266c3f20dc3d599b5c968ea5b39fe5c00e9c Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/233533 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Change-Id: I1be89bafacfe85cba63426e2d91f5d8d4caa1800 Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com> Signed-off-by: Marc Jones <marc.jones@se-eng.com> Reviewed-on: http://review.coreboot.org/7878 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@chromium.org>
2015-01-07 03:48:43 +01:00
ROMSTAGE_CBMEM_INIT_HOOK(migrate_ehci_debug);
#endif
int dbgp_ep_is_active(struct dbgp_pipe *pipe)
{
return (pipe->status & DBGP_EP_STATMASK) == (DBGP_EP_VALID | DBGP_EP_ENABLED);
}
struct dbgp_pipe *dbgp_console_output(void)
{
return &dbgp_ehci_info()->ep_pipe[DBGP_CONSOLE_EPOUT];
}
struct dbgp_pipe *dbgp_console_input(void)
{
return &dbgp_ehci_info()->ep_pipe[DBGP_CONSOLE_EPIN];
}
int usbdebug_init(void)
{
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
unsigned int ehci_base, dbg_offset;
#if !defined(__PRE_RAM__) && !defined(__SMM__)
if (!get_usbdebug_from_cbmem(dbg_info))
return 0;
#endif
if (ehci_debug_hw_enable(&ehci_base, &dbg_offset))
return -1;
return usbdebug_init_(ehci_base, dbg_offset, dbg_info);
}