PCI: hisi: add PCIe driver support for HiSilicon STB SoCs
Subsystems (4)
Shawn Guo
maintainerPATCH 1/1 PCI: hisi: add PCIe driver support for HiSilicon STB SoCs
From: Jianguo Sun <[email protected]>
Add PCIe controller driver for HiSilicon STB SoCs, the controller is based on the DesignWare's PCIe core.
--- .../bindings/pci/hisilicon-histb-pcie.txt | 66 +++ drivers/pci/dwc/Kconfig | 10 + drivers/pci/dwc/Makefile | 1 + drivers/pci/dwc/pcie-histb.c | 469 +++++++++++++++++++++ 4 files changed, 546 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt create mode 100644 drivers/pci/dwc/pcie-histb.c
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +66 -0
@@ -0,0 +1,66 @@ +HiSilicon STB PCIe host bridge DT description + +HiSilicon STB PCIe host controller is based on Designware PCI core. +It shares common functions with PCIe Designware core driver and inherits +common properties defined in +Documentation/devicetree/bindings/pci/designware-pcie.txt. + +Additional properties are described here: + +Required properties +- compatible: Should be one of the following strings: + "hisilicon,hi3798cv200-pcie" +- reg: Should contain sysctl, rc_dbi, config registers location and length. +- reg-names: Must include the following entries: + "control": control registers of PCIe controller; + "rc-dbi": configuration space of PCIe controller; + "config": configuration transaction space of PCIe controller. +- bus-range: PCI bus numbers covered. +- interrupts: MSI interrupt. +- interrupt-names: Must include "msi" entries. +- clocks: List of phandle and clock specifier pairs as listed in clock-names + property. +- clock-name: Must include the following entries: + "aux": auxiliary gate clock; + "pipe": pipe gate clock; + "sys": sys gate clock; + "bus": bus gate clock. +- resets: List of phandle and reset specifier pairs as listed in reset-names + property. +- reset-names: Must include the following entries: + "soft": soft reset; + "sys": sys reset; + "bus": bus reset. + +Optional properties: +- reset-gpios: The gpio to generate PCIe PERST# assert and deassert signal. +- phys: List of phandle and phy mode specifier, should be 0. +- phy-names: Must be "phy". + +Example: + pcie at f9860000 { + compatible = "hisilicon,hi3798cv200-pcie"; + reg = <0xf9860000 0x1000>, + <0xf0000000 0x2000>, + <0xf2000000 0x01000000>; + reg-names = "control", "rc-dbi", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0 15>; + num-lanes = <1>; + ranges=<0x81000000 0 0 0xf4000000 0 0x00010000 + 0x82000000 0 0xf3000000 0xf3000000 0 0x01000000>; + interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg PCIE_AUX_CLK>, + <&crg PCIE_PIPE_CLK>, + <&crg PCIE_SYS_CLK>, + <&crg PCIE_BUS_CLK>; + clock-names = "aux", "pipe", "sys", "bus"; + resets = <&crg 0x18c 6>, <&crg 0x18c 5>, <&crg 0x18c 4>; + reset-names = "soft", "sys", "bus"; + };
drivers/pci/dwc/Kconfig +10 -0
@@ -169,4 +169,14 @@ config PCIE_KIRIN Say Y here if you want PCIe controller support on HiSilicon Kirin series SoCs. +config PCIE_HISI_STB + bool "HiSilicon STB SoCs PCIe controllers" + depends on ARCH_HISI + depends on PCI + depends on PCI_MSI_IRQ_DOMAIN + select PCIEPORTBUS + select PCIE_DW_HOST + help + Say Y here if you want PCIe controller support on HiSilicon STB SoCs + endmenu
drivers/pci/dwc/Makefile +1 -0
@@ -14,6 +14,7 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o +obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o # The following drivers are for devices that use the generic ACPI # pci_root.c driver but don't support standard ECAM config access.
drivers/pci/dwc/pcie-histb.c new file +469 -0
469 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 1/1 PCI: hisi: add PCIe driver support for HiSilicon STB SoCs
Quoted 4 lines · Shawn Guo
From: Jianguo Sun <[email protected]>
Add PCIe controller driver for HiSilicon STB SoCs, the controller is based on the DesignWare's PCIe core.
s/DesignWare's/DesignWare/
Quoted 10 lines
Signed-off-by Jianguo Sun <[email protected]>Signed-off-by Shawn Guo <[email protected]>--- .../bindings/pci/hisilicon-histb-pcie.txt | 66 +++ drivers/pci/dwc/Kconfig | 10 + drivers/pci/dwc/Makefile | 1 + drivers/pci/dwc/pcie-histb.c | 469 +++++++++++++++++++++ 4 files changed, 546 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt create mode 100644 drivers/pci/dwc/pcie-histb.c
Looks beautiful overall!
This needs a MAINTAINERS update so "./scripts/get_maintainer.pl -f" prints something useful.
A few minor nits below that I would fix myself, but since you need to supply the MAINTAINERS update anyway, I'll let you do it :)
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt line 6
Quoted 12 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +6
-0@@ -0,0 +1,66 @@ +HiSilicon STB PCIe host bridge DT description + +HiSilicon STB PCIe host controller is based on Designware PCI core. +It shares common functions with PCIe Designware core driver and inherits +common properties defined in +Documentation/devicetree/bindings/pci/designware-pcie.txt.
s/Designware/DesignWare/ in English text above (not in filenames, function names, etc).
s/PCI/PCIe/
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt line 8
Quoted 2 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +2
-0+static u32 histb_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, + u32 reg, size_t size)
These should be lined up exactly ("u32" should line up with "struct" above it). They are currently off by one. Similarly for histb_pcie_write_dbi(), histb_pcie_rd_own_conf(), histb_pcie_wr_own_conf().
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt line 11
Quoted 3 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +3
-0+ hipcie->aux_clk = devm_clk_get(dev, "aux"); + if (IS_ERR(hipcie->aux_clk)) { + dev_err(dev, "Failed to get pcie aux clk\n");
s/pcie/PCIe/ in this message and the ones below. Also in histb_pcie_host_enable() comment.
Quoted 10 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +9
-0+ return PTR_ERR(hipcie->aux_clk); + } + + hipcie->pipe_clk = devm_clk_get(dev, "pipe"); + if (IS_ERR(hipcie->pipe_clk)) { + dev_err(dev, "Failed to get pcie pipe clk\n"); + return PTR_ERR(hipcie->pipe_clk); + if (IS_ENABLED(CONFIG_PCI_MSI)) { + pp->msi_irq = platform_get_irq_byname(pdev, "msi");
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt
Quoted 10 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +10
-0+ if (pp->msi_irq < 0) { + dev_err(dev, "Failed to get msi irq\n"); + return pp->msi_irq; + } + + ret = devm_request_irq(dev, pp->msi_irq, + histb_pcie_msi_irq_handler, + IRQF_SHARED, "histb-pcie-msi", pp); + if (ret) { + dev_err(dev, "cannot request msi irq\n");
s/msi irq/MSI IRQ/ in the error message. Also a few lines above.
Shawn Guo
maintainerPATCH 1/1 PCI: hisi: add PCIe driver support for HiSilicon STB SoCs
Hi Bjorn,
Thanks for taking time to look at the patch.
Quoted 19 lines · Bjorn Helgaas
Quoted 4 lines · Shawn Guo
From: Jianguo Sun <[email protected]>
Add PCIe controller driver for HiSilicon STB SoCs, the controller is based on the DesignWare's PCIe core.
s/DesignWare's/DesignWare/
Quoted 10 lines
Signed-off-by Jianguo Sun <[email protected]>Signed-off-by Shawn Guo <[email protected]>--- .../bindings/pci/hisilicon-histb-pcie.txt | 66 +++ drivers/pci/dwc/Kconfig | 10 + drivers/pci/dwc/Makefile | 1 + drivers/pci/dwc/pcie-histb.c | 469 +++++++++++++++++++++ 4 files changed, 546 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt create mode 100644 drivers/pci/dwc/pcie-histb.c
Quoted 4 lines
Looks beautiful overall!
This needs a
MAINTAINERSupdate so "./scripts/get_maintainer.pl-f" prints something useful.
Okay, I will add a MAINTAINERS entry for this driver.
Quoted 2 lines
A few minor nits below that I would fix myself, but since you need to supply the
MAINTAINERSupdate anyway, I'll let you do it :)
Thanks for all the suggestions. We fixed them all, and the code does look nicer.
Shawn
PATCH 1/1 PCI: hisi: add PCIe driver support for HiSilicon STB SoCs
In reply to Shawn GuoQuoted 70 lines · Shawn Guo
From: Jianguo Sun <[email protected]>
Add PCIe controller driver for HiSilicon STB SoCs, the controller is based on the DesignWare's PCIe core.
Signed-off-by Jianguo Sun <[email protected]>Signed-off-by Shawn Guo <[email protected]>--- .../bindings/pci/hisilicon-histb-pcie.txt | 66 +++ drivers/pci/dwc/Kconfig | 10 + drivers/pci/dwc/Makefile | 1 + drivers/pci/dwc/pcie-histb.c | 469 +++++++++++++++++++++ 4 files changed, 546 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt create mode 100644 drivers/pci/dwc/pcie-histb.cDocumentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +48
-0@@ -0,0 +1,66 @@ +HiSilicon STB PCIe host bridge DT description + +HiSilicon STB PCIe host controller is based on Designware PCI core. +It shares common functions with PCIe Designware core driver and inherits +common properties defined in +Documentation/devicetree/bindings/pci/designware-pcie.txt. + +Additional properties are described here: + +Required properties +- compatible: Should be one of the following strings: + "hisilicon,hi3798cv200-pcie" +- reg: Should contain sysctl, rc_dbi, config registers location and length. +- reg-names: Must include the following entries: + "control": control registers of PCIe controller; + "rc-dbi": configuration space of PCIe controller; + "config": configuration transaction space of PCIe controller. +- bus-range: PCI bus numbers covered. +- interrupts: MSI interrupt. +- interrupt-names: Must include "msi" entries. +- clocks: List of phandle and clock specifier pairs as listed in clock-names + property. +- clock-name: Must include the following entries: + "aux": auxiliary gate clock; + "pipe": pipe gate clock; + "sys": sys gate clock; + "bus": bus gate clock. +- resets: List of phandle and reset specifier pairs as listed in reset-names + property. +- reset-names: Must include the following entries: + "soft": soft reset; + "sys": sys reset; + "bus": bus reset. + +Optional properties: +- reset-gpios: The gpio to generate PCIe PERST# assert and deassert signal. +- phys: List of phandle and phy mode specifier, should be 0. +- phy-names: Must be "phy". + +Example: + pcie at f9860000 { + compatible = "hisilicon,hi3798cv200-pcie"; + reg = <0xf9860000 0x1000>, + <0xf0000000 0x2000>, + <0xf2000000 0x01000000>; + reg-names = "control", "rc-dbi", "config"; + #address-cells = <3>; + #size-cells = <2>;
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt line 58
Quoted 10 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +10
-0+ device_type = "pci"; + bus-range = <0 15>; + num-lanes = <1>; + ranges=<0x81000000 0 0 0xf4000000 0 0x00010000 + 0x82000000 0 0xf3000000 0xf3000000 0 0x01000000>; + interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
I know this is just the example, but this looks wrong to me: this only covers INTA, so any multi-function devices that rely on legacy interrupts (such as Nvidia GFX cards with HDMI audio device that are blacklisted for MSI support) will fail to work. What I /think/ you need is:
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
Quoted 522 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +8
-0+ clocks = <&crg PCIE_AUX_CLK>, + <&crg PCIE_PIPE_CLK>, + <&crg PCIE_SYS_CLK>, + <&crg PCIE_BUS_CLK>; + clock-names = "aux", "pipe", "sys", "bus"; + resets = <&crg 0x18c 6>, <&crg 0x18c 5>, <&crg 0x18c 4>; + reset-names = "soft", "sys", "bus"; + };drivers/pci/dwc/Kconfig +10
-0@@ -169,4 +169,14 @@ config PCIE_KIRIN Say Y here if you want PCIe controller support on HiSilicon Kirin series SoCs. +config PCIE_HISI_STB + bool "HiSilicon STB SoCs PCIe controllers" + depends on ARCH_HISI + depends on PCI + depends on PCI_MSI_IRQ_DOMAIN + select PCIEPORTBUS + select PCIE_DW_HOST + help + Say Y here if you want PCIe controller support on HiSilicon STB SoCs + endmenudrivers/pci/dwc/Makefile +1
-0@@ -14,6 +14,7 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o +obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o # The following drivers are for devices that use the generic ACPI # pci_root.c driver but don't support standard ECAM config access.drivers/pci/dwc/pcie-histb.c new file +469
-1@@ -0,0 +1,469 @@ +/* +* PCIe host controller driver for HiSilicon STB SoCs +* +* Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com +* +* Authors: Jianguo Sun <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/pci.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/resource.h> +#include <linux/reset.h> + +#include "pcie-designware.h" + +#define to_histb_pcie (x) dev_get_drvdata((x)->dev) + +#define PCIE_SYS_CTRL0 0x0000 +#define PCIE_SYS_CTRL1 0x0004 +#define PCIE_SYS_CTRL7 0x001C +#define PCIE_SYS_CTRL13 0x0034 +#define PCIE_SYS_CTRL15 0x003c +#define PCIE_SYS_CTRL16 0x0040 +#define PCIE_SYS_CTRL17 0x0044 + +#define PCIE_SYS_STAT0 0x0100 +#define PCIE_SYS_STAT4 0x0110 + +#define PCIE_RDLH_LINK_UP BIT(5) +#define PCIE_XMLH_LINK_UP BIT(15) +#define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) +#define PCIE_APP_LTSSM_ENABLE BIT(11) + +#define PCIE_DEVICE_TYPE_MASK GENMASK(31, 28) +#define PCIE_WM_EP 0 +#define PCIE_WM_LEGACY BIT(1) +#define PCIE_WM_RC BIT(30) + +#define PCIE_LTSSM_STATE_MASK GENMASK(5, 0) +#define PCIE_LTSSM_STATE_ACTIVE 0x11 + +struct histb_pcie { +struct dw_pcie *pci; +struct clk *aux_clk; +struct clk *pipe_clk; +struct clk *sys_clk; +struct clk *bus_clk; +struct phy *phy; +struct reset_control *soft_reset; +struct reset_control *sys_reset; +struct reset_control *bus_reset; +void __iomem *ctrl; +int reset_gpio; +}; + +static u32 histb_pcie_readl (struct histb_pcie *histb_pcie,u32 reg) +{ +return readl (histb_pcie->ctrl + reg); +} + +static void histb_pcie_writel (struct histb_pcie *histb_pcie, +u32 reg,u32 val) +{ +writel (val, histb_pcie->ctrl + reg); +} + +static void histb_pcie_dbi_w_mode (struct pcie_port *pp,bool enable) +{ +struct dw_pcie *pci =to_dw_pcie_from_pp (pp); +struct histb_pcie *hipcie =to_histb_pcie (pci); +u32 val; + + val =histb_pcie_readl (hipcie,PCIE_SYS_CTRL0 ); +if (enable) + val |=PCIE_ELBI_SLV_DBI_ENABLE ; +else + val &= ~PCIE_ELBI_SLV_DBI_ENABLE ; +histb_pcie_writel (hipcie,PCIE_SYS_CTRL0 , val); +} + +static void histb_pcie_dbi_r_mode (struct pcie_port *pp,bool enable) +{ +struct dw_pcie *pci =to_dw_pcie_from_pp (pp); +struct histb_pcie *hipcie =to_histb_pcie (pci); +u32 val; + + val =histb_pcie_readl (hipcie,PCIE_SYS_CTRL1 ); +if (enable) + val |=PCIE_ELBI_SLV_DBI_ENABLE ; +else + val &= ~PCIE_ELBI_SLV_DBI_ENABLE ; +histb_pcie_writel (hipcie,PCIE_SYS_CTRL1 , val); +} + +static u32 histb_pcie_read_dbi (struct dw_pcie *pci,void __iomem *base, +u32 reg,size_t size) +{ +u32 val; + +histb_pcie_dbi_r_mode (&pci->pp, true); +dw_pcie_read (base + reg, size, &val); +histb_pcie_dbi_r_mode (&pci->pp, false); + +return val; +} + +static void histb_pcie_write_dbi (struct dw_pcie *pci,void __iomem *base, +u32 reg,size_t size,u32 val) +{ +histb_pcie_dbi_w_mode (&pci->pp, true); +dw_pcie_write (base + reg, size, val); +histb_pcie_dbi_w_mode (&pci->pp, false); +} + +static int histb_pcie_rd_own_conf (struct pcie_port *pp, +int where,int size,u32 *val) +{ +struct dw_pcie *pci =to_dw_pcie_from_pp (pp); +int ret; + +histb_pcie_dbi_r_mode (pp, true); + ret =dw_pcie_read (pci->dbi_base + where, size, val); +histb_pcie_dbi_r_mode (pp, false); + +return ret; +} + +static int histb_pcie_wr_own_conf (struct pcie_port *pp, +int where,int size,u32 val) +{ +struct dw_pcie *pci =to_dw_pcie_from_pp (pp); +int ret; + +histb_pcie_dbi_w_mode (pp, true); + ret =dw_pcie_write (pci->dbi_base + where, size, val); +histb_pcie_dbi_w_mode (pp, false); + +return ret; +} + +static int histb_pcie_link_up (struct dw_pcie *pci) +{ +struct histb_pcie *hipcie =to_histb_pcie (pci); +u32 regval; +u32 status; + + regval =histb_pcie_readl (hipcie,PCIE_SYS_STAT0 ); + status =histb_pcie_readl (hipcie,PCIE_SYS_STAT4 ); + status &=PCIE_LTSSM_STATE_MASK ; +if ((regval &PCIE_XMLH_LINK_UP ) && (regval &PCIE_RDLH_LINK_UP ) && + (status ==PCIE_LTSSM_STATE_ACTIVE )) +return 1 ; + +return 0 ; +} + +static int histb_pcie_establish_link (struct pcie_port *pp) +{ +struct dw_pcie *pci =to_dw_pcie_from_pp (pp); +struct histb_pcie *hipcie =to_histb_pcie (pci); +u32 regval; + +if (dw_pcie_link_up (pci)) { +dev_info (pci->dev,"Link already up\n" ); +return 0 ; + } + +/* PCIe RC work mode */ + regval =histb_pcie_readl (hipcie,PCIE_SYS_CTRL0 ); + regval &= ~PCIE_DEVICE_TYPE_MASK ; + regval |=PCIE_WM_RC ; +histb_pcie_writel (hipcie,PCIE_SYS_CTRL0 , regval); + +/* setup root complex */ +dw_pcie_setup_rc (pp); + +/* assert LTSSM enable */ + regval =histb_pcie_readl (hipcie,PCIE_SYS_CTRL7 ); + regval |=PCIE_APP_LTSSM_ENABLE ; +histb_pcie_writel (hipcie,PCIE_SYS_CTRL7 , regval); + +return dw_pcie_wait_for_link (pci); +} + +static int histb_pcie_host_init (struct pcie_port *pp) +{ +histb_pcie_establish_link (pp); + +if (IS_ENABLED (CONFIG_PCI_MSI )) +dw_pcie_msi_init (pp); + +return 0 ; +} + +static struct dw_pcie_host_ops histb_pcie_host_ops = { + .rd_own_conf = histb_pcie_rd_own_conf, + .wr_own_conf = histb_pcie_wr_own_conf, + .host_init = histb_pcie_host_init, +}; + +static irqreturn_t histb_pcie_msi_irq_handler (int irq,void *arg) +{ +struct pcie_port *pp = arg; + +return dw_handle_msi_irq (pp); +} + +static void histb_pcie_host_disable (struct histb_pcie *hipcie) +{ +reset_control_assert (hipcie->soft_reset); +reset_control_assert (hipcie->sys_reset); +reset_control_assert (hipcie->bus_reset); + +clk_disable_unprepare (hipcie->aux_clk); +clk_disable_unprepare (hipcie->pipe_clk); +clk_disable_unprepare (hipcie->sys_clk); +clk_disable_unprepare (hipcie->bus_clk); + +if (gpio_is_valid (hipcie->reset_gpio)) +gpio_set_value_cansleep (hipcie->reset_gpio,0 ); +} + +static int histb_pcie_host_enable (struct pcie_port *pp) +{ +struct dw_pcie *pci =to_dw_pcie_from_pp (pp); +struct histb_pcie *hipcie =to_histb_pcie (pci); +struct device *dev = pci->dev; +int ret; + +/* power on pcie device if have */ +if (gpio_is_valid (hipcie->reset_gpio)) +gpio_set_value_cansleep (hipcie->reset_gpio,1 ); + + ret =clk_prepare_enable (hipcie->bus_clk); +if (ret) { +dev_err (dev,"cannot prepare/enable bus clk\n" ); + goto err_bus_clk; + } + + ret =clk_prepare_enable (hipcie->sys_clk); +if (ret) { +dev_err (dev,"cannot prepare/enable sys clk\n" ); + goto err_sys_clk; + } + + ret =clk_prepare_enable (hipcie->pipe_clk); +if (ret) { +dev_err (dev,"cannot prepare/enable pipe clk\n" ); + goto err_pipe_clk; + } + + ret =clk_prepare_enable (hipcie->aux_clk); +if (ret) { +dev_err (dev,"cannot prepare/enable aux clk\n" ); + goto err_aux_clk; + } + +reset_control_assert (hipcie->soft_reset); +reset_control_deassert (hipcie->soft_reset); + +reset_control_assert (hipcie->sys_reset); +reset_control_deassert (hipcie->sys_reset); + +reset_control_assert (hipcie->bus_reset); +reset_control_deassert (hipcie->bus_reset); + +return 0 ; + +err_aux_clk: +clk_disable_unprepare (hipcie->aux_clk); +err_pipe_clk: +clk_disable_unprepare (hipcie->pipe_clk); +err_sys_clk: +clk_disable_unprepare (hipcie->sys_clk); +err_bus_clk: +clk_disable_unprepare (hipcie->bus_clk); + +return ret; +} + +static const struct dw_pcie_ops dw_pcie_ops = { + .read_dbi = histb_pcie_read_dbi, + .write_dbi = histb_pcie_write_dbi, + .link_up = histb_pcie_link_up, +}; + +static int histb_pcie_probe (struct platform_device *pdev) +{ +struct histb_pcie *hipcie; +struct dw_pcie *pci; +struct pcie_port *pp; +struct resource *res; +struct device_node *np = pdev->dev.of_node; +struct device *dev = &pdev->dev; +enum of_gpio_flags of_flags; +unsigned long flag =GPIOF_DIR_OUT ; +int ret; + + hipcie =devm_kzalloc (dev,sizeof (*hipcie),GFP_KERNEL ); +if (!hipcie) +return -ENOMEM ; + + pci =devm_kzalloc (dev,sizeof (*pci),GFP_KERNEL ); +if (!pci) +return -ENOMEM ; + + hipcie->pci = pci; + pp = &pci->pp; + pci->dev = dev; + pci->ops = &dw_pcie_ops; + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"control" ); + hipcie->ctrl =devm_ioremap_resource (dev, res); +if (IS_ERR (hipcie->ctrl)) { +dev_err (dev,"cannot get control reg base\n" ); +return PTR_ERR (hipcie->ctrl); + } + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"rc-dbi" ); + pci->dbi_base =devm_ioremap_resource (dev, res); +if (IS_ERR (pci->dbi_base)) { +dev_err (dev,"cannot get rc-dbi base\n" ); +return PTR_ERR (pci->dbi_base); + } + + hipcie->reset_gpio =of_get_named_gpio_flags (np, +"reset-gpios" ,0 , &of_flags); +if (of_flags &OF_GPIO_ACTIVE_LOW ) + flag |=GPIOF_ACTIVE_LOW ; +if (gpio_is_valid (hipcie->reset_gpio)) { + ret =devm_gpio_request_one (dev, hipcie->reset_gpio, + flag,"PCIe device power control" ); +if (ret) { +dev_err (dev,"unable to request gpio\n" ); +return ret; + } + } + + hipcie->aux_clk =devm_clk_get (dev,"aux" ); +if (IS_ERR (hipcie->aux_clk)) { +dev_err (dev,"Failed to get pcie aux clk\n" ); +return PTR_ERR (hipcie->aux_clk); + } + + hipcie->pipe_clk =devm_clk_get (dev,"pipe" ); +if (IS_ERR (hipcie->pipe_clk)) { +dev_err (dev,"Failed to get pcie pipe clk\n" ); +return PTR_ERR (hipcie->pipe_clk); + } + + hipcie->sys_clk =devm_clk_get (dev,"sys" ); +if (IS_ERR (hipcie->sys_clk)) { +dev_err (dev,"Failed to get pcie sys clk\n" ); +return PTR_ERR (hipcie->sys_clk); + } + + hipcie->bus_clk =devm_clk_get (dev,"bus" ); +if (IS_ERR (hipcie->bus_clk)) { +dev_err (dev,"Failed to get pcie bus clk\n" ); +return PTR_ERR (hipcie->bus_clk); + } + + hipcie->soft_reset =devm_reset_control_get (dev,"soft" ); +if (IS_ERR (hipcie->soft_reset)) { +dev_err (dev,"couldn't get soft reset\n" ); +return PTR_ERR (hipcie->soft_reset); + } + + hipcie->sys_reset =devm_reset_control_get (dev,"sys" ); +if (IS_ERR (hipcie->sys_reset)) { +dev_err (dev,"couldn't get sys reset\n" ); +return PTR_ERR (hipcie->sys_reset); + } + + hipcie->bus_reset =devm_reset_control_get (dev,"bus" ); +if (IS_ERR (hipcie->bus_reset)) { +dev_err (dev,"couldn't get bus reset\n" ); +return PTR_ERR (hipcie->bus_reset); + } + +if (IS_ENABLED (CONFIG_PCI_MSI )) { + pp->msi_irq =platform_get_irq_byname (pdev,"msi" ); +if (pp->msi_irq <0 ) { +dev_err (dev,"Failed to get msi irq\n" ); +return pp->msi_irq; + } + + ret =devm_request_irq (dev, pp->msi_irq, + histb_pcie_msi_irq_handler, +IRQF_SHARED ,"histb-pcie-msi" , pp); +if (ret) { +dev_err (dev,"cannot request msi irq\n" ); +return ret; + } + } + + hipcie->phy =devm_phy_get (dev,"phy" ); +if (IS_ERR (hipcie->phy)) { +dev_info (dev,"no pcie-phy found\n" ); + hipcie->phy =NULL ; +/* fall through here! +* if no pcie-phy found, phy init +* should be done under boot! +*/ + }else { +phy_init (hipcie->phy); + } + + pp->root_bus_nr =-1 ; + pp->ops = &histb_pcie_host_ops; + +platform_set_drvdata (pdev, hipcie); + + ret =histb_pcie_host_enable (pp); +if (ret) { +dev_err (dev,"failed to enable host\n" ); +return ret; + } + + ret =dw_pcie_host_init (pp); +if (ret) { +dev_err (dev,"failed to initialize host\n" ); +return ret; + } + +return 0 ; +} + +static int histb_pcie_remove (struct platform_device *pdev) +{ +struct histb_pcie *hipcie =platform_get_drvdata (pdev); + +histb_pcie_host_disable (hipcie); + +if (hipcie->phy) +phy_exit (hipcie->phy); + +return 0 ; +} + +static const struct of_device_id histb_pcie_of_match[] = { + { .compatible ="hisilicon,hi3798cv200-pcie" , }, + {}, +}; +MODULE_DEVICE_TABLE (of, histb_pcie_of_match); + +static struct platform_driver histb_pcie_platform_driver = { + .probe = histb_pcie_probe, + .remove = histb_pcie_remove, + .driver = { + .name ="histb-pcie" , + .of_match_table = histb_pcie_of_match, + }, +}; +module_platform_driver (histb_pcie_platform_driver); + +MODULE_DESCRIPTION ("HiSilicon STB PCIe host controller driver" ); +MODULE_LICENSE ("GPL v2" ); --1.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Shawn Guo
maintainerPATCH 1/1 PCI: hisi: add PCIe driver support for HiSilicon STB SoCs
Hi Ard,
Quoted 20 lines · Ard Biesheuvel
Quoted 9 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +9
-0+Example: + pcie at f9860000 { + compatible = "hisilicon,hi3798cv200-pcie"; + reg = <0xf9860000 0x1000>, + <0xf0000000 0x2000>, + <0xf2000000 0x01000000>; + reg-names = "control", "rc-dbi", "config"; + #address-cells = <3>; + #size-cells = <2>;Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt line 58
Quoted 10 lines
Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt new file +10
-0+ device_type = "pci"; + bus-range = <0 15>; + num-lanes = <1>; + ranges=<0x81000000 0 0 0xf4000000 0 0x00010000 + 0x82000000 0 0xf3000000 0xf3000000 0 0x01000000>; + interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
Quoted 8 lines
I know this is just the example, but this looks wrong to me: this only covers INTA, so any multi-function devices that rely on legacy interrupts (such as Nvidia GFX cards with HDMI audio device that are blacklisted for MSI support) will fail to work. What I /think/ you need is:
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gicGIC_SPI131IRQ_TYPE_LEVEL_HIGH>;
I really appreciate the comment. Yes, all 4 legacy interrupts should be mapped to this IRQ. I will get it fixed. Thanks again.
Shawn