Guest User

Untitled

a guest
Aug 1st, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 9.56 KB | None | 0 0
  1. diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
  2. index 3fe38f7315..6f19471ae7 100644
  3. --- a/drivers/pci/Kconfig
  4. +++ b/drivers/pci/Kconfig
  5. @@ -145,4 +145,12 @@ config PCI_MVEBU
  6.      Say Y here if you want to enable PCIe controller support on
  7.      Armada XP/38x SoCs.
  8.  
  9. +config PCIE_MEDIATEK
  10. +    bool "MediaTek PCIe controller"
  11. +    depends on DM_PCI
  12. +    depends on ARCH_MEDIATEK
  13. +    help
  14. +      Say Y here if you want to enable PCIe controller support on
  15. +      MediaTek SoCs.
  16. +
  17. endif
  18. diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
  19. index b5ebd50c85..7093d63918 100644
  20. --- a/drivers/pci/Makefile
  21. +++ b/drivers/pci/Makefile
  22. @@ -38,3 +38,4 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
  23.                pcie_layerscape_gen4_fixup.o
  24. obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
  25. obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
  26. +obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
  27. diff --git a/drivers/pci/pcie_mediatek.c b/drivers/pci/pcie_mediatek.c
  28. new file mode 100644
  29. index 0000000000..1dc8b35232
  30. --- /dev/null
  31. +++ b/drivers/pci/pcie_mediatek.c
  32. @@ -0,0 +1,298 @@
  33. +// SPDX-License-Identifier: GPL-2.0
  34. +/*
  35. + * Copyright (c) 2019 MediaTek Inc.
  36. + *
  37. + * Author: Ryder Lee <ryder.lee@mediatek.com>
  38. + */
  39. +
  40. +#include <common.h>
  41. +#include <clk.h>
  42. +#include <dm.h>
  43. +#include <generic-phy.h>
  44. +#include <pci.h>
  45. +#include <reset.h>
  46. +#include <asm/io.h>
  47. +#include <linux/iopoll.h>
  48. +#include <linux/list.h>
  49. +
  50. +/* PCIe shared registers */
  51. +#define PCIE_SYS_CFG        0x00
  52. +#define PCIE_INT_ENABLE        0x0c
  53. +#define PCIE_CFG_ADDR        0x20
  54. +#define PCIE_CFG_DATA        0x24
  55. +
  56. +/* PCIe per port registers */
  57. +#define PCIE_BAR0_SETUP        0x10
  58. +#define PCIE_CLASS        0x34
  59. +#define PCIE_LINK_STATUS    0x50
  60. +
  61. +#define PCIE_PORT_INT_EN(x)    BIT(20 + (x))
  62. +#define PCIE_PORT_PERST(x)    BIT(1 + (x))
  63. +#define PCIE_PORT_LINKUP    BIT(0)
  64. +#define PCIE_BAR_MAP_MAX    GENMASK(31, 16)
  65. +
  66. +#define PCIE_BAR_ENABLE        BIT(0)
  67. +#define PCIE_REVISION_ID    BIT(0)
  68. +#define PCIE_CLASS_CODE        (0x60400 << 8)
  69. +#define PCIE_CONF_REG(regn)    (((regn) & GENMASK(7, 2)) | \
  70. +                ((((regn) >> 8) & GENMASK(3, 0)) << 24))
  71. +#define PCIE_CONF_FUN(fun)    (((fun) << 8) & GENMASK(10, 8))
  72. +#define PCIE_CONF_DEV(dev)    (((dev) << 11) & GENMASK(15, 11))
  73. +#define PCIE_CONF_BUS(bus)    (((bus) << 16) & GENMASK(23, 16))
  74. +#define PCIE_CONF_ADDR(regn, fun, dev, bus) \
  75. +                (PCIE_CONF_REG(regn) | PCIE_CONF_FUN(fun) | \
  76. +                PCIE_CONF_DEV(dev) | PCIE_CONF_BUS(bus))
  77. +
  78. +/* MediaTek specific configuration registers */
  79. +#define PCIE_FTS_NUM        0x70c
  80. +#define PCIE_FTS_NUM_MASK    GENMASK(15, 8)
  81. +#define PCIE_FTS_NUM_L0(x)    ((x) & 0xff << 8)
  82. +
  83. +#define PCIE_FC_CREDIT        0x73c
  84. +#define PCIE_FC_CREDIT_MASK    (GENMASK(31, 31) | GENMASK(28, 16))
  85. +#define PCIE_FC_CREDIT_VAL(x)    ((x) << 16)
  86. +
  87. +struct mtk_pcie_port {
  88. +    void __iomem *base;
  89. +    struct list_head list;
  90. +    struct mtk_pcie *pcie;
  91. +    struct reset_ctl reset;
  92. +    struct clk sys_ck;
  93. +    struct phy phy;
  94. +    u32 slot;
  95. +};
  96. +
  97. +struct mtk_pcie {
  98. +    void __iomem *base;
  99. +    struct clk free_ck;
  100. +    struct list_head ports;
  101. +};
  102. +
  103. +static int mtk_pcie_config_address(struct udevice *udev, pci_dev_t bdf,
  104. +                   uint offset, void **paddress)
  105. +{
  106. +    struct mtk_pcie *pcie = dev_get_priv(udev);
  107. +
  108. +    writel(PCIE_CONF_ADDR(offset, PCI_FUNC(bdf), PCI_DEV(bdf),
  109. +                  PCI_BUS(bdf)), pcie->base + PCIE_CFG_ADDR);
  110. +    *paddress = pcie->base + PCIE_CFG_DATA + (offset & 3);
  111. +
  112. +    return 0;
  113. +}
  114. +
  115. +static int mtk_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
  116. +                uint offset, ulong *valuep,
  117. +                enum pci_size_t size)
  118. +{
  119. +    return pci_generic_mmap_read_config(bus, mtk_pcie_config_address,
  120. +                        bdf, offset, valuep, size);
  121. +}
  122. +
  123. +static int mtk_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
  124. +                 uint offset, ulong value,
  125. +                 enum pci_size_t size)
  126. +{
  127. +    return pci_generic_mmap_write_config(bus, mtk_pcie_config_address,
  128. +                         bdf, offset, value, size);
  129. +}
  130. +
  131. +static const struct dm_pci_ops mtk_pcie_ops = {
  132. +    .read_config    = mtk_pcie_read_config,
  133. +    .write_config    = mtk_pcie_write_config,
  134. +};
  135. +
  136. +static void mtk_pcie_port_free(struct mtk_pcie_port *port)
  137. +{
  138. +    list_del(&port->list);
  139. +    free(port);
  140. +}
  141. +
  142. +static int mtk_pcie_startup_port(struct mtk_pcie_port *port)
  143. +{
  144. +    struct mtk_pcie *pcie = port->pcie;
  145. +    u32 func = PCI_FUNC(port->slot << 11);
  146. +    u32 slot = PCI_DEV(port->slot << 11);
  147. +    u32 val;
  148. +    int err;
  149. +
  150. +    /* assert port PERST_N */
  151. +    val = readl(pcie->base + PCIE_SYS_CFG);
  152. +    val |= PCIE_PORT_PERST(port->slot);
  153. +    writel(val, pcie->base + PCIE_SYS_CFG);
  154. +
  155. +    /* de-assert port PERST_N */
  156. +    val = readl(pcie->base + PCIE_SYS_CFG);
  157. +    val &= ~PCIE_PORT_PERST(port->slot);
  158. +    writel(val, pcie->base + PCIE_SYS_CFG);
  159. +
  160. +    /* 100ms timeout value should be enough for Gen1/2 training */
  161. +    err = readl_poll_timeout(port->base + PCIE_LINK_STATUS, val,
  162. +                 !!(val & PCIE_PORT_LINKUP), 100000);
  163. +    if (err)
  164. +        return -ETIMEDOUT;
  165. +
  166. +    /* enable interrupt */
  167. +    val = readl(pcie->base + PCIE_INT_ENABLE);
  168. +    val |= PCIE_PORT_INT_EN(port->slot);
  169. +    writel(val, pcie->base + PCIE_INT_ENABLE);
  170. +
  171. +    /* map to all DDR region. We need to set it before cfg operation. */
  172. +    writel(PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE,
  173. +           port->base + PCIE_BAR0_SETUP);
  174. +
  175. +    /* configure class code and revision ID */
  176. +    writel(PCIE_CLASS_CODE | PCIE_REVISION_ID, port->base + PCIE_CLASS);
  177. +
  178. +    /* configure FC credit */
  179. +    writel(PCIE_CONF_ADDR(PCIE_FC_CREDIT, func, slot, 0),
  180. +           pcie->base + PCIE_CFG_ADDR);
  181. +    val = readl(pcie->base + PCIE_CFG_DATA);
  182. +    val &= ~PCIE_FC_CREDIT_MASK;
  183. +    val |= PCIE_FC_CREDIT_VAL(0x806c);
  184. +    writel(PCIE_CONF_ADDR(PCIE_FC_CREDIT, func, slot, 0),
  185. +           pcie->base + PCIE_CFG_ADDR);
  186. +    writel(val, pcie->base + PCIE_CFG_DATA);
  187. +
  188. +    /* configure RC FTS number to 250 when it leaves L0s */
  189. +    writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, func, slot, 0),
  190. +           pcie->base + PCIE_CFG_ADDR);
  191. +    val = readl(pcie->base + PCIE_CFG_DATA);
  192. +    val &= ~PCIE_FTS_NUM_MASK;
  193. +    val |= PCIE_FTS_NUM_L0(0x50);
  194. +    writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, func, slot, 0),
  195. +           pcie->base + PCIE_CFG_ADDR);
  196. +    writel(val, pcie->base + PCIE_CFG_DATA);
  197. +
  198. +    return 0;
  199. +}
  200. +
  201. +static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
  202. +{
  203. +    int err;
  204. +
  205. +    err = clk_enable(&port->sys_ck);
  206. +    if (err)
  207. +        goto exit;
  208. +
  209. +    err = reset_assert(&port->reset);
  210. +    if (err)
  211. +        goto exit;
  212. +
  213. +    err = reset_deassert(&port->reset);
  214. +    if (err)
  215. +        goto exit;
  216. +
  217. +    err = generic_phy_init(&port->phy);
  218. +    if (err)
  219. +        goto exit;
  220. +
  221. +    err = generic_phy_power_on(&port->phy);
  222. +    if (err)
  223. +        goto exit;
  224. +
  225. +    if (!mtk_pcie_startup_port(port))
  226. +        return;
  227. +
  228. +    pr_err("Port%d link down\n", port->slot);
  229. +exit:
  230. +    mtk_pcie_port_free(port);
  231. +}
  232. +
  233. +static int mtk_pcie_parse_port(struct udevice *dev, u32 slot)
  234. +{
  235. +    struct mtk_pcie *pcie = dev_get_priv(dev);
  236. +    struct mtk_pcie_port *port;
  237. +    char name[10];
  238. +    int err;
  239. +
  240. +    port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
  241. +    if (!port)
  242. +        return -ENOMEM;
  243. +
  244. +    snprintf(name, sizeof(name), "port%d", slot);
  245. +    port->base = dev_remap_addr_name(dev, name);
  246. +    if (!port->base)
  247. +        return -ENOENT;
  248. +
  249. +    snprintf(name, sizeof(name), "sys_ck%d", slot);
  250. +    err = clk_get_by_name(dev, name, &port->sys_ck);
  251. +    if (err)
  252. +        return err;
  253. +
  254. +    err = reset_get_by_index(dev, slot, &port->reset);
  255. +    if (err)
  256. +        return err;
  257. +
  258. +    err = generic_phy_get_by_index(dev, slot, &port->phy);
  259. +    if (err)
  260. +        return err;
  261. +
  262. +    port->slot = slot;
  263. +    port->pcie = pcie;
  264. +
  265. +    INIT_LIST_HEAD(&port->list);
  266. +    list_add_tail(&port->list, &pcie->ports);
  267. +
  268. +    return 0;
  269. +}
  270. +
  271. +static int mtk_pcie_probe(struct udevice *dev)
  272. +{
  273. +    struct mtk_pcie *pcie = dev_get_priv(dev);
  274. +    struct mtk_pcie_port *port, *tmp;
  275. +    ofnode subnode;
  276. +    int err;
  277. +
  278. +    INIT_LIST_HEAD(&pcie->ports);
  279. +
  280. +    pcie->base = dev_remap_addr_name(dev, "subsys");
  281. +    if (!pcie->base)
  282. +        return -ENOENT;
  283. +
  284. +    err = clk_get_by_name(dev, "free_ck", &pcie->free_ck);
  285. +    if (err)
  286. +        return err;
  287. +
  288. +    /* enable top level clock */
  289. +    err = clk_enable(&pcie->free_ck);
  290. +    if (err)
  291. +        return err;
  292. +
  293. +    dev_for_each_subnode(subnode, dev) {
  294. +        struct fdt_pci_addr addr;
  295. +        u32 slot = 0;
  296. +
  297. +        if (!ofnode_is_available(subnode))
  298. +            continue;
  299. +
  300. +        err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
  301. +        if (err)
  302. +            return err;
  303. +
  304. +        slot = PCI_DEV(addr.phys_hi);
  305. +
  306. +        err = mtk_pcie_parse_port(dev, slot);
  307. +        if (err)
  308. +            return err;
  309. +    }
  310. +
  311. +    /* enable each port, and then check link status */
  312. +    list_for_each_entry_safe(port, tmp, &pcie->ports, list)
  313. +        mtk_pcie_enable_port(port);
  314. +
  315. +    return 0;
  316. +}
  317. +
  318. +static const struct udevice_id mtk_pcie_ids[] = {
  319. +    { .compatible = "mediatek,mt7623-pcie", },
  320. +    { }
  321. +};
  322. +
  323. +U_BOOT_DRIVER(pcie_mediatek) = {
  324. +    .name    = "pcie_mediatek",
  325. +    .id    = UCLASS_PCI,
  326. +    .of_match = mtk_pcie_ids,
  327. +    .ops    = &mtk_pcie_ops,
  328. +    .probe    = mtk_pcie_probe,
  329. +    .priv_auto_alloc_size = sizeof(struct mtk_pcie),
  330. +};
Add Comment
Please, Sign In to add comment