Ignore:
File:
1 edited

Legend:

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

    r8855939 rc060090  
    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(const ddf_dev_t *dev, int address, uint32_t *value)
     90{
     91        PCI_READ(32);
     92}
     93static int pci_read16(const ddf_dev_t *dev, int address, uint16_t *value)
     94{
     95        PCI_READ(16);
     96}
     97static int pci_read8(const 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(const ddf_dev_t *dev, int address, uint32_t value)
     118{
     119        PCI_WRITE(32);
     120}
     121static int pci_write16(const ddf_dev_t *dev, int address, uint16_t value)
     122{
     123        PCI_WRITE(16);
     124}
     125static int pci_write8(const 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.
     
    75136 * @return Error code.
    76137 */
    77 int pci_get_my_registers(ddf_dev_t *dev,
     138int pci_get_my_registers(const ddf_dev_t *dev,
    78139    uintptr_t *mem_reg_address, size_t *mem_reg_size, int *irq_no)
    79140{
    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;
     
    145206 * @return Error code.
    146207 */
    147 int pci_enable_interrupts(ddf_dev_t *device)
    148 {
    149         int parent_phone =
     208int pci_enable_interrupts(const ddf_dev_t *device)
     209{
     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;
     
    162223 * @return Error code.
    163224 */
    164 int pci_disable_legacy(ddf_dev_t *device)
     225int pci_disable_legacy(
     226    const ddf_dev_t *device, uintptr_t reg_base, size_t reg_size, int irq)
    165227{
    166228        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...) \
     229        (void) pci_read16;
     230        (void) pci_read8;
     231        (void) pci_write16;
     232
     233#define CHECK_RET_RETURN(ret, message...) \
    174234        if (ret != EOK) { \
    175235                usb_log_error(message); \
    176                 async_hangup(parent_phone); \
    177236                return ret; \
    178237        } else (void)0
    179238
    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;
    199 
    200         /* 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;
     239        /* Map EHCI registers */
     240        void *regs = NULL;
     241        int ret = pio_enable((void*)reg_base, reg_size, &regs);
     242        CHECK_RET_RETURN(ret, "Failed(%d) to map registers %p.\n",
     243            ret, (void *) reg_base);
    209244
    210245        const uint32_t hcc_params =
    211             *(uint32_t*)(registers + HCC_PARAMS_OFFSET);
     246            *(uint32_t*)(regs + HCC_PARAMS_OFFSET);
    212247        usb_log_debug("Value of hcc params register: %x.\n", hcc_params);
    213248
    214249        /* Read value of EHCI Extended Capabilities Pointer
    215          * (points to PCI config space) */
    216         uint32_t eecp =
     250         * position of EEC registers (points to PCI config space) */
     251        const uint32_t eecp =
    217252            (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
    218253        usb_log_debug("Value of EECP: %x.\n", eecp);
    219254
    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 
    227255        /* 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);
     256        uint32_t usblegsup;
     257        ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
     258        CHECK_RET_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
     259        usb_log_debug("USBLEGSUP: %" PRIxn ".\n", usblegsup);
    233260
    234261        /* Request control from firmware/BIOS, by writing 1 to highest byte.
    235262         * (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);
     263        usb_log_debug("Requesting OS control.\n");
     264        ret = pci_write8(device, eecp + USBLEGSUP_OFFSET + 3, 1);
     265        CHECK_RET_RETURN(ret, "Failed(%d) to request OS EHCI control.\n", ret);
    240266
    241267        size_t wait = 0;
    242268        /* Wait for BIOS to release control. */
    243         while ((wait < DEFAULT_WAIT) && (value & USBLEGSUP_BIOS_CONTROL)) {
     269        ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
     270        while ((wait < DEFAULT_WAIT) && (usblegsup & USBLEGSUP_BIOS_CONTROL)) {
    244271                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);
     272                ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
    247273                wait += WAIT_STEP;
    248274        }
    249275
    250276
    251         if ((value & USBLEGSUP_BIOS_CONTROL) == 0) {
     277        if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) {
    252278                usb_log_info("BIOS released control after %zu usec.\n", wait);
    253279        } else {
     
    255281                usb_log_warning( "BIOS failed to release control after "
    256282                    "%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,
     283                ret = pci_write32(device, eecp + USBLEGSUP_OFFSET,
    259284                    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);
     285                CHECK_RET_RETURN(ret, "Failed(%d) to force OS control.\n", ret);
     286                /* Check capability type here, A value of 01h
     287                 * identifies the capability as Legacy Support.
     288                 * This extended capability requires one
     289                 * additional 32-bit register for control/status information,
     290                 * and this register is located at offset EECP+04h
     291                 * */
     292                if ((usblegsup & 0xff) == 1) {
     293                        /* Read the second EEC
     294                         * Legacy Support and Control register */
     295                        uint32_t usblegctlsts;
     296                        ret = pci_read32(
     297                            device, eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
     298                        CHECK_RET_RETURN(ret,
     299                            "Failed(%d) to get USBLEGCTLSTS.\n", ret);
     300                        usb_log_debug("USBLEGCTLSTS: %" PRIxn ".\n",
     301                            usblegctlsts);
     302                        /* Zero SMI enables in legacy control register.
     303                         * It should prevent pre-OS code from interfering. */
     304                        ret = pci_write32(device, eecp + USBLEGCTLSTS_OFFSET,
     305                            0xe0000000); /* three upper bits are WC */
     306                        CHECK_RET_RETURN(ret,
     307                            "Failed(%d) zero USBLEGCTLSTS.\n", ret);
     308                        udelay(10);
     309                        ret = pci_read32(
     310                            device, eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
     311                        CHECK_RET_RETURN(ret,
     312                            "Failed(%d) to get USBLEGCTLSTS 2.\n", ret);
     313                        usb_log_debug("Zeroed USBLEGCTLSTS: %" PRIxn ".\n",
     314                            usblegctlsts);
     315                }
     316        }
     317
    276318
    277319        /* 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);
     320        ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
     321        CHECK_RET_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
     322        usb_log_debug("USBLEGSUP: %" PRIxn ".\n", usblegsup);
    282323
    283324        /*
     
    286327
    287328        /* Get size of capability registers in memory space. */
    288         uint8_t operation_offset = *(uint8_t*)registers;
     329        const unsigned operation_offset = *(uint8_t*)regs;
    289330        usb_log_debug("USBCMD offset: %d.\n", operation_offset);
    290331
    291332        /* Zero USBCMD register. */
    292333        volatile uint32_t *usbcmd =
    293             (uint32_t*)((uint8_t*)registers + operation_offset + CMD_OFFSET);
     334            (uint32_t*)((uint8_t*)regs + operation_offset + CMD_OFFSET);
    294335        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);
     336            (uint32_t*)((uint8_t*)regs + operation_offset + STS_OFFSET);
     337        volatile uint32_t *usbconf =
     338            (uint32_t*)((uint8_t*)regs + operation_offset + CFG_OFFSET);
     339        volatile uint32_t *usbint =
     340            (uint32_t*)((uint8_t*)regs + operation_offset + INT_OFFSET);
    298341        usb_log_debug("USBCMD value: %x.\n", *usbcmd);
    299342        if (*usbcmd & USBCMD_RUN) {
     343                *usbsts = 0x3f; /* ack all interrupts */
     344                *usbint = 0; /* disable all interrutps */
     345                *usbconf = 0; /* relase control of RH ports */
     346
    300347                *usbcmd = 0;
    301                 while (!(*usbsts & (1 << 12))); /*wait until hc is halted */
    302                 *usbconfigured = 0;
     348                /* Wait until hc is halted */
     349                while ((*usbsts & USBSTS_HALTED) == 0);
    303350                usb_log_info("EHCI turned off.\n");
    304351        } else {
    305352                usb_log_info("EHCI was not running.\n");
    306353        }
    307         usb_log_debug("Registers: %x(0x00080000):%x(0x00001000):%x(0x0).\n",
    308             *usbcmd, *usbsts, *usbconfigured);
    309 
    310         async_hangup(parent_phone);
     354        usb_log_debug("Registers: \n"
     355            "\t USBCMD: %x(0x00080000 = at least 1ms between interrupts)\n"
     356            "\t USBSTS: %x(0x00001000 = HC halted)\n"
     357            "\t USBINT: %x(0x0 = no interrupts).\n"
     358            "\t CONFIG: %x(0x0 = ports controlled by companion hc).\n",
     359            *usbcmd, *usbsts, *usbint, *usbconf);
     360
    311361        return ret;
    312 #undef CHECK_RET_HANGUP_RETURN
     362#undef CHECK_RET_RETURN
    313363}
    314364/*----------------------------------------------------------------------------*/
Note: See TracChangeset for help on using the changeset viewer.