Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | /* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2004-2009 Cavium Networks * Copyright (C) 2008 Wind River Systems */ #include <linux/init.h> #include <linux/irq.h> #include <linux/module.h> #include <linux/platform_device.h> #include <asm/octeon/octeon.h> #include <asm/octeon/cvmx-rnm-defs.h> static struct octeon_cf_data octeon_cf_data; static int __init octeon_cf_device_init(void) { union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; unsigned long base_ptr, region_base, region_size; struct platform_device *pd; struct resource cf_resources[3]; unsigned int num_resources; int i; int ret = 0; /* Setup octeon-cf platform device if present. */ base_ptr = 0; if (octeon_bootinfo->major_version == 1 && octeon_bootinfo->minor_version >= 1) { if (octeon_bootinfo->compact_flash_common_base_addr) base_ptr = octeon_bootinfo->compact_flash_common_base_addr; } else { base_ptr = 0x1d000800; } if (!base_ptr) return ret; /* Find CS0 region. */ for (i = 0; i < 8; i++) { mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i)); region_base = mio_boot_reg_cfg.s.base << 16; region_size = (mio_boot_reg_cfg.s.size + 1) << 16; if (mio_boot_reg_cfg.s.en && base_ptr >= region_base && base_ptr < region_base + region_size) break; } if (i >= 7) { /* i and i + 1 are CS0 and CS1, both must be less than 8. */ goto out; } octeon_cf_data.base_region = i; octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width; octeon_cf_data.base_region_bias = base_ptr - region_base; memset(cf_resources, 0, sizeof(cf_resources)); num_resources = 0; cf_resources[num_resources].flags = IORESOURCE_MEM; cf_resources[num_resources].start = region_base; cf_resources[num_resources].end = region_base + region_size - 1; num_resources++; if (!(base_ptr & 0xfffful)) { /* * Boot loader signals availability of DMA (true_ide * mode) by setting low order bits of base_ptr to * zero. */ /* Asume that CS1 immediately follows. */ mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1)); region_base = mio_boot_reg_cfg.s.base << 16; region_size = (mio_boot_reg_cfg.s.size + 1) << 16; if (!mio_boot_reg_cfg.s.en) goto out; cf_resources[num_resources].flags = IORESOURCE_MEM; cf_resources[num_resources].start = region_base; cf_resources[num_resources].end = region_base + region_size - 1; num_resources++; octeon_cf_data.dma_engine = 0; cf_resources[num_resources].flags = IORESOURCE_IRQ; cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA; cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA; num_resources++; } else { octeon_cf_data.dma_engine = -1; } pd = platform_device_alloc("pata_octeon_cf", -1); if (!pd) { ret = -ENOMEM; goto out; } pd->dev.platform_data = &octeon_cf_data; ret = platform_device_add_resources(pd, cf_resources, num_resources); if (ret) goto fail; ret = platform_device_add(pd); if (ret) goto fail; return ret; fail: platform_device_put(pd); out: return ret; } device_initcall(octeon_cf_device_init); /* Octeon Random Number Generator. */ static int __init octeon_rng_device_init(void) { struct platform_device *pd; int ret = 0; struct resource rng_resources[] = { { .flags = IORESOURCE_MEM, .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf }, { .flags = IORESOURCE_MEM, .start = cvmx_build_io_address(8, 0), .end = cvmx_build_io_address(8, 0) + 0x7 } }; pd = platform_device_alloc("octeon_rng", -1); if (!pd) { ret = -ENOMEM; goto out; } ret = platform_device_add_resources(pd, rng_resources, ARRAY_SIZE(rng_resources)); if (ret) goto fail; ret = platform_device_add(pd); if (ret) goto fail; return ret; fail: platform_device_put(pd); out: return ret; } device_initcall(octeon_rng_device_init); MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Platform driver for Octeon SOC"); |