1 | /* |
2 | * Broadcom specific AMBA |
3 | * ChipCommon serial flash interface |
4 | * |
5 | * Licensed under the GNU/GPL. See COPYING for details. |
6 | */ |
7 | |
8 | #include "bcma_private.h" |
9 | |
10 | #include <linux/platform_device.h> |
11 | #include <linux/bcma/bcma.h> |
12 | |
13 | static struct resource bcma_sflash_resource = { |
14 | .name = "bcma_sflash" , |
15 | .start = BCMA_SOC_FLASH2, |
16 | .end = 0, |
17 | .flags = IORESOURCE_MEM | IORESOURCE_READONLY, |
18 | }; |
19 | |
20 | struct platform_device bcma_sflash_dev = { |
21 | .name = "bcma_sflash" , |
22 | .resource = &bcma_sflash_resource, |
23 | .num_resources = 1, |
24 | }; |
25 | |
26 | struct bcma_sflash_tbl_e { |
27 | char *name; |
28 | u32 id; |
29 | u32 blocksize; |
30 | u16 numblocks; |
31 | }; |
32 | |
33 | static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = { |
34 | { "M25P20" , 0x11, 0x10000, 4, }, |
35 | { "M25P40" , 0x12, 0x10000, 8, }, |
36 | |
37 | { "M25P16" , 0x14, 0x10000, 32, }, |
38 | { "M25P32" , 0x15, 0x10000, 64, }, |
39 | { "M25P64" , 0x16, 0x10000, 128, }, |
40 | { "M25FL128" , 0x17, 0x10000, 256, }, |
41 | { "MX25L25635F" , 0x18, 0x10000, 512, }, |
42 | { NULL }, |
43 | }; |
44 | |
45 | static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = { |
46 | { "SST25WF512" , 1, 0x1000, 16, }, |
47 | { "SST25VF512" , 0x48, 0x1000, 16, }, |
48 | { "SST25WF010" , 2, 0x1000, 32, }, |
49 | { "SST25VF010" , 0x49, 0x1000, 32, }, |
50 | { "SST25WF020" , 3, 0x1000, 64, }, |
51 | { "SST25VF020" , 0x43, 0x1000, 64, }, |
52 | { "SST25WF040" , 4, 0x1000, 128, }, |
53 | { "SST25VF040" , 0x44, 0x1000, 128, }, |
54 | { "SST25VF040B" , 0x8d, 0x1000, 128, }, |
55 | { "SST25WF080" , 5, 0x1000, 256, }, |
56 | { "SST25VF080B" , 0x8e, 0x1000, 256, }, |
57 | { "SST25VF016" , 0x41, 0x1000, 512, }, |
58 | { "SST25VF032" , 0x4a, 0x1000, 1024, }, |
59 | { "SST25VF064" , 0x4b, 0x1000, 2048, }, |
60 | { NULL }, |
61 | }; |
62 | |
63 | static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = { |
64 | { "AT45DB011" , 0xc, 256, 512, }, |
65 | { "AT45DB021" , 0x14, 256, 1024, }, |
66 | { "AT45DB041" , 0x1c, 256, 2048, }, |
67 | { "AT45DB081" , 0x24, 256, 4096, }, |
68 | { "AT45DB161" , 0x2c, 512, 4096, }, |
69 | { "AT45DB321" , 0x34, 512, 8192, }, |
70 | { "AT45DB642" , 0x3c, 1024, 8192, }, |
71 | { NULL }, |
72 | }; |
73 | |
74 | static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode) |
75 | { |
76 | int i; |
77 | bcma_cc_write32(cc, BCMA_CC_FLASHCTL, |
78 | BCMA_CC_FLASHCTL_START | opcode); |
79 | for (i = 0; i < 1000; i++) { |
80 | if (!(bcma_cc_read32(cc, BCMA_CC_FLASHCTL) & |
81 | BCMA_CC_FLASHCTL_BUSY)) |
82 | return; |
83 | cpu_relax(); |
84 | } |
85 | bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n" ); |
86 | } |
87 | |
88 | /* Initialize serial flash access */ |
89 | int bcma_sflash_init(struct bcma_drv_cc *cc) |
90 | { |
91 | struct bcma_bus *bus = cc->core->bus; |
92 | struct bcma_sflash *sflash = &cc->sflash; |
93 | const struct bcma_sflash_tbl_e *e; |
94 | u32 id, id2; |
95 | |
96 | switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { |
97 | case BCMA_CC_FLASHT_STSER: |
98 | bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP); |
99 | |
100 | bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0); |
101 | bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES); |
102 | id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA); |
103 | |
104 | bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1); |
105 | bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES); |
106 | id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA); |
107 | |
108 | switch (id) { |
109 | case 0xbf: |
110 | for (e = bcma_sflash_sst_tbl; e->name; e++) { |
111 | if (e->id == id2) |
112 | break; |
113 | } |
114 | break; |
115 | case 0x13: |
116 | return -ENOTSUPP; |
117 | default: |
118 | for (e = bcma_sflash_st_tbl; e->name; e++) { |
119 | if (e->id == id) |
120 | break; |
121 | } |
122 | break; |
123 | } |
124 | if (!e->name) { |
125 | bcma_err(bus, "Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n" , id, id2); |
126 | return -ENOTSUPP; |
127 | } |
128 | |
129 | break; |
130 | case BCMA_CC_FLASHT_ATSER: |
131 | bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS); |
132 | id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c; |
133 | |
134 | for (e = bcma_sflash_at_tbl; e->name; e++) { |
135 | if (e->id == id) |
136 | break; |
137 | } |
138 | if (!e->name) { |
139 | bcma_err(bus, "Unsupported Atmel serial flash (id: 0x%X)\n" , id); |
140 | return -ENOTSUPP; |
141 | } |
142 | |
143 | break; |
144 | default: |
145 | bcma_err(bus, "Unsupported flash type\n" ); |
146 | return -ENOTSUPP; |
147 | } |
148 | |
149 | sflash->blocksize = e->blocksize; |
150 | sflash->numblocks = e->numblocks; |
151 | sflash->size = sflash->blocksize * sflash->numblocks; |
152 | sflash->present = true; |
153 | |
154 | bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n" , |
155 | e->name, sflash->size / 1024, sflash->blocksize, |
156 | sflash->numblocks); |
157 | |
158 | /* Prepare platform device, but don't register it yet. It's too early, |
159 | * malloc (required by device_private_init) is not available yet. */ |
160 | bcma_sflash_dev.resource[0].end = bcma_sflash_dev.resource[0].start + |
161 | sflash->size; |
162 | bcma_sflash_dev.dev.platform_data = sflash; |
163 | |
164 | return 0; |
165 | } |
166 | |