Ignore:
File:
1 edited

Legend:

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

    r99e8fb7b r615abda  
    4646
    4747#include "res.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)
     48#include "ehci_regs.h"
    6049
    6150#define USBLEGSUP_OFFSET 0
     
    6756#define WAIT_STEP 10
    6857
    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  */
    77 int 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             EXCHANGE_SERIALIZE, 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  */
    114 int enable_interrupts(ddf_dev_t *device)
    115 {
    116         async_sess_t *parent_sess = devman_parent_device_connect(
    117             EXCHANGE_SERIALIZE, 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 
    12758/** Implements BIOS hands-off routine as described in EHCI spec
    12859 *
     
    13162 * @return Error code.
    13263 */
    133 static int disable_extended_caps(ddf_dev_t *device, unsigned eecp)
     64static int disable_extended_caps(async_sess_t *parent_sess, unsigned eecp)
    13465{
    13566        /* nothing to do */
     
    13768                return EOK;
    13869
    139         async_sess_t *parent_sess = devman_parent_device_connect(
    140             EXCHANGE_SERIALIZE, ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);
    141         if (!parent_sess)
    142                 return ENOMEM;
    143 
    14470        /* Read the first EEC. i.e. Legacy Support register */
    14571        uint32_t usblegsup;
    146         int rc = pci_config_space_read_32(parent_sess,
     72        int ret = pci_config_space_read_32(parent_sess,
    14773            eecp + USBLEGSUP_OFFSET, &usblegsup);
    148         if (rc != EOK) {
    149                 usb_log_error("Failed to read USBLEGSUP: %s.\n",
    150                     str_error(rc));
    151                 goto error;
    152         }
    153 
     74        if (ret != EOK) {
     75                usb_log_error("Failed to read USBLEGSUP: %s.\n", str_error(ret));
     76                return ret;
     77        }
    15478        usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
    15579
     
    15781         * byte. (OS Control semaphore)*/
    15882        usb_log_debug("Requesting OS control.\n");
    159         rc = pci_config_space_write_8(parent_sess,
     83        ret = pci_config_space_write_8(parent_sess,
    16084            eecp + USBLEGSUP_OFFSET + 3, 1);
    161         if (rc != EOK) {
     85        if (ret != EOK) {
    16286                usb_log_error("Failed to request OS EHCI control: %s.\n",
    163                     str_error(rc));
    164                 goto error;
     87                    str_error(ret));
     88                return ret;
    16589        }
    16690
    16791        size_t wait = 0;
    16892        /* Wait for BIOS to release control. */
    169         rc = pci_config_space_read_32(
     93        ret = pci_config_space_read_32(
    17094            parent_sess, eecp + USBLEGSUP_OFFSET, &usblegsup);
    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)) {
     95        while ((ret == EOK) && (wait < DEFAULT_WAIT)
     96            && (usblegsup & USBLEGSUP_BIOS_CONTROL)) {
    17897                async_usleep(WAIT_STEP);
    179                 rc = pci_config_space_read_32(parent_sess,
     98                ret = pci_config_space_read_32(parent_sess,
    18099                    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                 }
    186100                wait += WAIT_STEP;
    187101        }
     
    189103        if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) {
    190104                usb_log_info("BIOS released control after %zu usec.\n", wait);
    191                 async_hangup(parent_sess);
    192105                return EOK;
    193106        }
     
    196109        usb_log_warning( "BIOS failed to release control after "
    197110            "%zu usecs, force it.\n", wait);
    198         rc = pci_config_space_write_32(parent_sess,
     111        ret = pci_config_space_write_32(parent_sess,
    199112            eecp + USBLEGSUP_OFFSET, USBLEGSUP_OS_CONTROL);
    200         if (rc != EOK) {
    201                 usb_log_error("Failed to force OS control: "
    202                     "%s.\n", str_error(rc));
    203                 goto error;
     113        if (ret != EOK) {
     114                usb_log_error("Failed to force OS control: %s.\n",
     115                    str_error(ret));
     116                return ret;
    204117        }
    205118
     
    213126                /* Read the second EEC Legacy Support and Control register */
    214127                uint32_t usblegctlsts;
    215                 rc = pci_config_space_read_32(parent_sess,
     128                ret = pci_config_space_read_32(parent_sess,
    216129                    eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
    217                 if (rc != EOK) {
     130                if (ret != EOK) {
    218131                        usb_log_error("Failed to get USBLEGCTLSTS: %s.\n",
    219                             str_error(rc));
    220                         goto error;
     132                            str_error(ret));
     133                        return ret;
    221134                }
    222 
    223135                usb_log_debug("USBLEGCTLSTS: %" PRIx32 ".\n", usblegctlsts);
    224136                /*
     
    227139                 * interfering. NOTE: Three upper bits are WC
    228140                 */
    229                 rc = pci_config_space_write_32(parent_sess,
     141                ret = pci_config_space_write_32(parent_sess,
    230142                    eecp + USBLEGCTLSTS_OFFSET, 0xe0000000);
    231                 if (rc != EOK) {
    232                         usb_log_error("Failed(%d) zero USBLEGCTLSTS.\n", rc);
    233                         goto error;
     143                if (ret != EOK) {
     144                        usb_log_error("Failed to zero USBLEGCTLSTS: %s\n",
     145                            str_error(ret));
     146                        return ret;
    234147                }
    235148
    236149                udelay(10);
    237                 rc = pci_config_space_read_32(parent_sess,
     150                /* read again to amke sure it's zeroed */
     151                ret = pci_config_space_read_32(parent_sess,
    238152                    eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
    239                 if (rc != EOK) {
     153                if (ret != EOK) {
    240154                        usb_log_error("Failed to get USBLEGCTLSTS 2: %s.\n",
    241                             str_error(rc));
    242                         goto error;
     155                            str_error(ret));
     156                        return ret;
    243157                }
    244 
    245158                usb_log_debug("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n",
    246159                    usblegctlsts);
     
    248161
    249162        /* Read again Legacy Support register */
    250         rc = pci_config_space_read_32(parent_sess,
     163        ret = pci_config_space_read_32(parent_sess,
    251164            eecp + USBLEGSUP_OFFSET, &usblegsup);
    252         if (rc != EOK) {
     165        if (ret != EOK) {
    253166                usb_log_error("Failed to read USBLEGSUP: %s.\n",
    254                     str_error(rc));
    255                 goto error;
    256         }
    257 
     167                    str_error(ret));
     168                return ret;
     169        }
    258170        usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
    259         async_hangup(parent_sess);
    260         return EOK;
    261 error:
    262         async_hangup(parent_sess);
    263         return rc;
     171        return ret;
    264172}
    265173
    266 int disable_legacy(ddf_dev_t *device, addr_range_t *reg_range)
     174int disable_legacy(ddf_dev_t *device)
    267175{
    268176        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
    269183        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        }
    270200
    271201        /* Map EHCI registers */
    272202        void *regs = NULL;
    273         int rc = pio_enable_range(reg_range, &regs);
    274         if (rc != EOK) {
     203        ret = pio_enable_range(&res.mem_ranges.ranges[0], &regs);
     204        if (ret != EOK) {
    275205                usb_log_error("Failed to map registers %p: %s.\n",
    276                     RNGABSPTR(*reg_range), str_error(rc));
    277                 return rc;
     206                    RNGABSPTR(res.mem_ranges.ranges[0]), str_error(ret));
     207                goto clean;
    278208        }
    279209
    280210        usb_log_debug2("Registers mapped at: %p.\n", regs);
    281211
    282         const uint32_t hcc_params =
    283             *(uint32_t*)(regs + HCC_PARAMS_OFFSET);
     212        ehci_caps_regs_t *ehci_caps = regs;
     213
     214        const uint32_t hcc_params = EHCI_RD(ehci_caps->hccparams);
    284215        usb_log_debug("Value of hcc params register: %x.\n", hcc_params);
    285216
     
    287218         * position of EEC registers (points to PCI config space) */
    288219        const uint32_t eecp =
    289             (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
     220            (hcc_params >> EHCI_CAPS_HCC_EECP_SHIFT) & EHCI_CAPS_HCC_EECP_MASK;
    290221        usb_log_debug("Value of EECP: %x.\n", eecp);
    291222
    292         rc = disable_extended_caps(device, eecp);
    293         if (rc != EOK) {
     223        ret = disable_extended_caps(parent_sess, eecp);
     224        if (ret != EOK) {
    294225                usb_log_error("Failed to disable extended capabilities: %s.\n",
    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;
     226                    str_error(ret));
     227                    goto clean;
     228        }
     229clean:
     230        //TODO unmap registers
     231        hw_res_list_parsed_clean(&res);
     232        async_hangup(parent_sess);
     233        return ret;
    337234}
    338235
Note: See TracChangeset for help on using the changeset viewer.