cobalt-flash.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Cobalt NOR flash functions
  4. *
  5. * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  6. * All rights reserved.
  7. */
  8. #include <linux/mtd/mtd.h>
  9. #include <linux/mtd/map.h>
  10. #include <linux/mtd/cfi.h>
  11. #include <linux/time.h>
  12. #include "cobalt-flash.h"
  13. #define ADRS(offset) (COBALT_BUS_FLASH_BASE + offset)
  14. static struct map_info cobalt_flash_map = {
  15. .name = "cobalt-flash",
  16. .bankwidth = 2, /* 16 bits */
  17. .size = 0x4000000, /* 64MB */
  18. .phys = 0, /* offset */
  19. };
  20. static map_word flash_read16(struct map_info *map, unsigned long offset)
  21. {
  22. map_word r;
  23. r.x[0] = cobalt_bus_read32(map->virt, ADRS(offset));
  24. if (offset & 0x2)
  25. r.x[0] >>= 16;
  26. else
  27. r.x[0] &= 0x0000ffff;
  28. return r;
  29. }
  30. static void flash_write16(struct map_info *map, const map_word datum,
  31. unsigned long offset)
  32. {
  33. u16 data = (u16)datum.x[0];
  34. cobalt_bus_write16(map->virt, ADRS(offset), data);
  35. }
  36. static void flash_copy_from(struct map_info *map, void *to,
  37. unsigned long from, ssize_t len)
  38. {
  39. u32 src = from;
  40. u8 *dest = to;
  41. u32 data;
  42. while (len) {
  43. data = cobalt_bus_read32(map->virt, ADRS(src));
  44. do {
  45. *dest = data >> (8 * (src & 3));
  46. src++;
  47. dest++;
  48. len--;
  49. } while (len && (src % 4));
  50. }
  51. }
  52. static void flash_copy_to(struct map_info *map, unsigned long to,
  53. const void *from, ssize_t len)
  54. {
  55. const u8 *src = from;
  56. u32 dest = to;
  57. pr_info("%s: offset 0x%x: length %zu\n", __func__, dest, len);
  58. while (len) {
  59. u16 data = 0xffff;
  60. do {
  61. data = *src << (8 * (dest & 1));
  62. src++;
  63. dest++;
  64. len--;
  65. } while (len && (dest % 2));
  66. cobalt_bus_write16(map->virt, ADRS(dest - 2), data);
  67. }
  68. }
  69. int cobalt_flash_probe(struct cobalt *cobalt)
  70. {
  71. struct map_info *map = &cobalt_flash_map;
  72. struct mtd_info *mtd;
  73. BUG_ON(!map_bankwidth_supported(map->bankwidth));
  74. map->virt = cobalt->bar1;
  75. map->read = flash_read16;
  76. map->write = flash_write16;
  77. map->copy_from = flash_copy_from;
  78. map->copy_to = flash_copy_to;
  79. mtd = do_map_probe("cfi_probe", map);
  80. cobalt->mtd = mtd;
  81. if (!mtd) {
  82. cobalt_err("Probe CFI flash failed!\n");
  83. return -1;
  84. }
  85. mtd->owner = THIS_MODULE;
  86. mtd->dev.parent = &cobalt->pci_dev->dev;
  87. mtd_device_register(mtd, NULL, 0);
  88. return 0;
  89. }
  90. void cobalt_flash_remove(struct cobalt *cobalt)
  91. {
  92. if (cobalt->mtd) {
  93. mtd_device_unregister(cobalt->mtd);
  94. map_destroy(cobalt->mtd);
  95. }
  96. }