Message ID | 20221113191301.5526-20-Sergey.Semin@baikalelectronics.ru (mailing list archive) |
---|---|
State | Accepted |
Delegated to: | Lorenzo Pieralisi |
Headers | show |
Series | PCI: dwc: Add generic resources and Baikal-T1 support | expand |
On Sun, Nov 13, 2022 at 10:13:00PM +0300, Serge Semin wrote: > Currently almost each platform driver uses its own resets and clocks > naming in order to get the corresponding descriptors. It makes the code > harder to maintain and comprehend especially seeing the DWC PCIe core main > resets and clocks signals set hasn't changed much for about at least one > major IP-core release. So in order to organize things around these signals > we suggest to create a generic interface for them in accordance with the > naming introduced in the DWC PCIe IP-core reference manual: > > Application clocks: > - "dbi" - data bus interface clock (on some DWC PCIe platforms it's > referred as "pclk", "pcie", "sys", "ahb", "cfg", "iface", > "gio", "reg", "pcie_apb_sys"); > - "mstr" - AXI-bus master interface clock (some DWC PCIe glue drivers > refer to this clock as "port", "bus", "pcie_bus", > "bus_master/master_bus/axi_m", "pcie_aclk"); > - "slv" - AXI-bus slave interface clock (also called as "port", "bus", > "pcie_bus", "bus_slave/slave_bus/axi_s", "pcie_aclk", > "pcie_inbound_axi"). > > Core clocks: > - "pipe" - core-PCS PIPE interface clock coming from external PHY (it's > normally named by the platform drivers as just "pipe"); > - "core" - primary clock of the controller (none of the platform drivers > declare such a clock but in accordance with the ref. manual > the devices may have it separately specified); > - "aux" - auxiliary PMC domain clock (it is named by some platforms as > "pcie_aux" and just "aux"); > - "ref" - Generic reference clock (it is a generic clock source, which > can be used as a signal source for multiple interfaces, some > platforms call it as "ref", "general", "pcie_phy", > "pcie_phy_ref"). > > Application resets: > - "dbi" - Data-bus interface reset (it's CSR interface clock and is > normally called as "apb" though technically it's not APB but > DWC PCIe-specific interface); > - "mstr" - AXI-bus master reset (some platforms call it as "port", "apps", > "bus", "axi_m"); > - "slv" - ABI-bus slave reset (some platforms call it as "port", "apps", > "bus", "axi_s"). > > Core resets: > - "non-sticky" - non-sticky CSR flags reset; > - "sticky" - sticky CSR flags reset; > - "pipe" - PIPE-interface (Core-PCS) logic reset (some platforms > call it just "pipe"); > - "core" - controller primary reset (resets everything except PMC > module, some platforms refer to this signal as "soft", > "pci"); > - "phy" - PCS/PHY block reset (strictly speaking it is normally > connected to the input of an external block, but the > reference manual says it must be available for the PMC > working correctly, some existing platforms call it > "pciephy", "phy", "link"); > - "hot" - PMC hot reset signal (also called as "sleep"); > - "pwr" - cold reset signal (can be referred as "pwr", "turnoff"). > > Bus reset: > - "perst" - PCIe standard signal used to reset the PCIe peripheral > devices. > > As you can see each platform uses it's own naming for basically the same > set of the signals. In the framework of this commit we suggest to add a > set of the clocks and reset signals resources, corresponding names and > identifiers for each denoted entity. At current stage the platforms will > be able to use the provided infrastructure to automatically request all > these resources and manipulate with them in the Host/EP init callbacks. > Alas it isn't that easy to create a common cold/hot reset procedure due to > too many platform-specifics in the procedure, like the external flags > exposure and the delays requirement. > I'm not really sure if this generification is going to help. For instance, in Qcom platforms we have some required clocks and some optional clocks and that too differs with each SoC. For sure you can add logic in the core dwc driver to handle those cases but that starting to do that will add a pile of mess to the dwc driver. IMO, if the dwc driver is not going to use these clocks, like controlling the clocks/resets, then there is no point in keeping the resource acquiring part in it. Thanks, Mani > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> > > --- > > Changelog v3: > - Add a method to at least request the generic clocks and resets. (@Rob) > - Add GPIO-based PERST# signal support. > --- > drivers/pci/controller/dwc/pcie-designware.c | 91 ++++++++++++++++++++ > drivers/pci/controller/dwc/pcie-designware.h | 42 +++++++++ > 2 files changed, 133 insertions(+) > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c > index d31f9d41d5cb..1e06ccf2dc9e 100644 > --- a/drivers/pci/controller/dwc/pcie-designware.c > +++ b/drivers/pci/controller/dwc/pcie-designware.c > @@ -10,7 +10,9 @@ > > #include <linux/align.h> > #include <linux/bitops.h> > +#include <linux/clk.h> > #include <linux/delay.h> > +#include <linux/gpio/consumer.h> > #include <linux/ioport.h> > #include <linux/of.h> > #include <linux/of_platform.h> > @@ -20,11 +22,89 @@ > #include "../../pci.h" > #include "pcie-designware.h" > > +static const char * const dw_pcie_app_clks[DW_PCIE_NUM_APP_CLKS] = { > + [DW_PCIE_DBI_CLK] = "dbi", > + [DW_PCIE_MSTR_CLK] = "mstr", > + [DW_PCIE_SLV_CLK] = "slv", > +}; > + > +static const char * const dw_pcie_core_clks[DW_PCIE_NUM_CORE_CLKS] = { > + [DW_PCIE_PIPE_CLK] = "pipe", > + [DW_PCIE_CORE_CLK] = "core", > + [DW_PCIE_AUX_CLK] = "aux", > + [DW_PCIE_REF_CLK] = "ref", > +}; > + > +static const char * const dw_pcie_app_rsts[DW_PCIE_NUM_APP_RSTS] = { > + [DW_PCIE_DBI_RST] = "dbi", > + [DW_PCIE_MSTR_RST] = "mstr", > + [DW_PCIE_SLV_RST] = "slv", > +}; > + > +static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = { > + [DW_PCIE_NON_STICKY_RST] = "non-sticky", > + [DW_PCIE_STICKY_RST] = "sticky", > + [DW_PCIE_CORE_RST] = "core", > + [DW_PCIE_PIPE_RST] = "pipe", > + [DW_PCIE_PHY_RST] = "phy", > + [DW_PCIE_HOT_RST] = "hot", > + [DW_PCIE_PWR_RST] = "pwr", > +}; > + > +static int dw_pcie_get_clocks(struct dw_pcie *pci) > +{ > + int i, ret; > + > + for (i = 0; i < DW_PCIE_NUM_APP_CLKS; i++) > + pci->app_clks[i].id = dw_pcie_app_clks[i]; > + > + for (i = 0; i < DW_PCIE_NUM_CORE_CLKS; i++) > + pci->core_clks[i].id = dw_pcie_core_clks[i]; > + > + ret = devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_APP_CLKS, > + pci->app_clks); > + if (ret) > + return ret; > + > + return devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_CORE_CLKS, > + pci->core_clks); > +} > + > +static int dw_pcie_get_resets(struct dw_pcie *pci) > +{ > + int i, ret; > + > + for (i = 0; i < DW_PCIE_NUM_APP_RSTS; i++) > + pci->app_rsts[i].id = dw_pcie_app_rsts[i]; > + > + for (i = 0; i < DW_PCIE_NUM_CORE_RSTS; i++) > + pci->core_rsts[i].id = dw_pcie_core_rsts[i]; > + > + ret = devm_reset_control_bulk_get_optional_shared(pci->dev, > + DW_PCIE_NUM_APP_RSTS, > + pci->app_rsts); > + if (ret) > + return ret; > + > + ret = devm_reset_control_bulk_get_optional_exclusive(pci->dev, > + DW_PCIE_NUM_CORE_RSTS, > + pci->core_rsts); > + if (ret) > + return ret; > + > + pci->pe_rst = devm_gpiod_get_optional(pci->dev, "reset", GPIOD_OUT_HIGH); > + if (IS_ERR(pci->pe_rst)) > + return PTR_ERR(pci->pe_rst); > + > + return 0; > +} > + > int dw_pcie_get_resources(struct dw_pcie *pci) > { > struct platform_device *pdev = to_platform_device(pci->dev); > struct device_node *np = dev_of_node(pci->dev); > struct resource *res; > + int ret; > > if (!pci->dbi_base) { > res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); > @@ -62,6 +142,17 @@ int dw_pcie_get_resources(struct dw_pcie *pci) > if (!pci->atu_size) > pci->atu_size = SZ_4K; > > + /* LLDD is supposed to manually switch the clocks and resets state */ > + if (dw_pcie_cap_is(pci, REQ_RES)) { > + ret = dw_pcie_get_clocks(pci); > + if (ret) > + return ret; > + > + ret = dw_pcie_get_resets(pci); > + if (ret) > + return ret; > + } > + > if (pci->link_gen < 1) > pci->link_gen = of_pci_get_max_link_speed(np); > > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h > index 081f169e6021..393dfb931df6 100644 > --- a/drivers/pci/controller/dwc/pcie-designware.h > +++ b/drivers/pci/controller/dwc/pcie-designware.h > @@ -13,10 +13,13 @@ > > #include <linux/bitfield.h> > #include <linux/bitops.h> > +#include <linux/clk.h> > #include <linux/dma-mapping.h> > +#include <linux/gpio/consumer.h> > #include <linux/irq.h> > #include <linux/msi.h> > #include <linux/pci.h> > +#include <linux/reset.h> > > #include <linux/pci-epc.h> > #include <linux/pci-epf.h> > @@ -45,6 +48,7 @@ > __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, >=)) > > /* DWC PCIe controller capabilities */ > +#define DW_PCIE_CAP_REQ_RES 0 > #define DW_PCIE_CAP_IATU_UNROLL 1 > #define DW_PCIE_CAP_CDM_CHECK 2 > > @@ -233,6 +237,39 @@ enum dw_pcie_device_mode { > DW_PCIE_RC_TYPE, > }; > > +enum dw_pcie_app_clk { > + DW_PCIE_DBI_CLK, > + DW_PCIE_MSTR_CLK, > + DW_PCIE_SLV_CLK, > + DW_PCIE_NUM_APP_CLKS > +}; > + > +enum dw_pcie_core_clk { > + DW_PCIE_PIPE_CLK, > + DW_PCIE_CORE_CLK, > + DW_PCIE_AUX_CLK, > + DW_PCIE_REF_CLK, > + DW_PCIE_NUM_CORE_CLKS > +}; > + > +enum dw_pcie_app_rst { > + DW_PCIE_DBI_RST, > + DW_PCIE_MSTR_RST, > + DW_PCIE_SLV_RST, > + DW_PCIE_NUM_APP_RSTS > +}; > + > +enum dw_pcie_core_rst { > + DW_PCIE_NON_STICKY_RST, > + DW_PCIE_STICKY_RST, > + DW_PCIE_CORE_RST, > + DW_PCIE_PIPE_RST, > + DW_PCIE_PHY_RST, > + DW_PCIE_HOT_RST, > + DW_PCIE_PWR_RST, > + DW_PCIE_NUM_CORE_RSTS > +}; > + > struct dw_pcie_host_ops { > int (*host_init)(struct dw_pcie_rp *pp); > void (*host_deinit)(struct dw_pcie_rp *pp); > @@ -332,6 +369,11 @@ struct dw_pcie { > int num_lanes; > int link_gen; > u8 n_fts[2]; > + struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS]; > + struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS]; > + struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS]; > + struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS]; > + struct gpio_desc *pe_rst; > }; > > #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) > -- > 2.38.1 > >
On Mon, Nov 14, 2022 at 12:31:15PM +0530, Manivannan Sadhasivam wrote: > On Sun, Nov 13, 2022 at 10:13:00PM +0300, Serge Semin wrote: > > Currently almost each platform driver uses its own resets and clocks > > naming in order to get the corresponding descriptors. It makes the code > > harder to maintain and comprehend especially seeing the DWC PCIe core main > > resets and clocks signals set hasn't changed much for about at least one > > major IP-core release. So in order to organize things around these signals > > we suggest to create a generic interface for them in accordance with the > > naming introduced in the DWC PCIe IP-core reference manual: > > > > Application clocks: > > - "dbi" - data bus interface clock (on some DWC PCIe platforms it's > > referred as "pclk", "pcie", "sys", "ahb", "cfg", "iface", > > "gio", "reg", "pcie_apb_sys"); > > - "mstr" - AXI-bus master interface clock (some DWC PCIe glue drivers > > refer to this clock as "port", "bus", "pcie_bus", > > "bus_master/master_bus/axi_m", "pcie_aclk"); > > - "slv" - AXI-bus slave interface clock (also called as "port", "bus", > > "pcie_bus", "bus_slave/slave_bus/axi_s", "pcie_aclk", > > "pcie_inbound_axi"). > > > > Core clocks: > > - "pipe" - core-PCS PIPE interface clock coming from external PHY (it's > > normally named by the platform drivers as just "pipe"); > > - "core" - primary clock of the controller (none of the platform drivers > > declare such a clock but in accordance with the ref. manual > > the devices may have it separately specified); > > - "aux" - auxiliary PMC domain clock (it is named by some platforms as > > "pcie_aux" and just "aux"); > > - "ref" - Generic reference clock (it is a generic clock source, which > > can be used as a signal source for multiple interfaces, some > > platforms call it as "ref", "general", "pcie_phy", > > "pcie_phy_ref"). > > > > Application resets: > > - "dbi" - Data-bus interface reset (it's CSR interface clock and is > > normally called as "apb" though technically it's not APB but > > DWC PCIe-specific interface); > > - "mstr" - AXI-bus master reset (some platforms call it as "port", "apps", > > "bus", "axi_m"); > > - "slv" - ABI-bus slave reset (some platforms call it as "port", "apps", > > "bus", "axi_s"). > > > > Core resets: > > - "non-sticky" - non-sticky CSR flags reset; > > - "sticky" - sticky CSR flags reset; > > - "pipe" - PIPE-interface (Core-PCS) logic reset (some platforms > > call it just "pipe"); > > - "core" - controller primary reset (resets everything except PMC > > module, some platforms refer to this signal as "soft", > > "pci"); > > - "phy" - PCS/PHY block reset (strictly speaking it is normally > > connected to the input of an external block, but the > > reference manual says it must be available for the PMC > > working correctly, some existing platforms call it > > "pciephy", "phy", "link"); > > - "hot" - PMC hot reset signal (also called as "sleep"); > > - "pwr" - cold reset signal (can be referred as "pwr", "turnoff"). > > > > Bus reset: > > - "perst" - PCIe standard signal used to reset the PCIe peripheral > > devices. > > > > As you can see each platform uses it's own naming for basically the same > > set of the signals. In the framework of this commit we suggest to add a > > set of the clocks and reset signals resources, corresponding names and > > identifiers for each denoted entity. At current stage the platforms will > > be able to use the provided infrastructure to automatically request all > > these resources and manipulate with them in the Host/EP init callbacks. > > Alas it isn't that easy to create a common cold/hot reset procedure due to > > too many platform-specifics in the procedure, like the external flags > > exposure and the delays requirement. > > > > I'm not really sure if this generification is going to help. For instance, in > Qcom platforms we have some required clocks and some optional clocks and that > too differs with each SoC. For sure you can add logic in the core dwc driver to > handle those cases but that starting to do that will add a pile of mess to the > dwc driver. It will help to place the order to the clock and reset naming, which in its turn will improve the driver readability and maintainability. Almost all the platforms get/check clocks and resets from the same set defined in the DW PCIe HW-manual (including the Qcom ones). The difference just in the names the developers used. Since the names is a contract (a part of the DT-bindings) which can't be changed that easy, we can't just update the already available drivers. But at the very least we can unify the DT-bindings and the resources names defined in there (which is already done and acked by Rob), provide a generic driver API and persuade the new drivers developers to be using the interface with already available names. As I already said many times for the last year. The clocks are mainly the same, but the way they are used to enable the interfaces (timings, order, etc) can be platform-specific. It's possible for the HW-designers in the framework of their platforms to re-use a clocks/resets generation module provided by Synopsys, but even Synopsys says that it's not always applicable. So practically the platform-designers prefer to omit the module and provide a direct control to the clocks and resets wires. Our platform is another example of such approach. Note you are still able to check whether the corresponding clocks/resets are available for your device just by checking the pointers. > > IMO, if the dwc driver is not going to use these clocks, like controlling the > clocks/resets, then there is no point in keeping the resource acquiring part in > it. Baikal-T1 will use these clocks and resets. The generic DWC PCIe Host/EP driver will provide a simple and ready-to-use API to request and check the clocks and resets. The new drivers will supposed to use it too. Thus eventually we'll get at least the modern drivers using the same names which will make the DW PCIe driver more readable and maintainable. Meanwhile the old drivers alas will have to be left with their platform-specific names since we can't change the DT-bindings. In anyway all of these has already been discussed with Rob. Here is what he said: On Mon, May 16, 2022 at 05:29:20PM -0500, Rob Herring wrote: > No doubt there is way to much variation here (ummm, Qcom!). Some > standardization of names in (new) bindings would be good. That's where > we should be defining names IMO. > On the driver side, I'd like to see the DW core handle clocks/resets/phys > at least for the easy cases of just turn on/off all the clocks and > toggle all resets. Perhaps even more minimally, move the clk/reset > struct pointers to the DWC core. Due to the platform-specific order and timings I don't think it's possible to create some generic clocks/resets enable/disable method. It could be done, but it will be too complex with many-platform specific hooks, callbacks, flags, etc. I even can't think of such interface even for already available drivers, not to say for some future designs. But the names and the handlers storage could be unified for sure. Note eventually, if anybody would be concerned about a full unification, the already available drivers could be converted to using the provided here API just on the level of the clock/reset IDs, but the names will have to be left as is alas. Also note my very first version of this patch provided just the clocks and reset names and their IDs without the corresponding resource request. Rob suggested to at least provide a generic request procedure. That's what I did in one of the subsequent patchset revisions. -Sergey > > Thanks, > Mani > > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> > > > > --- > > > > Changelog v3: > > - Add a method to at least request the generic clocks and resets. (@Rob) > > - Add GPIO-based PERST# signal support. > > --- > > drivers/pci/controller/dwc/pcie-designware.c | 91 ++++++++++++++++++++ > > drivers/pci/controller/dwc/pcie-designware.h | 42 +++++++++ > > 2 files changed, 133 insertions(+) > > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c > > index d31f9d41d5cb..1e06ccf2dc9e 100644 > > --- a/drivers/pci/controller/dwc/pcie-designware.c > > +++ b/drivers/pci/controller/dwc/pcie-designware.c > > @@ -10,7 +10,9 @@ > > > > #include <linux/align.h> > > #include <linux/bitops.h> > > +#include <linux/clk.h> > > #include <linux/delay.h> > > +#include <linux/gpio/consumer.h> > > #include <linux/ioport.h> > > #include <linux/of.h> > > #include <linux/of_platform.h> > > @@ -20,11 +22,89 @@ > > #include "../../pci.h" > > #include "pcie-designware.h" > > > > +static const char * const dw_pcie_app_clks[DW_PCIE_NUM_APP_CLKS] = { > > + [DW_PCIE_DBI_CLK] = "dbi", > > + [DW_PCIE_MSTR_CLK] = "mstr", > > + [DW_PCIE_SLV_CLK] = "slv", > > +}; > > + > > +static const char * const dw_pcie_core_clks[DW_PCIE_NUM_CORE_CLKS] = { > > + [DW_PCIE_PIPE_CLK] = "pipe", > > + [DW_PCIE_CORE_CLK] = "core", > > + [DW_PCIE_AUX_CLK] = "aux", > > + [DW_PCIE_REF_CLK] = "ref", > > +}; > > + > > +static const char * const dw_pcie_app_rsts[DW_PCIE_NUM_APP_RSTS] = { > > + [DW_PCIE_DBI_RST] = "dbi", > > + [DW_PCIE_MSTR_RST] = "mstr", > > + [DW_PCIE_SLV_RST] = "slv", > > +}; > > + > > +static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = { > > + [DW_PCIE_NON_STICKY_RST] = "non-sticky", > > + [DW_PCIE_STICKY_RST] = "sticky", > > + [DW_PCIE_CORE_RST] = "core", > > + [DW_PCIE_PIPE_RST] = "pipe", > > + [DW_PCIE_PHY_RST] = "phy", > > + [DW_PCIE_HOT_RST] = "hot", > > + [DW_PCIE_PWR_RST] = "pwr", > > +}; > > + > > +static int dw_pcie_get_clocks(struct dw_pcie *pci) > > +{ > > + int i, ret; > > + > > + for (i = 0; i < DW_PCIE_NUM_APP_CLKS; i++) > > + pci->app_clks[i].id = dw_pcie_app_clks[i]; > > + > > + for (i = 0; i < DW_PCIE_NUM_CORE_CLKS; i++) > > + pci->core_clks[i].id = dw_pcie_core_clks[i]; > > + > > + ret = devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_APP_CLKS, > > + pci->app_clks); > > + if (ret) > > + return ret; > > + > > + return devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_CORE_CLKS, > > + pci->core_clks); > > +} > > + > > +static int dw_pcie_get_resets(struct dw_pcie *pci) > > +{ > > + int i, ret; > > + > > + for (i = 0; i < DW_PCIE_NUM_APP_RSTS; i++) > > + pci->app_rsts[i].id = dw_pcie_app_rsts[i]; > > + > > + for (i = 0; i < DW_PCIE_NUM_CORE_RSTS; i++) > > + pci->core_rsts[i].id = dw_pcie_core_rsts[i]; > > + > > + ret = devm_reset_control_bulk_get_optional_shared(pci->dev, > > + DW_PCIE_NUM_APP_RSTS, > > + pci->app_rsts); > > + if (ret) > > + return ret; > > + > > + ret = devm_reset_control_bulk_get_optional_exclusive(pci->dev, > > + DW_PCIE_NUM_CORE_RSTS, > > + pci->core_rsts); > > + if (ret) > > + return ret; > > + > > + pci->pe_rst = devm_gpiod_get_optional(pci->dev, "reset", GPIOD_OUT_HIGH); > > + if (IS_ERR(pci->pe_rst)) > > + return PTR_ERR(pci->pe_rst); > > + > > + return 0; > > +} > > + > > int dw_pcie_get_resources(struct dw_pcie *pci) > > { > > struct platform_device *pdev = to_platform_device(pci->dev); > > struct device_node *np = dev_of_node(pci->dev); > > struct resource *res; > > + int ret; > > > > if (!pci->dbi_base) { > > res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); > > @@ -62,6 +142,17 @@ int dw_pcie_get_resources(struct dw_pcie *pci) > > if (!pci->atu_size) > > pci->atu_size = SZ_4K; > > > > + /* LLDD is supposed to manually switch the clocks and resets state */ > > + if (dw_pcie_cap_is(pci, REQ_RES)) { > > + ret = dw_pcie_get_clocks(pci); > > + if (ret) > > + return ret; > > + > > + ret = dw_pcie_get_resets(pci); > > + if (ret) > > + return ret; > > + } > > + > > if (pci->link_gen < 1) > > pci->link_gen = of_pci_get_max_link_speed(np); > > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h > > index 081f169e6021..393dfb931df6 100644 > > --- a/drivers/pci/controller/dwc/pcie-designware.h > > +++ b/drivers/pci/controller/dwc/pcie-designware.h > > @@ -13,10 +13,13 @@ > > > > #include <linux/bitfield.h> > > #include <linux/bitops.h> > > +#include <linux/clk.h> > > #include <linux/dma-mapping.h> > > +#include <linux/gpio/consumer.h> > > #include <linux/irq.h> > > #include <linux/msi.h> > > #include <linux/pci.h> > > +#include <linux/reset.h> > > > > #include <linux/pci-epc.h> > > #include <linux/pci-epf.h> > > @@ -45,6 +48,7 @@ > > __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, >=)) > > > > /* DWC PCIe controller capabilities */ > > +#define DW_PCIE_CAP_REQ_RES 0 > > #define DW_PCIE_CAP_IATU_UNROLL 1 > > #define DW_PCIE_CAP_CDM_CHECK 2 > > > > @@ -233,6 +237,39 @@ enum dw_pcie_device_mode { > > DW_PCIE_RC_TYPE, > > }; > > > > +enum dw_pcie_app_clk { > > + DW_PCIE_DBI_CLK, > > + DW_PCIE_MSTR_CLK, > > + DW_PCIE_SLV_CLK, > > + DW_PCIE_NUM_APP_CLKS > > +}; > > + > > +enum dw_pcie_core_clk { > > + DW_PCIE_PIPE_CLK, > > + DW_PCIE_CORE_CLK, > > + DW_PCIE_AUX_CLK, > > + DW_PCIE_REF_CLK, > > + DW_PCIE_NUM_CORE_CLKS > > +}; > > + > > +enum dw_pcie_app_rst { > > + DW_PCIE_DBI_RST, > > + DW_PCIE_MSTR_RST, > > + DW_PCIE_SLV_RST, > > + DW_PCIE_NUM_APP_RSTS > > +}; > > + > > +enum dw_pcie_core_rst { > > + DW_PCIE_NON_STICKY_RST, > > + DW_PCIE_STICKY_RST, > > + DW_PCIE_CORE_RST, > > + DW_PCIE_PIPE_RST, > > + DW_PCIE_PHY_RST, > > + DW_PCIE_HOT_RST, > > + DW_PCIE_PWR_RST, > > + DW_PCIE_NUM_CORE_RSTS > > +}; > > + > > struct dw_pcie_host_ops { > > int (*host_init)(struct dw_pcie_rp *pp); > > void (*host_deinit)(struct dw_pcie_rp *pp); > > @@ -332,6 +369,11 @@ struct dw_pcie { > > int num_lanes; > > int link_gen; > > u8 n_fts[2]; > > + struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS]; > > + struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS]; > > + struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS]; > > + struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS]; > > + struct gpio_desc *pe_rst; > > }; > > > > #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) > > -- > > 2.38.1 > > > > > > -- > மணிவண்ணன் சதாசிவம்
On Mon, Nov 14, 2022 at 12:37:59PM +0300, Serge Semin wrote: > On Mon, Nov 14, 2022 at 12:31:15PM +0530, Manivannan Sadhasivam wrote: > > On Sun, Nov 13, 2022 at 10:13:00PM +0300, Serge Semin wrote: > > > Currently almost each platform driver uses its own resets and clocks > > > naming in order to get the corresponding descriptors. It makes the code > > > harder to maintain and comprehend especially seeing the DWC PCIe core main > > > resets and clocks signals set hasn't changed much for about at least one > > > major IP-core release. So in order to organize things around these signals > > > we suggest to create a generic interface for them in accordance with the > > > naming introduced in the DWC PCIe IP-core reference manual: > > > > > > Application clocks: > > > - "dbi" - data bus interface clock (on some DWC PCIe platforms it's > > > referred as "pclk", "pcie", "sys", "ahb", "cfg", "iface", > > > "gio", "reg", "pcie_apb_sys"); > > > - "mstr" - AXI-bus master interface clock (some DWC PCIe glue drivers > > > refer to this clock as "port", "bus", "pcie_bus", > > > "bus_master/master_bus/axi_m", "pcie_aclk"); > > > - "slv" - AXI-bus slave interface clock (also called as "port", "bus", > > > "pcie_bus", "bus_slave/slave_bus/axi_s", "pcie_aclk", > > > "pcie_inbound_axi"). > > > > > > Core clocks: > > > - "pipe" - core-PCS PIPE interface clock coming from external PHY (it's > > > normally named by the platform drivers as just "pipe"); > > > - "core" - primary clock of the controller (none of the platform drivers > > > declare such a clock but in accordance with the ref. manual > > > the devices may have it separately specified); > > > - "aux" - auxiliary PMC domain clock (it is named by some platforms as > > > "pcie_aux" and just "aux"); > > > - "ref" - Generic reference clock (it is a generic clock source, which > > > can be used as a signal source for multiple interfaces, some > > > platforms call it as "ref", "general", "pcie_phy", > > > "pcie_phy_ref"). > > > > > > Application resets: > > > - "dbi" - Data-bus interface reset (it's CSR interface clock and is > > > normally called as "apb" though technically it's not APB but > > > DWC PCIe-specific interface); > > > - "mstr" - AXI-bus master reset (some platforms call it as "port", "apps", > > > "bus", "axi_m"); > > > - "slv" - ABI-bus slave reset (some platforms call it as "port", "apps", > > > "bus", "axi_s"). > > > > > > Core resets: > > > - "non-sticky" - non-sticky CSR flags reset; > > > - "sticky" - sticky CSR flags reset; > > > - "pipe" - PIPE-interface (Core-PCS) logic reset (some platforms > > > call it just "pipe"); > > > - "core" - controller primary reset (resets everything except PMC > > > module, some platforms refer to this signal as "soft", > > > "pci"); > > > - "phy" - PCS/PHY block reset (strictly speaking it is normally > > > connected to the input of an external block, but the > > > reference manual says it must be available for the PMC > > > working correctly, some existing platforms call it > > > "pciephy", "phy", "link"); > > > - "hot" - PMC hot reset signal (also called as "sleep"); > > > - "pwr" - cold reset signal (can be referred as "pwr", "turnoff"). > > > > > > Bus reset: > > > - "perst" - PCIe standard signal used to reset the PCIe peripheral > > > devices. > > > > > > As you can see each platform uses it's own naming for basically the same > > > set of the signals. In the framework of this commit we suggest to add a > > > set of the clocks and reset signals resources, corresponding names and > > > identifiers for each denoted entity. At current stage the platforms will > > > be able to use the provided infrastructure to automatically request all > > > these resources and manipulate with them in the Host/EP init callbacks. > > > Alas it isn't that easy to create a common cold/hot reset procedure due to > > > too many platform-specifics in the procedure, like the external flags > > > exposure and the delays requirement. > > > > > > > > I'm not really sure if this generification is going to help. For instance, in > > Qcom platforms we have some required clocks and some optional clocks and that > > too differs with each SoC. For sure you can add logic in the core dwc driver to > > handle those cases but that starting to do that will add a pile of mess to the > > dwc driver. > > It will help to place the order to the clock and reset naming, which > in its turn will improve the driver readability and maintainability. > Almost all the platforms get/check clocks and resets from the > same set defined in the DW PCIe HW-manual (including the Qcom ones). > The difference just in the names the developers used. Since the names > is a contract (a part of the DT-bindings) which can't be changed that > easy, we can't just update the already available drivers. But at the > very least we can unify the DT-bindings and the resources names > defined in there (which is already done and acked by Rob), provide a > generic driver API and persuade the new drivers developers to be using > the interface with already available names. > > As I already said many times for the last year. The clocks are mainly > the same, but the way they are used to enable the interfaces (timings, > order, etc) can be platform-specific. It's possible for the > HW-designers in the framework of their platforms to re-use a > clocks/resets generation module provided by Synopsys, but even > Synopsys says that it's not always applicable. So practically the > platform-designers prefer to omit the module and provide a direct > control to the clocks and resets wires. Our platform is another > example of such approach. > > Note you are still able to check whether the corresponding > clocks/resets are available for your device just by checking the > pointers. > > > > > IMO, if the dwc driver is not going to use these clocks, like controlling the > > clocks/resets, then there is no point in keeping the resource acquiring part in > > it. > > Baikal-T1 will use these clocks and resets. The generic DWC PCIe > Host/EP driver will provide a simple and ready-to-use API to request > and check the clocks and resets. The new drivers will supposed to use > it too. Thus eventually we'll get at least the modern drivers using > the same names which will make the DW PCIe driver more readable and > maintainable. Meanwhile the old drivers alas will have to be left > with their platform-specific names since we can't change the > DT-bindings. > > In anyway all of these has already been discussed with Rob. Here is > what he said: > > On Mon, May 16, 2022 at 05:29:20PM -0500, Rob Herring wrote: > > No doubt there is way to much variation here (ummm, Qcom!). Some > > standardization of names in (new) bindings would be good. That's where > > we should be defining names IMO. > > > On the driver side, I'd like to see the DW core handle clocks/resets/phys > > at least for the easy cases of just turn on/off all the clocks and > > toggle all resets. Perhaps even more minimally, move the clk/reset > > struct pointers to the DWC core. > > Due to the platform-specific order and timings I don't think it's > possible to create some generic clocks/resets enable/disable method. > It could be done, but it will be too complex with many-platform specific > hooks, callbacks, flags, etc. I even can't think of such interface > even for already available drivers, not to say for some future designs. > But the names and the handlers storage could be unified for sure. > > Note eventually, if anybody would be concerned about a full > unification, the already available drivers could be converted to using > the provided here API just on the level of the clock/reset IDs, but > the names will have to be left as is alas. > > Also note my very first version of this patch provided just the clocks > and reset names and their IDs without the corresponding resource > request. Rob suggested to at least provide a generic request > procedure. That's what I did in one of the subsequent patchset > revisions. > Okay then. I failed to go through the previous discussions, sorry about that. Thanks, Mani > -Sergey > > > > > Thanks, > > Mani > > > > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> > > > > > > --- > > > > > > Changelog v3: > > > - Add a method to at least request the generic clocks and resets. (@Rob) > > > - Add GPIO-based PERST# signal support. > > > --- > > > drivers/pci/controller/dwc/pcie-designware.c | 91 ++++++++++++++++++++ > > > drivers/pci/controller/dwc/pcie-designware.h | 42 +++++++++ > > > 2 files changed, 133 insertions(+) > > > > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c > > > index d31f9d41d5cb..1e06ccf2dc9e 100644 > > > --- a/drivers/pci/controller/dwc/pcie-designware.c > > > +++ b/drivers/pci/controller/dwc/pcie-designware.c > > > @@ -10,7 +10,9 @@ > > > > > > #include <linux/align.h> > > > #include <linux/bitops.h> > > > +#include <linux/clk.h> > > > #include <linux/delay.h> > > > +#include <linux/gpio/consumer.h> > > > #include <linux/ioport.h> > > > #include <linux/of.h> > > > #include <linux/of_platform.h> > > > @@ -20,11 +22,89 @@ > > > #include "../../pci.h" > > > #include "pcie-designware.h" > > > > > > +static const char * const dw_pcie_app_clks[DW_PCIE_NUM_APP_CLKS] = { > > > + [DW_PCIE_DBI_CLK] = "dbi", > > > + [DW_PCIE_MSTR_CLK] = "mstr", > > > + [DW_PCIE_SLV_CLK] = "slv", > > > +}; > > > + > > > +static const char * const dw_pcie_core_clks[DW_PCIE_NUM_CORE_CLKS] = { > > > + [DW_PCIE_PIPE_CLK] = "pipe", > > > + [DW_PCIE_CORE_CLK] = "core", > > > + [DW_PCIE_AUX_CLK] = "aux", > > > + [DW_PCIE_REF_CLK] = "ref", > > > +}; > > > + > > > +static const char * const dw_pcie_app_rsts[DW_PCIE_NUM_APP_RSTS] = { > > > + [DW_PCIE_DBI_RST] = "dbi", > > > + [DW_PCIE_MSTR_RST] = "mstr", > > > + [DW_PCIE_SLV_RST] = "slv", > > > +}; > > > + > > > +static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = { > > > + [DW_PCIE_NON_STICKY_RST] = "non-sticky", > > > + [DW_PCIE_STICKY_RST] = "sticky", > > > + [DW_PCIE_CORE_RST] = "core", > > > + [DW_PCIE_PIPE_RST] = "pipe", > > > + [DW_PCIE_PHY_RST] = "phy", > > > + [DW_PCIE_HOT_RST] = "hot", > > > + [DW_PCIE_PWR_RST] = "pwr", > > > +}; > > > + > > > +static int dw_pcie_get_clocks(struct dw_pcie *pci) > > > +{ > > > + int i, ret; > > > + > > > + for (i = 0; i < DW_PCIE_NUM_APP_CLKS; i++) > > > + pci->app_clks[i].id = dw_pcie_app_clks[i]; > > > + > > > + for (i = 0; i < DW_PCIE_NUM_CORE_CLKS; i++) > > > + pci->core_clks[i].id = dw_pcie_core_clks[i]; > > > + > > > + ret = devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_APP_CLKS, > > > + pci->app_clks); > > > + if (ret) > > > + return ret; > > > + > > > + return devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_CORE_CLKS, > > > + pci->core_clks); > > > +} > > > + > > > +static int dw_pcie_get_resets(struct dw_pcie *pci) > > > +{ > > > + int i, ret; > > > + > > > + for (i = 0; i < DW_PCIE_NUM_APP_RSTS; i++) > > > + pci->app_rsts[i].id = dw_pcie_app_rsts[i]; > > > + > > > + for (i = 0; i < DW_PCIE_NUM_CORE_RSTS; i++) > > > + pci->core_rsts[i].id = dw_pcie_core_rsts[i]; > > > + > > > + ret = devm_reset_control_bulk_get_optional_shared(pci->dev, > > > + DW_PCIE_NUM_APP_RSTS, > > > + pci->app_rsts); > > > + if (ret) > > > + return ret; > > > + > > > + ret = devm_reset_control_bulk_get_optional_exclusive(pci->dev, > > > + DW_PCIE_NUM_CORE_RSTS, > > > + pci->core_rsts); > > > + if (ret) > > > + return ret; > > > + > > > + pci->pe_rst = devm_gpiod_get_optional(pci->dev, "reset", GPIOD_OUT_HIGH); > > > + if (IS_ERR(pci->pe_rst)) > > > + return PTR_ERR(pci->pe_rst); > > > + > > > + return 0; > > > +} > > > + > > > int dw_pcie_get_resources(struct dw_pcie *pci) > > > { > > > struct platform_device *pdev = to_platform_device(pci->dev); > > > struct device_node *np = dev_of_node(pci->dev); > > > struct resource *res; > > > + int ret; > > > > > > if (!pci->dbi_base) { > > > res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); > > > @@ -62,6 +142,17 @@ int dw_pcie_get_resources(struct dw_pcie *pci) > > > if (!pci->atu_size) > > > pci->atu_size = SZ_4K; > > > > > > + /* LLDD is supposed to manually switch the clocks and resets state */ > > > + if (dw_pcie_cap_is(pci, REQ_RES)) { > > > + ret = dw_pcie_get_clocks(pci); > > > + if (ret) > > > + return ret; > > > + > > > + ret = dw_pcie_get_resets(pci); > > > + if (ret) > > > + return ret; > > > + } > > > + > > > if (pci->link_gen < 1) > > > pci->link_gen = of_pci_get_max_link_speed(np); > > > > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h > > > index 081f169e6021..393dfb931df6 100644 > > > --- a/drivers/pci/controller/dwc/pcie-designware.h > > > +++ b/drivers/pci/controller/dwc/pcie-designware.h > > > @@ -13,10 +13,13 @@ > > > > > > #include <linux/bitfield.h> > > > #include <linux/bitops.h> > > > +#include <linux/clk.h> > > > #include <linux/dma-mapping.h> > > > +#include <linux/gpio/consumer.h> > > > #include <linux/irq.h> > > > #include <linux/msi.h> > > > #include <linux/pci.h> > > > +#include <linux/reset.h> > > > > > > #include <linux/pci-epc.h> > > > #include <linux/pci-epf.h> > > > @@ -45,6 +48,7 @@ > > > __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, >=)) > > > > > > /* DWC PCIe controller capabilities */ > > > +#define DW_PCIE_CAP_REQ_RES 0 > > > #define DW_PCIE_CAP_IATU_UNROLL 1 > > > #define DW_PCIE_CAP_CDM_CHECK 2 > > > > > > @@ -233,6 +237,39 @@ enum dw_pcie_device_mode { > > > DW_PCIE_RC_TYPE, > > > }; > > > > > > +enum dw_pcie_app_clk { > > > + DW_PCIE_DBI_CLK, > > > + DW_PCIE_MSTR_CLK, > > > + DW_PCIE_SLV_CLK, > > > + DW_PCIE_NUM_APP_CLKS > > > +}; > > > + > > > +enum dw_pcie_core_clk { > > > + DW_PCIE_PIPE_CLK, > > > + DW_PCIE_CORE_CLK, > > > + DW_PCIE_AUX_CLK, > > > + DW_PCIE_REF_CLK, > > > + DW_PCIE_NUM_CORE_CLKS > > > +}; > > > + > > > +enum dw_pcie_app_rst { > > > + DW_PCIE_DBI_RST, > > > + DW_PCIE_MSTR_RST, > > > + DW_PCIE_SLV_RST, > > > + DW_PCIE_NUM_APP_RSTS > > > +}; > > > + > > > +enum dw_pcie_core_rst { > > > + DW_PCIE_NON_STICKY_RST, > > > + DW_PCIE_STICKY_RST, > > > + DW_PCIE_CORE_RST, > > > + DW_PCIE_PIPE_RST, > > > + DW_PCIE_PHY_RST, > > > + DW_PCIE_HOT_RST, > > > + DW_PCIE_PWR_RST, > > > + DW_PCIE_NUM_CORE_RSTS > > > +}; > > > + > > > struct dw_pcie_host_ops { > > > int (*host_init)(struct dw_pcie_rp *pp); > > > void (*host_deinit)(struct dw_pcie_rp *pp); > > > @@ -332,6 +369,11 @@ struct dw_pcie { > > > int num_lanes; > > > int link_gen; > > > u8 n_fts[2]; > > > + struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS]; > > > + struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS]; > > > + struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS]; > > > + struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS]; > > > + struct gpio_desc *pe_rst; > > > }; > > > > > > #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) > > > -- > > > 2.38.1 > > > > > > > > > > -- > > மணிவண்ணன் சதாசிவம்
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index d31f9d41d5cb..1e06ccf2dc9e 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -10,7 +10,9 @@ #include <linux/align.h> #include <linux/bitops.h> +#include <linux/clk.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/ioport.h> #include <linux/of.h> #include <linux/of_platform.h> @@ -20,11 +22,89 @@ #include "../../pci.h" #include "pcie-designware.h" +static const char * const dw_pcie_app_clks[DW_PCIE_NUM_APP_CLKS] = { + [DW_PCIE_DBI_CLK] = "dbi", + [DW_PCIE_MSTR_CLK] = "mstr", + [DW_PCIE_SLV_CLK] = "slv", +}; + +static const char * const dw_pcie_core_clks[DW_PCIE_NUM_CORE_CLKS] = { + [DW_PCIE_PIPE_CLK] = "pipe", + [DW_PCIE_CORE_CLK] = "core", + [DW_PCIE_AUX_CLK] = "aux", + [DW_PCIE_REF_CLK] = "ref", +}; + +static const char * const dw_pcie_app_rsts[DW_PCIE_NUM_APP_RSTS] = { + [DW_PCIE_DBI_RST] = "dbi", + [DW_PCIE_MSTR_RST] = "mstr", + [DW_PCIE_SLV_RST] = "slv", +}; + +static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = { + [DW_PCIE_NON_STICKY_RST] = "non-sticky", + [DW_PCIE_STICKY_RST] = "sticky", + [DW_PCIE_CORE_RST] = "core", + [DW_PCIE_PIPE_RST] = "pipe", + [DW_PCIE_PHY_RST] = "phy", + [DW_PCIE_HOT_RST] = "hot", + [DW_PCIE_PWR_RST] = "pwr", +}; + +static int dw_pcie_get_clocks(struct dw_pcie *pci) +{ + int i, ret; + + for (i = 0; i < DW_PCIE_NUM_APP_CLKS; i++) + pci->app_clks[i].id = dw_pcie_app_clks[i]; + + for (i = 0; i < DW_PCIE_NUM_CORE_CLKS; i++) + pci->core_clks[i].id = dw_pcie_core_clks[i]; + + ret = devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_APP_CLKS, + pci->app_clks); + if (ret) + return ret; + + return devm_clk_bulk_get_optional(pci->dev, DW_PCIE_NUM_CORE_CLKS, + pci->core_clks); +} + +static int dw_pcie_get_resets(struct dw_pcie *pci) +{ + int i, ret; + + for (i = 0; i < DW_PCIE_NUM_APP_RSTS; i++) + pci->app_rsts[i].id = dw_pcie_app_rsts[i]; + + for (i = 0; i < DW_PCIE_NUM_CORE_RSTS; i++) + pci->core_rsts[i].id = dw_pcie_core_rsts[i]; + + ret = devm_reset_control_bulk_get_optional_shared(pci->dev, + DW_PCIE_NUM_APP_RSTS, + pci->app_rsts); + if (ret) + return ret; + + ret = devm_reset_control_bulk_get_optional_exclusive(pci->dev, + DW_PCIE_NUM_CORE_RSTS, + pci->core_rsts); + if (ret) + return ret; + + pci->pe_rst = devm_gpiod_get_optional(pci->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(pci->pe_rst)) + return PTR_ERR(pci->pe_rst); + + return 0; +} + int dw_pcie_get_resources(struct dw_pcie *pci) { struct platform_device *pdev = to_platform_device(pci->dev); struct device_node *np = dev_of_node(pci->dev); struct resource *res; + int ret; if (!pci->dbi_base) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); @@ -62,6 +142,17 @@ int dw_pcie_get_resources(struct dw_pcie *pci) if (!pci->atu_size) pci->atu_size = SZ_4K; + /* LLDD is supposed to manually switch the clocks and resets state */ + if (dw_pcie_cap_is(pci, REQ_RES)) { + ret = dw_pcie_get_clocks(pci); + if (ret) + return ret; + + ret = dw_pcie_get_resets(pci); + if (ret) + return ret; + } + if (pci->link_gen < 1) pci->link_gen = of_pci_get_max_link_speed(np); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 081f169e6021..393dfb931df6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -13,10 +13,13 @@ #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/clk.h> #include <linux/dma-mapping.h> +#include <linux/gpio/consumer.h> #include <linux/irq.h> #include <linux/msi.h> #include <linux/pci.h> +#include <linux/reset.h> #include <linux/pci-epc.h> #include <linux/pci-epf.h> @@ -45,6 +48,7 @@ __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, >=)) /* DWC PCIe controller capabilities */ +#define DW_PCIE_CAP_REQ_RES 0 #define DW_PCIE_CAP_IATU_UNROLL 1 #define DW_PCIE_CAP_CDM_CHECK 2 @@ -233,6 +237,39 @@ enum dw_pcie_device_mode { DW_PCIE_RC_TYPE, }; +enum dw_pcie_app_clk { + DW_PCIE_DBI_CLK, + DW_PCIE_MSTR_CLK, + DW_PCIE_SLV_CLK, + DW_PCIE_NUM_APP_CLKS +}; + +enum dw_pcie_core_clk { + DW_PCIE_PIPE_CLK, + DW_PCIE_CORE_CLK, + DW_PCIE_AUX_CLK, + DW_PCIE_REF_CLK, + DW_PCIE_NUM_CORE_CLKS +}; + +enum dw_pcie_app_rst { + DW_PCIE_DBI_RST, + DW_PCIE_MSTR_RST, + DW_PCIE_SLV_RST, + DW_PCIE_NUM_APP_RSTS +}; + +enum dw_pcie_core_rst { + DW_PCIE_NON_STICKY_RST, + DW_PCIE_STICKY_RST, + DW_PCIE_CORE_RST, + DW_PCIE_PIPE_RST, + DW_PCIE_PHY_RST, + DW_PCIE_HOT_RST, + DW_PCIE_PWR_RST, + DW_PCIE_NUM_CORE_RSTS +}; + struct dw_pcie_host_ops { int (*host_init)(struct dw_pcie_rp *pp); void (*host_deinit)(struct dw_pcie_rp *pp); @@ -332,6 +369,11 @@ struct dw_pcie { int num_lanes; int link_gen; u8 n_fts[2]; + struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS]; + struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS]; + struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS]; + struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS]; + struct gpio_desc *pe_rst; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
Currently almost each platform driver uses its own resets and clocks naming in order to get the corresponding descriptors. It makes the code harder to maintain and comprehend especially seeing the DWC PCIe core main resets and clocks signals set hasn't changed much for about at least one major IP-core release. So in order to organize things around these signals we suggest to create a generic interface for them in accordance with the naming introduced in the DWC PCIe IP-core reference manual: Application clocks: - "dbi" - data bus interface clock (on some DWC PCIe platforms it's referred as "pclk", "pcie", "sys", "ahb", "cfg", "iface", "gio", "reg", "pcie_apb_sys"); - "mstr" - AXI-bus master interface clock (some DWC PCIe glue drivers refer to this clock as "port", "bus", "pcie_bus", "bus_master/master_bus/axi_m", "pcie_aclk"); - "slv" - AXI-bus slave interface clock (also called as "port", "bus", "pcie_bus", "bus_slave/slave_bus/axi_s", "pcie_aclk", "pcie_inbound_axi"). Core clocks: - "pipe" - core-PCS PIPE interface clock coming from external PHY (it's normally named by the platform drivers as just "pipe"); - "core" - primary clock of the controller (none of the platform drivers declare such a clock but in accordance with the ref. manual the devices may have it separately specified); - "aux" - auxiliary PMC domain clock (it is named by some platforms as "pcie_aux" and just "aux"); - "ref" - Generic reference clock (it is a generic clock source, which can be used as a signal source for multiple interfaces, some platforms call it as "ref", "general", "pcie_phy", "pcie_phy_ref"). Application resets: - "dbi" - Data-bus interface reset (it's CSR interface clock and is normally called as "apb" though technically it's not APB but DWC PCIe-specific interface); - "mstr" - AXI-bus master reset (some platforms call it as "port", "apps", "bus", "axi_m"); - "slv" - ABI-bus slave reset (some platforms call it as "port", "apps", "bus", "axi_s"). Core resets: - "non-sticky" - non-sticky CSR flags reset; - "sticky" - sticky CSR flags reset; - "pipe" - PIPE-interface (Core-PCS) logic reset (some platforms call it just "pipe"); - "core" - controller primary reset (resets everything except PMC module, some platforms refer to this signal as "soft", "pci"); - "phy" - PCS/PHY block reset (strictly speaking it is normally connected to the input of an external block, but the reference manual says it must be available for the PMC working correctly, some existing platforms call it "pciephy", "phy", "link"); - "hot" - PMC hot reset signal (also called as "sleep"); - "pwr" - cold reset signal (can be referred as "pwr", "turnoff"). Bus reset: - "perst" - PCIe standard signal used to reset the PCIe peripheral devices. As you can see each platform uses it's own naming for basically the same set of the signals. In the framework of this commit we suggest to add a set of the clocks and reset signals resources, corresponding names and identifiers for each denoted entity. At current stage the platforms will be able to use the provided infrastructure to automatically request all these resources and manipulate with them in the Host/EP init callbacks. Alas it isn't that easy to create a common cold/hot reset procedure due to too many platform-specifics in the procedure, like the external flags exposure and the delays requirement. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> --- Changelog v3: - Add a method to at least request the generic clocks and resets. (@Rob) - Add GPIO-based PERST# signal support. --- drivers/pci/controller/dwc/pcie-designware.c | 91 ++++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 42 +++++++++ 2 files changed, 133 insertions(+)