Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * Deal with PCI device quirks
4 : : *
5 : : * Copyright 2017-2018 IBM Corp.
6 : : */
7 : :
8 : : #define pr_fmt(fmt) "PCI-QUIRK: " fmt
9 : :
10 : : #include <skiboot.h>
11 : : #include <pci.h>
12 : : #include <pci-cfg.h>
13 : : #include <pci-quirk.h>
14 : : #include <platform.h>
15 : : #include <ast.h>
16 : :
17 : 0 : static int64_t cfg_block_filter(void *dev __unused,
18 : : struct pci_cfg_reg_filter *pcrf __unused,
19 : : uint32_t offset __unused, uint32_t len,
20 : : uint32_t *data, bool write)
21 : : {
22 : 0 : if (write)
23 : 0 : return OPAL_SUCCESS;
24 : :
25 : 0 : switch (len) {
26 : 0 : case 4:
27 : 0 : *data = 0x0;
28 : 0 : return OPAL_SUCCESS;
29 : 0 : case 2:
30 : 0 : *((uint16_t *)data) = 0x0;
31 : 0 : return OPAL_SUCCESS;
32 : 0 : case 1:
33 : 0 : *((uint8_t *)data) = 0x0;
34 : 0 : return OPAL_SUCCESS;
35 : : }
36 : :
37 : 0 : return OPAL_PARAMETER; /* should never happen */
38 : : }
39 : :
40 : : /* blocks config accesses to registers in the range: [start, end] */
41 : : #define BLOCK_CFG_RANGE(pd, start, end) \
42 : : pci_add_cfg_reg_filter(pd, start, end - start + 1, \
43 : : PCI_REG_FLAG_WRITE | PCI_REG_FLAG_READ, \
44 : : cfg_block_filter);
45 : :
46 : 0 : static void quirk_microsemi_gen4_sw(struct phb *phb, struct pci_device *pd)
47 : : {
48 : : uint8_t data;
49 : : bool frozen;
50 : : int offset;
51 : : int start;
52 : :
53 : 0 : pci_check_clear_freeze(phb);
54 : :
55 : : /*
56 : : * Reading from 0xff should trigger a UR on the affected switches.
57 : : * If we don't get a freeze then we don't need the workaround
58 : : */
59 : 0 : pci_cfg_read8(phb, pd->bdfn, 0xff, &data);
60 : 0 : frozen = pci_check_clear_freeze(phb);
61 : 0 : if (!frozen)
62 : 0 : return;
63 : :
64 : 0 : for (start = -1, offset = 0; offset < 4096; offset++) {
65 : 0 : pci_cfg_read8(phb, pd->bdfn, offset, &data);
66 : 0 : frozen = pci_check_clear_freeze(phb);
67 : :
68 : 0 : if (start < 0 && frozen) { /* new UR range */
69 : 0 : start = offset;
70 : 0 : } else if (start >= 0 && !frozen) { /* end of range */
71 : 0 : BLOCK_CFG_RANGE(pd, start, offset - 1);
72 : 0 : PCINOTICE(phb, pd->bdfn, "Applied UR workaround to [%03x..%03x]\n", start, offset - 1);
73 : :
74 : 0 : start = -1;
75 : : }
76 : : }
77 : :
78 : : /* range lasted until the end of config space */
79 : 0 : if (start >= 0) {
80 : 0 : BLOCK_CFG_RANGE(pd, start, 0xfff);
81 : 0 : PCINOTICE(phb, pd->bdfn, "Applied UR workaround to [%03x..fff]\n", start);
82 : : }
83 : : }
84 : :
85 : 0 : static void quirk_astbmc_vga(struct phb *phb __unused,
86 : : struct pci_device *pd)
87 : : {
88 : 0 : struct dt_node *np = pd->dn;
89 : : uint32_t revision, mcr_configuration, mcr_scu_mpll, mcr_scu_strap;
90 : :
91 : 0 : if (ast_sio_is_enabled()) {
92 : 0 : revision = ast_ahb_readl(SCU_REVISION_ID);
93 : 0 : mcr_configuration = ast_ahb_readl(MCR_CONFIGURATION);
94 : 0 : mcr_scu_mpll = ast_ahb_readl(MCR_SCU_MPLL);
95 : 0 : mcr_scu_strap = ast_ahb_readl(MCR_SCU_STRAP);
96 : : } else {
97 : : /* Previously we would warn, now SIO disabled by design */
98 : 0 : prlog(PR_INFO, "Assumed platform default parameters for %s\n",
99 : : __func__);
100 : 0 : revision = bmc_platform->hw->scu_revision_id;
101 : 0 : mcr_configuration = bmc_platform->hw->mcr_configuration;
102 : 0 : mcr_scu_mpll = bmc_platform->hw->mcr_scu_mpll;
103 : 0 : mcr_scu_strap = bmc_platform->hw->mcr_scu_strap;
104 : : }
105 : :
106 : 0 : dt_add_property_cells(np, "aspeed,scu-revision-id", revision);
107 : 0 : dt_add_property_cells(np, "aspeed,mcr-configuration", mcr_configuration);
108 : 0 : dt_add_property_cells(np, "aspeed,mcr-scu-mpll", mcr_scu_mpll);
109 : 0 : dt_add_property_cells(np, "aspeed,mcr-scu-strap", mcr_scu_strap);
110 : 0 : }
111 : :
112 : : /* Quirks are: {fixup function, vendor ID, (device ID or PCI_ANY_ID)} */
113 : : static const struct pci_quirk quirk_table[] = {
114 : : /* ASPEED 2400 VGA device */
115 : : { 0x1a03, 0x2000, &quirk_astbmc_vga },
116 : : { 0x11f8, 0x4052, &quirk_microsemi_gen4_sw },
117 : : { 0, 0, NULL }
118 : : };
119 : :
120 : 4 : static void __pci_handle_quirk(struct phb *phb, struct pci_device *pd,
121 : : const struct pci_quirk *quirks)
122 : : {
123 : 8 : while (quirks->vendor_id) {
124 : 4 : if (quirks->vendor_id == PCI_VENDOR_ID(pd->vdid) &&
125 : 2 : (quirks->device_id == PCI_ANY_ID ||
126 : 2 : quirks->device_id == PCI_DEVICE_ID(pd->vdid)))
127 : 1 : quirks->fixup(phb, pd);
128 : 4 : quirks++;
129 : : }
130 : 4 : }
131 : :
132 : 0 : void pci_handle_quirk(struct phb *phb, struct pci_device *pd)
133 : : {
134 : 0 : __pci_handle_quirk(phb, pd, quirk_table);
135 : 0 : }
|