|
@@ -13,8 +13,12 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/mm.h>
|
|
|
#include <linux/vmalloc.h>
|
|
|
-#include <linux/export.h>
|
|
|
-#include <linux/platform_device.h>
|
|
|
+#include <linux/module.h>
|
|
|
+#include <linux/clk.h>
|
|
|
+#include <linux/of_platform.h>
|
|
|
+#include <linux/of_gpio.h>
|
|
|
+#include <linux/of_irq.h>
|
|
|
+#include <linux/of_pci.h>
|
|
|
|
|
|
#include <asm/pci.h>
|
|
|
#include <asm/gpio.h>
|
|
@@ -22,17 +26,9 @@
|
|
|
|
|
|
#include <lantiq_soc.h>
|
|
|
#include <lantiq_irq.h>
|
|
|
-#include <lantiq_platform.h>
|
|
|
|
|
|
#include "pci-lantiq.h"
|
|
|
|
|
|
-#define LTQ_PCI_CFG_BASE 0x17000000
|
|
|
-#define LTQ_PCI_CFG_SIZE 0x00008000
|
|
|
-#define LTQ_PCI_MEM_BASE 0x18000000
|
|
|
-#define LTQ_PCI_MEM_SIZE 0x02000000
|
|
|
-#define LTQ_PCI_IO_BASE 0x1AE00000
|
|
|
-#define LTQ_PCI_IO_SIZE 0x00200000
|
|
|
-
|
|
|
#define PCI_CR_FCI_ADDR_MAP0 0x00C0
|
|
|
#define PCI_CR_FCI_ADDR_MAP1 0x00C4
|
|
|
#define PCI_CR_FCI_ADDR_MAP2 0x00C8
|
|
@@ -71,50 +67,24 @@
|
|
|
__iomem void *ltq_pci_mapped_cfg;
|
|
|
static __iomem void *ltq_pci_membase;
|
|
|
|
|
|
-int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
|
|
|
-
|
|
|
-/* Since the PCI REQ pins can be reused for other functionality, make it
|
|
|
- possible to exclude those from interpretation by the PCI controller */
|
|
|
-static int ltq_pci_req_mask = 0xf;
|
|
|
-
|
|
|
-static int *ltq_pci_irq_map;
|
|
|
-
|
|
|
-struct pci_ops ltq_pci_ops = {
|
|
|
+static int reset_gpio;
|
|
|
+static struct clk *clk_pci, *clk_external;
|
|
|
+static struct resource pci_io_resource;
|
|
|
+static struct resource pci_mem_resource;
|
|
|
+static struct pci_ops pci_ops = {
|
|
|
.read = ltq_pci_read_config_dword,
|
|
|
.write = ltq_pci_write_config_dword
|
|
|
};
|
|
|
|
|
|
-static struct resource pci_io_resource = {
|
|
|
- .name = "pci io space",
|
|
|
- .start = LTQ_PCI_IO_BASE,
|
|
|
- .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1,
|
|
|
- .flags = IORESOURCE_IO
|
|
|
-};
|
|
|
-
|
|
|
-static struct resource pci_mem_resource = {
|
|
|
- .name = "pci memory space",
|
|
|
- .start = LTQ_PCI_MEM_BASE,
|
|
|
- .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1,
|
|
|
- .flags = IORESOURCE_MEM
|
|
|
-};
|
|
|
-
|
|
|
-static struct pci_controller ltq_pci_controller = {
|
|
|
- .pci_ops = <q_pci_ops,
|
|
|
+static struct pci_controller pci_controller = {
|
|
|
+ .pci_ops = &pci_ops,
|
|
|
.mem_resource = &pci_mem_resource,
|
|
|
.mem_offset = 0x00000000UL,
|
|
|
.io_resource = &pci_io_resource,
|
|
|
.io_offset = 0x00000000UL,
|
|
|
};
|
|
|
|
|
|
-int pcibios_plat_dev_init(struct pci_dev *dev)
|
|
|
-{
|
|
|
- if (ltqpci_plat_dev_init)
|
|
|
- return ltqpci_plat_dev_init(dev);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static u32 ltq_calc_bar11mask(void)
|
|
|
+static inline u32 ltq_calc_bar11mask(void)
|
|
|
{
|
|
|
u32 mem, bar11mask;
|
|
|
|
|
@@ -125,32 +95,42 @@ static u32 ltq_calc_bar11mask(void)
|
|
|
return bar11mask;
|
|
|
}
|
|
|
|
|
|
-static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
|
|
|
+static int __devinit ltq_pci_startup(struct platform_device *pdev)
|
|
|
{
|
|
|
+ struct device_node *node = pdev->dev.of_node;
|
|
|
+ const __be32 *req_mask, *bus_clk;
|
|
|
u32 temp_buffer;
|
|
|
|
|
|
- /* set clock to 33Mhz */
|
|
|
- if (ltq_is_ar9()) {
|
|
|
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0x1f00000, LTQ_CGU_IFCCR);
|
|
|
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0xe00000, LTQ_CGU_IFCCR);
|
|
|
- } else {
|
|
|
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
|
|
|
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
|
|
|
+ /* get our clocks */
|
|
|
+ clk_pci = clk_get(&pdev->dev, NULL);
|
|
|
+ if (IS_ERR(clk_pci)) {
|
|
|
+ dev_err(&pdev->dev, "failed to get pci clock\n");
|
|
|
+ return PTR_ERR(clk_pci);
|
|
|
}
|
|
|
|
|
|
- /* external or internal clock ? */
|
|
|
- if (conf->clock) {
|
|
|
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16),
|
|
|
- LTQ_CGU_IFCCR);
|
|
|
- ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR);
|
|
|
- } else {
|
|
|
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16),
|
|
|
- LTQ_CGU_IFCCR);
|
|
|
- ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR);
|
|
|
+ clk_external = clk_get(&pdev->dev, "external");
|
|
|
+ if (IS_ERR(clk_external)) {
|
|
|
+ clk_put(clk_pci);
|
|
|
+ dev_err(&pdev->dev, "failed to get external pci clock\n");
|
|
|
+ return PTR_ERR(clk_external);
|
|
|
}
|
|
|
|
|
|
- /* setup pci clock and gpis used by pci */
|
|
|
- gpio_request(21, "pci-reset");
|
|
|
+ /* read the bus speed that we want */
|
|
|
+ bus_clk = of_get_property(node, "lantiq,bus-clock", NULL);
|
|
|
+ if (bus_clk)
|
|
|
+ clk_set_rate(clk_pci, *bus_clk);
|
|
|
+
|
|
|
+ /* and enable the clocks */
|
|
|
+ clk_enable(clk_pci);
|
|
|
+ if (of_find_property(node, "lantiq,external-clock", NULL))
|
|
|
+ clk_enable(clk_external);
|
|
|
+ else
|
|
|
+ clk_disable(clk_external);
|
|
|
+
|
|
|
+ /* setup reset gpio used by pci */
|
|
|
+ reset_gpio = of_get_named_gpio(node, "gpio-reset", 0);
|
|
|
+ if (reset_gpio > 0)
|
|
|
+ devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset");
|
|
|
|
|
|
/* enable auto-switching between PCI and EBU */
|
|
|
ltq_pci_w32(0xa, PCI_CR_CLK_CTRL);
|
|
@@ -163,7 +143,12 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
|
|
|
|
|
|
/* enable external 2 PCI masters */
|
|
|
temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB);
|
|
|
- temp_buffer &= (~(ltq_pci_req_mask << 16));
|
|
|
+ /* setup the request mask */
|
|
|
+ req_mask = of_get_property(node, "req-mask", NULL);
|
|
|
+ if (req_mask)
|
|
|
+ temp_buffer &= ~((*req_mask & 0xf) << 16);
|
|
|
+ else
|
|
|
+ temp_buffer &= ~0xf0000;
|
|
|
/* enable internal arbiter */
|
|
|
temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
|
|
|
/* enable internal PCI master reqest */
|
|
@@ -207,47 +192,55 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
|
|
|
ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
|
|
|
|
|
|
/* toggle reset pin */
|
|
|
- __gpio_set_value(21, 0);
|
|
|
- wmb();
|
|
|
- mdelay(1);
|
|
|
- __gpio_set_value(21, 1);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
|
-{
|
|
|
- if (ltq_pci_irq_map[slot])
|
|
|
- return ltq_pci_irq_map[slot];
|
|
|
- printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n",
|
|
|
- slot);
|
|
|
-
|
|
|
+ if (reset_gpio > 0) {
|
|
|
+ __gpio_set_value(reset_gpio, 0);
|
|
|
+ wmb();
|
|
|
+ mdelay(1);
|
|
|
+ __gpio_set_value(reset_gpio, 1);
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int __devinit ltq_pci_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct ltq_pci_data *ltq_pci_data =
|
|
|
- (struct ltq_pci_data *) pdev->dev.platform_data;
|
|
|
+ struct resource *res_cfg, *res_bridge;
|
|
|
|
|
|
pci_clear_flags(PCI_PROBE_ONLY);
|
|
|
- ltq_pci_irq_map = ltq_pci_data->irq;
|
|
|
- ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
|
|
|
- ltq_pci_mapped_cfg =
|
|
|
- ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE);
|
|
|
- ltq_pci_controller.io_map_base =
|
|
|
- (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1);
|
|
|
- ltq_pci_startup(ltq_pci_data);
|
|
|
- register_pci_controller(<q_pci_controller);
|
|
|
|
|
|
+ res_cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
+ res_bridge = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
|
|
+ if (!res_cfg || !res_bridge) {
|
|
|
+ dev_err(&pdev->dev, "missing memory reources\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ltq_pci_membase = devm_request_and_ioremap(&pdev->dev, res_bridge);
|
|
|
+ ltq_pci_mapped_cfg = devm_request_and_ioremap(&pdev->dev, res_cfg);
|
|
|
+
|
|
|
+ if (!ltq_pci_membase || !ltq_pci_mapped_cfg) {
|
|
|
+ dev_err(&pdev->dev, "failed to remap resources\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ ltq_pci_startup(pdev);
|
|
|
+
|
|
|
+ pci_load_of_ranges(&pci_controller, pdev->dev.of_node);
|
|
|
+ register_pci_controller(&pci_controller);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static struct platform_driver
|
|
|
-ltq_pci_driver = {
|
|
|
+static const struct of_device_id ltq_pci_match[] = {
|
|
|
+ { .compatible = "lantiq,pci-xway" },
|
|
|
+ {},
|
|
|
+};
|
|
|
+MODULE_DEVICE_TABLE(of, ltq_pci_match);
|
|
|
+
|
|
|
+static struct platform_driver ltq_pci_driver = {
|
|
|
.probe = ltq_pci_probe,
|
|
|
.driver = {
|
|
|
- .name = "ltq_pci",
|
|
|
+ .name = "pci-xway",
|
|
|
.owner = THIS_MODULE,
|
|
|
+ .of_match_table = ltq_pci_match,
|
|
|
},
|
|
|
};
|
|
|
|
|
@@ -255,7 +248,7 @@ int __init pcibios_init(void)
|
|
|
{
|
|
|
int ret = platform_driver_register(<q_pci_driver);
|
|
|
if (ret)
|
|
|
- printk(KERN_INFO "ltq_pci: Error registering platfom driver!");
|
|
|
+ pr_info("pci-xway: Error registering platform driver!");
|
|
|
return ret;
|
|
|
}
|
|
|
|