123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- // SPDX-License-Identifier: GPL-2.0
- // Copyright (c) 2017 Cadence
- // Cadence PCIe controller driver.
- // Author: Cyrille Pitchen <[email protected]>
- #include <linux/kernel.h>
- #include "pcie-cadence.h"
- void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie)
- {
- u32 delay = 0x3;
- u32 ltssm_control_cap;
- /*
- * Set the LTSSM Detect Quiet state min. delay to 2ms.
- */
- ltssm_control_cap = cdns_pcie_readl(pcie, CDNS_PCIE_LTSSM_CONTROL_CAP);
- ltssm_control_cap = ((ltssm_control_cap &
- ~CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK) |
- CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay));
- cdns_pcie_writel(pcie, CDNS_PCIE_LTSSM_CONTROL_CAP, ltssm_control_cap);
- }
- void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
- u32 r, bool is_io,
- u64 cpu_addr, u64 pci_addr, size_t size)
- {
- /*
- * roundup_pow_of_two() returns an unsigned long, which is not suited
- * for 64bit values.
- */
- u64 sz = 1ULL << fls64(size - 1);
- int nbits = ilog2(sz);
- u32 addr0, addr1, desc0, desc1;
- if (nbits < 8)
- nbits = 8;
- /* Set the PCI address */
- addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
- (lower_32_bits(pci_addr) & GENMASK(31, 8));
- addr1 = upper_32_bits(pci_addr);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1);
- /* Set the PCIe header descriptor */
- if (is_io)
- desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO;
- else
- desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM;
- desc1 = 0;
- /*
- * Whatever Bit [23] is set or not inside DESC0 register of the outbound
- * PCIe descriptor, the PCI function number must be set into
- * Bits [26:24] of DESC0 anyway.
- *
- * In Root Complex mode, the function number is always 0 but in Endpoint
- * mode, the PCIe controller may support more than one function. This
- * function number needs to be set properly into the outbound PCIe
- * descriptor.
- *
- * Besides, setting Bit [23] is mandatory when in Root Complex mode:
- * then the driver must provide the bus, resp. device, number in
- * Bits [7:0] of DESC1, resp. Bits[31:27] of DESC0. Like the function
- * number, the device number is always 0 in Root Complex mode.
- *
- * However when in Endpoint mode, we can clear Bit [23] of DESC0, hence
- * the PCIe controller will use the captured values for the bus and
- * device numbers.
- */
- if (pcie->is_rc) {
- /* The device and function numbers are always 0. */
- desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
- CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
- desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr);
- } else {
- /*
- * Use captured values for bus and device numbers but still
- * need to set the function number.
- */
- desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
- }
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
- /* Set the CPU address */
- if (pcie->ops->cpu_addr_fixup)
- cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
- addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
- (lower_32_bits(cpu_addr) & GENMASK(31, 8));
- addr1 = upper_32_bits(cpu_addr);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
- }
- void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
- u8 busnr, u8 fn,
- u32 r, u64 cpu_addr)
- {
- u32 addr0, addr1, desc0, desc1;
- desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG;
- desc1 = 0;
- /* See cdns_pcie_set_outbound_region() comments above. */
- if (pcie->is_rc) {
- desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
- CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
- desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr);
- } else {
- desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
- }
- /* Set the CPU address */
- if (pcie->ops->cpu_addr_fixup)
- cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
- addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
- (lower_32_bits(cpu_addr) & GENMASK(31, 8));
- addr1 = upper_32_bits(cpu_addr);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
- }
- void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
- {
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
- }
- void cdns_pcie_disable_phy(struct cdns_pcie *pcie)
- {
- int i = pcie->phy_count;
- while (i--) {
- phy_power_off(pcie->phy[i]);
- phy_exit(pcie->phy[i]);
- }
- }
- int cdns_pcie_enable_phy(struct cdns_pcie *pcie)
- {
- int ret;
- int i;
- for (i = 0; i < pcie->phy_count; i++) {
- ret = phy_init(pcie->phy[i]);
- if (ret < 0)
- goto err_phy;
- ret = phy_power_on(pcie->phy[i]);
- if (ret < 0) {
- phy_exit(pcie->phy[i]);
- goto err_phy;
- }
- }
- return 0;
- err_phy:
- while (--i >= 0) {
- phy_power_off(pcie->phy[i]);
- phy_exit(pcie->phy[i]);
- }
- return ret;
- }
- int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie)
- {
- struct device_node *np = dev->of_node;
- int phy_count;
- struct phy **phy;
- struct device_link **link;
- int i;
- int ret;
- const char *name;
- phy_count = of_property_count_strings(np, "phy-names");
- if (phy_count < 1) {
- dev_err(dev, "no phy-names. PHY will not be initialized\n");
- pcie->phy_count = 0;
- return 0;
- }
- phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL);
- if (!phy)
- return -ENOMEM;
- link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL);
- if (!link)
- return -ENOMEM;
- for (i = 0; i < phy_count; i++) {
- of_property_read_string_index(np, "phy-names", i, &name);
- phy[i] = devm_phy_get(dev, name);
- if (IS_ERR(phy[i])) {
- ret = PTR_ERR(phy[i]);
- goto err_phy;
- }
- link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
- if (!link[i]) {
- devm_phy_put(dev, phy[i]);
- ret = -EINVAL;
- goto err_phy;
- }
- }
- pcie->phy_count = phy_count;
- pcie->phy = phy;
- pcie->link = link;
- ret = cdns_pcie_enable_phy(pcie);
- if (ret)
- goto err_phy;
- return 0;
- err_phy:
- while (--i >= 0) {
- device_link_del(link[i]);
- devm_phy_put(dev, phy[i]);
- }
- return ret;
- }
- static int cdns_pcie_suspend_noirq(struct device *dev)
- {
- struct cdns_pcie *pcie = dev_get_drvdata(dev);
- cdns_pcie_disable_phy(pcie);
- return 0;
- }
- static int cdns_pcie_resume_noirq(struct device *dev)
- {
- struct cdns_pcie *pcie = dev_get_drvdata(dev);
- int ret;
- ret = cdns_pcie_enable_phy(pcie);
- if (ret) {
- dev_err(dev, "failed to enable phy\n");
- return ret;
- }
- return 0;
- }
- const struct dev_pm_ops cdns_pcie_pm_ops = {
- NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq,
- cdns_pcie_resume_noirq)
- };
|