Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 1 | #include <linux/string.h> |
| 2 | #include <linux/kernel.h> |
| 3 | #include <linux/of.h> |
| 4 | #include <linux/init.h> |
| 5 | #include <linux/module.h> |
| 6 | #include <linux/mod_devicetable.h> |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 7 | #include <linux/errno.h> |
| 8 | #include <linux/irq.h> |
| 9 | #include <linux/of_device.h> |
| 10 | #include <linux/of_platform.h> |
| 11 | |
| 12 | #include "of_device_common.h" |
| 13 | |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 14 | unsigned int irq_of_parse_and_map(struct device_node *node, int index) |
| 15 | { |
Grant Likely | cd4cd73 | 2010-07-22 16:04:30 -0600 | [diff] [blame] | 16 | struct platform_device *op = of_find_device_by_node(node); |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 17 | |
Grant Likely | 1636f8a | 2010-06-18 11:09:58 -0600 | [diff] [blame] | 18 | if (!op || index >= op->archdata.num_irqs) |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 19 | return 0; |
| 20 | |
Grant Likely | 1636f8a | 2010-06-18 11:09:58 -0600 | [diff] [blame] | 21 | return op->archdata.irqs[index]; |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 22 | } |
| 23 | EXPORT_SYMBOL(irq_of_parse_and_map); |
| 24 | |
David S. Miller | 930952a | 2011-03-18 15:31:19 -0700 | [diff] [blame] | 25 | int of_address_to_resource(struct device_node *node, int index, |
| 26 | struct resource *r) |
| 27 | { |
| 28 | struct platform_device *op = of_find_device_by_node(node); |
| 29 | |
| 30 | if (!op || index >= op->num_resources) |
| 31 | return -EINVAL; |
| 32 | |
| 33 | memcpy(r, &op->archdata.resource[index], sizeof(*r)); |
| 34 | return 0; |
| 35 | } |
| 36 | EXPORT_SYMBOL_GPL(of_address_to_resource); |
| 37 | |
David S. Miller | 9889376 | 2011-03-18 15:47:26 -0700 | [diff] [blame] | 38 | void __iomem *of_iomap(struct device_node *node, int index) |
| 39 | { |
| 40 | struct platform_device *op = of_find_device_by_node(node); |
| 41 | struct resource *r; |
| 42 | |
| 43 | if (!op || index >= op->num_resources) |
| 44 | return NULL; |
| 45 | |
| 46 | r = &op->archdata.resource[index]; |
| 47 | |
| 48 | return of_ioremap(r, 0, resource_size(r), (char *) r->name); |
| 49 | } |
| 50 | EXPORT_SYMBOL(of_iomap); |
| 51 | |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 52 | /* Take the archdata values for IOMMU, STC, and HOSTDATA found in |
Grant Likely | cd4cd73 | 2010-07-22 16:04:30 -0600 | [diff] [blame] | 53 | * BUS and propagate to all child platform_device objects. |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 54 | */ |
Grant Likely | cd4cd73 | 2010-07-22 16:04:30 -0600 | [diff] [blame] | 55 | void of_propagate_archdata(struct platform_device *bus) |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 56 | { |
| 57 | struct dev_archdata *bus_sd = &bus->dev.archdata; |
Grant Likely | 61c7a08 | 2010-04-13 16:12:29 -0700 | [diff] [blame] | 58 | struct device_node *bus_dp = bus->dev.of_node; |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 59 | struct device_node *dp; |
| 60 | |
| 61 | for (dp = bus_dp->child; dp; dp = dp->sibling) { |
Grant Likely | cd4cd73 | 2010-07-22 16:04:30 -0600 | [diff] [blame] | 62 | struct platform_device *op = of_find_device_by_node(dp); |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 63 | |
| 64 | op->dev.archdata.iommu = bus_sd->iommu; |
| 65 | op->dev.archdata.stc = bus_sd->stc; |
| 66 | op->dev.archdata.host_controller = bus_sd->host_controller; |
| 67 | op->dev.archdata.numa_node = bus_sd->numa_node; |
| 68 | |
| 69 | if (dp->child) |
| 70 | of_propagate_archdata(op); |
| 71 | } |
| 72 | } |
| 73 | |
Robert Reif | c9f5b7e | 2009-06-04 02:00:02 -0700 | [diff] [blame] | 74 | static void get_cells(struct device_node *dp, int *addrc, int *sizec) |
| 75 | { |
| 76 | if (addrc) |
| 77 | *addrc = of_n_addr_cells(dp); |
| 78 | if (sizec) |
| 79 | *sizec = of_n_size_cells(dp); |
| 80 | } |
| 81 | |
| 82 | /* |
| 83 | * Default translator (generic bus) |
| 84 | */ |
| 85 | |
| 86 | void of_bus_default_count_cells(struct device_node *dev, int *addrc, int *sizec) |
| 87 | { |
| 88 | get_cells(dev, addrc, sizec); |
| 89 | } |
| 90 | |
| 91 | /* Make sure the least significant 64-bits are in-range. Even |
| 92 | * for 3 or 4 cell values it is a good enough approximation. |
| 93 | */ |
| 94 | int of_out_of_range(const u32 *addr, const u32 *base, |
| 95 | const u32 *size, int na, int ns) |
| 96 | { |
| 97 | u64 a = of_read_addr(addr, na); |
| 98 | u64 b = of_read_addr(base, na); |
| 99 | |
| 100 | if (a < b) |
| 101 | return 1; |
| 102 | |
| 103 | b += of_read_addr(size, ns); |
| 104 | if (a >= b) |
| 105 | return 1; |
| 106 | |
| 107 | return 0; |
| 108 | } |
| 109 | |
| 110 | int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna) |
| 111 | { |
| 112 | u32 result[OF_MAX_ADDR_CELLS]; |
| 113 | int i; |
| 114 | |
| 115 | if (ns > 2) { |
| 116 | printk("of_device: Cannot handle size cells (%d) > 2.", ns); |
| 117 | return -EINVAL; |
| 118 | } |
| 119 | |
| 120 | if (of_out_of_range(addr, range, range + na + pna, na, ns)) |
| 121 | return -EINVAL; |
| 122 | |
| 123 | /* Start with the parent range base. */ |
| 124 | memcpy(result, range + na, pna * 4); |
| 125 | |
| 126 | /* Add in the child address offset. */ |
| 127 | for (i = 0; i < na; i++) |
| 128 | result[pna - 1 - i] += |
| 129 | (addr[na - 1 - i] - |
| 130 | range[na - 1 - i]); |
| 131 | |
| 132 | memcpy(addr, result, pna * 4); |
| 133 | |
| 134 | return 0; |
| 135 | } |
| 136 | |
| 137 | unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) |
| 138 | { |
| 139 | if (flags) |
| 140 | return flags; |
| 141 | return IORESOURCE_MEM; |
| 142 | } |
| 143 | |
| 144 | /* |
| 145 | * SBUS bus specific translator |
| 146 | */ |
| 147 | |
| 148 | int of_bus_sbus_match(struct device_node *np) |
| 149 | { |
| 150 | struct device_node *dp = np; |
| 151 | |
| 152 | while (dp) { |
| 153 | if (!strcmp(dp->name, "sbus") || |
| 154 | !strcmp(dp->name, "sbi")) |
| 155 | return 1; |
| 156 | |
| 157 | /* Have a look at use_1to1_mapping(). We're trying |
| 158 | * to match SBUS if that's the top-level bus and we |
| 159 | * don't have some intervening real bus that provides |
| 160 | * ranges based translations. |
| 161 | */ |
| 162 | if (of_find_property(dp, "ranges", NULL) != NULL) |
| 163 | break; |
| 164 | |
| 165 | dp = dp->parent; |
| 166 | } |
| 167 | |
| 168 | return 0; |
| 169 | } |
| 170 | |
| 171 | void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec) |
| 172 | { |
| 173 | if (addrc) |
| 174 | *addrc = 2; |
| 175 | if (sizec) |
| 176 | *sizec = 1; |
| 177 | } |