blob: bf2a1c12eeabee56a3a9b8576e4a72f578b3b49c [file] [log] [blame]
Rong Changaaa1acf2012-06-21 19:21:18 +08001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2012 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
35#if defined(__i386__) || defined(__x86_64__)
36#include <inttypes.h>
David Hendricks2b56e472016-10-21 19:05:21 -070037#include <stdlib.h>
Rong Changaaa1acf2012-06-21 19:21:18 +080038#include <string.h>
39#include <unistd.h>
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -070040#include <sys/time.h>
Rong Changaaa1acf2012-06-21 19:21:18 +080041
42#include "chipdrivers.h"
43#include "flash.h"
44#include "programmer.h"
Mayur Panchalf4796862019-08-05 15:46:12 +100045#include "hwaccess.h"
Rong Changaaa1acf2012-06-21 19:21:18 +080046#include "spi.h"
47
Victor Ding7a5b9252020-08-04 13:53:44 +100048/* MCU registers */
49#define REG_EC_HWVER 0xff00
50#define REG_EC_FWVER 0xff01
51#define REG_EC_EDIID 0xff24
52#define REG_8051_CTRL 0xff14
53#define REG_EC_EXTCMD 0xff10
54
55#define CPU_RESET 1
56
57/* MCU SPI peripheral registers */
58#define REG_SPI_DATA 0xfeab
59#define REG_SPI_COMMAND 0xfeac
60#define REG_SPI_CONFIG 0xfead
61
62#define CFG_CSn_FORCE_LOW (1 << 4)
63#define CFG_COMMAND_WRITE_ENABLE (1 << 3)
64#define CFG_STATUS (1 << 1)
65#define CFG_ENABLE_BUSY_STATUS_CHECK (1 << 0)
66
67/* Timeout */
68#define EC_COMMAND_TIMEOUT 4
69#define EC_RESTART_TIMEOUT 10
70#define ENE_SPI_DELAY_CYCLE 4
71#define EC_PAUSE_TIMEOUT 12
72#define EC_RESET_TRIES 3
73
74#define ENE_KB94X_PAUSE_WAKEUP_PORT 0x64
75
76#define MASK_INPUT_BUFFER_FULL 2
77#define MASK_OUTPUT_BUFFER_FULL 1
78
79const int port_ene_bank = 1;
80const int port_ene_offset = 2;
81const int port_ene_data = 3;
82
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070083/* Supported ENE ECs, ENE_LAST should always be LAST member */
84enum ene_chip_id {
85 ENE_KB932 = 0,
86 ENE_KB94X,
87 ENE_LAST
88};
89
Rong Changd8889e52012-07-27 21:42:25 +080090/* EC state */
91enum ene_ec_state {
92 EC_STATE_NORMAL,
93 EC_STATE_IDLE,
94 EC_STATE_RESET,
95 EC_STATE_UNKNOWN
96};
97
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070098/* chip-specific parameters */
99typedef struct {
100 enum ene_chip_id chip_id;
101 uint8_t hwver;
102 uint8_t ediid;
Rong Changd8889e52012-07-27 21:42:25 +0800103 uint32_t port_bios;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700104 uint32_t port_ec_command;
105 uint32_t port_ec_data;
106 uint8_t ec_reset_cmd;
107 uint8_t ec_reset_data;
108 uint8_t ec_restart_cmd;
109 uint8_t ec_restart_data;
Rong Changd8889e52012-07-27 21:42:25 +0800110 uint8_t ec_pause_cmd;
111 uint8_t ec_pause_data;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700112 uint16_t ec_status_buf;
113 uint8_t ec_is_stopping;
114 uint8_t ec_is_running;
Rong Changd8889e52012-07-27 21:42:25 +0800115 uint8_t ec_is_pausing;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700116 uint32_t port_io_base;
Victor Dingf5054472020-08-03 16:51:17 +1000117} ene_chip_t;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700118
Victor Ding70ba0162020-08-03 17:39:05 +1000119typedef struct
120{
121 /* pointer to table entry of identified chip */
122 ene_chip_t *chip;
123 /* current ec state */
124 enum ene_ec_state ec_state;
125 struct timeval pause_begin;
126} ene_lpc_data_t;
127
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700128/* table of supported chips + parameters */
Victor Dingf5054472020-08-03 16:51:17 +1000129static ene_chip_t ene_chips[] = {
Victor Ding7a5b9252020-08-04 13:53:44 +1000130 {
131 ENE_KB932, /* chip_id */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700132 0xa2, 0x02, /* hwver + ediid */
Rong Changd8889e52012-07-27 21:42:25 +0800133 0x66, /* port_bios */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700134 0x6c, 0x68, /* port_ec_{command,data} */
135 0x59, 0xf2, /* ec_reset_{cmd,data} */
136 0x59, 0xf9, /* ec_restart_{cmd,data} */
Rong Changd8889e52012-07-27 21:42:25 +0800137 0x59, 0xf1, /* ec_pause_{cmd,data} */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700138 0xf554, /* ec_status_buf */
139 0xa5, 0x00, /* ec_is_{stopping,running} masks */
Rong Changd8889e52012-07-27 21:42:25 +0800140 0x33, /* ec_is_pausing mask */
Victor Ding7a5b9252020-08-04 13:53:44 +1000141 0xfd60 /* port_io_base */
142 },
143 {
144 ENE_KB94X, /* chip_id */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700145 0xa3, 0x05, /* hwver + ediid */
Rong Changd8889e52012-07-27 21:42:25 +0800146 0x66, /* port_bios */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700147 0x66, 0x68, /* port_ec_{command,data} */
148 0x7d, 0x10, /* ec_reset_{cmd,data} */
149 0x7f, 0x10, /* ec_restart_{cmd,data} */
agnescheng433ff582012-09-26 12:33:35 +0800150 0x7e, 0x10, /* ec_pause_{cmd,data} */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700151 0xf710, /* ec_status_buf */
152 0x02, 0x00, /* ec_is_{stopping,running} masks */
Victor Ding7a5b9252020-08-04 13:53:44 +1000153 0x01, /* ec_is_pausing mask */
154 0x0380 /* port_io_base */
155 }
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700156};
157
Victor Dingf5054472020-08-03 16:51:17 +1000158static void ec_command(const ene_chip_t *chip, uint8_t cmd, uint8_t data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800159{
160 struct timeval begin, now;
161
162 /* Spin wait for EC input buffer empty */
163 gettimeofday(&begin, NULL);
Victor Dingf5054472020-08-03 16:51:17 +1000164 while (INB(chip->port_ec_command) & MASK_INPUT_BUFFER_FULL) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800165 gettimeofday(&now, NULL);
166 if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
167 msg_pdbg("%s: buf not empty\n", __func__);
168 return;
169 }
170 }
agnescheng433ff582012-09-26 12:33:35 +0800171
Rong Changaaa1acf2012-06-21 19:21:18 +0800172 /* Write command */
Victor Dingf5054472020-08-03 16:51:17 +1000173 OUTB(cmd, chip->port_ec_command);
Rong Changaaa1acf2012-06-21 19:21:18 +0800174
Victor Dingf5054472020-08-03 16:51:17 +1000175 if (chip->chip_id == ENE_KB932) {
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700176 /* Spin wait for EC input buffer empty */
177 gettimeofday(&begin, NULL);
Victor Dingf5054472020-08-03 16:51:17 +1000178 while (INB(chip->port_ec_command) &
David Hendricks835b3102015-11-05 20:33:00 -0800179 MASK_INPUT_BUFFER_FULL) {
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700180 gettimeofday(&now, NULL);
181 if ((now.tv_sec - begin.tv_sec) >=
182 EC_COMMAND_TIMEOUT) {
183 msg_pdbg("%s: buf not empty\n", __func__);
184 return;
185 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800186 }
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700187 /* Write data */
Victor Dingf5054472020-08-03 16:51:17 +1000188 OUTB(data, chip->port_ec_data);
Rong Changaaa1acf2012-06-21 19:21:18 +0800189 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800190}
191
Victor Dingf5054472020-08-03 16:51:17 +1000192static uint8_t ene_read(const ene_chip_t *chip, uint16_t addr)
Rong Changaaa1acf2012-06-21 19:21:18 +0800193{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700194 uint8_t bank;
195 uint8_t offset;
196 uint8_t data;
197 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800198
199 bank = addr >> 8;
200 offset = addr & 0xff;
Victor Dingf5054472020-08-03 16:51:17 +1000201 port_io_base = chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800202
203 OUTB(bank, port_io_base + port_ene_bank);
204 OUTB(offset, port_io_base + port_ene_offset);
205 data = INB(port_io_base + port_ene_data);
206
207 return data;
208}
209
Victor Dingf5054472020-08-03 16:51:17 +1000210static void ene_write(const ene_chip_t *chip, uint16_t addr, uint8_t data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800211{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700212 uint8_t bank;
213 uint8_t offset;
214 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800215
216 bank = addr >> 8;
217 offset = addr & 0xff;
Victor Dingf5054472020-08-03 16:51:17 +1000218 port_io_base = chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800219
220 OUTB(bank, port_io_base + port_ene_bank);
221 OUTB(offset, port_io_base + port_ene_offset);
222
223 OUTB(data, port_io_base + port_ene_data);
224}
225
226/**
227 * wait_cycles, wait for n LPC bus clock cycles
228 *
229 * @param n: number of LPC cycles to wait
230 * @return void
231 */
Victor Dingf5054472020-08-03 16:51:17 +1000232static void wait_cycles(const ene_chip_t *chip,int n)
Rong Changaaa1acf2012-06-21 19:21:18 +0800233{
234 while (n--)
Victor Dingf5054472020-08-03 16:51:17 +1000235 INB(chip->port_io_base + port_ene_bank);
Rong Changaaa1acf2012-06-21 19:21:18 +0800236}
237
Rong Changd8889e52012-07-27 21:42:25 +0800238static int is_spicmd_write(uint8_t cmd)
239{
240 switch (cmd) {
Rong Chang7797e4c2012-08-19 00:40:49 +0800241 case JEDEC_WREN:
242 /* Chip Write Enable */
243 case JEDEC_EWSR:
244 /* Write Status Enable */
Rong Changd8889e52012-07-27 21:42:25 +0800245 case JEDEC_CE_60:
246 /* Chip Erase 0x60 */
247 case JEDEC_CE_C7:
248 /* Chip Erase 0xc7 */
249 case JEDEC_BE_52:
250 /* Block Erase 0x52 */
251 case JEDEC_BE_D8:
252 /* Block Erase 0xd8 */
253 case JEDEC_BE_D7:
254 /* Block Erase 0xd7 */
255 case JEDEC_SE:
256 /* Sector Erase */
257 case JEDEC_BYTE_PROGRAM:
258 /* Write memory byte */
259 case JEDEC_AAI_WORD_PROGRAM:
260 /* Write AAI word */
261 return 1;
262 }
263 return 0;
264}
265
Victor Dingf5054472020-08-03 16:51:17 +1000266static void ene_spi_start(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800267{
268 int cfg;
269
Victor Dingf5054472020-08-03 16:51:17 +1000270 cfg = ene_read(chip, REG_SPI_CONFIG);
Rong Changaaa1acf2012-06-21 19:21:18 +0800271 cfg |= CFG_CSn_FORCE_LOW;
272 cfg |= CFG_COMMAND_WRITE_ENABLE;
Victor Dingf5054472020-08-03 16:51:17 +1000273 ene_write(chip, REG_SPI_CONFIG, cfg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800274
Victor Dingf5054472020-08-03 16:51:17 +1000275 wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
Rong Changaaa1acf2012-06-21 19:21:18 +0800276}
277
Victor Dingf5054472020-08-03 16:51:17 +1000278static void ene_spi_end(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800279{
280 int cfg;
281
Victor Dingf5054472020-08-03 16:51:17 +1000282 cfg = ene_read(chip, REG_SPI_CONFIG);
Rong Changaaa1acf2012-06-21 19:21:18 +0800283 cfg &= ~CFG_CSn_FORCE_LOW;
284 cfg |= CFG_COMMAND_WRITE_ENABLE;
Victor Dingf5054472020-08-03 16:51:17 +1000285 ene_write(chip, REG_SPI_CONFIG, cfg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800286
Victor Dingf5054472020-08-03 16:51:17 +1000287 wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
Rong Changaaa1acf2012-06-21 19:21:18 +0800288}
289
Victor Dingf5054472020-08-03 16:51:17 +1000290static int ene_spi_wait(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800291{
292 struct timeval begin, now;
293
294 gettimeofday(&begin, NULL);
Victor Dingf5054472020-08-03 16:51:17 +1000295 while(ene_read(chip, REG_SPI_CONFIG) & CFG_STATUS) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800296 gettimeofday(&now, NULL);
297 if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
298 msg_pdbg("%s: spi busy\n", __func__);
299 return 1;
300 }
301 }
302 return 0;
303}
304
Victor Ding70ba0162020-08-03 17:39:05 +1000305static int ene_pause_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800306{
307 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000308 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800309
Victor Ding70ba0162020-08-03 17:39:05 +1000310 if (!chip->ec_pause_cmd)
Rong Changd8889e52012-07-27 21:42:25 +0800311 return -1;
312
313 /* EC prepare pause */
Victor Ding70ba0162020-08-03 17:39:05 +1000314 ec_command(chip, chip->ec_pause_cmd, chip->ec_pause_data);
Rong Changd8889e52012-07-27 21:42:25 +0800315
316 gettimeofday(&begin, NULL);
317 /* Spin wait for EC ready */
Victor Ding70ba0162020-08-03 17:39:05 +1000318 while (ene_read(chip, chip->ec_status_buf) !=
319 chip->ec_is_pausing) {
Rong Changd8889e52012-07-27 21:42:25 +0800320 gettimeofday(&now, NULL);
321 if ((now.tv_sec - begin.tv_sec) >=
322 EC_COMMAND_TIMEOUT) {
323 msg_pdbg("%s: unable to pause ec\n", __func__);
324 return -1;
325 }
326 }
327
agnescheng433ff582012-09-26 12:33:35 +0800328
Victor Ding70ba0162020-08-03 17:39:05 +1000329 gettimeofday(&ctx_data->pause_begin, NULL);
330 ctx_data->ec_state = EC_STATE_IDLE;
Rong Changd8889e52012-07-27 21:42:25 +0800331 return 0;
332}
333
Victor Ding70ba0162020-08-03 17:39:05 +1000334static int ene_resume_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800335{
336 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000337 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800338
Victor Ding70ba0162020-08-03 17:39:05 +1000339 if (chip->chip_id == ENE_KB94X)
agnescheng433ff582012-09-26 12:33:35 +0800340 OUTB(0xff, ENE_KB94X_PAUSE_WAKEUP_PORT);
341 else
342 /* Trigger 8051 interrupt to resume */
Victor Ding70ba0162020-08-03 17:39:05 +1000343 ene_write(chip, REG_EC_EXTCMD, 0xff);
Rong Changd8889e52012-07-27 21:42:25 +0800344
345 gettimeofday(&begin, NULL);
Victor Ding70ba0162020-08-03 17:39:05 +1000346 while (ene_read(chip, chip->ec_status_buf) !=
347 chip->ec_is_running) {
Rong Changd8889e52012-07-27 21:42:25 +0800348 gettimeofday(&now, NULL);
349 if ((now.tv_sec - begin.tv_sec) >=
350 EC_COMMAND_TIMEOUT) {
351 msg_pdbg("%s: unable to resume ec\n", __func__);
352 return -1;
353 }
354 }
355
Victor Ding70ba0162020-08-03 17:39:05 +1000356 ctx_data->ec_state = EC_STATE_NORMAL;
Rong Changd8889e52012-07-27 21:42:25 +0800357 return 0;
358}
359
Victor Ding70ba0162020-08-03 17:39:05 +1000360static int ene_pause_timeout_check(ene_lpc_data_t *ctx_data)
agnescheng433ff582012-09-26 12:33:35 +0800361{
Victor Ding70ba0162020-08-03 17:39:05 +1000362 struct timeval pause_now;
agnescheng433ff582012-09-26 12:33:35 +0800363 gettimeofday(&pause_now, NULL);
Victor Ding70ba0162020-08-03 17:39:05 +1000364 if ((pause_now.tv_sec - ctx_data->pause_begin.tv_sec) >=
agnescheng433ff582012-09-26 12:33:35 +0800365 EC_PAUSE_TIMEOUT) {
Victor Ding70ba0162020-08-03 17:39:05 +1000366 if(ene_resume_ec(ctx_data) == 0)
367 ene_pause_ec(ctx_data);
agnescheng433ff582012-09-26 12:33:35 +0800368
369 }
370 return 0;
371}
372
Victor Ding70ba0162020-08-03 17:39:05 +1000373static int ene_reset_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800374{
375 uint8_t reg;
Rong Changd8889e52012-07-27 21:42:25 +0800376 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000377 const ene_chip_t *chip = ctx_data->chip;
378
Rong Changd8889e52012-07-27 21:42:25 +0800379 gettimeofday(&begin, NULL);
380
381 /* EC prepare reset */
Victor Ding70ba0162020-08-03 17:39:05 +1000382 ec_command(chip, chip->ec_reset_cmd, chip->ec_reset_data);
Rong Changd8889e52012-07-27 21:42:25 +0800383
384 /* Spin wait for EC ready */
Victor Ding70ba0162020-08-03 17:39:05 +1000385 while (ene_read(chip, chip->ec_status_buf) !=
386 chip->ec_is_stopping) {
Rong Changd8889e52012-07-27 21:42:25 +0800387 gettimeofday(&now, NULL);
388 if ((now.tv_sec - begin.tv_sec) >=
389 EC_COMMAND_TIMEOUT) {
390 msg_pdbg("%s: unable to reset ec\n", __func__);
391 return -1;
392 }
393 }
394
395 /* Wait 1 second */
396 sleep(1);
397
398 /* Reset 8051 */
Victor Ding70ba0162020-08-03 17:39:05 +1000399 reg = ene_read(chip, REG_8051_CTRL);
Rong Changd8889e52012-07-27 21:42:25 +0800400 reg |= CPU_RESET;
Victor Ding70ba0162020-08-03 17:39:05 +1000401 ene_write(chip, REG_8051_CTRL, reg);
Rong Changd8889e52012-07-27 21:42:25 +0800402
Victor Ding70ba0162020-08-03 17:39:05 +1000403 ctx_data->ec_state = EC_STATE_RESET;
Rong Changd8889e52012-07-27 21:42:25 +0800404 return 0;
405}
406
Victor Ding70ba0162020-08-03 17:39:05 +1000407static int ene_enter_flash_mode(ene_lpc_data_t *ctx_data)
agnescheng433ff582012-09-26 12:33:35 +0800408{
Victor Ding70ba0162020-08-03 17:39:05 +1000409 if (ene_pause_ec(ctx_data))
410 return ene_reset_ec(ctx_data);
agnescheng433ff582012-09-26 12:33:35 +0800411 return 0;
412}
413
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700414static int ene_spi_send_command(const struct flashctx *flash,
415 unsigned int writecnt,
Rong Changaaa1acf2012-06-21 19:21:18 +0800416 unsigned int readcnt,
417 const unsigned char *writearr,
418 unsigned char *readarr)
419{
Victor Dingae44d662020-08-13 21:18:43 +1000420 unsigned int i;
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700421 int tries = EC_RESET_TRIES;
Victor Ding70ba0162020-08-03 17:39:05 +1000422 ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)flash->mst->spi.data;
423 const ene_chip_t *chip = ctx_data->chip;
Rong Changaaa1acf2012-06-21 19:21:18 +0800424
Victor Ding70ba0162020-08-03 17:39:05 +1000425 if (ctx_data->ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) {
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700426 do {
427 /* Enter reset mode if we need to write/erase */
Victor Ding70ba0162020-08-03 17:39:05 +1000428 if (ene_resume_ec(ctx_data))
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700429 continue;
430
Victor Ding70ba0162020-08-03 17:39:05 +1000431 if (!ene_reset_ec(ctx_data))
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700432 break;
433 } while (--tries > 0);
434
435 if (!tries) {
Victor Ding70ba0162020-08-03 17:39:05 +1000436 msg_perr("%s: EC failed reset, skipping write\n", __func__);
437 ctx_data->ec_state = EC_STATE_IDLE;
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700438 return 1;
439 }
Rong Changd8889e52012-07-27 21:42:25 +0800440 }
Victor Ding70ba0162020-08-03 17:39:05 +1000441 else if(chip->chip_id == ENE_KB94X && ctx_data->ec_state == EC_STATE_IDLE)
442 ene_pause_timeout_check(ctx_data);
Rong Changd8889e52012-07-27 21:42:25 +0800443
Victor Ding70ba0162020-08-03 17:39:05 +1000444 ene_spi_start(chip);
Rong Changaaa1acf2012-06-21 19:21:18 +0800445
446 for (i = 0; i < writecnt; i++) {
Victor Ding70ba0162020-08-03 17:39:05 +1000447 ene_write(chip, REG_SPI_COMMAND, writearr[i]);
448 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800449 msg_pdbg("%s: write count %d\n", __func__, i);
450 return 1;
451 }
452 }
453
454 for (i = 0; i < readcnt; i++) {
455 /* Push data by clock the serial bus */
Victor Ding70ba0162020-08-03 17:39:05 +1000456 ene_write(chip, REG_SPI_COMMAND, 0);
457 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800458 msg_pdbg("%s: read count %d\n", __func__, i);
459 return 1;
460 }
Victor Ding70ba0162020-08-03 17:39:05 +1000461 readarr[i] = ene_read(chip, REG_SPI_DATA);
462 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800463 msg_pdbg("%s: read count %d\n", __func__, i);
464 return 1;
465 }
466 }
467
Victor Ding70ba0162020-08-03 17:39:05 +1000468 ene_spi_end(chip);
Rong Changaaa1acf2012-06-21 19:21:18 +0800469 return 0;
470}
471
David Hendricks93784b42016-08-09 17:00:38 -0700472static int ene_leave_flash_mode(void *data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800473{
Victor Ding70ba0162020-08-03 17:39:05 +1000474 ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)data;
475 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800476 int rv = 0;
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -0700477 uint8_t reg;
Rong Changaaa1acf2012-06-21 19:21:18 +0800478 struct timeval begin, now;
479
Victor Ding70ba0162020-08-03 17:39:05 +1000480 if (ctx_data->ec_state == EC_STATE_RESET) {
481 reg = ene_read(chip, REG_8051_CTRL);
Rong Changd8889e52012-07-27 21:42:25 +0800482 reg &= ~CPU_RESET;
Victor Ding70ba0162020-08-03 17:39:05 +1000483 ene_write(chip, REG_8051_CTRL, reg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800484
Rong Changd8889e52012-07-27 21:42:25 +0800485 gettimeofday(&begin, NULL);
486 /* EC restart */
Victor Ding70ba0162020-08-03 17:39:05 +1000487 while (ene_read(chip, chip->ec_status_buf) !=
488 chip->ec_is_running) {
Rong Changd8889e52012-07-27 21:42:25 +0800489 gettimeofday(&now, NULL);
490 if ((now.tv_sec - begin.tv_sec) >=
491 EC_RESTART_TIMEOUT) {
492 msg_pdbg("%s: ec restart busy\n", __func__);
493 rv = 1;
494 goto exit;
495 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800496 }
Rong Changd8889e52012-07-27 21:42:25 +0800497 msg_pdbg("%s: send ec restart\n", __func__);
Victor Ding70ba0162020-08-03 17:39:05 +1000498 ec_command(chip, chip->ec_restart_cmd,
499 chip->ec_restart_data);
Rong Changd8889e52012-07-27 21:42:25 +0800500
Victor Ding70ba0162020-08-03 17:39:05 +1000501 ctx_data->ec_state = EC_STATE_NORMAL;
Rong Changd8889e52012-07-27 21:42:25 +0800502 rv = 0;
503 goto exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800504 }
505
Victor Ding70ba0162020-08-03 17:39:05 +1000506 rv = ene_resume_ec(ctx_data);
Rong Changea1ec812012-07-21 11:41:32 +0800507
Rong Changd8889e52012-07-27 21:42:25 +0800508exit:
509 /*
510 * Trigger ec interrupt after pause/reset by sending 0x80
511 * to bios command port.
512 */
Victor Ding70ba0162020-08-03 17:39:05 +1000513 OUTB(0x80, chip->port_bios);
514 free(data);
Rong Changd8889e52012-07-27 21:42:25 +0800515 return rv;
Rong Changaaa1acf2012-06-21 19:21:18 +0800516}
517
Victor Ding70ba0162020-08-03 17:39:05 +1000518static struct spi_master spi_master_ene = {
Rong Changaaa1acf2012-06-21 19:21:18 +0800519 .max_data_read = 256,
520 .max_data_write = 256,
521 .command = ene_spi_send_command,
522 .multicommand = default_spi_send_multicommand,
523 .read = default_spi_read,
524 .write_256 = default_spi_write_256,
525};
526
David Hendricksac1d25c2016-08-09 17:00:58 -0700527int ene_probe_spi_flash(const char *name)
Rong Changaaa1acf2012-06-21 19:21:18 +0800528{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700529 uint8_t hwver, ediid, i;
David Hendricks2b56e472016-10-21 19:05:21 -0700530 int ret = 0;
531 char *p = NULL;
Victor Ding70ba0162020-08-03 17:39:05 +1000532 ene_lpc_data_t *ctx_data = NULL;
Rong Changaaa1acf2012-06-21 19:21:18 +0800533
David Hendricksba0827a2013-05-03 20:25:40 -0700534 if (alias && alias->type != ALIAS_EC)
535 return 1;
536
Rong Changaaa1acf2012-06-21 19:21:18 +0800537 msg_pdbg("%s\n", __func__);
Rong Changaaa1acf2012-06-21 19:21:18 +0800538
Victor Ding70ba0162020-08-03 17:39:05 +1000539 ctx_data = calloc(1, sizeof(ene_lpc_data_t));
540 if (!ctx_data) {
541 msg_perr("Unable to allocate space for extra context data.\n");
542 return 1;
543 }
544 ctx_data->ec_state = EC_STATE_NORMAL;
545
David Hendricks2b56e472016-10-21 19:05:21 -0700546 p = extract_programmer_param("type");
547 if (p && strcmp(p, "ec")) {
548 msg_pdbg("ene_lpc only supports \"ec\" type devices\n");
549 ret = 1;
550 goto ene_probe_spi_flash_exit;
551 }
552
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700553 for (i = 0; i < ENE_LAST; ++i) {
Victor Ding70ba0162020-08-03 17:39:05 +1000554 ctx_data->chip = &ene_chips[i];
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700555
Victor Ding70ba0162020-08-03 17:39:05 +1000556 hwver = ene_read(ctx_data->chip, REG_EC_HWVER);
557 ediid = ene_read(ctx_data->chip, REG_EC_EDIID);
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700558
559 if(hwver == ene_chips[i].hwver &&
560 ediid == ene_chips[i].ediid) {
561 break;
562 }
563 }
564
565 if (i == ENE_LAST) {
566 msg_pdbg("ENE EC not found (probe failed)\n");
David Hendricks2b56e472016-10-21 19:05:21 -0700567 ret = 1;
568 goto ene_probe_spi_flash_exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800569 }
570
571 /* TODO: probe the EC stop protocol
572 *
573 * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c
574 */
575
576
Victor Ding70ba0162020-08-03 17:39:05 +1000577 if (register_shutdown(ene_leave_flash_mode, ctx_data)) {
David Hendricks2b56e472016-10-21 19:05:21 -0700578 ret = 1;
579 goto ene_probe_spi_flash_exit;
580 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800581
Victor Ding70ba0162020-08-03 17:39:05 +1000582 ene_enter_flash_mode(ctx_data);
Rong Changaaa1acf2012-06-21 19:21:18 +0800583
David Hendricksac1d25c2016-08-09 17:00:58 -0700584 buses_supported |= BUS_LPC;
Victor Ding70ba0162020-08-03 17:39:05 +1000585 spi_master_ene.data = ctx_data;
Patrick Georgif4f1e2f2017-03-10 17:38:40 +0100586 register_spi_master(&spi_master_ene);
Rong Changaaa1acf2012-06-21 19:21:18 +0800587 msg_pdbg("%s: successfully initialized ene\n", __func__);
Victor Ding7a5b9252020-08-04 13:53:44 +1000588
David Hendricks2b56e472016-10-21 19:05:21 -0700589ene_probe_spi_flash_exit:
590 free(p);
Victor Ding70ba0162020-08-03 17:39:05 +1000591 if (ret)
592 free(ctx_data);
David Hendricks2b56e472016-10-21 19:05:21 -0700593 return ret;
Rong Changaaa1acf2012-06-21 19:21:18 +0800594}
595
596#endif /* __i386__ || __x86_64__ */