[PATCH] powerpc: Add FSL SOC library and setup code

Parse the flat device tree for devices on Freescale SOC's that we know
about (gianfar, gianfar_mdio, i2c, mpc83xx_wdt). We need to setup
platform devices and platform data for these devices to match arch/ppc
usage.

Also add a helper function (get_immrbase) that reports the base
address of the MMIO registers on the SOC.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Kumar Gala and committed by
Paul Mackerras
eed32001 b8e383d5

+326
+1
arch/powerpc/sysdev/Makefile
··· 7 obj-$(CONFIG_U3_DART) += dart_iommu.o 8 obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o 9 obj-$(CONFIG_PPC_83xx) += ipic.o
··· 7 obj-$(CONFIG_U3_DART) += dart_iommu.o 8 obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o 9 obj-$(CONFIG_PPC_83xx) += ipic.o 10 + obj-$(CONFIG_FSL_SOC) += fsl_soc.o
+317
arch/powerpc/sysdev/fsl_soc.c
···
··· 1 + /* 2 + * FSL SoC setup code 3 + * 4 + * Maintained by Kumar Gala (see MAINTAINERS for contact information) 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License as published by the 8 + * Free Software Foundation; either version 2 of the License, or (at your 9 + * option) any later version. 10 + */ 11 + 12 + #include <linux/config.h> 13 + #include <linux/stddef.h> 14 + #include <linux/kernel.h> 15 + #include <linux/init.h> 16 + #include <linux/errno.h> 17 + #include <linux/major.h> 18 + #include <linux/delay.h> 19 + #include <linux/irq.h> 20 + #include <linux/module.h> 21 + #include <linux/device.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/fsl_devices.h> 24 + 25 + #include <asm/system.h> 26 + #include <asm/atomic.h> 27 + #include <asm/io.h> 28 + #include <asm/irq.h> 29 + #include <asm/prom.h> 30 + #include <sysdev/fsl_soc.h> 31 + #include <mm/mmu_decl.h> 32 + 33 + static phys_addr_t immrbase = -1; 34 + 35 + phys_addr_t get_immrbase(void) 36 + { 37 + struct device_node *soc; 38 + 39 + if (immrbase != -1) 40 + return immrbase; 41 + 42 + soc = of_find_node_by_type(NULL, "soc"); 43 + if (soc != 0) { 44 + unsigned int size; 45 + void *prop = get_property(soc, "reg", &size); 46 + immrbase = of_translate_address(soc, prop); 47 + of_node_put(soc); 48 + }; 49 + 50 + return immrbase; 51 + } 52 + EXPORT_SYMBOL(get_immrbase); 53 + 54 + static const char * gfar_tx_intr = "tx"; 55 + static const char * gfar_rx_intr = "rx"; 56 + static const char * gfar_err_intr = "error"; 57 + 58 + static int __init gfar_of_init(void) 59 + { 60 + struct device_node *np; 61 + unsigned int i; 62 + struct platform_device *mdio_dev, *gfar_dev; 63 + struct resource res; 64 + int ret; 65 + 66 + for (np = NULL, i = 0; (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; i++) { 67 + int k; 68 + struct device_node *child = NULL; 69 + struct gianfar_mdio_data mdio_data; 70 + 71 + memset(&res, 0, sizeof(res)); 72 + memset(&mdio_data, 0, sizeof(mdio_data)); 73 + 74 + ret = of_address_to_resource(np, 0, &res); 75 + if (ret) 76 + goto mdio_err; 77 + 78 + mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1); 79 + if (IS_ERR(mdio_dev)) { 80 + ret = PTR_ERR(mdio_dev); 81 + goto mdio_err; 82 + } 83 + 84 + for (k = 0; k < 32; k++) 85 + mdio_data.irq[k] = -1; 86 + 87 + while ((child = of_get_next_child(np, child)) != NULL) { 88 + if (child->n_intrs) { 89 + u32 *id = (u32 *) get_property(child, "reg", NULL); 90 + mdio_data.irq[*id] = child->intrs[0].line; 91 + } 92 + } 93 + 94 + ret = platform_device_add_data(mdio_dev, &mdio_data, sizeof(struct gianfar_mdio_data)); 95 + if (ret) 96 + goto mdio_unreg; 97 + } 98 + 99 + for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; i++) { 100 + struct resource r[4]; 101 + struct device_node *phy, *mdio; 102 + struct gianfar_platform_data gfar_data; 103 + unsigned int *id; 104 + char *model; 105 + void *mac_addr; 106 + phandle *ph; 107 + 108 + memset(r, 0, sizeof(r)); 109 + memset(&gfar_data, 0, sizeof(gfar_data)); 110 + 111 + ret = of_address_to_resource(np, 0, &r[0]); 112 + if (ret) 113 + goto gfar_err; 114 + 115 + r[1].start = np->intrs[0].line; 116 + r[1].end = np->intrs[0].line; 117 + r[1].flags = IORESOURCE_IRQ; 118 + 119 + model = get_property(np, "model", NULL); 120 + 121 + /* If we aren't the FEC we have multiple interrupts */ 122 + if (model && strcasecmp(model, "FEC")) { 123 + r[1].name = gfar_tx_intr; 124 + 125 + r[2].name = gfar_rx_intr; 126 + r[2].start = np->intrs[1].line; 127 + r[2].end = np->intrs[1].line; 128 + r[2].flags = IORESOURCE_IRQ; 129 + 130 + r[3].name = gfar_err_intr; 131 + r[3].start = np->intrs[2].line; 132 + r[3].end = np->intrs[2].line; 133 + r[3].flags = IORESOURCE_IRQ; 134 + } 135 + 136 + gfar_dev = platform_device_register_simple("fsl-gianfar", i, &r[0], np->n_intrs + 1); 137 + 138 + if (IS_ERR(gfar_dev)) { 139 + ret = PTR_ERR(gfar_dev); 140 + goto gfar_err; 141 + } 142 + 143 + mac_addr = get_property(np, "address", NULL); 144 + memcpy(gfar_data.mac_addr, mac_addr, 6); 145 + 146 + if (model && !strcasecmp(model, "TSEC")) 147 + gfar_data.device_flags = 148 + FSL_GIANFAR_DEV_HAS_GIGABIT | 149 + FSL_GIANFAR_DEV_HAS_COALESCE | 150 + FSL_GIANFAR_DEV_HAS_RMON | 151 + FSL_GIANFAR_DEV_HAS_MULTI_INTR; 152 + if (model && !strcasecmp(model, "eTSEC")) 153 + gfar_data.device_flags = 154 + FSL_GIANFAR_DEV_HAS_GIGABIT | 155 + FSL_GIANFAR_DEV_HAS_COALESCE | 156 + FSL_GIANFAR_DEV_HAS_RMON | 157 + FSL_GIANFAR_DEV_HAS_MULTI_INTR | 158 + FSL_GIANFAR_DEV_HAS_CSUM | 159 + FSL_GIANFAR_DEV_HAS_VLAN | 160 + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; 161 + 162 + ph = (phandle *) get_property(np, "phy-handle", NULL); 163 + phy = of_find_node_by_phandle(*ph); 164 + 165 + if (phy == NULL) { 166 + ret = -ENODEV; 167 + goto gfar_unreg; 168 + } 169 + 170 + mdio = of_get_parent(phy); 171 + 172 + id = (u32 *) get_property(phy, "reg", NULL); 173 + ret = of_address_to_resource(mdio, 0, &res); 174 + if (ret) { 175 + of_node_put(phy); 176 + of_node_put(mdio); 177 + goto gfar_unreg; 178 + } 179 + 180 + gfar_data.phy_id = *id; 181 + gfar_data.bus_id = res.start; 182 + 183 + of_node_put(phy); 184 + of_node_put(mdio); 185 + 186 + ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct gianfar_platform_data)); 187 + if (ret) 188 + goto gfar_unreg; 189 + } 190 + 191 + return 0; 192 + 193 + mdio_unreg: 194 + platform_device_unregister(mdio_dev); 195 + mdio_err: 196 + return ret; 197 + 198 + gfar_unreg: 199 + platform_device_unregister(gfar_dev); 200 + gfar_err: 201 + return ret; 202 + } 203 + arch_initcall(gfar_of_init); 204 + 205 + static int __init fsl_i2c_of_init(void) 206 + { 207 + struct device_node *np; 208 + unsigned int i; 209 + struct platform_device *i2c_dev; 210 + int ret; 211 + 212 + for (np = NULL, i = 0; (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; i++) { 213 + struct resource r[2]; 214 + struct fsl_i2c_platform_data i2c_data; 215 + unsigned char * flags = NULL; 216 + 217 + memset(&r, 0, sizeof(r)); 218 + memset(&i2c_data, 0, sizeof(i2c_data)); 219 + 220 + ret = of_address_to_resource(np, 0, &r[0]); 221 + if (ret) 222 + goto i2c_err; 223 + 224 + r[1].start = np->intrs[0].line; 225 + r[1].end = np->intrs[0].line; 226 + r[1].flags = IORESOURCE_IRQ; 227 + 228 + i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2); 229 + if (IS_ERR(i2c_dev)) { 230 + ret = PTR_ERR(i2c_dev); 231 + goto i2c_err; 232 + } 233 + 234 + i2c_data.device_flags = 0; 235 + flags = get_property(np, "dfsrr", NULL); 236 + if (flags) 237 + i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR; 238 + 239 + flags = get_property(np, "fsl5200-clocking", NULL); 240 + if (flags) 241 + i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200; 242 + 243 + ret = platform_device_add_data(i2c_dev, &i2c_data, sizeof(struct fsl_i2c_platform_data)); 244 + if (ret) 245 + goto i2c_unreg; 246 + } 247 + 248 + return 0; 249 + 250 + i2c_unreg: 251 + platform_device_unregister(i2c_dev); 252 + i2c_err: 253 + return ret; 254 + } 255 + arch_initcall(fsl_i2c_of_init); 256 + 257 + #ifdef CONFIG_PPC_83xx 258 + static int __init mpc83xx_wdt_init(void) 259 + { 260 + struct resource r; 261 + struct device_node *soc, *np; 262 + struct platform_device *dev; 263 + unsigned int *freq; 264 + int ret; 265 + 266 + np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt"); 267 + 268 + if (!np) { 269 + ret = -ENODEV; 270 + goto mpc83xx_wdt_nodev; 271 + } 272 + 273 + soc = of_find_node_by_type(NULL, "soc"); 274 + 275 + if (!soc) { 276 + ret = -ENODEV; 277 + goto mpc83xx_wdt_nosoc; 278 + } 279 + 280 + freq = (unsigned int *)get_property(soc, "bus-frequency", NULL); 281 + if (!freq) { 282 + ret = -ENODEV; 283 + goto mpc83xx_wdt_err; 284 + } 285 + 286 + memset(&r, 0, sizeof(r)); 287 + 288 + ret = of_address_to_resource(np, 0, &r); 289 + if (ret) 290 + goto mpc83xx_wdt_err; 291 + 292 + dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1); 293 + if (IS_ERR(dev)) { 294 + ret = PTR_ERR(dev); 295 + goto mpc83xx_wdt_err; 296 + } 297 + 298 + ret = platform_device_add_data(dev, freq, sizeof(int)); 299 + if (ret) 300 + goto mpc83xx_wdt_unreg; 301 + 302 + of_node_put(soc); 303 + of_node_put(np); 304 + 305 + return 0; 306 + 307 + mpc83xx_wdt_unreg: 308 + platform_device_unregister(dev); 309 + mpc83xx_wdt_err: 310 + of_node_put(soc); 311 + mpc83xx_wdt_nosoc: 312 + of_node_put(np); 313 + mpc83xx_wdt_nodev: 314 + return ret; 315 + } 316 + arch_initcall(mpc83xx_wdt_init); 317 + #endif
+8
arch/powerpc/sysdev/fsl_soc.h
···
··· 1 + #ifndef __PPC_FSL_SOC_H 2 + #define __PPC_FSL_SOC_H 3 + #ifdef __KERNEL__ 4 + 5 + extern phys_addr_t get_immrbase(void); 6 + 7 + #endif 8 + #endif