From 29b635c00f3ebcdaf7a52c4948f6d948ad3757d3 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 16 May 2013 17:55:17 +0200 Subject: of/pci: Provide support for parsing PCI DT ranges property This patch factors out common implementation patterns to reduce overall kernel code and provide a means for host bridge drivers to directly obtain struct resources from the DT's ranges property without relying on architecture specific DT handling. This will make it easier to write archiecture independent host bridge drivers and mitigate against further duplication of DT parsing code. This patch can be used in the following way: struct of_pci_range_parser parser; struct of_pci_range range; if (of_pci_range_parser_init(&parser, np)) ; //no ranges property for_each_of_pci_range(&parser, &range) { /* directly access properties of the address range, e.g.: range.pci_space, range.pci_addr, range.cpu_addr, range.size, range.flags alternatively obtain a struct resource, e.g.: struct resource res; of_pci_range_to_resource(&range, np, &res); */ } Additionally the implementation takes care of adjacent ranges and merges them into a single range (as was the case with powerpc and microblaze). Signed-off-by: Andrew Murray Signed-off-by: Liviu Dudau Signed-off-by: Thomas Petazzoni Reviewed-by: Rob Herring Tested-by: Thomas Petazzoni Tested-by: Linus Walleij Tested-by: Jingoo Han Acked-by: Grant Likely Signed-off-by: Jason Cooper --- include/linux/of_address.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'include/linux') diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 0506eb53519b..4c2e6f26432c 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -4,6 +4,36 @@ #include #include +struct of_pci_range_parser { + struct device_node *node; + const __be32 *range; + const __be32 *end; + int np; + int pna; +}; + +struct of_pci_range { + u32 pci_space; + u64 pci_addr; + u64 cpu_addr; + u64 size; + u32 flags; +}; + +#define for_each_of_pci_range(parser, range) \ + for (; of_pci_range_parser_one(parser, range);) + +static inline void of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res) +{ + res->flags = range->flags; + res->start = range->cpu_addr; + res->end = range->cpu_addr + range->size - 1; + res->parent = res->child = res->sibling = NULL; + res->name = np->full_name; +} + #ifdef CONFIG_OF_ADDRESS extern u64 of_translate_address(struct device_node *np, const __be32 *addr); extern bool of_can_translate_address(struct device_node *dev); @@ -27,6 +57,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } #define pci_address_to_pio pci_address_to_pio #endif +extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node); +extern struct of_pci_range *of_pci_range_parser_one( + struct of_pci_range_parser *parser, + struct of_pci_range *range); #else /* CONFIG_OF_ADDRESS */ #ifndef of_address_to_resource static inline int of_address_to_resource(struct device_node *dev, int index, @@ -53,6 +88,19 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index, { return NULL; } + +static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node) +{ + return -1; +} + +static inline struct of_pci_range *of_pci_range_parser_one( + struct of_pci_range_parser *parser, + struct of_pci_range *range) +{ + return NULL; +} #endif /* CONFIG_OF_ADDRESS */ -- cgit v1.2.3 From 45ab9702fb47d18dca116b3a0509efa19fbcb27a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 16 May 2013 17:55:18 +0200 Subject: of/pci: Add of_pci_get_devfn() function This function can be used to parse the device and function number from a standard 5-cell PCI resource. PCI_SLOT() and PCI_FUNC() can be used on the returned value obtain the device and function numbers respectively. Signed-off-by: Thierry Reding Signed-off-by: Thomas Petazzoni Signed-off-by: Jason Cooper --- drivers/of/of_pci.c | 34 +++++++++++++++++++++++++++++----- include/linux/of_pci.h | 1 + 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 13e37e2d8ec1..4dd7b9b80076 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -5,14 +5,15 @@ #include static inline int __of_pci_pci_compare(struct device_node *node, - unsigned int devfn) + unsigned int data) { - unsigned int size; - const __be32 *reg = of_get_property(node, "reg", &size); + int devfn; - if (!reg || size < 5 * sizeof(__be32)) + devfn = of_pci_get_devfn(node); + if (devfn < 0) return 0; - return ((be32_to_cpup(®[0]) >> 8) & 0xff) == devfn; + + return devfn == data; } struct device_node *of_pci_find_child_device(struct device_node *parent, @@ -40,3 +41,26 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, return NULL; } EXPORT_SYMBOL_GPL(of_pci_find_child_device); + +/** + * of_pci_get_devfn() - Get device and function numbers for a device node + * @np: device node + * + * Parses a standard 5-cell PCI resource and returns an 8-bit value that can + * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device + * and function numbers respectively. On error a negative error code is + * returned. + */ +int of_pci_get_devfn(struct device_node *np) +{ + unsigned int size; + const __be32 *reg; + + reg = of_get_property(np, "reg", &size); + + if (!reg || size < 5 * sizeof(__be32)) + return -EINVAL; + + return (be32_to_cpup(reg) >> 8) & 0xff; +} +EXPORT_SYMBOL_GPL(of_pci_get_devfn); diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index bb115deb7612..91ec484e0045 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -10,5 +10,6 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq); struct device_node; struct device_node *of_pci_find_child_device(struct device_node *parent, unsigned int devfn); +int of_pci_get_devfn(struct device_node *np); #endif -- cgit v1.2.3 From 4e23d3f505e8acfeac7cc33d4113fbb5a25c3090 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 16 May 2013 17:55:19 +0200 Subject: of/pci: Add of_pci_parse_bus_range() function This function can be used to parse a bus-range property as specified by device nodes representing PCI bridges. Signed-off-by: Thierry Reding Signed-off-by: Jason Cooper --- drivers/of/of_pci.c | 25 +++++++++++++++++++++++++ include/linux/of_pci.h | 1 + 2 files changed, 26 insertions(+) (limited to 'include/linux') diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 4dd7b9b80076..42c687a820ac 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -64,3 +64,28 @@ int of_pci_get_devfn(struct device_node *np) return (be32_to_cpup(reg) >> 8) & 0xff; } EXPORT_SYMBOL_GPL(of_pci_get_devfn); + +/** + * of_pci_parse_bus_range() - parse the bus-range property of a PCI device + * @node: device node + * @res: address to a struct resource to return the bus-range + * + * Returns 0 on success or a negative error-code on failure. + */ +int of_pci_parse_bus_range(struct device_node *node, struct resource *res) +{ + const __be32 *values; + int len; + + values = of_get_property(node, "bus-range", &len); + if (!values || len < sizeof(*values) * 2) + return -EINVAL; + + res->name = node->name; + res->start = be32_to_cpup(values++); + res->end = be32_to_cpup(values); + res->flags = IORESOURCE_BUS; + + return 0; +} +EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 91ec484e0045..7a04826018c0 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -11,5 +11,6 @@ struct device_node; struct device_node *of_pci_find_child_device(struct device_node *parent, unsigned int devfn); int of_pci_get_devfn(struct device_node *np); +int of_pci_parse_bus_range(struct device_node *node, struct resource *res); #endif -- cgit v1.2.3 From 82c5cde1c4b01a62c9a19c9118b4b434c333ce86 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 30 May 2013 12:53:07 -0700 Subject: ARM: OMAP2+: Remove omap4 ocp2scp pdata This is omap4+ only and no longer needed as omap4+ can be booted using device tree. Also remove the related pdata handling from the driver and the now unneeded platform_data/omap_ocp2scp.h. Cc: Arnd Bergmann Cc: Olof Johansson Reviewed-by: Kishon Vijay Abraham I Acked-by: Felipe Balbi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/devices.c | 78 ------------------------------ arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 21 -------- drivers/bus/omap-ocp2scp.c | 60 ----------------------- include/linux/platform_data/omap_ocp2scp.h | 31 ------------ 4 files changed, 190 deletions(-) delete mode 100644 include/linux/platform_data/omap_ocp2scp.h (limited to 'include/linux') diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 350116906f18..721da484d8ec 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -515,82 +514,6 @@ static void omap_init_vout(void) static inline void omap_init_vout(void) {} #endif -#if defined(CONFIG_OMAP_OCP2SCP) || defined(CONFIG_OMAP_OCP2SCP_MODULE) -static int count_ocp2scp_devices(struct omap_ocp2scp_dev *ocp2scp_dev) -{ - int cnt = 0; - - while (ocp2scp_dev->drv_name != NULL) { - cnt++; - ocp2scp_dev++; - } - - return cnt; -} - -static void __init omap_init_ocp2scp(void) -{ - struct omap_hwmod *oh; - struct platform_device *pdev; - int bus_id = -1, dev_cnt = 0, i; - struct omap_ocp2scp_dev *ocp2scp_dev; - const char *oh_name, *name; - struct omap_ocp2scp_platform_data *pdata; - - if (!cpu_is_omap44xx()) - return; - - oh_name = "ocp2scp_usb_phy"; - name = "omap-ocp2scp"; - - oh = omap_hwmod_lookup(oh_name); - if (!oh) { - pr_err("%s: could not find omap_hwmod for %s\n", __func__, - oh_name); - return; - } - - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - pr_err("%s: No memory for ocp2scp pdata\n", __func__); - return; - } - - ocp2scp_dev = oh->dev_attr; - dev_cnt = count_ocp2scp_devices(ocp2scp_dev); - - if (!dev_cnt) { - pr_err("%s: No devices connected to ocp2scp\n", __func__); - kfree(pdata); - return; - } - - pdata->devices = kzalloc(sizeof(struct omap_ocp2scp_dev *) - * dev_cnt, GFP_KERNEL); - if (!pdata->devices) { - pr_err("%s: No memory for ocp2scp pdata devices\n", __func__); - kfree(pdata); - return; - } - - for (i = 0; i < dev_cnt; i++, ocp2scp_dev++) - pdata->devices[i] = ocp2scp_dev; - - pdata->dev_cnt = dev_cnt; - - pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata)); - if (IS_ERR(pdev)) { - pr_err("Could not build omap_device for %s %s\n", - name, oh_name); - kfree(pdata->devices); - kfree(pdata); - return; - } -} -#else -static inline void omap_init_ocp2scp(void) { } -#endif - #if IS_ENABLED(CONFIG_WL12XX) static struct wl12xx_platform_data wl12xx __initdata; @@ -655,7 +578,6 @@ static int __init omap2_init_devices(void) omap_init_sti(); omap_init_rng(); omap_init_vout(); - omap_init_ocp2scp(); return 0; } diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 848b6dc67590..d6dd70728c61 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -2695,25 +2694,6 @@ static struct omap_hwmod_class omap44xx_ocp2scp_hwmod_class = { .sysc = &omap44xx_ocp2scp_sysc, }; -/* ocp2scp dev_attr */ -static struct resource omap44xx_usb_phy_and_pll_addrs[] = { - { - .name = "usb_phy", - .start = 0x4a0ad080, - .end = 0x4a0ae000, - .flags = IORESOURCE_MEM, - }, - { } -}; - -static struct omap_ocp2scp_dev ocp2scp_dev_attr[] = { - { - .drv_name = "omap-usb2", - .res = omap44xx_usb_phy_and_pll_addrs, - }, - { } -}; - /* ocp2scp_usb_phy */ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = { .name = "ocp2scp_usb_phy", @@ -2737,7 +2717,6 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = { .modulemode = MODULEMODE_HWCTRL, }, }, - .dev_attr = ocp2scp_dev_attr, }; /* diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c index fe7191663bbd..5511f9814ddd 100644 --- a/drivers/bus/omap-ocp2scp.c +++ b/drivers/bus/omap-ocp2scp.c @@ -22,26 +22,6 @@ #include #include #include -#include - -/** - * _count_resources - count for the number of resources - * @res: struct resource * - * - * Count and return the number of resources populated for the device that is - * connected to ocp2scp. - */ -static unsigned _count_resources(struct resource *res) -{ - int cnt = 0; - - while (res->start != res->end) { - cnt++; - res++; - } - - return cnt; -} static int ocp2scp_remove_devices(struct device *dev, void *c) { @@ -55,11 +35,7 @@ static int ocp2scp_remove_devices(struct device *dev, void *c) static int omap_ocp2scp_probe(struct platform_device *pdev) { int ret; - unsigned res_cnt, i; struct device_node *np = pdev->dev.of_node; - struct platform_device *pdev_child; - struct omap_ocp2scp_platform_data *pdata = pdev->dev.platform_data; - struct omap_ocp2scp_dev *dev; if (np) { ret = of_platform_populate(np, NULL, NULL, &pdev->dev); @@ -68,48 +44,12 @@ static int omap_ocp2scp_probe(struct platform_device *pdev) "failed to add resources for ocp2scp child\n"); goto err0; } - } else if (pdata) { - for (i = 0, dev = *pdata->devices; i < pdata->dev_cnt; i++, - dev++) { - res_cnt = _count_resources(dev->res); - - pdev_child = platform_device_alloc(dev->drv_name, - PLATFORM_DEVID_AUTO); - if (!pdev_child) { - dev_err(&pdev->dev, - "failed to allocate mem for ocp2scp child\n"); - goto err0; - } - - ret = platform_device_add_resources(pdev_child, - dev->res, res_cnt); - if (ret) { - dev_err(&pdev->dev, - "failed to add resources for ocp2scp child\n"); - goto err1; - } - - pdev_child->dev.parent = &pdev->dev; - - ret = platform_device_add(pdev_child); - if (ret) { - dev_err(&pdev->dev, - "failed to register ocp2scp child device\n"); - goto err1; - } - } - } else { - dev_err(&pdev->dev, "OCP2SCP initialized without plat data\n"); - return -EINVAL; } pm_runtime_enable(&pdev->dev); return 0; -err1: - platform_device_put(pdev_child); - err0: device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); diff --git a/include/linux/platform_data/omap_ocp2scp.h b/include/linux/platform_data/omap_ocp2scp.h deleted file mode 100644 index 5c6c3939355f..000000000000 --- a/include/linux/platform_data/omap_ocp2scp.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * omap_ocp2scp.h -- ocp2scp header file - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Author: Kishon Vijay Abraham I - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __DRIVERS_OMAP_OCP2SCP_H -#define __DRIVERS_OMAP_OCP2SCP_H - -struct omap_ocp2scp_dev { - const char *drv_name; - struct resource *res; -}; - -struct omap_ocp2scp_platform_data { - int dev_cnt; - struct omap_ocp2scp_dev **devices; -}; -#endif /* __DRIVERS_OMAP_OCP2SCP_H */ -- cgit v1.2.3