Angel Pons | c74dae9 | 2020-04-02 23:48:16 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Kyösti Mälkki | d2cdfff | 2019-03-05 07:56:38 +0200 | [diff] [blame] | 2 | |
| 3 | #include <stdint.h> |
Kyösti Mälkki | 3f98d41 | 2019-07-29 16:38:14 +0300 | [diff] [blame] | 4 | #include <console/console.h> |
Kyösti Mälkki | 9c0e14e | 2019-01-23 16:46:35 +0200 | [diff] [blame] | 5 | #include <device/pci.h> |
| 6 | #include <device/pci_def.h> |
| 7 | #include <device/pci_ops.h> |
| 8 | #include <device/pci_type.h> |
Kyösti Mälkki | d2cdfff | 2019-03-05 07:56:38 +0200 | [diff] [blame] | 9 | |
Shelley Chen | 4e9bb33 | 2021-10-20 15:43:45 -0700 | [diff] [blame] | 10 | u8 *const pci_mmconf = (void *)(uintptr_t)CONFIG_ECAM_MMCONF_BASE_ADDRESS; |
Kyösti Mälkki | 9c0e14e | 2019-01-23 16:46:35 +0200 | [diff] [blame] | 11 | |
| 12 | /** |
| 13 | * Given a device, a capability type, and a last position, return the next |
| 14 | * matching capability. Always start at the head of the list. |
| 15 | * |
| 16 | * @param dev Pointer to the device structure. |
| 17 | * @param cap PCI_CAP_LIST_ID of the PCI capability we're looking for. |
| 18 | * @param last Location of the PCI capability register to start from. |
| 19 | * @return The next matching capability. |
| 20 | */ |
| 21 | u16 pci_s_find_next_capability(pci_devfn_t dev, u16 cap, u16 last) |
| 22 | { |
| 23 | u16 pos = 0; |
| 24 | u16 status; |
| 25 | int reps = 48; |
| 26 | |
| 27 | status = pci_s_read_config16(dev, PCI_STATUS); |
| 28 | if (!(status & PCI_STATUS_CAP_LIST)) |
| 29 | return 0; |
| 30 | |
| 31 | u8 hdr_type = pci_s_read_config8(dev, PCI_HEADER_TYPE); |
| 32 | switch (hdr_type & 0x7f) { |
| 33 | case PCI_HEADER_TYPE_NORMAL: |
| 34 | case PCI_HEADER_TYPE_BRIDGE: |
| 35 | pos = PCI_CAPABILITY_LIST; |
| 36 | break; |
| 37 | case PCI_HEADER_TYPE_CARDBUS: |
| 38 | pos = PCI_CB_CAPABILITY_LIST; |
| 39 | break; |
| 40 | default: |
| 41 | return 0; |
| 42 | } |
| 43 | |
| 44 | pos = pci_s_read_config8(dev, pos); |
| 45 | while (reps-- && (pos >= 0x40)) { /* Loop through the linked list. */ |
| 46 | int this_cap; |
| 47 | |
| 48 | pos &= ~3; |
| 49 | this_cap = pci_s_read_config8(dev, pos + PCI_CAP_LIST_ID); |
| 50 | if (this_cap == 0xff) |
| 51 | break; |
| 52 | |
| 53 | if (!last && (this_cap == cap)) |
| 54 | return pos; |
| 55 | |
| 56 | if (last == pos) |
| 57 | last = 0; |
| 58 | |
| 59 | pos = pci_s_read_config8(dev, pos + PCI_CAP_LIST_NEXT); |
| 60 | } |
| 61 | return 0; |
| 62 | } |
| 63 | |
| 64 | /** |
| 65 | * Given a device, and a capability type, return the next matching |
| 66 | * capability. Always start at the head of the list. |
| 67 | * |
| 68 | * @param dev Pointer to the device structure. |
| 69 | * @param cap PCI_CAP_LIST_ID of the PCI capability we're looking for. |
| 70 | * @return The next matching capability. |
| 71 | */ |
| 72 | u16 pci_s_find_capability(pci_devfn_t dev, u16 cap) |
| 73 | { |
| 74 | return pci_s_find_next_capability(dev, cap, 0); |
| 75 | } |
Kyösti Mälkki | 3f98d41 | 2019-07-29 16:38:14 +0300 | [diff] [blame] | 76 | |
| 77 | void __noreturn pcidev_die(void) |
| 78 | { |
| 79 | die("PCI: dev is NULL!\n"); |
| 80 | } |
Tim Wawrzynczak | 8a1ad13 | 2020-11-05 14:38:51 -0700 | [diff] [blame] | 81 | |
Tim Wawrzynczak | 93982c3 | 2021-04-29 09:45:59 -0600 | [diff] [blame] | 82 | bool pci_dev_is_wake_source(pci_devfn_t dev) |
Tim Wawrzynczak | 8a1ad13 | 2020-11-05 14:38:51 -0700 | [diff] [blame] | 83 | { |
| 84 | unsigned int pm_cap; |
| 85 | uint16_t pmcs; |
| 86 | |
Tim Wawrzynczak | 93982c3 | 2021-04-29 09:45:59 -0600 | [diff] [blame] | 87 | pm_cap = pci_s_find_capability(dev, PCI_CAP_ID_PM); |
Tim Wawrzynczak | 8a1ad13 | 2020-11-05 14:38:51 -0700 | [diff] [blame] | 88 | if (!pm_cap) |
| 89 | return false; |
| 90 | |
Tim Wawrzynczak | 93982c3 | 2021-04-29 09:45:59 -0600 | [diff] [blame] | 91 | pmcs = pci_s_read_config16(dev, pm_cap + PCI_PM_CTRL); |
Tim Wawrzynczak | 8a1ad13 | 2020-11-05 14:38:51 -0700 | [diff] [blame] | 92 | |
| 93 | /* PCI Device is a wake source if PME_ENABLE and PME_STATUS are set in PMCS register. */ |
| 94 | return (pmcs & PCI_PM_CTRL_PME_ENABLE) && (pmcs & PCI_PM_CTRL_PME_STATUS); |
| 95 | } |