1af6074fcSRob Herring // SPDX-License-Identifier: GPL-2.0 2606ad42aSRob Herring #define pr_fmt(fmt) "OF: " fmt 3606ad42aSRob Herring 45019f0b1SArnd Bergmann #include <linux/device.h> 5fcfaab30SGabriele Paoloni #include <linux/fwnode.h> 66b884a8dSGrant Likely #include <linux/io.h> 76b884a8dSGrant Likely #include <linux/ioport.h> 865af618dSZhichang Yuan #include <linux/logic_pio.h> 9dbbdee94SGrant Likely #include <linux/module.h> 106b884a8dSGrant Likely #include <linux/of_address.h> 11c5076cfeSTomasz Nowicki #include <linux/pci.h> 12dbbdee94SGrant Likely #include <linux/pci_regs.h> 1341f8bba7SLiviu Dudau #include <linux/sizes.h> 1441f8bba7SLiviu Dudau #include <linux/slab.h> 15dbbdee94SGrant Likely #include <linux/string.h> 166b884a8dSGrant Likely 17dbbdee94SGrant Likely /* Max address size we deal with */ 18dbbdee94SGrant Likely #define OF_MAX_ADDR_CELLS 4 195d61b165SStephen Warren #define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) 205d61b165SStephen Warren #define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0) 21dbbdee94SGrant Likely 22dbbdee94SGrant Likely static struct of_bus *of_match_bus(struct device_node *np); 230131d897SSebastian Andrzej Siewior static int __of_address_to_resource(struct device_node *dev, 240131d897SSebastian Andrzej Siewior const __be32 *addrp, u64 size, unsigned int flags, 2535f3da32SBenoit Cousson const char *name, struct resource *r); 26dbbdee94SGrant Likely 27dbbdee94SGrant Likely /* Debug utility */ 28dbbdee94SGrant Likely #ifdef DEBUG 290131d897SSebastian Andrzej Siewior static void of_dump_addr(const char *s, const __be32 *addr, int na) 30dbbdee94SGrant Likely { 31606ad42aSRob Herring pr_debug("%s", s); 32dbbdee94SGrant Likely while (na--) 33606ad42aSRob Herring pr_cont(" %08x", be32_to_cpu(*(addr++))); 34606ad42aSRob Herring pr_cont("\n"); 35dbbdee94SGrant Likely } 36dbbdee94SGrant Likely #else 370131d897SSebastian Andrzej Siewior static void of_dump_addr(const char *s, const __be32 *addr, int na) { } 38dbbdee94SGrant Likely #endif 39dbbdee94SGrant Likely 40dbbdee94SGrant Likely /* Callbacks for bus specific translators */ 41dbbdee94SGrant Likely struct of_bus { 42dbbdee94SGrant Likely const char *name; 43dbbdee94SGrant Likely const char *addresses; 44dbbdee94SGrant Likely int (*match)(struct device_node *parent); 45dbbdee94SGrant Likely void (*count_cells)(struct device_node *child, 46dbbdee94SGrant Likely int *addrc, int *sizec); 4747b1e689SKim Phillips u64 (*map)(__be32 *addr, const __be32 *range, 48dbbdee94SGrant Likely int na, int ns, int pna); 4947b1e689SKim Phillips int (*translate)(__be32 *addr, u64 offset, int na); 500131d897SSebastian Andrzej Siewior unsigned int (*get_flags)(const __be32 *addr); 51dbbdee94SGrant Likely }; 52dbbdee94SGrant Likely 53dbbdee94SGrant Likely /* 54dbbdee94SGrant Likely * Default translator (generic bus) 55dbbdee94SGrant Likely */ 56dbbdee94SGrant Likely 57dbbdee94SGrant Likely static void of_bus_default_count_cells(struct device_node *dev, 58dbbdee94SGrant Likely int *addrc, int *sizec) 59dbbdee94SGrant Likely { 60dbbdee94SGrant Likely if (addrc) 61dbbdee94SGrant Likely *addrc = of_n_addr_cells(dev); 62dbbdee94SGrant Likely if (sizec) 63dbbdee94SGrant Likely *sizec = of_n_size_cells(dev); 64dbbdee94SGrant Likely } 65dbbdee94SGrant Likely 6647b1e689SKim Phillips static u64 of_bus_default_map(__be32 *addr, const __be32 *range, 67dbbdee94SGrant Likely int na, int ns, int pna) 68dbbdee94SGrant Likely { 69dbbdee94SGrant Likely u64 cp, s, da; 70dbbdee94SGrant Likely 71dbbdee94SGrant Likely cp = of_read_number(range, na); 72dbbdee94SGrant Likely s = of_read_number(range + na + pna, ns); 73dbbdee94SGrant Likely da = of_read_number(addr, na); 74dbbdee94SGrant Likely 75606ad42aSRob Herring pr_debug("default map, cp=%llx, s=%llx, da=%llx\n", 76dbbdee94SGrant Likely (unsigned long long)cp, (unsigned long long)s, 77dbbdee94SGrant Likely (unsigned long long)da); 78dbbdee94SGrant Likely 79dbbdee94SGrant Likely if (da < cp || da >= (cp + s)) 80dbbdee94SGrant Likely return OF_BAD_ADDR; 81dbbdee94SGrant Likely return da - cp; 82dbbdee94SGrant Likely } 83dbbdee94SGrant Likely 8447b1e689SKim Phillips static int of_bus_default_translate(__be32 *addr, u64 offset, int na) 85dbbdee94SGrant Likely { 86dbbdee94SGrant Likely u64 a = of_read_number(addr, na); 87dbbdee94SGrant Likely memset(addr, 0, na * 4); 88dbbdee94SGrant Likely a += offset; 89dbbdee94SGrant Likely if (na > 1) 90154063a9SGrant Likely addr[na - 2] = cpu_to_be32(a >> 32); 91154063a9SGrant Likely addr[na - 1] = cpu_to_be32(a & 0xffffffffu); 92dbbdee94SGrant Likely 93dbbdee94SGrant Likely return 0; 94dbbdee94SGrant Likely } 95dbbdee94SGrant Likely 960131d897SSebastian Andrzej Siewior static unsigned int of_bus_default_get_flags(const __be32 *addr) 97dbbdee94SGrant Likely { 98dbbdee94SGrant Likely return IORESOURCE_MEM; 99dbbdee94SGrant Likely } 100dbbdee94SGrant Likely 1014670d610SRob Herring #ifdef CONFIG_PCI 102dbbdee94SGrant Likely /* 103dbbdee94SGrant Likely * PCI bus specific translator 104dbbdee94SGrant Likely */ 105dbbdee94SGrant Likely 106dbbdee94SGrant Likely static int of_bus_pci_match(struct device_node *np) 107dbbdee94SGrant Likely { 1086dd18e46SBenjamin Herrenschmidt /* 10914e2abb7SKleber Sacilotto de Souza * "pciex" is PCI Express 1106dd18e46SBenjamin Herrenschmidt * "vci" is for the /chaos bridge on 1st-gen PCI powermacs 1116dd18e46SBenjamin Herrenschmidt * "ht" is hypertransport 1126dd18e46SBenjamin Herrenschmidt */ 113e8b1dee2SRob Herring return of_node_is_type(np, "pci") || of_node_is_type(np, "pciex") || 114e8b1dee2SRob Herring of_node_is_type(np, "vci") || of_node_is_type(np, "ht"); 115dbbdee94SGrant Likely } 116dbbdee94SGrant Likely 117dbbdee94SGrant Likely static void of_bus_pci_count_cells(struct device_node *np, 118dbbdee94SGrant Likely int *addrc, int *sizec) 119dbbdee94SGrant Likely { 120dbbdee94SGrant Likely if (addrc) 121dbbdee94SGrant Likely *addrc = 3; 122dbbdee94SGrant Likely if (sizec) 123dbbdee94SGrant Likely *sizec = 2; 124dbbdee94SGrant Likely } 125dbbdee94SGrant Likely 1260131d897SSebastian Andrzej Siewior static unsigned int of_bus_pci_get_flags(const __be32 *addr) 127dbbdee94SGrant Likely { 128dbbdee94SGrant Likely unsigned int flags = 0; 1290131d897SSebastian Andrzej Siewior u32 w = be32_to_cpup(addr); 130dbbdee94SGrant Likely 131dbbdee94SGrant Likely switch((w >> 24) & 0x03) { 132dbbdee94SGrant Likely case 0x01: 133dbbdee94SGrant Likely flags |= IORESOURCE_IO; 134dbbdee94SGrant Likely break; 135dbbdee94SGrant Likely case 0x02: /* 32 bits */ 136dbbdee94SGrant Likely case 0x03: /* 64 bits */ 137dbbdee94SGrant Likely flags |= IORESOURCE_MEM; 138dbbdee94SGrant Likely break; 139dbbdee94SGrant Likely } 140dbbdee94SGrant Likely if (w & 0x40000000) 141dbbdee94SGrant Likely flags |= IORESOURCE_PREFETCH; 142dbbdee94SGrant Likely return flags; 143dbbdee94SGrant Likely } 144dbbdee94SGrant Likely 14547b1e689SKim Phillips static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns, 1460131d897SSebastian Andrzej Siewior int pna) 147dbbdee94SGrant Likely { 148dbbdee94SGrant Likely u64 cp, s, da; 149dbbdee94SGrant Likely unsigned int af, rf; 150dbbdee94SGrant Likely 151dbbdee94SGrant Likely af = of_bus_pci_get_flags(addr); 152dbbdee94SGrant Likely rf = of_bus_pci_get_flags(range); 153dbbdee94SGrant Likely 154dbbdee94SGrant Likely /* Check address type match */ 155dbbdee94SGrant Likely if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO)) 156dbbdee94SGrant Likely return OF_BAD_ADDR; 157dbbdee94SGrant Likely 158dbbdee94SGrant Likely /* Read address values, skipping high cell */ 159dbbdee94SGrant Likely cp = of_read_number(range + 1, na - 1); 160dbbdee94SGrant Likely s = of_read_number(range + na + pna, ns); 161dbbdee94SGrant Likely da = of_read_number(addr + 1, na - 1); 162dbbdee94SGrant Likely 163606ad42aSRob Herring pr_debug("PCI map, cp=%llx, s=%llx, da=%llx\n", 164dbbdee94SGrant Likely (unsigned long long)cp, (unsigned long long)s, 165dbbdee94SGrant Likely (unsigned long long)da); 166dbbdee94SGrant Likely 167dbbdee94SGrant Likely if (da < cp || da >= (cp + s)) 168dbbdee94SGrant Likely return OF_BAD_ADDR; 169dbbdee94SGrant Likely return da - cp; 170dbbdee94SGrant Likely } 171dbbdee94SGrant Likely 17247b1e689SKim Phillips static int of_bus_pci_translate(__be32 *addr, u64 offset, int na) 173dbbdee94SGrant Likely { 174dbbdee94SGrant Likely return of_bus_default_translate(addr + 1, offset, na - 1); 175dbbdee94SGrant Likely } 176dbbdee94SGrant Likely 1770131d897SSebastian Andrzej Siewior const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, 178dbbdee94SGrant Likely unsigned int *flags) 179dbbdee94SGrant Likely { 180a9fadeefSJeremy Kerr const __be32 *prop; 181dbbdee94SGrant Likely unsigned int psize; 182dbbdee94SGrant Likely struct device_node *parent; 183dbbdee94SGrant Likely struct of_bus *bus; 184dbbdee94SGrant Likely int onesize, i, na, ns; 185dbbdee94SGrant Likely 186dbbdee94SGrant Likely /* Get parent & match bus type */ 187dbbdee94SGrant Likely parent = of_get_parent(dev); 188dbbdee94SGrant Likely if (parent == NULL) 189dbbdee94SGrant Likely return NULL; 190dbbdee94SGrant Likely bus = of_match_bus(parent); 191dbbdee94SGrant Likely if (strcmp(bus->name, "pci")) { 192dbbdee94SGrant Likely of_node_put(parent); 193dbbdee94SGrant Likely return NULL; 194dbbdee94SGrant Likely } 195dbbdee94SGrant Likely bus->count_cells(dev, &na, &ns); 196dbbdee94SGrant Likely of_node_put(parent); 1975d61b165SStephen Warren if (!OF_CHECK_ADDR_COUNT(na)) 198dbbdee94SGrant Likely return NULL; 199dbbdee94SGrant Likely 200dbbdee94SGrant Likely /* Get "reg" or "assigned-addresses" property */ 201dbbdee94SGrant Likely prop = of_get_property(dev, bus->addresses, &psize); 202dbbdee94SGrant Likely if (prop == NULL) 203dbbdee94SGrant Likely return NULL; 204dbbdee94SGrant Likely psize /= 4; 205dbbdee94SGrant Likely 206dbbdee94SGrant Likely onesize = na + ns; 207154063a9SGrant Likely for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) { 208154063a9SGrant Likely u32 val = be32_to_cpu(prop[0]); 209154063a9SGrant Likely if ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { 210dbbdee94SGrant Likely if (size) 211dbbdee94SGrant Likely *size = of_read_number(prop + na, ns); 212dbbdee94SGrant Likely if (flags) 213dbbdee94SGrant Likely *flags = bus->get_flags(prop); 214dbbdee94SGrant Likely return prop; 215dbbdee94SGrant Likely } 216154063a9SGrant Likely } 217dbbdee94SGrant Likely return NULL; 218dbbdee94SGrant Likely } 219dbbdee94SGrant Likely EXPORT_SYMBOL(of_get_pci_address); 220dbbdee94SGrant Likely 221dbbdee94SGrant Likely int of_pci_address_to_resource(struct device_node *dev, int bar, 222dbbdee94SGrant Likely struct resource *r) 223dbbdee94SGrant Likely { 2240131d897SSebastian Andrzej Siewior const __be32 *addrp; 225dbbdee94SGrant Likely u64 size; 226dbbdee94SGrant Likely unsigned int flags; 227dbbdee94SGrant Likely 228dbbdee94SGrant Likely addrp = of_get_pci_address(dev, bar, &size, &flags); 229dbbdee94SGrant Likely if (addrp == NULL) 230dbbdee94SGrant Likely return -EINVAL; 23135f3da32SBenoit Cousson return __of_address_to_resource(dev, addrp, size, flags, NULL, r); 232dbbdee94SGrant Likely } 233dbbdee94SGrant Likely EXPORT_SYMBOL_GPL(of_pci_address_to_resource); 23429b635c0SAndrew Murray 235a060c210SMarc Gonzalez static int parser_init(struct of_pci_range_parser *parser, 236a060c210SMarc Gonzalez struct device_node *node, const char *name) 23729b635c0SAndrew Murray { 23829b635c0SAndrew Murray const int na = 3, ns = 2; 23929b635c0SAndrew Murray int rlen; 24029b635c0SAndrew Murray 24129b635c0SAndrew Murray parser->node = node; 24229b635c0SAndrew Murray parser->pna = of_n_addr_cells(node); 24329b635c0SAndrew Murray parser->np = parser->pna + na + ns; 24429b635c0SAndrew Murray 245a060c210SMarc Gonzalez parser->range = of_get_property(node, name, &rlen); 24629b635c0SAndrew Murray if (parser->range == NULL) 24729b635c0SAndrew Murray return -ENOENT; 24829b635c0SAndrew Murray 24929b635c0SAndrew Murray parser->end = parser->range + rlen / sizeof(__be32); 25029b635c0SAndrew Murray 25129b635c0SAndrew Murray return 0; 25229b635c0SAndrew Murray } 253a060c210SMarc Gonzalez 254a060c210SMarc Gonzalez int of_pci_range_parser_init(struct of_pci_range_parser *parser, 255a060c210SMarc Gonzalez struct device_node *node) 256a060c210SMarc Gonzalez { 257a060c210SMarc Gonzalez return parser_init(parser, node, "ranges"); 258a060c210SMarc Gonzalez } 25929b635c0SAndrew Murray EXPORT_SYMBOL_GPL(of_pci_range_parser_init); 26029b635c0SAndrew Murray 261a060c210SMarc Gonzalez int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser, 262a060c210SMarc Gonzalez struct device_node *node) 263a060c210SMarc Gonzalez { 264a060c210SMarc Gonzalez return parser_init(parser, node, "dma-ranges"); 265a060c210SMarc Gonzalez } 266a060c210SMarc Gonzalez EXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init); 267a060c210SMarc Gonzalez 26829b635c0SAndrew Murray struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, 26929b635c0SAndrew Murray struct of_pci_range *range) 27029b635c0SAndrew Murray { 27129b635c0SAndrew Murray const int na = 3, ns = 2; 27229b635c0SAndrew Murray 27329b635c0SAndrew Murray if (!range) 27429b635c0SAndrew Murray return NULL; 27529b635c0SAndrew Murray 27629b635c0SAndrew Murray if (!parser->range || parser->range + parser->np > parser->end) 27729b635c0SAndrew Murray return NULL; 27829b635c0SAndrew Murray 279eb310036SRob Herring range->pci_space = be32_to_cpup(parser->range); 28029b635c0SAndrew Murray range->flags = of_bus_pci_get_flags(parser->range); 28129b635c0SAndrew Murray range->pci_addr = of_read_number(parser->range + 1, ns); 28229b635c0SAndrew Murray range->cpu_addr = of_translate_address(parser->node, 28329b635c0SAndrew Murray parser->range + na); 28429b635c0SAndrew Murray range->size = of_read_number(parser->range + parser->pna + na, ns); 28529b635c0SAndrew Murray 28629b635c0SAndrew Murray parser->range += parser->np; 28729b635c0SAndrew Murray 28829b635c0SAndrew Murray /* Now consume following elements while they are contiguous */ 28929b635c0SAndrew Murray while (parser->range + parser->np <= parser->end) { 290fda9f5d4SShawn Lin u32 flags; 29129b635c0SAndrew Murray u64 pci_addr, cpu_addr, size; 29229b635c0SAndrew Murray 29329b635c0SAndrew Murray flags = of_bus_pci_get_flags(parser->range); 29429b635c0SAndrew Murray pci_addr = of_read_number(parser->range + 1, ns); 29529b635c0SAndrew Murray cpu_addr = of_translate_address(parser->node, 29629b635c0SAndrew Murray parser->range + na); 29729b635c0SAndrew Murray size = of_read_number(parser->range + parser->pna + na, ns); 29829b635c0SAndrew Murray 29929b635c0SAndrew Murray if (flags != range->flags) 30029b635c0SAndrew Murray break; 30129b635c0SAndrew Murray if (pci_addr != range->pci_addr + range->size || 30229b635c0SAndrew Murray cpu_addr != range->cpu_addr + range->size) 30329b635c0SAndrew Murray break; 30429b635c0SAndrew Murray 30529b635c0SAndrew Murray range->size += size; 30629b635c0SAndrew Murray parser->range += parser->np; 30729b635c0SAndrew Murray } 30829b635c0SAndrew Murray 30929b635c0SAndrew Murray return range; 31029b635c0SAndrew Murray } 31129b635c0SAndrew Murray EXPORT_SYMBOL_GPL(of_pci_range_parser_one); 31229b635c0SAndrew Murray 3130b0b0893SLiviu Dudau /* 3140b0b0893SLiviu Dudau * of_pci_range_to_resource - Create a resource from an of_pci_range 3150b0b0893SLiviu Dudau * @range: the PCI range that describes the resource 3160b0b0893SLiviu Dudau * @np: device node where the range belongs to 3170b0b0893SLiviu Dudau * @res: pointer to a valid resource that will be updated to 3180b0b0893SLiviu Dudau * reflect the values contained in the range. 3190b0b0893SLiviu Dudau * 3200b0b0893SLiviu Dudau * Returns EINVAL if the range cannot be converted to resource. 3210b0b0893SLiviu Dudau * 3220b0b0893SLiviu Dudau * Note that if the range is an IO range, the resource will be converted 3230b0b0893SLiviu Dudau * using pci_address_to_pio() which can fail if it is called too early or 3240b0b0893SLiviu Dudau * if the range cannot be matched to any host bridge IO space (our case here). 3250b0b0893SLiviu Dudau * To guard against that we try to register the IO range first. 3260b0b0893SLiviu Dudau * If that fails we know that pci_address_to_pio() will do too. 3270b0b0893SLiviu Dudau */ 3280b0b0893SLiviu Dudau int of_pci_range_to_resource(struct of_pci_range *range, 32983bbde1cSLiviu Dudau struct device_node *np, struct resource *res) 33083bbde1cSLiviu Dudau { 3310b0b0893SLiviu Dudau int err; 33283bbde1cSLiviu Dudau res->flags = range->flags; 33383bbde1cSLiviu Dudau res->parent = res->child = res->sibling = NULL; 33483bbde1cSLiviu Dudau res->name = np->full_name; 3350b0b0893SLiviu Dudau 3360b0b0893SLiviu Dudau if (res->flags & IORESOURCE_IO) { 3370b0b0893SLiviu Dudau unsigned long port; 338fcfaab30SGabriele Paoloni err = pci_register_io_range(&np->fwnode, range->cpu_addr, 339fcfaab30SGabriele Paoloni range->size); 3400b0b0893SLiviu Dudau if (err) 3410b0b0893SLiviu Dudau goto invalid_range; 3420b0b0893SLiviu Dudau port = pci_address_to_pio(range->cpu_addr); 3430b0b0893SLiviu Dudau if (port == (unsigned long)-1) { 3440b0b0893SLiviu Dudau err = -EINVAL; 3450b0b0893SLiviu Dudau goto invalid_range; 3460b0b0893SLiviu Dudau } 3470b0b0893SLiviu Dudau res->start = port; 3480b0b0893SLiviu Dudau } else { 3494af97106SPavel Fedin if ((sizeof(resource_size_t) < 8) && 3504af97106SPavel Fedin upper_32_bits(range->cpu_addr)) { 3514af97106SPavel Fedin err = -EINVAL; 3524af97106SPavel Fedin goto invalid_range; 3534af97106SPavel Fedin } 3544af97106SPavel Fedin 3550b0b0893SLiviu Dudau res->start = range->cpu_addr; 3560b0b0893SLiviu Dudau } 3570b0b0893SLiviu Dudau res->end = res->start + range->size - 1; 3580b0b0893SLiviu Dudau return 0; 3590b0b0893SLiviu Dudau 3600b0b0893SLiviu Dudau invalid_range: 3610b0b0893SLiviu Dudau res->start = (resource_size_t)OF_BAD_ADDR; 3620b0b0893SLiviu Dudau res->end = (resource_size_t)OF_BAD_ADDR; 3630b0b0893SLiviu Dudau return err; 36483bbde1cSLiviu Dudau } 365bf6681eaSManikanta Maddireddy EXPORT_SYMBOL(of_pci_range_to_resource); 366dbbdee94SGrant Likely #endif /* CONFIG_PCI */ 367dbbdee94SGrant Likely 368dbbdee94SGrant Likely /* 369dbbdee94SGrant Likely * ISA bus specific translator 370dbbdee94SGrant Likely */ 371dbbdee94SGrant Likely 372dbbdee94SGrant Likely static int of_bus_isa_match(struct device_node *np) 373dbbdee94SGrant Likely { 374b3e46d1aSRob Herring return of_node_name_eq(np, "isa"); 375dbbdee94SGrant Likely } 376dbbdee94SGrant Likely 377dbbdee94SGrant Likely static void of_bus_isa_count_cells(struct device_node *child, 378dbbdee94SGrant Likely int *addrc, int *sizec) 379dbbdee94SGrant Likely { 380dbbdee94SGrant Likely if (addrc) 381dbbdee94SGrant Likely *addrc = 2; 382dbbdee94SGrant Likely if (sizec) 383dbbdee94SGrant Likely *sizec = 1; 384dbbdee94SGrant Likely } 385dbbdee94SGrant Likely 38647b1e689SKim Phillips static u64 of_bus_isa_map(__be32 *addr, const __be32 *range, int na, int ns, 3870131d897SSebastian Andrzej Siewior int pna) 388dbbdee94SGrant Likely { 389dbbdee94SGrant Likely u64 cp, s, da; 390dbbdee94SGrant Likely 391dbbdee94SGrant Likely /* Check address type match */ 3920131d897SSebastian Andrzej Siewior if ((addr[0] ^ range[0]) & cpu_to_be32(1)) 393dbbdee94SGrant Likely return OF_BAD_ADDR; 394dbbdee94SGrant Likely 395dbbdee94SGrant Likely /* Read address values, skipping high cell */ 396dbbdee94SGrant Likely cp = of_read_number(range + 1, na - 1); 397dbbdee94SGrant Likely s = of_read_number(range + na + pna, ns); 398dbbdee94SGrant Likely da = of_read_number(addr + 1, na - 1); 399dbbdee94SGrant Likely 400606ad42aSRob Herring pr_debug("ISA map, cp=%llx, s=%llx, da=%llx\n", 401dbbdee94SGrant Likely (unsigned long long)cp, (unsigned long long)s, 402dbbdee94SGrant Likely (unsigned long long)da); 403dbbdee94SGrant Likely 404dbbdee94SGrant Likely if (da < cp || da >= (cp + s)) 405dbbdee94SGrant Likely return OF_BAD_ADDR; 406dbbdee94SGrant Likely return da - cp; 407dbbdee94SGrant Likely } 408dbbdee94SGrant Likely 40947b1e689SKim Phillips static int of_bus_isa_translate(__be32 *addr, u64 offset, int na) 410dbbdee94SGrant Likely { 411dbbdee94SGrant Likely return of_bus_default_translate(addr + 1, offset, na - 1); 412dbbdee94SGrant Likely } 413dbbdee94SGrant Likely 4140131d897SSebastian Andrzej Siewior static unsigned int of_bus_isa_get_flags(const __be32 *addr) 415dbbdee94SGrant Likely { 416dbbdee94SGrant Likely unsigned int flags = 0; 4170131d897SSebastian Andrzej Siewior u32 w = be32_to_cpup(addr); 418dbbdee94SGrant Likely 419dbbdee94SGrant Likely if (w & 1) 420dbbdee94SGrant Likely flags |= IORESOURCE_IO; 421dbbdee94SGrant Likely else 422dbbdee94SGrant Likely flags |= IORESOURCE_MEM; 423dbbdee94SGrant Likely return flags; 424dbbdee94SGrant Likely } 425dbbdee94SGrant Likely 426dbbdee94SGrant Likely /* 427dbbdee94SGrant Likely * Array of bus specific translators 428dbbdee94SGrant Likely */ 429dbbdee94SGrant Likely 430dbbdee94SGrant Likely static struct of_bus of_busses[] = { 4314670d610SRob Herring #ifdef CONFIG_PCI 432dbbdee94SGrant Likely /* PCI */ 433dbbdee94SGrant Likely { 434dbbdee94SGrant Likely .name = "pci", 435dbbdee94SGrant Likely .addresses = "assigned-addresses", 436dbbdee94SGrant Likely .match = of_bus_pci_match, 437dbbdee94SGrant Likely .count_cells = of_bus_pci_count_cells, 438dbbdee94SGrant Likely .map = of_bus_pci_map, 439dbbdee94SGrant Likely .translate = of_bus_pci_translate, 440dbbdee94SGrant Likely .get_flags = of_bus_pci_get_flags, 441dbbdee94SGrant Likely }, 4424670d610SRob Herring #endif /* CONFIG_PCI */ 443dbbdee94SGrant Likely /* ISA */ 444dbbdee94SGrant Likely { 445dbbdee94SGrant Likely .name = "isa", 446dbbdee94SGrant Likely .addresses = "reg", 447dbbdee94SGrant Likely .match = of_bus_isa_match, 448dbbdee94SGrant Likely .count_cells = of_bus_isa_count_cells, 449dbbdee94SGrant Likely .map = of_bus_isa_map, 450dbbdee94SGrant Likely .translate = of_bus_isa_translate, 451dbbdee94SGrant Likely .get_flags = of_bus_isa_get_flags, 452dbbdee94SGrant Likely }, 453dbbdee94SGrant Likely /* Default */ 454dbbdee94SGrant Likely { 455dbbdee94SGrant Likely .name = "default", 456dbbdee94SGrant Likely .addresses = "reg", 457dbbdee94SGrant Likely .match = NULL, 458dbbdee94SGrant Likely .count_cells = of_bus_default_count_cells, 459dbbdee94SGrant Likely .map = of_bus_default_map, 460dbbdee94SGrant Likely .translate = of_bus_default_translate, 461dbbdee94SGrant Likely .get_flags = of_bus_default_get_flags, 462dbbdee94SGrant Likely }, 463dbbdee94SGrant Likely }; 464dbbdee94SGrant Likely 465dbbdee94SGrant Likely static struct of_bus *of_match_bus(struct device_node *np) 466dbbdee94SGrant Likely { 467dbbdee94SGrant Likely int i; 468dbbdee94SGrant Likely 469dbbdee94SGrant Likely for (i = 0; i < ARRAY_SIZE(of_busses); i++) 470dbbdee94SGrant Likely if (!of_busses[i].match || of_busses[i].match(np)) 471dbbdee94SGrant Likely return &of_busses[i]; 472dbbdee94SGrant Likely BUG(); 473dbbdee94SGrant Likely return NULL; 474dbbdee94SGrant Likely } 475dbbdee94SGrant Likely 47641d94893SBenjamin Herrenschmidt static int of_empty_ranges_quirk(struct device_node *np) 477746c9e9fSBenjamin Herrenschmidt { 478746c9e9fSBenjamin Herrenschmidt if (IS_ENABLED(CONFIG_PPC)) { 47941d94893SBenjamin Herrenschmidt /* To save cycles, we cache the result for global "Mac" setting */ 480746c9e9fSBenjamin Herrenschmidt static int quirk_state = -1; 481746c9e9fSBenjamin Herrenschmidt 48241d94893SBenjamin Herrenschmidt /* PA-SEMI sdc DT bug */ 48341d94893SBenjamin Herrenschmidt if (of_device_is_compatible(np, "1682m-sdc")) 48441d94893SBenjamin Herrenschmidt return true; 48541d94893SBenjamin Herrenschmidt 48641d94893SBenjamin Herrenschmidt /* Make quirk cached */ 487746c9e9fSBenjamin Herrenschmidt if (quirk_state < 0) 488746c9e9fSBenjamin Herrenschmidt quirk_state = 489746c9e9fSBenjamin Herrenschmidt of_machine_is_compatible("Power Macintosh") || 490746c9e9fSBenjamin Herrenschmidt of_machine_is_compatible("MacRISC"); 491746c9e9fSBenjamin Herrenschmidt return quirk_state; 492746c9e9fSBenjamin Herrenschmidt } 493746c9e9fSBenjamin Herrenschmidt return false; 494746c9e9fSBenjamin Herrenschmidt } 495746c9e9fSBenjamin Herrenschmidt 496dbbdee94SGrant Likely static int of_translate_one(struct device_node *parent, struct of_bus *bus, 49747b1e689SKim Phillips struct of_bus *pbus, __be32 *addr, 498dbbdee94SGrant Likely int na, int ns, int pna, const char *rprop) 499dbbdee94SGrant Likely { 5000131d897SSebastian Andrzej Siewior const __be32 *ranges; 501dbbdee94SGrant Likely unsigned int rlen; 502dbbdee94SGrant Likely int rone; 503dbbdee94SGrant Likely u64 offset = OF_BAD_ADDR; 504dbbdee94SGrant Likely 505ba85edbeSMasahiro Yamada /* 506ba85edbeSMasahiro Yamada * Normally, an absence of a "ranges" property means we are 507dbbdee94SGrant Likely * crossing a non-translatable boundary, and thus the addresses 508ba85edbeSMasahiro Yamada * below the current cannot be converted to CPU physical ones. 509dbbdee94SGrant Likely * Unfortunately, while this is very clear in the spec, it's not 510dbbdee94SGrant Likely * what Apple understood, and they do have things like /uni-n or 511dbbdee94SGrant Likely * /ht nodes with no "ranges" property and a lot of perfectly 512dbbdee94SGrant Likely * useable mapped devices below them. Thus we treat the absence of 513dbbdee94SGrant Likely * "ranges" as equivalent to an empty "ranges" property which means 514dbbdee94SGrant Likely * a 1:1 translation at that level. It's up to the caller not to try 515dbbdee94SGrant Likely * to translate addresses that aren't supposed to be translated in 516dbbdee94SGrant Likely * the first place. --BenH. 5173930f294SGrant Likely * 5183930f294SGrant Likely * As far as we know, this damage only exists on Apple machines, so 5193930f294SGrant Likely * This code is only enabled on powerpc. --gcl 520dbbdee94SGrant Likely */ 521dbbdee94SGrant Likely ranges = of_get_property(parent, rprop, &rlen); 52241d94893SBenjamin Herrenschmidt if (ranges == NULL && !of_empty_ranges_quirk(parent)) { 523606ad42aSRob Herring pr_debug("no ranges; cannot translate\n"); 5243930f294SGrant Likely return 1; 5253930f294SGrant Likely } 526dbbdee94SGrant Likely if (ranges == NULL || rlen == 0) { 527dbbdee94SGrant Likely offset = of_read_number(addr, na); 528dbbdee94SGrant Likely memset(addr, 0, pna * 4); 529606ad42aSRob Herring pr_debug("empty ranges; 1:1 translation\n"); 530dbbdee94SGrant Likely goto finish; 531dbbdee94SGrant Likely } 532dbbdee94SGrant Likely 533606ad42aSRob Herring pr_debug("walking ranges...\n"); 534dbbdee94SGrant Likely 535dbbdee94SGrant Likely /* Now walk through the ranges */ 536dbbdee94SGrant Likely rlen /= 4; 537dbbdee94SGrant Likely rone = na + pna + ns; 538dbbdee94SGrant Likely for (; rlen >= rone; rlen -= rone, ranges += rone) { 539dbbdee94SGrant Likely offset = bus->map(addr, ranges, na, ns, pna); 540dbbdee94SGrant Likely if (offset != OF_BAD_ADDR) 541dbbdee94SGrant Likely break; 542dbbdee94SGrant Likely } 543dbbdee94SGrant Likely if (offset == OF_BAD_ADDR) { 544606ad42aSRob Herring pr_debug("not found !\n"); 545dbbdee94SGrant Likely return 1; 546dbbdee94SGrant Likely } 547dbbdee94SGrant Likely memcpy(addr, ranges + na, 4 * pna); 548dbbdee94SGrant Likely 549dbbdee94SGrant Likely finish: 550606ad42aSRob Herring of_dump_addr("parent translation for:", addr, pna); 551606ad42aSRob Herring pr_debug("with offset: %llx\n", (unsigned long long)offset); 552dbbdee94SGrant Likely 553dbbdee94SGrant Likely /* Translate it into parent bus space */ 554dbbdee94SGrant Likely return pbus->translate(addr, offset, pna); 555dbbdee94SGrant Likely } 556dbbdee94SGrant Likely 557dbbdee94SGrant Likely /* 558dbbdee94SGrant Likely * Translate an address from the device-tree into a CPU physical address, 559dbbdee94SGrant Likely * this walks up the tree and applies the various bus mappings on the 560dbbdee94SGrant Likely * way. 561dbbdee94SGrant Likely * 562dbbdee94SGrant Likely * Note: We consider that crossing any level with #size-cells == 0 to mean 563dbbdee94SGrant Likely * that translation is impossible (that is we are not dealing with a value 564dbbdee94SGrant Likely * that can be mapped to a cpu physical address). This is not really specified 565dbbdee94SGrant Likely * that way, but this is traditionally the way IBM at least do things 56665af618dSZhichang Yuan * 56765af618dSZhichang Yuan * Whenever the translation fails, the *host pointer will be set to the 56865af618dSZhichang Yuan * device that had registered logical PIO mapping, and the return code is 56965af618dSZhichang Yuan * relative to that node. 570dbbdee94SGrant Likely */ 57147b1e689SKim Phillips static u64 __of_translate_address(struct device_node *dev, 57265af618dSZhichang Yuan const __be32 *in_addr, const char *rprop, 57365af618dSZhichang Yuan struct device_node **host) 574dbbdee94SGrant Likely { 575dbbdee94SGrant Likely struct device_node *parent = NULL; 576dbbdee94SGrant Likely struct of_bus *bus, *pbus; 57747b1e689SKim Phillips __be32 addr[OF_MAX_ADDR_CELLS]; 578dbbdee94SGrant Likely int na, ns, pna, pns; 579dbbdee94SGrant Likely u64 result = OF_BAD_ADDR; 580dbbdee94SGrant Likely 5810d638a07SRob Herring pr_debug("** translation for device %pOF **\n", dev); 582dbbdee94SGrant Likely 583dbbdee94SGrant Likely /* Increase refcount at current level */ 584dbbdee94SGrant Likely of_node_get(dev); 585dbbdee94SGrant Likely 58665af618dSZhichang Yuan *host = NULL; 587dbbdee94SGrant Likely /* Get parent & match bus type */ 588dbbdee94SGrant Likely parent = of_get_parent(dev); 589dbbdee94SGrant Likely if (parent == NULL) 590dbbdee94SGrant Likely goto bail; 591dbbdee94SGrant Likely bus = of_match_bus(parent); 592dbbdee94SGrant Likely 59359f5ca48SAndrew Murray /* Count address cells & copy address locally */ 594dbbdee94SGrant Likely bus->count_cells(dev, &na, &ns); 595dbbdee94SGrant Likely if (!OF_CHECK_COUNTS(na, ns)) { 5960d638a07SRob Herring pr_debug("Bad cell count for %pOF\n", dev); 597dbbdee94SGrant Likely goto bail; 598dbbdee94SGrant Likely } 599dbbdee94SGrant Likely memcpy(addr, in_addr, na * 4); 600dbbdee94SGrant Likely 6010d638a07SRob Herring pr_debug("bus is %s (na=%d, ns=%d) on %pOF\n", 6020d638a07SRob Herring bus->name, na, ns, parent); 603606ad42aSRob Herring of_dump_addr("translating address:", addr, na); 604dbbdee94SGrant Likely 605dbbdee94SGrant Likely /* Translate */ 606dbbdee94SGrant Likely for (;;) { 60765af618dSZhichang Yuan struct logic_pio_hwaddr *iorange; 60865af618dSZhichang Yuan 609dbbdee94SGrant Likely /* Switch to parent bus */ 610dbbdee94SGrant Likely of_node_put(dev); 611dbbdee94SGrant Likely dev = parent; 612dbbdee94SGrant Likely parent = of_get_parent(dev); 613dbbdee94SGrant Likely 614dbbdee94SGrant Likely /* If root, we have finished */ 615dbbdee94SGrant Likely if (parent == NULL) { 616606ad42aSRob Herring pr_debug("reached root node\n"); 617dbbdee94SGrant Likely result = of_read_number(addr, na); 618dbbdee94SGrant Likely break; 619dbbdee94SGrant Likely } 620dbbdee94SGrant Likely 62165af618dSZhichang Yuan /* 62265af618dSZhichang Yuan * For indirectIO device which has no ranges property, get 62365af618dSZhichang Yuan * the address from reg directly. 62465af618dSZhichang Yuan */ 62565af618dSZhichang Yuan iorange = find_io_range_by_fwnode(&dev->fwnode); 62665af618dSZhichang Yuan if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) { 62765af618dSZhichang Yuan result = of_read_number(addr + 1, na - 1); 62865af618dSZhichang Yuan pr_debug("indirectIO matched(%pOF) 0x%llx\n", 62965af618dSZhichang Yuan dev, result); 63065af618dSZhichang Yuan *host = of_node_get(dev); 63165af618dSZhichang Yuan break; 63265af618dSZhichang Yuan } 63365af618dSZhichang Yuan 634dbbdee94SGrant Likely /* Get new parent bus and counts */ 635dbbdee94SGrant Likely pbus = of_match_bus(parent); 636dbbdee94SGrant Likely pbus->count_cells(dev, &pna, &pns); 637dbbdee94SGrant Likely if (!OF_CHECK_COUNTS(pna, pns)) { 6380d638a07SRob Herring pr_err("Bad cell count for %pOF\n", dev); 639dbbdee94SGrant Likely break; 640dbbdee94SGrant Likely } 641dbbdee94SGrant Likely 6420d638a07SRob Herring pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n", 6430d638a07SRob Herring pbus->name, pna, pns, parent); 644dbbdee94SGrant Likely 645dbbdee94SGrant Likely /* Apply bus translation */ 646dbbdee94SGrant Likely if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) 647dbbdee94SGrant Likely break; 648dbbdee94SGrant Likely 649dbbdee94SGrant Likely /* Complete the move up one level */ 650dbbdee94SGrant Likely na = pna; 651dbbdee94SGrant Likely ns = pns; 652dbbdee94SGrant Likely bus = pbus; 653dbbdee94SGrant Likely 654606ad42aSRob Herring of_dump_addr("one level translation:", addr, na); 655dbbdee94SGrant Likely } 656dbbdee94SGrant Likely bail: 657dbbdee94SGrant Likely of_node_put(parent); 658dbbdee94SGrant Likely of_node_put(dev); 659dbbdee94SGrant Likely 660dbbdee94SGrant Likely return result; 661dbbdee94SGrant Likely } 662dbbdee94SGrant Likely 6630131d897SSebastian Andrzej Siewior u64 of_translate_address(struct device_node *dev, const __be32 *in_addr) 664dbbdee94SGrant Likely { 66565af618dSZhichang Yuan struct device_node *host; 66665af618dSZhichang Yuan u64 ret; 66765af618dSZhichang Yuan 66865af618dSZhichang Yuan ret = __of_translate_address(dev, in_addr, "ranges", &host); 66965af618dSZhichang Yuan if (host) { 67065af618dSZhichang Yuan of_node_put(host); 67165af618dSZhichang Yuan return OF_BAD_ADDR; 67265af618dSZhichang Yuan } 67365af618dSZhichang Yuan 67465af618dSZhichang Yuan return ret; 675dbbdee94SGrant Likely } 676dbbdee94SGrant Likely EXPORT_SYMBOL(of_translate_address); 677dbbdee94SGrant Likely 6780131d897SSebastian Andrzej Siewior u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) 679dbbdee94SGrant Likely { 68065af618dSZhichang Yuan struct device_node *host; 68165af618dSZhichang Yuan u64 ret; 68265af618dSZhichang Yuan 68365af618dSZhichang Yuan ret = __of_translate_address(dev, in_addr, "dma-ranges", &host); 68465af618dSZhichang Yuan 68565af618dSZhichang Yuan if (host) { 68665af618dSZhichang Yuan of_node_put(host); 68765af618dSZhichang Yuan return OF_BAD_ADDR; 68865af618dSZhichang Yuan } 68965af618dSZhichang Yuan 69065af618dSZhichang Yuan return ret; 691dbbdee94SGrant Likely } 692dbbdee94SGrant Likely EXPORT_SYMBOL(of_translate_dma_address); 693dbbdee94SGrant Likely 6940131d897SSebastian Andrzej Siewior const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, 695dbbdee94SGrant Likely unsigned int *flags) 696dbbdee94SGrant Likely { 6970131d897SSebastian Andrzej Siewior const __be32 *prop; 698dbbdee94SGrant Likely unsigned int psize; 699dbbdee94SGrant Likely struct device_node *parent; 700dbbdee94SGrant Likely struct of_bus *bus; 701dbbdee94SGrant Likely int onesize, i, na, ns; 702dbbdee94SGrant Likely 703dbbdee94SGrant Likely /* Get parent & match bus type */ 704dbbdee94SGrant Likely parent = of_get_parent(dev); 705dbbdee94SGrant Likely if (parent == NULL) 706dbbdee94SGrant Likely return NULL; 707dbbdee94SGrant Likely bus = of_match_bus(parent); 708dbbdee94SGrant Likely bus->count_cells(dev, &na, &ns); 709dbbdee94SGrant Likely of_node_put(parent); 7105d61b165SStephen Warren if (!OF_CHECK_ADDR_COUNT(na)) 711dbbdee94SGrant Likely return NULL; 712dbbdee94SGrant Likely 713dbbdee94SGrant Likely /* Get "reg" or "assigned-addresses" property */ 714dbbdee94SGrant Likely prop = of_get_property(dev, bus->addresses, &psize); 715dbbdee94SGrant Likely if (prop == NULL) 716dbbdee94SGrant Likely return NULL; 717dbbdee94SGrant Likely psize /= 4; 718dbbdee94SGrant Likely 719dbbdee94SGrant Likely onesize = na + ns; 720dbbdee94SGrant Likely for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) 721dbbdee94SGrant Likely if (i == index) { 722dbbdee94SGrant Likely if (size) 723dbbdee94SGrant Likely *size = of_read_number(prop + na, ns); 724dbbdee94SGrant Likely if (flags) 725dbbdee94SGrant Likely *flags = bus->get_flags(prop); 726dbbdee94SGrant Likely return prop; 727dbbdee94SGrant Likely } 728dbbdee94SGrant Likely return NULL; 729dbbdee94SGrant Likely } 730dbbdee94SGrant Likely EXPORT_SYMBOL(of_get_address); 731dbbdee94SGrant Likely 73265af618dSZhichang Yuan static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr, 73365af618dSZhichang Yuan u64 size) 73465af618dSZhichang Yuan { 73565af618dSZhichang Yuan u64 taddr; 73665af618dSZhichang Yuan unsigned long port; 73765af618dSZhichang Yuan struct device_node *host; 73865af618dSZhichang Yuan 73965af618dSZhichang Yuan taddr = __of_translate_address(dev, in_addr, "ranges", &host); 74065af618dSZhichang Yuan if (host) { 74165af618dSZhichang Yuan /* host-specific port access */ 74265af618dSZhichang Yuan port = logic_pio_trans_hwaddr(&host->fwnode, taddr, size); 74365af618dSZhichang Yuan of_node_put(host); 74465af618dSZhichang Yuan } else { 74565af618dSZhichang Yuan /* memory-mapped I/O range */ 74665af618dSZhichang Yuan port = pci_address_to_pio(taddr); 74765af618dSZhichang Yuan } 74865af618dSZhichang Yuan 74965af618dSZhichang Yuan if (port == (unsigned long)-1) 75065af618dSZhichang Yuan return OF_BAD_ADDR; 75165af618dSZhichang Yuan 75265af618dSZhichang Yuan return port; 75365af618dSZhichang Yuan } 75465af618dSZhichang Yuan 7550131d897SSebastian Andrzej Siewior static int __of_address_to_resource(struct device_node *dev, 7560131d897SSebastian Andrzej Siewior const __be32 *addrp, u64 size, unsigned int flags, 75735f3da32SBenoit Cousson const char *name, struct resource *r) 7581f5bef30SGrant Likely { 7591f5bef30SGrant Likely u64 taddr; 7601f5bef30SGrant Likely 76165af618dSZhichang Yuan if (flags & IORESOURCE_MEM) 7621f5bef30SGrant Likely taddr = of_translate_address(dev, addrp); 76365af618dSZhichang Yuan else if (flags & IORESOURCE_IO) 76465af618dSZhichang Yuan taddr = of_translate_ioport(dev, addrp, size); 76565af618dSZhichang Yuan else 76665af618dSZhichang Yuan return -EINVAL; 76765af618dSZhichang Yuan 7681f5bef30SGrant Likely if (taddr == OF_BAD_ADDR) 7691f5bef30SGrant Likely return -EINVAL; 7701f5bef30SGrant Likely memset(r, 0, sizeof(struct resource)); 77165af618dSZhichang Yuan 7721f5bef30SGrant Likely r->start = taddr; 7731f5bef30SGrant Likely r->end = taddr + size - 1; 7741f5bef30SGrant Likely r->flags = flags; 77535f3da32SBenoit Cousson r->name = name ? name : dev->full_name; 77635f3da32SBenoit Cousson 7771f5bef30SGrant Likely return 0; 7781f5bef30SGrant Likely } 7791f5bef30SGrant Likely 7801f5bef30SGrant Likely /** 7811f5bef30SGrant Likely * of_address_to_resource - Translate device tree address and return as resource 7821f5bef30SGrant Likely * 7831f5bef30SGrant Likely * Note that if your address is a PIO address, the conversion will fail if 7841f5bef30SGrant Likely * the physical address can't be internally converted to an IO token with 7857602f422SFrank Rowand * pci_address_to_pio(), that is because it's either called too early or it 7861f5bef30SGrant Likely * can't be matched to any host bridge IO space 7871f5bef30SGrant Likely */ 7881f5bef30SGrant Likely int of_address_to_resource(struct device_node *dev, int index, 7891f5bef30SGrant Likely struct resource *r) 7901f5bef30SGrant Likely { 7910131d897SSebastian Andrzej Siewior const __be32 *addrp; 7921f5bef30SGrant Likely u64 size; 7931f5bef30SGrant Likely unsigned int flags; 79435f3da32SBenoit Cousson const char *name = NULL; 7951f5bef30SGrant Likely 7961f5bef30SGrant Likely addrp = of_get_address(dev, index, &size, &flags); 7971f5bef30SGrant Likely if (addrp == NULL) 7981f5bef30SGrant Likely return -EINVAL; 79935f3da32SBenoit Cousson 80035f3da32SBenoit Cousson /* Get optional "reg-names" property to add a name to a resource */ 80135f3da32SBenoit Cousson of_property_read_string_index(dev, "reg-names", index, &name); 80235f3da32SBenoit Cousson 80335f3da32SBenoit Cousson return __of_address_to_resource(dev, addrp, size, flags, name, r); 8041f5bef30SGrant Likely } 8051f5bef30SGrant Likely EXPORT_SYMBOL_GPL(of_address_to_resource); 8061f5bef30SGrant Likely 80790e33f62SGrant Likely struct device_node *of_find_matching_node_by_address(struct device_node *from, 80890e33f62SGrant Likely const struct of_device_id *matches, 80990e33f62SGrant Likely u64 base_address) 81090e33f62SGrant Likely { 81190e33f62SGrant Likely struct device_node *dn = of_find_matching_node(from, matches); 81290e33f62SGrant Likely struct resource res; 81390e33f62SGrant Likely 81490e33f62SGrant Likely while (dn) { 8153a496b00SDavid Daney if (!of_address_to_resource(dn, 0, &res) && 8163a496b00SDavid Daney res.start == base_address) 81790e33f62SGrant Likely return dn; 8183a496b00SDavid Daney 81990e33f62SGrant Likely dn = of_find_matching_node(dn, matches); 82090e33f62SGrant Likely } 82190e33f62SGrant Likely 82290e33f62SGrant Likely return NULL; 82390e33f62SGrant Likely } 82490e33f62SGrant Likely 8251f5bef30SGrant Likely 8266b884a8dSGrant Likely /** 8276b884a8dSGrant Likely * of_iomap - Maps the memory mapped IO for a given device_node 8286b884a8dSGrant Likely * @device: the device whose io range will be mapped 8296b884a8dSGrant Likely * @index: index of the io range 8306b884a8dSGrant Likely * 8316b884a8dSGrant Likely * Returns a pointer to the mapped memory 8326b884a8dSGrant Likely */ 8336b884a8dSGrant Likely void __iomem *of_iomap(struct device_node *np, int index) 8346b884a8dSGrant Likely { 8356b884a8dSGrant Likely struct resource res; 8366b884a8dSGrant Likely 8376b884a8dSGrant Likely if (of_address_to_resource(np, index, &res)) 8386b884a8dSGrant Likely return NULL; 8396b884a8dSGrant Likely 84028c1b6d6SFelipe Balbi return ioremap(res.start, resource_size(&res)); 8416b884a8dSGrant Likely } 8426b884a8dSGrant Likely EXPORT_SYMBOL(of_iomap); 84318308c94SGrygorii Strashko 844efd342fbSMatthias Brugger /* 845efd342fbSMatthias Brugger * of_io_request_and_map - Requests a resource and maps the memory mapped IO 846efd342fbSMatthias Brugger * for a given device_node 847efd342fbSMatthias Brugger * @device: the device whose io range will be mapped 848efd342fbSMatthias Brugger * @index: index of the io range 849b01dcdd8SBenjamin Herrenschmidt * @name: name "override" for the memory region request or NULL 850efd342fbSMatthias Brugger * 851efd342fbSMatthias Brugger * Returns a pointer to the requested and mapped memory or an ERR_PTR() encoded 852efd342fbSMatthias Brugger * error code on failure. Usage example: 853efd342fbSMatthias Brugger * 854efd342fbSMatthias Brugger * base = of_io_request_and_map(node, 0, "foo"); 855efd342fbSMatthias Brugger * if (IS_ERR(base)) 856efd342fbSMatthias Brugger * return PTR_ERR(base); 857efd342fbSMatthias Brugger */ 858efd342fbSMatthias Brugger void __iomem *of_io_request_and_map(struct device_node *np, int index, 859b75b276bSMatthias Brugger const char *name) 860efd342fbSMatthias Brugger { 861efd342fbSMatthias Brugger struct resource res; 862efd342fbSMatthias Brugger void __iomem *mem; 863efd342fbSMatthias Brugger 864efd342fbSMatthias Brugger if (of_address_to_resource(np, index, &res)) 865efd342fbSMatthias Brugger return IOMEM_ERR_PTR(-EINVAL); 866efd342fbSMatthias Brugger 867b01dcdd8SBenjamin Herrenschmidt if (!name) 868b01dcdd8SBenjamin Herrenschmidt name = res.name; 869efd342fbSMatthias Brugger if (!request_mem_region(res.start, resource_size(&res), name)) 870efd342fbSMatthias Brugger return IOMEM_ERR_PTR(-EBUSY); 871efd342fbSMatthias Brugger 872efd342fbSMatthias Brugger mem = ioremap(res.start, resource_size(&res)); 873efd342fbSMatthias Brugger if (!mem) { 874efd342fbSMatthias Brugger release_mem_region(res.start, resource_size(&res)); 875efd342fbSMatthias Brugger return IOMEM_ERR_PTR(-ENOMEM); 876efd342fbSMatthias Brugger } 877efd342fbSMatthias Brugger 878efd342fbSMatthias Brugger return mem; 879efd342fbSMatthias Brugger } 880efd342fbSMatthias Brugger EXPORT_SYMBOL(of_io_request_and_map); 881efd342fbSMatthias Brugger 88218308c94SGrygorii Strashko /** 88318308c94SGrygorii Strashko * of_dma_get_range - Get DMA range info 88418308c94SGrygorii Strashko * @np: device node to get DMA range info 88518308c94SGrygorii Strashko * @dma_addr: pointer to store initial DMA address of DMA range 88618308c94SGrygorii Strashko * @paddr: pointer to store initial CPU address of DMA range 88718308c94SGrygorii Strashko * @size: pointer to store size of DMA range 88818308c94SGrygorii Strashko * 88918308c94SGrygorii Strashko * Look in bottom up direction for the first "dma-ranges" property 89018308c94SGrygorii Strashko * and parse it. 89118308c94SGrygorii Strashko * dma-ranges format: 89218308c94SGrygorii Strashko * DMA addr (dma_addr) : naddr cells 89318308c94SGrygorii Strashko * CPU addr (phys_addr_t) : pna cells 89418308c94SGrygorii Strashko * size : nsize cells 89518308c94SGrygorii Strashko * 89618308c94SGrygorii Strashko * It returns -ENODEV if "dma-ranges" property was not found 89718308c94SGrygorii Strashko * for this device in DT. 89818308c94SGrygorii Strashko */ 89918308c94SGrygorii Strashko int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size) 90018308c94SGrygorii Strashko { 90118308c94SGrygorii Strashko struct device_node *node = of_node_get(np); 90218308c94SGrygorii Strashko const __be32 *ranges = NULL; 90318308c94SGrygorii Strashko int len, naddr, nsize, pna; 90418308c94SGrygorii Strashko int ret = 0; 90518308c94SGrygorii Strashko u64 dmaaddr; 90618308c94SGrygorii Strashko 90718308c94SGrygorii Strashko if (!node) 90818308c94SGrygorii Strashko return -EINVAL; 90918308c94SGrygorii Strashko 91018308c94SGrygorii Strashko while (1) { 91118308c94SGrygorii Strashko naddr = of_n_addr_cells(node); 91218308c94SGrygorii Strashko nsize = of_n_size_cells(node); 91318308c94SGrygorii Strashko node = of_get_next_parent(node); 91418308c94SGrygorii Strashko if (!node) 91518308c94SGrygorii Strashko break; 91618308c94SGrygorii Strashko 91718308c94SGrygorii Strashko ranges = of_get_property(node, "dma-ranges", &len); 91818308c94SGrygorii Strashko 91918308c94SGrygorii Strashko /* Ignore empty ranges, they imply no translation required */ 92018308c94SGrygorii Strashko if (ranges && len > 0) 92118308c94SGrygorii Strashko break; 92218308c94SGrygorii Strashko 92318308c94SGrygorii Strashko /* 92418308c94SGrygorii Strashko * At least empty ranges has to be defined for parent node if 92518308c94SGrygorii Strashko * DMA is supported 92618308c94SGrygorii Strashko */ 92718308c94SGrygorii Strashko if (!ranges) 92818308c94SGrygorii Strashko break; 92918308c94SGrygorii Strashko } 93018308c94SGrygorii Strashko 93118308c94SGrygorii Strashko if (!ranges) { 9320d638a07SRob Herring pr_debug("no dma-ranges found for node(%pOF)\n", np); 93318308c94SGrygorii Strashko ret = -ENODEV; 93418308c94SGrygorii Strashko goto out; 93518308c94SGrygorii Strashko } 93618308c94SGrygorii Strashko 93718308c94SGrygorii Strashko len /= sizeof(u32); 93818308c94SGrygorii Strashko 93918308c94SGrygorii Strashko pna = of_n_addr_cells(node); 94018308c94SGrygorii Strashko 94118308c94SGrygorii Strashko /* dma-ranges format: 94218308c94SGrygorii Strashko * DMA addr : naddr cells 94318308c94SGrygorii Strashko * CPU addr : pna cells 94418308c94SGrygorii Strashko * size : nsize cells 94518308c94SGrygorii Strashko */ 94618308c94SGrygorii Strashko dmaaddr = of_read_number(ranges, naddr); 94718308c94SGrygorii Strashko *paddr = of_translate_dma_address(np, ranges); 94818308c94SGrygorii Strashko if (*paddr == OF_BAD_ADDR) { 9490d638a07SRob Herring pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n", 9500d638a07SRob Herring dma_addr, np); 95118308c94SGrygorii Strashko ret = -EINVAL; 95218308c94SGrygorii Strashko goto out; 95318308c94SGrygorii Strashko } 95418308c94SGrygorii Strashko *dma_addr = dmaaddr; 95518308c94SGrygorii Strashko 95618308c94SGrygorii Strashko *size = of_read_number(ranges + naddr + pna, nsize); 95718308c94SGrygorii Strashko 95818308c94SGrygorii Strashko pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", 95918308c94SGrygorii Strashko *dma_addr, *paddr, *size); 96018308c94SGrygorii Strashko 96118308c94SGrygorii Strashko out: 96218308c94SGrygorii Strashko of_node_put(node); 96318308c94SGrygorii Strashko 96418308c94SGrygorii Strashko return ret; 96518308c94SGrygorii Strashko } 96618308c94SGrygorii Strashko EXPORT_SYMBOL_GPL(of_dma_get_range); 96792ea637eSSantosh Shilimkar 96892ea637eSSantosh Shilimkar /** 96992ea637eSSantosh Shilimkar * of_dma_is_coherent - Check if device is coherent 97092ea637eSSantosh Shilimkar * @np: device node 97192ea637eSSantosh Shilimkar * 97292ea637eSSantosh Shilimkar * It returns true if "dma-coherent" property was found 97392ea637eSSantosh Shilimkar * for this device in DT. 97492ea637eSSantosh Shilimkar */ 97592ea637eSSantosh Shilimkar bool of_dma_is_coherent(struct device_node *np) 97692ea637eSSantosh Shilimkar { 97792ea637eSSantosh Shilimkar struct device_node *node = of_node_get(np); 97892ea637eSSantosh Shilimkar 97992ea637eSSantosh Shilimkar while (node) { 98092ea637eSSantosh Shilimkar if (of_property_read_bool(node, "dma-coherent")) { 98192ea637eSSantosh Shilimkar of_node_put(node); 98292ea637eSSantosh Shilimkar return true; 98392ea637eSSantosh Shilimkar } 98492ea637eSSantosh Shilimkar node = of_get_next_parent(node); 98592ea637eSSantosh Shilimkar } 98692ea637eSSantosh Shilimkar of_node_put(node); 98792ea637eSSantosh Shilimkar return false; 98892ea637eSSantosh Shilimkar } 98992ea637eSSantosh Shilimkar EXPORT_SYMBOL_GPL(of_dma_is_coherent); 990