common.c revision 3a8f744169ebcb0064c46a755d9e3e27233f048a
1/* 2 * arch/arm/mach-orion5x/common.c 3 * 4 * Core functions for Marvell Orion 5x SoCs 5 * 6 * Maintainer: Tzachi Perelstein <tzachi@marvell.com> 7 * 8 * This file is licensed under the terms of the GNU General Public 9 * License version 2. This program is licensed "as is" without any 10 * warranty of any kind, whether express or implied. 11 */ 12 13#include <linux/kernel.h> 14#include <linux/init.h> 15#include <linux/platform_device.h> 16#include <linux/serial_8250.h> 17#include <linux/mbus.h> 18#include <linux/mv643xx_eth.h> 19#include <linux/mv643xx_i2c.h> 20#include <linux/ata_platform.h> 21#include <linux/spi/orion_spi.h> 22#include <net/dsa.h> 23#include <asm/page.h> 24#include <asm/setup.h> 25#include <asm/timex.h> 26#include <asm/mach/arch.h> 27#include <asm/mach/map.h> 28#include <asm/mach/time.h> 29#include <mach/hardware.h> 30#include <mach/orion5x.h> 31#include <plat/ehci-orion.h> 32#include <plat/mv_xor.h> 33#include <plat/orion_nand.h> 34#include <plat/orion_wdt.h> 35#include <plat/time.h> 36#include "common.h" 37 38/***************************************************************************** 39 * I/O Address Mapping 40 ****************************************************************************/ 41static struct map_desc orion5x_io_desc[] __initdata = { 42 { 43 .virtual = ORION5X_REGS_VIRT_BASE, 44 .pfn = __phys_to_pfn(ORION5X_REGS_PHYS_BASE), 45 .length = ORION5X_REGS_SIZE, 46 .type = MT_DEVICE, 47 }, { 48 .virtual = ORION5X_PCIE_IO_VIRT_BASE, 49 .pfn = __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE), 50 .length = ORION5X_PCIE_IO_SIZE, 51 .type = MT_DEVICE, 52 }, { 53 .virtual = ORION5X_PCI_IO_VIRT_BASE, 54 .pfn = __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE), 55 .length = ORION5X_PCI_IO_SIZE, 56 .type = MT_DEVICE, 57 }, { 58 .virtual = ORION5X_PCIE_WA_VIRT_BASE, 59 .pfn = __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE), 60 .length = ORION5X_PCIE_WA_SIZE, 61 .type = MT_DEVICE, 62 }, 63}; 64 65void __init orion5x_map_io(void) 66{ 67 iotable_init(orion5x_io_desc, ARRAY_SIZE(orion5x_io_desc)); 68} 69 70 71/***************************************************************************** 72 * EHCI 73 ****************************************************************************/ 74static struct orion_ehci_data orion5x_ehci_data = { 75 .dram = &orion5x_mbus_dram_info, 76 .phy_version = EHCI_PHY_ORION, 77}; 78 79static u64 ehci_dmamask = 0xffffffffUL; 80 81 82/***************************************************************************** 83 * EHCI0 84 ****************************************************************************/ 85static struct resource orion5x_ehci0_resources[] = { 86 { 87 .start = ORION5X_USB0_PHYS_BASE, 88 .end = ORION5X_USB0_PHYS_BASE + SZ_4K - 1, 89 .flags = IORESOURCE_MEM, 90 }, { 91 .start = IRQ_ORION5X_USB0_CTRL, 92 .end = IRQ_ORION5X_USB0_CTRL, 93 .flags = IORESOURCE_IRQ, 94 }, 95}; 96 97static struct platform_device orion5x_ehci0 = { 98 .name = "orion-ehci", 99 .id = 0, 100 .dev = { 101 .dma_mask = &ehci_dmamask, 102 .coherent_dma_mask = 0xffffffff, 103 .platform_data = &orion5x_ehci_data, 104 }, 105 .resource = orion5x_ehci0_resources, 106 .num_resources = ARRAY_SIZE(orion5x_ehci0_resources), 107}; 108 109void __init orion5x_ehci0_init(void) 110{ 111 platform_device_register(&orion5x_ehci0); 112} 113 114 115/***************************************************************************** 116 * EHCI1 117 ****************************************************************************/ 118static struct resource orion5x_ehci1_resources[] = { 119 { 120 .start = ORION5X_USB1_PHYS_BASE, 121 .end = ORION5X_USB1_PHYS_BASE + SZ_4K - 1, 122 .flags = IORESOURCE_MEM, 123 }, { 124 .start = IRQ_ORION5X_USB1_CTRL, 125 .end = IRQ_ORION5X_USB1_CTRL, 126 .flags = IORESOURCE_IRQ, 127 }, 128}; 129 130static struct platform_device orion5x_ehci1 = { 131 .name = "orion-ehci", 132 .id = 1, 133 .dev = { 134 .dma_mask = &ehci_dmamask, 135 .coherent_dma_mask = 0xffffffff, 136 .platform_data = &orion5x_ehci_data, 137 }, 138 .resource = orion5x_ehci1_resources, 139 .num_resources = ARRAY_SIZE(orion5x_ehci1_resources), 140}; 141 142void __init orion5x_ehci1_init(void) 143{ 144 platform_device_register(&orion5x_ehci1); 145} 146 147 148/***************************************************************************** 149 * GigE 150 ****************************************************************************/ 151struct mv643xx_eth_shared_platform_data orion5x_eth_shared_data = { 152 .dram = &orion5x_mbus_dram_info, 153}; 154 155static struct resource orion5x_eth_shared_resources[] = { 156 { 157 .start = ORION5X_ETH_PHYS_BASE + 0x2000, 158 .end = ORION5X_ETH_PHYS_BASE + 0x3fff, 159 .flags = IORESOURCE_MEM, 160 }, { 161 .start = IRQ_ORION5X_ETH_ERR, 162 .end = IRQ_ORION5X_ETH_ERR, 163 .flags = IORESOURCE_IRQ, 164 }, 165}; 166 167static struct platform_device orion5x_eth_shared = { 168 .name = MV643XX_ETH_SHARED_NAME, 169 .id = 0, 170 .dev = { 171 .platform_data = &orion5x_eth_shared_data, 172 }, 173 .num_resources = ARRAY_SIZE(orion5x_eth_shared_resources), 174 .resource = orion5x_eth_shared_resources, 175}; 176 177static struct resource orion5x_eth_resources[] = { 178 { 179 .name = "eth irq", 180 .start = IRQ_ORION5X_ETH_SUM, 181 .end = IRQ_ORION5X_ETH_SUM, 182 .flags = IORESOURCE_IRQ, 183 }, 184}; 185 186static struct platform_device orion5x_eth = { 187 .name = MV643XX_ETH_NAME, 188 .id = 0, 189 .num_resources = 1, 190 .resource = orion5x_eth_resources, 191 .dev = { 192 .coherent_dma_mask = 0xffffffff, 193 }, 194}; 195 196void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) 197{ 198 eth_data->shared = &orion5x_eth_shared; 199 orion5x_eth.dev.platform_data = eth_data; 200 201 platform_device_register(&orion5x_eth_shared); 202 platform_device_register(&orion5x_eth); 203} 204 205 206/***************************************************************************** 207 * Ethernet switch 208 ****************************************************************************/ 209static struct resource orion5x_switch_resources[] = { 210 { 211 .start = 0, 212 .end = 0, 213 .flags = IORESOURCE_IRQ, 214 }, 215}; 216 217static struct platform_device orion5x_switch_device = { 218 .name = "dsa", 219 .id = 0, 220 .num_resources = 0, 221 .resource = orion5x_switch_resources, 222}; 223 224void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq) 225{ 226 int i; 227 228 if (irq != NO_IRQ) { 229 orion5x_switch_resources[0].start = irq; 230 orion5x_switch_resources[0].end = irq; 231 orion5x_switch_device.num_resources = 1; 232 } 233 234 d->netdev = &orion5x_eth.dev; 235 for (i = 0; i < d->nr_chips; i++) 236 d->chip[i].mii_bus = &orion5x_eth_shared.dev; 237 orion5x_switch_device.dev.platform_data = d; 238 239 platform_device_register(&orion5x_switch_device); 240} 241 242 243/***************************************************************************** 244 * I2C 245 ****************************************************************************/ 246static struct mv64xxx_i2c_pdata orion5x_i2c_pdata = { 247 .freq_m = 8, /* assumes 166 MHz TCLK */ 248 .freq_n = 3, 249 .timeout = 1000, /* Default timeout of 1 second */ 250}; 251 252static struct resource orion5x_i2c_resources[] = { 253 { 254 .start = I2C_PHYS_BASE, 255 .end = I2C_PHYS_BASE + 0x1f, 256 .flags = IORESOURCE_MEM, 257 }, { 258 .start = IRQ_ORION5X_I2C, 259 .end = IRQ_ORION5X_I2C, 260 .flags = IORESOURCE_IRQ, 261 }, 262}; 263 264static struct platform_device orion5x_i2c = { 265 .name = MV64XXX_I2C_CTLR_NAME, 266 .id = 0, 267 .num_resources = ARRAY_SIZE(orion5x_i2c_resources), 268 .resource = orion5x_i2c_resources, 269 .dev = { 270 .platform_data = &orion5x_i2c_pdata, 271 }, 272}; 273 274void __init orion5x_i2c_init(void) 275{ 276 platform_device_register(&orion5x_i2c); 277} 278 279 280/***************************************************************************** 281 * SATA 282 ****************************************************************************/ 283static struct resource orion5x_sata_resources[] = { 284 { 285 .name = "sata base", 286 .start = ORION5X_SATA_PHYS_BASE, 287 .end = ORION5X_SATA_PHYS_BASE + 0x5000 - 1, 288 .flags = IORESOURCE_MEM, 289 }, { 290 .name = "sata irq", 291 .start = IRQ_ORION5X_SATA, 292 .end = IRQ_ORION5X_SATA, 293 .flags = IORESOURCE_IRQ, 294 }, 295}; 296 297static struct platform_device orion5x_sata = { 298 .name = "sata_mv", 299 .id = 0, 300 .dev = { 301 .coherent_dma_mask = 0xffffffff, 302 }, 303 .num_resources = ARRAY_SIZE(orion5x_sata_resources), 304 .resource = orion5x_sata_resources, 305}; 306 307void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) 308{ 309 sata_data->dram = &orion5x_mbus_dram_info; 310 orion5x_sata.dev.platform_data = sata_data; 311 platform_device_register(&orion5x_sata); 312} 313 314 315/***************************************************************************** 316 * SPI 317 ****************************************************************************/ 318static struct orion_spi_info orion5x_spi_plat_data = { 319 .tclk = 0, 320 .enable_clock_fix = 1, 321}; 322 323static struct resource orion5x_spi_resources[] = { 324 { 325 .name = "spi base", 326 .start = SPI_PHYS_BASE, 327 .end = SPI_PHYS_BASE + 0x1f, 328 .flags = IORESOURCE_MEM, 329 }, 330}; 331 332static struct platform_device orion5x_spi = { 333 .name = "orion_spi", 334 .id = 0, 335 .dev = { 336 .platform_data = &orion5x_spi_plat_data, 337 }, 338 .num_resources = ARRAY_SIZE(orion5x_spi_resources), 339 .resource = orion5x_spi_resources, 340}; 341 342void __init orion5x_spi_init() 343{ 344 platform_device_register(&orion5x_spi); 345} 346 347 348/***************************************************************************** 349 * UART0 350 ****************************************************************************/ 351static struct plat_serial8250_port orion5x_uart0_data[] = { 352 { 353 .mapbase = UART0_PHYS_BASE, 354 .membase = (char *)UART0_VIRT_BASE, 355 .irq = IRQ_ORION5X_UART0, 356 .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, 357 .iotype = UPIO_MEM, 358 .regshift = 2, 359 .uartclk = 0, 360 }, { 361 }, 362}; 363 364static struct resource orion5x_uart0_resources[] = { 365 { 366 .start = UART0_PHYS_BASE, 367 .end = UART0_PHYS_BASE + 0xff, 368 .flags = IORESOURCE_MEM, 369 }, { 370 .start = IRQ_ORION5X_UART0, 371 .end = IRQ_ORION5X_UART0, 372 .flags = IORESOURCE_IRQ, 373 }, 374}; 375 376static struct platform_device orion5x_uart0 = { 377 .name = "serial8250", 378 .id = PLAT8250_DEV_PLATFORM, 379 .dev = { 380 .platform_data = orion5x_uart0_data, 381 }, 382 .resource = orion5x_uart0_resources, 383 .num_resources = ARRAY_SIZE(orion5x_uart0_resources), 384}; 385 386void __init orion5x_uart0_init(void) 387{ 388 platform_device_register(&orion5x_uart0); 389} 390 391 392/***************************************************************************** 393 * UART1 394 ****************************************************************************/ 395static struct plat_serial8250_port orion5x_uart1_data[] = { 396 { 397 .mapbase = UART1_PHYS_BASE, 398 .membase = (char *)UART1_VIRT_BASE, 399 .irq = IRQ_ORION5X_UART1, 400 .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, 401 .iotype = UPIO_MEM, 402 .regshift = 2, 403 .uartclk = 0, 404 }, { 405 }, 406}; 407 408static struct resource orion5x_uart1_resources[] = { 409 { 410 .start = UART1_PHYS_BASE, 411 .end = UART1_PHYS_BASE + 0xff, 412 .flags = IORESOURCE_MEM, 413 }, { 414 .start = IRQ_ORION5X_UART1, 415 .end = IRQ_ORION5X_UART1, 416 .flags = IORESOURCE_IRQ, 417 }, 418}; 419 420static struct platform_device orion5x_uart1 = { 421 .name = "serial8250", 422 .id = PLAT8250_DEV_PLATFORM1, 423 .dev = { 424 .platform_data = orion5x_uart1_data, 425 }, 426 .resource = orion5x_uart1_resources, 427 .num_resources = ARRAY_SIZE(orion5x_uart1_resources), 428}; 429 430void __init orion5x_uart1_init(void) 431{ 432 platform_device_register(&orion5x_uart1); 433} 434 435 436/***************************************************************************** 437 * XOR engine 438 ****************************************************************************/ 439struct mv_xor_platform_shared_data orion5x_xor_shared_data = { 440 .dram = &orion5x_mbus_dram_info, 441}; 442 443static struct resource orion5x_xor_shared_resources[] = { 444 { 445 .name = "xor low", 446 .start = ORION5X_XOR_PHYS_BASE, 447 .end = ORION5X_XOR_PHYS_BASE + 0xff, 448 .flags = IORESOURCE_MEM, 449 }, { 450 .name = "xor high", 451 .start = ORION5X_XOR_PHYS_BASE + 0x200, 452 .end = ORION5X_XOR_PHYS_BASE + 0x2ff, 453 .flags = IORESOURCE_MEM, 454 }, 455}; 456 457static struct platform_device orion5x_xor_shared = { 458 .name = MV_XOR_SHARED_NAME, 459 .id = 0, 460 .dev = { 461 .platform_data = &orion5x_xor_shared_data, 462 }, 463 .num_resources = ARRAY_SIZE(orion5x_xor_shared_resources), 464 .resource = orion5x_xor_shared_resources, 465}; 466 467static u64 orion5x_xor_dmamask = DMA_BIT_MASK(32); 468 469static struct resource orion5x_xor0_resources[] = { 470 [0] = { 471 .start = IRQ_ORION5X_XOR0, 472 .end = IRQ_ORION5X_XOR0, 473 .flags = IORESOURCE_IRQ, 474 }, 475}; 476 477static struct mv_xor_platform_data orion5x_xor0_data = { 478 .shared = &orion5x_xor_shared, 479 .hw_id = 0, 480 .pool_size = PAGE_SIZE, 481}; 482 483static struct platform_device orion5x_xor0_channel = { 484 .name = MV_XOR_NAME, 485 .id = 0, 486 .num_resources = ARRAY_SIZE(orion5x_xor0_resources), 487 .resource = orion5x_xor0_resources, 488 .dev = { 489 .dma_mask = &orion5x_xor_dmamask, 490 .coherent_dma_mask = DMA_BIT_MASK(64), 491 .platform_data = (void *)&orion5x_xor0_data, 492 }, 493}; 494 495static struct resource orion5x_xor1_resources[] = { 496 [0] = { 497 .start = IRQ_ORION5X_XOR1, 498 .end = IRQ_ORION5X_XOR1, 499 .flags = IORESOURCE_IRQ, 500 }, 501}; 502 503static struct mv_xor_platform_data orion5x_xor1_data = { 504 .shared = &orion5x_xor_shared, 505 .hw_id = 1, 506 .pool_size = PAGE_SIZE, 507}; 508 509static struct platform_device orion5x_xor1_channel = { 510 .name = MV_XOR_NAME, 511 .id = 1, 512 .num_resources = ARRAY_SIZE(orion5x_xor1_resources), 513 .resource = orion5x_xor1_resources, 514 .dev = { 515 .dma_mask = &orion5x_xor_dmamask, 516 .coherent_dma_mask = DMA_BIT_MASK(64), 517 .platform_data = (void *)&orion5x_xor1_data, 518 }, 519}; 520 521void __init orion5x_xor_init(void) 522{ 523 platform_device_register(&orion5x_xor_shared); 524 525 /* 526 * two engines can't do memset simultaneously, this limitation 527 * satisfied by removing memset support from one of the engines. 528 */ 529 dma_cap_set(DMA_MEMCPY, orion5x_xor0_data.cap_mask); 530 dma_cap_set(DMA_XOR, orion5x_xor0_data.cap_mask); 531 platform_device_register(&orion5x_xor0_channel); 532 533 dma_cap_set(DMA_MEMCPY, orion5x_xor1_data.cap_mask); 534 dma_cap_set(DMA_MEMSET, orion5x_xor1_data.cap_mask); 535 dma_cap_set(DMA_XOR, orion5x_xor1_data.cap_mask); 536 platform_device_register(&orion5x_xor1_channel); 537} 538 539static struct resource orion5x_crypto_res[] = { 540 { 541 .name = "regs", 542 .start = ORION5X_CRYPTO_PHYS_BASE, 543 .end = ORION5X_CRYPTO_PHYS_BASE + 0xffff, 544 .flags = IORESOURCE_MEM, 545 }, { 546 .name = "sram", 547 .start = ORION5X_SRAM_PHYS_BASE, 548 .end = ORION5X_SRAM_PHYS_BASE + SZ_8K - 1, 549 .flags = IORESOURCE_MEM, 550 }, { 551 .name = "crypto interrupt", 552 .start = IRQ_ORION5X_CESA, 553 .end = IRQ_ORION5X_CESA, 554 .flags = IORESOURCE_IRQ, 555 }, 556}; 557 558static struct platform_device orion5x_crypto_device = { 559 .name = "mv_crypto", 560 .id = -1, 561 .num_resources = ARRAY_SIZE(orion5x_crypto_res), 562 .resource = orion5x_crypto_res, 563}; 564 565int __init orion5x_crypto_init(void) 566{ 567 int ret; 568 569 ret = orion5x_setup_sram_win(); 570 if (ret) 571 return ret; 572 573 return platform_device_register(&orion5x_crypto_device); 574} 575 576/***************************************************************************** 577 * Watchdog 578 ****************************************************************************/ 579static struct orion_wdt_platform_data orion5x_wdt_data = { 580 .tclk = 0, 581}; 582 583static struct platform_device orion5x_wdt_device = { 584 .name = "orion_wdt", 585 .id = -1, 586 .dev = { 587 .platform_data = &orion5x_wdt_data, 588 }, 589 .num_resources = 0, 590}; 591 592void __init orion5x_wdt_init(void) 593{ 594 orion5x_wdt_data.tclk = orion5x_tclk; 595 platform_device_register(&orion5x_wdt_device); 596} 597 598 599/***************************************************************************** 600 * Time handling 601 ****************************************************************************/ 602int orion5x_tclk; 603 604int __init orion5x_find_tclk(void) 605{ 606 u32 dev, rev; 607 608 orion5x_pcie_id(&dev, &rev); 609 if (dev == MV88F6183_DEV_ID && 610 (readl(MPP_RESET_SAMPLE) & 0x00000200) == 0) 611 return 133333333; 612 613 return 166666667; 614} 615 616static void orion5x_timer_init(void) 617{ 618 orion5x_tclk = orion5x_find_tclk(); 619 orion_time_init(IRQ_ORION5X_BRIDGE, orion5x_tclk); 620} 621 622struct sys_timer orion5x_timer = { 623 .init = orion5x_timer_init, 624}; 625 626 627/***************************************************************************** 628 * General 629 ****************************************************************************/ 630/* 631 * Identify device ID and rev from PCIe configuration header space '0'. 632 */ 633static void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name) 634{ 635 orion5x_pcie_id(dev, rev); 636 637 if (*dev == MV88F5281_DEV_ID) { 638 if (*rev == MV88F5281_REV_D2) { 639 *dev_name = "MV88F5281-D2"; 640 } else if (*rev == MV88F5281_REV_D1) { 641 *dev_name = "MV88F5281-D1"; 642 } else if (*rev == MV88F5281_REV_D0) { 643 *dev_name = "MV88F5281-D0"; 644 } else { 645 *dev_name = "MV88F5281-Rev-Unsupported"; 646 } 647 } else if (*dev == MV88F5182_DEV_ID) { 648 if (*rev == MV88F5182_REV_A2) { 649 *dev_name = "MV88F5182-A2"; 650 } else { 651 *dev_name = "MV88F5182-Rev-Unsupported"; 652 } 653 } else if (*dev == MV88F5181_DEV_ID) { 654 if (*rev == MV88F5181_REV_B1) { 655 *dev_name = "MV88F5181-Rev-B1"; 656 } else if (*rev == MV88F5181L_REV_A1) { 657 *dev_name = "MV88F5181L-Rev-A1"; 658 } else { 659 *dev_name = "MV88F5181(L)-Rev-Unsupported"; 660 } 661 } else if (*dev == MV88F6183_DEV_ID) { 662 if (*rev == MV88F6183_REV_B0) { 663 *dev_name = "MV88F6183-Rev-B0"; 664 } else { 665 *dev_name = "MV88F6183-Rev-Unsupported"; 666 } 667 } else { 668 *dev_name = "Device-Unknown"; 669 } 670} 671 672void __init orion5x_init(void) 673{ 674 char *dev_name; 675 u32 dev, rev; 676 677 orion5x_id(&dev, &rev, &dev_name); 678 printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk); 679 680 orion5x_eth_shared_data.t_clk = orion5x_tclk; 681 orion5x_spi_plat_data.tclk = orion5x_tclk; 682 orion5x_uart0_data[0].uartclk = orion5x_tclk; 683 orion5x_uart1_data[0].uartclk = orion5x_tclk; 684 685 /* 686 * Setup Orion address map 687 */ 688 orion5x_setup_cpu_mbus_bridge(); 689 690 /* 691 * Don't issue "Wait for Interrupt" instruction if we are 692 * running on D0 5281 silicon. 693 */ 694 if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) { 695 printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n"); 696 disable_hlt(); 697 } 698 699 /* 700 * Register watchdog driver 701 */ 702 orion5x_wdt_init(); 703} 704 705/* 706 * Many orion-based systems have buggy bootloader implementations. 707 * This is a common fixup for bogus memory tags. 708 */ 709void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t, 710 char **from, struct meminfo *meminfo) 711{ 712 for (; t->hdr.size; t = tag_next(t)) 713 if (t->hdr.tag == ATAG_MEM && 714 (!t->u.mem.size || t->u.mem.size & ~PAGE_MASK || 715 t->u.mem.start & ~PAGE_MASK)) { 716 printk(KERN_WARNING 717 "Clearing invalid memory bank %dKB@0x%08x\n", 718 t->u.mem.size / 1024, t->u.mem.start); 719 t->hdr.tag = 0; 720 } 721} 722