blob: f1072120da691152387485b3f6c65c6876cbdd06 [file] [log] [blame]
David Hendricks46d32e32011-01-19 16:01:52 -08001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2010 Google Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * Neither the name of Google or the names of contributors or
18 * licensors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * This software is provided "AS IS," without a warranty of any kind.
22 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
23 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
24 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
25 * GOOGLE INC AND ITS LICENSORS SHALL NOT BE LIABLE
26 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
27 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
28 * GOOGLE OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
29 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
30 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
31 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
32 * EVEN IF GOOGLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
33 */
34
David Hendrickscb2cec32011-03-24 18:44:49 -070035#if defined(__i386__) || defined(__x86_64__)
David Hendricks46d32e32011-01-19 16:01:52 -080036#include <inttypes.h>
37#include <string.h>
38#include <unistd.h>
39
40#include "flash.h"
41#include "chipdrivers.h"
42#include "programmer.h"
43#include "spi.h"
44
45#define MEC1308_SIO_PORT1 0x2e
46#define MEC1308_SIO_PORT2 0x4e
47#define MEC1308_SIO_ENTRY_KEY 0x55
48#define MEC1308_SIO_EXIT_KEY 0xaa
49
50#define MEC1308_SIOCFG_LDN 0x07 /* LDN Bank Selector */
51#define MEC1308_DEVICE_ID_REG 0x20 /* Device ID Register */
David Hendricksa7632f82011-09-06 13:56:02 -070052#define MEC1308_DEVICE_ID_VAL 0x4d /* Device ID Value for MEC1308 */
53#define MEC1310_DEVICE_ID_VAL 0x04 /* Device ID Value for MEC1310 */
David Hendricks46d32e32011-01-19 16:01:52 -080054#define MEC1308_DEVICE_REV 0x21 /* Device Revision ID Register */
55
56static unsigned int in_sio_cfgmode;
57
58#define MEC1308_MBX_CMD 0x82 /* mailbox command register offset */
59#define MEC1308_MBX_EXT_CMD 0x83 /* mailbox ext. command reg offset */
60#define MEC1308_MBX_DATA_START 0x84 /* first mailbox data register offset */
61#define MEC1308_MBX_DATA_END 0x91 /* last mailbox data register offset */
62
63static unsigned int mbx_idx; /* Mailbox register interface index address */
64static unsigned int mbx_data; /* Mailbox register interface data address*/
65
66/*
67 * These command codes depend on EC firmware. The ones listed below are input
68 * using the mailbox interface, though others may be input using the ACPI
69 * interface. Some commands also have an output value (ie pass/failure code)
70 * which EC writes to the mailbox command register after completion.
71 */
72#define MEC1308_CMD_SMI_ENABLE 0x84
73#define MEC1308_CMD_SMI_DISABLE 0x85
74#define MEC1308_CMD_ACPI_ENABLE 0x86
75#define MEC1308_CMD_ACPI_DISABLE 0x87
76
77/*
78 * Passthru commands are also input using the mailbox interface. Passthru mode
79 * enter/start/end commands are special since they require a command word to
80 * be written to the data registers. Other passthru commands are performed
81 * after passthru mode has been started.
82 *
83 * Multiple passthru mode commands may be issued before ending passthru mode.
84 * You do not need to enter, start, and end passthru mode for each SPI
85 * command. However, other mailbox commands might not work when passthru mode
86 * is enabled. For example, you may read all SPI chip content while in passthru
87 * mode, but you should exit passthru mode before performing other EC commands
88 * such as reading fan speed.
89 */
90#define MEC1308_CMD_PASSTHRU 0x55 /* force EC to process word */
91#define MEC1308_CMD_PASSTHRU_SUCCESS 0xaa /* success code for passthru */
92#define MEC1308_CMD_PASSTHRU_FAIL 0xfe /* failure code for passthru */
93#define MEC1308_CMD_PASSTHRU_ENTER "PathThruMode" /* not a typo... */
94#define MEC1308_CMD_PASSTHRU_START "Start"
95#define MEC1308_CMD_PASSTHRU_EXIT "End_Mode"
96#define MEC1308_CMD_PASSTHRU_CS_EN 0xf0 /* chip-select enable */
97#define MEC1308_CMD_PASSTHRU_CS_DIS 0xf1 /* chip-select disable */
98#define MEC1308_CMD_PASSTHRU_SEND 0xf2 /* send byte from data0 */
99#define MEC1308_CMD_PASSTHRU_READ 0xf3 /* read byte, place in data0 */
100
101static void mec1308_sio_enter(uint16_t port)
102{
103 if (in_sio_cfgmode)
104 return;
105
106 OUTB(MEC1308_SIO_ENTRY_KEY, port);
107 in_sio_cfgmode = 1;
108}
109
110static void mec1308_sio_exit(uint16_t port)
111{
112 if (!in_sio_cfgmode)
113 return;
114
115 OUTB(MEC1308_SIO_EXIT_KEY, port);
116 in_sio_cfgmode = 0;
117}
118
119/** probe for super i/o index
120 * @port: allocated buffer to store port
121 *
122 * returns 0 to indicate success, <0 to indicate error
123 */
124static int mec1308_get_sio_index(uint16_t *port)
125{
126 uint16_t ports[] = { MEC1308_SIO_PORT1,
127 MEC1308_SIO_PORT2,
128 };
129 int i;
130 static uint16_t port_internal, port_found = 0;
131
132 if (port_found) {
133 *port = port_internal;
134 return 0;
135 }
136
137 get_io_perms();
138
139 for (i = 0; i < ARRAY_SIZE(ports); i++) {
140 uint8_t tmp8;
141
David Hendricks46d32e32011-01-19 16:01:52 -0800142 /*
David Hendricks35a3e262011-11-17 18:50:49 -0800143 * Only after config mode has been successfully entered will the
144 * index port will read back the last value written to it.
145 * So we will attempt to enter config mode, set the index
146 * register, and see if the index register retains the value.
147 *
148 * Note: It seems to work "best" when using a device ID register
149 * as the index and reading from the data port before reading
150 * the index port.
David Hendricks46d32e32011-01-19 16:01:52 -0800151 */
David Hendricks35a3e262011-11-17 18:50:49 -0800152 mec1308_sio_enter(ports[i]);
153 OUTB(MEC1308_DEVICE_ID_REG, ports[i]);
David Hendricks46d32e32011-01-19 16:01:52 -0800154 tmp8 = INB(ports[i] + 1);
David Hendricks35a3e262011-11-17 18:50:49 -0800155 tmp8 = INB(ports[i]);
156 if ((tmp8 != MEC1308_DEVICE_ID_REG)) {
157 in_sio_cfgmode = 0;
David Hendricks46d32e32011-01-19 16:01:52 -0800158 continue;
David Hendricks35a3e262011-11-17 18:50:49 -0800159 }
David Hendricks46d32e32011-01-19 16:01:52 -0800160
161 port_internal = ports[i];
162 port_found = 1;
163 break;
164 }
165
166 if (!port_found) {
167 msg_cdbg("\nfailed to obtain super i/o index");
168 return -1;
169 }
170
171 msg_cdbg("\nsuper i/o index = 0x%04x\n", port_internal);
172 *port = port_internal;
173 return 0;
174}
175
176static uint8_t mbx_read(uint8_t idx)
177{
178 OUTB(idx, mbx_idx);
179 return INB(mbx_data);
180}
181
182static int mbx_wait(void)
183{
184 int i;
Louis Yung-Chieh Loa25e3302011-03-05 08:21:07 +0800185 int max_attempts = 10000;
David Hendricks46d32e32011-01-19 16:01:52 -0800186 int rc = 0;
187
188 for (i = 0; mbx_read(MEC1308_MBX_CMD); i++) {
189 if (i == max_attempts) {
190 rc = 1;
191 break;
192 }
193 /* FIXME: This delay adds determinism to the delay period. It
194 was chosen arbitrarily thru some experiments. */
195 programmer_delay(2);
196 }
197
198 return rc;
199}
200
201static int mbx_write(uint8_t idx, uint8_t data)
202{
203 int rc = 0;
204
David Hendricks5f0649c2011-05-16 16:54:19 -0700205 if (idx == MEC1308_MBX_CMD && mbx_wait()) {
206 msg_perr("%s: command register not clear\n", __func__);
207 return 1;
208 }
209
David Hendricks46d32e32011-01-19 16:01:52 -0800210 OUTB(idx, mbx_idx);
211 OUTB(data, mbx_data);
212
213 if (idx == MEC1308_MBX_CMD)
214 rc = mbx_wait();
215
216 return rc;
217}
218
219static void mbx_clear()
220{
221 int reg;
222
223 for (reg = MEC1308_MBX_DATA_START; reg < MEC1308_MBX_DATA_END; reg++)
224 mbx_write(reg, 0x00);
225 mbx_write(MEC1308_MBX_CMD, 0x00);
226}
227
David Hendricksce40a392011-02-17 13:43:03 -0800228static int mec1308_exit_passthru_mode(void)
229{
230 uint8_t tmp8;
231 int i;
232
233 /* exit passthru mode */
234 for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_EXIT); i++) {
235 mbx_write(MEC1308_MBX_DATA_START + i,
236 MEC1308_CMD_PASSTHRU_EXIT[i]);
237 }
238
239 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) {
240 msg_pdbg("%s(): exit passthru command timed out\n", __func__);
241 return 1;
242 }
243
244 tmp8 = mbx_read(MEC1308_MBX_DATA_START);
David Hendricks1ca53312011-03-04 19:15:38 -0800245 msg_pdbg("%s: result: 0x%02x ", __func__, tmp8);
246 if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS) {
247 msg_pdbg("(exited passthru mode)\n");
248 } else if (tmp8 == MEC1308_CMD_PASSTHRU_FAIL) {
249 msg_pdbg("(failed to exit passthru mode)\n");
David Hendricksce40a392011-02-17 13:43:03 -0800250 }
251
David Hendricksce40a392011-02-17 13:43:03 -0800252 return 0;
253}
254
David Hendricks46d32e32011-01-19 16:01:52 -0800255static int enter_passthru_mode(void)
256{
257 uint8_t tmp8;
258 int i;
259
260 /*
261 * Enter passthru mode. If the EC does not successfully enter passthru
David Hendricksce40a392011-02-17 13:43:03 -0800262 * mode the first time, we'll clear the mailbox and issue the "exit
263 * passthru mode" command sequence up to 3 times or until it arrives in
264 * a known state.
David Hendricks46d32e32011-01-19 16:01:52 -0800265 *
266 * Note: This workaround was developed experimentally.
267 */
268 for (i = 0; i < 3; i++) {
269 int j;
270
271 msg_pdbg("%s(): entering passthru mode, attempt %d out of 3\n",
272 __func__, i + 1);
273 for (j = 0; j < strlen(MEC1308_CMD_PASSTHRU_ENTER); j++) {
274 mbx_write(MEC1308_MBX_DATA_START + j,
275 MEC1308_CMD_PASSTHRU_ENTER[j]);
276 }
277
278 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU))
279 msg_pdbg("%s(): enter passthru command timed out\n",
280 __func__);
281
282 tmp8 = mbx_read(MEC1308_MBX_DATA_START);
283 if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS)
284 break;
285
286 msg_pdbg("%s(): command failed, clearing data registers and "
David Hendricksce40a392011-02-17 13:43:03 -0800287 "issuing full exit passthru command...\n", __func__);
David Hendricks46d32e32011-01-19 16:01:52 -0800288 mbx_clear();
David Hendricksce40a392011-02-17 13:43:03 -0800289 mec1308_exit_passthru_mode();
David Hendricks46d32e32011-01-19 16:01:52 -0800290 }
291
292 if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) {
293 msg_perr("%s(): failed to enter passthru mode, result=0x%02x\n",
294 __func__, tmp8);
295 return 1;
296 }
297
298 msg_pdbg("%s(): enter passthru mode return code: 0x%02x\n",
299 __func__, tmp8);
300
301 /* start passthru mode */
302 for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_START); i++)
303 mbx_write(MEC1308_MBX_DATA_START + i,
304 MEC1308_CMD_PASSTHRU_START[i]);
305 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) {
306 msg_pdbg("%s(): start passthru command timed out\n", __func__);
307 return 1;
308 }
309 tmp8 = mbx_read(MEC1308_MBX_DATA_START);
310 if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) {
311 msg_perr("%s(): failed to enter passthru mode, result=%02x\n",
312 __func__, tmp8);
313 return 1;
314 }
315 msg_pdbg("%s(): start passthru mode return code: 0x%02x\n",
316 __func__, tmp8);
317
318 return 0;
319}
320
David Hendricks93784b42016-08-09 17:00:38 -0700321static int mec1308_shutdown(void *data)
David Hendricks9f338cf2011-04-27 14:33:30 -0700322{
David Hendricks9f338cf2011-04-27 14:33:30 -0700323 /* Exit passthru mode before performing commands which do not affect
324 the SPI ROM */
325 mec1308_exit_passthru_mode();
326
327 /* Re-enable SMI and ACPI.
328 FIXME: is there an ordering dependency? */
David Hendricks5f0649c2011-05-16 16:54:19 -0700329 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_SMI_ENABLE))
330 msg_pdbg("%s: unable to re-enable SMI\n", __func__);
331 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_ACPI_ENABLE))
332 msg_pdbg("%s: unable to re-enable ACPI\n", __func__);
David Hendricks91040832011-07-08 20:01:09 -0700333
334 return 0;
David Hendricks9f338cf2011-04-27 14:33:30 -0700335}
336
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700337int mec1308_spi_read(struct flashctx *flash, uint8_t * buf, int start, int len)
David Hendricks2c7e61a2011-11-23 17:03:49 -0800338{
339 return spi_read_chunked(flash, buf, start, len, flash->page_size);
340}
341
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700342int mec1308_spi_write_256(struct flashctx *flash,
David Hendricks2c7e61a2011-11-23 17:03:49 -0800343 uint8_t *buf, int start, int len)
344{
345 return spi_write_chunked(flash, buf, start, len, flash->page_size);
346}
347
348static int mec1308_chip_select(void)
349{
350 return mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_EN);
351}
352
353static int mec1308_chip_deselect(void)
354{
355 return mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_DIS);
356}
357
358/*
359 * MEC1308 will not allow direct access to SPI chip from host if EC is
360 * connected to LPC bus. This function will forward commands issued thru
361 * mailbox interface to the SPI flash chip.
362 */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700363int mec1308_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
David Hendricks2c7e61a2011-11-23 17:03:49 -0800364 unsigned int readcnt,
365 const unsigned char *writearr,
366 unsigned char *readarr)
367{
368 int i, rc = 0;
369
370 if (mec1308_chip_select())
371 return 1;
372
373 for (i = 0; i < writecnt; i++) {
374 if (mbx_write(MEC1308_MBX_DATA_START, writearr[i]) ||
375 mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_SEND)) {
376 msg_pdbg("%s: failed to issue send command\n",__func__);
377 rc = 1;
378 goto mec1308_spi_send_command_exit;
379 }
380 }
381
382 for (i = 0; i < readcnt; i++) {
383 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_READ)) {
384 msg_pdbg("%s: failed to issue read command\n",__func__);
385 rc = 1;
386 goto mec1308_spi_send_command_exit;
387 }
388 readarr[i] = mbx_read(MEC1308_MBX_DATA_START);
389 }
390
391mec1308_spi_send_command_exit:
392 rc |= mec1308_chip_deselect();
393 return rc;
394}
395
David Hendricks91040832011-07-08 20:01:09 -0700396static const struct spi_programmer spi_programmer_mec1308 = {
397 .type = SPI_CONTROLLER_MEC1308,
398 .max_data_read = 256, /* FIXME: should be MAX_DATA_READ_UNLIMITED? */
399 .max_data_write = 256, /* FIXME: should be MAX_DATA_WRITE_UNLIMITED? */
400 .command = mec1308_spi_send_command,
401 .multicommand = default_spi_send_multicommand,
402 .read = default_spi_read,
403 .write_256 = default_spi_write_256,
404};
405
David Hendricks46d32e32011-01-19 16:01:52 -0800406/* Called by internal_init() */
Souvik Ghosh63b92f92016-06-29 18:45:52 -0700407int mec1308_probe_spi_flash(struct flashctx *flash, const char *name)
David Hendricks46d32e32011-01-19 16:01:52 -0800408{
409 uint16_t sio_port;
410 uint8_t device_id;
411 uint8_t tmp8;
412
413 msg_pdbg("%s(): entered\n", __func__);
414
David Hendricksba0827a2013-05-03 20:25:40 -0700415 if (alias && alias->type != ALIAS_EC)
416 return 1;
417
David Hendricks46d32e32011-01-19 16:01:52 -0800418 if (mec1308_get_sio_index(&sio_port) < 0) {
419 msg_pdbg("MEC1308 not found (probe failed).\n");
David Hendricks5e79c9f2013-11-04 22:05:08 -0800420 return 1;
David Hendricks46d32e32011-01-19 16:01:52 -0800421 }
422 device_id = sio_read(sio_port, MEC1308_DEVICE_ID_REG);
David Hendricksa7632f82011-09-06 13:56:02 -0700423 switch(device_id) {
424 case MEC1308_DEVICE_ID_VAL:
David Hendricks46d32e32011-01-19 16:01:52 -0800425 msg_pdbg("Found EC: MEC1308 (ID:0x%02x,Rev:0x%02x) on "
426 "sio_port:0x%x.\n", device_id,
427 sio_read(sio_port, MEC1308_DEVICE_REV), sio_port);
David Hendricksa7632f82011-09-06 13:56:02 -0700428 break;
429 case MEC1310_DEVICE_ID_VAL:
430 msg_pdbg("Found EC: MEC1310 (ID:0x%02x,Rev:0x%02x) on "
431 "sio_port:0x%x.\n", device_id,
432 sio_read(sio_port, MEC1308_DEVICE_REV), sio_port);
433 break;
434 default:
David Hendricks46d32e32011-01-19 16:01:52 -0800435 msg_pdbg("MEC1308 not found\n");
David Hendricks5e79c9f2013-11-04 22:05:08 -0800436 return 1;
David Hendricks46d32e32011-01-19 16:01:52 -0800437 }
438
439 /*
440 * setup mailbox interface at LDN 9
441 */
442 sio_write(sio_port, MEC1308_SIOCFG_LDN, 0x09);
443 tmp8 = sio_read(sio_port, 0x30);
444 tmp8 |= 1;
445 sio_write(sio_port, 0x30, tmp8); /* activate logical device */
446
Louis Yung-Chieh Loecc8f1d2012-03-13 19:23:28 +0800447 mbx_idx = (unsigned int)sio_read(sio_port, 0x60) << 8 |
448 sio_read(sio_port, 0x61);
David Hendricks46d32e32011-01-19 16:01:52 -0800449 mbx_data = mbx_idx + 1;
450 msg_pdbg("%s: mbx_idx: 0x%04x, mbx_data: 0x%04x\n",
451 __func__, mbx_idx, mbx_data);
452
453 /* Exit Super I/O config mode */
454 mec1308_sio_exit(sio_port);
455
David Hendricks945a8532011-03-04 20:32:20 -0800456 /* Now that we can read the mailbox, we will wait for any remaining
457 * command to finish.*/
458 if (mbx_wait() != 0) {
459 msg_perr("%s: mailbox is not available\n", __func__);
460 return 1;
461 }
462
David Hendricks46d32e32011-01-19 16:01:52 -0800463 /* Further setup -- disable SMI and ACPI.
464 FIXME: is there an ordering dependency? */
David Hendricks5f0649c2011-05-16 16:54:19 -0700465 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_ACPI_DISABLE)) {
466 msg_pdbg("%s: unable to disable ACPI\n", __func__);
467 return 1;
468 }
469
470 if (mbx_write(MEC1308_MBX_CMD, MEC1308_CMD_SMI_DISABLE)) {
471 msg_pdbg("%s: unable to disable SMI\n", __func__);
472 return 1;
473 }
David Hendricks46d32e32011-01-19 16:01:52 -0800474
David Hendricks9f338cf2011-04-27 14:33:30 -0700475 if (register_shutdown(mec1308_shutdown, NULL))
476 return 1;
477
David Hendricks1ca53312011-03-04 19:15:38 -0800478 /*
479 * Enter SPI Pass-Thru Mode after commands which do not require access
480 * to SPI ROM are complete. We'll start by doing the exit_passthru_mode
481 * sequence, which is benign if the EC is already in passthru mode.
482 */
483 mec1308_exit_passthru_mode();
David Hendricks9f338cf2011-04-27 14:33:30 -0700484
David Hendricks46d32e32011-01-19 16:01:52 -0800485 if (enter_passthru_mode())
486 return 1;
487
Souvik Ghosh63b92f92016-06-29 18:45:52 -0700488 flash->pgm->buses_supported |= BUS_LPC; /* for LPC <--> SPI bridging */
David Hendricks91040832011-07-08 20:01:09 -0700489 register_spi_programmer(&spi_programmer_mec1308);
David Hendricks46d32e32011-01-19 16:01:52 -0800490 msg_pdbg("%s(): successfully initialized mec1308\n", __func__);
491 return 0;
492}
David Hendrickscb2cec32011-03-24 18:44:49 -0700493#endif