Patch from andy yan <andyysj@gmail.com>:
[mirror/scst/.git] / mvsas_tgt / mv_spi.c
1 #ifdef SUPPORT_TARGET
2 #include "mv_sas.h"
3 #include "mv_spi.h"
4
5 static u8    SPICmd[16];
6
7 #ifndef IDENTIFY_SPI
8 u8   DEFAULT_SPI_CMD[16] =
9 {
10     0x06, 0x04, 0x05, 0x01, 0x03, 0x02, 0x52, 0x62, 0x15
11 };
12 #else
13 u8   ATMEL_SPI_CMD[16] =
14 {
15     0x06, 0x04, 0x05, 0x01, 0x03, 0x02, 0x52, 0x62, 0x15
16 };
17 u8   MXIC_SPI_CMD[16] =
18 {
19     0x06, 0x04, 0x05, 0x01, 0x03, 0x02, 0x20, 0x60, 0x90
20 };
21 u8   WINBOND_SPI_CMD[16] =
22 {
23     0x06, 0x04, 0x05, 0x01, 0x03, 0x02, 0x20, 0xC7, 0xAB
24 };
25
26 u8   ATMEL_SPI_CMD_41a_021[16] =
27 {
28 /*  0     1     2     3     4     5     6     7     8     9     10    11*/
29     0x06, 0x04, 0x05, 0x01, 0x03, 0x02, 0xD8, 0x60, 0x9F, 0x36, 0x39, 0x3C
30 };
31
32 u8      EON_F20_SPI_CMD[16] =
33 {
34         0x06, 0x04, 0x05, 0x01, 0x03, 0x02, 0x20, 0x60, 0x90
35 };
36 #endif
37
38
39
40
41 int spi_rdsr(struct mvs_info *mvi, u8 *sr)
42 {
43         u32  dwTmp;
44
45         MVS_CHIP_DISP->spi_buildcmd(mvi, &dwTmp,
46                         (u8)SPICmd[SPI_INS_RDSR],
47                         1,
48                         1,
49                         -1);
50         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
51
52         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, 10000)) {
53                 dwTmp = MVS_CHIP_DISP->spi_read_data(mvi);
54                 *sr = (u8)dwTmp;
55                 return 0;
56         } else {
57                 mv_dprintk("timeout\n");
58         }
59         return -1;
60 }
61
62 int spi_pollisr(struct mvs_info *mvi, u8 mask, u8 bit, u32 timeout)
63 {
64         u32  i;
65         u8   sr;
66
67         for (i = 0; i < timeout; i++) {
68                 if (0 == spi_rdsr(mvi, &sr)) {
69                         if ((sr & mask) == bit)
70                                 return 0;
71                 }
72                 msleep(20);
73         }
74         return -1;
75 }
76
77 #ifdef IDENTIFY_SPI
78 #define SPI_IDENTIFY_TIMER              10000
79
80 int spi_atmelidentify(struct mvs_info *mvi)
81 {
82         u32  dwtmp;
83         MVS_CHIP_DISP->spi_buildcmd(mvi, &dwtmp,
84                 ATMEL_SPI_CMD[SPI_INS_RDID],
85                 1,
86                 2,
87                 0);
88         MVS_CHIP_DISP->spi_issuecmd(mvi, dwtmp);
89         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, SPI_IDENTIFY_TIMER)) {
90                 dwtmp = MVS_CHIP_DISP->spi_read_data(mvi);
91                 switch (dwtmp) {
92                 case 0x631f:
93                         mvi->flashid = AT25F2048;
94                         mvi->flashsize = 256L * 1024;
95                         mvi->flashsectSize = 64L * 1024;
96                         return 0;
97                 }
98         }
99         mv_dprintk("identify failed\n");
100         return -1;
101 }
102
103 int spi_atmelidentify_41a_021(struct mvs_info *mvi)
104 {
105         u32  dwTmp;
106         MVS_CHIP_DISP->spi_buildcmd(mvi, &dwTmp,
107                 (u8)ATMEL_SPI_CMD_41a_021[SPI_INS_RDID],
108                 1,
109                 2,
110                 -1);
111         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
112
113         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, SPI_IDENTIFY_TIMER)) {
114                 dwTmp = MVS_CHIP_DISP->spi_read_data(mvi);
115                 switch (dwTmp) {
116                 case 0x441f:
117                         mvi->flashid = AT25DF041A;
118                         mvi->flashsize = 256L * 1024;
119                         mvi->flashsectSize = 64L * 1024;
120                         return 0;
121                 case 0x431f:
122                         mvi->flashid = AT25DF021;
123                         mvi->flashsize = 256L * 1024;
124                         mvi->flashsectSize = 64L * 1024;
125                         return 0;
126                 }
127         }
128
129     return -1;
130 }
131
132
133 int spi_winbondidentify(struct mvs_info *mvi)
134 {
135         u32  dwTmp;
136
137         MVS_CHIP_DISP->spi_buildcmd(mvi,  &dwTmp,
138                 WINBOND_SPI_CMD[SPI_INS_RDID],
139                 1,
140                 2,
141                 0);
142         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
143
144         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, SPI_IDENTIFY_TIMER)) {
145                 dwTmp = MVS_CHIP_DISP->spi_read_data(mvi);
146                 switch (dwTmp) {
147                 case 0x1212:
148                         mvi->flashid = W25X40;
149                         mvi->flashsize = 256L * 1024;
150                         mvi->flashsectSize = 64L * 1024;
151                         return 0;
152             }
153         }
154
155         return -1;
156 }
157
158 int spi_mxicidentify(struct mvs_info *mvi)
159 {
160         u32  dwTmp;
161
162         MVS_CHIP_DISP->spi_buildcmd(mvi, &dwTmp,
163                 MXIC_SPI_CMD[SPI_INS_RDID],
164                 1,
165                 2,
166                 0);
167         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
168
169         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, SPI_IDENTIFY_TIMER)) {
170                 dwTmp = MVS_CHIP_DISP->spi_read_data(mvi);
171                 switch (dwTmp) {
172                 case 0x11C2:
173                         mvi->flashid = MX25L2005;
174                         mvi->flashsize = 256L * 1024;
175                         mvi->flashsectSize = 4L * 1024;
176                         return 0;
177                 }
178         }
179         return -1;
180 }
181
182 int spi_eonidentify_f20(struct mvs_info *mvi)
183 {
184         u32  dwTmp;
185
186         MVS_CHIP_DISP->spi_buildcmd(mvi,  &dwTmp,
187                 EON_F20_SPI_CMD[SPI_INS_RDID],
188                 1,
189                 2,
190                 0);
191         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
192
193         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, SPI_IDENTIFY_TIMER)) {
194                 dwTmp = MVS_CHIP_DISP->spi_read_data(mvi);
195                 switch (dwTmp) {
196                 case 0x111C:
197                         mvi->flashid = EN25F20;
198                         mvi->flashsize = 256L * 1024;
199                         mvi->flashsectSize = 4L * 1024;
200                         return 0;
201                 }
202         }
203
204         return -1;
205
206 }
207 #endif
208
209
210 int spi_init(struct mvs_info *mvi)
211 {
212         u32  i;
213 #ifndef IDENTIFY_SPI
214         for (i = 0; i < sizeof(SPICmd); i++)
215                 SPICmd[i] = DEFAULT_SPI_CMD[i];
216
217         mvi->flashid = 0x11ab;
218         mvi->flashsize = 256L * 1024;
219         mvi->flashsectSize = 64L * 1024;
220         return 0;
221 #else
222         u8   *spivendor;
223
224         spivendor = NULL;
225         /* Identify Atmel first. Suppose it's popular.Don't identify Mxic
226          *  since it can use the same instruction set as Atmel.
227          * If cannot identify, by default use Atmel instruction set. */
228         if (0 == spi_atmelidentify(mvi))
229                 spivendor = ATMEL_SPI_CMD;
230         else if (0 == spi_atmelidentify_41a_021(mvi))
231                 spivendor = ATMEL_SPI_CMD_41a_021;
232         else if (0 == spi_winbondidentify(mvi))
233                 spivendor = WINBOND_SPI_CMD;
234         else if (0 == spi_eonidentify_f20(mvi))
235                 spivendor = EON_F20_SPI_CMD;
236         else
237                 spivendor = ATMEL_SPI_CMD;
238
239         if (spivendor) {
240                 for (i = 0; i < sizeof(SPICmd); i++)
241                         SPICmd[i] = spivendor[i];
242                 return 0;
243         }
244         return -1;
245 #endif
246 }
247
248 int spi_read(struct mvs_info *mvi, u32 addr, u8 *data, u8 size)
249 {
250         u32  i, dwTmp;
251
252         if (size > 4)
253                 size = 4;
254         MVS_CHIP_DISP->spi_buildcmd(mvi, &dwTmp,
255                 (u8)SPICmd[SPI_INS_READ],
256                 1,
257                 size,
258                 addr);
259         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
260
261         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, 10000)) {
262                 dwTmp = MVS_CHIP_DISP->spi_read_data(mvi);
263                 for (i = 0; i < size; i++)
264                         data[i] = ((u8 *)&dwTmp)[i];
265                 return 0;
266         } else
267             mv_dprintk("timeout\n");
268
269         return -1;
270 }
271
272 int spi_readbuf(struct mvs_info *mvi, u32 addr, u8 *data, u32 count)
273 {
274         u32      i, j;
275         u32      tmpAddr, tmpdata, addrend;
276         u8       *val = data;
277
278         addrend = addr + count;
279         tmpAddr = rounding(addr, 4);
280         j = (addr & ((1U<<2) - 1));
281         if (j > 0) {
282                 spi_read(mvi, tmpAddr, (u8 *)&tmpdata, 4);
283                 for (i = j; i < 4; i++)
284                         *val++ = ((u8 *)&tmpdata)[i];
285                 tmpAddr += 4;
286         }
287         j = rounding(addrend, 4);
288         for (; tmpAddr < j; tmpAddr += 4) {
289                 spi_read(mvi, tmpAddr, (u8 *)&tmpdata, 4);
290                 *((u32 *)val) = tmpdata;
291                 val += 4;
292         }
293         if (tmpAddr < addrend) {
294                 spi_read(mvi, tmpAddr, (u8 *)&tmpdata, 4);
295                 count = addrend - tmpAddr;
296                 for (i = 0; i < count; i++)
297                         *val++ = ((u8 *)&tmpdata)[i];
298         }
299
300     return 0;
301 }
302
303 u8      mvverifychecksum(u8 *address, u32 Size)
304 {
305         u8      checkSum = 0;
306         u32     temp = 0;
307
308         for (temp = 0; temp < Size ; temp++)
309                 checkSum += address[temp];
310
311         return  checkSum;
312 }
313
314 u8      mvcalculatechecksum(u8 *address, u32 size)
315 {
316         u8 checkSum;
317         u32 temp = 0;
318         checkSum = 0;
319
320         for (temp = 0; temp < size; temp++)
321                 checkSum += address[temp];
322
323         checkSum = (~checkSum) + 1;
324         return checkSum;
325 }
326
327 int spi_wren(struct mvs_info *mvi)
328 {
329         u32  dwTmp;
330
331         MVS_CHIP_DISP->spi_buildcmd(mvi,  &dwTmp,
332                 (u8)SPICmd[SPI_INS_WREN],
333                 0,
334                 0,
335                 -1);
336         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
337
338         if (0 != MVS_CHIP_DISP->spi_waitdataready(mvi, 10000))
339                 return -1;
340         if (0 == spi_pollisr(mvi, 0x03, 0x02, 300000))
341                 return 0;
342         return -1;
343 }
344
345 int spi_rdpt(struct mvs_info *mvi, u32 addr, u8 *data)
346 {
347         u32   dwTmp;
348
349         MVS_CHIP_DISP->spi_buildcmd(mvi,  &dwTmp,
350                 (u8)SPICmd[SPI_INS_RDPT],
351                 1,
352                 1,
353                 addr);
354         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
355
356         if (0 == MVS_CHIP_DISP->spi_waitdataready(mvi, 10000)) {
357                 dwTmp = MVS_CHIP_DISP->spi_read_data(mvi);
358                 *data = (u8)dwTmp;
359                 return 0;
360         } else {
361                 mv_dprintk("SPI_RDPT timeout\n");
362         }
363         return -1;
364 }
365
366 int spi_sectunprotect(struct mvs_info *mvi, u32 addr)
367 {
368         u32 dwTmp;
369         u8 protect_sect = 0xFF;
370         if (-1 == spi_rdpt(mvi, addr, &protect_sect))
371                 return -1;
372
373         if (protect_sect == 0)
374                 return 0;
375
376         if (-1 == spi_wren(mvi))
377                 return -1;
378
379         MVS_CHIP_DISP->spi_buildcmd(mvi,  &dwTmp,
380                 (u8)SPICmd[SPI_INS_UPTSEC],
381                 0,
382                 0,
383                 addr);
384         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
385         if (0 != MVS_CHIP_DISP->spi_waitdataready(mvi, 10000))
386                 return -1;
387         if (0 == spi_pollisr(mvi, 0x03, 0, 300000))
388                 return 0;
389         mv_dprintk("error SPI_SectUnprotect \n");
390         return -1;
391 }
392
393 int spi_secterase(struct mvs_info *mvi, u32 addr)
394 {
395         u32  dwTmp;
396
397         if (-1 == spi_wren(mvi))
398                 return -1;
399
400         if ((mvi->flashid == AT25DF041A) || (mvi->flashid == AT25DF021)) {
401                 if (-1 == spi_sectunprotect(mvi, addr)) {
402                         mv_dprintk("Un protect error.\n");
403                         return -1;
404                 }
405         }
406         MVS_CHIP_DISP->spi_buildcmd(mvi,  &dwTmp,
407                 (u8)SPICmd[SPI_INS_SERASE],
408                 0,
409                 0,
410                 addr);
411         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
412         if (0 != MVS_CHIP_DISP->spi_waitdataready(mvi, 10000))
413                 return -1;
414         if (0 == spi_pollisr(mvi, 0x03, 0, 300000))
415                 return 0;
416         mv_dprintk("error SPI_SectErase\n");
417         return -1;
418 }
419
420 int spi_write(struct mvs_info *mvi, u32 addr, u32 data)
421 {
422         u32 dwTmp;
423
424         spi_wren(mvi);
425         MVS_CHIP_DISP->spi_write_data(mvi, data);
426         MVS_CHIP_DISP->spi_buildcmd(mvi,  &dwTmp,
427                 (u8)SPICmd[SPI_INS_RPOG],
428                 0,
429                 4,
430                 addr);
431         MVS_CHIP_DISP->spi_issuecmd(mvi, dwTmp);
432
433         if (0 != MVS_CHIP_DISP->spi_waitdataready(mvi, 10000)) {
434                 mv_dprintk("timeout\n");
435                 return -1;
436         }
437         if (0 == spi_pollisr(mvi, 0x01, 0, 5000))
438                 return 0;
439         mv_dprintk("timeout\n");
440         return -1;
441 }
442
443 int spi_writebuf(struct mvs_info *mvi, u32 addr, u32 *data, u32 count)
444 {
445         u32  i;
446
447         for (i = 0; i < count; i += 4) {
448                 if (-1 == spi_write(mvi, addr + i, *(u32 *)&data[i])) {
449                         mv_dprintk("Write failed at %5.5x\n", addr+i);
450                         return -1;
451                 }
452         }
453         return 0;
454 }
455
456 bool mvui_init_param(struct mvs_info *mvi, struct hba_info_main *hba_info_para)
457 {
458         u32     param_flash_addr = PARA_OFF;
459         if (!mvi)
460                 return false;
461
462         if (spi_init(mvi)) {
463                 mv_dprintk("Init flash rom failed.\n");
464                 return false;
465         }
466         mv_dprintk("Init flash rom ok,flash type is 0x%x.\n", mvi->flashid);
467         /* step 1 read param from flash offset = 0x3FFF00 */
468         spi_readbuf(mvi, param_flash_addr, \
469                         (u8 *)hba_info_para, FLASH_PARA_SIZE);
470
471         /* step 2 check the signature first */
472         if (hba_info_para->signature[0] == 'M' && \
473             hba_info_para->signature[1] == 'R' && \
474             hba_info_para->signature[2] == 'V' && \
475             hba_info_para->signature[3] == 'L' && \
476             (!mvverifychecksum((u8 *)hba_info_para, FLASH_PARA_SIZE))) {
477                 return true;
478         }
479         return false;
480 }
481
482 u8 mvs_spi_init(struct mvs_info *mvi)
483 {
484         u8 i;
485         u64 sas_addr;
486         struct hba_info_main hba_info_para;
487
488         do {
489                 if (!mvui_init_param(mvi, &hba_info_para)) {
490                         for (i = 0; i < mvi->chip->n_phy; i++) {
491                                 sas_addr = 0x5005043011ab0000ULL;
492                                 mvi->phy[i].dev_sas_addr =
493                                         cpu_to_be64((u64)(*(u64 *)&sas_addr));
494                         }
495                         return -1;
496                 }
497                 for (i = 0; i < mvi->chip->n_phy; i++) {
498                         int vphy = i+mvi->id*mvi->chip->n_phy;
499                         sas_addr = hba_info_para.sas_address[vphy];
500                         mvi->phy[i].dev_sas_addr = sas_addr;
501                         mv_printk("Phy %d SAS ADDRESS %016llx\n", i,
502                                 SAS_ADDR(&mvi->phy[i].dev_sas_addr));
503                 }
504         } while (0);
505
506         memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE);
507
508         return 0;
509 }
510 #endif   /*SUPPORT_TARGET*/
511