Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ehci/res.c

    rf6f2a5f7 rf9b2cb4c  
    4646
    4747#include "res.h"
    48 #include "ehci_regs.h"
     48
     49#define HCC_PARAMS_OFFSET 0x8
     50#define HCC_PARAMS_EECP_MASK 0xff
     51#define HCC_PARAMS_EECP_OFFSET 8
     52
     53#define CMD_OFFSET 0x0
     54#define STS_OFFSET 0x4
     55#define INT_OFFSET 0x8
     56#define CFG_OFFSET 0x40
     57
     58#define USBCMD_RUN 1
     59#define USBSTS_HALTED (1 << 12)
    4960
    5061#define USBLEGSUP_OFFSET 0
     
    5667#define WAIT_STEP 10
    5768
     69
     70/** Get address of registers and IRQ for given device.
     71 *
     72 * @param[in] dev Device asking for the addresses.
     73 * @param[out] mem_regs_p Pointer to the register range.
     74 * @param[out] irq_no IRQ assigned to the device.
     75 * @return Error code.
     76 */
     77int get_my_registers(ddf_dev_t *dev,
     78    addr_range_t *mem_regs_p, int *irq_no)
     79{
     80        assert(dev);
     81       
     82        async_sess_t *parent_sess = devman_parent_device_connect(
     83            ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
     84        if (!parent_sess)
     85                return ENOMEM;
     86       
     87        hw_res_list_parsed_t hw_res;
     88        hw_res_list_parsed_init(&hw_res);
     89        const int ret = hw_res_get_list_parsed(parent_sess, &hw_res, 0);
     90        async_hangup(parent_sess);
     91        if (ret != EOK) {
     92                return ret;
     93        }
     94
     95        if (hw_res.irqs.count != 1 || hw_res.mem_ranges.count != 1) {
     96                hw_res_list_parsed_clean(&hw_res);
     97                return ENOENT;
     98        }
     99
     100        if (mem_regs_p)
     101                *mem_regs_p = hw_res.mem_ranges.ranges[0];
     102        if (irq_no)
     103                *irq_no = hw_res.irqs.irqs[0];
     104
     105        hw_res_list_parsed_clean(&hw_res);
     106        return EOK;
     107}
     108
     109/** Calls the PCI driver with a request to enable interrupts
     110 *
     111 * @param[in] device Device asking for interrupts
     112 * @return Error code.
     113 */
     114int enable_interrupts(ddf_dev_t *device)
     115{
     116        async_sess_t *parent_sess = devman_parent_device_connect(
     117            ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);
     118        if (!parent_sess)
     119                return ENOMEM;
     120       
     121        const bool enabled = hw_res_enable_interrupt(parent_sess);
     122        async_hangup(parent_sess);
     123       
     124        return enabled ? EOK : EIO;
     125}
     126
    58127/** Implements BIOS hands-off routine as described in EHCI spec
    59128 *
     
    62131 * @return Error code.
    63132 */
    64 static int disable_extended_caps(async_sess_t *parent_sess, unsigned eecp)
     133static int disable_extended_caps(ddf_dev_t *device, unsigned eecp)
    65134{
    66135        /* nothing to do */
     
    68137                return EOK;
    69138
     139        async_sess_t *parent_sess = devman_parent_device_connect(
     140            ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);
     141        if (!parent_sess)
     142                return ENOMEM;
     143
    70144        /* Read the first EEC. i.e. Legacy Support register */
    71145        uint32_t usblegsup;
    72         int ret = pci_config_space_read_32(parent_sess,
     146        int rc = pci_config_space_read_32(parent_sess,
    73147            eecp + USBLEGSUP_OFFSET, &usblegsup);
    74         if (ret != EOK) {
    75                 usb_log_error("Failed to read USBLEGSUP: %s.\n", str_error(ret));
    76                 return ret;
    77         }
    78         usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
     148        if (rc != EOK) {
     149                usb_log_error("Failed to read USBLEGSUP: %s.\n",
     150                    str_error(rc));
     151                goto error;
     152        }
     153
     154        usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
    79155
    80156        /* Request control from firmware/BIOS by writing 1 to highest
    81157         * byte. (OS Control semaphore)*/
    82158        usb_log_debug("Requesting OS control.\n");
    83         ret = pci_config_space_write_8(parent_sess,
     159        rc = pci_config_space_write_8(parent_sess,
    84160            eecp + USBLEGSUP_OFFSET + 3, 1);
    85         if (ret != EOK) {
     161        if (rc != EOK) {
    86162                usb_log_error("Failed to request OS EHCI control: %s.\n",
    87                     str_error(ret));
    88                 return ret;
     163                    str_error(rc));
     164                goto error;
    89165        }
    90166
    91167        size_t wait = 0;
    92168        /* Wait for BIOS to release control. */
    93         ret = pci_config_space_read_32(
     169        rc = pci_config_space_read_32(
    94170            parent_sess, eecp + USBLEGSUP_OFFSET, &usblegsup);
    95         while ((ret == EOK) && (wait < DEFAULT_WAIT)
    96             && (usblegsup & USBLEGSUP_BIOS_CONTROL)) {
     171        if (rc != EOK) {
     172                usb_log_error("Failed reading PCI config space: %s.\n",
     173                    str_error(rc));
     174                goto error;
     175        }
     176
     177        while ((wait < DEFAULT_WAIT) && (usblegsup & USBLEGSUP_BIOS_CONTROL)) {
    97178                async_usleep(WAIT_STEP);
    98                 ret = pci_config_space_read_32(parent_sess,
     179                rc = pci_config_space_read_32(parent_sess,
    99180                    eecp + USBLEGSUP_OFFSET, &usblegsup);
     181                if (rc != EOK) {
     182                        usb_log_error("Failed reading PCI config space: %s.\n",
     183                            str_error(rc));
     184                        goto error;
     185                }
    100186                wait += WAIT_STEP;
    101187        }
     
    103189        if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) {
    104190                usb_log_info("BIOS released control after %zu usec.\n", wait);
     191                async_hangup(parent_sess);
    105192                return EOK;
    106193        }
     
    109196        usb_log_warning( "BIOS failed to release control after "
    110197            "%zu usecs, force it.\n", wait);
    111         ret = pci_config_space_write_32(parent_sess,
     198        rc = pci_config_space_write_32(parent_sess,
    112199            eecp + USBLEGSUP_OFFSET, USBLEGSUP_OS_CONTROL);
    113         if (ret != EOK) {
    114                 usb_log_error("Failed to force OS control: %s.\n",
    115                     str_error(ret));
    116                 return ret;
     200        if (rc != EOK) {
     201                usb_log_error("Failed to force OS control: "
     202                    "%s.\n", str_error(rc));
     203                goto error;
    117204        }
    118205
     
    126213                /* Read the second EEC Legacy Support and Control register */
    127214                uint32_t usblegctlsts;
    128                 ret = pci_config_space_read_32(parent_sess,
     215                rc = pci_config_space_read_32(parent_sess,
    129216                    eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
    130                 if (ret != EOK) {
     217                if (rc != EOK) {
    131218                        usb_log_error("Failed to get USBLEGCTLSTS: %s.\n",
    132                             str_error(ret));
    133                         return ret;
     219                            str_error(rc));
     220                        goto error;
    134221                }
    135                 usb_log_debug2("USBLEGCTLSTS: %" PRIx32 ".\n", usblegctlsts);
     222
     223                usb_log_debug("USBLEGCTLSTS: %" PRIx32 ".\n", usblegctlsts);
    136224                /*
    137225                 * Zero SMI enables in legacy control register.
     
    139227                 * interfering. NOTE: Three upper bits are WC
    140228                 */
    141                 ret = pci_config_space_write_32(parent_sess,
     229                rc = pci_config_space_write_32(parent_sess,
    142230                    eecp + USBLEGCTLSTS_OFFSET, 0xe0000000);
    143                 if (ret != EOK) {
    144                         usb_log_error("Failed to zero USBLEGCTLSTS: %s\n",
    145                             str_error(ret));
    146                         return ret;
     231                if (rc != EOK) {
     232                        usb_log_error("Failed(%d) zero USBLEGCTLSTS.\n", rc);
     233                        goto error;
    147234                }
    148235
    149236                udelay(10);
    150                 /* read again to amke sure it's zeroed */
    151                 ret = pci_config_space_read_32(parent_sess,
     237                rc = pci_config_space_read_32(parent_sess,
    152238                    eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
    153                 if (ret != EOK) {
     239                if (rc != EOK) {
    154240                        usb_log_error("Failed to get USBLEGCTLSTS 2: %s.\n",
    155                             str_error(ret));
    156                         return ret;
     241                            str_error(rc));
     242                        goto error;
    157243                }
    158                 usb_log_debug2("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n",
     244
     245                usb_log_debug("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n",
    159246                    usblegctlsts);
    160247        }
    161248
    162249        /* Read again Legacy Support register */
    163         ret = pci_config_space_read_32(parent_sess,
     250        rc = pci_config_space_read_32(parent_sess,
    164251            eecp + USBLEGSUP_OFFSET, &usblegsup);
    165         if (ret != EOK) {
     252        if (rc != EOK) {
    166253                usb_log_error("Failed to read USBLEGSUP: %s.\n",
    167                     str_error(ret));
    168                 return ret;
    169         }
    170         usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
    171         return ret;
     254                    str_error(rc));
     255                goto error;
     256        }
     257
     258        usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
     259        async_hangup(parent_sess);
     260        return EOK;
     261error:
     262        async_hangup(parent_sess);
     263        return rc;
    172264}
    173265
    174 int disable_legacy(ddf_dev_t *device)
     266int disable_legacy(ddf_dev_t *device, addr_range_t *reg_range)
    175267{
    176268        assert(device);
    177 
    178         async_sess_t *parent_sess = devman_parent_device_connect(
    179             EXCHANGE_SERIALIZE, ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);
    180         if (!parent_sess)
    181                 return ENOMEM;
    182 
    183269        usb_log_debug("Disabling EHCI legacy support.\n");
    184 
    185         hw_res_list_parsed_t res;
    186         hw_res_list_parsed_init(&res);
    187         int ret = hw_res_get_list_parsed(parent_sess, &res, 0);
    188         if (ret != EOK) {
    189                 usb_log_error("Failed to get resource list: %s\n",
    190                     str_error(ret));
    191                 goto clean;
    192         }
    193 
    194         if (res.mem_ranges.count < 1) {
    195                 usb_log_error("Incorrect mem range count: %zu",
    196                     res.mem_ranges.count);
    197                 ret = EINVAL;
    198                 goto clean;
    199         }
    200270
    201271        /* Map EHCI registers */
    202272        void *regs = NULL;
    203         ret = pio_enable_range(&res.mem_ranges.ranges[0], &regs);
    204         if (ret != EOK) {
     273        int rc = pio_enable_range(reg_range, &regs);
     274        if (rc != EOK) {
    205275                usb_log_error("Failed to map registers %p: %s.\n",
    206                     RNGABSPTR(res.mem_ranges.ranges[0]), str_error(ret));
    207                 goto clean;
    208         }
    209 
    210         usb_log_debug("Registers mapped at: %p.\n", regs);
    211 
    212         ehci_caps_regs_t *ehci_caps = regs;
    213 
    214         const uint32_t hcc_params = EHCI_RD(ehci_caps->hccparams);
    215         usb_log_debug2("Value of hcc params register: %x.\n", hcc_params);
     276                    RNGABSPTR(*reg_range), str_error(rc));
     277                return rc;
     278        }
     279
     280        usb_log_debug2("Registers mapped at: %p.\n", regs);
     281
     282        const uint32_t hcc_params =
     283            *(uint32_t*)(regs + HCC_PARAMS_OFFSET);
     284        usb_log_debug("Value of hcc params register: %x.\n", hcc_params);
    216285
    217286        /* Read value of EHCI Extended Capabilities Pointer
    218287         * position of EEC registers (points to PCI config space) */
    219288        const uint32_t eecp =
    220             (hcc_params >> EHCI_CAPS_HCC_EECP_SHIFT) & EHCI_CAPS_HCC_EECP_MASK;
    221         usb_log_debug2("Value of EECP: %x.\n", eecp);
    222 
    223         ret = disable_extended_caps(parent_sess, eecp);
    224         if (ret != EOK) {
     289            (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
     290        usb_log_debug("Value of EECP: %x.\n", eecp);
     291
     292        rc = disable_extended_caps(device, eecp);
     293        if (rc != EOK) {
    225294                usb_log_error("Failed to disable extended capabilities: %s.\n",
    226                     str_error(ret));
    227                     goto clean;
    228         }
    229 clean:
    230         //TODO unmap registers
    231         hw_res_list_parsed_clean(&res);
    232         async_hangup(parent_sess);
    233         return ret;
     295                    str_error(rc));
     296                return rc;
     297        }
     298
     299        /*
     300         * TURN OFF EHCI FOR NOW, DRIVER WILL REINITIALIZE IT IF NEEDED
     301         */
     302
     303        /* Get size of capability registers in memory space. */
     304        const unsigned operation_offset = *(uint8_t*)regs;
     305        usb_log_debug("USBCMD offset: %d.\n", operation_offset);
     306
     307        /* Zero USBCMD register. */
     308        volatile uint32_t *usbcmd =
     309            (uint32_t*)((uint8_t*)regs + operation_offset + CMD_OFFSET);
     310        volatile uint32_t *usbsts =
     311            (uint32_t*)((uint8_t*)regs + operation_offset + STS_OFFSET);
     312        volatile uint32_t *usbconf =
     313            (uint32_t*)((uint8_t*)regs + operation_offset + CFG_OFFSET);
     314        volatile uint32_t *usbint =
     315            (uint32_t*)((uint8_t*)regs + operation_offset + INT_OFFSET);
     316        usb_log_debug("USBCMD value: %x.\n", *usbcmd);
     317        if (*usbcmd & USBCMD_RUN) {
     318                *usbsts = 0x3f; /* ack all interrupts */
     319                *usbint = 0; /* disable all interrupts */
     320                *usbconf = 0; /* release control of RH ports */
     321
     322                *usbcmd = 0;
     323                /* Wait until hc is halted */
     324                while ((*usbsts & USBSTS_HALTED) == 0);
     325                usb_log_info("EHCI turned off.\n");
     326        } else {
     327                usb_log_info("EHCI was not running.\n");
     328        }
     329        usb_log_debug("Registers: \n"
     330            "\t USBCMD(%p): %x(0x00080000 = at least 1ms between interrupts)\n"
     331            "\t USBSTS(%p): %x(0x00001000 = HC halted)\n"
     332            "\t USBINT(%p): %x(0x0 = no interrupts).\n"
     333            "\t CONFIG(%p): %x(0x0 = ports controlled by companion hc).\n",
     334            usbcmd, *usbcmd, usbsts, *usbsts, usbint, *usbint, usbconf,*usbconf);
     335
     336        return rc;
    234337}
    235338
Note: See TracChangeset for help on using the changeset viewer.