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