Changeset 91ca111 in mainline for uspace/drv/bus/usb/xhci/hc.c


Ignore:
Timestamp:
2017-06-23T11:18:50Z (7 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
51b2693
Parents:
e4d7363
Message:

xhci: extended capability handling

Currently, only detection of legacy support and parsing of protocol speeds is
implemented.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/hc.c

    re4d7363 r91ca111  
    6969};
    7070
     71/**
     72 * Default USB Speed ID mapping: Table 157
     73 */
     74#define PSI_TO_BPS(psie, psim) (((uint64_t) psim) << (10 * psie))
     75#define PORT_SPEED(psie, psim) { \
     76        .rx_bps = PSI_TO_BPS(psie, psim), \
     77        .tx_bps = PSI_TO_BPS(psie, psim) \
     78}
     79static const xhci_port_speed_t ps_default_full  = PORT_SPEED(2, 12);
     80static const xhci_port_speed_t ps_default_low   = PORT_SPEED(1, 1500);
     81static const xhci_port_speed_t ps_default_high  = PORT_SPEED(2, 480);
     82static const xhci_port_speed_t ps_default_super = PORT_SPEED(3, 5);
     83
     84/**
     85 * Walk the list of extended capabilities.
     86 */
     87static int hc_parse_ec(xhci_hc_t *hc)
     88{
     89        unsigned psic, major;
     90
     91        for (xhci_extcap_t *ec = hc->xecp; ec; ec = xhci_extcap_next(ec)) {
     92                xhci_dump_extcap(ec);
     93                switch (XHCI_REG_RD(ec, XHCI_EC_CAP_ID)) {
     94                case XHCI_EC_USB_LEGACY:
     95                        assert(hc->legsup == NULL);
     96                        hc->legsup = (xhci_legsup_t *) ec;
     97                        break;
     98                case XHCI_EC_SUPPORTED_PROTOCOL:
     99                        psic = XHCI_REG_RD(ec, XHCI_EC_SP_PSIC);
     100                        major = XHCI_REG_RD(ec, XHCI_EC_SP_MAJOR);
     101
     102                        // "Implied" speed
     103                        if (psic == 0) {
     104                                /*
     105                                 * According to section 7.2.2.1.2, only USB 2.0
     106                                 * and USB 3.0 can have psic == 0. So we
     107                                 * blindly assume the name == "USB " and minor
     108                                 * == 0.
     109                                 */
     110                                if (major == 2) {
     111                                        hc->speeds[1] = ps_default_full;
     112                                        hc->speeds[2] = ps_default_low;
     113                                        hc->speeds[3] = ps_default_high;
     114                                } else if (major == 3) {
     115                                        hc->speeds[4] = ps_default_super;
     116                                } else {
     117                                        return EINVAL;
     118                                }
     119
     120                                usb_log_debug2("Implied speed of USB %u set up.", major);
     121                        } else {
     122                                for (unsigned i = 0; i < psic; i++) {
     123                                        xhci_psi_t *psi = xhci_extcap_psi(ec, i);
     124                                        unsigned sim = XHCI_REG_RD(psi, XHCI_PSI_PSIM);
     125                                        unsigned psiv = XHCI_REG_RD(psi, XHCI_PSI_PSIV);
     126                                        unsigned psie = XHCI_REG_RD(psi, XHCI_PSI_PSIE);
     127                                        unsigned psim = XHCI_REG_RD(psi, XHCI_PSI_PSIM);
     128
     129                                        uint64_t bps = PSI_TO_BPS(psie, psim);
     130
     131                                        if (sim == XHCI_PSI_PLT_SYMM || sim == XHCI_PSI_PLT_RX)
     132                                                hc->speeds[psiv].rx_bps = bps;
     133                                        if (sim == XHCI_PSI_PLT_SYMM || sim == XHCI_PSI_PLT_TX) {
     134                                                hc->speeds[psiv].tx_bps = bps;
     135                                                usb_log_debug2("Speed %u set up for bps %" PRIu64 " / %" PRIu64 ".", psiv, hc->speeds[psiv].rx_bps, hc->speeds[psiv].tx_bps);
     136                                        }
     137                                }
     138                        }
     139                }
     140        }
     141        return EOK;
     142}
     143
    71144int hc_init_mmio(xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
    72145{
     
    90163                return err;
    91164
     165        hc->base = base;
    92166        hc->cap_regs = (xhci_cap_regs_t *)  base;
    93167        hc->op_regs  = (xhci_op_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
    94168        hc->rt_regs  = (xhci_rt_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF));
    95169        hc->db_arry  = (xhci_doorbell_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_DBOFF));
     170
     171        uintptr_t xec_offset = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_XECP) * sizeof(xhci_dword_t);
     172        if (xec_offset > 0)
     173                hc->xecp = (xhci_extcap_t *) (base + xec_offset);
    96174
    97175        usb_log_debug2("Initialized MMIO reg areas:");
     
    105183        hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64);
    106184        hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS);
     185
     186        if ((err = hc_parse_ec(hc))) {
     187                pio_disable(hc->base, RNGSZ(hc->mmio_range));
     188                return err;
     189        }
    107190
    108191        return EOK;
     
    151234        }
    152235
    153         addr_range_t mmio_range = hw_res->mem_ranges.ranges[0];
    154 
    155236        code->ranges = malloc(sizeof(irq_pio_range_t));
    156237        if (code->ranges == NULL)
     
    165246        code->rangecount = 1;
    166247        code->ranges[0] = (irq_pio_range_t) {
    167             .base = RNGABS(mmio_range),
    168             .size = RNGSZ(mmio_range),
     248            .base = RNGABS(hc->mmio_range),
     249            .size = RNGSZ(hc->mmio_range),
    169250        };
    170251
     
    172253        memcpy(code->cmds, irq_commands, sizeof(irq_commands));
    173254
    174         void *intr0_iman = RNGABSPTR(mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
     255        void *intr0_iman = RNGABSPTR(hc->mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
    175256        code->cmds[0].addr = intr0_iman;
    176257        code->cmds[3].addr = intr0_iman;
     
    182263int hc_claim(xhci_hc_t *hc, ddf_dev_t *dev)
    183264{
    184         // TODO: impl
    185         return EOK;
     265        /* No legacy support capability, the controller is solely for us */
     266        if (!hc->legsup)
     267                return EOK;
     268
     269        /*
     270         * TODO: Implement handoff from BIOS, section 4.22.1
     271         * QEMU does not support this, so we have to test on real HW.
     272         */
     273        return ENOTSUP;
    186274}
    187275
     
    346434        xhci_trb_ring_fini(&hc->command_ring);
    347435        xhci_event_ring_fini(&hc->event_ring);
     436        pio_disable(hc->base, RNGSZ(hc->mmio_range));
    348437        usb_log_info("HC(%p): Finalized.", hc);
    349438}
Note: See TracChangeset for help on using the changeset viewer.