winbond.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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_WREN 0x06 /* Write Enable */
  12. #define CMD_W25_WRDI 0x04 /* Write Disable */
  13. #define CMD_W25_RDSR 0x05 /* Read Status Register */
  14. #define CMD_W25_WRSR 0x01 /* Write Status Register */
  15. #define CMD_W25_READ 0x03 /* Read Data Bytes */
  16. #define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
  17. #define CMD_W25_PP 0x02 /* Page Program */
  18. #define CMD_W25_SE 0x20 /* Sector (4K) Erase */
  19. #define CMD_W25_BE 0xd8 /* Block (64K) Erase */
  20. #define CMD_W25_CE 0xc7 /* Chip Erase */
  21. #define CMD_W25_DP 0xb9 /* Deep Power-down */
  22. #define CMD_W25_RES 0xab /* Release from DP, and Read Signature */
  23. struct winbond_spi_flash_params {
  24. uint16_t id;
  25. /* Log2 of page size in power-of-two mode */
  26. uint8_t l2_page_size;
  27. uint16_t pages_per_sector;
  28. uint16_t sectors_per_block;
  29. uint16_t nr_blocks;
  30. const char *name;
  31. };
  32. static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {
  33. {
  34. .id = 0x3013,
  35. .l2_page_size = 8,
  36. .pages_per_sector = 16,
  37. .sectors_per_block = 16,
  38. .nr_blocks = 8,
  39. .name = "W25X40",
  40. },
  41. {
  42. .id = 0x3015,
  43. .l2_page_size = 8,
  44. .pages_per_sector = 16,
  45. .sectors_per_block = 16,
  46. .nr_blocks = 32,
  47. .name = "W25X16",
  48. },
  49. {
  50. .id = 0x3016,
  51. .l2_page_size = 8,
  52. .pages_per_sector = 16,
  53. .sectors_per_block = 16,
  54. .nr_blocks = 64,
  55. .name = "W25X32",
  56. },
  57. {
  58. .id = 0x3017,
  59. .l2_page_size = 8,
  60. .pages_per_sector = 16,
  61. .sectors_per_block = 16,
  62. .nr_blocks = 128,
  63. .name = "W25X64",
  64. },
  65. {
  66. .id = 0x4014,
  67. .l2_page_size = 8,
  68. .pages_per_sector = 16,
  69. .sectors_per_block = 16,
  70. .nr_blocks = 16,
  71. .name = "W25Q80BL",
  72. },
  73. {
  74. .id = 0x4015,
  75. .l2_page_size = 8,
  76. .pages_per_sector = 16,
  77. .sectors_per_block = 16,
  78. .nr_blocks = 32,
  79. .name = "W25Q16",
  80. },
  81. {
  82. .id = 0x4016,
  83. .l2_page_size = 8,
  84. .pages_per_sector = 16,
  85. .sectors_per_block = 16,
  86. .nr_blocks = 64,
  87. .name = "W25Q32",
  88. },
  89. {
  90. .id = 0x4017,
  91. .l2_page_size = 8,
  92. .pages_per_sector = 16,
  93. .sectors_per_block = 16,
  94. .nr_blocks = 128,
  95. .name = "W25Q64",
  96. },
  97. {
  98. .id = 0x4018,
  99. .l2_page_size = 8,
  100. .pages_per_sector = 16,
  101. .sectors_per_block = 16,
  102. .nr_blocks = 256,
  103. .name = "W25Q128",
  104. },
  105. };
  106. static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len)
  107. {
  108. return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len);
  109. }
  110. struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
  111. {
  112. const struct winbond_spi_flash_params *params;
  113. struct spi_flash *flash;
  114. unsigned int i;
  115. unsigned page_size;
  116. for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) {
  117. params = &winbond_spi_flash_table[i];
  118. if (params->id == ((idcode[1] << 8) | idcode[2]))
  119. break;
  120. }
  121. if (i == ARRAY_SIZE(winbond_spi_flash_table)) {
  122. debug("SF: Unsupported Winbond ID %02x%02x\n",
  123. idcode[1], idcode[2]);
  124. return NULL;
  125. }
  126. flash = malloc(sizeof(*flash));
  127. if (!flash) {
  128. debug("SF: Failed to allocate memory\n");
  129. return NULL;
  130. }
  131. flash->spi = spi;
  132. flash->name = params->name;
  133. /* Assuming power-of-two page size initially. */
  134. page_size = 1 << params->l2_page_size;
  135. flash->write = spi_flash_cmd_write_multi;
  136. flash->erase = winbond_erase;
  137. flash->read = spi_flash_cmd_read_fast;
  138. flash->page_size = page_size;
  139. flash->sector_size = page_size * params->pages_per_sector;
  140. flash->size = page_size * params->pages_per_sector
  141. * params->sectors_per_block
  142. * params->nr_blocks;
  143. return flash;
  144. }