blob: 2da18de8d3c918205145c7f462497e048bfd1a90 [file] [log] [blame]
stugea564bcf2009-01-26 03:08:45 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2008 Peter Stuge <peter@stuge.se>
hailfinger1220e592010-01-07 03:32:17 +00005 * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
stugea564bcf2009-01-26 03:08:45 +00006 *
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.
stugea564bcf2009-01-26 03:08:45 +000015 */
16
hailfinger324a9cc2010-05-26 01:45:41 +000017#if defined(__i386__) || defined(__x86_64__)
18
stugea564bcf2009-01-26 03:08:45 +000019#include "flash.h"
snelson8913d082010-02-26 05:48:29 +000020#include "chipdrivers.h"
hailfinger428f6852010-07-27 22:41:39 +000021#include "programmer.h"
stugea564bcf2009-01-26 03:08:45 +000022#include "spi.h"
23
24#define WBSIO_PORT1 0x2e
25#define WBSIO_PORT2 0x4e
26
27static uint16_t wbsio_spibase = 0;
28
uwe5e931bc2009-04-15 10:52:49 +000029static uint16_t wbsio_get_spibase(uint16_t port)
30{
stugea564bcf2009-01-26 03:08:45 +000031 uint8_t id;
32 uint16_t flashport = 0;
33
34 w836xx_ext_enter(port);
hailfinger7bac0e52009-05-25 23:26:50 +000035 id = sio_read(port, 0x20);
uwe5e931bc2009-04-15 10:52:49 +000036 if (id != 0xa0) {
snelsoncf6a2852010-01-09 23:34:45 +000037 msg_perr("\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id);
stugea564bcf2009-01-26 03:08:45 +000038 goto done;
39 }
40
hailfinger7bac0e52009-05-25 23:26:50 +000041 if (0 == (sio_read(port, 0x24) & 2)) {
snelsoncf6a2852010-01-09 23:34:45 +000042 msg_perr("\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port);
stugea564bcf2009-01-26 03:08:45 +000043 goto done;
44 }
45
hailfinger7bac0e52009-05-25 23:26:50 +000046 sio_write(port, 0x07, 0x06);
47 if (0 == (sio_read(port, 0x30) & 1)) {
snelsoncf6a2852010-01-09 23:34:45 +000048 msg_perr("\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port);
stugea564bcf2009-01-26 03:08:45 +000049 goto done;
50 }
51
hailfinger7bac0e52009-05-25 23:26:50 +000052 flashport = (sio_read(port, 0x62) << 8) | sio_read(port, 0x63);
stugea564bcf2009-01-26 03:08:45 +000053
54done:
55 w836xx_ext_leave(port);
56 return flashport;
57}
58
Souvik Ghoshd75cd672016-06-17 14:21:39 -070059static int wbsio_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
mkarcherd264e9e2011-05-11 17:07:07 +000060 const unsigned char *writearr, unsigned char *readarr);
Souvik Ghoshd75cd672016-06-17 14:21:39 -070061static int wbsio_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
mkarcherd264e9e2011-05-11 17:07:07 +000062
Patrick Georgif4f1e2f2017-03-10 17:38:40 +010063static const struct spi_master spi_master_wbsio = {
mkarcherd264e9e2011-05-11 17:07:07 +000064 .type = SPI_CONTROLLER_WBSIO,
65 .max_data_read = MAX_DATA_UNSPECIFIED,
66 .max_data_write = MAX_DATA_UNSPECIFIED,
67 .command = wbsio_spi_send_command,
68 .multicommand = default_spi_send_multicommand,
69 .read = wbsio_spi_read,
70 .write_256 = spi_chip_write_1,
71};
72
uweeb26b6e2010-06-07 19:06:26 +000073int wbsio_check_for_spi(void)
uwe5e931bc2009-04-15 10:52:49 +000074{
stugea564bcf2009-01-26 03:08:45 +000075 if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT1)))
76 if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2)))
77 return 1;
78
snelsoncf6a2852010-01-09 23:34:45 +000079 msg_pspew("\nwbsio_spibase = 0x%x\n", wbsio_spibase);
hailfingera916b422009-06-01 02:08:58 +000080
hailfingerd91c81f2010-07-14 19:57:52 +000081 msg_pdbg("%s: Winbond saved on 4 register bits so max chip size is "
stefanct707f13b2011-05-19 02:58:17 +000082 "1024 kB!\n", __func__);
hailfingerd91c81f2010-07-14 19:57:52 +000083 max_rom_decode.spi = 1024 * 1024;
Patrick Georgif4f1e2f2017-03-10 17:38:40 +010084 register_spi_master(&spi_master_wbsio);
hailfingera916b422009-06-01 02:08:58 +000085
stugea564bcf2009-01-26 03:08:45 +000086 return 0;
87}
88
89/* W83627DHG has 11 command modes:
90 * 1=1 command only
91 * 2=1 command+1 data write
92 * 3=1 command+2 data read
93 * 4=1 command+3 address
94 * 5=1 command+3 address+1 data write
95 * 6=1 command+3 address+4 data write
96 * 7=1 command+3 address+1 dummy address inserted by wbsio+4 data read
97 * 8=1 command+3 address+1 data read
98 * 9=1 command+3 address+2 data read
99 * a=1 command+3 address+3 data read
100 * b=1 command+3 address+4 data read
101 *
102 * mode[7:4] holds the command mode
103 * mode[3:0] holds SPI address bits [19:16]
104 *
105 * The Winbond SPI master only supports 20 bit addresses on the SPI bus. :\
106 * Would one more byte of RAM in the chip (to get all 24 bits) really make
107 * such a big difference?
108 */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700109static int wbsio_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
uwe5e931bc2009-04-15 10:52:49 +0000110 const unsigned char *writearr, unsigned char *readarr)
111{
stugea564bcf2009-01-26 03:08:45 +0000112 int i;
113 uint8_t mode = 0;
114
snelsoncf6a2852010-01-09 23:34:45 +0000115 msg_pspew("%s:", __func__);
stugea564bcf2009-01-26 03:08:45 +0000116
117 if (1 == writecnt && 0 == readcnt) {
118 mode = 0x10;
119 } else if (2 == writecnt && 0 == readcnt) {
120 OUTB(writearr[1], wbsio_spibase + 4);
snelsoncf6a2852010-01-09 23:34:45 +0000121 msg_pspew(" data=0x%02x", writearr[1]);
stugea564bcf2009-01-26 03:08:45 +0000122 mode = 0x20;
123 } else if (1 == writecnt && 2 == readcnt) {
124 mode = 0x30;
125 } else if (4 == writecnt && 0 == readcnt) {
snelsoncf6a2852010-01-09 23:34:45 +0000126 msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
stugea564bcf2009-01-26 03:08:45 +0000127 for (i = 2; i < writecnt; i++) {
128 OUTB(writearr[i], wbsio_spibase + i);
snelsoncf6a2852010-01-09 23:34:45 +0000129 msg_pspew("%02x", writearr[i]);
stugea564bcf2009-01-26 03:08:45 +0000130 }
131 mode = 0x40 | (writearr[1] & 0x0f);
132 } else if (5 == writecnt && 0 == readcnt) {
snelsoncf6a2852010-01-09 23:34:45 +0000133 msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
stugea564bcf2009-01-26 03:08:45 +0000134 for (i = 2; i < 4; i++) {
135 OUTB(writearr[i], wbsio_spibase + i);
snelsoncf6a2852010-01-09 23:34:45 +0000136 msg_pspew("%02x", writearr[i]);
stugea564bcf2009-01-26 03:08:45 +0000137 }
138 OUTB(writearr[i], wbsio_spibase + i);
snelsoncf6a2852010-01-09 23:34:45 +0000139 msg_pspew(" data=0x%02x", writearr[i]);
stugea564bcf2009-01-26 03:08:45 +0000140 mode = 0x50 | (writearr[1] & 0x0f);
141 } else if (8 == writecnt && 0 == readcnt) {
snelsoncf6a2852010-01-09 23:34:45 +0000142 msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
stugea564bcf2009-01-26 03:08:45 +0000143 for (i = 2; i < 4; i++) {
144 OUTB(writearr[i], wbsio_spibase + i);
snelsoncf6a2852010-01-09 23:34:45 +0000145 msg_pspew("%02x", writearr[i]);
stugea564bcf2009-01-26 03:08:45 +0000146 }
snelsoncf6a2852010-01-09 23:34:45 +0000147 msg_pspew(" data=0x");
stugea564bcf2009-01-26 03:08:45 +0000148 for (; i < writecnt; i++) {
149 OUTB(writearr[i], wbsio_spibase + i);
snelsoncf6a2852010-01-09 23:34:45 +0000150 msg_pspew("%02x", writearr[i]);
stugea564bcf2009-01-26 03:08:45 +0000151 }
152 mode = 0x60 | (writearr[1] & 0x0f);
153 } else if (5 == writecnt && 4 == readcnt) {
154 /* XXX: TODO not supported by flashrom infrastructure!
155 * This mode, 7, discards the fifth byte in writecnt,
156 * but since we can not express that in flashrom, fail
157 * the operation for now.
158 */
159 ;
160 } else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) {
snelsoncf6a2852010-01-09 23:34:45 +0000161 msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f));
stugea564bcf2009-01-26 03:08:45 +0000162 for (i = 2; i < writecnt; i++) {
163 OUTB(writearr[i], wbsio_spibase + i);
snelsoncf6a2852010-01-09 23:34:45 +0000164 msg_pspew("%02x", writearr[i]);
stugea564bcf2009-01-26 03:08:45 +0000165 }
166 mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f);
167 }
snelsoncf6a2852010-01-09 23:34:45 +0000168 msg_pspew(" cmd=%02x mode=%02x\n", writearr[0], mode);
stugea564bcf2009-01-26 03:08:45 +0000169
170 if (!mode) {
snelsoncf6a2852010-01-09 23:34:45 +0000171 msg_perr("%s: unsupported command type wr=%d rd=%d\n",
stugea564bcf2009-01-26 03:08:45 +0000172 __func__, writecnt, readcnt);
hailfinger9c290a72009-07-14 10:26:56 +0000173 /* Command type refers to the number of bytes read/written. */
174 return SPI_INVALID_LENGTH;
stugea564bcf2009-01-26 03:08:45 +0000175 }
176
177 OUTB(writearr[0], wbsio_spibase);
178 OUTB(mode, wbsio_spibase + 1);
hailfingere5829f62009-06-05 17:48:08 +0000179 programmer_delay(10);
stugea564bcf2009-01-26 03:08:45 +0000180
181 if (!readcnt)
182 return 0;
183
snelsoncf6a2852010-01-09 23:34:45 +0000184 msg_pspew("%s: returning data =", __func__);
stugea564bcf2009-01-26 03:08:45 +0000185 for (i = 0; i < readcnt; i++) {
186 readarr[i] = INB(wbsio_spibase + 4 + i);
snelsoncf6a2852010-01-09 23:34:45 +0000187 msg_pspew(" 0x%02x", readarr[i]);
stugea564bcf2009-01-26 03:08:45 +0000188 }
snelsoncf6a2852010-01-09 23:34:45 +0000189 msg_pspew("\n");
stugea564bcf2009-01-26 03:08:45 +0000190 return 0;
191}
192
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700193static int wbsio_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
uwe5e931bc2009-04-15 10:52:49 +0000194{
hailfingere8b674c2009-08-10 02:29:21 +0000195 return read_memmapped(flash, buf, start, len);
stugea564bcf2009-01-26 03:08:45 +0000196}
197
hailfinger324a9cc2010-05-26 01:45:41 +0000198#endif