Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usb: Adapt USB stack to work on ia32 #525

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _targets/Makefile.ia32-generic
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
# Copyright 2019 Phoenix Systems
#

DEFAULT_COMPONENTS := pc-tty uart16550 pc-ata
DEFAULT_COMPONENTS := pc-tty uart16550 pc-ata libusbehci umass
8 changes: 6 additions & 2 deletions usb/ehci/Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#
# Makefile for Phoenix-RTOS imx6ull-ehci
# Makefile for Phoenix-RTOS ehci
#
# Copyright 2018, 2019 Phoenix Systems
#

# FIXME: rename usb host component
NAME := libusbehci
LOCAL_SRCS := ehci.c ehci-hub.c phy-$(TARGET_SUBFAMILY).c
LOCAL_SRCS := ehci.c ehci-hub.c phy-$(TARGET_FAMILY)-$(TARGET_SUBFAMILY).c

ifneq (,$(findstring imx,$(TARGET_SUBFAMILY)))
CFLAGS += -DEHCI_IMX
endif

include $(static-lib.mk)
22 changes: 15 additions & 7 deletions usb/ehci/ehci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#include <sys/minmax.h>

#include <hcd.h>

Check failure on line 23 in usb/ehci/ehci-hub.c

View workflow job for this annotation

GitHub Actions / call-ci / build (ia32-generic-pc)

hcd.h: No such file or directory

Check failure on line 23 in usb/ehci/ehci-hub.c

View workflow job for this annotation

GitHub Actions / call-ci / build (ia32-generic-qemu)

hcd.h: No such file or directory
#include <hub.h>
#include "ehci.h"

Expand Down Expand Up @@ -87,17 +87,23 @@
static void ehci_resetPort(hcd_t *hcd, int port)
{
ehci_t *ehci = (ehci_t *)hcd->priv;
volatile int *reg = (hcd->base + portsc1) + (port - 1);
volatile int *reg = (ehci->opbase + portsc1) + (port - 1);

*reg &= ~PORTSC_ENA;
*reg |= PORTSC_PR;

#ifdef EHCI_IMX
/*
* This is imx deviation. According to ehci documentation
* imx deviation: According to ehci documentation
* it is up to software to set the PR bit 0 after waiting 20ms
*/
while (*reg & PORTSC_PR)
;
usleep(20 * 1000);
#else
usleep(20 * 1000);
*reg &= ~PORTSC_PR;
#endif

ehci->portResetChange = 1 << port;

Expand All @@ -118,7 +124,7 @@
status->wPortChange = 0;
status->wPortStatus = 0;

val = *(hcd->base + portsc1 + port - 1);
val = *(ehci->opbase + portsc1 + port - 1);
if (val & PORTSC_CCS)
status->wPortStatus |= USB_PORT_STAT_CONNECTION;

Expand Down Expand Up @@ -192,7 +198,7 @@
{
hcd_t *hcd = hub->hcd;
ehci_t *ehci = (ehci_t *)hcd->priv;
volatile int *portsc = hcd->base + portsc1 + port - 1;
volatile int *portsc = ehci->opbase + portsc1 + port - 1;
uint32_t val = *portsc;

if (port > hub->nports)
Expand Down Expand Up @@ -285,6 +291,7 @@
static int ehci_getDesc(usb_dev_t *hub, int type, int index, char *buf, size_t size)
{
hcd_t *hcd = hub->hcd;
ehci_t *ehci = (ehci_t *)hcd->priv;
usb_hub_desc_t *hdesc;
int bytes = 0;

Expand All @@ -309,7 +316,7 @@
hdesc->wHubCharacteristics = 0x1;
hdesc->bPwrOn2PwrGood = 10;
hdesc->bHubContrCurrent = 10;
hdesc->bNbrPorts = *(hcd->base + hcsparams) & 0xf;
hdesc->bNbrPorts = *(ehci->base + hcsparams) & 0xf;
hdesc->variable[0] = 0; /* Device not removable */
hdesc->variable[1] = 0xff; /* PortPwrCtrlMask */
break;
Expand Down Expand Up @@ -340,12 +347,13 @@
{
usb_setup_packet_t *setup = t->setup;
int ret;
ehci_t *ehci = (ehci_t *)hub->hcd->priv;

/* It will be finished, when a port status changes */
if (t->type == usb_transfer_interrupt) {
/* Enable Port Status Changed interrupt if this is a first call */
if ((*(hub->hcd->base + usbintr) & USBSTS_PCI) == 0)
*(hub->hcd->base + usbintr) |= USBSTS_PCI;
if ((*(ehci->opbase + usbintr) & USBSTS_PCI) == 0)
*(ehci->opbase + usbintr) |= USBSTS_PCI;
return 0;
}

Expand Down
83 changes: 62 additions & 21 deletions usb/ehci/ehci.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <usbhost.h>

Check failure on line 29 in usb/ehci/ehci.c

View workflow job for this annotation

GitHub Actions / call-ci / build (ia32-generic-pc)

usbhost.h: No such file or directory

Check failure on line 29 in usb/ehci/ehci.c

View workflow job for this annotation

GitHub Actions / call-ci / build (ia32-generic-qemu)

usbhost.h: No such file or directory
#include <stdio.h>

#include <hub.h>
Expand All @@ -34,32 +34,42 @@

#include "ehci.h"

#ifdef EHCI_IMX
#define EHCI_PERIODIC_SIZE 128
#else
#define EHCI_PERIODIC_SIZE 1024
#endif


static inline void ehci_memDmb(void)
{
asm volatile ("dmb" ::: "memory");
#ifdef EHCI_IMX
asm volatile("dmb" ::: "memory");
#else
__sync_synchronize();
#endif
Comment on lines +46 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://godbolt.org/z/1q4s7Gsbe

Suggested change
#ifdef EHCI_IMX
asm volatile("dmb" ::: "memory");
#else
__sync_synchronize();
#endif
__sync_synchronize();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GCC won't reduce __sync_synchronize() to dmb prior to 9.3.1, see e.g. 9.2.1 https://godbolt.org/z/orPnWevvn

}


static void ehci_startAsync(hcd_t *hcd)
{
ehci_t *ehci = (ehci_t *)hcd->priv;

*(hcd->base + asynclistaddr) = va2pa((void *)ehci->asyncList->hw);
*(hcd->base + usbcmd) |= USBCMD_ASE;
*(ehci->opbase + asynclistaddr) = va2pa((void *)ehci->asyncList->hw);
*(ehci->opbase + usbcmd) |= USBCMD_ASE;
ehci_memDmb();
while ((*(hcd->base + usbsts) & USBSTS_AS) == 0)
while ((*(ehci->opbase + usbsts) & USBSTS_AS) == 0)
;
}


static void ehci_stopAsync(hcd_t *hcd)
{
*(hcd->base + usbcmd) &= ~USBCMD_ASE;
ehci_t *ehci = (ehci_t *)hcd->priv;

*(ehci->opbase + usbcmd) &= ~USBCMD_ASE;
ehci_memDmb();
while ((*(hcd->base + usbsts) & USBSTS_AS) != 0)
while ((*(ehci->opbase + usbsts) & USBSTS_AS) != 0)
;
}

Expand Down Expand Up @@ -488,19 +498,19 @@
ehci_t *ehci = (ehci_t *)hcd->priv;
uint32_t currentStatus;

currentStatus = *(hcd->base + usbsts);
currentStatus = *(ehci->opbase + usbsts);
do {
*(hcd->base + usbsts) = currentStatus & EHCI_INTRMASK;
*(ehci->opbase + usbsts) = currentStatus & EHCI_INTRMASK;

ehci->status |= currentStatus;

/* For edge triggered interrupts to prevent losing interrupts,
* poll the usbsts register until it is stable */
currentStatus = *(hcd->base + usbsts);
currentStatus = *(ehci->opbase + usbsts);
} while ((currentStatus & EHCI_INTRMASK) != 0);

if (ehci->status & USBSTS_PCI)
ehci->portsc = *(hcd->base + portsc1);
ehci->portsc = *(ehci->opbase + portsc1);

return -!(ehci->status & EHCI_INTRMASK);
}
Expand Down Expand Up @@ -594,8 +604,9 @@
mutexUnlock(hcd->transLock);
}

if (ehci->status & USBSTS_PCI)
if (ehci->status & USBSTS_PCI) {
ehci_portStatusChanged(hcd);
}
}
}

Expand Down Expand Up @@ -671,7 +682,7 @@

/* Data stage */
if ((t->type == usb_transfer_control && t->size > 0) || t->type == usb_transfer_bulk ||
t->type == usb_transfer_interrupt) {
t->type == usb_transfer_interrupt) {
if (ehci_qtdAdd(hcd->priv, &qtds, token, pipe->maxPacketLen, t->buffer, t->size, 1) < 0) {
ehci_qtdsPut(hcd->priv, &qtds);
t->hcdpriv = NULL;
Expand Down Expand Up @@ -838,27 +849,57 @@
ehci_free(ehci);
return -ENOMEM;
}

interrupt(hcd->info->irq, ehci_irqHandler, hcd, ehci->irqCond, &ehci->irqHandle);

if (((addr_t)hcd->base & (0x20 - 1)) != 0) {
fprintf(stderr, "ehci: USBBASE not aligned to 32 bits\n");
ehci_free(ehci);
return -EINVAL;
}

/* Set USBBASE */
ehci->base = hcd->base;

#ifdef EHCI_IMX
/* imx deviation: Here we don't distinguish between base/opbase addresses, as
* the distance between operational register base and USBBASE is a known
* constant accounted for in the register enum already. */
ehci->opbase = ehci->base;
#else
/* In general, EHCI states that the operational register base has address:
* USBBASE + CAPLENGTH */
ehci->opbase = (volatile int *)((char *)ehci->base + *(uint8_t *)(ehci->base + caplength));
#endif

/* Reset controller */
*(hcd->base + usbcmd) |= 2;
while (*(hcd->base + usbcmd) & 2)
*(ehci->opbase + usbcmd) |= USBCMD_HCRESET;
while ((*(ehci->opbase + usbcmd) & USBCMD_HCRESET) != 0)
;

/* Set host mode */
*(hcd->base + usbmode) |= 3;
#ifdef EHCI_IMX
/* imx deviation: Set host mode */
*(ehci->opbase + usbmode) |= 3;
#endif

/* Enable interrupts */
*(hcd->base + usbintr) = USBSTS_UI | USBSTS_UEI;
*(ehci->opbase + usbintr) = USBSTS_UI | USBSTS_UEI;

/* Set periodic frame list */
*(hcd->base + periodiclistbase) = va2pa(ehci->periodicList);
*(ehci->opbase + periodiclistbase) = va2pa(ehci->periodicList);

#ifdef EHCI_IMX
/* imx deviation: Set frame list size (128 bytes) */
*(ehci->opbase + usbcmd) |= (3 << 2);
#endif

/* Set interrupts threshold, frame list size - 128 bytes, turn controller on */
*(hcd->base + usbcmd) |= (1 << 4) | (3 << 2) | 1;
/* Enable periodic scheduling, turn the controller on */
*(ehci->opbase + usbcmd) |= USBCMD_PSE | USBCMD_RUN;
while ((*(ehci->opbase + usbsts) & (USBSTS_HCH)) != 0)
;

/* Route all ports to this host controller */
*(hcd->base + configflag) = 1;
*(ehci->opbase + configflag) = 1;

ehci_startAsync(hcd);

Expand Down
30 changes: 27 additions & 3 deletions usb/ehci/ehci.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@

#define EHCI_INTRMASK (USBSTS_PCI | USBSTS_UEI | USBSTS_UI)

#define USBCMD_ASE (1 << 5)
#define USBCMD_IAA (1 << 6)
#define USBCMD_RUN (1 << 0)
#define USBCMD_HCRESET (1 << 1)
#define USBCMD_PSE (1 << 4)
#define USBCMD_ASE (1 << 5)
#define USBCMD_IAA (1 << 6)

#define PORTSC_PTS_1 (3 << 30)
#define PORTSC_STS (1 << 29)
Expand Down Expand Up @@ -116,6 +119,9 @@
#define EHCI_MAX_QTD_POOL 20
#define EHCI_MAX_QH_POOL 10


/* clang-format off */
#ifdef EHCI_IMX
enum {
/* identification regs */
id = 0x0, hwgeneral, hwhost, hwdevice, hwtxbuf, hwrxbuf,
Expand All @@ -136,10 +142,24 @@ enum {
endptctrl2, endptctrl3, endptctrl4, endptctrl5, endptctrl6, endptctrl7,
};


enum { usb_otg1_ctrl = 0x200, usb_otg2_ctrl, usb_otg1_phy_ctrl = usb_otg2_ctrl + 5, usb_otg2_phy_ctrl };

enum { ehci_item_itd = 0, ehci_item_qh, ehci_item_sitd, ehci_item_fstn };
#else
enum {
/* capability regs */
caplength = 0x0, hciversion = 0x0, hcsparams, hccparams,
hcspportroute1, hcspportroute2 /* hcspportroute is a 64-bit register */
};

enum {
/* operational regs */
usbcmd = 0x0, usbsts, usbintr, frindex, ctrldssegment,
periodiclistbase = 0x5, asynclistaddr,
configflag = 0x10, portsc1
};
#endif
/* clang-format on */


struct qtd {
Expand Down Expand Up @@ -184,6 +204,7 @@ typedef struct _ehci_qh {

typedef struct {
char stack[1024] __attribute__((aligned(8)));

uint32_t *periodicList;
ehci_qh_t *asyncList;
ehci_qh_t **periodicNodes;
Expand All @@ -197,6 +218,9 @@ typedef struct {
volatile unsigned portResetChange;
volatile unsigned status;
volatile unsigned portsc;

volatile int *base;
volatile int *opbase;
} ehci_t;


Expand Down
20 changes: 10 additions & 10 deletions usb/ehci/phy-imx6ull.c → usb/ehci/phy-armv7a7-imx6ull.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@

/* NOTE: This should be obtained using device tree */
static const hcd_info_t imx6ull_info[] = {
{
.type = "ehci",
{ .type = "ehci",
.hcdaddr = 0x02184200,
.phyaddr = 0x020ca000,
.clk = pctl_clk_usboh3,
.irq = 74
}
.phy = {

Check failure on line 38 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

'hcd_info_t' {aka 'const struct <anonymous>'} has no member named 'phy'

Check warning on line 38 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

braces around scalar initializer
.addr = 0x020ca000,

Check failure on line 39 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

field name not in record or union initializer
.clk = pctl_clk_usboh3,

Check failure on line 40 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

field name not in record or union initializer

Check warning on line 40 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

excess elements in scalar initializer
},
.irq = 74 }
};


Expand Down Expand Up @@ -88,7 +88,7 @@
.action = pctl_set,
.type = pctl_devclock,
.devclock = {
.dev = hcd->info->clk,
.dev = hcd->info->phy.clk,

Check failure on line 91 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

'hcd_info_t' {aka 'const struct <anonymous>'} has no member named 'phy'
.state = 3,
}
};
Expand All @@ -103,7 +103,7 @@
.action = pctl_set,
.type = pctl_devclock,
.devclock = {
.dev = hcd->info->clk,
.dev = hcd->info->phy.clk,

Check failure on line 106 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

'hcd_info_t' {aka 'const struct <anonymous>'} has no member named 'phy'
.state = 0,
}
};
Expand All @@ -123,8 +123,8 @@
{
off_t offs;

offs = hcd->info->phyaddr % _PAGE_SIZE;
hcd->phybase = mmap(NULL, _PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, hcd->info->phyaddr - offs);
offs = hcd->info->phy.addr % _PAGE_SIZE;

Check failure on line 126 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

'hcd_info_t' {aka 'const struct <anonymous>'} has no member named 'phy'
hcd->phybase = mmap(NULL, _PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, hcd->info->phy.addr - offs);

Check failure on line 127 in usb/ehci/phy-armv7a7-imx6ull.c

View workflow job for this annotation

GitHub Actions / call-ci / build (armv7a7-imx6ull-evk)

'hcd_info_t' {aka 'const struct <anonymous>'} has no member named 'phy'
if (hcd->phybase == MAP_FAILED)
return -ENOMEM;
hcd->phybase += (offs / sizeof(int));
Expand Down
Loading
Loading