PCI: faraday: Add clock handling

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>
This commit is contained in:
Linus Walleij 2017-05-15 19:23:24 +02:00 committed by Bjorn Helgaas
parent d1ef28900d
commit 2eeb02b285

View File

@ -25,6 +25,7 @@
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/clk.h>
/* /*
* Special configuration registers directly in the first few words * Special configuration registers directly in the first few words
@ -37,6 +38,7 @@
#define PCI_CONFIG 0x28 /* PCI configuration command register */ #define PCI_CONFIG 0x28 /* PCI configuration command register */
#define PCI_DATA 0x2C #define PCI_DATA 0x2C
#define FARADAY_PCI_STATUS_CMD 0x04 /* Status and command */
#define FARADAY_PCI_PMC 0x40 /* Power management control */ #define FARADAY_PCI_PMC 0x40 /* Power management control */
#define FARADAY_PCI_PMCSR 0x44 /* Power management status */ #define FARADAY_PCI_PMCSR 0x44 /* Power management status */
#define FARADAY_PCI_CTRL1 0x48 /* Control register 1 */ #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_MEM2_BASE_SIZE 0x54 /* Memory base and size #2 */
#define FARADAY_PCI_MEM3_BASE_SIZE 0x58 /* Memory base and size #3 */ #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 */ /* Bits 31..28 gives INTD..INTA status */
#define PCI_CTRL2_INTSTS_SHIFT 28 #define PCI_CTRL2_INTSTS_SHIFT 28
#define PCI_CTRL2_INTMASK_CMDERR BIT(27) #define PCI_CTRL2_INTMASK_CMDERR BIT(27)
@ -117,6 +121,7 @@ struct faraday_pci {
void __iomem *base; void __iomem *base;
struct irq_domain *irqdomain; struct irq_domain *irqdomain;
struct pci_bus *bus; struct pci_bus *bus;
struct clk *bus_clk;
}; };
static int faraday_res_to_memcfg(resource_size_t mem_base, 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 *mem;
struct resource *io; struct resource *io;
struct pci_host_bridge *host; 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; int ret;
u32 val; u32 val;
LIST_HEAD(res); LIST_HEAD(res);
@ -462,6 +470,24 @@ static int faraday_pci_probe(struct platform_device *pdev)
host->sysdata = p; host->sysdata = p;
p->dev = dev; 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); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
p->base = devm_ioremap_resource(dev, regs); p->base = devm_ioremap_resource(dev, regs);
if (IS_ERR(p->base)) 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); ret = faraday_pci_parse_map_dma_ranges(p, dev->of_node);
if (ret) if (ret)
return ret; return ret;
@ -535,6 +589,8 @@ static int faraday_pci_probe(struct platform_device *pdev)
return ret; return ret;
} }
p->bus = host->bus; 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_assign_resources(p->bus);
pci_bus_add_devices(p->bus); pci_bus_add_devices(p->bus);