cobalt-flash.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * Cobalt NOR flash functions
  3. *
  4. * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  5. * All rights reserved.
  6. *
  7. * This program is free software; you may redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; version 2 of the License.
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  12. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  13. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  14. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  15. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  16. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. * SOFTWARE.
  19. */
  20. #include <linux/mtd/mtd.h>
  21. #include <linux/mtd/map.h>
  22. #include <linux/mtd/cfi.h>
  23. #include <linux/time.h>
  24. #include "cobalt-flash.h"
  25. #define ADRS(offset) (COBALT_BUS_FLASH_BASE + offset)
  26. static struct map_info cobalt_flash_map = {
  27. .name = "cobalt-flash",
  28. .bankwidth = 2, /* 16 bits */
  29. .size = 0x4000000, /* 64MB */
  30. .phys = 0, /* offset */
  31. };
  32. static map_word flash_read16(struct map_info *map, unsigned long offset)
  33. {
  34. map_word r;
  35. r.x[0] = cobalt_bus_read32(map->virt, ADRS(offset));
  36. if (offset & 0x2)
  37. r.x[0] >>= 16;
  38. else
  39. r.x[0] &= 0x0000ffff;
  40. return r;
  41. }
  42. static void flash_write16(struct map_info *map, const map_word datum,
  43. unsigned long offset)
  44. {
  45. u16 data = (u16)datum.x[0];
  46. cobalt_bus_write16(map->virt, ADRS(offset), data);
  47. }
  48. static void flash_copy_from(struct map_info *map, void *to,
  49. unsigned long from, ssize_t len)
  50. {
  51. u32 src = from;
  52. u8 *dest = to;
  53. u32 data;
  54. while (len) {
  55. data = cobalt_bus_read32(map->virt, ADRS(src));
  56. do {
  57. *dest = data >> (8 * (src & 3));
  58. src++;
  59. dest++;
  60. len--;
  61. } while (len && (src % 4));
  62. }
  63. }
  64. static void flash_copy_to(struct map_info *map, unsigned long to,
  65. const void *from, ssize_t len)
  66. {
  67. const u8 *src = from;
  68. u32 dest = to;
  69. pr_info("%s: offset 0x%x: length %zu\n", __func__, dest, len);
  70. while (len) {
  71. u16 data = 0xffff;
  72. do {
  73. data = *src << (8 * (dest & 1));
  74. src++;
  75. dest++;
  76. len--;
  77. } while (len && (dest % 2));
  78. cobalt_bus_write16(map->virt, ADRS(dest - 2), data);
  79. }
  80. }
  81. int cobalt_flash_probe(struct cobalt *cobalt)
  82. {
  83. struct map_info *map = &cobalt_flash_map;
  84. struct mtd_info *mtd;
  85. BUG_ON(!map_bankwidth_supported(map->bankwidth));
  86. map->virt = cobalt->bar1;
  87. map->read = flash_read16;
  88. map->write = flash_write16;
  89. map->copy_from = flash_copy_from;
  90. map->copy_to = flash_copy_to;
  91. mtd = do_map_probe("cfi_probe", map);
  92. cobalt->mtd = mtd;
  93. if (!mtd) {
  94. cobalt_err("Probe CFI flash failed!\n");
  95. return -1;
  96. }
  97. mtd->owner = THIS_MODULE;
  98. mtd->dev.parent = &cobalt->pci_dev->dev;
  99. mtd_device_register(mtd, NULL, 0);
  100. return 0;
  101. }
  102. void cobalt_flash_remove(struct cobalt *cobalt)
  103. {
  104. if (cobalt->mtd) {
  105. mtd_device_unregister(cobalt->mtd);
  106. map_destroy(cobalt->mtd);
  107. }
  108. }