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