at v2.6.27 526 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.force_phy_addr = 1; 298 pdata.phy_addr = *prop; 299 } 300 301 of_node_put(phy); 302 303 pdev = platform_device_alloc(MV643XX_ETH_NAME, id); 304 if (!pdev) 305 return -ENOMEM; 306 307 err = platform_device_add_resources(pdev, r, 1); 308 if (err) 309 goto error; 310 311 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 312 if (err) 313 goto error; 314 315 err = platform_device_add(pdev); 316 if (err) 317 goto error; 318 319 return 0; 320 321error: 322 platform_device_put(pdev); 323 return err; 324} 325 326/* 327 * Create mv64x60_i2c platform devices 328 */ 329static int __init mv64x60_i2c_device_setup(struct device_node *np, int id) 330{ 331 struct resource r[2]; 332 struct platform_device *pdev; 333 struct mv64xxx_i2c_pdata pdata; 334 const unsigned int *prop; 335 int err; 336 337 memset(r, 0, sizeof(r)); 338 339 err = of_address_to_resource(np, 0, &r[0]); 340 if (err) 341 return err; 342 343 of_irq_to_resource(np, 0, &r[1]); 344 345 memset(&pdata, 0, sizeof(pdata)); 346 347 pdata.freq_m = 8; /* default */ 348 prop = of_get_property(np, "freq_m", NULL); 349 if (prop) 350 pdata.freq_m = *prop; 351 352 pdata.freq_m = 3; /* default */ 353 prop = of_get_property(np, "freq_n", NULL); 354 if (prop) 355 pdata.freq_n = *prop; 356 357 pdata.timeout = 1000; /* default: 1 second */ 358 359 pdev = platform_device_alloc(MV64XXX_I2C_CTLR_NAME, id); 360 if (!pdev) 361 return -ENOMEM; 362 363 err = platform_device_add_resources(pdev, r, 2); 364 if (err) 365 goto error; 366 367 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 368 if (err) 369 goto error; 370 371 err = platform_device_add(pdev); 372 if (err) 373 goto error; 374 375 return 0; 376 377error: 378 platform_device_put(pdev); 379 return err; 380} 381 382/* 383 * Create mv64x60_wdt platform devices 384 */ 385static int __init mv64x60_wdt_device_setup(struct device_node *np, int id) 386{ 387 struct resource r; 388 struct platform_device *pdev; 389 struct mv64x60_wdt_pdata pdata; 390 const unsigned int *prop; 391 int err; 392 393 err = of_address_to_resource(np, 0, &r); 394 if (err) 395 return err; 396 397 memset(&pdata, 0, sizeof(pdata)); 398 399 pdata.timeout = 10; /* Default: 10 seconds */ 400 401 np = of_get_parent(np); 402 if (!np) 403 return -ENODEV; 404 405 prop = of_get_property(np, "clock-frequency", NULL); 406 of_node_put(np); 407 if (!prop) 408 return -ENODEV; 409 pdata.bus_clk = *prop / 1000000; /* wdt driver wants freq in MHz */ 410 411 pdev = platform_device_alloc(MV64x60_WDT_NAME, id); 412 if (!pdev) 413 return -ENOMEM; 414 415 err = platform_device_add_resources(pdev, &r, 1); 416 if (err) 417 goto error; 418 419 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 420 if (err) 421 goto error; 422 423 err = platform_device_add(pdev); 424 if (err) 425 goto error; 426 427 return 0; 428 429error: 430 platform_device_put(pdev); 431 return err; 432} 433 434static int __init mv64x60_device_setup(void) 435{ 436 struct device_node *np, *np2; 437 struct platform_device *pdev; 438 int id, id2; 439 int err; 440 441 id = 0; 442 for_each_compatible_node(np, "serial", "marvell,mv64360-mpsc") { 443 err = mv64x60_mpsc_device_setup(np, id++); 444 if (err) 445 printk(KERN_ERR "Failed to initialize MV64x60 " 446 "serial device %s: error %d.\n", 447 np->full_name, err); 448 } 449 450 id = 0; 451 id2 = 0; 452 for_each_compatible_node(np, NULL, "marvell,mv64360-eth-group") { 453 pdev = mv64x60_eth_register_shared_pdev(np, id++); 454 if (IS_ERR(pdev)) { 455 err = PTR_ERR(pdev); 456 printk(KERN_ERR "Failed to initialize MV64x60 " 457 "network block %s: error %d.\n", 458 np->full_name, err); 459 continue; 460 } 461 for_each_child_of_node(np, np2) { 462 if (!of_device_is_compatible(np2, 463 "marvell,mv64360-eth")) 464 continue; 465 err = mv64x60_eth_device_setup(np2, id2++, pdev); 466 if (err) 467 printk(KERN_ERR "Failed to initialize " 468 "MV64x60 network device %s: " 469 "error %d.\n", 470 np2->full_name, err); 471 } 472 } 473 474 id = 0; 475 for_each_compatible_node(np, "i2c", "marvell,mv64360-i2c") { 476 err = mv64x60_i2c_device_setup(np, id++); 477 if (err) 478 printk(KERN_ERR "Failed to initialize MV64x60 I2C " 479 "bus %s: error %d.\n", 480 np->full_name, err); 481 } 482 483 /* support up to one watchdog timer */ 484 np = of_find_compatible_node(np, NULL, "marvell,mv64360-wdt"); 485 if (np) { 486 if ((err = mv64x60_wdt_device_setup(np, id))) 487 printk(KERN_ERR "Failed to initialize MV64x60 " 488 "Watchdog %s: error %d.\n", 489 np->full_name, err); 490 of_node_put(np); 491 } 492 493 /* Now add every node that is on the device bus */ 494 for_each_compatible_node(np, NULL, "marvell,mv64360") 495 of_platform_bus_probe(np, of_mv64x60_devices, NULL); 496 497 return 0; 498} 499arch_initcall(mv64x60_device_setup); 500 501static int __init mv64x60_add_mpsc_console(void) 502{ 503 struct device_node *np = NULL; 504 const char *prop; 505 506 prop = of_get_property(of_chosen, "linux,stdout-path", NULL); 507 if (prop == NULL) 508 goto not_mpsc; 509 510 np = of_find_node_by_path(prop); 511 if (!np) 512 goto not_mpsc; 513 514 if (!of_device_is_compatible(np, "marvell,mv64360-mpsc")) 515 goto not_mpsc; 516 517 prop = of_get_property(np, "cell-index", NULL); 518 if (!prop) 519 goto not_mpsc; 520 521 add_preferred_console("ttyMM", *(int *)prop, NULL); 522 523not_mpsc: 524 return 0; 525} 526console_initcall(mv64x60_add_mpsc_console);