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