blob: c46b53f516d65d7d85953e0054b5c42200376cf2 [file] [log] [blame]
Jianjun Wang270b0b62021-07-14 15:38:19 +08001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <commonlib/stdlib.h>
4#include <console/console.h>
5#include <device/device.h>
6#include <device/mmio.h>
7#include <device/pci.h>
8#include <device/pci_def.h>
9#include <device/pci_ids.h>
10#include <device/resource.h>
11#include <delay.h>
12#include <lib.h>
13#include <soc/addressmap.h>
14#include <soc/pcie.h>
15#include <soc/pcie_common.h>
Jianjun Wangc0808b62022-03-14 20:38:18 +080016#include <soc/soc_chip.h>
Jianjun Wang270b0b62021-07-14 15:38:19 +080017#include <stdlib.h>
18#include <types.h>
19
20#define PCIE_SETTING_REG 0x80
21#define PCIE_PCI_IDS_1 0x9c
22#define PCI_CLASS(class) ((class) << 8)
23#define PCIE_RC_MODE BIT(0)
24
25#define PCIE_CFGNUM_REG 0x140
26#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0))
27#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8))
28#define PCIE_CFG_OFFSET_ADDR 0x1000
29#define PCIE_CFG_HEADER(bus, devfn) \
30 (PCIE_CFG_BUS(bus) | PCIE_CFG_DEVFN(devfn))
31
32#define PCIE_RST_CTRL_REG 0x148
33#define PCIE_MAC_RSTB BIT(0)
34#define PCIE_PHY_RSTB BIT(1)
35#define PCIE_BRG_RSTB BIT(2)
36#define PCIE_PE_RSTB BIT(3)
37
38#define PCIE_LTSSM_STATUS_REG 0x150
39#define PCIE_LTSSM_STATE(val) (((val) >> 24) & 0x1f)
40
41#define PCIE_LINK_STATUS_REG 0x154
42#define PCIE_CTRL_LINKUP BIT(8)
43
44#define PCI_NUM_INTX 4
45#define PCIE_INT_ENABLE_REG 0x180
46#define PCIE_INTX_SHIFT 24
47#define PCIE_INTX_ENABLE \
48 GENMASK(PCIE_INTX_SHIFT + PCI_NUM_INTX - 1, PCIE_INTX_SHIFT)
49
50#define PCIE_TRANS_TABLE_BASE_REG 0x800
51#define PCIE_ATR_SRC_ADDR_MSB_OFFSET 0x4
52#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET 0x8
53#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET 0xc
54#define PCIE_ATR_TRSL_PARAM_OFFSET 0x10
55#define PCIE_ATR_TLB_SET_OFFSET 0x20
56
57#define PCIE_MAX_TRANS_TABLES 8
58#define PCIE_ATR_EN BIT(0)
59#define PCIE_ATR_SIZE(size) \
60 (((((size) - 1) << 1) & GENMASK(6, 1)) | PCIE_ATR_EN)
61#define PCIE_ATR_ID(id) ((id) & GENMASK(3, 0))
62#define PCIE_ATR_TYPE_MEM PCIE_ATR_ID(0)
63#define PCIE_ATR_TYPE_IO PCIE_ATR_ID(1)
64#define PCIE_ATR_TLP_TYPE(type) (((type) << 16) & GENMASK(18, 16))
65#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0)
66#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2)
67
Jianjun Wang270b0b62021-07-14 15:38:19 +080068/* LTSSM state in PCIE_LTSSM_STATUS_REG bit[28:24] */
69static const char *const ltssm_str[] = {
70 "detect.quiet", /* 0x00 */
71 "detect.active", /* 0x01 */
72 "polling.active", /* 0x02 */
73 "polling.compliance", /* 0x03 */
74 "polling.configuration", /* 0x04 */
75 "config.linkwidthstart", /* 0x05 */
76 "config.linkwidthaccept", /* 0x06 */
77 "config.lanenumwait", /* 0x07 */
78 "config.lanenumaccept", /* 0x08 */
79 "config.complete", /* 0x09 */
80 "config.idle", /* 0x0A */
81 "recovery.receiverlock", /* 0x0B */
82 "recovery.equalization", /* 0x0C */
83 "recovery.speed", /* 0x0D */
84 "recovery.receiverconfig", /* 0x0E */
85 "recovery.idle", /* 0x0F */
86 "L0", /* 0x10 */
87 "L0s", /* 0x11 */
88 "L1.entry", /* 0x12 */
89 "L1.idle", /* 0x13 */
90 "L2.idle", /* 0x14 */
91 "L2.transmitwake", /* 0x15 */
92 "disable", /* 0x16 */
93 "loopback.entry", /* 0x17 */
94 "loopback.active", /* 0x18 */
95 "loopback.exit", /* 0x19 */
96 "hotreset", /* 0x1A */
97};
98
Jianjun Wang51113262022-03-15 13:43:14 +080099static uintptr_t mtk_pcie_get_controller_base(pci_devfn_t devfn)
100{
101 struct device *root_dev;
102 const mtk_soc_config_t *config;
103 static uintptr_t base = 0;
104
105 if (!base) {
106 root_dev = pcidev_path_on_root(devfn);
107 config = config_of(root_dev);
108 base = config->pcie_config.base;
109 }
110
111 return base;
112}
113
Jianjun Wang270b0b62021-07-14 15:38:19 +0800114volatile union pci_bank *pci_map_bus(pci_devfn_t dev)
115{
116 u32 val, devfn, bus;
Jianjun Wang51113262022-03-15 13:43:14 +0800117 uintptr_t base;
Jianjun Wang270b0b62021-07-14 15:38:19 +0800118
119 devfn = PCI_DEV2DEVFN(dev);
120 bus = PCI_DEV2SEGBUS(dev);
121 val = PCIE_CFG_HEADER(bus, devfn);
122
Jianjun Wang51113262022-03-15 13:43:14 +0800123 base = mtk_pcie_get_controller_base(dev);
124 write32p(base + PCIE_CFGNUM_REG, val);
Jianjun Wang270b0b62021-07-14 15:38:19 +0800125
Jianjun Wang51113262022-03-15 13:43:14 +0800126 return (void *)(base + PCIE_CFG_OFFSET_ADDR);
Jianjun Wang270b0b62021-07-14 15:38:19 +0800127}
128
129static int mtk_pcie_set_trans_window(struct device *dev, uintptr_t table,
130 const struct mtk_pcie_mmio_res *mmio_res)
131{
132 const char *range_type;
133 uint32_t table_attr;
134
135 if (!mmio_res)
136 return -1;
137
138 if (mmio_res->type == IORESOURCE_IO) {
139 range_type = "IO";
140 table_attr = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
141 } else if (mmio_res->type == IORESOURCE_MEM) {
142 range_type = "MEM";
143 table_attr = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM;
144 } else {
145 printk(BIOS_ERR, "%s: Unknown trans table type %#lx\n",
146 __func__, mmio_res->type);
147 return -1;
148 }
149
150 write32p(table, mmio_res->cpu_addr |
151 PCIE_ATR_SIZE(__fls(mmio_res->size)));
152 write32p(table + PCIE_ATR_SRC_ADDR_MSB_OFFSET, 0);
153 write32p(table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET, mmio_res->pci_addr);
154 write32p(table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET, 0);
155 write32p(table + PCIE_ATR_TRSL_PARAM_OFFSET, table_attr);
156
157 printk(BIOS_INFO,
158 "%s: set %s trans window: cpu_addr = %#x, pci_addr = %#x, size = %#x\n",
159 __func__, range_type, mmio_res->cpu_addr, mmio_res->pci_addr,
160 mmio_res->size);
161
162 return 0;
163}
164
165static void mtk_pcie_domain_new_res(struct device *dev, unsigned int index,
166 const struct mtk_pcie_mmio_res *mmio_res)
167{
168 struct resource *res;
169
170 if (!mmio_res)
171 return;
172
173 res = new_resource(dev, index);
174 res->base = mmio_res->cpu_addr;
175 res->limit = mmio_res->cpu_addr + mmio_res->size - 1;
176 res->flags = mmio_res->type | IORESOURCE_SUBTRACTIVE |
177 IORESOURCE_ASSIGNED;
178}
179
180void mtk_pcie_domain_read_resources(struct device *dev)
181{
Jianjun Wangc0808b62022-03-14 20:38:18 +0800182 const mtk_soc_config_t *config = config_of(dev);
183 const struct mtk_pcie_config *conf = &config->pcie_config;
Jianjun Wang270b0b62021-07-14 15:38:19 +0800184
185 mtk_pcie_domain_new_res(dev, IOINDEX_SUBTRACTIVE(0, 0),
Jianjun Wangc0808b62022-03-14 20:38:18 +0800186 &conf->mmio_res_io);
Jianjun Wang270b0b62021-07-14 15:38:19 +0800187
188 mtk_pcie_domain_new_res(dev, IOINDEX_SUBTRACTIVE(1, 0),
Jianjun Wangc0808b62022-03-14 20:38:18 +0800189 &conf->mmio_res_mem);
Jianjun Wang270b0b62021-07-14 15:38:19 +0800190}
191
192void mtk_pcie_domain_set_resources(struct device *dev)
193{
Jianjun Wangc0808b62022-03-14 20:38:18 +0800194 const mtk_soc_config_t *config = config_of(dev);
195 const struct mtk_pcie_config *conf = &config->pcie_config;
Jianjun Wang270b0b62021-07-14 15:38:19 +0800196 uintptr_t table;
197
198 /* Initialize I/O space constraints. */
Jianjun Wangc0808b62022-03-14 20:38:18 +0800199 table = conf->base + PCIE_TRANS_TABLE_BASE_REG;
200 if (mtk_pcie_set_trans_window(dev, table, &conf->mmio_res_io) < 0)
Jianjun Wang270b0b62021-07-14 15:38:19 +0800201 printk(BIOS_ERR, "%s: Failed to set IO window\n", __func__);
202
203 /* Initialize memory resources constraints. */
Jianjun Wangc0808b62022-03-14 20:38:18 +0800204 table = conf->base + PCIE_TRANS_TABLE_BASE_REG +
Jianjun Wang270b0b62021-07-14 15:38:19 +0800205 PCIE_ATR_TLB_SET_OFFSET;
Jianjun Wangc0808b62022-03-14 20:38:18 +0800206 if (mtk_pcie_set_trans_window(dev, table, &conf->mmio_res_mem) < 0)
Jianjun Wang270b0b62021-07-14 15:38:19 +0800207 printk(BIOS_ERR, "%s: Failed to set MEM window\n", __func__);
208
209 pci_domain_set_resources(dev);
210}
211
212void mtk_pcie_domain_enable(struct device *dev)
213{
Jianjun Wangc0808b62022-03-14 20:38:18 +0800214 const mtk_soc_config_t *config = config_of(dev);
Jianjun Wang51113262022-03-15 13:43:14 +0800215 const struct mtk_pcie_config *conf = &config->pcie_config;
Jianjun Wangc0808b62022-03-14 20:38:18 +0800216 const char *ltssm_state;
217 size_t tries = 0;
218 uint32_t val;
Jianjun Wang270b0b62021-07-14 15:38:19 +0800219
Jianjun Wangc0808b62022-03-14 20:38:18 +0800220 /* Set as RC mode */
Jianjun Wang51113262022-03-15 13:43:14 +0800221 val = read32p(conf->base + PCIE_SETTING_REG);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800222 val |= PCIE_RC_MODE;
Jianjun Wang51113262022-03-15 13:43:14 +0800223 write32p(conf->base + PCIE_SETTING_REG, val);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800224
225 /* Set class code */
Jianjun Wang51113262022-03-15 13:43:14 +0800226 val = read32p(conf->base + PCIE_PCI_IDS_1);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800227 val &= ~GENMASK(31, 8);
228 val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI << 8);
Jianjun Wang51113262022-03-15 13:43:14 +0800229 write32p(conf->base + PCIE_PCI_IDS_1, val);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800230
231 /* Mask all INTx interrupts */
Jianjun Wang51113262022-03-15 13:43:14 +0800232 val = read32p(conf->base + PCIE_INT_ENABLE_REG);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800233 val &= ~PCIE_INTX_ENABLE;
Jianjun Wang51113262022-03-15 13:43:14 +0800234 write32p(conf->base + PCIE_INT_ENABLE_REG, val);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800235
236 /* De-assert reset signals */
Jianjun Wang51113262022-03-15 13:43:14 +0800237 mtk_pcie_reset(conf->base + PCIE_RST_CTRL_REG, false);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800238
239 if (!retry(100,
Jianjun Wang51113262022-03-15 13:43:14 +0800240 (tries++, read32p(conf->base + PCIE_LINK_STATUS_REG) &
Jianjun Wangc0808b62022-03-14 20:38:18 +0800241 PCIE_CTRL_LINKUP), mdelay(1))) {
Jianjun Wang51113262022-03-15 13:43:14 +0800242 val = read32p(conf->base + PCIE_LTSSM_STATUS_REG);
Jianjun Wangc0808b62022-03-14 20:38:18 +0800243 ltssm_state = PCIE_LTSSM_STATE(val) >= ARRAY_SIZE(ltssm_str) ?
244 "Unknown state" : ltssm_str[PCIE_LTSSM_STATE(val)];
245 printk(BIOS_ERR, "%s: PCIe link down, current ltssm state: %s\n",
246 __func__, ltssm_state);
Jianjun Wang270b0b62021-07-14 15:38:19 +0800247 return;
Jianjun Wangc0808b62022-03-14 20:38:18 +0800248 }
Jianjun Wang270b0b62021-07-14 15:38:19 +0800249
Jianjun Wangc0808b62022-03-14 20:38:18 +0800250 printk(BIOS_INFO, "%s: PCIe link up success (%ld tries)\n", __func__,
251 tries);
Jianjun Wang270b0b62021-07-14 15:38:19 +0800252}