source: trunk/wbsio_spi.c @ 1511

Revision 1511, 6.1 KB checked in by hailfinger, 3 months ago (diff)

Fix parallel-style programmer access from ITE IT87/Winbond W83627 SPI

The ITE IT87 SPI driver uses a trick to speed up reading and writing:
If a flash chip is 512 kByte or less, the flash chip can be completely
mapped in memory and both read and write accesses are faster that way.
The current IT87 SPI code did use the parallel programmer interface for
memory mapped reads and writes, but that's the wrong abstraction. It has
been fixed to use mmio_read*/mmio_write* for that purpose.

The Winbond W83627 SPI driver uses the same trick in its read path for
all supported chip sizes. Fix it the same way.

Switch internal_chip_readn to use mmio_readn as proper abstraction.

Kudos to Michael Karcher for spotting the bugs.

Reported-by: Johan Svensson <flashrom.js@…>
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>
Acked-by: Michael Karcher <flashrom@…>
Tested-by: Johan Svensson <flashrom.js@…>

Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2008 Peter Stuge <peter@stuge.se>
5 * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19 */
20
21#if defined(__i386__) || defined(__x86_64__)
22
23#include "flash.h"
24#include "chipdrivers.h"
25#include "programmer.h"
26#include "spi.h"
27
28#define WBSIO_PORT1     0x2e
29#define WBSIO_PORT2     0x4e
30
31static uint16_t wbsio_spibase = 0;
32
33static uint16_t wbsio_get_spibase(uint16_t port)
34{
35        uint8_t id;
36        uint16_t flashport = 0;
37
38        w836xx_ext_enter(port);
39        id = sio_read(port, 0x20);
40        if (id != 0xa0) {
41                msg_perr("\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id);
42                goto done;
43        }
44
45        if (0 == (sio_read(port, 0x24) & 2)) {
46                msg_perr("\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port);
47                goto done;
48        }
49
50        sio_write(port, 0x07, 0x06);
51        if (0 == (sio_read(port, 0x30) & 1)) {
52                msg_perr("\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port);
53                goto done;
54        }
55
56        flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63);
57
58done:
59        w836xx_ext_leave(port);
60        return flashport;
61}
62
63static int wbsio_spi_send_command(struct flashctx *flash, unsigned int writecnt,
64                                  unsigned int readcnt,
65                                  const unsigned char *writearr,
66                                  unsigned char *readarr);
67static int wbsio_spi_read(struct flashctx *flash, uint8_t *buf,
68                          unsigned int start, unsigned int len);
69
70static const struct spi_programmer spi_programmer_wbsio = {
71        .type = SPI_CONTROLLER_WBSIO,
72        .max_data_read = MAX_DATA_UNSPECIFIED,
73        .max_data_write = MAX_DATA_UNSPECIFIED,
74        .command = wbsio_spi_send_command,
75        .multicommand = default_spi_send_multicommand,
76        .read = wbsio_spi_read,
77        .write_256 = spi_chip_write_1,
78};
79
80int wbsio_check_for_spi(void)
81{
82        if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1)))
83                if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2)))
84                        return 1;
85
86        msg_pspew("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
87
88        msg_pdbg("%s: Winbond saved on 4 register bits so max chip size is "
89                 "1024 kB!\n", __func__);
90        max_rom_decode.spi = 1024 * 1024;
91        register_spi_programmer(&spi_programmer_wbsio);
92
93        return 0;
94}
95
96/* W83627DHG has 11 command modes:
97 * 1=1 command only
98 * 2=1 command+1 data write
99 * 3=1 command+2 data read
100 * 4=1 command+3 address
101 * 5=1 command+3 address+1 data write
102 * 6=1 command+3 address+4 data write
103 * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read
104 * 8=1 command+3 address+1 data read
105 * 9=1 command+3 address+2 data read
106 * a=1 command+3 address+3 data read
107 * b=1 command+3 address+4 data read
108 *
109 * mode[7:4] holds the command mode
110 * mode[3:0] holds SPI address bits [19:16]
111 *
112 * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\
113 * Would one more byte of RAM in the chip (to get all 24 bits) really make
114 * such a big difference?
115 */
116static int wbsio_spi_send_command(struct flashctx *flash, unsigned int writecnt,
117                                  unsigned int readcnt,
118                                  const unsigned char *writearr,
119                                  unsigned char *readarr)
120{
121        int i;
122        uint8_t mode = 0;
123
124        msg_pspew("%s:", __func__);
125
126        if (1 == writecnt && 0 == readcnt) {
127                mode = 0x10;
128        } else if (2 == writecnt && 0 == readcnt) {
129                OUTB(writearr[1], wbsio_spibase + 4);
130                msg_pspew(" data=0x%02x", writearr[1]);
131                mode = 0x20;
132        } else if (1 == writecnt && 2 == readcnt) {
133                mode = 0x30;
134        } else if (4 == writecnt && 0 == readcnt) {
135                msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
136                for (i = 2; i < writecnt; i++) {
137                        OUTB(writearr[i], wbsio_spibase + i);
138                        msg_pspew("%02x", writearr[i]);
139                }
140                mode = 0x40 | (writearr[1] & 0x0f);
141        } else if (5 == writecnt && 0 == readcnt) {
142                msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
143                for (i = 2; i < 4; i++) {
144                        OUTB(writearr[i], wbsio_spibase + i);
145                        msg_pspew("%02x", writearr[i]);
146                }
147                OUTB(writearr[i], wbsio_spibase + i);
148                msg_pspew(" data=0x%02x", writearr[i]);
149                mode = 0x50 | (writearr[1] & 0x0f);
150        } else if (8 == writecnt && 0 == readcnt) {
151                msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
152                for (i = 2; i < 4; i++) {
153                        OUTB(writearr[i], wbsio_spibase + i);
154                        msg_pspew("%02x", writearr[i]);
155                }
156                msg_pspew(" data=0x");
157                for (; i < writecnt; i++) {
158                        OUTB(writearr[i], wbsio_spibase + i);
159                        msg_pspew("%02x", writearr[i]);
160                }
161                mode = 0x60 | (writearr[1] & 0x0f);
162        } else if (5 == writecnt && 4 == readcnt) {
163                /* XXX: TODO not supported by flashrom infrastructure!
164                 * This mode, 7, discards the fifth byte in writecnt,
165                 * but since we can not express that in flashrom, fail
166                 * the operation for now.
167                 */
168                ;
169        } else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) {
170                msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
171                for (i = 2; i < writecnt; i++) {
172                        OUTB(writearr[i], wbsio_spibase + i);
173                        msg_pspew("%02x", writearr[i]);
174                }
175                mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f);
176        }
177        msg_pspew(" cmd=%02x mode=%02x\n", writearr[0], mode);
178
179        if (!mode) {
180                msg_perr("%s: unsupported command type wr=%d rd=%d\n",
181                        __func__, writecnt, readcnt);
182                /* Command type refers to the number of bytes read/written. */
183                return SPI_INVALID_LENGTH;
184        }
185
186        OUTB(writearr[0], wbsio_spibase);
187        OUTB(mode, wbsio_spibase + 1);
188        programmer_delay(10);
189
190        if (!readcnt)
191                return 0;
192
193        msg_pspew("%s: returning data =", __func__);
194        for (i = 0; i < readcnt; i++) {
195                readarr[i] = INB(wbsio_spibase + 4 + i);
196                msg_pspew(" 0x%02x", readarr[i]);
197        }
198        msg_pspew("\n");
199        return 0;
200}
201
202static int wbsio_spi_read(struct flashctx *flash, uint8_t *buf,
203                          unsigned int start, unsigned int len)
204{
205        mmio_readn((void *)(flash->virtual_memory + start), buf, len);
206        return 0;
207}
208
209#endif
Note: See TracBrowser for help on using the repository browser.