common.c revision 85bc26211c6a2c6e82c2403697f8ce44e9587215
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/orion5x_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}; 192 193void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) 194{ 195 eth_data->shared = &orion5x_eth_shared; 196 orion5x_eth.dev.platform_data = eth_data; 197 198 platform_device_register(&orion5x_eth_shared); 199 platform_device_register(&orion5x_eth); 200} 201 202 203/***************************************************************************** 204 * Ethernet switch 205 ****************************************************************************/ 206static struct resource orion5x_switch_resources[] = { 207 { 208 .start = 0, 209 .end = 0, 210 .flags = IORESOURCE_IRQ, 211 }, 212}; 213 214static struct platform_device orion5x_switch_device = { 215 .name = "dsa", 216 .id = 0, 217 .num_resources = 0, 218 .resource = orion5x_switch_resources, 219}; 220 221void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq) 222{ 223 int i; 224 225 if (irq != NO_IRQ) { 226 orion5x_switch_resources[0].start = irq; 227 orion5x_switch_resources[0].end = irq; 228 orion5x_switch_device.num_resources = 1; 229 } 230 231 d->netdev = &orion5x_eth.dev; 232 for (i = 0; i < d->nr_chips; i++) 233 d->chip[i].mii_bus = &orion5x_eth_shared.dev; 234 orion5x_switch_device.dev.platform_data = d; 235 236 platform_device_register(&orion5x_switch_device); 237} 238 239 240/***************************************************************************** 241 * I2C 242 ****************************************************************************/ 243static struct mv64xxx_i2c_pdata orion5x_i2c_pdata = { 244 .freq_m = 8, /* assumes 166 MHz TCLK */ 245 .freq_n = 3, 246 .timeout = 1000, /* Default timeout of 1 second */ 247}; 248 249static struct resource orion5x_i2c_resources[] = { 250 { 251 .start = I2C_PHYS_BASE, 252 .end = I2C_PHYS_BASE + 0x1f, 253 .flags = IORESOURCE_MEM, 254 }, { 255 .start = IRQ_ORION5X_I2C, 256 .end = IRQ_ORION5X_I2C, 257 .flags = IORESOURCE_IRQ, 258 }, 259}; 260 261static struct platform_device orion5x_i2c = { 262 .name = MV64XXX_I2C_CTLR_NAME, 263 .id = 0, 264 .num_resources = ARRAY_SIZE(orion5x_i2c_resources), 265 .resource = orion5x_i2c_resources, 266 .dev = { 267 .platform_data = &orion5x_i2c_pdata, 268 }, 269}; 270 271void __init orion5x_i2c_init(void) 272{ 273 platform_device_register(&orion5x_i2c); 274} 275 276 277/***************************************************************************** 278 * SATA 279 ****************************************************************************/ 280static struct resource orion5x_sata_resources[] = { 281 { 282 .name = "sata base", 283 .start = ORION5X_SATA_PHYS_BASE, 284 .end = ORION5X_SATA_PHYS_BASE + 0x5000 - 1, 285 .flags = IORESOURCE_MEM, 286 }, { 287 .name = "sata irq", 288 .start = IRQ_ORION5X_SATA, 289 .end = IRQ_ORION5X_SATA, 290 .flags = IORESOURCE_IRQ, 291 }, 292}; 293 294static struct platform_device orion5x_sata = { 295 .name = "sata_mv", 296 .id = 0, 297 .dev = { 298 .coherent_dma_mask = 0xffffffff, 299 }, 300 .num_resources = ARRAY_SIZE(orion5x_sata_resources), 301 .resource = orion5x_sata_resources, 302}; 303 304void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) 305{ 306 sata_data->dram = &orion5x_mbus_dram_info; 307 orion5x_sata.dev.platform_data = sata_data; 308 platform_device_register(&orion5x_sata); 309} 310 311 312/***************************************************************************** 313 * SPI 314 ****************************************************************************/ 315static struct orion_spi_info orion5x_spi_plat_data = { 316 .tclk = 0, 317 .enable_clock_fix = 1, 318}; 319 320static struct resource orion5x_spi_resources[] = { 321 { 322 .name = "spi base", 323 .start = SPI_PHYS_BASE, 324 .end = SPI_PHYS_BASE + 0x1f, 325 .flags = IORESOURCE_MEM, 326 }, 327}; 328 329static struct platform_device orion5x_spi = { 330 .name = "orion_spi", 331 .id = 0, 332 .dev = { 333 .platform_data = &orion5x_spi_plat_data, 334 }, 335 .num_resources = ARRAY_SIZE(orion5x_spi_resources), 336 .resource = orion5x_spi_resources, 337}; 338 339void __init orion5x_spi_init() 340{ 341 platform_device_register(&orion5x_spi); 342} 343 344 345/***************************************************************************** 346 * UART0 347 ****************************************************************************/ 348static struct plat_serial8250_port orion5x_uart0_data[] = { 349 { 350 .mapbase = UART0_PHYS_BASE, 351 .membase = (char *)UART0_VIRT_BASE, 352 .irq = IRQ_ORION5X_UART0, 353 .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, 354 .iotype = UPIO_MEM, 355 .regshift = 2, 356 .uartclk = 0, 357 }, { 358 }, 359}; 360 361static struct resource orion5x_uart0_resources[] = { 362 { 363 .start = UART0_PHYS_BASE, 364 .end = UART0_PHYS_BASE + 0xff, 365 .flags = IORESOURCE_MEM, 366 }, { 367 .start = IRQ_ORION5X_UART0, 368 .end = IRQ_ORION5X_UART0, 369 .flags = IORESOURCE_IRQ, 370 }, 371}; 372 373static struct platform_device orion5x_uart0 = { 374 .name = "serial8250", 375 .id = PLAT8250_DEV_PLATFORM, 376 .dev = { 377 .platform_data = orion5x_uart0_data, 378 }, 379 .resource = orion5x_uart0_resources, 380 .num_resources = ARRAY_SIZE(orion5x_uart0_resources), 381}; 382 383void __init orion5x_uart0_init(void) 384{ 385 platform_device_register(&orion5x_uart0); 386} 387 388 389/***************************************************************************** 390 * UART1 391 ****************************************************************************/ 392static struct plat_serial8250_port orion5x_uart1_data[] = { 393 { 394 .mapbase = UART1_PHYS_BASE, 395 .membase = (char *)UART1_VIRT_BASE, 396 .irq = IRQ_ORION5X_UART1, 397 .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, 398 .iotype = UPIO_MEM, 399 .regshift = 2, 400 .uartclk = 0, 401 }, { 402 }, 403}; 404 405static struct resource orion5x_uart1_resources[] = { 406 { 407 .start = UART1_PHYS_BASE, 408 .end = UART1_PHYS_BASE + 0xff, 409 .flags = IORESOURCE_MEM, 410 }, { 411 .start = IRQ_ORION5X_UART1, 412 .end = IRQ_ORION5X_UART1, 413 .flags = IORESOURCE_IRQ, 414 }, 415}; 416 417static struct platform_device orion5x_uart1 = { 418 .name = "serial8250", 419 .id = PLAT8250_DEV_PLATFORM1, 420 .dev = { 421 .platform_data = orion5x_uart1_data, 422 }, 423 .resource = orion5x_uart1_resources, 424 .num_resources = ARRAY_SIZE(orion5x_uart1_resources), 425}; 426 427void __init orion5x_uart1_init(void) 428{ 429 platform_device_register(&orion5x_uart1); 430} 431 432 433/***************************************************************************** 434 * XOR engine 435 ****************************************************************************/ 436struct mv_xor_platform_shared_data orion5x_xor_shared_data = { 437 .dram = &orion5x_mbus_dram_info, 438}; 439 440static struct resource orion5x_xor_shared_resources[] = { 441 { 442 .name = "xor low", 443 .start = ORION5X_XOR_PHYS_BASE, 444 .end = ORION5X_XOR_PHYS_BASE + 0xff, 445 .flags = IORESOURCE_MEM, 446 }, { 447 .name = "xor high", 448 .start = ORION5X_XOR_PHYS_BASE + 0x200, 449 .end = ORION5X_XOR_PHYS_BASE + 0x2ff, 450 .flags = IORESOURCE_MEM, 451 }, 452}; 453 454static struct platform_device orion5x_xor_shared = { 455 .name = MV_XOR_SHARED_NAME, 456 .id = 0, 457 .dev = { 458 .platform_data = &orion5x_xor_shared_data, 459 }, 460 .num_resources = ARRAY_SIZE(orion5x_xor_shared_resources), 461 .resource = orion5x_xor_shared_resources, 462}; 463 464static u64 orion5x_xor_dmamask = DMA_BIT_MASK(32); 465 466static struct resource orion5x_xor0_resources[] = { 467 [0] = { 468 .start = IRQ_ORION5X_XOR0, 469 .end = IRQ_ORION5X_XOR0, 470 .flags = IORESOURCE_IRQ, 471 }, 472}; 473 474static struct mv_xor_platform_data orion5x_xor0_data = { 475 .shared = &orion5x_xor_shared, 476 .hw_id = 0, 477 .pool_size = PAGE_SIZE, 478}; 479 480static struct platform_device orion5x_xor0_channel = { 481 .name = MV_XOR_NAME, 482 .id = 0, 483 .num_resources = ARRAY_SIZE(orion5x_xor0_resources), 484 .resource = orion5x_xor0_resources, 485 .dev = { 486 .dma_mask = &orion5x_xor_dmamask, 487 .coherent_dma_mask = DMA_BIT_MASK(64), 488 .platform_data = (void *)&orion5x_xor0_data, 489 }, 490}; 491 492static struct resource orion5x_xor1_resources[] = { 493 [0] = { 494 .start = IRQ_ORION5X_XOR1, 495 .end = IRQ_ORION5X_XOR1, 496 .flags = IORESOURCE_IRQ, 497 }, 498}; 499 500static struct mv_xor_platform_data orion5x_xor1_data = { 501 .shared = &orion5x_xor_shared, 502 .hw_id = 1, 503 .pool_size = PAGE_SIZE, 504}; 505 506static struct platform_device orion5x_xor1_channel = { 507 .name = MV_XOR_NAME, 508 .id = 1, 509 .num_resources = ARRAY_SIZE(orion5x_xor1_resources), 510 .resource = orion5x_xor1_resources, 511 .dev = { 512 .dma_mask = &orion5x_xor_dmamask, 513 .coherent_dma_mask = DMA_BIT_MASK(64), 514 .platform_data = (void *)&orion5x_xor1_data, 515 }, 516}; 517 518void __init orion5x_xor_init(void) 519{ 520 platform_device_register(&orion5x_xor_shared); 521 522 /* 523 * two engines can't do memset simultaneously, this limitation 524 * satisfied by removing memset support from one of the engines. 525 */ 526 dma_cap_set(DMA_MEMCPY, orion5x_xor0_data.cap_mask); 527 dma_cap_set(DMA_XOR, orion5x_xor0_data.cap_mask); 528 platform_device_register(&orion5x_xor0_channel); 529 530 dma_cap_set(DMA_MEMCPY, orion5x_xor1_data.cap_mask); 531 dma_cap_set(DMA_MEMSET, orion5x_xor1_data.cap_mask); 532 dma_cap_set(DMA_XOR, orion5x_xor1_data.cap_mask); 533 platform_device_register(&orion5x_xor1_channel); 534} 535 536 537/***************************************************************************** 538 * Watchdog 539 ****************************************************************************/ 540static struct orion5x_wdt_platform_data orion5x_wdt_data = { 541 .tclk = 0, 542}; 543 544static struct platform_device orion5x_wdt_device = { 545 .name = "orion5x_wdt", 546 .id = -1, 547 .dev = { 548 .platform_data = &orion5x_wdt_data, 549 }, 550 .num_resources = 0, 551}; 552 553void __init orion5x_wdt_init(void) 554{ 555 orion5x_wdt_data.tclk = orion5x_tclk; 556 platform_device_register(&orion5x_wdt_device); 557} 558 559 560/***************************************************************************** 561 * Time handling 562 ****************************************************************************/ 563int orion5x_tclk; 564 565int __init orion5x_find_tclk(void) 566{ 567 u32 dev, rev; 568 569 orion5x_pcie_id(&dev, &rev); 570 if (dev == MV88F6183_DEV_ID && 571 (readl(MPP_RESET_SAMPLE) & 0x00000200) == 0) 572 return 133333333; 573 574 return 166666667; 575} 576 577static void orion5x_timer_init(void) 578{ 579 orion5x_tclk = orion5x_find_tclk(); 580 orion_time_init(IRQ_ORION5X_BRIDGE, orion5x_tclk); 581} 582 583struct sys_timer orion5x_timer = { 584 .init = orion5x_timer_init, 585}; 586 587 588/***************************************************************************** 589 * General 590 ****************************************************************************/ 591/* 592 * Identify device ID and rev from PCIe configuration header space '0'. 593 */ 594static void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name) 595{ 596 orion5x_pcie_id(dev, rev); 597 598 if (*dev == MV88F5281_DEV_ID) { 599 if (*rev == MV88F5281_REV_D2) { 600 *dev_name = "MV88F5281-D2"; 601 } else if (*rev == MV88F5281_REV_D1) { 602 *dev_name = "MV88F5281-D1"; 603 } else if (*rev == MV88F5281_REV_D0) { 604 *dev_name = "MV88F5281-D0"; 605 } else { 606 *dev_name = "MV88F5281-Rev-Unsupported"; 607 } 608 } else if (*dev == MV88F5182_DEV_ID) { 609 if (*rev == MV88F5182_REV_A2) { 610 *dev_name = "MV88F5182-A2"; 611 } else { 612 *dev_name = "MV88F5182-Rev-Unsupported"; 613 } 614 } else if (*dev == MV88F5181_DEV_ID) { 615 if (*rev == MV88F5181_REV_B1) { 616 *dev_name = "MV88F5181-Rev-B1"; 617 } else if (*rev == MV88F5181L_REV_A1) { 618 *dev_name = "MV88F5181L-Rev-A1"; 619 } else { 620 *dev_name = "MV88F5181(L)-Rev-Unsupported"; 621 } 622 } else if (*dev == MV88F6183_DEV_ID) { 623 if (*rev == MV88F6183_REV_B0) { 624 *dev_name = "MV88F6183-Rev-B0"; 625 } else { 626 *dev_name = "MV88F6183-Rev-Unsupported"; 627 } 628 } else { 629 *dev_name = "Device-Unknown"; 630 } 631} 632 633void __init orion5x_init(void) 634{ 635 char *dev_name; 636 u32 dev, rev; 637 638 orion5x_id(&dev, &rev, &dev_name); 639 printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk); 640 641 orion5x_eth_shared_data.t_clk = orion5x_tclk; 642 orion5x_spi_plat_data.tclk = orion5x_tclk; 643 orion5x_uart0_data[0].uartclk = orion5x_tclk; 644 orion5x_uart1_data[0].uartclk = orion5x_tclk; 645 646 /* 647 * Setup Orion address map 648 */ 649 orion5x_setup_cpu_mbus_bridge(); 650 651 /* 652 * Don't issue "Wait for Interrupt" instruction if we are 653 * running on D0 5281 silicon. 654 */ 655 if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) { 656 printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n"); 657 disable_hlt(); 658 } 659 660 /* 661 * Register watchdog driver 662 */ 663 orion5x_wdt_init(); 664} 665 666/* 667 * Many orion-based systems have buggy bootloader implementations. 668 * This is a common fixup for bogus memory tags. 669 */ 670void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t, 671 char **from, struct meminfo *meminfo) 672{ 673 for (; t->hdr.size; t = tag_next(t)) 674 if (t->hdr.tag == ATAG_MEM && 675 (!t->u.mem.size || t->u.mem.size & ~PAGE_MASK || 676 t->u.mem.start & ~PAGE_MASK)) { 677 printk(KERN_WARNING 678 "Clearing invalid memory bank %dKB@0x%08x\n", 679 t->u.mem.size / 1024, t->u.mem.start); 680 t->hdr.tag = 0; 681 } 682} 683