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-2009 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/module.h> 14#include <linux/platform_device.h> 15 16#include <asm/octeon/octeon.h> 17#include <asm/octeon/cvmx-rnm-defs.h> 18 19static struct octeon_cf_data octeon_cf_data; 20 21static int __init octeon_cf_device_init(void) 22{ 23 union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 24 unsigned long base_ptr, region_base, region_size; 25 struct platform_device *pd; 26 struct resource cf_resources[3]; 27 unsigned int num_resources; 28 int i; 29 int ret = 0; 30 31 /* Setup octeon-cf platform device if present. */ 32 base_ptr = 0; 33 if (octeon_bootinfo->major_version == 1 34 && octeon_bootinfo->minor_version >= 1) { 35 if (octeon_bootinfo->compact_flash_common_base_addr) 36 base_ptr = 37 octeon_bootinfo->compact_flash_common_base_addr; 38 } else { 39 base_ptr = 0x1d000800; 40 } 41 42 if (!base_ptr) 43 return ret; 44 45 /* Find CS0 region. */ 46 for (i = 0; i < 8; i++) { 47 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i)); 48 region_base = mio_boot_reg_cfg.s.base << 16; 49 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 50 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 51 && base_ptr < region_base + region_size) 52 break; 53 } 54 if (i >= 7) { 55 /* i and i + 1 are CS0 and CS1, both must be less than 8. */ 56 goto out; 57 } 58 octeon_cf_data.base_region = i; 59 octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width; 60 octeon_cf_data.base_region_bias = base_ptr - region_base; 61 memset(cf_resources, 0, sizeof(cf_resources)); 62 num_resources = 0; 63 cf_resources[num_resources].flags = IORESOURCE_MEM; 64 cf_resources[num_resources].start = region_base; 65 cf_resources[num_resources].end = region_base + region_size - 1; 66 num_resources++; 67 68 69 if (!(base_ptr & 0xfffful)) { 70 /* 71 * Boot loader signals availability of DMA (true_ide 72 * mode) by setting low order bits of base_ptr to 73 * zero. 74 */ 75 76 /* Asume that CS1 immediately follows. */ 77 mio_boot_reg_cfg.u64 = 78 cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1)); 79 region_base = mio_boot_reg_cfg.s.base << 16; 80 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 81 if (!mio_boot_reg_cfg.s.en) 82 goto out; 83 84 cf_resources[num_resources].flags = IORESOURCE_MEM; 85 cf_resources[num_resources].start = region_base; 86 cf_resources[num_resources].end = region_base + region_size - 1; 87 num_resources++; 88 89 octeon_cf_data.dma_engine = 0; 90 cf_resources[num_resources].flags = IORESOURCE_IRQ; 91 cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA; 92 cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA; 93 num_resources++; 94 } else { 95 octeon_cf_data.dma_engine = -1; 96 } 97 98 pd = platform_device_alloc("pata_octeon_cf", -1); 99 if (!pd) { 100 ret = -ENOMEM; 101 goto out; 102 } 103 pd->dev.platform_data = &octeon_cf_data; 104 105 ret = platform_device_add_resources(pd, cf_resources, num_resources); 106 if (ret) 107 goto fail; 108 109 ret = platform_device_add(pd); 110 if (ret) 111 goto fail; 112 113 return ret; 114fail: 115 platform_device_put(pd); 116out: 117 return ret; 118} 119device_initcall(octeon_cf_device_init); 120 121/* Octeon Random Number Generator. */ 122static int __init octeon_rng_device_init(void) 123{ 124 struct platform_device *pd; 125 int ret = 0; 126 127 struct resource rng_resources[] = { 128 { 129 .flags = IORESOURCE_MEM, 130 .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), 131 .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf 132 }, { 133 .flags = IORESOURCE_MEM, 134 .start = cvmx_build_io_address(8, 0), 135 .end = cvmx_build_io_address(8, 0) + 0x7 136 } 137 }; 138 139 pd = platform_device_alloc("octeon_rng", -1); 140 if (!pd) { 141 ret = -ENOMEM; 142 goto out; 143 } 144 145 ret = platform_device_add_resources(pd, rng_resources, 146 ARRAY_SIZE(rng_resources)); 147 if (ret) 148 goto fail; 149 150 ret = platform_device_add(pd); 151 if (ret) 152 goto fail; 153 154 return ret; 155fail: 156 platform_device_put(pd); 157 158out: 159 return ret; 160} 161device_initcall(octeon_rng_device_init); 162 163static struct i2c_board_info __initdata octeon_i2c_devices[] = { 164 { 165 I2C_BOARD_INFO("ds1337", 0x68), 166 }, 167}; 168 169static int __init octeon_i2c_devices_init(void) 170{ 171 return i2c_register_board_info(0, octeon_i2c_devices, 172 ARRAY_SIZE(octeon_i2c_devices)); 173} 174arch_initcall(octeon_i2c_devices_init); 175 176#define OCTEON_I2C_IO_BASE 0x1180000001000ull 177#define OCTEON_I2C_IO_UNIT_OFFSET 0x200 178 179static struct octeon_i2c_data octeon_i2c_data[2]; 180 181static int __init octeon_i2c_device_init(void) 182{ 183 struct platform_device *pd; 184 int ret = 0; 185 int port, num_ports; 186 187 struct resource i2c_resources[] = { 188 { 189 .flags = IORESOURCE_MEM, 190 }, { 191 .flags = IORESOURCE_IRQ, 192 } 193 }; 194 195 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 196 num_ports = 2; 197 else 198 num_ports = 1; 199 200 for (port = 0; port < num_ports; port++) { 201 octeon_i2c_data[port].sys_freq = octeon_get_clock_rate(); 202 octeon_i2c_data[port].i2c_freq = 100000; 203 204 pd = platform_device_alloc("i2c-octeon", port); 205 if (!pd) { 206 ret = -ENOMEM; 207 goto out; 208 } 209 210 pd->dev.platform_data = octeon_i2c_data + port; 211 212 i2c_resources[0].start = 213 OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET); 214 i2c_resources[0].end = i2c_resources[0].start + 0x1f; 215 switch (port) { 216 case 0: 217 i2c_resources[1].start = OCTEON_IRQ_TWSI; 218 i2c_resources[1].end = OCTEON_IRQ_TWSI; 219 break; 220 case 1: 221 i2c_resources[1].start = OCTEON_IRQ_TWSI2; 222 i2c_resources[1].end = OCTEON_IRQ_TWSI2; 223 break; 224 default: 225 BUG(); 226 } 227 228 ret = platform_device_add_resources(pd, 229 i2c_resources, 230 ARRAY_SIZE(i2c_resources)); 231 if (ret) 232 goto fail; 233 234 ret = platform_device_add(pd); 235 if (ret) 236 goto fail; 237 } 238 return ret; 239fail: 240 platform_device_put(pd); 241out: 242 return ret; 243} 244device_initcall(octeon_i2c_device_init); 245 246/* Octeon SMI/MDIO interface. */ 247static int __init octeon_mdiobus_device_init(void) 248{ 249 struct platform_device *pd; 250 int ret = 0; 251 252 if (octeon_is_simulation()) 253 return 0; /* No mdio in the simulator. */ 254 255 /* The bus number is the platform_device id. */ 256 pd = platform_device_alloc("mdio-octeon", 0); 257 if (!pd) { 258 ret = -ENOMEM; 259 goto out; 260 } 261 262 ret = platform_device_add(pd); 263 if (ret) 264 goto fail; 265 266 return ret; 267fail: 268 platform_device_put(pd); 269 270out: 271 return ret; 272 273} 274device_initcall(octeon_mdiobus_device_init); 275 276/* Octeon mgmt port Ethernet interface. */ 277static int __init octeon_mgmt_device_init(void) 278{ 279 struct platform_device *pd; 280 int ret = 0; 281 int port, num_ports; 282 283 struct resource mgmt_port_resource = { 284 .flags = IORESOURCE_IRQ, 285 .start = -1, 286 .end = -1 287 }; 288 289 if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX)) 290 return 0; 291 292 if (OCTEON_IS_MODEL(OCTEON_CN56XX)) 293 num_ports = 1; 294 else 295 num_ports = 2; 296 297 for (port = 0; port < num_ports; port++) { 298 pd = platform_device_alloc("octeon_mgmt", port); 299 if (!pd) { 300 ret = -ENOMEM; 301 goto out; 302 } 303 switch (port) { 304 case 0: 305 mgmt_port_resource.start = OCTEON_IRQ_MII0; 306 break; 307 case 1: 308 mgmt_port_resource.start = OCTEON_IRQ_MII1; 309 break; 310 default: 311 BUG(); 312 } 313 mgmt_port_resource.end = mgmt_port_resource.start; 314 315 ret = platform_device_add_resources(pd, &mgmt_port_resource, 1); 316 317 if (ret) 318 goto fail; 319 320 ret = platform_device_add(pd); 321 if (ret) 322 goto fail; 323 } 324 return ret; 325fail: 326 platform_device_put(pd); 327 328out: 329 return ret; 330 331} 332device_initcall(octeon_mgmt_device_init); 333 334MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); 335MODULE_LICENSE("GPL"); 336MODULE_DESCRIPTION("Platform driver for Octeon SOC"); 337