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/module.h> 13 #include <linux/platform_device.h> 14 15 #include <asm/octeon/octeon.h> 16 #include <asm/octeon/cvmx-rnm-defs.h> 17 18 static struct octeon_cf_data octeon_cf_data; 19 20 static int __init octeon_cf_device_init(void) 21 { 22 union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 23 unsigned long base_ptr, region_base, region_size; 24 struct platform_device *pd; 25 struct resource cf_resources[3]; 26 unsigned int num_resources; 27 int i; 28 int ret = 0; 29 30 /* Setup octeon-cf platform device if present. */ 31 base_ptr = 0; 32 if (octeon_bootinfo->major_version == 1 33 && octeon_bootinfo->minor_version >= 1) { 34 if (octeon_bootinfo->compact_flash_common_base_addr) 35 base_ptr = 36 octeon_bootinfo->compact_flash_common_base_addr; 37 } else { 38 base_ptr = 0x1d000800; 39 } 40 41 if (!base_ptr) 42 return ret; 43 44 /* Find CS0 region. */ 45 for (i = 0; i < 8; i++) { 46 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i)); 47 region_base = mio_boot_reg_cfg.s.base << 16; 48 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 49 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 50 && base_ptr < region_base + region_size) 51 break; 52 } 53 if (i >= 7) { 54 /* i and i + 1 are CS0 and CS1, both must be less than 8. */ 55 goto out; 56 } 57 octeon_cf_data.base_region = i; 58 octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width; 59 octeon_cf_data.base_region_bias = base_ptr - region_base; 60 memset(cf_resources, 0, sizeof(cf_resources)); 61 num_resources = 0; 62 cf_resources[num_resources].flags = IORESOURCE_MEM; 63 cf_resources[num_resources].start = region_base; 64 cf_resources[num_resources].end = region_base + region_size - 1; 65 num_resources++; 66 67 68 if (!(base_ptr & 0xfffful)) { 69 /* 70 * Boot loader signals availability of DMA (true_ide 71 * mode) by setting low order bits of base_ptr to 72 * zero. 73 */ 74 75 /* Asume that CS1 immediately follows. */ 76 mio_boot_reg_cfg.u64 = 77 cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1)); 78 region_base = mio_boot_reg_cfg.s.base << 16; 79 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 80 if (!mio_boot_reg_cfg.s.en) 81 goto out; 82 83 cf_resources[num_resources].flags = IORESOURCE_MEM; 84 cf_resources[num_resources].start = region_base; 85 cf_resources[num_resources].end = region_base + region_size - 1; 86 num_resources++; 87 88 octeon_cf_data.dma_engine = 0; 89 cf_resources[num_resources].flags = IORESOURCE_IRQ; 90 cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA; 91 cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA; 92 num_resources++; 93 } else { 94 octeon_cf_data.dma_engine = -1; 95 } 96 97 pd = platform_device_alloc("pata_octeon_cf", -1); 98 if (!pd) { 99 ret = -ENOMEM; 100 goto out; 101 } 102 pd->dev.platform_data = &octeon_cf_data; 103 104 ret = platform_device_add_resources(pd, cf_resources, num_resources); 105 if (ret) 106 goto fail; 107 108 ret = platform_device_add(pd); 109 if (ret) 110 goto fail; 111 112 return ret; 113 fail: 114 platform_device_put(pd); 115 out: 116 return ret; 117 } 118 device_initcall(octeon_cf_device_init); 119 120 /* Octeon Random Number Generator. */ 121 static int __init octeon_rng_device_init(void) 122 { 123 struct platform_device *pd; 124 int ret = 0; 125 126 struct resource rng_resources[] = { 127 { 128 .flags = IORESOURCE_MEM, 129 .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), 130 .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf 131 }, { 132 .flags = IORESOURCE_MEM, 133 .start = cvmx_build_io_address(8, 0), 134 .end = cvmx_build_io_address(8, 0) + 0x7 135 } 136 }; 137 138 pd = platform_device_alloc("octeon_rng", -1); 139 if (!pd) { 140 ret = -ENOMEM; 141 goto out; 142 } 143 144 ret = platform_device_add_resources(pd, rng_resources, 145 ARRAY_SIZE(rng_resources)); 146 if (ret) 147 goto fail; 148 149 ret = platform_device_add(pd); 150 if (ret) 151 goto fail; 152 153 return ret; 154 fail: 155 platform_device_put(pd); 156 157 out: 158 return ret; 159 } 160 device_initcall(octeon_rng_device_init); 161 162 /* Octeon SMI/MDIO interface. */ 163 static int __init octeon_mdiobus_device_init(void) 164 { 165 struct platform_device *pd; 166 int ret = 0; 167 168 if (octeon_is_simulation()) 169 return 0; /* No mdio in the simulator. */ 170 171 /* The bus number is the platform_device id. */ 172 pd = platform_device_alloc("mdio-octeon", 0); 173 if (!pd) { 174 ret = -ENOMEM; 175 goto out; 176 } 177 178 ret = platform_device_add(pd); 179 if (ret) 180 goto fail; 181 182 return ret; 183 fail: 184 platform_device_put(pd); 185 186 out: 187 return ret; 188 189 } 190 device_initcall(octeon_mdiobus_device_init); 191 192 /* Octeon mgmt port Ethernet interface. */ 193 static int __init octeon_mgmt_device_init(void) 194 { 195 struct platform_device *pd; 196 int ret = 0; 197 int port, num_ports; 198 199 struct resource mgmt_port_resource = { 200 .flags = IORESOURCE_IRQ, 201 .start = -1, 202 .end = -1 203 }; 204 205 if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX)) 206 return 0; 207 208 if (OCTEON_IS_MODEL(OCTEON_CN56XX)) 209 num_ports = 1; 210 else 211 num_ports = 2; 212 213 for (port = 0; port < num_ports; port++) { 214 pd = platform_device_alloc("octeon_mgmt", port); 215 if (!pd) { 216 ret = -ENOMEM; 217 goto out; 218 } 219 switch (port) { 220 case 0: 221 mgmt_port_resource.start = OCTEON_IRQ_MII0; 222 break; 223 case 1: 224 mgmt_port_resource.start = OCTEON_IRQ_MII1; 225 break; 226 default: 227 BUG(); 228 } 229 mgmt_port_resource.end = mgmt_port_resource.start; 230 231 ret = platform_device_add_resources(pd, &mgmt_port_resource, 1); 232 233 if (ret) 234 goto fail; 235 236 ret = platform_device_add(pd); 237 if (ret) 238 goto fail; 239 } 240 return ret; 241 fail: 242 platform_device_put(pd); 243 244 out: 245 return ret; 246 247 } 248 device_initcall(octeon_mgmt_device_init); 249 250 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); 251 MODULE_LICENSE("GPL"); 252 MODULE_DESCRIPTION("Platform driver for Octeon SOC"); 253