Message ID | 1409856338-1730-2-git-send-email-Minghuan.Lian@freescale.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
On Thursday 04 September 2014 18:45:38 Minghuan Lian wrote: > + > +#define PCIE_LS1021A_BASE 0x3400000 > +#define PCIE_LS1021A_REG_SIZE 0x0100000 This does not belong here. All addresses must come from DT, and you should not do the calculation below based on the address. > +struct ls_pcie { > + struct list_head node; > + struct device *dev; > + struct pci_bus *bus; > + void __iomem *dbi; > + void __iomem *scfg; > + struct pcie_port pp; > + int id; > + int index; > + int irq; > + int msi_irq; > + int pme_irq; > +}; irq and pme_irq seem to be completely unused, so better not add them until they are actually used. The scfg registers seem to belong to another device that is responsible for multiple instances. Unfortunately, this "fsl,ls1021a-scfg" device is not documented anywhere that I can see. Is this some sort of syscon node, or is it specific to the pcie controller(s)? > +static LIST_HEAD(ls_pcie_list); Don't maintain your own lists please. > +static int ls_pcie_link_up(struct pcie_port *pp) > +{ > + u32 rc, tmp; > + struct ls_pcie *pcie = to_ls_pcie(pp); > + > + tmp = ioread32(pcie->scfg + SCFG_SCFGREVCR_OFF); > + iowrite32(SCFG_NO_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); > + > + rc = (ioread32(pcie->scfg + PEXMSCPORTSR(pcie->index)) >> > + LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; > + > + iowrite32(tmp, pcie->scfg + SCFG_SCFGREVCR_OFF); > + > + if (rc < LTSSM_PCIE_L0) > + return 0; > + > + return 1; > +} This looks like it is really a phy driver, although a pretty minimal one. > +static u32 ls_pcie_get_msi_addr(struct pcie_port *pp) > +{ > + return SCFG_SPIMSICR_ADDR; > +} > + > +static u32 ls_pcie_get_msi_data(struct pcie_port *pp, int pos) > +{ > + struct ls_pcie *pcie = to_ls_pcie(pp); > + > + if (pcie->id == PCI_DEVICE_ID_LS1021A) > + return MSI_LS1021A_DATA(pcie->index); > + > + return pos; > +} My impression is that you have two distinct MSI controller implementations, one for LS1021A and the other one for everything else. How about using separate pcie_host_ops for them, possibly also moving them into separate files? A good way to deal with this is to put the pointers to the two pcie_host_ops into the data fields of the ls_pcie_of_match table. > +/* Freescale PCIe driver does not allow module unload */ > +static int __init ls_pcie_init(void) > +{ > + return platform_driver_probe(&ls_pcie_driver, ls_pcie_probe); > +} > +subsys_initcall(ls_pcie_init); Better change to platform_driver_register, so you can use deferred probing. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Sep 4, 2014 at 12:45 PM, Minghuan Lian <Minghuan.Lian@freescale.com> wrote: > Add support for Freescale Layerscape PCIe controller. This driver > re-uses the designware core code. > > Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com> > --- > .../devicetree/bindings/pci/fsl,ls-pcie.txt | 41 +++ > drivers/pci/host/Kconfig | 7 + > drivers/pci/host/Makefile | 1 + > drivers/pci/host/pci-layerscape.c | 315 +++++++++++++++++++++ > include/linux/pci_ids.h | 1 + > 5 files changed, 365 insertions(+) > create mode 100644 Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt > create mode 100644 drivers/pci/host/pci-layerscape.c > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h > index 6ed0bb7..26d4c30 100644 > --- a/include/linux/pci_ids.h > +++ b/include/linux/pci_ids.h > @@ -2442,6 +2442,7 @@ > #define PCI_DEVICE_ID_P5020 0x0421 > #define PCI_DEVICE_ID_P5010E 0x0428 > #define PCI_DEVICE_ID_P5010 0x0429 > +#define PCI_DEVICE_ID_LS1021A 0x0e0b This is only used in one file and should not be in pci_ids.h (per the comment at the top of pci_ids.h). > #define PCI_DEVICE_ID_MPC8641 0x7010 > #define PCI_DEVICE_ID_MPC8641D 0x7011 > #define PCI_DEVICE_ID_MPC8610 0x7018 > -- > 1.9.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-pci" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thursday 04 September 2014 14:14:48 Arnd Bergmann wrote: > > My impression is that you have two distinct MSI controller > implementations, one for LS1021A and the other one for everything > else. How about using separate pcie_host_ops for them, possibly > also moving them into separate files? > One more thing: you should really use the msi-parent property to find the MSI controller: Sooner or later this PCI block is likely to end up in a real product that has GICv2m or GICv3 support, so you will have to pick which of the two MSI controllers to use. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thursday 04 September 2014 15:51:22 Arnd Bergmann wrote: > On Thursday 04 September 2014 14:14:48 Arnd Bergmann wrote: > > > > My impression is that you have two distinct MSI controller > > implementations, one for LS1021A and the other one for everything > > else. How about using separate pcie_host_ops for them, possibly > > also moving them into separate files? > > > > One more thing: you should really use the msi-parent property to > find the MSI controller: Sooner or later this PCI block is likely > to end up in a real product that has GICv2m or GICv3 support, so > you will have to pick which of the two MSI controllers to use. Ah, I missed the fact that LS1021A is a real product already, I was confusing it with the LS2085A patches that are also on the list at the moment and that only work in a simulator at present. Note that LS2085A does have GICv3. I don't know if it has a similar PCIe implementation, but if it does, the DT representation should definitely provide a way to pick the MSI controller (you will always want the GIC in practice). Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Sep 4, 2014 at 3:45 PM, Minghuan Lian <Minghuan.Lian@freescale.com> wrote: > Add support for Freescale Layerscape PCIe controller. This driver > re-uses the designware core code. It seems that this is the same IP as on mx6, right? Is it possible to adapt drivers/pci/host/pci-imx6.c to work on Layerscape? > +#define PCIE_LS1021A_BASE 0x3400000 > +#define PCIE_LS1021A_REG_SIZE 0x0100000 You should retrieve base and reg size from the dtsi file. -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thursday 04 September 2014 17:21:48 Fabio Estevam wrote: > On Thu, Sep 4, 2014 at 3:45 PM, Minghuan Lian > <Minghuan.Lian@freescale.com> wrote: > > Add support for Freescale Layerscape PCIe controller. This driver > > re-uses the designware core code. > > It seems that this is the same IP as on mx6, right? > > Is it possible to adapt drivers/pci/host/pci-imx6.c to work on Layerscape? For all I can tell, the common parts are already shared in pcie-designware.c, while the new file contains only those parts that are specific to layerscape and different from imx. If there are parts in there that are the same between layerscape and imx, the implementation should also be moved to a shared file. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Friday 05 September 2014 07:22:08 Minghuan.Lian@freescale.com wrote: > Hi Arnd, > > Please see my comments inline. Please use the usual reply style in the future, using '>' characters to properly give attribution. I'm fixing this up manually in my reply here, so others can follow the discussion. > > On Thursday 04 September 2014 18:45:38 Minghuan Lian wrote: > > > + > > > +#define PCIE_LS1021A_BASE 0x3400000 > > > +#define PCIE_LS1021A_REG_SIZE 0x0100000 > > > > This does not belong here. All addresses must come from DT, > > and you should not do the calculation below based on the address. > [Minghuan] LS1021A contains two PCI controllers. I use them to > calculation the PCI controller index. > There are several separate registers for PEX1 and PEX2 in SCFG > register space. It is hard to get them address from DTS. Could > you tell me a way to get PCI controller index? The easiest way would be to put the index as a property in the device tree itself. > > +struct ls_pcie { > > + struct list_head node; > > + struct device *dev; > > + struct pci_bus *bus; > > + void __iomem *dbi; > > + void __iomem *scfg; > > + struct pcie_port pp; > > + int id; > > + int index; > > + int irq; > > + int msi_irq; > > + int pme_irq; > > +}; > > irq and pme_irq seem to be completely unused, so better > not add them until they are actually used. > [Minghuan] Ok, I will remove them. > > The scfg registers seem to belong to another device that > is responsible for multiple instances. Unfortunately, > this "fsl,ls1021a-scfg" device is not documented anywhere > that I can see. > > Is this some sort of syscon node, or is it specific to the > pcie controller(s)? > > [Minghaun] SCFG provides SoC specific configuration and status > registers for the device including PCI USB eTSEC SATA ... > The platform patches that contains SCFG code are being upstream. This sounds like it should be a syscon node, and you should use syscon_regmap_lookup_by_phandle() to find the scfg node from each of those drivers, rather than scanning the DT yourself in each of the drivers using it. This can also be a place to put the index, such as scfg = <&scfg 0>; for the first PCIe node. The probe function then extracts both the phandle for the syscon and the index from that property. > > +static int ls_pcie_link_up(struct pcie_port *pp) > > +{ > > + u32 rc, tmp; > > + struct ls_pcie *pcie = to_ls_pcie(pp); > > + > > + tmp = ioread32(pcie->scfg + SCFG_SCFGREVCR_OFF); > > + iowrite32(SCFG_NO_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); > > + > > + rc = (ioread32(pcie->scfg + PEXMSCPORTSR(pcie->index)) >> > > + LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; > > + > > + iowrite32(tmp, pcie->scfg + SCFG_SCFGREVCR_OFF); > > + > > + if (rc < LTSSM_PCIE_L0) > > + return 0; > > + > > + return 1; > > +} > > This looks like it is really a phy driver, although a pretty minimal > one. > > [Minghuan] I read SCFG register. SCFG provides SoC specific configuration > and status registers for the device including PCI USB eTSEC SATA ... I'm guessing that a lot of that is phy related information though. A nicer way to deal with this, compared to using syscon directly is to have a phy driver for your chip, and have that deal with all the phy related setup. In this case you would have a reference in the client driver like phys = <&scfgphy LS1021A_PHY_PCIE0>; phy-names = "pcie"; And in the pcie driver you just call devm_phy_get(dev, "pcie") to get a reference to that phy node, and then you can use the phy API to perform actions on it (init, power_on, power_off, exit). This keeps all knowledge about the phy registers inside of the scfg area in one place, and you only have to add a new phy driver for a future SoC that has the same PCIe core but different scfg. > > +static u32 ls_pcie_get_msi_addr(struct pcie_port *pp) > > +{ > > + return SCFG_SPIMSICR_ADDR; > > +} > > + > > +static u32 ls_pcie_get_msi_data(struct pcie_port *pp, int pos) > > +{ > > + struct ls_pcie *pcie = to_ls_pcie(pp); > > + > > + if (pcie->id == PCI_DEVICE_ID_LS1021A) > > + return MSI_LS1021A_DATA(pcie->index); > > + > > + return pos; > > +} > > My impression is that you have two distinct MSI controller > implementations, one for LS1021A and the other one for everything > else. How about using separate pcie_host_ops for them, possibly > also moving them into separate files? > > A good way to deal with this is to put the pointers to the two > pcie_host_ops into the data fields of the ls_pcie_of_match table. > > [Minghuan] LS1021 contains the same two PCI controllers PEX1 and PEX2. > both PEX1 and PEX use the same MSI address, but different MSI message data. I mean LS1021 is different from other chips here, since you compare the pcie->id value. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tuesday 09 September 2014 17:25:57 Lian Minghuan-B31939 wrote: > On 2014?09?05? 08:44, Arnd Bergmann wrote: > > On Friday 05 September 2014 07:22:08 Minghuan.Lian@freescale.com wrote: > >>> +struct ls_pcie { > >>> + struct list_head node; > >>> + struct device *dev; > >>> + struct pci_bus *bus; > >>> + void __iomem *dbi; > >>> + void __iomem *scfg; > >>> + struct pcie_port pp; > >>> + int id; > >>> + int index; > >>> + int irq; > >>> + int msi_irq; > >>> + int pme_irq; > >>> +}; > >> irq and pme_irq seem to be completely unused, so better > >> not add them until they are actually used. > >> [Minghuan] Ok, I will remove them. > >> > >> The scfg registers seem to belong to another device that > >> is responsible for multiple instances. Unfortunately, > >> this "fsl,ls1021a-scfg" device is not documented anywhere > >> that I can see. > >> > >> Is this some sort of syscon node, or is it specific to the > >> pcie controller(s)? > >> > >> [Minghaun] SCFG provides SoC specific configuration and status > >> registers for the device including PCI USB eTSEC SATA ... > >> The platform patches that contains SCFG code are being upstream. > > This sounds like it should be a syscon node, and you should use > > syscon_regmap_lookup_by_phandle() to find the scfg node from each > > of those drivers, rather than scanning the DT yourself in each > > of the drivers using it. > > > > This can also be a place to put the index, such as > > > > scfg = <&scfg 0>; > > > > for the first PCIe node. The probe function then extracts both > > the phandle for the syscon and the index from that property. > [Minghuan] I discussed with my colleague. They worry about performance > degradation if using regmap API, > because there are some fast device use scfg. We tend to use a simple way > to map andread/write scfg directly. I see. In this case, I would probably create a separate msi controller driver that owns the "fsl,ls1021a-scfg" device, and is referenced through the "msi-parent" property in the pcie controller. You can use of_pci_find_msi_chip_by_node() to get the msi_chip instance and then connect that to your pci host. This will also take care of the case where you may want to use the main GICv3 on a future SoC. > >>> +static int ls_pcie_link_up(struct pcie_port *pp) > >>> +{ > >>> + u32 rc, tmp; > >>> + struct ls_pcie *pcie = to_ls_pcie(pp); > >>> + > >>> + tmp = ioread32(pcie->scfg + SCFG_SCFGREVCR_OFF); > >>> + iowrite32(SCFG_NO_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); > >>> + > >>> + rc = (ioread32(pcie->scfg + PEXMSCPORTSR(pcie->index)) >> > >>> + LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; > >>> + > >>> + iowrite32(tmp, pcie->scfg + SCFG_SCFGREVCR_OFF); > >>> + > >>> + if (rc < LTSSM_PCIE_L0) > >>> + return 0; > >>> + > >>> + return 1; > >>> +} > >> This looks like it is really a phy driver, although a pretty minimal > >> one. > >> > >> [Minghuan] I read SCFG register. SCFG provides SoC specific configuration > >> and status registers for the device including PCI USB eTSEC SATA ... > > I'm guessing that a lot of that is phy related information though. > > A nicer way to deal with this, compared to using syscon directly is > > to have a phy driver for your chip, and have that deal with all > > the phy related setup. In this case you would have a reference in > > the client driver like > > > > phys = <&scfgphy LS1021A_PHY_PCIE0>; > > phy-names = "pcie"; > > > > And in the pcie driver you just call devm_phy_get(dev, "pcie") to get a reference > > to that phy node, and then you can use the phy API to perform actions on > > it (init, power_on, power_off, exit). > > > > This keeps all knowledge about the phy registers inside of the scfg area > > in one place, and you only have to add a new phy driver for a future SoC > > that has the same PCIe core but different scfg. > [Minghuan] SCFG does not contains power_on power_off or other PCI > control registers. > We only get link up and MSI related status via SCFG. So I think it is > not enough to call scfg PCIe phy. Ok, then use syscon for this one. Note that we are currently changing the syscon code to make it easier for the same device to be both syscon and driven by another device driver such as the msi_chip above. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tuesday 09 September 2014 18:46:59 Lian Minghuan-B31939 wrote: > On 2014?09?09? 09:56, Arnd Bergmann wrote: > > On Tuesday 09 September 2014 17:25:57 Lian Minghuan-B31939 wrote: > >> [Minghuan] I discussed with my colleague. They worry about performance > >> degradation if using regmap API, > >> because there are some fast device use scfg. We tend to use a simple way > >> to map andread/write scfg directly. > > > > I see. In this case, I would probably create a separate msi controller > > driver that owns the "fsl,ls1021a-scfg" device, and is referenced > > through the "msi-parent" property in the pcie controller. > > > > You can use of_pci_find_msi_chip_by_node() to get the msi_chip > > instance and then connect that to your pci host. This will also > > take care of the case where you may want to use the main GICv3 > > > on a future SoC. > [Minghuan] There is something wrong with LS1021A MSI hardware that it > only supports one interrupt not 32 interrupts. Now, I do not want to > create a separate msi controller driver just for incorrect hardware. > I may provide complete MSI driver for the new hardware when it is ready. Would you just leave out MSI support for the LS1021A PCIe variant? I guess that's fine because all device drivers should also support legacy interrupts and there is no performance gain in MSI in this case. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tuesday 09 September 2014 19:16:01 Lian Minghuan-B31939 wrote: > On 2014?09?09? 10:50, Arnd Bergmann wrote: > > On Tuesday 09 September 2014 18:46:59 Lian Minghuan-B31939 wrote: > >> On 2014?09?09? 09:56, Arnd Bergmann wrote: > >>> On Tuesday 09 September 2014 17:25:57 Lian Minghuan-B31939 wrote: > >>>> [Minghuan] I discussed with my colleague. They worry about performance > >>>> degradation if using regmap API, > >>>> because there are some fast device use scfg. We tend to use a simple way > >>>> to map andread/write scfg directly. > >>> I see. In this case, I would probably create a separate msi controller > >>> driver that owns the "fsl,ls1021a-scfg" device, and is referenced > >>> through the "msi-parent" property in the pcie controller. > >>> > >>> You can use of_pci_find_msi_chip_by_node() to get the msi_chip > >>> instance and then connect that to your pci host. This will also > >>> take care of the case where you may want to use the main GICv3 > >>> on a future SoC. > >> > >> [Minghuan] There is something wrong with LS1021A MSI hardware that it > >> only supports one interrupt not 32 interrupts. Now, I do not want to > >> create a separate msi controller driver just for incorrect hardware. > >> I may provide complete MSI driver for the new hardware when it is ready. > > > > Would you just leave out MSI support for the LS1021A PCIe variant? > > I guess that's fine because all device drivers should also support > > legacy interrupts and there is no performance gain in MSI in this > > case. > > [Minghuan] I have added MSI support for LS1021A PCIe just reserved 31 > interrupts as used. I don't understand your logic then. If LS1021A has an incorrect MSI implementation, and you may want to reuse the PCIe driver with a future chip that either includes a correct MSI implementation, or with one that uses the GICv3 instead, isn't that even more reason to split out the MSI support into a separate driver? That way you can at least separate the normal code path from the broken one and don't need any special run-time or compile-conditionals beyond calling of_pci_find_msi_chip_by_node(). Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Arnd, I am sorry for missed reply style and thank you very much for fixing it. please see my comments inline. Thanks, Minghuan On 2014?09?05? 08:44, Arnd Bergmann wrote: > On Friday 05 September 2014 07:22:08 Minghuan.Lian@freescale.com wrote: >> Hi Arnd, >> >> Please see my comments inline. > Please use the usual reply style in the future, using '>' characters to > properly give attribution. I'm fixing this up manually in my reply > here, so others can follow the discussion. > >>> On Thursday 04 September 2014 18:45:38 Minghuan Lian wrote: >>>> + >>>> +#define PCIE_LS1021A_BASE 0x3400000 >>>> +#define PCIE_LS1021A_REG_SIZE 0x0100000 >>> This does not belong here. All addresses must come from DT, >>> and you should not do the calculation below based on the address. >> [Minghuan] LS1021A contains two PCI controllers. I use them to >> calculation the PCI controller index. >> There are several separate registers for PEX1 and PEX2 in SCFG >> register space. It is hard to get them address from DTS. Could >> you tell me a way to get PCI controller index? > The easiest way would be to put the index as a property in the > device tree itself. [Minghuan] I want to use scfg = <&scfg 0> you mentioned below. >>> +struct ls_pcie { >>> + struct list_head node; >>> + struct device *dev; >>> + struct pci_bus *bus; >>> + void __iomem *dbi; >>> + void __iomem *scfg; >>> + struct pcie_port pp; >>> + int id; >>> + int index; >>> + int irq; >>> + int msi_irq; >>> + int pme_irq; >>> +}; >> irq and pme_irq seem to be completely unused, so better >> not add them until they are actually used. >> [Minghuan] Ok, I will remove them. >> >> The scfg registers seem to belong to another device that >> is responsible for multiple instances. Unfortunately, >> this "fsl,ls1021a-scfg" device is not documented anywhere >> that I can see. >> >> Is this some sort of syscon node, or is it specific to the >> pcie controller(s)? >> >> [Minghaun] SCFG provides SoC specific configuration and status >> registers for the device including PCI USB eTSEC SATA ... >> The platform patches that contains SCFG code are being upstream. > This sounds like it should be a syscon node, and you should use > syscon_regmap_lookup_by_phandle() to find the scfg node from each > of those drivers, rather than scanning the DT yourself in each > of the drivers using it. > > This can also be a place to put the index, such as > > scfg = <&scfg 0>; > > for the first PCIe node. The probe function then extracts both > the phandle for the syscon and the index from that property. [Minghuan] I discussed with my colleague. They worry about performance degradation if using regmap API, because there are some fast device use scfg. We tend to use a simple way to map andread/write scfg directly. >>> +static int ls_pcie_link_up(struct pcie_port *pp) >>> +{ >>> + u32 rc, tmp; >>> + struct ls_pcie *pcie = to_ls_pcie(pp); >>> + >>> + tmp = ioread32(pcie->scfg + SCFG_SCFGREVCR_OFF); >>> + iowrite32(SCFG_NO_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); >>> + >>> + rc = (ioread32(pcie->scfg + PEXMSCPORTSR(pcie->index)) >> >>> + LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; >>> + >>> + iowrite32(tmp, pcie->scfg + SCFG_SCFGREVCR_OFF); >>> + >>> + if (rc < LTSSM_PCIE_L0) >>> + return 0; >>> + >>> + return 1; >>> +} >> This looks like it is really a phy driver, although a pretty minimal >> one. >> >> [Minghuan] I read SCFG register. SCFG provides SoC specific configuration >> and status registers for the device including PCI USB eTSEC SATA ... > I'm guessing that a lot of that is phy related information though. > A nicer way to deal with this, compared to using syscon directly is > to have a phy driver for your chip, and have that deal with all > the phy related setup. In this case you would have a reference in > the client driver like > > phys = <&scfgphy LS1021A_PHY_PCIE0>; > phy-names = "pcie"; > > And in the pcie driver you just call devm_phy_get(dev, "pcie") to get a reference > to that phy node, and then you can use the phy API to perform actions on > it (init, power_on, power_off, exit). > > This keeps all knowledge about the phy registers inside of the scfg area > in one place, and you only have to add a new phy driver for a future SoC > that has the same PCIe core but different scfg. [Minghuan] SCFG does not contains power_on power_off or other PCI control registers. We only get link up and MSI related status via SCFG. So I think it is not enough to call scfg PCIe phy. >>> +static u32 ls_pcie_get_msi_addr(struct pcie_port *pp) >>> +{ >>> + return SCFG_SPIMSICR_ADDR; >>> +} >>> + >>> +static u32 ls_pcie_get_msi_data(struct pcie_port *pp, int pos) >>> +{ >>> + struct ls_pcie *pcie = to_ls_pcie(pp); >>> + >>> + if (pcie->id == PCI_DEVICE_ID_LS1021A) >>> + return MSI_LS1021A_DATA(pcie->index); >>> + >>> + return pos; >>> +} >> My impression is that you have two distinct MSI controller >> implementations, one for LS1021A and the other one for everything >> else. How about using separate pcie_host_ops for them, possibly >> also moving them into separate files? >> >> A good way to deal with this is to put the pointers to the two >> pcie_host_ops into the data fields of the ls_pcie_of_match table. >> >> [Minghuan] LS1021 contains the same two PCI controllers PEX1 and PEX2. >> both PEX1 and PEX use the same MSI address, but different MSI message data. > I mean LS1021 is different from other chips here, since you compare > the pcie->id value. [Minghuan] I see. I will change it. > Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Arnd, please see my comments inline. On 2014?09?09? 09:56, Arnd Bergmann wrote: > On Tuesday 09 September 2014 17:25:57 Lian Minghuan-B31939 wrote: >> On 2014?09?05? 08:44, Arnd Bergmann wrote: >>> On Friday 05 September 2014 07:22:08 Minghuan.Lian@freescale.com wrote: >>>>> +struct ls_pcie { >>>>> + struct list_head node; >>>>> + struct device *dev; >>>>> + struct pci_bus *bus; >>>>> + void __iomem *dbi; >>>>> + void __iomem *scfg; >>>>> + struct pcie_port pp; >>>>> + int id; >>>>> + int index; >>>>> + int irq; >>>>> + int msi_irq; >>>>> + int pme_irq; >>>>> +}; >>>> irq and pme_irq seem to be completely unused, so better >>>> not add them until they are actually used. >>>> [Minghuan] Ok, I will remove them. >>>> >>>> The scfg registers seem to belong to another device that >>>> is responsible for multiple instances. Unfortunately, >>>> this "fsl,ls1021a-scfg" device is not documented anywhere >>>> that I can see. >>>> >>>> Is this some sort of syscon node, or is it specific to the >>>> pcie controller(s)? >>>> >>>> [Minghaun] SCFG provides SoC specific configuration and status >>>> registers for the device including PCI USB eTSEC SATA ... >>>> The platform patches that contains SCFG code are being upstream. >>> This sounds like it should be a syscon node, and you should use >>> syscon_regmap_lookup_by_phandle() to find the scfg node from each >>> of those drivers, rather than scanning the DT yourself in each >>> of the drivers using it. >>> >>> This can also be a place to put the index, such as >>> >>> scfg = <&scfg 0>; >>> >>> for the first PCIe node. The probe function then extracts both >>> the phandle for the syscon and the index from that property. >> [Minghuan] I discussed with my colleague. They worry about performance >> degradation if using regmap API, >> because there are some fast device use scfg. We tend to use a simple way >> to map andread/write scfg directly. > I see. In this case, I would probably create a separate msi controller > driver that owns the "fsl,ls1021a-scfg" device, and is referenced > through the "msi-parent" property in the pcie controller. > > You can use of_pci_find_msi_chip_by_node() to get the msi_chip > instance and then connect that to your pci host. This will also > take care of the case where you may want to use the main GICv3 > on a future SoC. [Minghuan] There is something wrong with LS1021A MSI hardware that it only supports one interrupt not 32 interrupts. Now, I do not want to create a separate msi controller driver just for incorrect hardware. I may provide complete MSI driver for the new hardware when it is ready. >>>>> +static int ls_pcie_link_up(struct pcie_port *pp) >>>>> +{ >>>>> + u32 rc, tmp; >>>>> + struct ls_pcie *pcie = to_ls_pcie(pp); >>>>> + >>>>> + tmp = ioread32(pcie->scfg + SCFG_SCFGREVCR_OFF); >>>>> + iowrite32(SCFG_NO_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); >>>>> + >>>>> + rc = (ioread32(pcie->scfg + PEXMSCPORTSR(pcie->index)) >> >>>>> + LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; >>>>> + >>>>> + iowrite32(tmp, pcie->scfg + SCFG_SCFGREVCR_OFF); >>>>> + >>>>> + if (rc < LTSSM_PCIE_L0) >>>>> + return 0; >>>>> + >>>>> + return 1; >>>>> +} >>>> This looks like it is really a phy driver, although a pretty minimal >>>> one. >>>> >>>> [Minghuan] I read SCFG register. SCFG provides SoC specific configuration >>>> and status registers for the device including PCI USB eTSEC SATA ... >>> I'm guessing that a lot of that is phy related information though. >>> A nicer way to deal with this, compared to using syscon directly is >>> to have a phy driver for your chip, and have that deal with all >>> the phy related setup. In this case you would have a reference in >>> the client driver like >>> >>> phys = <&scfgphy LS1021A_PHY_PCIE0>; >>> phy-names = "pcie"; >>> >>> And in the pcie driver you just call devm_phy_get(dev, "pcie") to get a reference >>> to that phy node, and then you can use the phy API to perform actions on >>> it (init, power_on, power_off, exit). >>> >>> This keeps all knowledge about the phy registers inside of the scfg area >>> in one place, and you only have to add a new phy driver for a future SoC >>> that has the same PCIe core but different scfg. >> [Minghuan] SCFG does not contains power_on power_off or other PCI >> control registers. >> We only get link up and MSI related status via SCFG. So I think it is >> not enough to call scfg PCIe phy. > Ok, then use syscon for this one. Note that we are currently changing > the syscon code to make it easier for the same device to be both syscon > and driven by another device driver such as the msi_chip above. [Minghuan] I will try > Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 2014?09?09? 10:50, Arnd Bergmann wrote: > On Tuesday 09 September 2014 18:46:59 Lian Minghuan-B31939 wrote: >> On 2014?09?09? 09:56, Arnd Bergmann wrote: >>> On Tuesday 09 September 2014 17:25:57 Lian Minghuan-B31939 wrote: >>>> [Minghuan] I discussed with my colleague. They worry about performance >>>> degradation if using regmap API, >>>> because there are some fast device use scfg. We tend to use a simple way >>>> to map andread/write scfg directly. >>> I see. In this case, I would probably create a separate msi controller >>> driver that owns the "fsl,ls1021a-scfg" device, and is referenced >>> through the "msi-parent" property in the pcie controller. >>> >>> You can use of_pci_find_msi_chip_by_node() to get the msi_chip >>> instance and then connect that to your pci host. This will also >>> take care of the case where you may want to use the main GICv3 >>> on a future SoC. >> [Minghuan] There is something wrong with LS1021A MSI hardware that it >> only supports one interrupt not 32 interrupts. Now, I do not want to >> create a separate msi controller driver just for incorrect hardware. >> I may provide complete MSI driver for the new hardware when it is ready. > Would you just leave out MSI support for the LS1021A PCIe variant? > I guess that's fine because all device drivers should also support > legacy interrupts and there is no performance gain in MSI in this > case. [Minghuan] I have added MSI support for LS1021A PCIe just reserved 31 interrupts as used. > Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Arnd, On 2014?09?09? 11:58, Arnd Bergmann wrote: > On Tuesday 09 September 2014 19:16:01 Lian Minghuan-B31939 wrote: >> On 2014?09?09? 10:50, Arnd Bergmann wrote: >>> On Tuesday 09 September 2014 18:46:59 Lian Minghuan-B31939 wrote: >>>> On 2014?09?09? 09:56, Arnd Bergmann wrote: >>>>> On Tuesday 09 September 2014 17:25:57 Lian Minghuan-B31939 wrote: >>>>>> [Minghuan] I discussed with my colleague. They worry about performance >>>>>> degradation if using regmap API, >>>>>> because there are some fast device use scfg. We tend to use a simple way >>>>>> to map andread/write scfg directly. >>>>> I see. In this case, I would probably create a separate msi controller >>>>> driver that owns the "fsl,ls1021a-scfg" device, and is referenced >>>>> through the "msi-parent" property in the pcie controller. >>>>> >>>>> You can use of_pci_find_msi_chip_by_node() to get the msi_chip >>>>> instance and then connect that to your pci host. This will also >>>>> take care of the case where you may want to use the main GICv3 >>>>> on a future SoC. >>>> [Minghuan] There is something wrong with LS1021A MSI hardware that it >>>> only supports one interrupt not 32 interrupts. Now, I do not want to >>>> create a separate msi controller driver just for incorrect hardware. >>>> I may provide complete MSI driver for the new hardware when it is ready. >>> Would you just leave out MSI support for the LS1021A PCIe variant? >>> I guess that's fine because all device drivers should also support >>> legacy interrupts and there is no performance gain in MSI in this >>> case. >> [Minghuan] I have added MSI support for LS1021A PCIe just reserved 31 >> interrupts as used. > I don't understand your logic then. If LS1021A has an incorrect MSI > implementation, and you may want to reuse the PCIe driver with a > future chip that either includes a correct MSI implementation, or > with one that uses the GICv3 instead, isn't that even more reason > to split out the MSI support into a separate driver? > > That way you can at least separate the normal code path from the > broken one and don't need any special run-time or compile-conditionals > beyond calling of_pci_find_msi_chip_by_node(). [Minghuan] The new MSI hardware implementation is not ready, I do not know how to describe its dts node and how to implement its driver. When it is ready, I will implement the driver and add a workaround for the current incorrect MSI. The current MSI driver is based on pci-designware. > Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt new file mode 100644 index 0000000..af2ee1c0 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt @@ -0,0 +1,41 @@ +Freescale Layerscape PCIe controller + +This PCIe host controller is based on the Synopsis Designware PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: should contain "fsl,ls-pcie", to identify the platform, + plus an identifier for specific instance such as "fsl,ls1021a-pcie" +- reg: base addresses and lengths of the PCIe controller +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + "intr": The interrupt that is asserted for controller interrupts + "msi": The interrupt that is asserted when an MSI is received + "pme": The interrupt that is asserted when PME state changes + +Example: + + pcie@3400000 { + compatible = "fsl,ls1021a-pcie", "fsl,ls-pcie", "snps,dw-pcie"; + reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ + 0x40 0x00000000 0x0 0x00080000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */ + <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>, /* MSI interrupt */ + <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>; /* PME interrupt */ + interrupt-names = "intr", "msi", "pme"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + num-lanes = <4>; + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x00000000 0x41 0x00000000 0x1 0x00000000>; /* non-prefetchable memory */ + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 2 &gic GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 3 &gic GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 4 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 8922c37..e0d7bbf 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -63,4 +63,11 @@ config PCIE_SPEAR13XX help Say Y here if you want PCIe support on SPEAr13XX SoCs. +config PCI_LAYERSCAPE + bool "Freescale Layerscape PCIe controller" + depends on SOC_LS1021A + select PCIE_DW + help + Say Y here if you want PCIe controller support on Layerscape SoCs. + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index d0e88f1..54cd9b2 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o +obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c new file mode 100644 index 0000000..077a20b --- /dev/null +++ b/drivers/pci/host/pci-layerscape.c @@ -0,0 +1,315 @@ +/* + * PCIe host controller driver for Freescale Layerscape SoCs + * + * Copyright (C) 2014 Freescale Semiconductor. + * + * Author: Minghuan Lian <Minghuan.Lian@freescale.com> + * + * 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/kernel.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_pci.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/resource.h> + +#include "pcie-designware.h" + +/* PEX1/2 Misc Ports Status Register */ +#define PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) +#define LTSSM_STATE_SHIFT 20 +#define LTSSM_STATE_MASK 0x3f +#define LTSSM_PCIE_L0 0x11 /* L0 state */ + +#define SCFG_SPIMSICR_OFF 0x40 +#define SCFG_SPIMSICR_ADDR 0x1570040 +#define SCFG_SPIMSICLRCR_OFF 0x90 +#define SCFG_SCFGREVCR_OFF 0x200 +#define SCFG_BIT_REVERSE 0xFFFFFFFF +#define SCFG_NO_BIT_REVERSE 0x0 + +#define MSI_LS1021A_DATA(pex_idx) (0xb3 + pex_idx) + +/* Symbol Timer Register and Filter Mask Register 1 */ +#define PCIE_STRFMR1 0x71c + +#define PCIE_LS1021A_BASE 0x3400000 +#define PCIE_LS1021A_REG_SIZE 0x0100000 + +struct ls_pcie { + struct list_head node; + struct device *dev; + struct pci_bus *bus; + void __iomem *dbi; + void __iomem *scfg; + struct pcie_port pp; + int id; + int index; + int irq; + int msi_irq; + int pme_irq; +}; + +static LIST_HEAD(ls_pcie_list); + +#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp) + +static int ls_pcie_link_up(struct pcie_port *pp) +{ + u32 rc, tmp; + struct ls_pcie *pcie = to_ls_pcie(pp); + + tmp = ioread32(pcie->scfg + SCFG_SCFGREVCR_OFF); + iowrite32(SCFG_NO_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); + + rc = (ioread32(pcie->scfg + PEXMSCPORTSR(pcie->index)) >> + LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; + + iowrite32(tmp, pcie->scfg + SCFG_SCFGREVCR_OFF); + + if (rc < LTSSM_PCIE_L0) + return 0; + + return 1; +} + +static u32 ls_pcie_get_msi_addr(struct pcie_port *pp) +{ + return SCFG_SPIMSICR_ADDR; +} + +static u32 ls_pcie_get_msi_data(struct pcie_port *pp, int pos) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + + if (pcie->id == PCI_DEVICE_ID_LS1021A) + return MSI_LS1021A_DATA(pcie->index); + + return pos; +} + +static irqreturn_t ls_pcie_msi_irq_handler(int irq, void *data) +{ + struct pcie_port *pp = data; + struct ls_pcie *pcie = to_ls_pcie(pp); + unsigned int msi_irq, processed = 0; + + if (pcie->id == PCI_DEVICE_ID_LS1021A) { + /* clear the interrupt */ + iowrite32(MSI_LS1021A_DATA(pcie->index), + pcie->scfg + SCFG_SPIMSICLRCR_OFF); + + msi_irq = irq_find_mapping(pp->irq_domain, 0); + if (msi_irq) + generic_handle_irq(msi_irq); + else + /* + * that's weird who triggered this? + * just clear it + */ + dev_info(pcie->dev, "unexpected MSI\n"); + + processed++; + } + + return processed > 0 ? IRQ_HANDLED : IRQ_NONE; +} + +static void ls_pcie_msi_clear_irq(struct pcie_port *pp, int irq) +{ +} + +static void ls_pcie_msi_set_irq(struct pcie_port *pp, int irq) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + + /* MSI needs to set SCFG bit reverse */ + iowrite32(SCFG_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); +} + +static void ls_pcie_msi_fixup(struct pcie_port *pp) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + int i; + + if (pcie->id != PCI_DEVICE_ID_LS1021A) + return; + + /** + * LS1021A has only one MSI interrupt + * Set all msi interrupts as used except the first one + */ + for (i = 1; i < MAX_MSI_IRQS; i++) + set_bit(i, pp->msi_irq_in_use); +} + +static void ls_pcie_host_init(struct pcie_port *pp) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + int count = 0; + u32 val; + + dw_pcie_setup_rc(pp); + + while (!ls_pcie_link_up(pp)) { + usleep_range(100, 1000); + count++; + if (count >= 200) { + dev_err(pp->dev, "phy link never came up\n"); + return; + } + } + + /* Workaround for internal TKT228622 to fix the INTx hang issue */ + val = ioread32(pcie->dbi + PCIE_STRFMR1); + val &= 0xffff; + iowrite32(val, pcie->dbi + PCIE_STRFMR1); + + ls_pcie_msi_fixup(pp); +} + +static struct pcie_host_ops ls_pcie_host_ops = { + .link_up = ls_pcie_link_up, + .host_init = ls_pcie_host_init, + .msi_set_irq = ls_pcie_msi_set_irq, + .msi_clear_irq = ls_pcie_msi_clear_irq, + .get_msi_addr = ls_pcie_get_msi_addr, + .get_msi_data = ls_pcie_get_msi_data, +}; + +static int ls_add_pcie_port(struct ls_pcie *pcie) +{ + struct pcie_port *pp; + int ret; + + if (!pcie) + return -EINVAL; + + pp = &pcie->pp; + pp->dev = pcie->dev; + pp->dbi_base = pcie->dbi; + pp->msi_irq = pcie->msi_irq; + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = devm_request_irq(pp->dev, pp->msi_irq, + ls_pcie_msi_irq_handler, + IRQF_SHARED, "ls-pcie-msi", pp); + if (ret) { + dev_err(pp->dev, "failed to request msi irq\n"); + return ret; + } + } + + pp->root_bus_nr = -1; + pp->ops = &ls_pcie_host_ops; + + ret = dw_pcie_host_init(pp); + if (ret) { + dev_err(pp->dev, "failed to initialize host\n"); + return ret; + } + + return 0; +} + +static int __init ls_pcie_probe(struct platform_device *pdev) +{ + struct ls_pcie *pcie; + struct resource *dbi_base; + struct device_node *np; + int ret; + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = &pdev->dev; + + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!dbi_base) { + dev_err(&pdev->dev, "missing *regs* space\n"); + return -ENODEV; + } + + pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); + if (IS_ERR(pcie->dbi)) + return PTR_ERR(pcie->dbi); + + if (of_device_is_compatible(pdev->dev.of_node, "fsl,ls1021a-pcie")) { + pcie->id = PCI_DEVICE_ID_LS1021A; + pcie->index = (dbi_base->start - PCIE_LS1021A_BASE) / + PCIE_LS1021A_REG_SIZE; + + /* map SCFG register */ + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-scfg"); + pcie->scfg = of_iomap(np, 0); + if (!pcie->scfg) { + dev_err(&pdev->dev, "unable to find SCFG registers\n"); + return PTR_ERR(pcie->scfg); + } + } + + /* request interrupt */ + pcie->irq = platform_get_irq_byname(pdev, "intr"); + if (pcie->irq < 0) { + dev_err(&pdev->dev, "failed to get IRQ: %d\n", pcie->irq); + return pcie->irq; + } + + pcie->msi_irq = platform_get_irq_byname(pdev, "msi"); + if (pcie->msi_irq < 0) { + dev_err(&pdev->dev, + "failed to get MSI IRQ: %d\n", pcie->msi_irq); + return pcie->msi_irq; + } + + pcie->pme_irq = platform_get_irq_byname(pdev, "pme"); + if (pcie->pme_irq < 0) { + dev_err(&pdev->dev, + "failed to get PME IRQ: %d\n", pcie->pme_irq); + return pcie->pme_irq; + } + + ret = ls_add_pcie_port(pcie); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, pcie); + list_add(&pcie->node, &ls_pcie_list); + + return 0; +} + +static const struct of_device_id ls_pcie_of_match[] = { + { .compatible = "fsl,ls-pcie" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ls_pcie_of_match); + +static struct platform_driver ls_pcie_driver = { + .driver = { + .name = "layerscape-pcie", + .owner = THIS_MODULE, + .of_match_table = ls_pcie_of_match, + }, +}; + +/* Freescale PCIe driver does not allow module unload */ +static int __init ls_pcie_init(void) +{ + return platform_driver_probe(&ls_pcie_driver, ls_pcie_probe); +} +subsys_initcall(ls_pcie_init); + +MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@freescale.com>"); +MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6ed0bb7..26d4c30 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2442,6 +2442,7 @@ #define PCI_DEVICE_ID_P5020 0x0421 #define PCI_DEVICE_ID_P5010E 0x0428 #define PCI_DEVICE_ID_P5010 0x0429 +#define PCI_DEVICE_ID_LS1021A 0x0e0b #define PCI_DEVICE_ID_MPC8641 0x7010 #define PCI_DEVICE_ID_MPC8641D 0x7011 #define PCI_DEVICE_ID_MPC8610 0x7018
Add support for Freescale Layerscape PCIe controller. This driver re-uses the designware core code. Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com> --- .../devicetree/bindings/pci/fsl,ls-pcie.txt | 41 +++ drivers/pci/host/Kconfig | 7 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pci-layerscape.c | 315 +++++++++++++++++++++ include/linux/pci_ids.h | 1 + 5 files changed, 365 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt create mode 100644 drivers/pci/host/pci-layerscape.c