Skip to content

Commit

Permalink
PCI: rcar: Allow DT to override default window settings
Browse files Browse the repository at this point in the history
If the DTB specifies dma-ranges, use those values.  Otherwise, default to
the values that were previously hardcoded into the driver.

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Simon Horman <horms+renesas@verge.net.au>
  • Loading branch information
Phil Edworthy authored and Bjorn Helgaas committed Nov 25, 2015
1 parent 1ec2183 commit 8d598ca
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 3 deletions.
6 changes: 6 additions & 0 deletions Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ Required properties:
- interrupt-map-mask: standard property that helps to define the interrupt
mapping.

Optional properties:
- dma-ranges: a single range for the inbound memory region. If not supplied,
defaults to 1GiB at 0x40000000. Note there are hardware restrictions on the
allowed combinations of address and size.

Example SoC configuration:

pci0: pci@ee090000 {
Expand All @@ -38,6 +43,7 @@ Example SoC configuration:
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>;
interrupt-map-mask = <0xff00 0 0 0x7>;
interrupt-map = <0x0000 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
0x0800 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
Expand Down
76 changes: 73 additions & 3 deletions drivers/pci/host/pci-rcar-gen2.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
Expand Down Expand Up @@ -102,6 +103,8 @@ struct rcar_pci_priv {
unsigned busnr;
int irq;
unsigned long window_size;
unsigned long window_addr;
unsigned long window_pci;
};

/* PCI configuration space operations */
Expand Down Expand Up @@ -239,8 +242,8 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
RCAR_PCI_ARBITER_PCIBP_MODE;
iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);

/* PCI-AHB mapping: 0x40000000 base */
iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
/* PCI-AHB mapping */
iowrite32(priv->window_addr | RCAR_PCIAHB_PREFETCH16,
reg + RCAR_PCIAHB_WIN1_CTR_REG);

/* AHB-PCI mapping: OHCI/EHCI registers */
Expand All @@ -251,7 +254,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
reg + RCAR_AHBPCI_WIN1_CTR_REG);
/* Set PCI-AHB Window1 address */
iowrite32(0x40000000 | PCI_BASE_ADDRESS_MEM_PREFETCH,
iowrite32(priv->window_pci | PCI_BASE_ADDRESS_MEM_PREFETCH,
reg + PCI_BASE_ADDRESS_1);
/* Set AHB-PCI bridge PCI communication area address */
val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
Expand Down Expand Up @@ -284,6 +287,64 @@ static struct pci_ops rcar_pci_ops = {
.write = pci_generic_config_write,
};

static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node)
{
const int na = 3, ns = 2;
int rlen;

parser->node = node;
parser->pna = of_n_addr_cells(node);
parser->np = parser->pna + na + ns;

parser->range = of_get_property(node, "dma-ranges", &rlen);
if (!parser->range)
return -ENOENT;

parser->end = parser->range + rlen / sizeof(__be32);
return 0;
}

static int rcar_pci_parse_map_dma_ranges(struct rcar_pci_priv *pci,
struct device_node *np)
{
struct of_pci_range range;
struct of_pci_range_parser parser;
int index = 0;

/* Failure to parse is ok as we fall back to defaults */
if (pci_dma_range_parser_init(&parser, np))
return 0;

/* Get the dma-ranges from DT */
for_each_of_pci_range(&parser, &range) {
/* Hardware only allows one inbound 32-bit range */
if (index)
return -EINVAL;

pci->window_addr = (unsigned long)range.cpu_addr;
pci->window_pci = (unsigned long)range.pci_addr;
pci->window_size = (unsigned long)range.size;

/* Catch HW limitations */
if (!(range.flags & IORESOURCE_PREFETCH)) {
dev_err(pci->dev, "window must be prefetchable\n");
return -EINVAL;
}
if (pci->window_addr) {
u32 lowaddr = 1 << (ffs(pci->window_addr) - 1);

if (lowaddr < pci->window_size) {
dev_err(pci->dev, "invalid window size/addr\n");
return -EINVAL;
}
}
index++;
}

return 0;
}

static int rcar_pci_probe(struct platform_device *pdev)
{
struct resource *cfg_res, *mem_res;
Expand Down Expand Up @@ -329,6 +390,9 @@ static int rcar_pci_probe(struct platform_device *pdev)
return priv->irq;
}

/* default window addr and size if not specified in DT */
priv->window_addr = 0x40000000;
priv->window_pci = 0x40000000;
priv->window_size = SZ_1G;

if (pdev->dev.of_node) {
Expand All @@ -344,6 +408,12 @@ static int rcar_pci_probe(struct platform_device *pdev)
priv->busnr = busnr.start;
if (busnr.end != busnr.start)
dev_warn(&pdev->dev, "only one bus number supported\n");

ret = rcar_pci_parse_map_dma_ranges(priv, pdev->dev.of_node);
if (ret < 0) {
dev_err(&pdev->dev, "failed to parse dma-range\n");
return ret;
}
} else {
priv->busnr = pdev->id;
}
Expand Down

0 comments on commit 8d598ca

Please sign in to comment.