2007-02-28 12:17:02 +01:00
|
|
|
/*
|
2009-07-21 23:20:45 +02:00
|
|
|
* This file is part of the coreboot project.
|
|
|
|
*
|
2007-02-28 12:17:02 +01:00
|
|
|
* Copyright (C) 2006 Eric Biederman (ebiederm@xmission.com)
|
2011-01-28 09:05:54 +01:00
|
|
|
* Copyright (C) 2007 AMD
|
2007-02-28 12:17:02 +01:00
|
|
|
*
|
2009-07-21 23:20:45 +02:00
|
|
|
* 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.
|
|
|
|
*/
|
2010-09-23 20:16:46 +02:00
|
|
|
|
2011-01-28 09:05:54 +01:00
|
|
|
#include <stddef.h>
|
2007-02-28 12:17:02 +01:00
|
|
|
#include <console/console.h>
|
2014-02-05 12:02:55 +01:00
|
|
|
#include <console/usb.h>
|
2007-02-28 12:17:02 +01:00
|
|
|
#include <arch/io.h>
|
2018-12-28 17:53:36 +01:00
|
|
|
#include <arch/symbols.h>
|
2013-06-19 21:25:44 +02:00
|
|
|
#include <arch/early_variables.h>
|
2013-07-28 22:16:47 +02:00
|
|
|
#include <string.h>
|
2013-07-06 10:41:21 +02:00
|
|
|
#include <cbmem.h>
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2014-02-07 18:24:23 +01:00
|
|
|
#include "ehci_debug.h"
|
2014-02-05 12:02:55 +01:00
|
|
|
#include "usb_ch9.h"
|
|
|
|
#include "ehci.h"
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-07-08 17:11:44 +02:00
|
|
|
struct ehci_debug_info {
|
2014-10-27 14:07:20 +01:00
|
|
|
void *ehci_base;
|
2013-07-08 17:11:44 +02:00
|
|
|
void *ehci_debug;
|
|
|
|
|
|
|
|
struct dbgp_pipe ep_pipe[DBGP_MAX_ENDPOINTS];
|
|
|
|
};
|
|
|
|
|
2017-06-24 22:07:25 +02:00
|
|
|
#if IS_ENABLED(CONFIG_DEBUG_USBDEBUG)
|
2013-08-10 09:50:43 +02:00
|
|
|
static void dbgp_print_data(struct ehci_dbg_port *ehci_debug);
|
2013-08-12 15:11:34 +02:00
|
|
|
static int dbgp_enabled(void);
|
|
|
|
# define dprintk(LEVEL, args...) \
|
|
|
|
do { if (!dbgp_enabled()) printk(LEVEL, ##args); } while (0)
|
2011-01-28 09:05:54 +01:00
|
|
|
#else
|
2016-08-25 20:50:50 +02:00
|
|
|
# define dbgp_print_data(x) do {} while (0)
|
|
|
|
# define dprintk(LEVEL, args...) do {} while (0)
|
2011-01-28 09:05:54 +01:00
|
|
|
#endif
|
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
#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
|
|
|
|
|
2013-08-19 11:45:16 +02:00
|
|
|
#define DBGP_MICROFRAME_TIMEOUT_LOOPS 1000
|
|
|
|
#define DBGP_MICROFRAME_RETRIES 10
|
2007-02-28 12:17:02 +01:00
|
|
|
#define DBGP_MAX_PACKET 8
|
|
|
|
|
2013-07-06 10:41:09 +02:00
|
|
|
static struct ehci_debug_info glob_dbg_info CAR_GLOBAL;
|
2014-10-27 07:01:55 +01:00
|
|
|
static struct ehci_debug_info * glob_dbg_info_p CAR_GLOBAL;
|
2013-07-06 10:56:49 +02:00
|
|
|
|
2013-07-11 06:49:46 +02:00
|
|
|
static inline struct ehci_debug_info *dbgp_ehci_info(void)
|
|
|
|
{
|
2018-12-28 17:53:36 +01:00
|
|
|
if (IS_ENABLED(CONFIG_USBDEBUG_IN_PRE_RAM)
|
|
|
|
&& (ENV_ROMSTAGE || ENV_BOOTBLOCK || ENV_VERSTAGE))
|
|
|
|
glob_dbg_info_p =
|
|
|
|
(struct ehci_debug_info *)_car_ehci_dbg_info_start;
|
2014-10-27 07:01:55 +01:00
|
|
|
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);
|
2013-07-11 06:49:46 +02:00
|
|
|
}
|
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
static int dbgp_wait_until_complete(struct ehci_dbg_port *ehci_debug)
|
|
|
|
{
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 ctrl;
|
2013-08-19 11:45:16 +02:00
|
|
|
int loop = 0;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
do {
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
/* Stop when the transaction is finished */
|
|
|
|
if (ctrl & DBGP_DONE)
|
|
|
|
break;
|
2013-08-19 11:45:16 +02:00
|
|
|
} while (++loop < DBGP_MICROFRAME_TIMEOUT_LOOPS);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-08-10 09:50:43 +02:00
|
|
|
if (! (ctrl & DBGP_DONE)) {
|
|
|
|
dprintk(BIOS_ERR, "dbgp_wait_until_complete: retry timeout.\n");
|
2013-08-19 11:45:16 +02:00
|
|
|
return -DBGP_ERR_SIGNAL;
|
2013-08-10 09:50:43 +02:00
|
|
|
}
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
/* Now that we have observed the completed transaction,
|
|
|
|
* clear the done bit.
|
|
|
|
*/
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->control, ctrl | DBGP_DONE);
|
2007-02-28 12:17:02 +01:00
|
|
|
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 */
|
|
|
|
}
|
|
|
|
|
2013-08-10 09:34:01 +02:00
|
|
|
static int dbgp_wait_until_done(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe,
|
2013-08-19 11:45:16 +02:00
|
|
|
unsigned ctrl, const int timeout)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
2013-08-10 09:50:38 +02:00
|
|
|
u32 rd_ctrl, rd_pids;
|
2013-08-10 09:50:43 +02:00
|
|
|
u32 ctrl_prev = 0, pids_prev = 0;
|
2013-08-10 09:50:38 +02:00
|
|
|
u8 lpid;
|
2013-08-19 11:45:16 +02:00
|
|
|
int ret, host_retries;
|
2013-08-19 11:45:16 +02:00
|
|
|
int loop;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2013-08-19 11:45:16 +02:00
|
|
|
loop = 0;
|
|
|
|
device_retry:
|
2013-08-19 11:45:16 +02:00
|
|
|
host_retries = 0;
|
2013-08-19 11:45:16 +02:00
|
|
|
if (loop++ >= timeout)
|
|
|
|
return -DBGP_ERR_BAD;
|
|
|
|
|
2013-08-19 11:45:16 +02:00
|
|
|
host_retry:
|
|
|
|
if (host_retries++ >= DBGP_MICROFRAME_RETRIES)
|
|
|
|
return -DBGP_ERR_BAD;
|
2013-08-10 09:50:43 +02:00
|
|
|
if (loop == 1 || host_retries > 1)
|
|
|
|
dprintk(BIOS_SPEW, "dbgp: start (@ %3d,%d) ctrl=%08x\n",
|
|
|
|
loop, host_retries, ctrl | DBGP_GO);
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->control, ctrl | DBGP_GO);
|
2007-02-28 12:17:02 +01:00
|
|
|
ret = dbgp_wait_until_complete(ehci_debug);
|
2014-12-25 03:43:20 +01:00
|
|
|
rd_ctrl = read32(&ehci_debug->control);
|
|
|
|
rd_pids = read32(&ehci_debug->pids);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-08-10 09:50:43 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-08-19 11:45:16 +02:00
|
|
|
/* Controller hardware failure. */
|
|
|
|
if (ret == -DBGP_ERR_SIGNAL) {
|
2007-02-28 12:17:02 +01:00
|
|
|
return ret;
|
2013-08-19 11:45:16 +02:00
|
|
|
|
|
|
|
/* Bus failure (corrupted microframe). */
|
|
|
|
} else if (ret == -DBGP_ERR_BAD) {
|
|
|
|
goto host_retry;
|
2012-07-25 14:19:45 +02:00
|
|
|
}
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-08-10 09:50:38 +02:00
|
|
|
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)) {
|
2014-01-21 09:44:08 +01:00
|
|
|
pipe->pid ^= USB_PID_DATA_TOGGLE;
|
2013-08-10 09:50:38 +02:00
|
|
|
}
|
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
/* If the port is getting full or it has dropped data
|
|
|
|
* start pacing ourselves, not necessary but it's friendly.
|
|
|
|
*/
|
2013-08-10 09:50:38 +02:00
|
|
|
else if (lpid == USB_PID_NYET) {
|
2007-02-28 12:17:02 +01:00
|
|
|
dbgp_breath();
|
2013-08-19 11:45:16 +02:00
|
|
|
goto device_retry;
|
2013-08-10 09:50:38 +02:00
|
|
|
}
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2013-08-10 09:50:38 +02:00
|
|
|
/* 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))) {
|
2013-08-19 11:45:16 +02:00
|
|
|
goto device_retry;
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
2013-08-10 09:08:38 +02:00
|
|
|
/* Abort on STALL handshake for endpoint 0.*/
|
|
|
|
else if ((lpid == USB_PID_STALL) && (pipe->endpoint == 0x0)) {
|
|
|
|
ret = -DBGP_ERR_BAD;
|
|
|
|
}
|
|
|
|
|
2013-08-10 09:50:43 +02:00
|
|
|
dbgp_print_data(ehci_debug);
|
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dbgp_set_data(struct ehci_dbg_port *ehci_debug, const void *buf, int size)
|
|
|
|
{
|
|
|
|
const unsigned char *bytes = buf;
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 lo, hi;
|
2007-02-28 12:17:02 +01:00
|
|
|
int i;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
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));
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->data03, lo);
|
|
|
|
write32(&ehci_debug->data47, hi);
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dbgp_get_data(struct ehci_dbg_port *ehci_debug, void *buf, int size)
|
|
|
|
{
|
|
|
|
unsigned char *bytes = buf;
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 lo, hi;
|
2007-02-28 12:17:02 +01:00
|
|
|
int i;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2014-12-25 03:43:20 +01:00
|
|
|
lo = read32(&ehci_debug->data03);
|
|
|
|
hi = read32(&ehci_debug->data47);
|
2007-02-28 12:17:02 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-06-24 22:07:25 +02:00
|
|
|
#if IS_ENABLED(CONFIG_DEBUG_USBDEBUG)
|
2013-08-10 09:50:43 +02:00
|
|
|
static void dbgp_print_data(struct ehci_dbg_port *ehci_debug)
|
|
|
|
{
|
2014-12-25 03:43:20 +01:00
|
|
|
u32 ctrl = read32(&ehci_debug->control);
|
|
|
|
u32 lo = read32(&ehci_debug->data03);
|
|
|
|
u32 hi = read32(&ehci_debug->data47);
|
2013-08-10 09:50:43 +02:00
|
|
|
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
|
|
|
|
|
2013-08-10 09:34:01 +02:00
|
|
|
static int dbgp_bulk_write(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe,
|
|
|
|
const char *bytes, int size)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 pids, addr, ctrl;
|
2007-02-28 12:17:02 +01:00
|
|
|
int ret;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
if (size > DBGP_MAX_PACKET)
|
|
|
|
return -1;
|
|
|
|
|
2013-08-10 09:34:01 +02:00
|
|
|
addr = DBGP_EPADDR(pipe->devnum, pipe->endpoint);
|
2013-08-10 09:50:38 +02:00
|
|
|
pids = DBGP_PID_SET(pipe->pid, USB_PID_OUT);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
ctrl = DBGP_LEN_UPDATE(ctrl, size);
|
|
|
|
ctrl |= DBGP_OUT;
|
|
|
|
|
|
|
|
dbgp_set_data(ehci_debug, bytes, size);
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->address, addr);
|
|
|
|
write32(&ehci_debug->pids, pids);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-08-19 11:45:16 +02:00
|
|
|
ret = dbgp_wait_until_done(ehci_debug, pipe, ctrl, pipe->timeout);
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-07-08 17:11:44 +02:00
|
|
|
int dbgp_bulk_write_x(struct dbgp_pipe *pipe, const char *bytes, int size)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
2013-07-08 17:11:44 +02:00
|
|
|
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
|
2013-08-10 09:34:01 +02:00
|
|
|
return dbgp_bulk_write(dbg_info->ehci_debug, pipe, bytes, size);
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
2013-08-10 09:34:01 +02:00
|
|
|
static int dbgp_bulk_read(struct ehci_dbg_port *ehci_debug, struct dbgp_pipe *pipe,
|
2013-08-19 11:45:16 +02:00
|
|
|
void *data, int size)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 pids, addr, ctrl;
|
2007-02-28 12:17:02 +01:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (size > DBGP_MAX_PACKET)
|
|
|
|
return -1;
|
|
|
|
|
2013-08-10 09:34:01 +02:00
|
|
|
addr = DBGP_EPADDR(pipe->devnum, pipe->endpoint);
|
2013-08-10 09:50:38 +02:00
|
|
|
pids = DBGP_PID_SET(pipe->pid, USB_PID_IN);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
ctrl = DBGP_LEN_UPDATE(ctrl, size);
|
|
|
|
ctrl &= ~DBGP_OUT;
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->address, addr);
|
|
|
|
write32(&ehci_debug->pids, pids);
|
2013-08-19 11:45:16 +02:00
|
|
|
ret = dbgp_wait_until_done(ehci_debug, pipe, ctrl, pipe->timeout);
|
2007-02-28 12:17:02 +01:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
if (size > ret)
|
|
|
|
size = ret;
|
|
|
|
dbgp_get_data(ehci_debug, data, size);
|
|
|
|
return ret;
|
|
|
|
}
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2013-07-08 17:11:44 +02:00
|
|
|
int dbgp_bulk_read_x(struct dbgp_pipe *pipe, void *data, int size)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
2013-07-08 17:11:44 +02:00
|
|
|
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
|
2013-08-19 11:45:16 +02:00
|
|
|
return dbgp_bulk_read(dbg_info->ehci_debug, pipe, data, size);
|
2011-01-28 09:05:54 +01:00
|
|
|
}
|
|
|
|
|
2014-02-25 19:11:52 +01:00
|
|
|
void dbgp_mdelay(int ms)
|
2011-01-28 09:05:54 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
while (ms--) {
|
|
|
|
for (i = 0; i < 1000; i++)
|
|
|
|
inb(0x80);
|
|
|
|
}
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
2014-02-25 19:11:52 +01:00
|
|
|
int dbgp_control_msg(struct ehci_dbg_port *ehci_debug, unsigned devnum, int requesttype,
|
2011-01-28 09:05:54 +01:00
|
|
|
int request, int value, int index, void *data, int size)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
2013-08-10 09:34:01 +02:00
|
|
|
struct ehci_debug_info *info = dbgp_ehci_info();
|
|
|
|
struct dbgp_pipe *pipe = &info->ep_pipe[DBGP_SETUP_EP0];
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 pids, addr, ctrl;
|
2007-02-28 12:17:02 +01:00
|
|
|
struct usb_ctrlrequest req;
|
|
|
|
int read;
|
2013-08-10 09:08:38 +02:00
|
|
|
int ret, ret2;
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
read = (requesttype & USB_DIR_IN) != 0;
|
2013-08-10 09:08:38 +02:00
|
|
|
if (size > DBGP_MAX_PACKET)
|
2007-02-28 12:17:02 +01:00
|
|
|
return -1;
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
/* Compute the control message */
|
|
|
|
req.bRequestType = requesttype;
|
|
|
|
req.bRequest = request;
|
2011-01-28 09:05:54 +01:00
|
|
|
req.wValue = cpu_to_le16(value);
|
|
|
|
req.wIndex = cpu_to_le16(index);
|
|
|
|
req.wLength = cpu_to_le16(size);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-08-10 09:34:01 +02:00
|
|
|
pipe->devnum = devnum;
|
|
|
|
pipe->endpoint = 0;
|
2013-08-10 09:50:38 +02:00
|
|
|
pipe->pid = USB_PID_DATA0;
|
2013-08-19 11:45:16 +02:00
|
|
|
pipe->timeout = 1000;
|
2013-08-10 09:34:01 +02:00
|
|
|
addr = DBGP_EPADDR(pipe->devnum, pipe->endpoint);
|
2013-08-10 09:50:38 +02:00
|
|
|
pids = DBGP_PID_SET(pipe->pid, USB_PID_SETUP);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
ctrl = DBGP_LEN_UPDATE(ctrl, sizeof(req));
|
|
|
|
ctrl |= DBGP_OUT;
|
|
|
|
|
2013-08-10 09:08:38 +02:00
|
|
|
/* Setup stage */
|
2007-02-28 12:17:02 +01:00
|
|
|
dbgp_set_data(ehci_debug, &req, sizeof(req));
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->address, addr);
|
|
|
|
write32(&ehci_debug->pids, pids);
|
2013-08-19 11:45:16 +02:00
|
|
|
ret = dbgp_wait_until_done(ehci_debug, pipe, ctrl, 1);
|
2007-02-28 12:17:02 +01:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2013-08-10 09:08:38 +02:00
|
|
|
/* Data stage (optional) */
|
|
|
|
if (read && size)
|
2013-08-19 11:45:16 +02:00
|
|
|
ret = dbgp_bulk_read(ehci_debug, pipe, data, size);
|
2013-08-10 09:08:38 +02:00
|
|
|
else if (!read && size)
|
|
|
|
ret = dbgp_bulk_write(ehci_debug, pipe, data, size);
|
|
|
|
|
|
|
|
/* Status stage in opposite direction */
|
|
|
|
pipe->pid = USB_PID_DATA1;
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2013-08-10 09:08:38 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->pids, pids);
|
2013-08-19 11:45:16 +02:00
|
|
|
ret2 = dbgp_wait_until_done(ehci_debug, pipe, ctrl, pipe->timeout);
|
2013-08-10 09:08:38 +02:00
|
|
|
if (ret2 < 0)
|
|
|
|
return ret2;
|
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ehci_reset_port(struct ehci_regs *ehci_regs, int port)
|
|
|
|
{
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 portsc;
|
2007-02-28 12:17:02 +01:00
|
|
|
int loop;
|
|
|
|
|
|
|
|
/* Reset the usb debug port */
|
2014-12-25 03:43:20 +01:00
|
|
|
portsc = read32(&ehci_regs->port_status[port - 1]);
|
2007-02-28 12:17:02 +01:00
|
|
|
portsc &= ~PORT_PE;
|
|
|
|
portsc |= PORT_RESET;
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_regs->port_status[port - 1], portsc);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-08-12 20:35:20 +02:00
|
|
|
dbgp_mdelay(HUB_ROOT_RESET_TIME);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2014-12-25 03:43:20 +01:00
|
|
|
portsc = read32(&ehci_regs->port_status[port - 1]);
|
|
|
|
write32(&ehci_regs->port_status[port - 1],
|
2013-08-12 20:35:20 +02:00
|
|
|
portsc & ~(PORT_RWC_BITS | PORT_RESET));
|
|
|
|
|
|
|
|
loop = 100;
|
|
|
|
do {
|
|
|
|
dbgp_mdelay(1);
|
2014-12-25 03:43:20 +01:00
|
|
|
portsc = read32(&ehci_regs->port_status[port - 1]);
|
2013-08-12 20:35:20 +02:00
|
|
|
} 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;
|
|
|
|
|
2011-01-28 09:05:54 +01:00
|
|
|
return -3; //-EBUSY;
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
2011-01-28 09:05:54 +01:00
|
|
|
static int ehci_wait_for_port(struct ehci_regs *ehci_regs, int port)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
2011-01-28 09:05:54 +01:00
|
|
|
u32 status;
|
2007-02-28 12:17:02 +01:00
|
|
|
int ret, reps;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
for (reps = 0; reps < 3; reps++) {
|
|
|
|
dbgp_mdelay(100);
|
2014-12-25 03:43:20 +01:00
|
|
|
status = read32(&ehci_regs->status);
|
2007-02-28 12:17:02 +01:00
|
|
|
if (status & STS_PCD) {
|
|
|
|
ret = ehci_reset_port(ehci_regs, port);
|
|
|
|
if (ret == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2011-01-28 09:05:54 +01:00
|
|
|
return -1; //-ENOTCONN;
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
2013-08-23 22:33:16 +02:00
|
|
|
|
2013-08-15 15:27:06 +02:00
|
|
|
|
2013-07-06 10:56:49 +02:00
|
|
|
static int usbdebug_init_(unsigned ehci_bar, unsigned offset, struct ehci_debug_info *info)
|
2007-02-28 12:17:02 +01:00
|
|
|
{
|
|
|
|
struct ehci_caps *ehci_caps;
|
|
|
|
struct ehci_regs *ehci_regs;
|
2011-01-28 09:05:54 +01:00
|
|
|
|
|
|
|
u32 cmd, ctrl, status, portsc, hcs_params;
|
|
|
|
u32 debug_port, new_debug_port = 0, n_ports;
|
2014-10-27 13:07:28 +01:00
|
|
|
int ret, i;
|
2007-02-28 12:17:02 +01:00
|
|
|
int loop;
|
2011-01-28 09:05:54 +01:00
|
|
|
int port_map_tried;
|
|
|
|
int playtimes = 3;
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2014-10-27 14:07:20 +01:00
|
|
|
/* 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);
|
|
|
|
|
2014-02-09 18:21:30 +01:00
|
|
|
dprintk(BIOS_INFO, "ehci_bar: 0x%x debug_offset 0x%x\n", ehci_bar, offset);
|
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
ehci_caps = (struct ehci_caps *)ehci_bar;
|
2011-10-31 20:56:45 +01:00
|
|
|
ehci_regs = (struct ehci_regs *)(ehci_bar +
|
2014-12-25 03:43:20 +01:00
|
|
|
HC_LENGTH(read32(&ehci_caps->hc_capbase)));
|
2014-10-27 14:07:20 +01:00
|
|
|
|
|
|
|
struct ehci_dbg_port *ehci_debug = info->ehci_debug;
|
2013-08-12 19:40:37 +02:00
|
|
|
|
|
|
|
if (CONFIG_USBDEBUG_DEFAULT_PORT > 0)
|
2014-02-07 18:24:23 +01:00
|
|
|
ehci_debug_select_port(CONFIG_USBDEBUG_DEFAULT_PORT);
|
2013-08-12 19:40:37 +02:00
|
|
|
else
|
2014-02-07 18:24:23 +01:00
|
|
|
ehci_debug_select_port(1);
|
2013-08-12 19:40:37 +02:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
try_next_time:
|
|
|
|
port_map_tried = 0;
|
|
|
|
|
|
|
|
try_next_port:
|
2014-12-25 03:43:20 +01:00
|
|
|
hcs_params = read32(&ehci_caps->hcs_params);
|
2007-02-28 12:17:02 +01:00
|
|
|
debug_port = HCS_DEBUG_PORT(hcs_params);
|
|
|
|
n_ports = HCS_N_PORTS(hcs_params);
|
|
|
|
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "debug_port: %d\n", debug_port);
|
|
|
|
dprintk(BIOS_INFO, "n_ports: %d\n", n_ports);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2017-07-24 04:00:04 +02:00
|
|
|
for (i = 1; i <= n_ports; i++) {
|
|
|
|
portsc = read32(&ehci_regs->port_status[i-1]);
|
|
|
|
dprintk(BIOS_INFO, "PORTSC #%d: %08x\n", i, portsc);
|
|
|
|
}
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2016-08-25 20:50:50 +02:00
|
|
|
if (port_map_tried && (new_debug_port != debug_port)) {
|
|
|
|
if (--playtimes) {
|
2014-02-07 18:24:23 +01:00
|
|
|
ehci_debug_select_port(debug_port);
|
2007-02-28 12:17:02 +01:00
|
|
|
goto try_next_time;
|
|
|
|
}
|
2011-01-28 09:05:54 +01:00
|
|
|
return -1;
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
2013-08-12 14:32:25 +02:00
|
|
|
/* Wait until the controller is halted */
|
2014-12-25 03:43:20 +01:00
|
|
|
status = read32(&ehci_regs->status);
|
2013-08-12 14:32:25 +02:00
|
|
|
if (!(status & STS_HALT)) {
|
2014-12-25 03:43:20 +01:00
|
|
|
cmd = read32(&ehci_regs->command);
|
2013-08-12 14:32:25 +02:00
|
|
|
cmd &= ~CMD_RUN;
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_regs->command, cmd);
|
2013-08-12 14:32:25 +02:00
|
|
|
loop = 100;
|
|
|
|
do {
|
|
|
|
dbgp_mdelay(10);
|
2014-12-25 03:43:20 +01:00
|
|
|
status = read32(&ehci_regs->status);
|
2013-08-12 14:32:25 +02:00
|
|
|
} 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");
|
|
|
|
}
|
|
|
|
|
2011-01-28 09:05:54 +01:00
|
|
|
loop = 100;
|
2007-02-28 12:17:02 +01:00
|
|
|
/* Reset the EHCI controller */
|
2014-12-25 03:43:20 +01:00
|
|
|
cmd = read32(&ehci_regs->command);
|
2007-02-28 12:17:02 +01:00
|
|
|
cmd |= CMD_RESET;
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_regs->command, cmd);
|
2007-02-28 12:17:02 +01:00
|
|
|
do {
|
2011-01-28 09:05:54 +01:00
|
|
|
dbgp_mdelay(10);
|
2014-12-25 03:43:20 +01:00
|
|
|
cmd = read32(&ehci_regs->command);
|
2007-02-28 12:17:02 +01:00
|
|
|
} while ((cmd & CMD_RESET) && (--loop > 0));
|
|
|
|
|
2016-08-25 20:50:50 +02:00
|
|
|
if (!loop) {
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "Could not reset EHCI controller.\n");
|
2011-01-28 09:05:54 +01:00
|
|
|
// on some systems it works without succeeding here.
|
|
|
|
// return -2;
|
|
|
|
} else {
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "EHCI controller reset successfully.\n");
|
2011-01-28 09:05:54 +01:00
|
|
|
}
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
/* Claim ownership, but do not enable yet */
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
ctrl |= DBGP_OWNER;
|
|
|
|
ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->control, ctrl);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2011-01-28 09:05:54 +01:00
|
|
|
/* Start EHCI controller */
|
2014-12-25 03:43:20 +01:00
|
|
|
cmd = read32(&ehci_regs->command);
|
2007-02-28 12:17:02 +01:00
|
|
|
cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
|
|
|
|
cmd |= CMD_RUN;
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_regs->command, cmd);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
/* Ensure everything is routed to the EHCI */
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_regs->configured_flag, FLAG_CF);
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
/* Wait until the controller is no longer halted */
|
|
|
|
loop = 10;
|
|
|
|
do {
|
2011-01-28 09:05:54 +01:00
|
|
|
dbgp_mdelay(10);
|
2014-12-25 03:43:20 +01:00
|
|
|
status = read32(&ehci_regs->status);
|
2011-01-28 09:05:54 +01:00
|
|
|
} while ((status & STS_HALT) && (--loop > 0));
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2016-08-25 20:50:50 +02:00
|
|
|
if (!loop) {
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "EHCI could not be started.\n");
|
2011-01-28 09:05:54 +01:00
|
|
|
return -3;
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "EHCI started.\n");
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
/* Wait for a device to show up in the debug port */
|
|
|
|
ret = ehci_wait_for_port(ehci_regs, debug_port);
|
|
|
|
if (ret < 0) {
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "No device found in debug port %d\n", debug_port);
|
2007-02-28 12:17:02 +01:00
|
|
|
goto next_debug_port;
|
|
|
|
}
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "EHCI done waiting for port.\n");
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2014-10-27 14:07:20 +01:00
|
|
|
|
2007-02-28 12:17:02 +01:00
|
|
|
/* Enable the debug port */
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
ctrl |= DBGP_CLAIM;
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->control, ctrl);
|
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "No device in EHCI debug port.\n");
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->control, ctrl & ~DBGP_CLAIM);
|
2011-01-28 09:05:54 +01:00
|
|
|
ret = -4;
|
2007-02-28 12:17:02 +01:00
|
|
|
goto err;
|
|
|
|
}
|
2013-08-12 15:11:34 +02:00
|
|
|
dprintk(BIOS_INFO, "EHCI debug port enabled.\n");
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2013-06-06 09:33:39 +02:00
|
|
|
#if 0
|
2007-02-28 12:17:02 +01:00
|
|
|
/* Completely transfer the debug device to the debug controller */
|
2014-12-25 03:43:20 +01:00
|
|
|
portsc = read32(&ehci_regs->port_status[debug_port - 1]);
|
2007-02-28 12:17:02 +01:00
|
|
|
portsc &= ~PORT_PE;
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_regs->port_status[debug_port - 1], portsc);
|
2013-06-06 09:33:39 +02:00
|
|
|
#endif
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
dbgp_mdelay(100);
|
|
|
|
|
2014-02-25 19:11:52 +01:00
|
|
|
ret = dbgp_probe_gadget(info->ehci_debug, &info->ep_pipe[0]);
|
2013-08-23 22:33:16 +02:00
|
|
|
if (ret < 0) {
|
2014-02-25 19:11:52 +01:00
|
|
|
dprintk(BIOS_INFO, "Could not probe gadget on debug port.\n");
|
2013-08-23 22:33:16 +02:00
|
|
|
ret = -6;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2011-01-28 09:05:54 +01:00
|
|
|
return 0;
|
2007-02-28 12:17:02 +01:00
|
|
|
err:
|
|
|
|
/* Things didn't work so remove my claim */
|
2014-12-25 03:43:20 +01:00
|
|
|
ctrl = read32(&ehci_debug->control);
|
2007-02-28 12:17:02 +01:00
|
|
|
ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
|
2014-12-25 03:43:20 +01:00
|
|
|
write32(&ehci_debug->control, ctrl);
|
2011-01-28 09:05:54 +01:00
|
|
|
//return ret;
|
2007-02-28 12:17:02 +01:00
|
|
|
|
|
|
|
next_debug_port:
|
2017-06-24 22:07:25 +02:00
|
|
|
#if CONFIG_USBDEBUG_DEFAULT_PORT == 0
|
2011-01-28 09:05:54 +01:00
|
|
|
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)) {
|
2014-02-07 18:24:23 +01:00
|
|
|
ehci_debug_select_port(new_debug_port);
|
2007-02-28 12:17:02 +01:00
|
|
|
goto try_next_port;
|
|
|
|
}
|
2011-01-28 09:05:54 +01:00
|
|
|
if (--playtimes) {
|
2014-02-07 18:24:23 +01:00
|
|
|
ehci_debug_select_port(new_debug_port);
|
2007-02-28 12:17:02 +01:00
|
|
|
goto try_next_time;
|
|
|
|
}
|
2013-08-12 19:40:37 +02:00
|
|
|
#else
|
|
|
|
if (0)
|
|
|
|
goto try_next_port;
|
|
|
|
if (--playtimes)
|
|
|
|
goto try_next_time;
|
|
|
|
#endif
|
2007-02-28 12:17:02 +01:00
|
|
|
|
2011-01-28 09:05:54 +01:00
|
|
|
return -10;
|
2007-02-28 12:17:02 +01:00
|
|
|
}
|
|
|
|
|
2013-08-12 15:11:34 +02:00
|
|
|
static int dbgp_enabled(void)
|
|
|
|
{
|
|
|
|
struct dbgp_pipe *globals = &dbgp_ehci_info()->ep_pipe[DBGP_SETUP_EP0];
|
|
|
|
return (globals->status & DBGP_EP_ENABLED);
|
|
|
|
}
|
|
|
|
|
2014-02-09 22:35:39 +01:00
|
|
|
int dbgp_try_get(struct dbgp_pipe *pipe)
|
2013-08-12 15:11:34 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-02-09 22:35:39 +01:00
|
|
|
void dbgp_put(struct dbgp_pipe *pipe)
|
2013-08-12 15:11:34 +02:00
|
|
|
{
|
|
|
|
struct dbgp_pipe *globals = &dbgp_ehci_info()->ep_pipe[DBGP_SETUP_EP0];
|
|
|
|
globals->status &= ~DBGP_EP_BUSY;
|
|
|
|
pipe->status &= ~DBGP_EP_BUSY;
|
|
|
|
}
|
|
|
|
|
2017-09-07 18:16:27 +02:00
|
|
|
#if ENV_RAMSTAGE
|
2014-02-07 18:24:23 +01:00
|
|
|
void usbdebug_re_enable(unsigned ehci_base)
|
2013-07-09 03:19:22 +02:00
|
|
|
{
|
2013-07-11 06:49:46 +02:00
|
|
|
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
|
2013-07-09 03:19:22 +02:00
|
|
|
unsigned diff;
|
2013-07-08 17:11:44 +02:00
|
|
|
int i;
|
2013-07-09 03:19:22 +02:00
|
|
|
|
2014-10-27 14:07:20 +01:00
|
|
|
diff = (unsigned)dbg_info->ehci_base - ehci_base;
|
2013-07-09 03:19:22 +02:00
|
|
|
dbg_info->ehci_debug -= diff;
|
2018-07-08 12:33:47 +02:00
|
|
|
dbg_info->ehci_base = (void *)ehci_base;
|
2013-07-08 17:11:44 +02:00
|
|
|
|
|
|
|
for (i=0; i<DBGP_MAX_ENDPOINTS; i++)
|
2014-10-27 14:07:20 +01:00
|
|
|
if (dbg_info->ep_pipe[i].status & DBGP_EP_VALID)
|
|
|
|
dbg_info->ep_pipe[i].status |= DBGP_EP_ENABLED;
|
2013-07-09 03:19:22 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 18:24:23 +01:00
|
|
|
void usbdebug_disable(void)
|
2013-07-09 03:19:22 +02:00
|
|
|
{
|
2013-07-11 06:49:46 +02:00
|
|
|
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
|
2013-07-08 17:11:44 +02:00
|
|
|
int i;
|
|
|
|
for (i=0; i<DBGP_MAX_ENDPOINTS; i++)
|
|
|
|
dbg_info->ep_pipe[i].status &= ~DBGP_EP_ENABLED;
|
2013-07-09 03:19:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2018-12-29 08:40:40 +01:00
|
|
|
int usbdebug_hw_init(bool force)
|
2013-07-06 10:41:21 +02:00
|
|
|
{
|
2017-09-07 18:16:27 +02:00
|
|
|
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
|
|
|
|
unsigned int ehci_base, dbg_offset;
|
2013-07-06 10:41:21 +02:00
|
|
|
|
2018-12-29 08:40:40 +01:00
|
|
|
if (dbgp_enabled() && !force)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Do not attempt slow gadget init in postcar. */
|
|
|
|
if (ENV_POSTCAR)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Do full init if state claims we are still not enabled. */
|
2017-09-07 18:16:27 +02:00
|
|
|
if (ehci_debug_hw_enable(&ehci_base, &dbg_offset))
|
2013-07-06 10:41:21 +02:00
|
|
|
return -1;
|
2017-09-07 18:16:27 +02:00
|
|
|
return usbdebug_init_(ehci_base, dbg_offset, dbg_info);
|
2013-07-06 10:41:21 +02:00
|
|
|
}
|
|
|
|
|
2015-06-09 20:54:10 +02:00
|
|
|
static void migrate_ehci_debug(int is_recovery)
|
2013-07-06 10:41:21 +02:00
|
|
|
{
|
|
|
|
struct ehci_debug_info *dbg_info_cbmem;
|
2017-09-07 18:16:27 +02:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
if (ENV_ROMSTAGE) {
|
|
|
|
/* Move state from CAR to CBMEM. */
|
|
|
|
struct ehci_debug_info *dbg_info = dbgp_ehci_info();
|
|
|
|
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);
|
2013-07-06 10:41:21 +02:00
|
|
|
return;
|
2017-09-07 18:16:27 +02:00
|
|
|
}
|
|
|
|
|
2018-12-28 15:48:58 +01:00
|
|
|
if (IS_ENABLED(CONFIG_USBDEBUG_IN_PRE_RAM)) {
|
2017-09-07 18:16:27 +02:00
|
|
|
/* Use state in CBMEM. */
|
|
|
|
dbg_info_cbmem = cbmem_find(CBMEM_ID_EHCI_DEBUG);
|
|
|
|
if (dbg_info_cbmem)
|
|
|
|
car_set_var(glob_dbg_info_p, dbg_info_cbmem);
|
|
|
|
}
|
|
|
|
|
2018-12-29 08:40:40 +01:00
|
|
|
rv = usbdebug_hw_init(false);
|
2017-09-07 18:16:27 +02:00
|
|
|
if (rv < 0)
|
|
|
|
printk(BIOS_DEBUG, "usbdebug: Failed hardware init\n");
|
|
|
|
else
|
|
|
|
printk(BIOS_DEBUG, "usbdebug: " ENV_STRING " starting...\n");
|
2013-07-06 10:41:21 +02:00
|
|
|
}
|
2017-09-07 18:16:27 +02:00
|
|
|
|
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);
|
2017-09-07 18:16:27 +02:00
|
|
|
POSTCAR_CBMEM_INIT_HOOK(migrate_ehci_debug);
|
|
|
|
RAMSTAGE_CBMEM_INIT_HOOK(migrate_ehci_debug);
|
2013-07-06 10:41:21 +02:00
|
|
|
|
2013-07-08 17:11:44 +02:00
|
|
|
int dbgp_ep_is_active(struct dbgp_pipe *pipe)
|
2013-07-05 20:38:54 +02:00
|
|
|
{
|
2013-07-08 17:11:44 +02:00
|
|
|
return (pipe->status & DBGP_EP_STATMASK) == (DBGP_EP_VALID | DBGP_EP_ENABLED);
|
2011-01-28 09:05:54 +01:00
|
|
|
}
|
2013-07-06 10:56:49 +02:00
|
|
|
|
2013-07-08 17:11:44 +02:00
|
|
|
struct dbgp_pipe *dbgp_console_output(void)
|
2013-07-06 10:56:49 +02:00
|
|
|
{
|
2013-07-08 17:11:44 +02:00
|
|
|
return &dbgp_ehci_info()->ep_pipe[DBGP_CONSOLE_EPOUT];
|
2013-07-11 06:49:46 +02:00
|
|
|
}
|
|
|
|
|
2013-07-08 17:11:44 +02:00
|
|
|
struct dbgp_pipe *dbgp_console_input(void)
|
2013-07-11 06:49:46 +02:00
|
|
|
{
|
2013-07-08 17:11:44 +02:00
|
|
|
return &dbgp_ehci_info()->ep_pipe[DBGP_CONSOLE_EPIN];
|
2013-07-06 10:56:49 +02:00
|
|
|
}
|
|
|
|
|
2017-09-07 18:16:27 +02:00
|
|
|
void usbdebug_init(void)
|
2013-07-06 10:56:49 +02:00
|
|
|
{
|
2017-09-07 18:16:27 +02:00
|
|
|
/* USB console init is done early in romstage, yet delayed to
|
|
|
|
* CBMEM_INIT_HOOKs for postcar and ramstage as we recover state
|
|
|
|
* from CBMEM.
|
|
|
|
*/
|
2018-12-28 15:48:58 +01:00
|
|
|
if (IS_ENABLED(CONFIG_USBDEBUG_IN_PRE_RAM)
|
|
|
|
&& (ENV_ROMSTAGE || ENV_BOOTBLOCK))
|
2018-12-29 08:40:40 +01:00
|
|
|
usbdebug_hw_init(false);
|
2013-07-06 10:41:09 +02:00
|
|
|
|
2017-09-07 18:16:27 +02:00
|
|
|
/* USB console init is done early in ramstage if it was
|
|
|
|
* not done in romstage, this does not require CBMEM.
|
|
|
|
*/
|
2018-12-28 15:48:58 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_USBDEBUG_IN_PRE_RAM) && ENV_RAMSTAGE)
|
2018-12-29 08:40:40 +01:00
|
|
|
usbdebug_hw_init(false);
|
2013-07-06 10:56:49 +02:00
|
|
|
}
|