blob: 16a9dbfcb83cf6a17f50a9af3106c12367b8f231 [file] [log] [blame]
Ryder Lee42d37452019-08-22 12:26:49 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * MediaTek PCIe host controller driver.
4 *
5 * Copyright (c) 2017-2019 MediaTek Inc.
6 * Author: Ryder Lee <ryder.lee@mediatek.com>
7 * Honghui Zhang <honghui.zhang@mediatek.com>
8 */
9
10#include <common.h>
11#include <clk.h>
12#include <dm.h>
13#include <generic-phy.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060014#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070015#include <malloc.h>
Ryder Lee42d37452019-08-22 12:26:49 +020016#include <pci.h>
17#include <reset.h>
18#include <asm/io.h>
Simon Glass61b29b82020-02-03 07:36:15 -070019#include <dm/devres.h>
Simon Glasscd93d622020-05-10 11:40:13 -060020#include <linux/bitops.h>
Ryder Lee42d37452019-08-22 12:26:49 +020021#include <linux/iopoll.h>
22#include <linux/list.h>
Chuanjia Liu91ee45d2020-08-10 16:17:10 +080023#include "pci_internal.h"
Ryder Lee42d37452019-08-22 12:26:49 +020024
25/* PCIe shared registers */
26#define PCIE_SYS_CFG 0x00
27#define PCIE_INT_ENABLE 0x0c
28#define PCIE_CFG_ADDR 0x20
29#define PCIE_CFG_DATA 0x24
30
31/* PCIe per port registers */
32#define PCIE_BAR0_SETUP 0x10
33#define PCIE_CLASS 0x34
34#define PCIE_LINK_STATUS 0x50
35
36#define PCIE_PORT_INT_EN(x) BIT(20 + (x))
37#define PCIE_PORT_PERST(x) BIT(1 + (x))
38#define PCIE_PORT_LINKUP BIT(0)
39#define PCIE_BAR_MAP_MAX GENMASK(31, 16)
40
41#define PCIE_BAR_ENABLE BIT(0)
42#define PCIE_REVISION_ID BIT(0)
43#define PCIE_CLASS_CODE (0x60400 << 8)
44#define PCIE_CONF_REG(regn) (((regn) & GENMASK(7, 2)) | \
45 ((((regn) >> 8) & GENMASK(3, 0)) << 24))
46#define PCIE_CONF_ADDR(regn, bdf) \
47 (PCIE_CONF_REG(regn) | (bdf))
48
49/* MediaTek specific configuration registers */
50#define PCIE_FTS_NUM 0x70c
51#define PCIE_FTS_NUM_MASK GENMASK(15, 8)
52#define PCIE_FTS_NUM_L0(x) ((x) & 0xff << 8)
53
54#define PCIE_FC_CREDIT 0x73c
55#define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16))
56#define PCIE_FC_CREDIT_VAL(x) ((x) << 16)
57
Chuanjia Liu91ee45d2020-08-10 16:17:10 +080058/* PCIe V2 share registers */
59#define PCIE_SYS_CFG_V2 0x0
60#define PCIE_CSR_LTSSM_EN(x) BIT(0 + (x) * 8)
61#define PCIE_CSR_ASPM_L1_EN(x) BIT(1 + (x) * 8)
62
63/* PCIe V2 per-port registers */
64#define PCIE_CONF_VEND_ID 0x100
65#define PCIE_CONF_DEVICE_ID 0x102
66#define PCIE_CONF_CLASS_ID 0x106
67
68#define PCIE_AHB_TRANS_BASE0_L 0x438
69#define PCIE_AHB_TRANS_BASE0_H 0x43c
70#define AHB2PCIE_SIZE(x) ((x) & GENMASK(4, 0))
71#define PCIE_AXI_WINDOW0 0x448
72#define WIN_ENABLE BIT(7)
73
74/*
75 * Define PCIe to AHB window size as 2^33 to support max 8GB address space
76 * translate, support least 4GB DRAM size access from EP DMA(physical DRAM
77 * start from 0x40000000).
78 */
79#define PCIE2AHB_SIZE 0x21
80
81/* PCIe V2 configuration transaction header */
82#define PCIE_CFG_HEADER0 0x460
83#define PCIE_CFG_HEADER1 0x464
84#define PCIE_CFG_HEADER2 0x468
85#define PCIE_CFG_WDATA 0x470
86#define PCIE_APP_TLP_REQ 0x488
87#define PCIE_CFG_RDATA 0x48c
88#define APP_CFG_REQ BIT(0)
89#define APP_CPL_STATUS GENMASK(7, 5)
90
91#define CFG_WRRD_TYPE_0 4
92#define CFG_WR_FMT 2
93#define CFG_RD_FMT 0
94
95#define CFG_DW0_LENGTH(length) ((length) & GENMASK(9, 0))
96#define CFG_DW0_TYPE(type) (((type) << 24) & GENMASK(28, 24))
97#define CFG_DW0_FMT(fmt) (((fmt) << 29) & GENMASK(31, 29))
98#define CFG_DW2_REGN(regn) ((regn) & GENMASK(11, 2))
99#define CFG_DW2_FUN(fun) (((fun) << 16) & GENMASK(18, 16))
100#define CFG_DW2_DEV(dev) (((dev) << 19) & GENMASK(23, 19))
101#define CFG_DW2_BUS(bus) (((bus) << 24) & GENMASK(31, 24))
102#define CFG_HEADER_DW0(type, fmt) \
103 (CFG_DW0_LENGTH(1) | CFG_DW0_TYPE(type) | CFG_DW0_FMT(fmt))
104#define CFG_HEADER_DW1(where, size) \
105 (GENMASK(((size) - 1), 0) << ((where) & 0x3))
106#define CFG_HEADER_DW2(regn, fun, dev, bus) \
107 (CFG_DW2_REGN(regn) | CFG_DW2_FUN(fun) | \
108 CFG_DW2_DEV(dev) | CFG_DW2_BUS(bus))
109
110#define PCIE_RST_CTRL 0x510
111#define PCIE_PHY_RSTB BIT(0)
112#define PCIE_PIPE_SRSTB BIT(1)
113#define PCIE_MAC_SRSTB BIT(2)
114#define PCIE_CRSTB BIT(3)
115#define PCIE_PERSTB BIT(8)
116#define PCIE_LINKDOWN_RST_EN GENMASK(15, 13)
117#define PCIE_LINK_STATUS_V2 0x804
118#define PCIE_PORT_LINKUP_V2 BIT(11)
119
120#define PCI_VENDOR_ID_MEDIATEK 0x14c3
121
122enum MTK_PCIE_GEN {PCIE_V1, PCIE_V2, PCIE_V3};
123
Ryder Lee42d37452019-08-22 12:26:49 +0200124struct mtk_pcie_port {
125 void __iomem *base;
126 struct list_head list;
127 struct mtk_pcie *pcie;
128 struct reset_ctl reset;
129 struct clk sys_ck;
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800130 struct clk ahb_ck;
131 struct clk axi_ck;
132 struct clk aux_ck;
133 struct clk obff_ck;
134 struct clk pipe_ck;
Ryder Lee42d37452019-08-22 12:26:49 +0200135 struct phy phy;
136 u32 slot;
137};
138
139struct mtk_pcie {
140 void __iomem *base;
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800141 void *priv;
Ryder Lee42d37452019-08-22 12:26:49 +0200142 struct clk free_ck;
143 struct list_head ports;
144};
145
Simon Glassc4e72c42020-01-27 08:49:37 -0700146static int mtk_pcie_config_address(const struct udevice *udev, pci_dev_t bdf,
Ryder Lee42d37452019-08-22 12:26:49 +0200147 uint offset, void **paddress)
148{
149 struct mtk_pcie *pcie = dev_get_priv(udev);
150
151 writel(PCIE_CONF_ADDR(offset, bdf), pcie->base + PCIE_CFG_ADDR);
152 *paddress = pcie->base + PCIE_CFG_DATA + (offset & 3);
153
154 return 0;
155}
156
Simon Glassc4e72c42020-01-27 08:49:37 -0700157static int mtk_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
Ryder Lee42d37452019-08-22 12:26:49 +0200158 uint offset, ulong *valuep,
159 enum pci_size_t size)
160{
161 return pci_generic_mmap_read_config(bus, mtk_pcie_config_address,
162 bdf, offset, valuep, size);
163}
164
165static int mtk_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
166 uint offset, ulong value,
167 enum pci_size_t size)
168{
169 return pci_generic_mmap_write_config(bus, mtk_pcie_config_address,
170 bdf, offset, value, size);
171}
172
173static const struct dm_pci_ops mtk_pcie_ops = {
174 .read_config = mtk_pcie_read_config,
175 .write_config = mtk_pcie_write_config,
176};
177
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800178static int mtk_pcie_check_cfg_cpld(struct mtk_pcie_port *port)
179{
180 u32 val;
181 int err;
182
183 err = readl_poll_timeout(port->base + PCIE_APP_TLP_REQ, val,
184 !(val & APP_CFG_REQ), 100 * 1000);
185 if (err)
186 return -1;
187
188 if (readl(port->base + PCIE_APP_TLP_REQ) & APP_CPL_STATUS)
189 return -1;
190
191 return 0;
192}
193
194static int mtk_pcie_hw_rd_cfg(struct mtk_pcie_port *port, u32 bus, pci_dev_t devfn,
195 int where, int size, ulong *val)
196{
197 u32 tmp;
198
199 writel(CFG_HEADER_DW0(CFG_WRRD_TYPE_0, CFG_RD_FMT),
200 port->base + PCIE_CFG_HEADER0);
201 writel(CFG_HEADER_DW1(where, size), port->base + PCIE_CFG_HEADER1);
202 writel(CFG_HEADER_DW2(where, PCI_FUNC(devfn), PCI_DEV(devfn), bus),
203 port->base + PCIE_CFG_HEADER2);
204
205 /* Trigger h/w to transmit Cfgrd TLP */
206 tmp = readl(port->base + PCIE_APP_TLP_REQ);
207 tmp |= APP_CFG_REQ;
208 writel(tmp, port->base + PCIE_APP_TLP_REQ);
209
210 /* Check completion status */
211 if (mtk_pcie_check_cfg_cpld(port))
212 return -1;
213
214 /* Read cpld payload of Cfgrd */
215 *val = readl(port->base + PCIE_CFG_RDATA);
216
217 if (size == 1)
218 *val = (*val >> (8 * (where & 3))) & 0xff;
219 else if (size == 2)
220 *val = (*val >> (8 * (where & 3))) & 0xffff;
221
222 return 0;
223}
224
225static int mtk_pcie_hw_wr_cfg(struct mtk_pcie_port *port, u32 bus, pci_dev_t devfn,
226 int where, int size, u32 val)
227{
228 /* Write PCIe configuration transaction header for Cfgwr */
229 writel(CFG_HEADER_DW0(CFG_WRRD_TYPE_0, CFG_WR_FMT),
230 port->base + PCIE_CFG_HEADER0);
231 writel(CFG_HEADER_DW1(where, size), port->base + PCIE_CFG_HEADER1);
232 writel(CFG_HEADER_DW2(where, PCI_FUNC(devfn), PCI_DEV(devfn), bus),
233 port->base + PCIE_CFG_HEADER2);
234
235 /* Write Cfgwr data */
236 val = val << 8 * (where & 3);
237 writel(val, port->base + PCIE_CFG_WDATA);
238
239 /* Trigger h/w to transmit Cfgwr TLP */
240 val = readl(port->base + PCIE_APP_TLP_REQ);
241 val |= APP_CFG_REQ;
242 writel(val, port->base + PCIE_APP_TLP_REQ);
243
244 /* Check completion status */
245 return mtk_pcie_check_cfg_cpld(port);
246}
247
248static struct mtk_pcie_port *mtk_pcie_find_port(const struct udevice *bus,
249 pci_dev_t bdf)
250{
251 struct mtk_pcie *pcie = dev_get_priv(bus);
252 struct mtk_pcie_port *port;
253 struct udevice *dev;
Simon Glass8a8d24b2020-12-03 16:55:23 -0700254 struct pci_child_plat *pplat = NULL;
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800255 int ret = 0;
256
257 if (PCI_BUS(bdf) != 0) {
258 ret = pci_get_bus(PCI_BUS(bdf), &dev);
259 if (ret) {
260 debug("No such device,ret = %d\n", ret);
261 return NULL;
262 }
263
264 while (dev->parent->seq != 0)
265 dev = dev->parent;
266
Simon Glasscaa4daa2020-12-03 16:55:18 -0700267 pplat = dev_get_parent_plat(dev);
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800268 }
269
270 list_for_each_entry(port, &pcie->ports, list) {
271 if ((PCI_BUS(bdf) == 0) && (PCI_DEV(bdf) == port->slot))
272 return port;
273
274 if (PCI_BUS(bdf) != 0 && PCI_DEV(bdf) == 0 &&
275 PCI_DEV(pplat->devfn) == port->slot)
276 return port;
277 }
278
279 return NULL;
280}
281
282static int mtk_pcie_config_read(const struct udevice *bus, pci_dev_t bdf,
283 uint offset, ulong *valuep,
284 enum pci_size_t size)
285{
286 struct mtk_pcie_port *port;
287 int ret;
288
289 port = mtk_pcie_find_port(bus, bdf);
290 if (!port) {
291 *valuep = pci_get_ff(size);
292 return 0;
293 }
294
295 ret = mtk_pcie_hw_rd_cfg(port, PCI_BUS(bdf), bdf, offset, (1 << size), valuep);
296 if (ret)
297 *valuep = pci_get_ff(size);
298
299 return ret;
300}
301
302static int mtk_pcie_config_write(struct udevice *bus, pci_dev_t bdf,
303 uint offset, ulong value,
304 enum pci_size_t size)
305{
306 struct mtk_pcie_port *port;
307
308 port = mtk_pcie_find_port(bus, bdf);
309 if (!port)
310 return 0;
311
312 /* Do not modify RC bar 0/1. */
313 if (PCI_BUS(bdf) == 0 && (offset == 0x10 || offset == 0x14))
314 return 0;
315
316 return mtk_pcie_hw_wr_cfg(port, PCI_BUS(bdf), bdf, offset, (1 << size), value);
317}
318
319static const struct dm_pci_ops mtk_pcie_ops_v2 = {
320 .read_config = mtk_pcie_config_read,
321 .write_config = mtk_pcie_config_write,
322};
323
Ryder Lee42d37452019-08-22 12:26:49 +0200324static void mtk_pcie_port_free(struct mtk_pcie_port *port)
325{
326 list_del(&port->list);
327 free(port);
328}
329
330static int mtk_pcie_startup_port(struct mtk_pcie_port *port)
331{
332 struct mtk_pcie *pcie = port->pcie;
333 u32 slot = PCI_DEV(port->slot << 11);
334 u32 val;
335 int err;
336
337 /* assert port PERST_N */
338 setbits_le32(pcie->base + PCIE_SYS_CFG, PCIE_PORT_PERST(port->slot));
339 /* de-assert port PERST_N */
340 clrbits_le32(pcie->base + PCIE_SYS_CFG, PCIE_PORT_PERST(port->slot));
341
342 /* 100ms timeout value should be enough for Gen1/2 training */
343 err = readl_poll_timeout(port->base + PCIE_LINK_STATUS, val,
344 !!(val & PCIE_PORT_LINKUP), 100000);
345 if (err)
346 return -ETIMEDOUT;
347
348 /* disable interrupt */
349 clrbits_le32(pcie->base + PCIE_INT_ENABLE,
350 PCIE_PORT_INT_EN(port->slot));
351
352 /* map to all DDR region. We need to set it before cfg operation. */
353 writel(PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE,
354 port->base + PCIE_BAR0_SETUP);
355
356 /* configure class code and revision ID */
357 writel(PCIE_CLASS_CODE | PCIE_REVISION_ID, port->base + PCIE_CLASS);
358
359 /* configure FC credit */
360 writel(PCIE_CONF_ADDR(PCIE_FC_CREDIT, slot),
361 pcie->base + PCIE_CFG_ADDR);
362 clrsetbits_le32(pcie->base + PCIE_CFG_DATA, PCIE_FC_CREDIT_MASK,
363 PCIE_FC_CREDIT_VAL(0x806c));
364
365 /* configure RC FTS number to 250 when it leaves L0s */
366 writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, slot), pcie->base + PCIE_CFG_ADDR);
367 clrsetbits_le32(pcie->base + PCIE_CFG_DATA, PCIE_FTS_NUM_MASK,
368 PCIE_FTS_NUM_L0(0x50));
369
370 return 0;
371}
372
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800373static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
374{
375 struct mtk_pcie *pcie = port->pcie;
376 struct udevice *dev = pcie->priv;
377 struct pci_region *pci_mem;
378 u32 val;
379 int err;
380
381 /* MT7622/MT7629 platforms need to enable LTSSM and ASPM from PCIe subsys */
382 if (pcie->base) {
383 val = readl(pcie->base + PCIE_SYS_CFG_V2);
384 val |= PCIE_CSR_LTSSM_EN(port->slot) |
385 PCIE_CSR_ASPM_L1_EN(port->slot);
386 writel(val, pcie->base + PCIE_SYS_CFG_V2);
387 }
388
389 /* Assert all reset signals */
390 writel(0, port->base + PCIE_RST_CTRL);
391
392 /*
393 * Enable PCIe link down reset, if link status changed from link up to
394 * link down, this will reset MAC control registers and configuration
395 * space.
396 */
397 writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
398 udelay(500);
399
400 /* De-assert PHY, PE, PIPE, MAC and configuration reset */
401 val = readl(port->base + PCIE_RST_CTRL);
402 val |= PCIE_PHY_RSTB | PCIE_PIPE_SRSTB | PCIE_MAC_SRSTB | PCIE_CRSTB;
403 writel(val, port->base + PCIE_RST_CTRL);
404
405 mdelay(100);
406 val |= PCIE_PERSTB;
407 writel(val, port->base + PCIE_RST_CTRL);
408
409 /* Set up vendor ID and class code */
410 val = PCI_VENDOR_ID_MEDIATEK;
411 writew(val, port->base + PCIE_CONF_VEND_ID);
412
413 val = PCI_CLASS_BRIDGE_PCI;
414 writew(val, port->base + PCIE_CONF_CLASS_ID);
415
416 /* 100ms timeout value should be enough for Gen1/2 training */
417 err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
418 !!(val & PCIE_PORT_LINKUP_V2),
419 100 * 1000);
420 if (err)
421 return -ETIMEDOUT;
422
423 pci_get_regions(dev, NULL, &pci_mem, NULL);
424
425 /* Set AHB to PCIe translation windows */
426 val = lower_32_bits(pci_mem->bus_start) |
427 AHB2PCIE_SIZE(fls(pci_mem->size) - 1);
428 writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
429
430 val = upper_32_bits(pci_mem->bus_start);
431 writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
432
433 /* Set PCIe to AXI translation memory space.*/
434 val = PCIE2AHB_SIZE | WIN_ENABLE;
435 writel(val, port->base + PCIE_AXI_WINDOW0);
436
437 return 0;
438}
439
Ryder Lee42d37452019-08-22 12:26:49 +0200440static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
441{
442 int err;
443
444 err = clk_enable(&port->sys_ck);
445 if (err)
Chuanjia Liu9250d0b2020-08-31 15:53:12 +0800446 goto err_sys_clk;
Ryder Lee42d37452019-08-22 12:26:49 +0200447
448 err = reset_assert(&port->reset);
449 if (err)
Chuanjia Liu9250d0b2020-08-31 15:53:12 +0800450 goto err_reset;
Ryder Lee42d37452019-08-22 12:26:49 +0200451
452 err = reset_deassert(&port->reset);
453 if (err)
Chuanjia Liu9250d0b2020-08-31 15:53:12 +0800454 goto err_reset;
Ryder Lee42d37452019-08-22 12:26:49 +0200455
456 err = generic_phy_init(&port->phy);
457 if (err)
Chuanjia Liu9250d0b2020-08-31 15:53:12 +0800458 goto err_phy_init;
Ryder Lee42d37452019-08-22 12:26:49 +0200459
460 err = generic_phy_power_on(&port->phy);
461 if (err)
Chuanjia Liu9250d0b2020-08-31 15:53:12 +0800462 goto err_phy_on;
Ryder Lee42d37452019-08-22 12:26:49 +0200463
464 if (!mtk_pcie_startup_port(port))
465 return;
466
467 pr_err("Port%d link down\n", port->slot);
Chuanjia Liu9250d0b2020-08-31 15:53:12 +0800468
469 generic_phy_power_off(&port->phy);
470err_phy_on:
471 generic_phy_exit(&port->phy);
472err_phy_init:
473err_reset:
474 clk_disable(&port->sys_ck);
475err_sys_clk:
Ryder Lee42d37452019-08-22 12:26:49 +0200476 mtk_pcie_port_free(port);
477}
478
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800479static void mtk_pcie_enable_port_v2(struct mtk_pcie_port *port)
480{
481 int err = 0;
482
483 err = clk_enable(&port->sys_ck);
484 if (err) {
485 debug("clk_enable(sys_ck) failed: %d\n", err);
486 goto exit;
487 }
488
489 err = clk_enable(&port->ahb_ck);
490 if (err) {
491 debug("clk_enable(ahb_ck) failed: %d\n", err);
492 goto exit;
493 }
494
495 err = clk_enable(&port->aux_ck);
496 if (err) {
497 debug("clk_enable(aux_ck) failed: %d\n", err);
498 goto exit;
499 }
500
501 err = clk_enable(&port->axi_ck);
502 if (err) {
503 debug("clk_enable(axi_ck) failed: %d\n", err);
504 goto exit;
505 }
506
507 err = clk_enable(&port->obff_ck);
508 if (err) {
509 debug("clk_enable(obff_ck) failed: %d\n", err);
510 goto exit;
511 }
512
513 err = clk_enable(&port->pipe_ck);
514 if (err) {
515 debug("clk_enable(pipe_ck) failed: %d\n", err);
516 goto exit;
517 }
518
519 err = mtk_pcie_startup_port_v2(port);
520 if (!err)
521 return;
522
523 pr_err("Port%d link down\n", port->slot);
524exit:
525 mtk_pcie_port_free(port);
526}
527
Ryder Lee42d37452019-08-22 12:26:49 +0200528static int mtk_pcie_parse_port(struct udevice *dev, u32 slot)
529{
530 struct mtk_pcie *pcie = dev_get_priv(dev);
531 struct mtk_pcie_port *port;
532 char name[10];
533 int err;
534
535 port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
536 if (!port)
537 return -ENOMEM;
538
539 snprintf(name, sizeof(name), "port%d", slot);
540 port->base = dev_remap_addr_name(dev, name);
541 if (!port->base)
542 return -ENOENT;
543
544 snprintf(name, sizeof(name), "sys_ck%d", slot);
545 err = clk_get_by_name(dev, name, &port->sys_ck);
546 if (err)
547 return err;
548
549 err = reset_get_by_index(dev, slot, &port->reset);
550 if (err)
551 return err;
552
553 err = generic_phy_get_by_index(dev, slot, &port->phy);
554 if (err)
555 return err;
556
557 port->slot = slot;
558 port->pcie = pcie;
559
560 INIT_LIST_HEAD(&port->list);
561 list_add_tail(&port->list, &pcie->ports);
562
563 return 0;
564}
565
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800566static int mtk_pcie_parse_port_v2(struct udevice *dev, u32 slot)
567{
568 struct mtk_pcie *pcie = dev_get_priv(dev);
569 struct mtk_pcie_port *port;
570 char name[10];
571 int err;
572
573 port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
574 if (!port)
575 return -ENOMEM;
576
577 snprintf(name, sizeof(name), "port%d", slot);
578 port->base = dev_remap_addr_name(dev, name);
579 if (!port->base) {
580 debug("failed to map port%d base\n", slot);
581 return -ENOENT;
582 }
583
584 snprintf(name, sizeof(name), "sys_ck%d", slot);
585 err = clk_get_by_name(dev, name, &port->sys_ck);
586 if (err) {
587 debug("clk_get_by_name(sys_ck) failed: %d\n", err);
588 return err;
589 }
590
591 snprintf(name, sizeof(name), "ahb_ck%d", slot);
592 err = clk_get_by_name(dev, name, &port->ahb_ck);
593 if (err) {
594 debug("clk_get_by_name(ahb_ck) failed: %d\n", err);
595 return err;
596 }
597
598 snprintf(name, sizeof(name), "aux_ck%d", slot);
599 err = clk_get_by_name(dev, name, &port->aux_ck);
600 if (err) {
601 debug("clk_get_by_name(aux_ck) failed: %d\n", err);
602 return err;
603 }
604
605 snprintf(name, sizeof(name), "axi_ck%d", slot);
606 err = clk_get_by_name(dev, name, &port->axi_ck);
607 if (err) {
608 debug("clk_get_by_name(axi_ck) failed: %d\n", err);
609 return err;
610 }
611
612 snprintf(name, sizeof(name), "obff_ck%d", slot);
613 err = clk_get_by_name(dev, name, &port->obff_ck);
614 if (err) {
615 debug("clk_get_by_name(obff_ck) failed: %d\n", err);
616 return err;
617 }
618
619 snprintf(name, sizeof(name), "pipe_ck%d", slot);
620 err = clk_get_by_name(dev, name, &port->pipe_ck);
621 if (err) {
622 debug("clk_get_by_name(pipe_ck) failed: %d\n", err);
623 return err;
624 }
625
626 port->slot = slot;
627 port->pcie = pcie;
628
629 INIT_LIST_HEAD(&port->list);
630 list_add_tail(&port->list, &pcie->ports);
631
632 return 0;
633}
634
Ryder Lee42d37452019-08-22 12:26:49 +0200635static int mtk_pcie_probe(struct udevice *dev)
636{
637 struct mtk_pcie *pcie = dev_get_priv(dev);
638 struct mtk_pcie_port *port, *tmp;
639 ofnode subnode;
640 int err;
641
642 INIT_LIST_HEAD(&pcie->ports);
643
644 pcie->base = dev_remap_addr_name(dev, "subsys");
645 if (!pcie->base)
646 return -ENOENT;
647
648 err = clk_get_by_name(dev, "free_ck", &pcie->free_ck);
649 if (err)
650 return err;
651
652 /* enable top level clock */
653 err = clk_enable(&pcie->free_ck);
654 if (err)
655 return err;
656
657 dev_for_each_subnode(subnode, dev) {
658 struct fdt_pci_addr addr;
659 u32 slot = 0;
660
661 if (!ofnode_is_available(subnode))
662 continue;
663
664 err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
665 if (err)
666 return err;
667
668 slot = PCI_DEV(addr.phys_hi);
669
670 err = mtk_pcie_parse_port(dev, slot);
671 if (err)
672 return err;
673 }
674
675 /* enable each port, and then check link status */
676 list_for_each_entry_safe(port, tmp, &pcie->ports, list)
677 mtk_pcie_enable_port(port);
678
679 return 0;
680}
681
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800682static int mtk_pcie_probe_v2(struct udevice *dev)
683{
684 struct mtk_pcie *pcie = dev_get_priv(dev);
685 struct mtk_pcie_port *port, *tmp;
686 struct fdt_pci_addr addr;
687 ofnode subnode;
688 unsigned int slot;
689 int err;
690
691 INIT_LIST_HEAD(&pcie->ports);
692
693 pcie->base = dev_remap_addr_name(dev, "subsys");
694 if (!pcie->base)
695 return -ENOENT;
696
697 pcie->priv = dev;
698
699 dev_for_each_subnode(subnode, dev) {
700 if (!ofnode_is_available(subnode))
701 continue;
702
703 err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
704 if (err)
705 return err;
706
707 slot = PCI_DEV(addr.phys_hi);
708 err = mtk_pcie_parse_port_v2(dev, slot);
709 if (err)
710 return err;
711 }
712
713 /* enable each port, and then check link status */
714 list_for_each_entry_safe(port, tmp, &pcie->ports, list)
715 mtk_pcie_enable_port_v2(port);
716
717 return 0;
718}
719
Ryder Lee42d37452019-08-22 12:26:49 +0200720static const struct udevice_id mtk_pcie_ids[] = {
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800721 { .compatible = "mediatek,mt7623-pcie", PCIE_V1},
Ryder Lee42d37452019-08-22 12:26:49 +0200722 { }
723};
724
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800725U_BOOT_DRIVER(pcie_mediatek_v1) = {
726 .name = "pcie_mediatek_v1",
Ryder Lee42d37452019-08-22 12:26:49 +0200727 .id = UCLASS_PCI,
728 .of_match = mtk_pcie_ids,
729 .ops = &mtk_pcie_ops,
730 .probe = mtk_pcie_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700731 .priv_auto = sizeof(struct mtk_pcie),
Ryder Lee42d37452019-08-22 12:26:49 +0200732};
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800733
734static const struct udevice_id mtk_pcie_ids_v2[] = {
735 { .compatible = "mediatek,mt7622-pcie", PCIE_V2},
736 { }
737};
738
739U_BOOT_DRIVER(pcie_mediatek_v2) = {
740 .name = "pcie_mediatek_v2",
741 .id = UCLASS_PCI,
742 .of_match = mtk_pcie_ids_v2,
743 .ops = &mtk_pcie_ops_v2,
744 .probe = mtk_pcie_probe_v2,
Simon Glass41575d82020-12-03 16:55:17 -0700745 .priv_auto = sizeof(struct mtk_pcie),
Chuanjia Liu91ee45d2020-08-10 16:17:10 +0800746};