Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/pci/controller/dwc/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 18 kB image not shown  

Quelle  pcie-kirin.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * PCIe host controller driver for Kirin Phone SoCs
 *
 * Copyright (C) 2017 HiSilicon Electronics Co., Ltd.
 * https://www.huawei.com
 *
 * Author: Xiaowei Song <songxiaowei@huawei.com>
 */


#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_pci.h>
#include <linux/phy/phy.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/resource.h>
#include <linux/types.h>
#include "pcie-designware.h"

#define to_kirin_pcie(x) dev_get_drvdata((x)->dev)

/* PCIe ELBI registers */
#define SOC_PCIECTRL_CTRL0_ADDR  0x000
#define SOC_PCIECTRL_CTRL1_ADDR  0x004
#define PCIE_ELBI_SLV_DBI_ENABLE (0x1 << 21)

/* info located in APB */
#define PCIE_APP_LTSSM_ENABLE 0x01c
#define PCIE_APB_PHY_STATUS0 0x400
#define PCIE_LINKUP_ENABLE (0x8020)
#define PCIE_LTSSM_ENABLE_BIT (0x1 << 11)

/* info located in sysctrl */
#define SCTRL_PCIE_CMOS_OFFSET 0x60
#define SCTRL_PCIE_CMOS_BIT 0x10
#define SCTRL_PCIE_ISO_OFFSET 0x44
#define SCTRL_PCIE_ISO_BIT 0x30
#define SCTRL_PCIE_HPCLK_OFFSET 0x190
#define SCTRL_PCIE_HPCLK_BIT 0x184000
#define SCTRL_PCIE_OE_OFFSET 0x14a
#define PCIE_DEBOUNCE_PARAM 0xF0F400
#define PCIE_OE_BYPASS  (0x3 << 28)

/*
 * Max number of connected PCI slots at an external PCI bridge
 *
 * This is used on HiKey 970, which has a PEX 8606 bridge with 4 connected
 * lanes (lane 0 upstream, and the other three lanes, one connected to an
 * in-board Ethernet adapter and the other two connected to M.2 and mini
 * PCI slots.
 *
 * Each slot has a different clock source and uses a separate PERST# pin.
 */

#define MAX_PCI_SLOTS  3

enum pcie_kirin_phy_type {
 PCIE_KIRIN_INTERNAL_PHY,
 PCIE_KIRIN_EXTERNAL_PHY
};

struct kirin_pcie {
 enum pcie_kirin_phy_type type;

 struct dw_pcie *pci;
 struct regmap   *apb;
 struct phy *phy;
 void  *phy_priv; /* only for PCIE_KIRIN_INTERNAL_PHY */

 /* DWC PERST# */
 struct gpio_desc *id_dwc_perst_gpio;

 /* Per-slot PERST# */
 int  num_slots;
 struct gpio_desc *id_reset_gpio[MAX_PCI_SLOTS];
 const char *reset_names[MAX_PCI_SLOTS];

 /* Per-slot clkreq */
 int  n_gpio_clkreq;
 struct gpio_desc *id_clkreq_gpio[MAX_PCI_SLOTS];
 const char *clkreq_names[MAX_PCI_SLOTS];
};

/*
 * Kirin 960 PHY. Can't be split into a PHY driver without changing the
 * DT schema.
 */


#define REF_CLK_FREQ   100000000

/* PHY info located in APB */
#define PCIE_APB_PHY_CTRL0 0x0
#define PCIE_APB_PHY_CTRL1 0x4
#define PCIE_APB_PHY_STATUS0   0x400
#define PIPE_CLK_STABLE  BIT(19)
#define PHY_REF_PAD_BIT  BIT(8)
#define PHY_PWR_DOWN_BIT BIT(22)
#define PHY_RST_ACK_BIT  BIT(16)

/* peri_crg ctrl */
#define CRGCTRL_PCIE_ASSERT_OFFSET 0x88
#define CRGCTRL_PCIE_ASSERT_BIT  0x8c000000

/* Time for delay */
#define REF_2_PERST_MIN  21000
#define REF_2_PERST_MAX  25000
#define PERST_2_ACCESS_MIN 10000
#define PERST_2_ACCESS_MAX 12000
#define PIPE_CLK_WAIT_MIN 550
#define PIPE_CLK_WAIT_MAX 600
#define TIME_CMOS_MIN  100
#define TIME_CMOS_MAX  105
#define TIME_PHY_PD_MIN  10
#define TIME_PHY_PD_MAX  11

struct hi3660_pcie_phy {
 struct device *dev;
 void __iomem *base;
 struct regmap *crgctrl;
 struct regmap *sysctrl;
 struct clk *apb_sys_clk;
 struct clk *apb_phy_clk;
 struct clk *phy_ref_clk;
 struct clk *aclk;
 struct clk *aux_clk;
};

/* Registers in PCIePHY */
static inline void kirin_apb_phy_writel(struct hi3660_pcie_phy *hi3660_pcie_phy,
     u32 val, u32 reg)
{
 writel(val, hi3660_pcie_phy->base + reg);
}

static inline u32 kirin_apb_phy_readl(struct hi3660_pcie_phy *hi3660_pcie_phy,
          u32 reg)
{
 return readl(hi3660_pcie_phy->base + reg);
}

static int hi3660_pcie_phy_get_clk(struct hi3660_pcie_phy *phy)
{
 struct device *dev = phy->dev;

 phy->phy_ref_clk = devm_clk_get(dev, "pcie_phy_ref");
 if (IS_ERR(phy->phy_ref_clk))
  return PTR_ERR(phy->phy_ref_clk);

 phy->aux_clk = devm_clk_get(dev, "pcie_aux");
 if (IS_ERR(phy->aux_clk))
  return PTR_ERR(phy->aux_clk);

 phy->apb_phy_clk = devm_clk_get(dev, "pcie_apb_phy");
 if (IS_ERR(phy->apb_phy_clk))
  return PTR_ERR(phy->apb_phy_clk);

 phy->apb_sys_clk = devm_clk_get(dev, "pcie_apb_sys");
 if (IS_ERR(phy->apb_sys_clk))
  return PTR_ERR(phy->apb_sys_clk);

 phy->aclk = devm_clk_get(dev, "pcie_aclk");
 if (IS_ERR(phy->aclk))
  return PTR_ERR(phy->aclk);

 return 0;
}

static int hi3660_pcie_phy_get_resource(struct hi3660_pcie_phy *phy)
{
 struct device *dev = phy->dev;
 struct platform_device *pdev;

 /* registers */
 pdev = container_of(dev, struct platform_device, dev);

 phy->base = devm_platform_ioremap_resource_byname(pdev, "phy");
 if (IS_ERR(phy->base))
  return PTR_ERR(phy->base);

 phy->crgctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3660-crgctrl");
 if (IS_ERR(phy->crgctrl))
  return PTR_ERR(phy->crgctrl);

 phy->sysctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3660-sctrl");
 if (IS_ERR(phy->sysctrl))
  return PTR_ERR(phy->sysctrl);

 return 0;
}

static int hi3660_pcie_phy_start(struct hi3660_pcie_phy *phy)
{
 struct device *dev = phy->dev;
 u32 reg_val;

 reg_val = kirin_apb_phy_readl(phy, PCIE_APB_PHY_CTRL1);
 reg_val &= ~PHY_REF_PAD_BIT;
 kirin_apb_phy_writel(phy, reg_val, PCIE_APB_PHY_CTRL1);

 reg_val = kirin_apb_phy_readl(phy, PCIE_APB_PHY_CTRL0);
 reg_val &= ~PHY_PWR_DOWN_BIT;
 kirin_apb_phy_writel(phy, reg_val, PCIE_APB_PHY_CTRL0);
 usleep_range(TIME_PHY_PD_MIN, TIME_PHY_PD_MAX);

 reg_val = kirin_apb_phy_readl(phy, PCIE_APB_PHY_CTRL1);
 reg_val &= ~PHY_RST_ACK_BIT;
 kirin_apb_phy_writel(phy, reg_val, PCIE_APB_PHY_CTRL1);

 usleep_range(PIPE_CLK_WAIT_MIN, PIPE_CLK_WAIT_MAX);
 reg_val = kirin_apb_phy_readl(phy, PCIE_APB_PHY_STATUS0);
 if (reg_val & PIPE_CLK_STABLE)
  return dev_err_probe(dev, -ETIMEDOUT,
         "PIPE clk is not stable\n");

 return 0;
}

static void hi3660_pcie_phy_oe_enable(struct hi3660_pcie_phy *phy)
{
 u32 val;

 regmap_read(phy->sysctrl, SCTRL_PCIE_OE_OFFSET, &val);
 val |= PCIE_DEBOUNCE_PARAM;
 val &= ~PCIE_OE_BYPASS;
 regmap_write(phy->sysctrl, SCTRL_PCIE_OE_OFFSET, val);
}

static int hi3660_pcie_phy_clk_ctrl(struct hi3660_pcie_phy *phy, bool enable)
{
 int ret = 0;

 if (!enable)
  goto close_clk;

 ret = clk_set_rate(phy->phy_ref_clk, REF_CLK_FREQ);
 if (ret)
  return ret;

 ret = clk_prepare_enable(phy->phy_ref_clk);
 if (ret)
  return ret;

 ret = clk_prepare_enable(phy->apb_sys_clk);
 if (ret)
  goto apb_sys_fail;

 ret = clk_prepare_enable(phy->apb_phy_clk);
 if (ret)
  goto apb_phy_fail;

 ret = clk_prepare_enable(phy->aclk);
 if (ret)
  goto aclk_fail;

 ret = clk_prepare_enable(phy->aux_clk);
 if (ret)
  goto aux_clk_fail;

 return 0;

close_clk:
 clk_disable_unprepare(phy->aux_clk);
aux_clk_fail:
 clk_disable_unprepare(phy->aclk);
aclk_fail:
 clk_disable_unprepare(phy->apb_phy_clk);
apb_phy_fail:
 clk_disable_unprepare(phy->apb_sys_clk);
apb_sys_fail:
 clk_disable_unprepare(phy->phy_ref_clk);

 return ret;
}

static int hi3660_pcie_phy_power_on(struct kirin_pcie *pcie)
{
 struct hi3660_pcie_phy *phy = pcie->phy_priv;
 int ret;

 /* Power supply for Host */
 regmap_write(phy->sysctrl,
       SCTRL_PCIE_CMOS_OFFSET, SCTRL_PCIE_CMOS_BIT);
 usleep_range(TIME_CMOS_MIN, TIME_CMOS_MAX);

 hi3660_pcie_phy_oe_enable(phy);

 ret = hi3660_pcie_phy_clk_ctrl(phy, true);
 if (ret)
  return ret;

 /* ISO disable, PCIeCtrl, PHY assert and clk gate clear */
 regmap_write(phy->sysctrl,
       SCTRL_PCIE_ISO_OFFSET, SCTRL_PCIE_ISO_BIT);
 regmap_write(phy->crgctrl,
       CRGCTRL_PCIE_ASSERT_OFFSET, CRGCTRL_PCIE_ASSERT_BIT);
 regmap_write(phy->sysctrl,
       SCTRL_PCIE_HPCLK_OFFSET, SCTRL_PCIE_HPCLK_BIT);

 ret = hi3660_pcie_phy_start(phy);
 if (ret)
  goto disable_clks;

 return 0;

disable_clks:
 hi3660_pcie_phy_clk_ctrl(phy, false);
 return ret;
}

static int hi3660_pcie_phy_init(struct platform_device *pdev,
    struct kirin_pcie *pcie)
{
 struct device *dev = &pdev->dev;
 struct hi3660_pcie_phy *phy;
 int ret;

 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
 if (!phy)
  return -ENOMEM;

 pcie->phy_priv = phy;
 phy->dev = dev;

 ret = hi3660_pcie_phy_get_clk(phy);
 if (ret)
  return ret;

 return hi3660_pcie_phy_get_resource(phy);
}

static int hi3660_pcie_phy_power_off(struct kirin_pcie *pcie)
{
 struct hi3660_pcie_phy *phy = pcie->phy_priv;

 /* Drop power supply for Host */
 regmap_write(phy->sysctrl, SCTRL_PCIE_CMOS_OFFSET, 0x00);

 hi3660_pcie_phy_clk_ctrl(phy, false);

 return 0;
}

/*
 * The non-PHY part starts here
 */


static const struct regmap_config pcie_kirin_regmap_conf = {
 .name = "kirin_pcie_apb",
 .reg_bits = 32,
 .val_bits = 32,
 .reg_stride = 4,
};

static int kirin_pcie_get_gpio_enable(struct kirin_pcie *pcie,
          struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 int ret, i;

 /* This is an optional property */
 ret = gpiod_count(dev, "hisilicon,clken");
 if (ret < 0)
  return 0;

 if (ret > MAX_PCI_SLOTS)
  return dev_err_probe(dev, -EINVAL,
         "Too many GPIO clock requests!\n");

 pcie->n_gpio_clkreq = ret;

 for (i = 0; i < pcie->n_gpio_clkreq; i++) {
  pcie->id_clkreq_gpio[i] = devm_gpiod_get_index(dev,
       "hisilicon,clken", i,
       GPIOD_OUT_LOW);
  if (IS_ERR(pcie->id_clkreq_gpio[i]))
   return dev_err_probe(dev, PTR_ERR(pcie->id_clkreq_gpio[i]),
          "unable to get a valid clken gpio\n");

  pcie->clkreq_names[i] = devm_kasprintf(dev, GFP_KERNEL,
             "pcie_clkreq_%d", i);
  if (!pcie->clkreq_names[i])
   return -ENOMEM;

  gpiod_set_consumer_name(pcie->id_clkreq_gpio[i],
     pcie->clkreq_names[i]);
 }

 return 0;
}

static int kirin_pcie_parse_port(struct kirin_pcie *pcie,
     struct platform_device *pdev,
     struct device_node *node)
{
 struct device *dev = &pdev->dev;
 int ret, slot, i;

 for_each_available_child_of_node_scoped(node, parent) {
  for_each_available_child_of_node_scoped(parent, child) {
   i = pcie->num_slots;

   pcie->id_reset_gpio[i] = devm_fwnode_gpiod_get_index(dev,
        of_fwnode_handle(child),
        "reset", 0, GPIOD_OUT_LOW,
        NULL);
   if (IS_ERR(pcie->id_reset_gpio[i])) {
    if (PTR_ERR(pcie->id_reset_gpio[i]) == -ENOENT)
     continue;
    return dev_err_probe(dev, PTR_ERR(pcie->id_reset_gpio[i]),
           "unable to get a valid reset gpio\n");
   }

   if (pcie->num_slots + 1 >= MAX_PCI_SLOTS)
    return dev_err_probe(dev, -EINVAL,
           "Too many PCI slots!\n");

   pcie->num_slots++;

   ret = of_pci_get_devfn(child);
   if (ret < 0)
    return dev_err_probe(dev, ret,
           "failed to parse devfn\n");

   slot = PCI_SLOT(ret);

   pcie->reset_names[i] = devm_kasprintf(dev, GFP_KERNEL,
             "pcie_perst_%d",
             slot);
   if (!pcie->reset_names[i])
    return -ENOMEM;

   gpiod_set_consumer_name(pcie->id_reset_gpio[i],
      pcie->reset_names[i]);
  }
 }

 return 0;
}

static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
        struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct device_node *node = dev->of_node;
 void __iomem *apb_base;
 int ret;

 apb_base = devm_platform_ioremap_resource_byname(pdev, "apb");
 if (IS_ERR(apb_base))
  return PTR_ERR(apb_base);

 kirin_pcie->apb = devm_regmap_init_mmio(dev, apb_base,
      &pcie_kirin_regmap_conf);
 if (IS_ERR(kirin_pcie->apb))
  return PTR_ERR(kirin_pcie->apb);

 /* pcie internal PERST# gpio */
 kirin_pcie->id_dwc_perst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
 if (IS_ERR(kirin_pcie->id_dwc_perst_gpio))
  return dev_err_probe(dev, PTR_ERR(kirin_pcie->id_dwc_perst_gpio),
         "unable to get a valid gpio pin\n");
 gpiod_set_consumer_name(kirin_pcie->id_dwc_perst_gpio, "pcie_perst_bridge");

 ret = kirin_pcie_get_gpio_enable(kirin_pcie, pdev);
 if (ret)
  return ret;

 /* Parse OF children */
 for_each_available_child_of_node_scoped(node, child) {
  ret = kirin_pcie_parse_port(kirin_pcie, pdev, child);
  if (ret)
   return ret;
 }

 return 0;
}

static void kirin_pcie_sideband_dbi_w_mode(struct kirin_pcie *kirin_pcie,
        bool on)
{
 u32 val;

 regmap_read(kirin_pcie->apb, SOC_PCIECTRL_CTRL0_ADDR, &val);
 if (on)
  val = val | PCIE_ELBI_SLV_DBI_ENABLE;
 else
  val = val & ~PCIE_ELBI_SLV_DBI_ENABLE;

 regmap_write(kirin_pcie->apb, SOC_PCIECTRL_CTRL0_ADDR, val);
}

static void kirin_pcie_sideband_dbi_r_mode(struct kirin_pcie *kirin_pcie,
        bool on)
{
 u32 val;

 regmap_read(kirin_pcie->apb, SOC_PCIECTRL_CTRL1_ADDR, &val);
 if (on)
  val = val | PCIE_ELBI_SLV_DBI_ENABLE;
 else
  val = val & ~PCIE_ELBI_SLV_DBI_ENABLE;

 regmap_write(kirin_pcie->apb, SOC_PCIECTRL_CTRL1_ADDR, val);
}

static int kirin_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
      int where, int size, u32 *val)
{
 struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);

 if (PCI_SLOT(devfn))
  return PCIBIOS_DEVICE_NOT_FOUND;

 *val = dw_pcie_read_dbi(pci, where, size);
 return PCIBIOS_SUCCESSFUL;
}

static int kirin_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
      int where, int size, u32 val)
{
 struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);

 if (PCI_SLOT(devfn))
  return PCIBIOS_DEVICE_NOT_FOUND;

 dw_pcie_write_dbi(pci, where, size, val);
 return PCIBIOS_SUCCESSFUL;
}

static int kirin_pcie_add_bus(struct pci_bus *bus)
{
 struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
 struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
 int i, ret;

 if (!kirin_pcie->num_slots)
  return 0;

 /* Send PERST# to each slot */
 for (i = 0; i < kirin_pcie->num_slots; i++) {
  ret = gpiod_direction_output_raw(kirin_pcie->id_reset_gpio[i], 1);
  if (ret) {
   dev_err(pci->dev, "PERST# %s error: %d\n",
    kirin_pcie->reset_names[i], ret);
  }
 }
 usleep_range(PERST_2_ACCESS_MIN, PERST_2_ACCESS_MAX);

 return 0;
}

static struct pci_ops kirin_pci_ops = {
 .read = kirin_pcie_rd_own_conf,
 .write = kirin_pcie_wr_own_conf,
 .add_bus = kirin_pcie_add_bus,
};

static u32 kirin_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
          u32 reg, size_t size)
{
 struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
 u32 ret;

 kirin_pcie_sideband_dbi_r_mode(kirin_pcie, true);
 dw_pcie_read(base + reg, size, &ret);
 kirin_pcie_sideband_dbi_r_mode(kirin_pcie, false);

 return ret;
}

static void kirin_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
     u32 reg, size_t size, u32 val)
{
 struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);

 kirin_pcie_sideband_dbi_w_mode(kirin_pcie, true);
 dw_pcie_write(base + reg, size, val);
 kirin_pcie_sideband_dbi_w_mode(kirin_pcie, false);
}

static bool kirin_pcie_link_up(struct dw_pcie *pci)
{
 struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
 u32 val;

 regmap_read(kirin_pcie->apb, PCIE_APB_PHY_STATUS0, &val);
 return (val & PCIE_LINKUP_ENABLE) == PCIE_LINKUP_ENABLE;
}

static int kirin_pcie_start_link(struct dw_pcie *pci)
{
 struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);

 /* assert LTSSM enable */
 regmap_write(kirin_pcie->apb, PCIE_APP_LTSSM_ENABLE,
       PCIE_LTSSM_ENABLE_BIT);

 return 0;
}

static int kirin_pcie_host_init(struct dw_pcie_rp *pp)
{
 pp->bridge->ops = &kirin_pci_ops;

 return 0;
}

static const struct dw_pcie_ops kirin_dw_pcie_ops = {
 .read_dbi = kirin_pcie_read_dbi,
 .write_dbi = kirin_pcie_write_dbi,
 .link_up = kirin_pcie_link_up,
 .start_link = kirin_pcie_start_link,
};

static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
 .init = kirin_pcie_host_init,
};

static int kirin_pcie_power_off(struct kirin_pcie *kirin_pcie)
{
 int i;

 if (kirin_pcie->type == PCIE_KIRIN_INTERNAL_PHY)
  return hi3660_pcie_phy_power_off(kirin_pcie);

 for (i = 0; i < kirin_pcie->n_gpio_clkreq; i++)
  gpiod_direction_output_raw(kirin_pcie->id_clkreq_gpio[i], 1);

 phy_power_off(kirin_pcie->phy);
 phy_exit(kirin_pcie->phy);

 return 0;
}

static int kirin_pcie_power_on(struct platform_device *pdev,
          struct kirin_pcie *kirin_pcie)
{
 struct device *dev = &pdev->dev;
 int ret;

 if (kirin_pcie->type == PCIE_KIRIN_INTERNAL_PHY) {
  ret = hi3660_pcie_phy_init(pdev, kirin_pcie);
  if (ret)
   return ret;

  ret = hi3660_pcie_phy_power_on(kirin_pcie);
  if (ret)
   return ret;
 } else {
  kirin_pcie->phy = devm_of_phy_get(dev, dev->of_node, NULL);
  if (IS_ERR(kirin_pcie->phy))
   return PTR_ERR(kirin_pcie->phy);

  ret = phy_init(kirin_pcie->phy);
  if (ret)
   goto err;

  ret = phy_power_on(kirin_pcie->phy);
  if (ret)
   goto err;
 }

 /* perst assert Endpoint */
 usleep_range(REF_2_PERST_MIN, REF_2_PERST_MAX);

 ret = gpiod_direction_output_raw(kirin_pcie->id_dwc_perst_gpio, 1);
 if (ret)
  goto err;

 usleep_range(PERST_2_ACCESS_MIN, PERST_2_ACCESS_MAX);

 return 0;
err:
 kirin_pcie_power_off(kirin_pcie);

 return ret;
}

static void kirin_pcie_remove(struct platform_device *pdev)
{
 struct kirin_pcie *kirin_pcie = platform_get_drvdata(pdev);

 dw_pcie_host_deinit(&kirin_pcie->pci->pp);

 kirin_pcie_power_off(kirin_pcie);
}

struct kirin_pcie_data {
 enum pcie_kirin_phy_type phy_type;
};

static const struct kirin_pcie_data kirin_960_data = {
 .phy_type = PCIE_KIRIN_INTERNAL_PHY,
};

static const struct kirin_pcie_data kirin_970_data = {
 .phy_type = PCIE_KIRIN_EXTERNAL_PHY,
};

static const struct of_device_id kirin_pcie_match[] = {
 { .compatible = "hisilicon,kirin960-pcie", .data = &kirin_960_data },
 { .compatible = "hisilicon,kirin970-pcie", .data = &kirin_970_data },
 {},
};

static int kirin_pcie_probe(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 const struct kirin_pcie_data *data;
 struct kirin_pcie *kirin_pcie;
 struct dw_pcie *pci;
 int ret;

 data = of_device_get_match_data(dev);
 if (!data)
  return dev_err_probe(dev, -EINVAL, "OF data missing\n");

 kirin_pcie = devm_kzalloc(dev, sizeof(struct kirin_pcie), GFP_KERNEL);
 if (!kirin_pcie)
  return -ENOMEM;

 pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
 if (!pci)
  return -ENOMEM;

 pci->dev = dev;
 pci->ops = &kirin_dw_pcie_ops;
 pci->pp.ops = &kirin_pcie_host_ops;
 kirin_pcie->pci = pci;
 kirin_pcie->type = data->phy_type;

 ret = kirin_pcie_get_resource(kirin_pcie, pdev);
 if (ret)
  return ret;

 platform_set_drvdata(pdev, kirin_pcie);

 ret = kirin_pcie_power_on(pdev, kirin_pcie);
 if (ret)
  return ret;

 return dw_pcie_host_init(&pci->pp);
}

static struct platform_driver kirin_pcie_driver = {
 .probe   = kirin_pcie_probe,
 .remove   = kirin_pcie_remove,
 .driver   = {
  .name   = "kirin-pcie",
  .of_match_table  = kirin_pcie_match,
  .suppress_bind_attrs = true,
 },
};
module_platform_driver(kirin_pcie_driver);

MODULE_DEVICE_TABLE(of, kirin_pcie_match);
MODULE_DESCRIPTION("PCIe host controller driver for Kirin Phone SoCs");
MODULE_AUTHOR("Xiaowei Song ");
MODULE_LICENSE("GPL v2");

Messung V0.5
C=92 H=95 G=93

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.