at v2.6.25 504 lines 10 kB view raw
1/* 2 * Platform device setup for Marvell mv64360/mv64460 host bridges (Discovery) 3 * 4 * Author: Dale Farnsworth <dale@farnsworth.org> 5 * 6 * 2007 (c) MontaVista, Software, Inc. This file is licensed under 7 * the terms of the GNU General Public License version 2. This program 8 * is licensed "as is" without any warranty of any kind, whether express 9 * or implied. 10 */ 11 12#include <linux/stddef.h> 13#include <linux/kernel.h> 14#include <linux/init.h> 15#include <linux/console.h> 16#include <linux/mv643xx.h> 17#include <linux/platform_device.h> 18 19#include <asm/prom.h> 20 21/* 22 * These functions provide the necessary setup for the mv64x60 drivers. 23 * These drivers are unusual in that they work on both the MIPS and PowerPC 24 * architectures. Because of that, the drivers do not support the normal 25 * PowerPC of_platform_bus_type. They support platform_bus_type instead. 26 */ 27 28/* 29 * Create MPSC platform devices 30 */ 31static int __init mv64x60_mpsc_register_shared_pdev(struct device_node *np) 32{ 33 struct platform_device *pdev; 34 struct resource r[2]; 35 struct mpsc_shared_pdata pdata; 36 const phandle *ph; 37 struct device_node *mpscrouting, *mpscintr; 38 int err; 39 40 ph = of_get_property(np, "mpscrouting", NULL); 41 mpscrouting = of_find_node_by_phandle(*ph); 42 if (!mpscrouting) 43 return -ENODEV; 44 45 err = of_address_to_resource(mpscrouting, 0, &r[0]); 46 of_node_put(mpscrouting); 47 if (err) 48 return err; 49 50 ph = of_get_property(np, "mpscintr", NULL); 51 mpscintr = of_find_node_by_phandle(*ph); 52 if (!mpscintr) 53 return -ENODEV; 54 55 err = of_address_to_resource(mpscintr, 0, &r[1]); 56 of_node_put(mpscintr); 57 if (err) 58 return err; 59 60 memset(&pdata, 0, sizeof(pdata)); 61 62 pdev = platform_device_alloc(MPSC_SHARED_NAME, 0); 63 if (!pdev) 64 return -ENOMEM; 65 66 err = platform_device_add_resources(pdev, r, 2); 67 if (err) 68 goto error; 69 70 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 71 if (err) 72 goto error; 73 74 err = platform_device_add(pdev); 75 if (err) 76 goto error; 77 78 return 0; 79 80error: 81 platform_device_put(pdev); 82 return err; 83} 84 85 86static int __init mv64x60_mpsc_device_setup(struct device_node *np, int id) 87{ 88 struct resource r[5]; 89 struct mpsc_pdata pdata; 90 struct platform_device *pdev; 91 const unsigned int *prop; 92 const phandle *ph; 93 struct device_node *sdma, *brg; 94 int err; 95 int port_number; 96 97 /* only register the shared platform device the first time through */ 98 if (id == 0 && (err = mv64x60_mpsc_register_shared_pdev(np))) 99 return err; 100 101 memset(r, 0, sizeof(r)); 102 103 err = of_address_to_resource(np, 0, &r[0]); 104 if (err) 105 return err; 106 107 of_irq_to_resource(np, 0, &r[4]); 108 109 ph = of_get_property(np, "sdma", NULL); 110 sdma = of_find_node_by_phandle(*ph); 111 if (!sdma) 112 return -ENODEV; 113 114 of_irq_to_resource(sdma, 0, &r[3]); 115 err = of_address_to_resource(sdma, 0, &r[1]); 116 of_node_put(sdma); 117 if (err) 118 return err; 119 120 ph = of_get_property(np, "brg", NULL); 121 brg = of_find_node_by_phandle(*ph); 122 if (!brg) 123 return -ENODEV; 124 125 err = of_address_to_resource(brg, 0, &r[2]); 126 of_node_put(brg); 127 if (err) 128 return err; 129 130 prop = of_get_property(np, "block-index", NULL); 131 if (!prop) 132 return -ENODEV; 133 port_number = *(int *)prop; 134 135 memset(&pdata, 0, sizeof(pdata)); 136 137 pdata.cache_mgmt = 1; /* All current revs need this set */ 138 139 prop = of_get_property(np, "max_idle", NULL); 140 if (prop) 141 pdata.max_idle = *prop; 142 143 prop = of_get_property(brg, "current-speed", NULL); 144 if (prop) 145 pdata.default_baud = *prop; 146 147 /* Default is 8 bits, no parity, no flow control */ 148 pdata.default_bits = 8; 149 pdata.default_parity = 'n'; 150 pdata.default_flow = 'n'; 151 152 prop = of_get_property(np, "chr_1", NULL); 153 if (prop) 154 pdata.chr_1_val = *prop; 155 156 prop = of_get_property(np, "chr_2", NULL); 157 if (prop) 158 pdata.chr_2_val = *prop; 159 160 prop = of_get_property(np, "chr_10", NULL); 161 if (prop) 162 pdata.chr_10_val = *prop; 163 164 prop = of_get_property(np, "mpcr", NULL); 165 if (prop) 166 pdata.mpcr_val = *prop; 167 168 prop = of_get_property(brg, "bcr", NULL); 169 if (prop) 170 pdata.bcr_val = *prop; 171 172 pdata.brg_can_tune = 1; /* All current revs need this set */ 173 174 prop = of_get_property(brg, "clock-src", NULL); 175 if (prop) 176 pdata.brg_clk_src = *prop; 177 178 prop = of_get_property(brg, "clock-frequency", NULL); 179 if (prop) 180 pdata.brg_clk_freq = *prop; 181 182 pdev = platform_device_alloc(MPSC_CTLR_NAME, port_number); 183 if (!pdev) 184 return -ENOMEM; 185 186 err = platform_device_add_resources(pdev, r, 5); 187 if (err) 188 goto error; 189 190 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 191 if (err) 192 goto error; 193 194 err = platform_device_add(pdev); 195 if (err) 196 goto error; 197 198 return 0; 199 200error: 201 platform_device_put(pdev); 202 return err; 203} 204 205/* 206 * Create mv64x60_eth platform devices 207 */ 208static int __init eth_register_shared_pdev(struct device_node *np) 209{ 210 struct platform_device *pdev; 211 struct resource r[1]; 212 int err; 213 214 np = of_get_parent(np); 215 if (!np) 216 return -ENODEV; 217 218 err = of_address_to_resource(np, 0, &r[0]); 219 of_node_put(np); 220 if (err) 221 return err; 222 223 pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, 0, 224 r, 1); 225 if (IS_ERR(pdev)) 226 return PTR_ERR(pdev); 227 228 return 0; 229} 230 231static int __init mv64x60_eth_device_setup(struct device_node *np, int id) 232{ 233 struct resource r[1]; 234 struct mv643xx_eth_platform_data pdata; 235 struct platform_device *pdev; 236 struct device_node *phy; 237 const u8 *mac_addr; 238 const int *prop; 239 const phandle *ph; 240 int err; 241 242 /* only register the shared platform device the first time through */ 243 if (id == 0 && (err = eth_register_shared_pdev(np))) 244 return err; 245 246 memset(r, 0, sizeof(r)); 247 of_irq_to_resource(np, 0, &r[0]); 248 249 memset(&pdata, 0, sizeof(pdata)); 250 251 prop = of_get_property(np, "block-index", NULL); 252 if (!prop) 253 return -ENODEV; 254 pdata.port_number = *prop; 255 256 mac_addr = of_get_mac_address(np); 257 if (mac_addr) 258 memcpy(pdata.mac_addr, mac_addr, 6); 259 260 prop = of_get_property(np, "speed", NULL); 261 if (prop) 262 pdata.speed = *prop; 263 264 prop = of_get_property(np, "tx_queue_size", NULL); 265 if (prop) 266 pdata.tx_queue_size = *prop; 267 268 prop = of_get_property(np, "rx_queue_size", NULL); 269 if (prop) 270 pdata.rx_queue_size = *prop; 271 272 prop = of_get_property(np, "tx_sram_addr", NULL); 273 if (prop) 274 pdata.tx_sram_addr = *prop; 275 276 prop = of_get_property(np, "tx_sram_size", NULL); 277 if (prop) 278 pdata.tx_sram_size = *prop; 279 280 prop = of_get_property(np, "rx_sram_addr", NULL); 281 if (prop) 282 pdata.rx_sram_addr = *prop; 283 284 prop = of_get_property(np, "rx_sram_size", NULL); 285 if (prop) 286 pdata.rx_sram_size = *prop; 287 288 ph = of_get_property(np, "phy", NULL); 289 if (!ph) 290 return -ENODEV; 291 292 phy = of_find_node_by_phandle(*ph); 293 if (phy == NULL) 294 return -ENODEV; 295 296 prop = of_get_property(phy, "reg", NULL); 297 if (prop) { 298 pdata.force_phy_addr = 1; 299 pdata.phy_addr = *prop; 300 } 301 302 of_node_put(phy); 303 304 pdev = platform_device_alloc(MV643XX_ETH_NAME, pdata.port_number); 305 if (!pdev) 306 return -ENOMEM; 307 308 err = platform_device_add_resources(pdev, r, 1); 309 if (err) 310 goto error; 311 312 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 313 if (err) 314 goto error; 315 316 err = platform_device_add(pdev); 317 if (err) 318 goto error; 319 320 return 0; 321 322error: 323 platform_device_put(pdev); 324 return err; 325} 326 327/* 328 * Create mv64x60_i2c platform devices 329 */ 330static int __init mv64x60_i2c_device_setup(struct device_node *np, int id) 331{ 332 struct resource r[2]; 333 struct platform_device *pdev; 334 struct mv64xxx_i2c_pdata pdata; 335 const unsigned int *prop; 336 int err; 337 338 memset(r, 0, sizeof(r)); 339 340 err = of_address_to_resource(np, 0, &r[0]); 341 if (err) 342 return err; 343 344 of_irq_to_resource(np, 0, &r[1]); 345 346 memset(&pdata, 0, sizeof(pdata)); 347 348 prop = of_get_property(np, "freq_m", NULL); 349 if (!prop) 350 return -ENODEV; 351 pdata.freq_m = *prop; 352 353 prop = of_get_property(np, "freq_n", NULL); 354 if (!prop) 355 return -ENODEV; 356 pdata.freq_n = *prop; 357 358 prop = of_get_property(np, "timeout", NULL); 359 if (prop) 360 pdata.timeout = *prop; 361 else 362 pdata.timeout = 1000; /* 1 second */ 363 364 pdev = platform_device_alloc(MV64XXX_I2C_CTLR_NAME, id); 365 if (!pdev) 366 return -ENOMEM; 367 368 err = platform_device_add_resources(pdev, r, 2); 369 if (err) 370 goto error; 371 372 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 373 if (err) 374 goto error; 375 376 err = platform_device_add(pdev); 377 if (err) 378 goto error; 379 380 return 0; 381 382error: 383 platform_device_put(pdev); 384 return err; 385} 386 387/* 388 * Create mv64x60_wdt platform devices 389 */ 390static int __init mv64x60_wdt_device_setup(struct device_node *np, int id) 391{ 392 struct resource r; 393 struct platform_device *pdev; 394 struct mv64x60_wdt_pdata pdata; 395 const unsigned int *prop; 396 int err; 397 398 err = of_address_to_resource(np, 0, &r); 399 if (err) 400 return err; 401 402 memset(&pdata, 0, sizeof(pdata)); 403 404 prop = of_get_property(np, "timeout", NULL); 405 if (!prop) 406 return -ENODEV; 407 pdata.timeout = *prop; 408 409 np = of_get_parent(np); 410 if (!np) 411 return -ENODEV; 412 413 prop = of_get_property(np, "clock-frequency", NULL); 414 of_node_put(np); 415 if (!prop) 416 return -ENODEV; 417 pdata.bus_clk = *prop / 1000000; /* wdt driver wants freq in MHz */ 418 419 pdev = platform_device_alloc(MV64x60_WDT_NAME, id); 420 if (!pdev) 421 return -ENOMEM; 422 423 err = platform_device_add_resources(pdev, &r, 1); 424 if (err) 425 goto error; 426 427 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 428 if (err) 429 goto error; 430 431 err = platform_device_add(pdev); 432 if (err) 433 goto error; 434 435 return 0; 436 437error: 438 platform_device_put(pdev); 439 return err; 440} 441 442static int __init mv64x60_device_setup(void) 443{ 444 struct device_node *np = NULL; 445 int id; 446 int err; 447 448 id = 0; 449 for_each_compatible_node(np, "serial", "marvell,mpsc") 450 if ((err = mv64x60_mpsc_device_setup(np, id++))) 451 goto error; 452 453 id = 0; 454 for_each_compatible_node(np, "network", "marvell,mv64x60-eth") 455 if ((err = mv64x60_eth_device_setup(np, id++))) 456 goto error; 457 458 id = 0; 459 for_each_compatible_node(np, "i2c", "marvell,mv64x60-i2c") 460 if ((err = mv64x60_i2c_device_setup(np, id++))) 461 goto error; 462 463 /* support up to one watchdog timer */ 464 np = of_find_compatible_node(np, NULL, "marvell,mv64x60-wdt"); 465 if (np) { 466 if ((err = mv64x60_wdt_device_setup(np, id))) 467 goto error; 468 of_node_put(np); 469 } 470 471 return 0; 472 473error: 474 of_node_put(np); 475 return err; 476} 477arch_initcall(mv64x60_device_setup); 478 479static int __init mv64x60_add_mpsc_console(void) 480{ 481 struct device_node *np = NULL; 482 const char *prop; 483 484 prop = of_get_property(of_chosen, "linux,stdout-path", NULL); 485 if (prop == NULL) 486 goto not_mpsc; 487 488 np = of_find_node_by_path(prop); 489 if (!np) 490 goto not_mpsc; 491 492 if (!of_device_is_compatible(np, "marvell,mpsc")) 493 goto not_mpsc; 494 495 prop = of_get_property(np, "block-index", NULL); 496 if (!prop) 497 goto not_mpsc; 498 499 add_preferred_console("ttyMM", *(int *)prop, NULL); 500 501not_mpsc: 502 return 0; 503} 504console_initcall(mv64x60_add_mpsc_console);