pcie_dw_meson.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Amlogic DesignWare based PCIe host controller driver
  4. *
  5. * Copyright (c) 2021 BayLibre, SAS
  6. * Author: Neil Armstrong <narmstrong@baylibre.com>
  7. *
  8. * Based on pcie_dw_rockchip.c
  9. * Copyright (c) 2021 Rockchip, Inc.
  10. */
  11. #include <common.h>
  12. #include <clk.h>
  13. #include <dm.h>
  14. #include <generic-phy.h>
  15. #include <pci.h>
  16. #include <power-domain.h>
  17. #include <reset.h>
  18. #include <syscon.h>
  19. #include <asm/global_data.h>
  20. #include <asm/io.h>
  21. #include <asm-generic/gpio.h>
  22. #include <dm/device_compat.h>
  23. #include <linux/iopoll.h>
  24. #include <linux/delay.h>
  25. #include <linux/log2.h>
  26. #include <linux/bitfield.h>
  27. #include "pcie_dw_common.h"
  28. DECLARE_GLOBAL_DATA_PTR;
  29. /**
  30. * struct meson_pcie - Amlogic Meson DW PCIe controller state
  31. *
  32. * @pci: The common PCIe DW structure
  33. * @meson_cfg_base: The base address of vendor regs
  34. * @phy
  35. * @clk_port
  36. * @clk_general
  37. * @clk_pclk
  38. * @rsts
  39. * @rst_gpio: The #PERST signal for slot
  40. */
  41. struct meson_pcie {
  42. /* Must be first member of the struct */
  43. struct pcie_dw dw;
  44. void *meson_cfg_base;
  45. struct phy phy;
  46. struct clk clk_port;
  47. struct clk clk_general;
  48. struct clk clk_pclk;
  49. struct reset_ctl_bulk rsts;
  50. struct gpio_desc rst_gpio;
  51. };
  52. #define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
  53. #define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5)
  54. #define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12)
  55. /* PCIe specific config registers */
  56. #define PCIE_CFG0 0x0
  57. #define APP_LTSSM_ENABLE BIT(7)
  58. #define PCIE_CFG_STATUS12 0x30
  59. #define IS_SMLH_LINK_UP(x) ((x) & (1 << 6))
  60. #define IS_RDLH_LINK_UP(x) ((x) & (1 << 16))
  61. #define IS_LTSSM_UP(x) ((((x) >> 10) & 0x1f) == 0x11)
  62. #define PCIE_CFG_STATUS17 0x44
  63. #define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1)
  64. #define WAIT_LINKUP_TIMEOUT 4000
  65. #define PORT_CLK_RATE 100000000UL
  66. #define MAX_PAYLOAD_SIZE 256
  67. #define MAX_READ_REQ_SIZE 256
  68. #define PCIE_RESET_DELAY 500
  69. #define PCIE_SHARED_RESET 1
  70. #define PCIE_NORMAL_RESET 0
  71. enum pcie_data_rate {
  72. PCIE_GEN1,
  73. PCIE_GEN2,
  74. PCIE_GEN3,
  75. PCIE_GEN4
  76. };
  77. /* Parameters for the waiting for #perst signal */
  78. #define PERST_WAIT_US 1000000
  79. static inline u32 meson_cfg_readl(struct meson_pcie *priv, u32 reg)
  80. {
  81. return readl(priv->meson_cfg_base + reg);
  82. }
  83. static inline void meson_cfg_writel(struct meson_pcie *priv, u32 val, u32 reg)
  84. {
  85. writel(val, priv->meson_cfg_base + reg);
  86. }
  87. /**
  88. * meson_pcie_configure() - Configure link
  89. *
  90. * @meson_pcie: Pointer to the PCI controller state
  91. *
  92. * Configure the link mode and width
  93. */
  94. static void meson_pcie_configure(struct meson_pcie *priv)
  95. {
  96. u32 val;
  97. dw_pcie_dbi_write_enable(&priv->dw, true);
  98. val = readl(priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
  99. val &= ~PORT_LINK_FAST_LINK_MODE;
  100. val |= PORT_LINK_DLL_LINK_EN;
  101. val &= ~PORT_LINK_MODE_MASK;
  102. val |= PORT_LINK_MODE_1_LANES;
  103. writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
  104. val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
  105. val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
  106. val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
  107. writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
  108. dw_pcie_dbi_write_enable(&priv->dw, false);
  109. }
  110. static inline void meson_pcie_enable_ltssm(struct meson_pcie *priv)
  111. {
  112. u32 val;
  113. val = meson_cfg_readl(priv, PCIE_CFG0);
  114. val |= APP_LTSSM_ENABLE;
  115. meson_cfg_writel(priv, val, PCIE_CFG0);
  116. }
  117. static int meson_pcie_wait_link_up(struct meson_pcie *priv)
  118. {
  119. u32 speed_okay = 0;
  120. u32 cnt = 0;
  121. u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
  122. do {
  123. state12 = meson_cfg_readl(priv, PCIE_CFG_STATUS12);
  124. state17 = meson_cfg_readl(priv, PCIE_CFG_STATUS17);
  125. smlh_up = IS_SMLH_LINK_UP(state12);
  126. rdlh_up = IS_RDLH_LINK_UP(state12);
  127. ltssm_up = IS_LTSSM_UP(state12);
  128. if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
  129. speed_okay = 1;
  130. if (smlh_up)
  131. debug("%s: smlh_link_up is on\n", __func__);
  132. if (rdlh_up)
  133. debug("%s: rdlh_link_up is on\n", __func__);
  134. if (ltssm_up)
  135. debug("%s: ltssm_up is on\n", __func__);
  136. if (speed_okay)
  137. debug("%s: speed_okay\n", __func__);
  138. if (smlh_up && rdlh_up && ltssm_up && speed_okay)
  139. return 0;
  140. cnt++;
  141. udelay(10);
  142. } while (cnt < WAIT_LINKUP_TIMEOUT);
  143. printf("%s: error: wait linkup timeout\n", __func__);
  144. return -EIO;
  145. }
  146. /**
  147. * meson_pcie_link_up() - Wait for the link to come up
  148. *
  149. * @meson_pcie: Pointer to the PCI controller state
  150. * @cap_speed: Desired link speed
  151. *
  152. * Return: 1 (true) for active line and negative (false) for no link (timeout)
  153. */
  154. static int meson_pcie_link_up(struct meson_pcie *priv, u32 cap_speed)
  155. {
  156. /* DW link configurations */
  157. meson_pcie_configure(priv);
  158. /* Reset the device */
  159. if (dm_gpio_is_valid(&priv->rst_gpio)) {
  160. dm_gpio_set_value(&priv->rst_gpio, 1);
  161. /*
  162. * Minimal is 100ms from spec but we see
  163. * some wired devices need much more, such as 600ms.
  164. * Add a enough delay to cover all cases.
  165. */
  166. udelay(PERST_WAIT_US);
  167. dm_gpio_set_value(&priv->rst_gpio, 0);
  168. }
  169. /* Enable LTSSM */
  170. meson_pcie_enable_ltssm(priv);
  171. return meson_pcie_wait_link_up(priv);
  172. }
  173. static int meson_size_to_payload(int size)
  174. {
  175. /*
  176. * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
  177. * So if input size is not 2^order alignment or less than 2^7 or bigger
  178. * than 2^12, just set to default size 2^(1+7).
  179. */
  180. if (!is_power_of_2(size) || size < 128 || size > 4096) {
  181. debug("%s: payload size %d, set to default 256\n", __func__, size);
  182. return 1;
  183. }
  184. return fls(size) - 8;
  185. }
  186. static void meson_set_max_payload(struct meson_pcie *priv, int size)
  187. {
  188. u32 val;
  189. u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
  190. int max_payload_size = meson_size_to_payload(size);
  191. dw_pcie_dbi_write_enable(&priv->dw, true);
  192. val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
  193. val &= ~PCI_EXP_DEVCTL_PAYLOAD;
  194. writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
  195. val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
  196. val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
  197. writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
  198. dw_pcie_dbi_write_enable(&priv->dw, false);
  199. }
  200. static void meson_set_max_rd_req_size(struct meson_pcie *priv, int size)
  201. {
  202. u32 val;
  203. u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
  204. int max_rd_req_size = meson_size_to_payload(size);
  205. dw_pcie_dbi_write_enable(&priv->dw, true);
  206. val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
  207. val &= ~PCI_EXP_DEVCTL_PAYLOAD;
  208. writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
  209. val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
  210. val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
  211. writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
  212. dw_pcie_dbi_write_enable(&priv->dw, false);
  213. }
  214. static int meson_pcie_init_port(struct udevice *dev)
  215. {
  216. int ret;
  217. struct meson_pcie *priv = dev_get_priv(dev);
  218. ret = generic_phy_init(&priv->phy);
  219. if (ret) {
  220. dev_err(dev, "failed to init phy (ret=%d)\n", ret);
  221. return ret;
  222. }
  223. ret = generic_phy_power_on(&priv->phy);
  224. if (ret) {
  225. dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
  226. goto err_exit_phy;
  227. }
  228. ret = generic_phy_reset(&priv->phy);
  229. if (ret) {
  230. dev_err(dev, "failed to reset phy (ret=%d)\n", ret);
  231. goto err_exit_phy;
  232. }
  233. ret = reset_assert_bulk(&priv->rsts);
  234. if (ret) {
  235. dev_err(dev, "failed to assert resets (ret=%d)\n", ret);
  236. goto err_power_off_phy;
  237. }
  238. udelay(PCIE_RESET_DELAY);
  239. ret = reset_deassert_bulk(&priv->rsts);
  240. if (ret) {
  241. dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
  242. goto err_power_off_phy;
  243. }
  244. udelay(PCIE_RESET_DELAY);
  245. ret = clk_set_rate(&priv->clk_port, PORT_CLK_RATE);
  246. if (ret) {
  247. dev_err(dev, "failed to set port clk rate (ret=%d)\n", ret);
  248. goto err_deassert_bulk;
  249. }
  250. ret = clk_enable(&priv->clk_general);
  251. if (ret) {
  252. dev_err(dev, "failed to enable clk general (ret=%d)\n", ret);
  253. goto err_deassert_bulk;
  254. }
  255. ret = clk_enable(&priv->clk_pclk);
  256. if (ret) {
  257. dev_err(dev, "failed to enable pclk (ret=%d)\n", ret);
  258. goto err_deassert_bulk;
  259. }
  260. meson_set_max_payload(priv, MAX_PAYLOAD_SIZE);
  261. meson_set_max_rd_req_size(priv, MAX_READ_REQ_SIZE);
  262. pcie_dw_setup_host(&priv->dw);
  263. ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2);
  264. if (ret < 0)
  265. goto err_link_up;
  266. return 0;
  267. err_link_up:
  268. clk_disable(&priv->clk_port);
  269. clk_disable(&priv->clk_general);
  270. clk_disable(&priv->clk_pclk);
  271. err_deassert_bulk:
  272. reset_assert_bulk(&priv->rsts);
  273. err_power_off_phy:
  274. generic_phy_power_off(&priv->phy);
  275. err_exit_phy:
  276. generic_phy_exit(&priv->phy);
  277. return ret;
  278. }
  279. static int meson_pcie_parse_dt(struct udevice *dev)
  280. {
  281. struct meson_pcie *priv = dev_get_priv(dev);
  282. int ret;
  283. priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
  284. if (!priv->dw.dbi_base)
  285. return -ENODEV;
  286. dev_dbg(dev, "ELBI address is 0x%p\n", priv->dw.dbi_base);
  287. priv->meson_cfg_base = (void *)dev_read_addr_index(dev, 1);
  288. if (!priv->meson_cfg_base)
  289. return -ENODEV;
  290. dev_dbg(dev, "CFG address is 0x%p\n", priv->meson_cfg_base);
  291. ret = gpio_request_by_name(dev, "reset-gpios", 0,
  292. &priv->rst_gpio, GPIOD_IS_OUT);
  293. if (ret) {
  294. dev_err(dev, "failed to find reset-gpios property\n");
  295. return ret;
  296. }
  297. ret = reset_get_bulk(dev, &priv->rsts);
  298. if (ret) {
  299. dev_err(dev, "Can't get reset: %d\n", ret);
  300. return ret;
  301. }
  302. ret = clk_get_by_name(dev, "port", &priv->clk_port);
  303. if (ret) {
  304. dev_err(dev, "Can't get port clock: %d\n", ret);
  305. return ret;
  306. }
  307. ret = clk_get_by_name(dev, "general", &priv->clk_general);
  308. if (ret) {
  309. dev_err(dev, "Can't get port clock: %d\n", ret);
  310. return ret;
  311. }
  312. ret = clk_get_by_name(dev, "pclk", &priv->clk_pclk);
  313. if (ret) {
  314. dev_err(dev, "Can't get port clock: %d\n", ret);
  315. return ret;
  316. }
  317. ret = generic_phy_get_by_index(dev, 0, &priv->phy);
  318. if (ret) {
  319. dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
  320. return ret;
  321. }
  322. return 0;
  323. }
  324. /**
  325. * meson_pcie_probe() - Probe the PCIe bus for active link
  326. *
  327. * @dev: A pointer to the device being operated on
  328. *
  329. * Probe for an active link on the PCIe bus and configure the controller
  330. * to enable this port.
  331. *
  332. * Return: 0 on success, else -ENODEV
  333. */
  334. static int meson_pcie_probe(struct udevice *dev)
  335. {
  336. struct meson_pcie *priv = dev_get_priv(dev);
  337. struct udevice *ctlr = pci_get_controller(dev);
  338. struct pci_controller *hose = dev_get_uclass_priv(ctlr);
  339. int ret = 0;
  340. priv->dw.first_busno = dev_seq(dev);
  341. priv->dw.dev = dev;
  342. ret = meson_pcie_parse_dt(dev);
  343. if (ret)
  344. return ret;
  345. ret = meson_pcie_init_port(dev);
  346. if (ret) {
  347. dm_gpio_free(dev, &priv->rst_gpio);
  348. return ret;
  349. }
  350. printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
  351. dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
  352. pcie_dw_get_link_width(&priv->dw),
  353. hose->first_busno);
  354. return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
  355. PCIE_ATU_REGION_INDEX0,
  356. PCIE_ATU_TYPE_MEM,
  357. priv->dw.mem.phys_start,
  358. priv->dw.mem.bus_start,
  359. priv->dw.mem.size);
  360. }
  361. static const struct dm_pci_ops meson_pcie_ops = {
  362. .read_config = pcie_dw_read_config,
  363. .write_config = pcie_dw_write_config,
  364. };
  365. static const struct udevice_id meson_pcie_ids[] = {
  366. { .compatible = "amlogic,axg-pcie" },
  367. { .compatible = "amlogic,g12a-pcie" },
  368. { }
  369. };
  370. U_BOOT_DRIVER(meson_dw_pcie) = {
  371. .name = "pcie_dw_meson",
  372. .id = UCLASS_PCI,
  373. .of_match = meson_pcie_ids,
  374. .ops = &meson_pcie_ops,
  375. .probe = meson_pcie_probe,
  376. .priv_auto = sizeof(struct meson_pcie),
  377. };