PCI: dwc: Move dw_pcie_setup_rc() to DWC common code
[linux-2.6-microblaze.git] / drivers / pci / controller / dwc / pci-meson.c
index 4f183b9..04589f0 100644 (file)
 #include <linux/resource.h>
 #include <linux/types.h>
 #include <linux/phy/phy.h>
+#include <linux/module.h>
 
 #include "pcie-designware.h"
 
 #define to_meson_pcie(x) dev_get_drvdata((x)->dev)
 
-/* External local bus interface registers */
-#define PLR_OFFSET                     0x700
-#define PCIE_PORT_LINK_CTRL_OFF                (PLR_OFFSET + 0x10)
-#define FAST_LINK_MODE                 BIT(7)
-#define LINK_CAPABLE_MASK              GENMASK(21, 16)
-#define LINK_CAPABLE_X1                        BIT(16)
-
-#define PCIE_GEN2_CTRL_OFF             (PLR_OFFSET + 0x10c)
-#define NUM_OF_LANES_MASK              GENMASK(12, 8)
-#define NUM_OF_LANES_X1                        BIT(8)
-#define DIRECT_SPEED_CHANGE            BIT(17)
-
-#define TYPE1_HDR_OFFSET               0x0
-#define PCIE_STATUS_COMMAND            (TYPE1_HDR_OFFSET + 0x04)
-#define PCI_IO_EN                      BIT(0)
-#define PCI_MEM_SPACE_EN               BIT(1)
-#define PCI_BUS_MASTER_EN              BIT(2)
-
-#define PCIE_BASE_ADDR0                        (TYPE1_HDR_OFFSET + 0x10)
-#define PCIE_BASE_ADDR1                        (TYPE1_HDR_OFFSET + 0x14)
-
-#define PCIE_CAP_OFFSET                        0x70
-#define PCIE_DEV_CTRL_DEV_STUS         (PCIE_CAP_OFFSET + 0x08)
-#define PCIE_CAP_MAX_PAYLOAD_MASK      GENMASK(7, 5)
 #define PCIE_CAP_MAX_PAYLOAD_SIZE(x)   ((x) << 5)
-#define PCIE_CAP_MAX_READ_REQ_MASK     GENMASK(14, 12)
 #define PCIE_CAP_MAX_READ_REQ_SIZE(x)  ((x) << 12)
 
 /* PCIe specific config registers */
@@ -77,11 +53,6 @@ enum pcie_data_rate {
        PCIE_GEN4
 };
 
-struct meson_pcie_mem_res {
-       void __iomem *elbi_base;
-       void __iomem *cfg_base;
-};
-
 struct meson_pcie_clk_res {
        struct clk *clk;
        struct clk *port_clk;
@@ -95,7 +66,7 @@ struct meson_pcie_rc_reset {
 
 struct meson_pcie {
        struct dw_pcie pci;
-       struct meson_pcie_mem_res mem_res;
+       void __iomem *cfg_base;
        struct meson_pcie_clk_res clk_res;
        struct meson_pcie_rc_reset mrst;
        struct gpio_desc *reset_gpio;
@@ -134,28 +105,18 @@ static int meson_pcie_get_resets(struct meson_pcie *mp)
        return 0;
 }
 
-static void __iomem *meson_pcie_get_mem(struct platform_device *pdev,
-                                       struct meson_pcie *mp,
-                                       const char *id)
-{
-       struct device *dev = mp->pci.dev;
-       struct resource *res;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
-
-       return devm_ioremap_resource(dev, res);
-}
-
 static int meson_pcie_get_mems(struct platform_device *pdev,
                               struct meson_pcie *mp)
 {
-       mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi");
-       if (IS_ERR(mp->mem_res.elbi_base))
-               return PTR_ERR(mp->mem_res.elbi_base);
+       struct dw_pcie *pci = &mp->pci;
 
-       mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg");
-       if (IS_ERR(mp->mem_res.cfg_base))
-               return PTR_ERR(mp->mem_res.cfg_base);
+       pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
+       if (IS_ERR(pci->dbi_base))
+               return PTR_ERR(pci->dbi_base);
+
+       mp->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
+       if (IS_ERR(mp->cfg_base))
+               return PTR_ERR(mp->cfg_base);
 
        return 0;
 }
@@ -253,24 +214,14 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
        return 0;
 }
 
-static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
-{
-       writel(val, mp->mem_res.elbi_base + reg);
-}
-
-static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg)
-{
-       return readl(mp->mem_res.elbi_base + reg);
-}
-
 static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg)
 {
-       return readl(mp->mem_res.cfg_base + reg);
+       return readl(mp->cfg_base + reg);
 }
 
 static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
 {
-       writel(val, mp->mem_res.cfg_base + reg);
+       writel(val, mp->cfg_base + reg);
 }
 
 static void meson_pcie_assert_reset(struct meson_pcie *mp)
@@ -280,32 +231,13 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp)
        gpiod_set_value_cansleep(mp->reset_gpio, 0);
 }
 
-static void meson_pcie_init_dw(struct meson_pcie *mp)
+static void meson_pcie_ltssm_enable(struct meson_pcie *mp)
 {
        u32 val;
 
        val = meson_cfg_readl(mp, PCIE_CFG0);
        val |= APP_LTSSM_ENABLE;
        meson_cfg_writel(mp, val, PCIE_CFG0);
-
-       val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
-       val &= ~(LINK_CAPABLE_MASK | FAST_LINK_MODE);
-       meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
-
-       val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
-       val |= LINK_CAPABLE_X1;
-       meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
-
-       val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
-       val &= ~NUM_OF_LANES_MASK;
-       meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
-
-       val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
-       val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE;
-       meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
-
-       meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0);
-       meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1);
 }
 
 static int meson_size_to_payload(struct meson_pcie *mp, int size)
@@ -327,69 +259,52 @@ static int meson_size_to_payload(struct meson_pcie *mp, int size)
 
 static void meson_set_max_payload(struct meson_pcie *mp, int size)
 {
+       struct dw_pcie *pci = &mp->pci;
        u32 val;
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        int max_payload_size = meson_size_to_payload(mp, size);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
-       val &= ~PCIE_CAP_MAX_PAYLOAD_MASK;
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
+       val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
        val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 }
 
 static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
 {
+       struct dw_pcie *pci = &mp->pci;
        u32 val;
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        int max_rd_req_size = meson_size_to_payload(mp, size);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
-       val &= ~PCIE_CAP_MAX_READ_REQ_MASK;
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
+       val &= ~PCI_EXP_DEVCTL_READRQ;
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 
-       val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+       val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
        val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
-       meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+       dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
 }
 
-static inline void meson_enable_memory_space(struct meson_pcie *mp)
+static int meson_pcie_start_link(struct dw_pcie *pci)
 {
-       /* Set the RC Bus Master, Memory Space and I/O Space enables */
-       meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN,
-                        PCIE_STATUS_COMMAND);
-}
-
-static int meson_pcie_establish_link(struct meson_pcie *mp)
-{
-       struct dw_pcie *pci = &mp->pci;
-       struct pcie_port *pp = &pci->pp;
-
-       meson_pcie_init_dw(mp);
-       meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
-       meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
-
-       dw_pcie_setup_rc(pp);
-       meson_enable_memory_space(mp);
+       struct meson_pcie *mp = to_meson_pcie(pci);
 
+       meson_pcie_ltssm_enable(mp);
        meson_pcie_assert_reset(mp);
 
-       return dw_pcie_wait_for_link(pci);
-}
-
-static void meson_pcie_enable_interrupts(struct meson_pcie *mp)
-{
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(&mp->pci.pp);
+       return 0;
 }
 
-static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
-                                 u32 *val)
+static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
+                                 int where, int size, u32 *val)
 {
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        int ret;
 
-       ret = dw_pcie_read(pci->dbi_base + where, size, val);
+       ret = pci_generic_config_read(bus, devfn, where, size, val);
        if (ret != PCIBIOS_SUCCESSFUL)
                return ret;
 
@@ -410,13 +325,11 @@ static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
        return PCIBIOS_SUCCESSFUL;
 }
 
-static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where,
-                                 int size, u32 val)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-
-       return dw_pcie_write(pci->dbi_base + where, size, val);
-}
+static struct pci_ops meson_pci_ops = {
+       .map_bus = dw_pcie_own_conf_map_bus,
+       .read = meson_pcie_rd_own_conf,
+       .write = pci_generic_config_write,
+};
 
 static int meson_pcie_link_up(struct dw_pcie *pci)
 {
@@ -461,20 +374,16 @@ static int meson_pcie_host_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct meson_pcie *mp = to_meson_pcie(pci);
-       int ret;
 
-       ret = meson_pcie_establish_link(mp);
-       if (ret)
-               return ret;
+       pp->bridge->ops = &meson_pci_ops;
 
-       meson_pcie_enable_interrupts(mp);
+       meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
+       meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
 
        return 0;
 }
 
 static const struct dw_pcie_host_ops meson_pcie_host_ops = {
-       .rd_own_conf = meson_pcie_rd_own_conf,
-       .wr_own_conf = meson_pcie_wr_own_conf,
        .host_init = meson_pcie_host_init,
 };
 
@@ -486,14 +395,7 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
        struct device *dev = &pdev->dev;
        int ret;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI)) {
-               pp->msi_irq = platform_get_irq(pdev, 0);
-               if (pp->msi_irq < 0)
-                       return pp->msi_irq;
-       }
-
        pp->ops = &meson_pcie_host_ops;
-       pci->dbi_base = mp->mem_res.elbi_base;
 
        ret = dw_pcie_host_init(pp);
        if (ret) {
@@ -506,6 +408,7 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
 
 static const struct dw_pcie_ops dw_pcie_ops = {
        .link_up = meson_pcie_link_up,
+       .start_link = meson_pcie_start_link,
 };
 
 static int meson_pcie_probe(struct platform_device *pdev)
@@ -522,6 +425,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
        pci = &mp->pci;
        pci->dev = dev;
        pci->ops = &dw_pcie_ops;
+       pci->num_lanes = 1;
 
        mp->phy = devm_phy_get(dev, "pcie");
        if (IS_ERR(mp->phy)) {
@@ -589,6 +493,7 @@ static const struct of_device_id meson_pcie_of_match[] = {
        },
        {},
 };
+MODULE_DEVICE_TABLE(of, meson_pcie_of_match);
 
 static struct platform_driver meson_pcie_driver = {
        .probe = meson_pcie_probe,
@@ -598,4 +503,8 @@ static struct platform_driver meson_pcie_driver = {
        },
 };
 
-builtin_platform_driver(meson_pcie_driver);
+module_platform_driver(meson_pcie_driver);
+
+MODULE_AUTHOR("Yue Wang <yue.wang@amlogic.com>");
+MODULE_DESCRIPTION("Amlogic PCIe Controller driver");
+MODULE_LICENSE("GPL v2");