blob: 6bb8d49e4ce00baaf581123d7eeaa5485ecc10d7 [file] [log] [blame]
Rong Changaaa1acf2012-06-21 19:21:18 +08001/*
2 * This file is part of the flashrom project.
3 *
Victor Ding1cc6d242020-09-25 20:30:42 +10004 * Copyright (C) 2012-2020, Google Inc.
5 * All rights reserved.
Rong Changaaa1acf2012-06-21 19:21:18 +08006 *
7 * Redistribution and use in source and binary forms, with or without
Victor Ding1cc6d242020-09-25 20:30:42 +10008 * modification, are permitted provided that the following conditions are
9 * met:
Rong Changaaa1acf2012-06-21 19:21:18 +080010 *
Victor Ding1cc6d242020-09-25 20:30:42 +100011 * * Redistributions of source code must retain the above copyright
Rong Changaaa1acf2012-06-21 19:21:18 +080012 * notice, this list of conditions and the following disclaimer.
Victor Ding1cc6d242020-09-25 20:30:42 +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.
Rong Changaaa1acf2012-06-21 19:21:18 +080020 *
Victor Ding1cc6d242020-09-25 20:30:42 +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.
Rong Changaaa1acf2012-06-21 19:21:18 +080032 *
Victor Ding1cc6d242020-09-25 20:30:42 +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.
Rong Changaaa1acf2012-06-21 19:21:18 +080036 */
37
38#if defined(__i386__) || defined(__x86_64__)
39#include <inttypes.h>
David Hendricks2b56e472016-10-21 19:05:21 -070040#include <stdlib.h>
Rong Changaaa1acf2012-06-21 19:21:18 +080041#include <string.h>
42#include <unistd.h>
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -070043#include <sys/time.h>
Rong Changaaa1acf2012-06-21 19:21:18 +080044
45#include "chipdrivers.h"
46#include "flash.h"
47#include "programmer.h"
Mayur Panchalf4796862019-08-05 15:46:12 +100048#include "hwaccess.h"
Rong Changaaa1acf2012-06-21 19:21:18 +080049#include "spi.h"
50
Victor Ding7a5b9252020-08-04 13:53:44 +100051/* MCU registers */
52#define REG_EC_HWVER 0xff00
53#define REG_EC_FWVER 0xff01
54#define REG_EC_EDIID 0xff24
55#define REG_8051_CTRL 0xff14
56#define REG_EC_EXTCMD 0xff10
57
58#define CPU_RESET 1
59
60/* MCU SPI peripheral registers */
61#define REG_SPI_DATA 0xfeab
62#define REG_SPI_COMMAND 0xfeac
63#define REG_SPI_CONFIG 0xfead
64
65#define CFG_CSn_FORCE_LOW (1 << 4)
66#define CFG_COMMAND_WRITE_ENABLE (1 << 3)
67#define CFG_STATUS (1 << 1)
68#define CFG_ENABLE_BUSY_STATUS_CHECK (1 << 0)
69
70/* Timeout */
71#define EC_COMMAND_TIMEOUT 4
72#define EC_RESTART_TIMEOUT 10
73#define ENE_SPI_DELAY_CYCLE 4
74#define EC_PAUSE_TIMEOUT 12
75#define EC_RESET_TRIES 3
76
77#define ENE_KB94X_PAUSE_WAKEUP_PORT 0x64
78
79#define MASK_INPUT_BUFFER_FULL 2
80#define MASK_OUTPUT_BUFFER_FULL 1
81
82const int port_ene_bank = 1;
83const int port_ene_offset = 2;
84const int port_ene_data = 3;
85
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070086/* Supported ENE ECs, ENE_LAST should always be LAST member */
87enum ene_chip_id {
88 ENE_KB932 = 0,
89 ENE_KB94X,
90 ENE_LAST
91};
92
Rong Changd8889e52012-07-27 21:42:25 +080093/* EC state */
94enum ene_ec_state {
95 EC_STATE_NORMAL,
96 EC_STATE_IDLE,
97 EC_STATE_RESET,
98 EC_STATE_UNKNOWN
99};
100
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700101/* chip-specific parameters */
102typedef struct {
103 enum ene_chip_id chip_id;
104 uint8_t hwver;
105 uint8_t ediid;
Rong Changd8889e52012-07-27 21:42:25 +0800106 uint32_t port_bios;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700107 uint32_t port_ec_command;
108 uint32_t port_ec_data;
109 uint8_t ec_reset_cmd;
110 uint8_t ec_reset_data;
111 uint8_t ec_restart_cmd;
112 uint8_t ec_restart_data;
Rong Changd8889e52012-07-27 21:42:25 +0800113 uint8_t ec_pause_cmd;
114 uint8_t ec_pause_data;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700115 uint16_t ec_status_buf;
116 uint8_t ec_is_stopping;
117 uint8_t ec_is_running;
Rong Changd8889e52012-07-27 21:42:25 +0800118 uint8_t ec_is_pausing;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700119 uint32_t port_io_base;
Victor Dingf5054472020-08-03 16:51:17 +1000120} ene_chip_t;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700121
Victor Ding70ba0162020-08-03 17:39:05 +1000122typedef struct
123{
124 /* pointer to table entry of identified chip */
125 ene_chip_t *chip;
126 /* current ec state */
127 enum ene_ec_state ec_state;
128 struct timeval pause_begin;
129} ene_lpc_data_t;
130
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700131/* table of supported chips + parameters */
Victor Dingf5054472020-08-03 16:51:17 +1000132static ene_chip_t ene_chips[] = {
Victor Ding7a5b9252020-08-04 13:53:44 +1000133 {
134 ENE_KB932, /* chip_id */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700135 0xa2, 0x02, /* hwver + ediid */
Rong Changd8889e52012-07-27 21:42:25 +0800136 0x66, /* port_bios */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700137 0x6c, 0x68, /* port_ec_{command,data} */
138 0x59, 0xf2, /* ec_reset_{cmd,data} */
139 0x59, 0xf9, /* ec_restart_{cmd,data} */
Rong Changd8889e52012-07-27 21:42:25 +0800140 0x59, 0xf1, /* ec_pause_{cmd,data} */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700141 0xf554, /* ec_status_buf */
142 0xa5, 0x00, /* ec_is_{stopping,running} masks */
Rong Changd8889e52012-07-27 21:42:25 +0800143 0x33, /* ec_is_pausing mask */
Victor Ding7a5b9252020-08-04 13:53:44 +1000144 0xfd60 /* port_io_base */
145 },
146 {
147 ENE_KB94X, /* chip_id */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700148 0xa3, 0x05, /* hwver + ediid */
Rong Changd8889e52012-07-27 21:42:25 +0800149 0x66, /* port_bios */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700150 0x66, 0x68, /* port_ec_{command,data} */
151 0x7d, 0x10, /* ec_reset_{cmd,data} */
152 0x7f, 0x10, /* ec_restart_{cmd,data} */
agnescheng433ff582012-09-26 12:33:35 +0800153 0x7e, 0x10, /* ec_pause_{cmd,data} */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700154 0xf710, /* ec_status_buf */
155 0x02, 0x00, /* ec_is_{stopping,running} masks */
Victor Ding7a5b9252020-08-04 13:53:44 +1000156 0x01, /* ec_is_pausing mask */
157 0x0380 /* port_io_base */
158 }
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700159};
160
Victor Dingf5054472020-08-03 16:51:17 +1000161static void ec_command(const ene_chip_t *chip, uint8_t cmd, uint8_t data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800162{
163 struct timeval begin, now;
164
165 /* Spin wait for EC input buffer empty */
166 gettimeofday(&begin, NULL);
Victor Dingf5054472020-08-03 16:51:17 +1000167 while (INB(chip->port_ec_command) & MASK_INPUT_BUFFER_FULL) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800168 gettimeofday(&now, NULL);
169 if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
170 msg_pdbg("%s: buf not empty\n", __func__);
171 return;
172 }
173 }
agnescheng433ff582012-09-26 12:33:35 +0800174
Rong Changaaa1acf2012-06-21 19:21:18 +0800175 /* Write command */
Victor Dingf5054472020-08-03 16:51:17 +1000176 OUTB(cmd, chip->port_ec_command);
Rong Changaaa1acf2012-06-21 19:21:18 +0800177
Victor Dingf5054472020-08-03 16:51:17 +1000178 if (chip->chip_id == ENE_KB932) {
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700179 /* Spin wait for EC input buffer empty */
180 gettimeofday(&begin, NULL);
Victor Dingf5054472020-08-03 16:51:17 +1000181 while (INB(chip->port_ec_command) &
David Hendricks835b3102015-11-05 20:33:00 -0800182 MASK_INPUT_BUFFER_FULL) {
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700183 gettimeofday(&now, NULL);
184 if ((now.tv_sec - begin.tv_sec) >=
185 EC_COMMAND_TIMEOUT) {
186 msg_pdbg("%s: buf not empty\n", __func__);
187 return;
188 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800189 }
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700190 /* Write data */
Victor Dingf5054472020-08-03 16:51:17 +1000191 OUTB(data, chip->port_ec_data);
Rong Changaaa1acf2012-06-21 19:21:18 +0800192 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800193}
194
Victor Dingf5054472020-08-03 16:51:17 +1000195static uint8_t ene_read(const ene_chip_t *chip, uint16_t addr)
Rong Changaaa1acf2012-06-21 19:21:18 +0800196{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700197 uint8_t bank;
198 uint8_t offset;
199 uint8_t data;
200 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800201
202 bank = addr >> 8;
203 offset = addr & 0xff;
Victor Dingf5054472020-08-03 16:51:17 +1000204 port_io_base = chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800205
206 OUTB(bank, port_io_base + port_ene_bank);
207 OUTB(offset, port_io_base + port_ene_offset);
208 data = INB(port_io_base + port_ene_data);
209
210 return data;
211}
212
Victor Dingf5054472020-08-03 16:51:17 +1000213static void ene_write(const ene_chip_t *chip, uint16_t addr, uint8_t data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800214{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700215 uint8_t bank;
216 uint8_t offset;
217 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800218
219 bank = addr >> 8;
220 offset = addr & 0xff;
Victor Dingf5054472020-08-03 16:51:17 +1000221 port_io_base = chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800222
223 OUTB(bank, port_io_base + port_ene_bank);
224 OUTB(offset, port_io_base + port_ene_offset);
225
226 OUTB(data, port_io_base + port_ene_data);
227}
228
229/**
230 * wait_cycles, wait for n LPC bus clock cycles
231 *
232 * @param n: number of LPC cycles to wait
233 * @return void
234 */
Victor Dingf5054472020-08-03 16:51:17 +1000235static void wait_cycles(const ene_chip_t *chip,int n)
Rong Changaaa1acf2012-06-21 19:21:18 +0800236{
237 while (n--)
Victor Dingf5054472020-08-03 16:51:17 +1000238 INB(chip->port_io_base + port_ene_bank);
Rong Changaaa1acf2012-06-21 19:21:18 +0800239}
240
Rong Changd8889e52012-07-27 21:42:25 +0800241static int is_spicmd_write(uint8_t cmd)
242{
243 switch (cmd) {
Rong Chang7797e4c2012-08-19 00:40:49 +0800244 case JEDEC_WREN:
245 /* Chip Write Enable */
246 case JEDEC_EWSR:
247 /* Write Status Enable */
Rong Changd8889e52012-07-27 21:42:25 +0800248 case JEDEC_CE_60:
249 /* Chip Erase 0x60 */
250 case JEDEC_CE_C7:
251 /* Chip Erase 0xc7 */
252 case JEDEC_BE_52:
253 /* Block Erase 0x52 */
254 case JEDEC_BE_D8:
255 /* Block Erase 0xd8 */
256 case JEDEC_BE_D7:
257 /* Block Erase 0xd7 */
258 case JEDEC_SE:
259 /* Sector Erase */
260 case JEDEC_BYTE_PROGRAM:
261 /* Write memory byte */
262 case JEDEC_AAI_WORD_PROGRAM:
263 /* Write AAI word */
264 return 1;
265 }
266 return 0;
267}
268
Victor Dingf5054472020-08-03 16:51:17 +1000269static void ene_spi_start(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800270{
271 int cfg;
272
Victor Dingf5054472020-08-03 16:51:17 +1000273 cfg = ene_read(chip, REG_SPI_CONFIG);
Rong Changaaa1acf2012-06-21 19:21:18 +0800274 cfg |= CFG_CSn_FORCE_LOW;
275 cfg |= CFG_COMMAND_WRITE_ENABLE;
Victor Dingf5054472020-08-03 16:51:17 +1000276 ene_write(chip, REG_SPI_CONFIG, cfg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800277
Victor Dingf5054472020-08-03 16:51:17 +1000278 wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
Rong Changaaa1acf2012-06-21 19:21:18 +0800279}
280
Victor Dingf5054472020-08-03 16:51:17 +1000281static void ene_spi_end(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800282{
283 int cfg;
284
Victor Dingf5054472020-08-03 16:51:17 +1000285 cfg = ene_read(chip, REG_SPI_CONFIG);
Rong Changaaa1acf2012-06-21 19:21:18 +0800286 cfg &= ~CFG_CSn_FORCE_LOW;
287 cfg |= CFG_COMMAND_WRITE_ENABLE;
Victor Dingf5054472020-08-03 16:51:17 +1000288 ene_write(chip, REG_SPI_CONFIG, cfg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800289
Victor Dingf5054472020-08-03 16:51:17 +1000290 wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
Rong Changaaa1acf2012-06-21 19:21:18 +0800291}
292
Victor Dingf5054472020-08-03 16:51:17 +1000293static int ene_spi_wait(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800294{
295 struct timeval begin, now;
296
297 gettimeofday(&begin, NULL);
Victor Dingf5054472020-08-03 16:51:17 +1000298 while(ene_read(chip, REG_SPI_CONFIG) & CFG_STATUS) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800299 gettimeofday(&now, NULL);
300 if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
301 msg_pdbg("%s: spi busy\n", __func__);
302 return 1;
303 }
304 }
305 return 0;
306}
307
Victor Ding70ba0162020-08-03 17:39:05 +1000308static int ene_pause_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800309{
310 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000311 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800312
Victor Ding70ba0162020-08-03 17:39:05 +1000313 if (!chip->ec_pause_cmd)
Rong Changd8889e52012-07-27 21:42:25 +0800314 return -1;
315
316 /* EC prepare pause */
Victor Ding70ba0162020-08-03 17:39:05 +1000317 ec_command(chip, chip->ec_pause_cmd, chip->ec_pause_data);
Rong Changd8889e52012-07-27 21:42:25 +0800318
319 gettimeofday(&begin, NULL);
320 /* Spin wait for EC ready */
Victor Ding70ba0162020-08-03 17:39:05 +1000321 while (ene_read(chip, chip->ec_status_buf) !=
322 chip->ec_is_pausing) {
Rong Changd8889e52012-07-27 21:42:25 +0800323 gettimeofday(&now, NULL);
324 if ((now.tv_sec - begin.tv_sec) >=
325 EC_COMMAND_TIMEOUT) {
326 msg_pdbg("%s: unable to pause ec\n", __func__);
327 return -1;
328 }
329 }
330
agnescheng433ff582012-09-26 12:33:35 +0800331
Victor Ding70ba0162020-08-03 17:39:05 +1000332 gettimeofday(&ctx_data->pause_begin, NULL);
333 ctx_data->ec_state = EC_STATE_IDLE;
Rong Changd8889e52012-07-27 21:42:25 +0800334 return 0;
335}
336
Victor Ding70ba0162020-08-03 17:39:05 +1000337static int ene_resume_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800338{
339 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000340 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800341
Victor Ding70ba0162020-08-03 17:39:05 +1000342 if (chip->chip_id == ENE_KB94X)
agnescheng433ff582012-09-26 12:33:35 +0800343 OUTB(0xff, ENE_KB94X_PAUSE_WAKEUP_PORT);
344 else
345 /* Trigger 8051 interrupt to resume */
Victor Ding70ba0162020-08-03 17:39:05 +1000346 ene_write(chip, REG_EC_EXTCMD, 0xff);
Rong Changd8889e52012-07-27 21:42:25 +0800347
348 gettimeofday(&begin, NULL);
Victor Ding70ba0162020-08-03 17:39:05 +1000349 while (ene_read(chip, chip->ec_status_buf) !=
350 chip->ec_is_running) {
Rong Changd8889e52012-07-27 21:42:25 +0800351 gettimeofday(&now, NULL);
352 if ((now.tv_sec - begin.tv_sec) >=
353 EC_COMMAND_TIMEOUT) {
354 msg_pdbg("%s: unable to resume ec\n", __func__);
355 return -1;
356 }
357 }
358
Victor Ding70ba0162020-08-03 17:39:05 +1000359 ctx_data->ec_state = EC_STATE_NORMAL;
Rong Changd8889e52012-07-27 21:42:25 +0800360 return 0;
361}
362
Victor Ding70ba0162020-08-03 17:39:05 +1000363static int ene_pause_timeout_check(ene_lpc_data_t *ctx_data)
agnescheng433ff582012-09-26 12:33:35 +0800364{
Victor Ding70ba0162020-08-03 17:39:05 +1000365 struct timeval pause_now;
agnescheng433ff582012-09-26 12:33:35 +0800366 gettimeofday(&pause_now, NULL);
Victor Ding70ba0162020-08-03 17:39:05 +1000367 if ((pause_now.tv_sec - ctx_data->pause_begin.tv_sec) >=
agnescheng433ff582012-09-26 12:33:35 +0800368 EC_PAUSE_TIMEOUT) {
Victor Ding70ba0162020-08-03 17:39:05 +1000369 if(ene_resume_ec(ctx_data) == 0)
370 ene_pause_ec(ctx_data);
agnescheng433ff582012-09-26 12:33:35 +0800371
372 }
373 return 0;
374}
375
Victor Ding70ba0162020-08-03 17:39:05 +1000376static int ene_reset_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800377{
378 uint8_t reg;
Rong Changd8889e52012-07-27 21:42:25 +0800379 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000380 const ene_chip_t *chip = ctx_data->chip;
381
Rong Changd8889e52012-07-27 21:42:25 +0800382 gettimeofday(&begin, NULL);
383
384 /* EC prepare reset */
Victor Ding70ba0162020-08-03 17:39:05 +1000385 ec_command(chip, chip->ec_reset_cmd, chip->ec_reset_data);
Rong Changd8889e52012-07-27 21:42:25 +0800386
387 /* Spin wait for EC ready */
Victor Ding70ba0162020-08-03 17:39:05 +1000388 while (ene_read(chip, chip->ec_status_buf) !=
389 chip->ec_is_stopping) {
Rong Changd8889e52012-07-27 21:42:25 +0800390 gettimeofday(&now, NULL);
391 if ((now.tv_sec - begin.tv_sec) >=
392 EC_COMMAND_TIMEOUT) {
393 msg_pdbg("%s: unable to reset ec\n", __func__);
394 return -1;
395 }
396 }
397
398 /* Wait 1 second */
399 sleep(1);
400
401 /* Reset 8051 */
Victor Ding70ba0162020-08-03 17:39:05 +1000402 reg = ene_read(chip, REG_8051_CTRL);
Rong Changd8889e52012-07-27 21:42:25 +0800403 reg |= CPU_RESET;
Victor Ding70ba0162020-08-03 17:39:05 +1000404 ene_write(chip, REG_8051_CTRL, reg);
Rong Changd8889e52012-07-27 21:42:25 +0800405
Victor Ding70ba0162020-08-03 17:39:05 +1000406 ctx_data->ec_state = EC_STATE_RESET;
Rong Changd8889e52012-07-27 21:42:25 +0800407 return 0;
408}
409
Victor Ding70ba0162020-08-03 17:39:05 +1000410static int ene_enter_flash_mode(ene_lpc_data_t *ctx_data)
agnescheng433ff582012-09-26 12:33:35 +0800411{
Victor Ding70ba0162020-08-03 17:39:05 +1000412 if (ene_pause_ec(ctx_data))
413 return ene_reset_ec(ctx_data);
agnescheng433ff582012-09-26 12:33:35 +0800414 return 0;
415}
416
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700417static int ene_spi_send_command(const struct flashctx *flash,
418 unsigned int writecnt,
Rong Changaaa1acf2012-06-21 19:21:18 +0800419 unsigned int readcnt,
420 const unsigned char *writearr,
421 unsigned char *readarr)
422{
Victor Dingae44d662020-08-13 21:18:43 +1000423 unsigned int i;
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700424 int tries = EC_RESET_TRIES;
Victor Ding70ba0162020-08-03 17:39:05 +1000425 ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)flash->mst->spi.data;
426 const ene_chip_t *chip = ctx_data->chip;
Rong Changaaa1acf2012-06-21 19:21:18 +0800427
Victor Ding70ba0162020-08-03 17:39:05 +1000428 if (ctx_data->ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) {
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700429 do {
430 /* Enter reset mode if we need to write/erase */
Victor Ding70ba0162020-08-03 17:39:05 +1000431 if (ene_resume_ec(ctx_data))
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700432 continue;
433
Victor Ding70ba0162020-08-03 17:39:05 +1000434 if (!ene_reset_ec(ctx_data))
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700435 break;
436 } while (--tries > 0);
437
438 if (!tries) {
Victor Ding70ba0162020-08-03 17:39:05 +1000439 msg_perr("%s: EC failed reset, skipping write\n", __func__);
440 ctx_data->ec_state = EC_STATE_IDLE;
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700441 return 1;
442 }
Rong Changd8889e52012-07-27 21:42:25 +0800443 }
Victor Ding70ba0162020-08-03 17:39:05 +1000444 else if(chip->chip_id == ENE_KB94X && ctx_data->ec_state == EC_STATE_IDLE)
445 ene_pause_timeout_check(ctx_data);
Rong Changd8889e52012-07-27 21:42:25 +0800446
Victor Ding70ba0162020-08-03 17:39:05 +1000447 ene_spi_start(chip);
Rong Changaaa1acf2012-06-21 19:21:18 +0800448
449 for (i = 0; i < writecnt; i++) {
Victor Ding70ba0162020-08-03 17:39:05 +1000450 ene_write(chip, REG_SPI_COMMAND, writearr[i]);
451 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800452 msg_pdbg("%s: write count %d\n", __func__, i);
453 return 1;
454 }
455 }
456
457 for (i = 0; i < readcnt; i++) {
458 /* Push data by clock the serial bus */
Victor Ding70ba0162020-08-03 17:39:05 +1000459 ene_write(chip, REG_SPI_COMMAND, 0);
460 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800461 msg_pdbg("%s: read count %d\n", __func__, i);
462 return 1;
463 }
Victor Ding70ba0162020-08-03 17:39:05 +1000464 readarr[i] = ene_read(chip, REG_SPI_DATA);
465 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800466 msg_pdbg("%s: read count %d\n", __func__, i);
467 return 1;
468 }
469 }
470
Victor Ding70ba0162020-08-03 17:39:05 +1000471 ene_spi_end(chip);
Rong Changaaa1acf2012-06-21 19:21:18 +0800472 return 0;
473}
474
David Hendricks93784b42016-08-09 17:00:38 -0700475static int ene_leave_flash_mode(void *data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800476{
Victor Ding70ba0162020-08-03 17:39:05 +1000477 ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)data;
478 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800479 int rv = 0;
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -0700480 uint8_t reg;
Rong Changaaa1acf2012-06-21 19:21:18 +0800481 struct timeval begin, now;
482
Victor Ding70ba0162020-08-03 17:39:05 +1000483 if (ctx_data->ec_state == EC_STATE_RESET) {
484 reg = ene_read(chip, REG_8051_CTRL);
Rong Changd8889e52012-07-27 21:42:25 +0800485 reg &= ~CPU_RESET;
Victor Ding70ba0162020-08-03 17:39:05 +1000486 ene_write(chip, REG_8051_CTRL, reg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800487
Rong Changd8889e52012-07-27 21:42:25 +0800488 gettimeofday(&begin, NULL);
489 /* EC restart */
Victor Ding70ba0162020-08-03 17:39:05 +1000490 while (ene_read(chip, chip->ec_status_buf) !=
491 chip->ec_is_running) {
Rong Changd8889e52012-07-27 21:42:25 +0800492 gettimeofday(&now, NULL);
493 if ((now.tv_sec - begin.tv_sec) >=
494 EC_RESTART_TIMEOUT) {
495 msg_pdbg("%s: ec restart busy\n", __func__);
496 rv = 1;
497 goto exit;
498 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800499 }
Rong Changd8889e52012-07-27 21:42:25 +0800500 msg_pdbg("%s: send ec restart\n", __func__);
Victor Ding70ba0162020-08-03 17:39:05 +1000501 ec_command(chip, chip->ec_restart_cmd,
502 chip->ec_restart_data);
Rong Changd8889e52012-07-27 21:42:25 +0800503
Victor Ding70ba0162020-08-03 17:39:05 +1000504 ctx_data->ec_state = EC_STATE_NORMAL;
Rong Changd8889e52012-07-27 21:42:25 +0800505 rv = 0;
506 goto exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800507 }
508
Victor Ding70ba0162020-08-03 17:39:05 +1000509 rv = ene_resume_ec(ctx_data);
Rong Changea1ec812012-07-21 11:41:32 +0800510
Rong Changd8889e52012-07-27 21:42:25 +0800511exit:
512 /*
513 * Trigger ec interrupt after pause/reset by sending 0x80
514 * to bios command port.
515 */
Victor Ding70ba0162020-08-03 17:39:05 +1000516 OUTB(0x80, chip->port_bios);
517 free(data);
Rong Changd8889e52012-07-27 21:42:25 +0800518 return rv;
Rong Changaaa1acf2012-06-21 19:21:18 +0800519}
520
Victor Ding70ba0162020-08-03 17:39:05 +1000521static struct spi_master spi_master_ene = {
Rong Changaaa1acf2012-06-21 19:21:18 +0800522 .max_data_read = 256,
523 .max_data_write = 256,
524 .command = ene_spi_send_command,
525 .multicommand = default_spi_send_multicommand,
526 .read = default_spi_read,
527 .write_256 = default_spi_write_256,
528};
529
Victor Ding7fd63dc2020-08-19 23:03:23 +1000530int ene_probe_spi_flash()
Rong Changaaa1acf2012-06-21 19:21:18 +0800531{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700532 uint8_t hwver, ediid, i;
David Hendricks2b56e472016-10-21 19:05:21 -0700533 int ret = 0;
534 char *p = NULL;
Victor Ding70ba0162020-08-03 17:39:05 +1000535 ene_lpc_data_t *ctx_data = NULL;
Rong Changaaa1acf2012-06-21 19:21:18 +0800536
David Hendricksba0827a2013-05-03 20:25:40 -0700537 if (alias && alias->type != ALIAS_EC)
538 return 1;
539
Rong Changaaa1acf2012-06-21 19:21:18 +0800540 msg_pdbg("%s\n", __func__);
Rong Changaaa1acf2012-06-21 19:21:18 +0800541
Victor Ding70ba0162020-08-03 17:39:05 +1000542 ctx_data = calloc(1, sizeof(ene_lpc_data_t));
543 if (!ctx_data) {
544 msg_perr("Unable to allocate space for extra context data.\n");
545 return 1;
546 }
547 ctx_data->ec_state = EC_STATE_NORMAL;
548
David Hendricks2b56e472016-10-21 19:05:21 -0700549 p = extract_programmer_param("type");
550 if (p && strcmp(p, "ec")) {
551 msg_pdbg("ene_lpc only supports \"ec\" type devices\n");
552 ret = 1;
553 goto ene_probe_spi_flash_exit;
554 }
555
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700556 for (i = 0; i < ENE_LAST; ++i) {
Victor Ding70ba0162020-08-03 17:39:05 +1000557 ctx_data->chip = &ene_chips[i];
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700558
Victor Ding70ba0162020-08-03 17:39:05 +1000559 hwver = ene_read(ctx_data->chip, REG_EC_HWVER);
560 ediid = ene_read(ctx_data->chip, REG_EC_EDIID);
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700561
562 if(hwver == ene_chips[i].hwver &&
563 ediid == ene_chips[i].ediid) {
564 break;
565 }
566 }
567
568 if (i == ENE_LAST) {
569 msg_pdbg("ENE EC not found (probe failed)\n");
David Hendricks2b56e472016-10-21 19:05:21 -0700570 ret = 1;
571 goto ene_probe_spi_flash_exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800572 }
573
574 /* TODO: probe the EC stop protocol
575 *
576 * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c
577 */
578
579
Victor Ding70ba0162020-08-03 17:39:05 +1000580 if (register_shutdown(ene_leave_flash_mode, ctx_data)) {
David Hendricks2b56e472016-10-21 19:05:21 -0700581 ret = 1;
582 goto ene_probe_spi_flash_exit;
583 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800584
Victor Ding70ba0162020-08-03 17:39:05 +1000585 ene_enter_flash_mode(ctx_data);
Rong Changaaa1acf2012-06-21 19:21:18 +0800586
David Hendricksac1d25c2016-08-09 17:00:58 -0700587 buses_supported |= BUS_LPC;
Victor Ding70ba0162020-08-03 17:39:05 +1000588 spi_master_ene.data = ctx_data;
Patrick Georgif4f1e2f2017-03-10 17:38:40 +0100589 register_spi_master(&spi_master_ene);
Rong Changaaa1acf2012-06-21 19:21:18 +0800590 msg_pdbg("%s: successfully initialized ene\n", __func__);
Victor Ding7a5b9252020-08-04 13:53:44 +1000591
David Hendricks2b56e472016-10-21 19:05:21 -0700592ene_probe_spi_flash_exit:
593 free(p);
Victor Ding70ba0162020-08-03 17:39:05 +1000594 if (ret)
595 free(ctx_data);
David Hendricks2b56e472016-10-21 19:05:21 -0700596 return ret;
Rong Changaaa1acf2012-06-21 19:21:18 +0800597}
598
599#endif /* __i386__ || __x86_64__ */