winbond.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * Copyright 2008, Network Appliance Inc.
  3. * Author: Jason McMullan <mcmullan <at> netapp.com>
  4. * Licensed under the GPL-2 or later.
  5. */
  6. #include <common.h>
  7. #include <malloc.h>
  8. #include <spi_flash.h>
  9. #include "spi_flash_internal.h"
  10. /* M25Pxx-specific commands */
  11. #define CMD_W25_SE 0x20 /* Sector (4K) Erase */
  12. #define CMD_W25_BE 0xd8 /* Block (64K) Erase */
  13. #define CMD_W25_CE 0xc7 /* Chip Erase */
  14. struct winbond_spi_flash_params {
  15. uint16_t id;
  16. /* Log2 of page size in power-of-two mode */
  17. uint8_t l2_page_size;
  18. uint16_t pages_per_sector;
  19. uint16_t sectors_per_block;
  20. uint16_t nr_blocks;
  21. const char *name;
  22. };
  23. static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {
  24. {
  25. .id = 0x3013,
  26. .l2_page_size = 8,
  27. .pages_per_sector = 16,
  28. .sectors_per_block = 16,
  29. .nr_blocks = 8,
  30. .name = "W25X40",
  31. },
  32. {
  33. .id = 0x3015,
  34. .l2_page_size = 8,
  35. .pages_per_sector = 16,
  36. .sectors_per_block = 16,
  37. .nr_blocks = 32,
  38. .name = "W25X16",
  39. },
  40. {
  41. .id = 0x3016,
  42. .l2_page_size = 8,
  43. .pages_per_sector = 16,
  44. .sectors_per_block = 16,
  45. .nr_blocks = 64,
  46. .name = "W25X32",
  47. },
  48. {
  49. .id = 0x3017,
  50. .l2_page_size = 8,
  51. .pages_per_sector = 16,
  52. .sectors_per_block = 16,
  53. .nr_blocks = 128,
  54. .name = "W25X64",
  55. },
  56. {
  57. .id = 0x4014,
  58. .l2_page_size = 8,
  59. .pages_per_sector = 16,
  60. .sectors_per_block = 16,
  61. .nr_blocks = 16,
  62. .name = "W25Q80BL",
  63. },
  64. {
  65. .id = 0x4015,
  66. .l2_page_size = 8,
  67. .pages_per_sector = 16,
  68. .sectors_per_block = 16,
  69. .nr_blocks = 32,
  70. .name = "W25Q16",
  71. },
  72. {
  73. .id = 0x4016,
  74. .l2_page_size = 8,
  75. .pages_per_sector = 16,
  76. .sectors_per_block = 16,
  77. .nr_blocks = 64,
  78. .name = "W25Q32",
  79. },
  80. {
  81. .id = 0x4017,
  82. .l2_page_size = 8,
  83. .pages_per_sector = 16,
  84. .sectors_per_block = 16,
  85. .nr_blocks = 128,
  86. .name = "W25Q64",
  87. },
  88. {
  89. .id = 0x4018,
  90. .l2_page_size = 8,
  91. .pages_per_sector = 16,
  92. .sectors_per_block = 16,
  93. .nr_blocks = 256,
  94. .name = "W25Q128",
  95. },
  96. };
  97. static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len)
  98. {
  99. return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len);
  100. }
  101. struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
  102. {
  103. const struct winbond_spi_flash_params *params;
  104. struct spi_flash *flash;
  105. unsigned int i;
  106. unsigned page_size;
  107. for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) {
  108. params = &winbond_spi_flash_table[i];
  109. if (params->id == ((idcode[1] << 8) | idcode[2]))
  110. break;
  111. }
  112. if (i == ARRAY_SIZE(winbond_spi_flash_table)) {
  113. debug("SF: Unsupported Winbond ID %02x%02x\n",
  114. idcode[1], idcode[2]);
  115. return NULL;
  116. }
  117. flash = malloc(sizeof(*flash));
  118. if (!flash) {
  119. debug("SF: Failed to allocate memory\n");
  120. return NULL;
  121. }
  122. flash->spi = spi;
  123. flash->name = params->name;
  124. /* Assuming power-of-two page size initially. */
  125. page_size = 1 << params->l2_page_size;
  126. flash->write = spi_flash_cmd_write_multi;
  127. flash->erase = winbond_erase;
  128. flash->read = spi_flash_cmd_read_fast;
  129. flash->page_size = page_size;
  130. flash->sector_size = page_size * params->pages_per_sector;
  131. flash->size = page_size * params->pages_per_sector
  132. * params->sectors_per_block
  133. * params->nr_blocks;
  134. return flash;
  135. }