octeon-platform.c 4.0 KB

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