blob: 70d2a7963e586ab74fc7fecae5dca95ced67ca50 [file] [log] [blame]
David Hendricks46d32e32011-01-19 16:01:52 -08001/*
2 * This file is part of the flashrom project.
3 *
Victor Ding092176d2020-09-25 20:38:09 +10004 * Copyright (C) 2010-2020, Google Inc.
5 * All rights reserved.
David Hendricks46d32e32011-01-19 16:01:52 -08006 *
7 * Redistribution and use in source and binary forms, with or without
Victor Ding092176d2020-09-25 20:38:09 +10008 * modification, are permitted provided that the following conditions are
9 * met:
David Hendricks46d32e32011-01-19 16:01:52 -080010 *
Victor Ding092176d2020-09-25 20:38:09 +100011 * * Redistributions of source code must retain the above copyright
David Hendricks46d32e32011-01-19 16:01:52 -080012 * notice, this list of conditions and the following disclaimer.
Victor Ding092176d2020-09-25 20:38:09 +100013 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Google Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
David Hendricks46d32e32011-01-19 16:01:52 -080020 *
Victor Ding092176d2020-09-25 20:38:09 +100021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
David Hendricks46d32e32011-01-19 16:01:52 -080032 *
Victor Ding092176d2020-09-25 20:38:09 +100033 * Alternatively, this software may be distributed under the terms of the
34 * GNU General Public License ("GPL") version 2 as published by the Free
35 * Software Foundation.
David Hendricks46d32e32011-01-19 16:01:52 -080036 */
37
David Hendrickscb2cec32011-03-24 18:44:49 -070038#if defined(__i386__) || defined(__x86_64__)
David Hendricks46d32e32011-01-19 16:01:52 -080039#include <inttypes.h>
David Hendricks2b56e472016-10-21 19:05:21 -070040#include <stdlib.h>
David Hendricks46d32e32011-01-19 16:01:52 -080041#include <string.h>
42#include <unistd.h>
43
44#include "flash.h"
Mayur Panchalf4796862019-08-05 15:46:12 +100045#include "hwaccess.h"
David Hendricks46d32e32011-01-19 16:01:52 -080046#include "chipdrivers.h"
47#include "programmer.h"
48#include "spi.h"
49
50#define MEC1308_SIO_PORT1 0x2e
51#define MEC1308_SIO_PORT2 0x4e
52#define MEC1308_SIO_ENTRY_KEY 0x55
53#define MEC1308_SIO_EXIT_KEY 0xaa
54
55#define MEC1308_SIOCFG_LDN 0x07 /* LDN Bank Selector */
56#define MEC1308_DEVICE_ID_REG 0x20 /* Device ID Register */
David Hendricksa7632f82011-09-06 13:56:02 -070057#define MEC1308_DEVICE_ID_VAL 0x4d /* Device ID Value for MEC1308 */
58#define MEC1310_DEVICE_ID_VAL 0x04 /* Device ID Value for MEC1310 */
David Hendricks46d32e32011-01-19 16:01:52 -080059#define MEC1308_DEVICE_REV 0x21 /* Device Revision ID Register */
60
David Hendricks46d32e32011-01-19 16:01:52 -080061#define MEC1308_MBX_CMD 0x82 /* mailbox command register offset */
62#define MEC1308_MBX_EXT_CMD 0x83 /* mailbox ext. command reg offset */
63#define MEC1308_MBX_DATA_START 0x84 /* first mailbox data register offset */
64#define MEC1308_MBX_DATA_END 0x91 /* last mailbox data register offset */
65
David Hendricks46d32e32011-01-19 16:01:52 -080066static unsigned int mbx_data; /* Mailbox register interface data address*/
67
68/*
69 * These command codes depend on EC firmware. The ones listed below are input
70 * using the mailbox interface, though others may be input using the ACPI
71 * interface. Some commands also have an output value (ie pass/failure code)
72 * which EC writes to the mailbox command register after completion.
73 */
74#define MEC1308_CMD_SMI_ENABLE 0x84
75#define MEC1308_CMD_SMI_DISABLE 0x85
76#define MEC1308_CMD_ACPI_ENABLE 0x86
77#define MEC1308_CMD_ACPI_DISABLE 0x87
78
79/*
80 * Passthru commands are also input using the mailbox interface. Passthru mode
81 * enter/start/end commands are special since they require a command word to
82 * be written to the data registers. Other passthru commands are performed
83 * after passthru mode has been started.
84 *
85 * Multiple passthru mode commands may be issued before ending passthru mode.
86 * You do not need to enter, start, and end passthru mode for each SPI
87 * command. However, other mailbox commands might not work when passthru mode
88 * is enabled. For example, you may read all SPI chip content while in passthru
89 * mode, but you should exit passthru mode before performing other EC commands
90 * such as reading fan speed.
91 */
92#define MEC1308_CMD_PASSTHRU 0x55 /* force EC to process word */
93#define MEC1308_CMD_PASSTHRU_SUCCESS 0xaa /* success code for passthru */
94#define MEC1308_CMD_PASSTHRU_FAIL 0xfe /* failure code for passthru */
95#define MEC1308_CMD_PASSTHRU_ENTER "PathThruMode" /* not a typo... */
96#define MEC1308_CMD_PASSTHRU_START "Start"
97#define MEC1308_CMD_PASSTHRU_EXIT "End_Mode"
98#define MEC1308_CMD_PASSTHRU_CS_EN 0xf0 /* chip-select enable */
99#define MEC1308_CMD_PASSTHRU_CS_DIS 0xf1 /* chip-select disable */
100#define MEC1308_CMD_PASSTHRU_SEND 0xf2 /* send byte from data0 */
101#define MEC1308_CMD_PASSTHRU_READ 0xf3 /* read byte, place in data0 */
102
Victor Ding7e335dc2020-08-04 16:42:54 +1000103typedef struct
David Hendricks46d32e32011-01-19 16:01:52 -0800104{
Victor Ding7e335dc2020-08-04 16:42:54 +1000105 unsigned int in_sio_cfgmode;
106 unsigned int mbx_idx; /* Mailbox register interface index address */
107 unsigned int mbx_data; /* Mailbox register interface data address*/
108} mec1308_data_t;
109
110static void mec1308_sio_enter(mec1308_data_t *ctx_data, uint16_t port)
111{
112 if (ctx_data->in_sio_cfgmode)
David Hendricks46d32e32011-01-19 16:01:52 -0800113 return;
114
115 OUTB(MEC1308_SIO_ENTRY_KEY, port);
Victor Ding7e335dc2020-08-04 16:42:54 +1000116 ctx_data->in_sio_cfgmode = 1;
David Hendricks46d32e32011-01-19 16:01:52 -0800117}
118
Victor Ding7e335dc2020-08-04 16:42:54 +1000119static void mec1308_sio_exit(mec1308_data_t *ctx_data, uint16_t port)
David Hendricks46d32e32011-01-19 16:01:52 -0800120{
Victor Ding7e335dc2020-08-04 16:42:54 +1000121 if (!ctx_data->in_sio_cfgmode)
David Hendricks46d32e32011-01-19 16:01:52 -0800122 return;
123
124 OUTB(MEC1308_SIO_EXIT_KEY, port);
Victor Ding7e335dc2020-08-04 16:42:54 +1000125 ctx_data->in_sio_cfgmode = 0;
David Hendricks46d32e32011-01-19 16:01:52 -0800126}
127
128/** probe for super i/o index
129 * @port: allocated buffer to store port
130 *
131 * returns 0 to indicate success, <0 to indicate error
132 */
Victor Ding7e335dc2020-08-04 16:42:54 +1000133static int mec1308_get_sio_index(mec1308_data_t *ctx_data, uint16_t *port)
David Hendricks46d32e32011-01-19 16:01:52 -0800134{
135 uint16_t ports[] = { MEC1308_SIO_PORT1,
136 MEC1308_SIO_PORT2,
137 };
Victor Dingb3e9d212020-08-13 20:49:07 +1000138 size_t i;
David Hendricks46d32e32011-01-19 16:01:52 -0800139 static uint16_t port_internal, port_found = 0;
140
141 if (port_found) {
142 *port = port_internal;
143 return 0;
144 }
145
Patrick Georgi2a2d67f2017-03-09 10:15:39 +0100146 if (rget_io_perms())
147 return -1;
David Hendricks46d32e32011-01-19 16:01:52 -0800148
149 for (i = 0; i < ARRAY_SIZE(ports); i++) {
150 uint8_t tmp8;
151
David Hendricks46d32e32011-01-19 16:01:52 -0800152 /*
David Hendricks35a3e262011-11-17 18:50:49 -0800153 * Only after config mode has been successfully entered will the
154 * index port will read back the last value written to it.
155 * So we will attempt to enter config mode, set the index
156 * register, and see if the index register retains the value.
157 *
158 * Note: It seems to work "best" when using a device ID register
159 * as the index and reading from the data port before reading
160 * the index port.
David Hendricks46d32e32011-01-19 16:01:52 -0800161 */
Victor Ding7e335dc2020-08-04 16:42:54 +1000162 mec1308_sio_enter(ctx_data, ports[i]);
David Hendricks35a3e262011-11-17 18:50:49 -0800163 OUTB(MEC1308_DEVICE_ID_REG, ports[i]);
David Hendricks46d32e32011-01-19 16:01:52 -0800164 tmp8 = INB(ports[i] + 1);
David Hendricks35a3e262011-11-17 18:50:49 -0800165 tmp8 = INB(ports[i]);
166 if ((tmp8 != MEC1308_DEVICE_ID_REG)) {
Victor Ding7e335dc2020-08-04 16:42:54 +1000167 ctx_data->in_sio_cfgmode = 0;
David Hendricks46d32e32011-01-19 16:01:52 -0800168 continue;
David Hendricks35a3e262011-11-17 18:50:49 -0800169 }
David Hendricks46d32e32011-01-19 16:01:52 -0800170
171 port_internal = ports[i];
172 port_found = 1;
173 break;
174 }
175
176 if (!port_found) {
Edward O'Callaghan26fde5b2020-10-20 00:33:32 +1100177 msg_cdbg("\nfailed to obtain super i/o index\n");
David Hendricks46d32e32011-01-19 16:01:52 -0800178 return -1;
179 }
180
181 msg_cdbg("\nsuper i/o index = 0x%04x\n", port_internal);
182 *port = port_internal;
183 return 0;
184}
185
Victor Ding7e335dc2020-08-04 16:42:54 +1000186static uint8_t mbx_read(mec1308_data_t *ctx_data, uint8_t idx)
David Hendricks46d32e32011-01-19 16:01:52 -0800187{
Victor Ding7e335dc2020-08-04 16:42:54 +1000188 OUTB(idx, ctx_data->mbx_idx);
David Hendricks46d32e32011-01-19 16:01:52 -0800189 return INB(mbx_data);
190}
191
Victor Ding7e335dc2020-08-04 16:42:54 +1000192static int mbx_wait(mec1308_data_t *ctx_data)
David Hendricks46d32e32011-01-19 16:01:52 -0800193{
194 int i;
Louis Yung-Chieh Loa25e3302011-03-05 08:21:07 +0800195 int max_attempts = 10000;
David Hendricks46d32e32011-01-19 16:01:52 -0800196 int rc = 0;
197
Victor Ding7e335dc2020-08-04 16:42:54 +1000198 for (i = 0; mbx_read(ctx_data, MEC1308_MBX_CMD); i++) {
David Hendricks46d32e32011-01-19 16:01:52 -0800199 if (i == max_attempts) {
200 rc = 1;
201 break;
202 }
203 /* FIXME: This delay adds determinism to the delay period. It
204 was chosen arbitrarily thru some experiments. */
205 programmer_delay(2);
206 }
207
208 return rc;
209}
210
Victor Ding7e335dc2020-08-04 16:42:54 +1000211static int mbx_write(mec1308_data_t *ctx_data, uint8_t idx, uint8_t data)
David Hendricks46d32e32011-01-19 16:01:52 -0800212{
213 int rc = 0;
214
Victor Ding7e335dc2020-08-04 16:42:54 +1000215 if (idx == MEC1308_MBX_CMD && mbx_wait(ctx_data)) {
David Hendricks5f0649c2011-05-16 16:54:19 -0700216 msg_perr("%s: command register not clear\n", __func__);
217 return 1;
218 }
219
Victor Ding7e335dc2020-08-04 16:42:54 +1000220 OUTB(idx, ctx_data->mbx_idx);
David Hendricks46d32e32011-01-19 16:01:52 -0800221 OUTB(data, mbx_data);
222
223 if (idx == MEC1308_MBX_CMD)
Victor Ding7e335dc2020-08-04 16:42:54 +1000224 rc = mbx_wait(ctx_data);
David Hendricks46d32e32011-01-19 16:01:52 -0800225
226 return rc;
227}
228
Victor Ding7e335dc2020-08-04 16:42:54 +1000229static void mbx_clear(mec1308_data_t *ctx_data)
David Hendricks46d32e32011-01-19 16:01:52 -0800230{
231 int reg;
232
233 for (reg = MEC1308_MBX_DATA_START; reg < MEC1308_MBX_DATA_END; reg++)
Victor Ding7e335dc2020-08-04 16:42:54 +1000234 mbx_write(ctx_data, reg, 0x00);
235 mbx_write(ctx_data, MEC1308_MBX_CMD, 0x00);
David Hendricks46d32e32011-01-19 16:01:52 -0800236}
237
Victor Ding7e335dc2020-08-04 16:42:54 +1000238static int mec1308_exit_passthru_mode(mec1308_data_t *ctx_data)
David Hendricksce40a392011-02-17 13:43:03 -0800239{
240 uint8_t tmp8;
Victor Dingb3e9d212020-08-13 20:49:07 +1000241 size_t i;
David Hendricksce40a392011-02-17 13:43:03 -0800242
243 /* exit passthru mode */
244 for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_EXIT); i++) {
Victor Ding7e335dc2020-08-04 16:42:54 +1000245 mbx_write(ctx_data, MEC1308_MBX_DATA_START + i,
David Hendricksce40a392011-02-17 13:43:03 -0800246 MEC1308_CMD_PASSTHRU_EXIT[i]);
247 }
248
Victor Ding7e335dc2020-08-04 16:42:54 +1000249 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) {
David Hendricksce40a392011-02-17 13:43:03 -0800250 msg_pdbg("%s(): exit passthru command timed out\n", __func__);
251 return 1;
252 }
253
Victor Ding7e335dc2020-08-04 16:42:54 +1000254 tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
David Hendricks1ca53312011-03-04 19:15:38 -0800255 msg_pdbg("%s: result: 0x%02x ", __func__, tmp8);
256 if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS) {
257 msg_pdbg("(exited passthru mode)\n");
258 } else if (tmp8 == MEC1308_CMD_PASSTHRU_FAIL) {
259 msg_pdbg("(failed to exit passthru mode)\n");
David Hendricksce40a392011-02-17 13:43:03 -0800260 }
261
David Hendricksce40a392011-02-17 13:43:03 -0800262 return 0;
263}
264
Victor Ding7e335dc2020-08-04 16:42:54 +1000265static int enter_passthru_mode(mec1308_data_t *ctx_data)
David Hendricks46d32e32011-01-19 16:01:52 -0800266{
267 uint8_t tmp8;
Victor Dingb3e9d212020-08-13 20:49:07 +1000268 size_t i;
David Hendricks46d32e32011-01-19 16:01:52 -0800269
270 /*
271 * Enter passthru mode. If the EC does not successfully enter passthru
David Hendricksce40a392011-02-17 13:43:03 -0800272 * mode the first time, we'll clear the mailbox and issue the "exit
273 * passthru mode" command sequence up to 3 times or until it arrives in
274 * a known state.
David Hendricks46d32e32011-01-19 16:01:52 -0800275 *
276 * Note: This workaround was developed experimentally.
277 */
278 for (i = 0; i < 3; i++) {
Victor Dingb3e9d212020-08-13 20:49:07 +1000279 size_t j;
David Hendricks46d32e32011-01-19 16:01:52 -0800280
281 msg_pdbg("%s(): entering passthru mode, attempt %d out of 3\n",
Victor Dingb3e9d212020-08-13 20:49:07 +1000282 __func__, (int)(i + 1));
David Hendricks46d32e32011-01-19 16:01:52 -0800283 for (j = 0; j < strlen(MEC1308_CMD_PASSTHRU_ENTER); j++) {
Victor Ding7e335dc2020-08-04 16:42:54 +1000284 mbx_write(ctx_data, MEC1308_MBX_DATA_START + j,
David Hendricks46d32e32011-01-19 16:01:52 -0800285 MEC1308_CMD_PASSTHRU_ENTER[j]);
286 }
287
Victor Ding7e335dc2020-08-04 16:42:54 +1000288 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU))
David Hendricks46d32e32011-01-19 16:01:52 -0800289 msg_pdbg("%s(): enter passthru command timed out\n",
290 __func__);
291
Victor Ding7e335dc2020-08-04 16:42:54 +1000292 tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
David Hendricks46d32e32011-01-19 16:01:52 -0800293 if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS)
294 break;
295
296 msg_pdbg("%s(): command failed, clearing data registers and "
David Hendricksce40a392011-02-17 13:43:03 -0800297 "issuing full exit passthru command...\n", __func__);
Victor Ding7e335dc2020-08-04 16:42:54 +1000298 mbx_clear(ctx_data);
299 mec1308_exit_passthru_mode(ctx_data);
David Hendricks46d32e32011-01-19 16:01:52 -0800300 }
301
302 if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) {
303 msg_perr("%s(): failed to enter passthru mode, result=0x%02x\n",
304 __func__, tmp8);
305 return 1;
306 }
307
308 msg_pdbg("%s(): enter passthru mode return code: 0x%02x\n",
309 __func__, tmp8);
310
311 /* start passthru mode */
312 for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_START); i++)
Victor Ding7e335dc2020-08-04 16:42:54 +1000313 mbx_write(ctx_data, MEC1308_MBX_DATA_START + i,
David Hendricks46d32e32011-01-19 16:01:52 -0800314 MEC1308_CMD_PASSTHRU_START[i]);
Victor Ding7e335dc2020-08-04 16:42:54 +1000315 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) {
David Hendricks46d32e32011-01-19 16:01:52 -0800316 msg_pdbg("%s(): start passthru command timed out\n", __func__);
317 return 1;
318 }
Victor Ding7e335dc2020-08-04 16:42:54 +1000319 tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
David Hendricks46d32e32011-01-19 16:01:52 -0800320 if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) {
321 msg_perr("%s(): failed to enter passthru mode, result=%02x\n",
322 __func__, tmp8);
323 return 1;
324 }
325 msg_pdbg("%s(): start passthru mode return code: 0x%02x\n",
326 __func__, tmp8);
327
328 return 0;
329}
330
David Hendricks93784b42016-08-09 17:00:38 -0700331static int mec1308_shutdown(void *data)
David Hendricks9f338cf2011-04-27 14:33:30 -0700332{
Victor Ding7e335dc2020-08-04 16:42:54 +1000333 mec1308_data_t *ctx_data = (mec1308_data_t *)data;
334
David Hendricks9f338cf2011-04-27 14:33:30 -0700335 /* Exit passthru mode before performing commands which do not affect
336 the SPI ROM */
Victor Ding7e335dc2020-08-04 16:42:54 +1000337 mec1308_exit_passthru_mode(ctx_data);
David Hendricks9f338cf2011-04-27 14:33:30 -0700338
339 /* Re-enable SMI and ACPI.
340 FIXME: is there an ordering dependency? */
Victor Ding7e335dc2020-08-04 16:42:54 +1000341 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_SMI_ENABLE))
David Hendricks5f0649c2011-05-16 16:54:19 -0700342 msg_pdbg("%s: unable to re-enable SMI\n", __func__);
Victor Ding7e335dc2020-08-04 16:42:54 +1000343 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_ACPI_ENABLE))
David Hendricks5f0649c2011-05-16 16:54:19 -0700344 msg_pdbg("%s: unable to re-enable ACPI\n", __func__);
David Hendricks91040832011-07-08 20:01:09 -0700345
Victor Ding7e335dc2020-08-04 16:42:54 +1000346 free(data);
David Hendricks91040832011-07-08 20:01:09 -0700347 return 0;
David Hendricks9f338cf2011-04-27 14:33:30 -0700348}
349
Victor Ding7e335dc2020-08-04 16:42:54 +1000350static int mec1308_chip_select(mec1308_data_t *ctx_data)
David Hendricks2c7e61a2011-11-23 17:03:49 -0800351{
Victor Ding7e335dc2020-08-04 16:42:54 +1000352 return mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_EN);
David Hendricks2c7e61a2011-11-23 17:03:49 -0800353}
354
Victor Ding7e335dc2020-08-04 16:42:54 +1000355static int mec1308_chip_deselect(mec1308_data_t *ctx_data)
David Hendricks2c7e61a2011-11-23 17:03:49 -0800356{
Victor Ding7e335dc2020-08-04 16:42:54 +1000357 return mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_DIS);
David Hendricks2c7e61a2011-11-23 17:03:49 -0800358}
359
360/*
361 * MEC1308 will not allow direct access to SPI chip from host if EC is
362 * connected to LPC bus. This function will forward commands issued thru
363 * mailbox interface to the SPI flash chip.
364 */
Victor Ding00f8a8f2020-08-13 20:25:43 +1000365static int mec1308_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
366 unsigned int readcnt,
367 const unsigned char *writearr,
368 unsigned char *readarr)
David Hendricks2c7e61a2011-11-23 17:03:49 -0800369{
Victor Dingb3e9d212020-08-13 20:49:07 +1000370 int rc = 0;
371 size_t i;
Victor Ding7e335dc2020-08-04 16:42:54 +1000372 mec1308_data_t *ctx_data = (mec1308_data_t *)flash->mst->spi.data;
David Hendricks2c7e61a2011-11-23 17:03:49 -0800373
Victor Ding7e335dc2020-08-04 16:42:54 +1000374 if (mec1308_chip_select(ctx_data))
David Hendricks2c7e61a2011-11-23 17:03:49 -0800375 return 1;
376
377 for (i = 0; i < writecnt; i++) {
Victor Ding7e335dc2020-08-04 16:42:54 +1000378 if (mbx_write(ctx_data, MEC1308_MBX_DATA_START, writearr[i]) ||
379 mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_SEND)) {
David Hendricks2c7e61a2011-11-23 17:03:49 -0800380 msg_pdbg("%s: failed to issue send command\n",__func__);
381 rc = 1;
382 goto mec1308_spi_send_command_exit;
383 }
384 }
385
386 for (i = 0; i < readcnt; i++) {
Victor Ding7e335dc2020-08-04 16:42:54 +1000387 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_READ)) {
David Hendricks2c7e61a2011-11-23 17:03:49 -0800388 msg_pdbg("%s: failed to issue read command\n",__func__);
389 rc = 1;
390 goto mec1308_spi_send_command_exit;
391 }
Victor Ding7e335dc2020-08-04 16:42:54 +1000392 readarr[i] = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
David Hendricks2c7e61a2011-11-23 17:03:49 -0800393 }
394
395mec1308_spi_send_command_exit:
Victor Ding7e335dc2020-08-04 16:42:54 +1000396 rc |= mec1308_chip_deselect(ctx_data);
David Hendricks2c7e61a2011-11-23 17:03:49 -0800397 return rc;
398}
399
Victor Ding7e335dc2020-08-04 16:42:54 +1000400static struct spi_master spi_master_mec1308 = {
David Hendricks91040832011-07-08 20:01:09 -0700401 .max_data_read = 256, /* FIXME: should be MAX_DATA_READ_UNLIMITED? */
402 .max_data_write = 256, /* FIXME: should be MAX_DATA_WRITE_UNLIMITED? */
403 .command = mec1308_spi_send_command,
404 .multicommand = default_spi_send_multicommand,
405 .read = default_spi_read,
406 .write_256 = default_spi_write_256,
407};
408
Anastasia Klimchuk0a86f0c2021-04-21 15:19:24 +1000409static int check_params(void)
410{
411 int ret = 0;
Anastasia Klimchuka1dcf7f2021-04-28 12:05:38 +1000412 char *const p = extract_programmer_param("type");
Anastasia Klimchuk0a86f0c2021-04-21 15:19:24 +1000413 if (p && strcmp(p, "ec")) {
414 msg_pdbg("mec1308 only supports \"ec\" type devices\n");
415 ret = 1;
416 }
417
418 free(p);
419 return ret;
420}
421
Edward O'Callaghan26fde5b2020-10-20 00:33:32 +1100422int mec1308_init(void)
David Hendricks46d32e32011-01-19 16:01:52 -0800423{
424 uint16_t sio_port;
425 uint8_t device_id;
426 uint8_t tmp8;
Victor Ding7e335dc2020-08-04 16:42:54 +1000427 mec1308_data_t *ctx_data = NULL;
David Hendricks46d32e32011-01-19 16:01:52 -0800428
429 msg_pdbg("%s(): entered\n", __func__);
430
Victor Ding7e335dc2020-08-04 16:42:54 +1000431 ctx_data = calloc(1, sizeof(mec1308_data_t));
432 if (!ctx_data) {
433 msg_perr("Unable to allocate space for extra context data.\n");
434 return 1;
435 }
436
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000437 if (check_params())
438 goto init_err_exit;
David Hendricks2b56e472016-10-21 19:05:21 -0700439
Victor Ding7e335dc2020-08-04 16:42:54 +1000440 if (mec1308_get_sio_index(ctx_data, &sio_port) < 0) {
David Hendricks46d32e32011-01-19 16:01:52 -0800441 msg_pdbg("MEC1308 not found (probe failed).\n");
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000442 goto init_err_exit;
David Hendricks46d32e32011-01-19 16:01:52 -0800443 }
444 device_id = sio_read(sio_port, MEC1308_DEVICE_ID_REG);
David Hendricksa7632f82011-09-06 13:56:02 -0700445 switch(device_id) {
446 case MEC1308_DEVICE_ID_VAL:
David Hendricks46d32e32011-01-19 16:01:52 -0800447 msg_pdbg("Found EC: MEC1308 (ID:0x%02x,Rev:0x%02x) on "
448 "sio_port:0x%x.\n", device_id,
449 sio_read(sio_port, MEC1308_DEVICE_REV), sio_port);
David Hendricksa7632f82011-09-06 13:56:02 -0700450 break;
451 case MEC1310_DEVICE_ID_VAL:
452 msg_pdbg("Found EC: MEC1310 (ID:0x%02x,Rev:0x%02x) on "
453 "sio_port:0x%x.\n", device_id,
454 sio_read(sio_port, MEC1308_DEVICE_REV), sio_port);
455 break;
456 default:
David Hendricks46d32e32011-01-19 16:01:52 -0800457 msg_pdbg("MEC1308 not found\n");
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000458 goto init_err_exit;
David Hendricks46d32e32011-01-19 16:01:52 -0800459 }
460
461 /*
462 * setup mailbox interface at LDN 9
463 */
464 sio_write(sio_port, MEC1308_SIOCFG_LDN, 0x09);
465 tmp8 = sio_read(sio_port, 0x30);
466 tmp8 |= 1;
467 sio_write(sio_port, 0x30, tmp8); /* activate logical device */
468
Victor Ding7e335dc2020-08-04 16:42:54 +1000469 ctx_data->mbx_idx = (unsigned int)sio_read(sio_port, 0x60) << 8 |
470 sio_read(sio_port, 0x61);
471 mbx_data = ctx_data->mbx_idx + 1;
David Hendricks46d32e32011-01-19 16:01:52 -0800472 msg_pdbg("%s: mbx_idx: 0x%04x, mbx_data: 0x%04x\n",
Victor Ding7e335dc2020-08-04 16:42:54 +1000473 __func__, ctx_data->mbx_idx, mbx_data);
David Hendricks46d32e32011-01-19 16:01:52 -0800474
475 /* Exit Super I/O config mode */
Victor Ding7e335dc2020-08-04 16:42:54 +1000476 mec1308_sio_exit(ctx_data, sio_port);
David Hendricks46d32e32011-01-19 16:01:52 -0800477
David Hendricks945a8532011-03-04 20:32:20 -0800478 /* Now that we can read the mailbox, we will wait for any remaining
479 * command to finish.*/
Victor Ding7e335dc2020-08-04 16:42:54 +1000480 if (mbx_wait(ctx_data) != 0) {
David Hendricks945a8532011-03-04 20:32:20 -0800481 msg_perr("%s: mailbox is not available\n", __func__);
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000482 goto init_err_exit;
David Hendricks945a8532011-03-04 20:32:20 -0800483 }
484
David Hendricks46d32e32011-01-19 16:01:52 -0800485 /* Further setup -- disable SMI and ACPI.
486 FIXME: is there an ordering dependency? */
Victor Ding7e335dc2020-08-04 16:42:54 +1000487 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_ACPI_DISABLE)) {
David Hendricks5f0649c2011-05-16 16:54:19 -0700488 msg_pdbg("%s: unable to disable ACPI\n", __func__);
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000489 goto init_err_exit;
David Hendricks5f0649c2011-05-16 16:54:19 -0700490 }
491
Victor Ding7e335dc2020-08-04 16:42:54 +1000492 if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_SMI_DISABLE)) {
David Hendricks5f0649c2011-05-16 16:54:19 -0700493 msg_pdbg("%s: unable to disable SMI\n", __func__);
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000494 goto init_err_exit;
David Hendricks5f0649c2011-05-16 16:54:19 -0700495 }
David Hendricks46d32e32011-01-19 16:01:52 -0800496
David Hendricks1ca53312011-03-04 19:15:38 -0800497 /*
498 * Enter SPI Pass-Thru Mode after commands which do not require access
499 * to SPI ROM are complete. We'll start by doing the exit_passthru_mode
500 * sequence, which is benign if the EC is already in passthru mode.
501 */
Victor Ding7e335dc2020-08-04 16:42:54 +1000502 mec1308_exit_passthru_mode(ctx_data);
David Hendricks9f338cf2011-04-27 14:33:30 -0700503
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000504 if (enter_passthru_mode(ctx_data))
Anastasia Klimchukfe896bd2021-04-26 15:19:11 +1000505 goto init_err_cleanup_exit;
David Hendricks46d32e32011-01-19 16:01:52 -0800506
Edward O'Callaghanc66827e2020-10-09 12:22:04 +1100507 internal_buses_supported |= BUS_LPC; /* for LPC <--> SPI bridging */
Victor Ding7e335dc2020-08-04 16:42:54 +1000508 spi_master_mec1308.data = ctx_data;
Anastasia Klimchukfe896bd2021-04-26 15:19:11 +1000509
510 if (register_shutdown(mec1308_shutdown, ctx_data))
511 goto init_err_cleanup_exit;
Nico Huberf1eeda62021-05-11 17:38:14 +0200512 register_spi_master(&spi_master_mec1308, NULL);
David Hendricks46d32e32011-01-19 16:01:52 -0800513 msg_pdbg("%s(): successfully initialized mec1308\n", __func__);
Victor Ding7e335dc2020-08-04 16:42:54 +1000514
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000515 return 0;
516
Anastasia Klimchukfe896bd2021-04-26 15:19:11 +1000517init_err_cleanup_exit:
518 mec1308_shutdown(ctx_data);
519 return 1;
520
Anastasia Klimchuk53c86122021-04-26 15:10:34 +1000521init_err_exit:
522 free(ctx_data);
523 return 1;
David Hendricks46d32e32011-01-19 16:01:52 -0800524}
David Hendrickscb2cec32011-03-24 18:44:49 -0700525#endif