111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. Content-Type: text/plain; charset="utf-8"
  2. MIME-Version: 1.0
  3. Content-Transfer-Encoding: 7bit
  4. Subject: [v2,4/5] PCI: qcom: Add Qualcomm PCIe controller driver
  5. From: Stanimir Varbanov <svarbanov@mm-sol.com>
  6. X-Patchwork-Id: 6326161
  7. Message-Id: <1430743338-10441-5-git-send-email-svarbanov@mm-sol.com>
  8. To: Rob Herring <robh+dt@kernel.org>, Kumar Gala <galak@codeaurora.org>,
  9. Mark Rutland <mark.rutland@arm.com>,
  10. Grant Likely <grant.likely@linaro.org>,
  11. Bjorn Helgaas <bhelgaas@google.com>,
  12. Kishon Vijay Abraham I <kishon@ti.com>,
  13. Russell King <linux@arm.linux.org.uk>, Arnd Bergmann <arnd@arndb.de>
  14. Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
  15. linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
  16. linux-pci@vger.kernel.org, Mathieu Olivari <mathieu@codeaurora.org>,
  17. Srinivas Kandagatla <srinivas.kandagatla@linaro.org>,
  18. Stanimir Varbanov <svarbanov@mm-sol.com>
  19. Date: Mon, 4 May 2015 15:42:17 +0300
  20. The PCIe driver reuse the Designware common code for host
  21. and MSI initialization, and also program the Qualcomm
  22. application specific registers.
  23. Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
  24. ---
  25. MAINTAINERS | 7 +
  26. drivers/pci/host/Kconfig | 9 +
  27. drivers/pci/host/Makefile | 1 +
  28. drivers/pci/host/pcie-qcom.c | 677 ++++++++++++++++++++++++++++++++++++++++++
  29. 4 files changed, 694 insertions(+), 0 deletions(-)
  30. create mode 100644 drivers/pci/host/pcie-qcom.c
  31. --- a/MAINTAINERS
  32. +++ b/MAINTAINERS
  33. @@ -8253,6 +8253,13 @@ S: Maintained
  34. F: Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
  35. F: drivers/pci/host/pcie-hisi.c
  36. +PCIE DRIVER FOR QUALCOMM MSM
  37. +M: Stanimir Varbanov <svarbanov@mm-sol.com>
  38. +L: linux-pci@vger.kernel.org
  39. +L: linux-arm-msm@vger.kernel.org
  40. +S: Maintained
  41. +F: drivers/pci/host/*qcom*
  42. +
  43. PCMCIA SUBSYSTEM
  44. P: Linux PCMCIA Team
  45. L: linux-pcmcia@lists.infradead.org
  46. --- a/drivers/pci/host/Kconfig
  47. +++ b/drivers/pci/host/Kconfig
  48. @@ -173,4 +173,13 @@ config PCI_HISI
  49. help
  50. Say Y here if you want PCIe controller support on HiSilicon HIP05 SoC
  51. +config PCIE_QCOM
  52. + bool "Qualcomm PCIe controller"
  53. + depends on ARCH_QCOM && OF || (ARM && COMPILE_TEST)
  54. + select PCIE_DW
  55. + select PCIEPORTBUS
  56. + help
  57. + Say Y here to enable PCIe controller support on Qualcomm SoCs. The
  58. + PCIe controller use Designware core plus Qualcomm specific hardware
  59. + wrappers.
  60. endmenu
  61. --- /dev/null
  62. +++ b/drivers/pci/host/pcie-qcom.c
  63. @@ -0,0 +1,676 @@
  64. +/*
  65. + * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  66. + *
  67. + * This program is free software; you can redistribute it and/or modify
  68. + * it under the terms of the GNU General Public License version 2 and
  69. + * only version 2 as published by the Free Software Foundation.
  70. + *
  71. + * This program is distributed in the hope that it will be useful,
  72. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  73. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  74. + * GNU General Public License for more details.
  75. + */
  76. +
  77. +#include <linux/clk.h>
  78. +#include <linux/delay.h>
  79. +#include <linux/gpio.h>
  80. +#include <linux/interrupt.h>
  81. +#include <linux/io.h>
  82. +#include <linux/kernel.h>
  83. +#include <linux/module.h>
  84. +#include <linux/of_gpio.h>
  85. +#include <linux/pci.h>
  86. +#include <linux/platform_device.h>
  87. +#include <linux/phy/phy.h>
  88. +#include <linux/regulator/consumer.h>
  89. +#include <linux/reset.h>
  90. +#include <linux/slab.h>
  91. +#include <linux/types.h>
  92. +
  93. +#include "pcie-designware.h"
  94. +
  95. +#define PCIE20_PARF_PHY_CTRL 0x40
  96. +#define PCIE20_PARF_PHY_REFCLK 0x4C
  97. +#define PCIE20_PARF_DBI_BASE_ADDR 0x168
  98. +#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c
  99. +#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178
  100. +
  101. +#define PCIE20_ELBI_SYS_CTRL 0x04
  102. +#define PCIE20_ELBI_SYS_STTS 0x08
  103. +#define XMLH_LINK_UP BIT(10)
  104. +
  105. +#define PCIE20_CAP 0x70
  106. +#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
  107. +
  108. +#define PERST_DELAY_MIN_US 1000
  109. +#define PERST_DELAY_MAX_US 1005
  110. +
  111. +#define LINKUP_DELAY_MIN_US 5000
  112. +#define LINKUP_DELAY_MAX_US 5100
  113. +#define LINKUP_RETRIES_COUNT 20
  114. +
  115. +#define PCIE_V0 0 /* apq8064 */
  116. +#define PCIE_V1 1 /* apq8084 */
  117. +
  118. +struct qcom_pcie_resources_v0 {
  119. + struct clk *iface_clk;
  120. + struct clk *core_clk;
  121. + struct clk *phy_clk;
  122. + struct reset_control *pci_reset;
  123. + struct reset_control *axi_reset;
  124. + struct reset_control *ahb_reset;
  125. + struct reset_control *por_reset;
  126. + struct reset_control *phy_reset;
  127. + struct regulator *vdda;
  128. + struct regulator *vdda_phy;
  129. + struct regulator *vdda_refclk;
  130. +};
  131. +
  132. +struct qcom_pcie_resources_v1 {
  133. + struct clk *iface;
  134. + struct clk *aux;
  135. + struct clk *master_bus;
  136. + struct clk *slave_bus;
  137. + struct reset_control *core;
  138. + struct regulator *vdda;
  139. +};
  140. +
  141. +union pcie_resources {
  142. + struct qcom_pcie_resources_v0 v0;
  143. + struct qcom_pcie_resources_v1 v1;
  144. +};
  145. +
  146. +struct qcom_pcie {
  147. + struct pcie_port pp;
  148. + struct device *dev;
  149. + union pcie_resources res;
  150. + void __iomem *parf;
  151. + void __iomem *dbi;
  152. + void __iomem *elbi;
  153. + struct phy *phy;
  154. + struct gpio_desc *reset;
  155. + unsigned int version;
  156. +};
  157. +
  158. +#define to_qcom_pcie(x) container_of(x, struct qcom_pcie, pp)
  159. +
  160. +static inline void
  161. +writel_masked(void __iomem *addr, u32 clear_mask, u32 set_mask)
  162. +{
  163. + u32 val = readl(addr);
  164. +
  165. + val &= ~clear_mask;
  166. + val |= set_mask;
  167. + writel(val, addr);
  168. +}
  169. +
  170. +static void qcom_ep_reset_assert_deassert(struct qcom_pcie *pcie, int assert)
  171. +{
  172. + int val, active_low;
  173. +
  174. + if (IS_ERR_OR_NULL(pcie->reset))
  175. + return;
  176. +
  177. + active_low = gpiod_is_active_low(pcie->reset);
  178. +
  179. + if (assert)
  180. + val = !!active_low;
  181. + else
  182. + val = !active_low;
  183. +
  184. + gpiod_set_value(pcie->reset, val);
  185. +
  186. + usleep_range(PERST_DELAY_MIN_US, PERST_DELAY_MAX_US);
  187. +}
  188. +
  189. +static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
  190. +{
  191. + qcom_ep_reset_assert_deassert(pcie, 1);
  192. +}
  193. +
  194. +static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
  195. +{
  196. + qcom_ep_reset_assert_deassert(pcie, 0);
  197. +}
  198. +
  199. +static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg)
  200. +{
  201. + struct pcie_port *pp = arg;
  202. +
  203. + return dw_handle_msi_irq(pp);
  204. +}
  205. +
  206. +static int qcom_pcie_link_up(struct pcie_port *pp)
  207. +{
  208. + struct qcom_pcie *pcie = to_qcom_pcie(pp);
  209. + u32 val = readl(pcie->dbi + PCIE20_CAP_LINKCTRLSTATUS);
  210. +
  211. + return val & BIT(29) ? 1 : 0;
  212. +}
  213. +
  214. +static void qcom_pcie_disable_resources_v0(struct qcom_pcie *pcie)
  215. +{
  216. + struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
  217. +
  218. + reset_control_assert(res->pci_reset);
  219. + reset_control_assert(res->axi_reset);
  220. + reset_control_assert(res->ahb_reset);
  221. + reset_control_assert(res->por_reset);
  222. + reset_control_assert(res->pci_reset);
  223. + clk_disable_unprepare(res->iface_clk);
  224. + clk_disable_unprepare(res->core_clk);
  225. + clk_disable_unprepare(res->phy_clk);
  226. + regulator_disable(res->vdda);
  227. + regulator_disable(res->vdda_phy);
  228. + regulator_disable(res->vdda_refclk);
  229. +}
  230. +
  231. +static void qcom_pcie_disable_resources_v1(struct qcom_pcie *pcie)
  232. +{
  233. + struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
  234. +
  235. + reset_control_assert(res->core);
  236. + clk_disable_unprepare(res->slave_bus);
  237. + clk_disable_unprepare(res->master_bus);
  238. + clk_disable_unprepare(res->iface);
  239. + clk_disable_unprepare(res->aux);
  240. + regulator_disable(res->vdda);
  241. +}
  242. +
  243. +static int qcom_pcie_enable_resources_v0(struct qcom_pcie *pcie)
  244. +{
  245. + struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
  246. + struct device *dev = pcie->dev;
  247. + int ret;
  248. +
  249. + ret = regulator_enable(res->vdda);
  250. + if (ret) {
  251. + dev_err(dev, "cannot enable vdda regulator\n");
  252. + return ret;
  253. + }
  254. +
  255. + ret = regulator_enable(res->vdda_refclk);
  256. + if (ret) {
  257. + dev_err(dev, "cannot enable vdda_refclk regulator\n");
  258. + goto err_refclk;
  259. + }
  260. +
  261. + ret = regulator_enable(res->vdda_phy);
  262. + if (ret) {
  263. + dev_err(dev, "cannot enable vdda_phy regulator\n");
  264. + goto err_vdda_phy;
  265. + }
  266. +
  267. + ret = clk_prepare_enable(res->iface_clk);
  268. + if (ret) {
  269. + dev_err(dev, "cannot prepare/enable iface clock\n");
  270. + goto err_iface;
  271. + }
  272. +
  273. + ret = clk_prepare_enable(res->core_clk);
  274. + if (ret) {
  275. + dev_err(dev, "cannot prepare/enable core clock\n");
  276. + goto err_clk_core;
  277. + }
  278. +
  279. + ret = clk_prepare_enable(res->phy_clk);
  280. + if (ret) {
  281. + dev_err(dev, "cannot prepare/enable phy clock\n");
  282. + goto err_clk_phy;
  283. + }
  284. +
  285. + ret = reset_control_deassert(res->ahb_reset);
  286. + if (ret) {
  287. + dev_err(dev, "cannot deassert ahb reset\n");
  288. + goto err_reset_ahb;
  289. + }
  290. +
  291. + return 0;
  292. +
  293. +err_reset_ahb:
  294. + clk_disable_unprepare(res->phy_clk);
  295. +err_clk_phy:
  296. + clk_disable_unprepare(res->core_clk);
  297. +err_clk_core:
  298. + clk_disable_unprepare(res->iface_clk);
  299. +err_iface:
  300. + regulator_disable(res->vdda_phy);
  301. +err_vdda_phy:
  302. + regulator_disable(res->vdda_refclk);
  303. +err_refclk:
  304. + regulator_disable(res->vdda);
  305. + return ret;
  306. +}
  307. +
  308. +static int qcom_pcie_enable_resources_v1(struct qcom_pcie *pcie)
  309. +{
  310. + struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
  311. + struct device *dev = pcie->dev;
  312. + int ret;
  313. +
  314. + ret = reset_control_deassert(res->core);
  315. + if (ret) {
  316. + dev_err(dev, "cannot deassert core reset\n");
  317. + return ret;
  318. + }
  319. +
  320. + ret = clk_prepare_enable(res->aux);
  321. + if (ret) {
  322. + dev_err(dev, "cannot prepare/enable aux clock\n");
  323. + goto err_res;
  324. + }
  325. +
  326. + ret = clk_prepare_enable(res->iface);
  327. + if (ret) {
  328. + dev_err(dev, "cannot prepare/enable iface clock\n");
  329. + goto err_aux;
  330. + }
  331. +
  332. + ret = clk_prepare_enable(res->master_bus);
  333. + if (ret) {
  334. + dev_err(dev, "cannot prepare/enable master_bus clock\n");
  335. + goto err_iface;
  336. + }
  337. +
  338. + ret = clk_prepare_enable(res->slave_bus);
  339. + if (ret) {
  340. + dev_err(dev, "cannot prepare/enable slave_bus clock\n");
  341. + goto err_master;
  342. + }
  343. +
  344. + ret = regulator_enable(res->vdda);
  345. + if (ret) {
  346. + dev_err(dev, "cannot enable vdda regulator\n");
  347. + goto err_slave;
  348. + }
  349. +
  350. + return 0;
  351. +
  352. +err_slave:
  353. + clk_disable_unprepare(res->slave_bus);
  354. +err_master:
  355. + clk_disable_unprepare(res->master_bus);
  356. +err_iface:
  357. + clk_disable_unprepare(res->iface);
  358. +err_aux:
  359. + clk_disable_unprepare(res->aux);
  360. +err_res:
  361. + reset_control_assert(res->core);
  362. +
  363. + return ret;
  364. +}
  365. +
  366. +static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
  367. +{
  368. + struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
  369. + struct device *dev = pcie->dev;
  370. +
  371. + res->vdda = devm_regulator_get(dev, "vdda");
  372. + if (IS_ERR(res->vdda))
  373. + return PTR_ERR(res->vdda);
  374. +
  375. + res->vdda_phy = devm_regulator_get(dev, "vdda_phy");
  376. + if (IS_ERR(res->vdda_phy))
  377. + return PTR_ERR(res->vdda_phy);
  378. +
  379. + res->vdda_refclk = devm_regulator_get(dev, "vdda_refclk");
  380. + if (IS_ERR(res->vdda_refclk))
  381. + return PTR_ERR(res->vdda_refclk);
  382. +
  383. + res->iface_clk = devm_clk_get(dev, "iface");
  384. + if (IS_ERR(res->iface_clk))
  385. + return PTR_ERR(res->iface_clk);
  386. +
  387. + res->core_clk = devm_clk_get(dev, "core");
  388. + if (IS_ERR(res->core_clk))
  389. + return PTR_ERR(res->core_clk);
  390. +
  391. + res->phy_clk = devm_clk_get(dev, "phy");
  392. + if (IS_ERR(res->phy_clk))
  393. + return PTR_ERR(res->phy_clk);
  394. +
  395. + res->pci_reset = devm_reset_control_get(dev, "pci");
  396. + if (IS_ERR(res->pci_reset))
  397. + return PTR_ERR(res->pci_reset);
  398. +
  399. + res->axi_reset = devm_reset_control_get(dev, "axi");
  400. + if (IS_ERR(res->axi_reset))
  401. + return PTR_ERR(res->axi_reset);
  402. +
  403. + res->ahb_reset = devm_reset_control_get(dev, "ahb");
  404. + if (IS_ERR(res->ahb_reset))
  405. + return PTR_ERR(res->ahb_reset);
  406. +
  407. + res->por_reset = devm_reset_control_get(dev, "por");
  408. + if (IS_ERR(res->por_reset))
  409. + return PTR_ERR(res->por_reset);
  410. +
  411. + res->phy_reset = devm_reset_control_get(dev, "phy");
  412. + if (IS_ERR(res->phy_reset))
  413. + return PTR_ERR(res->phy_reset);
  414. +
  415. + return 0;
  416. +}
  417. +
  418. +static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie)
  419. +{
  420. + struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
  421. + struct device *dev = pcie->dev;
  422. +
  423. + res->vdda = devm_regulator_get(dev, "vdda");
  424. + if (IS_ERR(res->vdda))
  425. + return PTR_ERR(res->vdda);
  426. +
  427. + res->iface = devm_clk_get(dev, "iface");
  428. + if (IS_ERR(res->iface))
  429. + return PTR_ERR(res->iface);
  430. +
  431. + res->aux = devm_clk_get(dev, "aux");
  432. + if (IS_ERR(res->aux) && PTR_ERR(res->aux) == -EPROBE_DEFER)
  433. + return -EPROBE_DEFER;
  434. + else if (IS_ERR(res->aux))
  435. + res->aux = NULL;
  436. +
  437. + res->master_bus = devm_clk_get(dev, "master_bus");
  438. + if (IS_ERR(res->master_bus))
  439. + return PTR_ERR(res->master_bus);
  440. +
  441. + res->slave_bus = devm_clk_get(dev, "slave_bus");
  442. + if (IS_ERR(res->slave_bus))
  443. + return PTR_ERR(res->slave_bus);
  444. +
  445. + res->core = devm_reset_control_get(dev, "core");
  446. + if (IS_ERR(res->core))
  447. + return PTR_ERR(res->core);
  448. +
  449. + return 0;
  450. +}
  451. +
  452. +static int qcom_pcie_enable_link_training(struct pcie_port *pp)
  453. +{
  454. + struct qcom_pcie *pcie = to_qcom_pcie(pp);
  455. + struct device *dev = pp->dev;
  456. + int retries;
  457. + u32 val;
  458. +
  459. + /* enable link training */
  460. + writel_masked(pcie->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
  461. +
  462. + /* wait for up to 100ms for the link to come up */
  463. + retries = LINKUP_RETRIES_COUNT;
  464. + do {
  465. + val = readl(pcie->elbi + PCIE20_ELBI_SYS_STTS);
  466. + if (val & XMLH_LINK_UP)
  467. + break;
  468. + usleep_range(LINKUP_DELAY_MIN_US, LINKUP_DELAY_MAX_US);
  469. + } while (retries--);
  470. +
  471. + if (retries < 0 || !dw_pcie_link_up(pp)) {
  472. + dev_err(dev, "link initialization failed\n");
  473. + return -ENXIO;
  474. + }
  475. +
  476. + return 0;
  477. +}
  478. +
  479. +static void qcom_pcie_host_init_v1(struct pcie_port *pp)
  480. +{
  481. + struct qcom_pcie *pcie = to_qcom_pcie(pp);
  482. + int ret;
  483. +
  484. + qcom_ep_reset_assert(pcie);
  485. +
  486. + ret = qcom_pcie_enable_resources_v1(pcie);
  487. + if (ret)
  488. + return;
  489. +
  490. + /* change DBI base address */
  491. + writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
  492. +
  493. + if (IS_ENABLED(CONFIG_PCI_MSI))
  494. + writel_masked(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT,
  495. + 0, BIT(31));
  496. +
  497. + ret = phy_init(pcie->phy);
  498. + if (ret)
  499. + goto err_res;
  500. +
  501. + ret = phy_power_on(pcie->phy);
  502. + if (ret)
  503. + goto err_phy;
  504. +
  505. + dw_pcie_setup_rc(pp);
  506. +
  507. + if (IS_ENABLED(CONFIG_PCI_MSI))
  508. + dw_pcie_msi_init(pp);
  509. +
  510. + qcom_ep_reset_deassert(pcie);
  511. +
  512. + ret = qcom_pcie_enable_link_training(pp);
  513. + if (ret)
  514. + goto err;
  515. +
  516. + return;
  517. +
  518. +err:
  519. + qcom_ep_reset_assert(pcie);
  520. + phy_power_off(pcie->phy);
  521. +err_phy:
  522. + phy_exit(pcie->phy);
  523. +err_res:
  524. + qcom_pcie_disable_resources_v1(pcie);
  525. +}
  526. +
  527. +static void qcom_pcie_host_init_v0(struct pcie_port *pp)
  528. +{
  529. + struct qcom_pcie *pcie = to_qcom_pcie(pp);
  530. + struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
  531. + struct device *dev = pcie->dev;
  532. + int ret;
  533. +
  534. + qcom_ep_reset_assert(pcie);
  535. +
  536. + ret = qcom_pcie_enable_resources_v0(pcie);
  537. + if (ret)
  538. + return;
  539. +
  540. + writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
  541. +
  542. + /* enable external reference clock */
  543. + writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
  544. +
  545. + ret = reset_control_deassert(res->phy_reset);
  546. + if (ret) {
  547. + dev_err(dev, "cannot deassert phy reset\n");
  548. + return;
  549. + }
  550. +
  551. + ret = reset_control_deassert(res->pci_reset);
  552. + if (ret) {
  553. + dev_err(dev, "cannot deassert pci reset\n");
  554. + return;
  555. + }
  556. +
  557. + ret = reset_control_deassert(res->por_reset);
  558. + if (ret) {
  559. + dev_err(dev, "cannot deassert por reset\n");
  560. + return;
  561. + }
  562. +
  563. + ret = reset_control_deassert(res->axi_reset);
  564. + if (ret) {
  565. + dev_err(dev, "cannot deassert axi reset\n");
  566. + return;
  567. + }
  568. +
  569. + /* wait 150ms for clock acquisition */
  570. + usleep_range(10000, 15000);
  571. +
  572. + dw_pcie_setup_rc(pp);
  573. +
  574. + if (IS_ENABLED(CONFIG_PCI_MSI))
  575. + dw_pcie_msi_init(pp);
  576. +
  577. + qcom_ep_reset_deassert(pcie);
  578. +
  579. + ret = qcom_pcie_enable_link_training(pp);
  580. + if (ret)
  581. + goto err;
  582. +
  583. + return;
  584. +err:
  585. + qcom_ep_reset_assert(pcie);
  586. + qcom_pcie_disable_resources_v0(pcie);
  587. +}
  588. +
  589. +static void qcom_pcie_host_init(struct pcie_port *pp)
  590. +{
  591. + struct qcom_pcie *pcie = to_qcom_pcie(pp);
  592. +
  593. + if (pcie->version == PCIE_V0)
  594. + return qcom_pcie_host_init_v0(pp);
  595. + else
  596. + return qcom_pcie_host_init_v1(pp);
  597. +}
  598. +
  599. +static int
  600. +qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val)
  601. +{
  602. + /* the device class is not reported correctly from the register */
  603. + if (where == PCI_CLASS_REVISION && size == 4) {
  604. + *val = readl(pp->dbi_base + PCI_CLASS_REVISION);
  605. + *val &= ~(0xffff << 16);
  606. + *val |= PCI_CLASS_BRIDGE_PCI << 16;
  607. + return PCIBIOS_SUCCESSFUL;
  608. + }
  609. +
  610. + return dw_pcie_cfg_read(pp->dbi_base + where, size, val);
  611. +}
  612. +
  613. +static struct pcie_host_ops qcom_pcie_ops = {
  614. + .link_up = qcom_pcie_link_up,
  615. + .host_init = qcom_pcie_host_init,
  616. + .rd_own_conf = qcom_pcie_rd_own_conf,
  617. +};
  618. +
  619. +static const struct of_device_id qcom_pcie_match[] = {
  620. + { .compatible = "qcom,pcie-v0", .data = (void *)PCIE_V0 },
  621. + { .compatible = "qcom,pcie-v1", .data = (void *)PCIE_V1 },
  622. + { }
  623. +};
  624. +
  625. +static int qcom_pcie_probe(struct platform_device *pdev)
  626. +{
  627. + struct device *dev = &pdev->dev;
  628. + const struct of_device_id *match;
  629. + struct resource *res;
  630. + struct qcom_pcie *pcie;
  631. + struct pcie_port *pp;
  632. + int ret;
  633. +
  634. + match = of_match_node(qcom_pcie_match, dev->of_node);
  635. + if (!match)
  636. + return -ENXIO;
  637. +
  638. + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
  639. + if (!pcie)
  640. + return -ENOMEM;
  641. +
  642. + pcie->version = (unsigned int)match->data;
  643. +
  644. + pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW);
  645. + if (IS_ERR(pcie->reset) && PTR_ERR(pcie->reset) == -EPROBE_DEFER)
  646. + return PTR_ERR(pcie->reset);
  647. +
  648. + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
  649. + pcie->parf = devm_ioremap_resource(dev, res);
  650. + if (IS_ERR(pcie->parf))
  651. + return PTR_ERR(pcie->parf);
  652. +
  653. + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
  654. + pcie->dbi = devm_ioremap_resource(dev, res);
  655. + if (IS_ERR(pcie->dbi))
  656. + return PTR_ERR(pcie->dbi);
  657. +
  658. + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi");
  659. + pcie->elbi = devm_ioremap_resource(dev, res);
  660. + if (IS_ERR(pcie->elbi))
  661. + return PTR_ERR(pcie->elbi);
  662. +
  663. + pcie->phy = devm_phy_optional_get(dev, "pciephy");
  664. + if (IS_ERR(pcie->phy))
  665. + return PTR_ERR(pcie->phy);
  666. +
  667. + pcie->dev = dev;
  668. +
  669. + if (pcie->version == PCIE_V0)
  670. + ret = qcom_pcie_get_resources_v0(pcie);
  671. + else
  672. + ret = qcom_pcie_get_resources_v1(pcie);
  673. +
  674. + if (ret)
  675. + return ret;
  676. +
  677. + pp = &pcie->pp;
  678. + pp->dev = dev;
  679. + pp->dbi_base = pcie->dbi;
  680. + pp->root_bus_nr = -1;
  681. + pp->ops = &qcom_pcie_ops;
  682. +
  683. + if (IS_ENABLED(CONFIG_PCI_MSI)) {
  684. + pp->msi_irq = platform_get_irq_byname(pdev, "msi");
  685. + if (pp->msi_irq < 0) {
  686. + dev_err(dev, "cannot get msi irq\n");
  687. + return pp->msi_irq;
  688. + }
  689. +
  690. + ret = devm_request_irq(dev, pp->msi_irq,
  691. + qcom_pcie_msi_irq_handler,
  692. + IRQF_SHARED, "qcom-pcie-msi", pp);
  693. + if (ret) {
  694. + dev_err(dev, "cannot request msi irq\n");
  695. + return ret;
  696. + }
  697. + }
  698. +
  699. + ret = dw_pcie_host_init(pp);
  700. + if (ret) {
  701. + dev_err(dev, "cannot initialize host\n");
  702. + return ret;
  703. + }
  704. +
  705. + platform_set_drvdata(pdev, pcie);
  706. +
  707. + return 0;
  708. +}
  709. +
  710. +static int qcom_pcie_remove(struct platform_device *pdev)
  711. +{
  712. + struct qcom_pcie *pcie = platform_get_drvdata(pdev);
  713. +
  714. + qcom_ep_reset_assert(pcie);
  715. + phy_power_off(pcie->phy);
  716. + phy_exit(pcie->phy);
  717. + if (pcie->version == PCIE_V0)
  718. + qcom_pcie_disable_resources_v0(pcie);
  719. + else
  720. + qcom_pcie_disable_resources_v1(pcie);
  721. +
  722. + return 0;
  723. +}
  724. +
  725. +static struct platform_driver qcom_pcie_driver = {
  726. + .probe = qcom_pcie_probe,
  727. + .remove = qcom_pcie_remove,
  728. + .driver = {
  729. + .name = "qcom-pcie",
  730. + .of_match_table = qcom_pcie_match,
  731. + },
  732. +};
  733. +
  734. +module_platform_driver(qcom_pcie_driver);
  735. +
  736. +MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");
  737. +MODULE_DESCRIPTION("Qualcomm PCIe root complex driver");
  738. +MODULE_LICENSE("GPL v2");
  739. +MODULE_ALIAS("platform:qcom-pcie");
  740. --- a/drivers/pci/host/Makefile
  741. +++ b/drivers/pci/host/Makefile
  742. @@ -20,3 +20,4 @@ obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-ip
  743. obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
  744. obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
  745. obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
  746. +obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o