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 <asm/page.h> 22 #include <asm/setup.h> 23 #include <asm/timex.h> 24 #include <asm/mach/arch.h> 25 #include <asm/mach/map.h> 26 #include <asm/mach/time.h> 27 #include <mach/hardware.h> 28 #include <mach/orion5x.h> 29 #include <plat/ehci-orion.h> 30 #include <plat/mv_xor.h> 31 #include <plat/orion_nand.h> 32 #include <plat/time.h> 33 #include "common.h" 34 35 /***************************************************************************** 36 * I/O Address Mapping 37 ****************************************************************************/ 38 static struct map_desc orion5x_io_desc[] __initdata = { 39 { 40 .virtual = ORION5X_REGS_VIRT_BASE, 41 .pfn = __phys_to_pfn(ORION5X_REGS_PHYS_BASE), 42 .length = ORION5X_REGS_SIZE, 43 .type = MT_DEVICE, 44 }, { 45 .virtual = ORION5X_PCIE_IO_VIRT_BASE, 46 .pfn = __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE), 47 .length = ORION5X_PCIE_IO_SIZE, 48 .type = MT_DEVICE, 49 }, { 50 .virtual = ORION5X_PCI_IO_VIRT_BASE, 51 .pfn = __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE), 52 .length = ORION5X_PCI_IO_SIZE, 53 .type = MT_DEVICE, 54 }, { 55 .virtual = ORION5X_PCIE_WA_VIRT_BASE, 56 .pfn = __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE), 57 .length = ORION5X_PCIE_WA_SIZE, 58 .type = MT_DEVICE, 59 }, 60 }; 61 62 void __init orion5x_map_io(void) 63 { 64 iotable_init(orion5x_io_desc, ARRAY_SIZE(orion5x_io_desc)); 65 } 66 67 68 /***************************************************************************** 69 * EHCI 70 ****************************************************************************/ 71 static struct orion_ehci_data orion5x_ehci_data = { 72 .dram = &orion5x_mbus_dram_info, 73 }; 74 75 static u64 ehci_dmamask = 0xffffffffUL; 76 77 78 /***************************************************************************** 79 * EHCI0 80 ****************************************************************************/ 81 static struct resource orion5x_ehci0_resources[] = { 82 { 83 .start = ORION5X_USB0_PHYS_BASE, 84 .end = ORION5X_USB0_PHYS_BASE + SZ_4K - 1, 85 .flags = IORESOURCE_MEM, 86 }, { 87 .start = IRQ_ORION5X_USB0_CTRL, 88 .end = IRQ_ORION5X_USB0_CTRL, 89 .flags = IORESOURCE_IRQ, 90 }, 91 }; 92 93 static struct platform_device orion5x_ehci0 = { 94 .name = "orion-ehci", 95 .id = 0, 96 .dev = { 97 .dma_mask = &ehci_dmamask, 98 .coherent_dma_mask = 0xffffffff, 99 .platform_data = &orion5x_ehci_data, 100 }, 101 .resource = orion5x_ehci0_resources, 102 .num_resources = ARRAY_SIZE(orion5x_ehci0_resources), 103 }; 104 105 void __init orion5x_ehci0_init(void) 106 { 107 platform_device_register(&orion5x_ehci0); 108 } 109 110 111 /***************************************************************************** 112 * EHCI1 113 ****************************************************************************/ 114 static struct resource orion5x_ehci1_resources[] = { 115 { 116 .start = ORION5X_USB1_PHYS_BASE, 117 .end = ORION5X_USB1_PHYS_BASE + SZ_4K - 1, 118 .flags = IORESOURCE_MEM, 119 }, { 120 .start = IRQ_ORION5X_USB1_CTRL, 121 .end = IRQ_ORION5X_USB1_CTRL, 122 .flags = IORESOURCE_IRQ, 123 }, 124 }; 125 126 static struct platform_device orion5x_ehci1 = { 127 .name = "orion-ehci", 128 .id = 1, 129 .dev = { 130 .dma_mask = &ehci_dmamask, 131 .coherent_dma_mask = 0xffffffff, 132 .platform_data = &orion5x_ehci_data, 133 }, 134 .resource = orion5x_ehci1_resources, 135 .num_resources = ARRAY_SIZE(orion5x_ehci1_resources), 136 }; 137 138 void __init orion5x_ehci1_init(void) 139 { 140 platform_device_register(&orion5x_ehci1); 141 } 142 143 144 /***************************************************************************** 145 * GigE 146 ****************************************************************************/ 147 struct mv643xx_eth_shared_platform_data orion5x_eth_shared_data = { 148 .dram = &orion5x_mbus_dram_info, 149 .t_clk = ORION5X_TCLK, 150 }; 151 152 static struct resource orion5x_eth_shared_resources[] = { 153 { 154 .start = ORION5X_ETH_PHYS_BASE + 0x2000, 155 .end = ORION5X_ETH_PHYS_BASE + 0x3fff, 156 .flags = IORESOURCE_MEM, 157 }, 158 }; 159 160 static struct platform_device orion5x_eth_shared = { 161 .name = MV643XX_ETH_SHARED_NAME, 162 .id = 0, 163 .dev = { 164 .platform_data = &orion5x_eth_shared_data, 165 }, 166 .num_resources = 1, 167 .resource = orion5x_eth_shared_resources, 168 }; 169 170 static struct resource orion5x_eth_resources[] = { 171 { 172 .name = "eth irq", 173 .start = IRQ_ORION5X_ETH_SUM, 174 .end = IRQ_ORION5X_ETH_SUM, 175 .flags = IORESOURCE_IRQ, 176 }, 177 }; 178 179 static struct platform_device orion5x_eth = { 180 .name = MV643XX_ETH_NAME, 181 .id = 0, 182 .num_resources = 1, 183 .resource = orion5x_eth_resources, 184 }; 185 186 void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) 187 { 188 eth_data->shared = &orion5x_eth_shared; 189 orion5x_eth.dev.platform_data = eth_data; 190 191 platform_device_register(&orion5x_eth_shared); 192 platform_device_register(&orion5x_eth); 193 } 194 195 196 /***************************************************************************** 197 * I2C 198 ****************************************************************************/ 199 static struct mv64xxx_i2c_pdata orion5x_i2c_pdata = { 200 .freq_m = 8, /* assumes 166 MHz TCLK */ 201 .freq_n = 3, 202 .timeout = 1000, /* Default timeout of 1 second */ 203 }; 204 205 static struct resource orion5x_i2c_resources[] = { 206 { 207 .name = "i2c base", 208 .start = I2C_PHYS_BASE, 209 .end = I2C_PHYS_BASE + 0x1f, 210 .flags = IORESOURCE_MEM, 211 }, { 212 .name = "i2c irq", 213 .start = IRQ_ORION5X_I2C, 214 .end = IRQ_ORION5X_I2C, 215 .flags = IORESOURCE_IRQ, 216 }, 217 }; 218 219 static struct platform_device orion5x_i2c = { 220 .name = MV64XXX_I2C_CTLR_NAME, 221 .id = 0, 222 .num_resources = ARRAY_SIZE(orion5x_i2c_resources), 223 .resource = orion5x_i2c_resources, 224 .dev = { 225 .platform_data = &orion5x_i2c_pdata, 226 }, 227 }; 228 229 void __init orion5x_i2c_init(void) 230 { 231 platform_device_register(&orion5x_i2c); 232 } 233 234 235 /***************************************************************************** 236 * SATA 237 ****************************************************************************/ 238 static struct resource orion5x_sata_resources[] = { 239 { 240 .name = "sata base", 241 .start = ORION5X_SATA_PHYS_BASE, 242 .end = ORION5X_SATA_PHYS_BASE + 0x5000 - 1, 243 .flags = IORESOURCE_MEM, 244 }, { 245 .name = "sata irq", 246 .start = IRQ_ORION5X_SATA, 247 .end = IRQ_ORION5X_SATA, 248 .flags = IORESOURCE_IRQ, 249 }, 250 }; 251 252 static struct platform_device orion5x_sata = { 253 .name = "sata_mv", 254 .id = 0, 255 .dev = { 256 .coherent_dma_mask = 0xffffffff, 257 }, 258 .num_resources = ARRAY_SIZE(orion5x_sata_resources), 259 .resource = orion5x_sata_resources, 260 }; 261 262 void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) 263 { 264 sata_data->dram = &orion5x_mbus_dram_info; 265 orion5x_sata.dev.platform_data = sata_data; 266 platform_device_register(&orion5x_sata); 267 } 268 269 270 /***************************************************************************** 271 * UART0 272 ****************************************************************************/ 273 static struct plat_serial8250_port orion5x_uart0_data[] = { 274 { 275 .mapbase = UART0_PHYS_BASE, 276 .membase = (char *)UART0_VIRT_BASE, 277 .irq = IRQ_ORION5X_UART0, 278 .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, 279 .iotype = UPIO_MEM, 280 .regshift = 2, 281 .uartclk = ORION5X_TCLK, 282 }, { 283 }, 284 }; 285 286 static struct resource orion5x_uart0_resources[] = { 287 { 288 .start = UART0_PHYS_BASE, 289 .end = UART0_PHYS_BASE + 0xff, 290 .flags = IORESOURCE_MEM, 291 }, { 292 .start = IRQ_ORION5X_UART0, 293 .end = IRQ_ORION5X_UART0, 294 .flags = IORESOURCE_IRQ, 295 }, 296 }; 297 298 static struct platform_device orion5x_uart0 = { 299 .name = "serial8250", 300 .id = PLAT8250_DEV_PLATFORM, 301 .dev = { 302 .platform_data = orion5x_uart0_data, 303 }, 304 .resource = orion5x_uart0_resources, 305 .num_resources = ARRAY_SIZE(orion5x_uart0_resources), 306 }; 307 308 void __init orion5x_uart0_init(void) 309 { 310 platform_device_register(&orion5x_uart0); 311 } 312 313 314 /***************************************************************************** 315 * UART1 316 ****************************************************************************/ 317 static struct plat_serial8250_port orion5x_uart1_data[] = { 318 { 319 .mapbase = UART1_PHYS_BASE, 320 .membase = (char *)UART1_VIRT_BASE, 321 .irq = IRQ_ORION5X_UART1, 322 .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, 323 .iotype = UPIO_MEM, 324 .regshift = 2, 325 .uartclk = ORION5X_TCLK, 326 }, { 327 }, 328 }; 329 330 static struct resource orion5x_uart1_resources[] = { 331 { 332 .start = UART1_PHYS_BASE, 333 .end = UART1_PHYS_BASE + 0xff, 334 .flags = IORESOURCE_MEM, 335 }, { 336 .start = IRQ_ORION5X_UART1, 337 .end = IRQ_ORION5X_UART1, 338 .flags = IORESOURCE_IRQ, 339 }, 340 }; 341 342 static struct platform_device orion5x_uart1 = { 343 .name = "serial8250", 344 .id = PLAT8250_DEV_PLATFORM1, 345 .dev = { 346 .platform_data = orion5x_uart1_data, 347 }, 348 .resource = orion5x_uart1_resources, 349 .num_resources = ARRAY_SIZE(orion5x_uart1_resources), 350 }; 351 352 void __init orion5x_uart1_init(void) 353 { 354 platform_device_register(&orion5x_uart1); 355 } 356 357 358 /***************************************************************************** 359 * XOR engine 360 ****************************************************************************/ 361 static struct resource orion5x_xor_shared_resources[] = { 362 { 363 .name = "xor low", 364 .start = ORION5X_XOR_PHYS_BASE, 365 .end = ORION5X_XOR_PHYS_BASE + 0xff, 366 .flags = IORESOURCE_MEM, 367 }, { 368 .name = "xor high", 369 .start = ORION5X_XOR_PHYS_BASE + 0x200, 370 .end = ORION5X_XOR_PHYS_BASE + 0x2ff, 371 .flags = IORESOURCE_MEM, 372 }, 373 }; 374 375 static struct platform_device orion5x_xor_shared = { 376 .name = MV_XOR_SHARED_NAME, 377 .id = 0, 378 .num_resources = ARRAY_SIZE(orion5x_xor_shared_resources), 379 .resource = orion5x_xor_shared_resources, 380 }; 381 382 static u64 orion5x_xor_dmamask = DMA_32BIT_MASK; 383 384 static struct resource orion5x_xor0_resources[] = { 385 [0] = { 386 .start = IRQ_ORION5X_XOR0, 387 .end = IRQ_ORION5X_XOR0, 388 .flags = IORESOURCE_IRQ, 389 }, 390 }; 391 392 static struct mv_xor_platform_data orion5x_xor0_data = { 393 .shared = &orion5x_xor_shared, 394 .hw_id = 0, 395 .pool_size = PAGE_SIZE, 396 }; 397 398 static struct platform_device orion5x_xor0_channel = { 399 .name = MV_XOR_NAME, 400 .id = 0, 401 .num_resources = ARRAY_SIZE(orion5x_xor0_resources), 402 .resource = orion5x_xor0_resources, 403 .dev = { 404 .dma_mask = &orion5x_xor_dmamask, 405 .coherent_dma_mask = DMA_64BIT_MASK, 406 .platform_data = (void *)&orion5x_xor0_data, 407 }, 408 }; 409 410 static struct resource orion5x_xor1_resources[] = { 411 [0] = { 412 .start = IRQ_ORION5X_XOR1, 413 .end = IRQ_ORION5X_XOR1, 414 .flags = IORESOURCE_IRQ, 415 }, 416 }; 417 418 static struct mv_xor_platform_data orion5x_xor1_data = { 419 .shared = &orion5x_xor_shared, 420 .hw_id = 1, 421 .pool_size = PAGE_SIZE, 422 }; 423 424 static struct platform_device orion5x_xor1_channel = { 425 .name = MV_XOR_NAME, 426 .id = 1, 427 .num_resources = ARRAY_SIZE(orion5x_xor1_resources), 428 .resource = orion5x_xor1_resources, 429 .dev = { 430 .dma_mask = &orion5x_xor_dmamask, 431 .coherent_dma_mask = DMA_64BIT_MASK, 432 .platform_data = (void *)&orion5x_xor1_data, 433 }, 434 }; 435 436 void __init orion5x_xor_init(void) 437 { 438 platform_device_register(&orion5x_xor_shared); 439 440 /* 441 * two engines can't do memset simultaneously, this limitation 442 * satisfied by removing memset support from one of the engines. 443 */ 444 dma_cap_set(DMA_MEMCPY, orion5x_xor0_data.cap_mask); 445 dma_cap_set(DMA_XOR, orion5x_xor0_data.cap_mask); 446 platform_device_register(&orion5x_xor0_channel); 447 448 dma_cap_set(DMA_MEMCPY, orion5x_xor1_data.cap_mask); 449 dma_cap_set(DMA_MEMSET, orion5x_xor1_data.cap_mask); 450 dma_cap_set(DMA_XOR, orion5x_xor1_data.cap_mask); 451 platform_device_register(&orion5x_xor1_channel); 452 } 453 454 455 /***************************************************************************** 456 * Time handling 457 ****************************************************************************/ 458 static void orion5x_timer_init(void) 459 { 460 orion_time_init(IRQ_ORION5X_BRIDGE, ORION5X_TCLK); 461 } 462 463 struct sys_timer orion5x_timer = { 464 .init = orion5x_timer_init, 465 }; 466 467 468 /***************************************************************************** 469 * General 470 ****************************************************************************/ 471 /* 472 * Identify device ID and rev from PCIe configuration header space '0'. 473 */ 474 static void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name) 475 { 476 orion5x_pcie_id(dev, rev); 477 478 if (*dev == MV88F5281_DEV_ID) { 479 if (*rev == MV88F5281_REV_D2) { 480 *dev_name = "MV88F5281-D2"; 481 } else if (*rev == MV88F5281_REV_D1) { 482 *dev_name = "MV88F5281-D1"; 483 } else if (*rev == MV88F5281_REV_D0) { 484 *dev_name = "MV88F5281-D0"; 485 } else { 486 *dev_name = "MV88F5281-Rev-Unsupported"; 487 } 488 } else if (*dev == MV88F5182_DEV_ID) { 489 if (*rev == MV88F5182_REV_A2) { 490 *dev_name = "MV88F5182-A2"; 491 } else { 492 *dev_name = "MV88F5182-Rev-Unsupported"; 493 } 494 } else if (*dev == MV88F5181_DEV_ID) { 495 if (*rev == MV88F5181_REV_B1) { 496 *dev_name = "MV88F5181-Rev-B1"; 497 } else if (*rev == MV88F5181L_REV_A1) { 498 *dev_name = "MV88F5181L-Rev-A1"; 499 } else { 500 *dev_name = "MV88F5181(L)-Rev-Unsupported"; 501 } 502 } else { 503 *dev_name = "Device-Unknown"; 504 } 505 } 506 507 void __init orion5x_init(void) 508 { 509 char *dev_name; 510 u32 dev, rev; 511 512 orion5x_id(&dev, &rev, &dev_name); 513 printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, ORION5X_TCLK); 514 515 /* 516 * Setup Orion address map 517 */ 518 orion5x_setup_cpu_mbus_bridge(); 519 520 /* 521 * Don't issue "Wait for Interrupt" instruction if we are 522 * running on D0 5281 silicon. 523 */ 524 if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) { 525 printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n"); 526 disable_hlt(); 527 } 528 } 529 530 /* 531 * Many orion-based systems have buggy bootloader implementations. 532 * This is a common fixup for bogus memory tags. 533 */ 534 void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t, 535 char **from, struct meminfo *meminfo) 536 { 537 for (; t->hdr.size; t = tag_next(t)) 538 if (t->hdr.tag == ATAG_MEM && 539 (!t->u.mem.size || t->u.mem.size & ~PAGE_MASK || 540 t->u.mem.start & ~PAGE_MASK)) { 541 printk(KERN_WARNING 542 "Clearing invalid memory bank %dKB@0x%08x\n", 543 t->u.mem.size / 1024, t->u.mem.start); 544 t->hdr.tag = 0; 545 } 546 } 547