PCI: faraday: Add clock handling
authorLinus Walleij <linus.walleij@linaro.org>
Mon, 15 May 2017 17:23:24 +0000 (19:23 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Sun, 2 Jul 2017 23:42:35 +0000 (18:42 -0500)
Add some optional clock handling to the Faraday FTPCI100.  We just get and
prepare+enable the clocks right now, if they exist.  We can add more
elaborate clock handling later.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
[bhelgaas: folded in "Make clocks compulsory" fix from
http://lkml.kernel.org/r/20170621085730.28804-1-linus.walleij@linaro.org
Also folded in the clock max/cur speed fixes from
http://lkml.kernel.org/r/20170621162651.25315-1-linus.walleij@linaro.org]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/host/pci-ftpci100.c

index e938eebcb18058c3698df4baa3ad152809a2d042..5162dffc102b02c5241b1be909234f415736e67d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/bitops.h>
 #include <linux/irq.h>
+#include <linux/clk.h>
 
 /*
  * Special configuration registers directly in the first few words
@@ -37,6 +38,7 @@
 #define PCI_CONFIG     0x28 /* PCI configuration command register */
 #define PCI_DATA       0x2C
 
+#define FARADAY_PCI_STATUS_CMD         0x04 /* Status and command */
 #define FARADAY_PCI_PMC                        0x40 /* Power management control */
 #define FARADAY_PCI_PMCSR              0x44 /* Power management status */
 #define FARADAY_PCI_CTRL1              0x48 /* Control register 1 */
@@ -45,6 +47,8 @@
 #define FARADAY_PCI_MEM2_BASE_SIZE     0x54 /* Memory base and size #2 */
 #define FARADAY_PCI_MEM3_BASE_SIZE     0x58 /* Memory base and size #3 */
 
+#define PCI_STATUS_66MHZ_CAPABLE       BIT(21)
+
 /* Bits 31..28 gives INTD..INTA status */
 #define PCI_CTRL2_INTSTS_SHIFT         28
 #define PCI_CTRL2_INTMASK_CMDERR       BIT(27)
@@ -117,6 +121,7 @@ struct faraday_pci {
        void __iomem *base;
        struct irq_domain *irqdomain;
        struct pci_bus *bus;
+       struct clk *bus_clk;
 };
 
 static int faraday_res_to_memcfg(resource_size_t mem_base,
@@ -444,6 +449,9 @@ static int faraday_pci_probe(struct platform_device *pdev)
        struct resource *mem;
        struct resource *io;
        struct pci_host_bridge *host;
+       struct clk *clk;
+       unsigned char max_bus_speed = PCI_SPEED_33MHz;
+       unsigned char cur_bus_speed = PCI_SPEED_33MHz;
        int ret;
        u32 val;
        LIST_HEAD(res);
@@ -462,6 +470,24 @@ static int faraday_pci_probe(struct platform_device *pdev)
        host->sysdata = p;
        p->dev = dev;
 
+       /* Retrieve and enable optional clocks */
+       clk = devm_clk_get(dev, "PCLK");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+       ret = clk_prepare_enable(clk);
+       if (ret) {
+               dev_err(dev, "could not prepare PCLK\n");
+               return ret;
+       }
+       p->bus_clk = devm_clk_get(dev, "PCICLK");
+       if (IS_ERR(p->bus_clk))
+               return PTR_ERR(clk);
+       ret = clk_prepare_enable(p->bus_clk);
+       if (ret) {
+               dev_err(dev, "could not prepare PCICLK\n");
+               return ret;
+       }
+
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        p->base = devm_ioremap_resource(dev, regs);
        if (IS_ERR(p->base))
@@ -524,6 +550,34 @@ static int faraday_pci_probe(struct platform_device *pdev)
                }
        }
 
+       /* Check bus clock if we can gear up to 66 MHz */
+       if (!IS_ERR(p->bus_clk)) {
+               unsigned long rate;
+               u32 val;
+
+               faraday_raw_pci_read_config(p, 0, 0,
+                                           FARADAY_PCI_STATUS_CMD, 4, &val);
+               rate = clk_get_rate(p->bus_clk);
+
+               if ((rate == 33000000) && (val & PCI_STATUS_66MHZ_CAPABLE)) {
+                       dev_info(dev, "33MHz bus is 66MHz capable\n");
+                       max_bus_speed = PCI_SPEED_66MHz;
+                       ret = clk_set_rate(p->bus_clk, 66000000);
+                       if (ret)
+                               dev_err(dev, "failed to set bus clock\n");
+               } else {
+                       dev_info(dev, "33MHz only bus\n");
+                       max_bus_speed = PCI_SPEED_33MHz;
+               }
+
+               /* Bumping the clock may fail so read back the rate */
+               rate = clk_get_rate(p->bus_clk);
+               if (rate == 33000000)
+                       cur_bus_speed = PCI_SPEED_33MHz;
+               if (rate == 66000000)
+                       cur_bus_speed = PCI_SPEED_66MHz;
+       }
+
        ret = faraday_pci_parse_map_dma_ranges(p, dev->of_node);
        if (ret)
                return ret;
@@ -535,6 +589,8 @@ static int faraday_pci_probe(struct platform_device *pdev)
                return ret;
        }
        p->bus = host->bus;
+       p->bus->max_bus_speed = max_bus_speed;
+       p->bus->cur_bus_speed = cur_bus_speed;
 
        pci_bus_assign_resources(p->bus);
        pci_bus_add_devices(p->bus);