Changeset 17d1542 in mainline


Ignore:
Timestamp:
2011-05-30T17:20:48Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
3ae26a8
Parents:
399a13c
Message:

EHCI reworked

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/ehci-hcd/pci.c

    r399a13c r17d1542  
    5555#define CMD_OFFSET 0x0
    5656#define STS_OFFSET 0x4
     57#define INT_OFFSET 0x8
    5758#define CFG_OFFSET 0x40
    5859
    5960#define USBCMD_RUN 1
     61#define USBSTS_HALTED (1 << 12)
    6062
    6163#define USBLEGSUP_OFFSET 0
     
    6466#define USBLEGCTLSTS_OFFSET 4
    6567
    66 #define DEFAULT_WAIT 10000
     68#define DEFAULT_WAIT 1000
    6769#define WAIT_STEP 10
     70
     71#define PCI_READ(size) \
     72do { \
     73        const int parent_phone = \
     74            devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING);\
     75        if (parent_phone < 0) {\
     76                return parent_phone; \
     77        } \
     78        sysarg_t add = (sysarg_t)address; \
     79        sysarg_t val; \
     80        const int ret = \
     81            async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), \
     82                IPC_M_CONFIG_SPACE_READ_##size, add, &val); \
     83        assert(value); \
     84        *value = val; \
     85        async_hangup(parent_phone); \
     86        return ret; \
     87} while(0)
     88
     89static int pci_read32(ddf_dev_t *dev, int address, uint32_t *value)
     90{
     91        PCI_READ(32);
     92}
     93static int pci_read16(ddf_dev_t *dev, int address, uint16_t *value)
     94{
     95        PCI_READ(16);
     96}
     97static int pci_read8(ddf_dev_t *dev, int address, uint8_t *value)
     98{
     99        PCI_READ(8);
     100}
     101#define PCI_WRITE(size) \
     102do { \
     103        const int parent_phone = \
     104            devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING);\
     105        if (parent_phone < 0) {\
     106                return parent_phone; \
     107        } \
     108        sysarg_t add = (sysarg_t)address; \
     109        sysarg_t val = value; \
     110        const int ret = \
     111            async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), \
     112                IPC_M_CONFIG_SPACE_WRITE_##size, add, val); \
     113        async_hangup(parent_phone); \
     114        return ret; \
     115} while(0)
     116
     117static int pci_write32(ddf_dev_t *dev, int address, uint32_t value)
     118{
     119        PCI_WRITE(32);
     120}
     121static int pci_write16(ddf_dev_t *dev, int address, uint16_t value)
     122{
     123        PCI_WRITE(16);
     124}
     125static int pci_write8(ddf_dev_t *dev, int address, uint8_t value)
     126{
     127        PCI_WRITE(8);
     128}
    68129
    69130/** Get address of registers and IRQ for given device.
     
    80141        assert(dev != NULL);
    81142
    82         int parent_phone = devman_parent_device_connect(dev->handle,
    83             IPC_FLAG_BLOCKING);
     143        const int parent_phone =
     144            devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING);
    84145        if (parent_phone < 0) {
    85146                return parent_phone;
     
    147208int pci_enable_interrupts(ddf_dev_t *device)
    148209{
    149         int parent_phone =
     210        const int parent_phone =
    150211            devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING);
    151212        if (parent_phone < 0) {
    152213                return parent_phone;
    153214        }
    154         bool enabled = hw_res_enable_interrupt(parent_phone);
     215        const bool enabled = hw_res_enable_interrupt(parent_phone);
    155216        async_hangup(parent_phone);
    156217        return enabled ? EOK : EIO;
     
    165226{
    166227        assert(device);
    167         int parent_phone = devman_parent_device_connect(device->handle,
    168                 IPC_FLAG_BLOCKING);
    169         if (parent_phone < 0) {
    170                 return parent_phone;
    171         }
    172 
    173 #define CHECK_RET_HANGUP_RETURN(ret, message...) \
     228        (void) pci_read16;
     229        (void) pci_read8;
     230        (void) pci_write16;
     231
     232#define CHECK_RET_RETURN(ret, message...) \
    174233        if (ret != EOK) { \
    175234                usb_log_error(message); \
    176                 async_hangup(parent_phone); \
    177235                return ret; \
    178236        } else (void)0
    179237
    180 
    181         /* read register space BASE BAR */
    182         sysarg_t address = 0x10;
    183         sysarg_t value;
    184 
    185         int ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    186             IPC_M_CONFIG_SPACE_READ_32, address, &value);
    187         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read PCI config space.\n",
    188             ret);
    189         usb_log_info("Register space BAR at %p:%" PRIxn ".\n",
    190             (void *) address, value);
    191 
    192         /* clear lower byte, it's not part of the BASE address */
    193         uintptr_t registers = (value & 0xffffff00);
    194         usb_log_info("Memory registers BASE address:%p.\n", (void *) registers);
    195 
    196         /* if nothing setup the hc, we don't need to turn it off */
    197         if (registers == 0)
    198                 return ENOTSUP;
     238        uintptr_t reg_base = 0;
     239        size_t reg_size = 0;
     240        int irq = 0;
     241
     242        int ret = pci_get_my_registers(device, &reg_base, &reg_size, &irq);
     243        CHECK_RET_RETURN(ret, "Failed(%d) to get EHCI registers.\n", ret);
     244
     245        usb_log_info("EHCI: Memory registers:%p size: %zu irq:%d.\n",
     246            (void *) reg_base, reg_size, irq);
     247
    199248
    200249        /* map EHCI registers */
    201         void *regs = as_get_mappable_page(4096);
    202         ret = physmem_map((void*)(registers & PAGE_SIZE_MASK), regs, 1,
    203             AS_AREA_READ | AS_AREA_WRITE);
    204         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to map registers %p:%p.\n",
    205             ret, regs, (void *) registers);
    206 
    207         /* calculate value of BASE */
    208         registers = (registers & 0xf00) | (uintptr_t)regs;
     250        void *regs = NULL;
     251        ret = pio_enable((void*)reg_base, reg_size, &regs);
     252        CHECK_RET_RETURN(ret, "Failed(%d) to map registers %p.\n",
     253            ret, (void *) reg_base);
    209254
    210255        const uint32_t hcc_params =
    211             *(uint32_t*)(registers + HCC_PARAMS_OFFSET);
     256            *(uint32_t*)(regs + HCC_PARAMS_OFFSET);
    212257        usb_log_debug("Value of hcc params register: %x.\n", hcc_params);
    213258
    214259        /* Read value of EHCI Extended Capabilities Pointer
    215          * (points to PCI config space) */
    216         uint32_t eecp =
     260         * position of EEC registers (points to PCI config space) */
     261        const uint32_t eecp =
    217262            (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
    218263        usb_log_debug("Value of EECP: %x.\n", eecp);
    219264
    220         /* Read the second EEC. i.e. Legacy Support and Control register */
    221         /* TODO: Check capability type here */
    222         ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    223             IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value);
    224         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGCTLSTS.\n", ret);
    225         usb_log_debug("USBLEGCTLSTS: %" PRIxn ".\n", value);
    226 
    227265        /* Read the first EEC. i.e. Legacy Support register */
    228         /* TODO: Check capability type here */
    229         ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    230             IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
    231         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
    232         usb_log_debug2("USBLEGSUP: %" PRIxn ".\n", value);
     266        uint32_t usblegsup;
     267        ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
     268        CHECK_RET_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
     269        usb_log_debug("USBLEGSUP: %" PRIxn ".\n", usblegsup);
    233270
    234271        /* Request control from firmware/BIOS, by writing 1 to highest byte.
    235272         * (OS Control semaphore)*/
    236         ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    237            IPC_M_CONFIG_SPACE_WRITE_8, eecp + USBLEGSUP_OFFSET + 3, 1);
    238         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to request OS EHCI control.\n",
    239             ret);
     273        usb_log_debug("Requesting OS control.\n");
     274        ret = pci_write8(device, eecp + USBLEGSUP_OFFSET + 3, 1);
     275        CHECK_RET_RETURN(ret, "Failed(%d) to request OS EHCI control.\n", ret);
    240276
    241277        size_t wait = 0;
    242278        /* Wait for BIOS to release control. */
    243         while ((wait < DEFAULT_WAIT) && (value & USBLEGSUP_BIOS_CONTROL)) {
     279        ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
     280        while ((wait < DEFAULT_WAIT) && (usblegsup & USBLEGSUP_BIOS_CONTROL)) {
    244281                async_usleep(WAIT_STEP);
    245                 ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    246                     IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
     282                ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
    247283                wait += WAIT_STEP;
    248284        }
    249285
    250286
    251         if ((value & USBLEGSUP_BIOS_CONTROL) == 0) {
     287        if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) {
    252288                usb_log_info("BIOS released control after %zu usec.\n", wait);
    253289        } else {
     
    255291                usb_log_warning( "BIOS failed to release control after "
    256292                    "%zu usecs, force it.\n", wait);
    257                 ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    258                     IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGSUP_OFFSET,
     293                ret = pci_write32(device, eecp + USBLEGSUP_OFFSET,
    259294                    USBLEGSUP_OS_CONTROL);
    260                 CHECK_RET_HANGUP_RETURN(ret,
    261                     "Failed(%d) to force OS EHCI control.\n", ret);
    262         }
    263 
    264         /* Zero SMI enables in legacy control register.
    265          * It would prevent pre-OS code from interfering. */
    266         ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    267            IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGCTLSTS_OFFSET,
    268            0xe0000000);
    269         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) zero USBLEGCTLSTS.\n", ret);
    270 
    271         /* Read again Legacy Support and Control register */
    272         ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    273             IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value);
    274         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGCTLSTS.\n", ret);
    275         usb_log_debug2("USBLEGCTLSTS: %" PRIxn ".\n", value);
     295                CHECK_RET_RETURN(ret, "Failed(%d) to force OS control.\n", ret);
     296                /* Check capability type here, A value of 01h
     297                 * identifies the capability as Legacy Support.
     298                 * This extended capability requires one
     299                 * additional 32-bit register for control/status information,
     300                 * and this register is located at offset EECP+04h
     301                 * */
     302                if ((usblegsup & 0xff) == 1) {
     303                        /* Read the second EEC
     304                         * Legacy Support and Control register */
     305                        uint32_t usblegctlsts;
     306                        ret = pci_read32(
     307                            device, eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
     308                        CHECK_RET_RETURN(ret,
     309                            "Failed(%d) to get USBLEGCTLSTS.\n", ret);
     310                        usb_log_debug("USBLEGCTLSTS: %" PRIxn ".\n",
     311                            usblegctlsts);
     312                        /* Zero SMI enables in legacy control register.
     313                         * It should prevent pre-OS code from interfering. */
     314                        ret = pci_write32(device, eecp + USBLEGCTLSTS_OFFSET,
     315                            0xe0000000); /* three upper bits are WC */
     316                        CHECK_RET_RETURN(ret,
     317                            "Failed(%d) zero USBLEGCTLSTS.\n", ret);
     318                        ret = pci_read32(
     319                            device, eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
     320                        CHECK_RET_RETURN(ret,
     321                            "Failed(%d) to get USBLEGCTLSTS 2.\n", ret);
     322                        usb_log_debug("Zeroed USBLEGCTLSTS: %" PRIxn ".\n",
     323                            usblegctlsts);
     324                }
     325        }
     326
    276327
    277328        /* Read again Legacy Support register */
    278         ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    279             IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
    280         CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
    281         usb_log_debug2("USBLEGSUP: %" PRIxn ".\n", value);
     329        ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
     330        CHECK_RET_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
     331        usb_log_debug("USBLEGSUP: %" PRIxn ".\n", usblegsup);
    282332
    283333        /*
     
    286336
    287337        /* Get size of capability registers in memory space. */
    288         uint8_t operation_offset = *(uint8_t*)registers;
     338        const unsigned operation_offset = *(uint8_t*)regs;
    289339        usb_log_debug("USBCMD offset: %d.\n", operation_offset);
    290340
    291341        /* Zero USBCMD register. */
    292342        volatile uint32_t *usbcmd =
    293             (uint32_t*)((uint8_t*)registers + operation_offset + CMD_OFFSET);
     343            (uint32_t*)((uint8_t*)regs + operation_offset + CMD_OFFSET);
    294344        volatile uint32_t *usbsts =
    295             (uint32_t*)((uint8_t*)registers + operation_offset + STS_OFFSET);
    296         volatile uint32_t *usbconfigured =
    297             (uint32_t*)((uint8_t*)registers + operation_offset + CFG_OFFSET);
     345            (uint32_t*)((uint8_t*)regs + operation_offset + STS_OFFSET);
     346        volatile uint32_t *usbconf =
     347            (uint32_t*)((uint8_t*)regs + operation_offset + CFG_OFFSET);
     348        volatile uint32_t *usbint =
     349            (uint32_t*)((uint8_t*)regs + operation_offset + INT_OFFSET);
    298350        usb_log_debug("USBCMD value: %x.\n", *usbcmd);
    299351        if (*usbcmd & USBCMD_RUN) {
    300352                *usbcmd = 0;
    301                 while (!(*usbsts & (1 << 12))); /*wait until hc is halted */
    302                 *usbconfigured = 0;
     353                /* Wait until hc is halted */
     354                while ((*usbsts & USBSTS_HALTED) != 0);
     355                *usbsts = 0x3f; /* ack all interrupts */
     356                *usbint = 0; /* disable all interrutps */
     357                *usbconf = 0; /* relase control of RH ports */
    303358                usb_log_info("EHCI turned off.\n");
    304359        } else {
    305360                usb_log_info("EHCI was not running.\n");
    306361        }
    307         usb_log_debug("Registers: %x(0x00080000):%x(0x00001000):%x(0x0).\n",
    308             *usbcmd, *usbsts, *usbconfigured);
    309 
    310         async_hangup(parent_phone);
     362        usb_log_debug("Registers: \n"
     363            "\t USBCMD: %x(0x00080000 = at least 1ms between interrupts)\n"
     364            "\t USBSTS: %x(0x00001000 = HC halted)\n"
     365            "\t USBINT: %x(0x0 = no interrupts).\n"
     366            "\t CONFIG: %x(0x0 = ports controlled by companion hc).\n",
     367            *usbcmd, *usbsts, *usbint, *usbconf);
     368
    311369        return ret;
    312 #undef CHECK_RET_HANGUP_RETURN
     370#undef CHECK_RET_RETURN
    313371}
    314372/*----------------------------------------------------------------------------*/
Note: See TracChangeset for help on using the changeset viewer.