mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-27 01:29:27 +00:00
detect_dev
This commit is contained in:
1 parent
72bd5756af
commit
ef57ad6164
1 file changed
+40
-63
+40
-63
@@ -80,10 +80,12 @@ enum
|
|||||||
#define GRUB_DWC2_N_TD 640
|
#define GRUB_DWC2_N_TD 640
|
||||||
|
|
||||||
#define GRUB_DWC2_QH_EMPTY 1
|
#define GRUB_DWC2_QH_EMPTY 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Operational registers offsets */
|
/* Operational registers offsets */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
GRUB_DWC2_COMMAND = 0x00,
|
GRUB_DWC2_COMMAND = 0x00,
|
||||||
GRUB_DWC2_STATUS = 0x04,
|
GRUB_DWC2_STATUS = 0x04,
|
||||||
GRUB_DWC2_INTERRUPT = 0x08,
|
GRUB_DWC2_INTERRUPT = 0x08,
|
||||||
@@ -92,9 +94,11 @@ enum
|
|||||||
GRUB_DWC2_FL_BASE = 0x14,
|
GRUB_DWC2_FL_BASE = 0x14,
|
||||||
GRUB_DWC2_CUR_AL_ADDR = 0x18,
|
GRUB_DWC2_CUR_AL_ADDR = 0x18,
|
||||||
GRUB_DWC2_CONFIG_FLAG = 0x40,
|
GRUB_DWC2_CONFIG_FLAG = 0x40,
|
||||||
GRUB_DWC2_PORT_STAT_CMD = 0x44
|
#endif
|
||||||
|
GRUB_DWC2_PORT_STAT_CMD = 0x440
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* Operational register COMMAND bits */
|
/* Operational register COMMAND bits */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -124,7 +128,7 @@ enum
|
|||||||
GRUB_DWC2_ST_PS_STATUS = (1 << 14),
|
GRUB_DWC2_ST_PS_STATUS = (1 << 14),
|
||||||
GRUB_DWC2_ST_AS_STATUS = (1 << 15)
|
GRUB_DWC2_ST_AS_STATUS = (1 << 15)
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
/* Operational register PORT_STAT_CMD bits */
|
/* Operational register PORT_STAT_CMD bits */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -152,10 +156,11 @@ enum
|
|||||||
GRUB_DWC2_PORT_LINE_UNDEF = (3 << 10),
|
GRUB_DWC2_PORT_LINE_UNDEF = (3 << 10),
|
||||||
GRUB_DWC2_PORT_LINE_LOWSP = GRUB_DWC2_PORT_LINE_K, /* K state means low speed */
|
GRUB_DWC2_PORT_LINE_LOWSP = GRUB_DWC2_PORT_LINE_K, /* K state means low speed */
|
||||||
GRUB_DWC2_PORT_WMASK = ~(GRUB_DWC2_PORT_CONNECT_CH
|
GRUB_DWC2_PORT_WMASK = ~(GRUB_DWC2_PORT_CONNECT_CH
|
||||||
|
| GRUB_DWC2_PORT_ENABLED
|
||||||
| GRUB_DWC2_PORT_ENABLED_CH
|
| GRUB_DWC2_PORT_ENABLED_CH
|
||||||
| GRUB_DWC2_PORT_OVERCUR_CH)
|
| GRUB_DWC2_PORT_OVERCUR_CH)
|
||||||
};
|
};
|
||||||
|
#if 0
|
||||||
/* Operational register CONFIGFLAGS bits */
|
/* Operational register CONFIGFLAGS bits */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -321,8 +326,8 @@ struct grub_dwc2
|
|||||||
grub_uint32_t td_phys;
|
grub_uint32_t td_phys;
|
||||||
grub_dwc2_td_t tdfree_virt; /* Free Transfer Descriptors */
|
grub_dwc2_td_t tdfree_virt; /* Free Transfer Descriptors */
|
||||||
int flag64;
|
int flag64;
|
||||||
grub_uint32_t reset; /* bits 1-15 are flags if port was reset from connected time or not */
|
|
||||||
#endif
|
#endif
|
||||||
|
grub_uint32_t reset; /* bits 1-15 are flags if port was reset from connected time or not */
|
||||||
struct grub_dwc2 *next;
|
struct grub_dwc2 *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -367,6 +372,8 @@ grub_dwc2_ehcc_read8 (struct grub_dwc2 *e, grub_uint32_t addr)
|
|||||||
return *((volatile grub_uint8_t *) e->iobase_ehcc + addr);
|
return *((volatile grub_uint8_t *) e->iobase_ehcc + addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Operational registers access functions */
|
/* Operational registers access functions */
|
||||||
static inline grub_uint32_t
|
static inline grub_uint32_t
|
||||||
grub_dwc2_oper_read32 (struct grub_dwc2 *e, grub_uint32_t addr)
|
grub_dwc2_oper_read32 (struct grub_dwc2 *e, grub_uint32_t addr)
|
||||||
@@ -379,39 +386,39 @@ grub_dwc2_oper_read32 (struct grub_dwc2 *e, grub_uint32_t addr)
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
grub_dwc2_oper_write32 (struct grub_dwc2 *e, grub_uint32_t addr,
|
grub_dwc2_oper_write32 (struct grub_dwc2 *e, grub_uint32_t addr,
|
||||||
grub_uint32_t value)
|
grub_uint32_t value)
|
||||||
{
|
{
|
||||||
*((volatile grub_uint32_t *) e->iobase + (addr / sizeof (grub_uint32_t))) =
|
*((volatile grub_uint32_t *) e->iobase + (addr / sizeof (grub_uint32_t))) =
|
||||||
grub_cpu_to_le32 (value);
|
grub_cpu_to_le32 (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline grub_uint32_t
|
static inline grub_uint32_t
|
||||||
grub_dwc2_port_read (struct grub_dwc2 *e, grub_uint32_t port)
|
grub_dwc2_port_read (struct grub_dwc2 *e)
|
||||||
{
|
{
|
||||||
return grub_dwc2_oper_read32 (e, GRUB_DWC2_PORT_STAT_CMD + port * 4);
|
return grub_dwc2_oper_read32 (e, GRUB_DWC2_PORT_STAT_CMD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
grub_dwc2_port_resbits (struct grub_dwc2 *e, grub_uint32_t port,
|
grub_dwc2_port_resbits (struct grub_dwc2 *e,
|
||||||
grub_uint32_t bits)
|
grub_uint32_t bits)
|
||||||
{
|
{
|
||||||
grub_dwc2_oper_write32 (e, GRUB_DWC2_PORT_STAT_CMD + port * 4,
|
grub_dwc2_oper_write32 (e, GRUB_DWC2_PORT_STAT_CMD,
|
||||||
grub_dwc2_port_read (e,
|
grub_dwc2_port_read (e) & GRUB_DWC2_PORT_WMASK &
|
||||||
port) & GRUB_DWC2_PORT_WMASK &
|
|
||||||
~(bits));
|
~(bits));
|
||||||
grub_dwc2_port_read (e, port);
|
grub_dwc2_port_read (e);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
grub_dwc2_port_setbits (struct grub_dwc2 *e, grub_uint32_t port,
|
grub_dwc2_port_setbits (struct grub_dwc2 *e,
|
||||||
grub_uint32_t bits)
|
grub_uint32_t bits)
|
||||||
{
|
{
|
||||||
grub_dwc2_oper_write32 (e, GRUB_DWC2_PORT_STAT_CMD + port * 4,
|
grub_dwc2_oper_write32 (e, GRUB_DWC2_PORT_STAT_CMD,
|
||||||
(grub_dwc2_port_read (e, port) &
|
(grub_dwc2_port_read (e) &
|
||||||
GRUB_DWC2_PORT_WMASK) | bits);
|
GRUB_DWC2_PORT_WMASK) | bits);
|
||||||
grub_dwc2_port_read (e, port);
|
grub_dwc2_port_read (e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* Halt if DWC2 HC not halted */
|
/* Halt if DWC2 HC not halted */
|
||||||
static grub_usb_err_t
|
static grub_usb_err_t
|
||||||
grub_dwc2_halt (struct grub_dwc2 *e)
|
grub_dwc2_halt (struct grub_dwc2 *e)
|
||||||
@@ -1673,74 +1680,43 @@ grub_dwc2_portstatus (grub_usb_controller_t dev,
|
|||||||
return GRUB_USB_ERR_NONE;
|
return GRUB_USB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static grub_usb_speed_t
|
static grub_usb_speed_t
|
||||||
grub_dwc2_detect_dev (grub_usb_controller_t dev, int port, int *changed)
|
grub_dwc2_detect_dev (grub_usb_controller_t dev, int port __attribute__ ((unused)), int *changed)
|
||||||
{
|
{
|
||||||
struct grub_dwc2 *e = (struct grub_dwc2 *) dev->data;
|
struct grub_dwc2 *e = (struct grub_dwc2 *) dev->data;
|
||||||
grub_uint32_t status, line_state;
|
grub_uint32_t status;
|
||||||
|
|
||||||
status = grub_dwc2_port_read (e, port);
|
status = grub_dwc2_port_read (e);
|
||||||
|
|
||||||
/* Connect Status Change bit - it detects change of connection */
|
/* Connect Status Change bit - it detects change of connection */
|
||||||
if (status & GRUB_DWC2_PORT_CONNECT_CH)
|
if (status & GRUB_DWC2_PORT_CONNECT_CH)
|
||||||
{
|
{
|
||||||
*changed = 1;
|
*changed = 1;
|
||||||
/* Reset bit Connect Status Change */
|
/* Reset bit Connect Status Change */
|
||||||
grub_dwc2_port_setbits (e, port, GRUB_DWC2_PORT_CONNECT_CH);
|
grub_dwc2_port_setbits (e, GRUB_DWC2_PORT_CONNECT_CH);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*changed = 0;
|
*changed = 0;
|
||||||
|
|
||||||
if (!(status & GRUB_DWC2_PORT_CONNECT))
|
if (!(status & GRUB_DWC2_PORT_CONNECT))
|
||||||
{ /* We should reset related "reset" flag in not connected state */
|
{ /* We should reset related "reset" flag in not connected state */
|
||||||
e->reset &= ~(1 << port);
|
e->reset &= ~(1 << 0);
|
||||||
return GRUB_USB_SPEED_NONE;
|
return GRUB_USB_SPEED_NONE;
|
||||||
}
|
}
|
||||||
/* Detected connected state, so we should return speed.
|
switch ((status >> 17) & 3)
|
||||||
* But we can detect only LOW speed device and only at connection
|
|
||||||
* time when PortEnabled=FALSE. FULL / HIGH speed detection is made
|
|
||||||
* later by DWC2-specific reset procedure.
|
|
||||||
* Another thing - if detected speed is LOW at connection time,
|
|
||||||
* we should change port ownership to companion controller.
|
|
||||||
* So:
|
|
||||||
* 1. If we detect connected and enabled and DWC2-owned port,
|
|
||||||
* we can say it is HIGH speed.
|
|
||||||
* 2. If we detect connected and not DWC2-owned port, we can say
|
|
||||||
* NONE speed, because such devices are not handled by DWC2.
|
|
||||||
* 3. If we detect connected, not enabled but reset port, we can say
|
|
||||||
* NONE speed, because it means FULL device connected to port and
|
|
||||||
* such devices are not handled by DWC2.
|
|
||||||
* 4. If we detect connected, not enabled and not reset port, which
|
|
||||||
* has line state != "K", we will say HIGH - it could be FULL or HIGH
|
|
||||||
* device, we will see it later after end of DWC2-specific reset
|
|
||||||
* procedure.
|
|
||||||
* 5. If we detect connected, not enabled and not reset port, which
|
|
||||||
* has line state == "K", we can say NONE speed, because LOW speed
|
|
||||||
* device is connected and we should change port ownership. */
|
|
||||||
if ((status & GRUB_DWC2_PORT_ENABLED) != 0) /* Port already enabled, return high speed. */
|
|
||||||
return GRUB_USB_SPEED_HIGH;
|
|
||||||
if ((status & GRUB_DWC2_PORT_OWNER) != 0) /* DWC2 is not port owner */
|
|
||||||
return GRUB_USB_SPEED_NONE; /* DWC2 driver is ignoring this port. */
|
|
||||||
if ((e->reset & (1 << port)) != 0) /* Port reset was done = FULL speed */
|
|
||||||
return GRUB_USB_SPEED_NONE; /* DWC2 driver is ignoring this port. */
|
|
||||||
else /* Port connected but not enabled - test port speed. */
|
|
||||||
{
|
{
|
||||||
line_state = status & GRUB_DWC2_PORT_LINE_STAT;
|
case 0:
|
||||||
if (line_state != GRUB_DWC2_PORT_LINE_LOWSP)
|
return GRUB_USB_SPEED_HIGH;
|
||||||
return GRUB_USB_SPEED_HIGH;
|
case 1:
|
||||||
/* Detected LOW speed device, we should change
|
return GRUB_USB_SPEED_FULL;
|
||||||
* port ownership.
|
case 2:
|
||||||
* XXX: Fix it!: There should be test if related companion
|
return GRUB_USB_SPEED_LOW;
|
||||||
* controler is available ! And what to do if it does not exist ? */
|
default:
|
||||||
grub_dwc2_port_setbits (e, port, GRUB_DWC2_PORT_OWNER);
|
return GRUB_USB_SPEED_NONE;
|
||||||
return GRUB_USB_SPEED_NONE; /* Ignore this port */
|
|
||||||
/* Note: Reset of PORT_OWNER bit is done by DWC2 HW when
|
|
||||||
* device is really disconnected from port.
|
|
||||||
* Don't do PORT_OWNER bit reset by SW when not connected signal
|
|
||||||
* is detected in port register ! */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_dwc2_restore_hw (void)
|
grub_dwc2_restore_hw (void)
|
||||||
@@ -1781,6 +1757,7 @@ grub_dwc2_fini_hw (int noreturn __attribute__ ((unused)))
|
|||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
#endif
|
#endif
|
||||||
|
// WIP
|
||||||
return GRUB_ERR_NOT_IMPLEMENTED_YET;
|
return GRUB_ERR_NOT_IMPLEMENTED_YET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user