1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2004-2010 Cavium Networks 7 * Copyright (C) 2008 Wind River Systems 8 */ 9 10 #include <linux/init.h> 11 #include <linux/irq.h> 12 #include <linux/i2c.h> 13 #include <linux/usb.h> 14 #include <linux/dma-mapping.h> 15 #include <linux/module.h> 16 #include <linux/platform_device.h> 17 18 #include <asm/octeon/octeon.h> 19 #include <asm/octeon/cvmx-rnm-defs.h> 20 21 static struct octeon_cf_data octeon_cf_data; 22 23 static int __init octeon_cf_device_init(void) 24 { 25 union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 26 unsigned long base_ptr, region_base, region_size; 27 struct platform_device *pd; 28 struct resource cf_resources[3]; 29 unsigned int num_resources; 30 int i; 31 int ret = 0; 32 33 /* Setup octeon-cf platform device if present. */ 34 base_ptr = 0; 35 if (octeon_bootinfo->major_version == 1 36 && octeon_bootinfo->minor_version >= 1) { 37 if (octeon_bootinfo->compact_flash_common_base_addr) 38 base_ptr = 39 octeon_bootinfo->compact_flash_common_base_addr; 40 } else { 41 base_ptr = 0x1d000800; 42 } 43 44 if (!base_ptr) 45 return ret; 46 47 /* Find CS0 region. */ 48 for (i = 0; i < 8; i++) { 49 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i)); 50 region_base = mio_boot_reg_cfg.s.base << 16; 51 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 52 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 53 && base_ptr < region_base + region_size) 54 break; 55 } 56 if (i >= 7) { 57 /* i and i + 1 are CS0 and CS1, both must be less than 8. */ 58 goto out; 59 } 60 octeon_cf_data.base_region = i; 61 octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width; 62 octeon_cf_data.base_region_bias = base_ptr - region_base; 63 memset(cf_resources, 0, sizeof(cf_resources)); 64 num_resources = 0; 65 cf_resources[num_resources].flags = IORESOURCE_MEM; 66 cf_resources[num_resources].start = region_base; 67 cf_resources[num_resources].end = region_base + region_size - 1; 68 num_resources++; 69 70 71 if (!(base_ptr & 0xfffful)) { 72 /* 73 * Boot loader signals availability of DMA (true_ide 74 * mode) by setting low order bits of base_ptr to 75 * zero. 76 */ 77 78 /* Asume that CS1 immediately follows. */ 79 mio_boot_reg_cfg.u64 = 80 cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1)); 81 region_base = mio_boot_reg_cfg.s.base << 16; 82 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 83 if (!mio_boot_reg_cfg.s.en) 84 goto out; 85 86 cf_resources[num_resources].flags = IORESOURCE_MEM; 87 cf_resources[num_resources].start = region_base; 88 cf_resources[num_resources].end = region_base + region_size - 1; 89 num_resources++; 90 91 octeon_cf_data.dma_engine = 0; 92 cf_resources[num_resources].flags = IORESOURCE_IRQ; 93 cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA; 94 cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA; 95 num_resources++; 96 } else { 97 octeon_cf_data.dma_engine = -1; 98 } 99 100 pd = platform_device_alloc("pata_octeon_cf", -1); 101 if (!pd) { 102 ret = -ENOMEM; 103 goto out; 104 } 105 pd->dev.platform_data = &octeon_cf_data; 106 107 ret = platform_device_add_resources(pd, cf_resources, num_resources); 108 if (ret) 109 goto fail; 110 111 ret = platform_device_add(pd); 112 if (ret) 113 goto fail; 114 115 return ret; 116 fail: 117 platform_device_put(pd); 118 out: 119 return ret; 120 } 121 device_initcall(octeon_cf_device_init); 122 123 /* Octeon Random Number Generator. */ 124 static int __init octeon_rng_device_init(void) 125 { 126 struct platform_device *pd; 127 int ret = 0; 128 129 struct resource rng_resources[] = { 130 { 131 .flags = IORESOURCE_MEM, 132 .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), 133 .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf 134 }, { 135 .flags = IORESOURCE_MEM, 136 .start = cvmx_build_io_address(8, 0), 137 .end = cvmx_build_io_address(8, 0) + 0x7 138 } 139 }; 140 141 pd = platform_device_alloc("octeon_rng", -1); 142 if (!pd) { 143 ret = -ENOMEM; 144 goto out; 145 } 146 147 ret = platform_device_add_resources(pd, rng_resources, 148 ARRAY_SIZE(rng_resources)); 149 if (ret) 150 goto fail; 151 152 ret = platform_device_add(pd); 153 if (ret) 154 goto fail; 155 156 return ret; 157 fail: 158 platform_device_put(pd); 159 160 out: 161 return ret; 162 } 163 device_initcall(octeon_rng_device_init); 164 165 static struct i2c_board_info __initdata octeon_i2c_devices[] = { 166 { 167 I2C_BOARD_INFO("ds1337", 0x68), 168 }, 169 }; 170 171 static int __init octeon_i2c_devices_init(void) 172 { 173 return i2c_register_board_info(0, octeon_i2c_devices, 174 ARRAY_SIZE(octeon_i2c_devices)); 175 } 176 arch_initcall(octeon_i2c_devices_init); 177 178 #define OCTEON_I2C_IO_BASE 0x1180000001000ull 179 #define OCTEON_I2C_IO_UNIT_OFFSET 0x200 180 181 static struct octeon_i2c_data octeon_i2c_data[2]; 182 183 static int __init octeon_i2c_device_init(void) 184 { 185 struct platform_device *pd; 186 int ret = 0; 187 int port, num_ports; 188 189 struct resource i2c_resources[] = { 190 { 191 .flags = IORESOURCE_MEM, 192 }, { 193 .flags = IORESOURCE_IRQ, 194 } 195 }; 196 197 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 198 num_ports = 2; 199 else 200 num_ports = 1; 201 202 for (port = 0; port < num_ports; port++) { 203 octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate(); 204 /*FIXME: should be examined. At the moment is set for 100Khz */ 205 octeon_i2c_data[port].i2c_freq = 100000; 206 207 pd = platform_device_alloc("i2c-octeon", port); 208 if (!pd) { 209 ret = -ENOMEM; 210 goto out; 211 } 212 213 pd->dev.platform_data = octeon_i2c_data + port; 214 215 i2c_resources[0].start = 216 OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET); 217 i2c_resources[0].end = i2c_resources[0].start + 0x1f; 218 switch (port) { 219 case 0: 220 i2c_resources[1].start = OCTEON_IRQ_TWSI; 221 i2c_resources[1].end = OCTEON_IRQ_TWSI; 222 break; 223 case 1: 224 i2c_resources[1].start = OCTEON_IRQ_TWSI2; 225 i2c_resources[1].end = OCTEON_IRQ_TWSI2; 226 break; 227 default: 228 BUG(); 229 } 230 231 ret = platform_device_add_resources(pd, 232 i2c_resources, 233 ARRAY_SIZE(i2c_resources)); 234 if (ret) 235 goto fail; 236 237 ret = platform_device_add(pd); 238 if (ret) 239 goto fail; 240 } 241 return ret; 242 fail: 243 platform_device_put(pd); 244 out: 245 return ret; 246 } 247 device_initcall(octeon_i2c_device_init); 248 249 /* Octeon SMI/MDIO interface. */ 250 static int __init octeon_mdiobus_device_init(void) 251 { 252 struct platform_device *pd; 253 int ret = 0; 254 255 if (octeon_is_simulation()) 256 return 0; /* No mdio in the simulator. */ 257 258 /* The bus number is the platform_device id. */ 259 pd = platform_device_alloc("mdio-octeon", 0); 260 if (!pd) { 261 ret = -ENOMEM; 262 goto out; 263 } 264 265 ret = platform_device_add(pd); 266 if (ret) 267 goto fail; 268 269 return ret; 270 fail: 271 platform_device_put(pd); 272 273 out: 274 return ret; 275 276 } 277 device_initcall(octeon_mdiobus_device_init); 278 279 /* Octeon mgmt port Ethernet interface. */ 280 static int __init octeon_mgmt_device_init(void) 281 { 282 struct platform_device *pd; 283 int ret = 0; 284 int port, num_ports; 285 286 struct resource mgmt_port_resource = { 287 .flags = IORESOURCE_IRQ, 288 .start = -1, 289 .end = -1 290 }; 291 292 if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX)) 293 return 0; 294 295 if (OCTEON_IS_MODEL(OCTEON_CN56XX)) 296 num_ports = 1; 297 else 298 num_ports = 2; 299 300 for (port = 0; port < num_ports; port++) { 301 pd = platform_device_alloc("octeon_mgmt", port); 302 if (!pd) { 303 ret = -ENOMEM; 304 goto out; 305 } 306 /* No DMA restrictions */ 307 pd->dev.coherent_dma_mask = DMA_BIT_MASK(64); 308 pd->dev.dma_mask = &pd->dev.coherent_dma_mask; 309 310 switch (port) { 311 case 0: 312 mgmt_port_resource.start = OCTEON_IRQ_MII0; 313 break; 314 case 1: 315 mgmt_port_resource.start = OCTEON_IRQ_MII1; 316 break; 317 default: 318 BUG(); 319 } 320 mgmt_port_resource.end = mgmt_port_resource.start; 321 322 ret = platform_device_add_resources(pd, &mgmt_port_resource, 1); 323 324 if (ret) 325 goto fail; 326 327 ret = platform_device_add(pd); 328 if (ret) 329 goto fail; 330 } 331 return ret; 332 fail: 333 platform_device_put(pd); 334 335 out: 336 return ret; 337 338 } 339 device_initcall(octeon_mgmt_device_init); 340 341 #ifdef CONFIG_USB 342 343 static int __init octeon_ehci_device_init(void) 344 { 345 struct platform_device *pd; 346 int ret = 0; 347 348 struct resource usb_resources[] = { 349 { 350 .flags = IORESOURCE_MEM, 351 }, { 352 .flags = IORESOURCE_IRQ, 353 } 354 }; 355 356 /* Only Octeon2 has ehci/ohci */ 357 if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) 358 return 0; 359 360 if (octeon_is_simulation() || usb_disabled()) 361 return 0; /* No USB in the simulator. */ 362 363 pd = platform_device_alloc("octeon-ehci", 0); 364 if (!pd) { 365 ret = -ENOMEM; 366 goto out; 367 } 368 369 usb_resources[0].start = 0x00016F0000000000ULL; 370 usb_resources[0].end = usb_resources[0].start + 0x100; 371 372 usb_resources[1].start = OCTEON_IRQ_USB0; 373 usb_resources[1].end = OCTEON_IRQ_USB0; 374 375 ret = platform_device_add_resources(pd, usb_resources, 376 ARRAY_SIZE(usb_resources)); 377 if (ret) 378 goto fail; 379 380 ret = platform_device_add(pd); 381 if (ret) 382 goto fail; 383 384 return ret; 385 fail: 386 platform_device_put(pd); 387 out: 388 return ret; 389 } 390 device_initcall(octeon_ehci_device_init); 391 392 static int __init octeon_ohci_device_init(void) 393 { 394 struct platform_device *pd; 395 int ret = 0; 396 397 struct resource usb_resources[] = { 398 { 399 .flags = IORESOURCE_MEM, 400 }, { 401 .flags = IORESOURCE_IRQ, 402 } 403 }; 404 405 /* Only Octeon2 has ehci/ohci */ 406 if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) 407 return 0; 408 409 if (octeon_is_simulation() || usb_disabled()) 410 return 0; /* No USB in the simulator. */ 411 412 pd = platform_device_alloc("octeon-ohci", 0); 413 if (!pd) { 414 ret = -ENOMEM; 415 goto out; 416 } 417 418 usb_resources[0].start = 0x00016F0000000400ULL; 419 usb_resources[0].end = usb_resources[0].start + 0x100; 420 421 usb_resources[1].start = OCTEON_IRQ_USB0; 422 usb_resources[1].end = OCTEON_IRQ_USB0; 423 424 ret = platform_device_add_resources(pd, usb_resources, 425 ARRAY_SIZE(usb_resources)); 426 if (ret) 427 goto fail; 428 429 ret = platform_device_add(pd); 430 if (ret) 431 goto fail; 432 433 return ret; 434 fail: 435 platform_device_put(pd); 436 out: 437 return ret; 438 } 439 device_initcall(octeon_ohci_device_init); 440 441 #endif /* CONFIG_USB */ 442 443 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); 444 MODULE_LICENSE("GPL"); 445 MODULE_DESCRIPTION("Platform driver for Octeon SOC"); 446