]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/spi/winbond.c
Merge branch 'master' of git://git.denx.de/u-boot-usb
[karo-tx-uboot.git] / drivers / mtd / spi / winbond.c
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
7 #include <common.h>
8 #include <malloc.h>
9 #include <spi_flash.h>
10
11 #include "spi_flash_internal.h"
12
13 /* M25Pxx-specific commands */
14 #define CMD_W25_SE              0x20    /* Sector (4K) Erase */
15 #define CMD_W25_BE              0xd8    /* Block (64K) Erase */
16 #define CMD_W25_CE              0xc7    /* Chip Erase */
17
18 struct winbond_spi_flash_params {
19         uint16_t        id;
20         /* Log2 of page size in power-of-two mode */
21         uint8_t         l2_page_size;
22         uint16_t        pages_per_sector;
23         uint16_t        sectors_per_block;
24         uint16_t        nr_blocks;
25         const char      *name;
26 };
27
28 static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {
29         {
30                 .id                     = 0x3013,
31                 .l2_page_size           = 8,
32                 .pages_per_sector       = 16,
33                 .sectors_per_block      = 16,
34                 .nr_blocks              = 8,
35                 .name                   = "W25X40",
36         },
37         {
38                 .id                     = 0x3015,
39                 .l2_page_size           = 8,
40                 .pages_per_sector       = 16,
41                 .sectors_per_block      = 16,
42                 .nr_blocks              = 32,
43                 .name                   = "W25X16",
44         },
45         {
46                 .id                     = 0x3016,
47                 .l2_page_size           = 8,
48                 .pages_per_sector       = 16,
49                 .sectors_per_block      = 16,
50                 .nr_blocks              = 64,
51                 .name                   = "W25X32",
52         },
53         {
54                 .id                     = 0x3017,
55                 .l2_page_size           = 8,
56                 .pages_per_sector       = 16,
57                 .sectors_per_block      = 16,
58                 .nr_blocks              = 128,
59                 .name                   = "W25X64",
60         },
61         {
62                 .id                     = 0x4014,
63                 .l2_page_size           = 8,
64                 .pages_per_sector       = 16,
65                 .sectors_per_block      = 16,
66                 .nr_blocks              = 16,
67                 .name                   = "W25Q80BL",
68         },
69         {
70                 .id                     = 0x4015,
71                 .l2_page_size           = 8,
72                 .pages_per_sector       = 16,
73                 .sectors_per_block      = 16,
74                 .nr_blocks              = 32,
75                 .name                   = "W25Q16",
76         },
77         {
78                 .id                     = 0x4016,
79                 .l2_page_size           = 8,
80                 .pages_per_sector       = 16,
81                 .sectors_per_block      = 16,
82                 .nr_blocks              = 64,
83                 .name                   = "W25Q32",
84         },
85         {
86                 .id                     = 0x4017,
87                 .l2_page_size           = 8,
88                 .pages_per_sector       = 16,
89                 .sectors_per_block      = 16,
90                 .nr_blocks              = 128,
91                 .name                   = "W25Q64",
92         },
93         {
94                 .id                     = 0x4018,
95                 .l2_page_size           = 8,
96                 .pages_per_sector       = 16,
97                 .sectors_per_block      = 16,
98                 .nr_blocks              = 256,
99                 .name                   = "W25Q128",
100         },
101 };
102
103 static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len)
104 {
105         return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len);
106 }
107
108 struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
109 {
110         const struct winbond_spi_flash_params *params;
111         struct spi_flash *flash;
112         unsigned int i;
113         unsigned page_size;
114
115         for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) {
116                 params = &winbond_spi_flash_table[i];
117                 if (params->id == ((idcode[1] << 8) | idcode[2]))
118                         break;
119         }
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
127         flash = malloc(sizeof(*flash));
128         if (!flash) {
129                 debug("SF: Failed to allocate memory\n");
130                 return NULL;
131         }
132
133         flash->spi = spi;
134         flash->name = params->name;
135
136         /* Assuming power-of-two page size initially. */
137         page_size = 1 << params->l2_page_size;
138
139         flash->write = spi_flash_cmd_write_multi;
140         flash->erase = winbond_erase;
141         flash->read = spi_flash_cmd_read_fast;
142         flash->page_size = page_size;
143         flash->sector_size = page_size * params->pages_per_sector;
144         flash->size = page_size * params->pages_per_sector
145                                 * params->sectors_per_block
146                                 * params->nr_blocks;
147
148         return flash;
149 }