blob: 46f1783299e0392fdf06e0e6ed0be4b5a972f3a4 [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);
Angel Pons0c0ac672021-04-16 11:16:52 +0200169 if (now.tv_sec - begin.tv_sec >= EC_COMMAND_TIMEOUT) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800170 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);
Angel Pons0c0ac672021-04-16 11:16:52 +0200181 while (INB(chip->port_ec_command) & MASK_INPUT_BUFFER_FULL) {
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700182 gettimeofday(&now, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200183 if (now.tv_sec - begin.tv_sec >= EC_COMMAND_TIMEOUT) {
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700184 msg_pdbg("%s: buf not empty\n", __func__);
185 return;
186 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800187 }
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700188 /* Write data */
Victor Dingf5054472020-08-03 16:51:17 +1000189 OUTB(data, chip->port_ec_data);
Rong Changaaa1acf2012-06-21 19:21:18 +0800190 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800191}
192
Victor Dingf5054472020-08-03 16:51:17 +1000193static uint8_t ene_read(const ene_chip_t *chip, uint16_t addr)
Rong Changaaa1acf2012-06-21 19:21:18 +0800194{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700195 uint8_t bank;
196 uint8_t offset;
197 uint8_t data;
198 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800199
200 bank = addr >> 8;
201 offset = addr & 0xff;
Victor Dingf5054472020-08-03 16:51:17 +1000202 port_io_base = chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800203
204 OUTB(bank, port_io_base + port_ene_bank);
205 OUTB(offset, port_io_base + port_ene_offset);
206 data = INB(port_io_base + port_ene_data);
207
208 return data;
209}
210
Victor Dingf5054472020-08-03 16:51:17 +1000211static void ene_write(const ene_chip_t *chip, uint16_t addr, uint8_t data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800212{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700213 uint8_t bank;
214 uint8_t offset;
215 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800216
217 bank = addr >> 8;
218 offset = addr & 0xff;
Victor Dingf5054472020-08-03 16:51:17 +1000219 port_io_base = chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800220
221 OUTB(bank, port_io_base + port_ene_bank);
222 OUTB(offset, port_io_base + port_ene_offset);
223
224 OUTB(data, port_io_base + port_ene_data);
225}
226
227/**
228 * wait_cycles, wait for n LPC bus clock cycles
229 *
230 * @param n: number of LPC cycles to wait
231 * @return void
232 */
Victor Dingf5054472020-08-03 16:51:17 +1000233static void wait_cycles(const ene_chip_t *chip,int n)
Rong Changaaa1acf2012-06-21 19:21:18 +0800234{
235 while (n--)
Victor Dingf5054472020-08-03 16:51:17 +1000236 INB(chip->port_io_base + port_ene_bank);
Rong Changaaa1acf2012-06-21 19:21:18 +0800237}
238
Rong Changd8889e52012-07-27 21:42:25 +0800239static int is_spicmd_write(uint8_t cmd)
240{
241 switch (cmd) {
Rong Chang7797e4c2012-08-19 00:40:49 +0800242 case JEDEC_WREN:
243 /* Chip Write Enable */
244 case JEDEC_EWSR:
245 /* Write Status Enable */
Rong Changd8889e52012-07-27 21:42:25 +0800246 case JEDEC_CE_60:
247 /* Chip Erase 0x60 */
248 case JEDEC_CE_C7:
249 /* Chip Erase 0xc7 */
250 case JEDEC_BE_52:
251 /* Block Erase 0x52 */
252 case JEDEC_BE_D8:
253 /* Block Erase 0xd8 */
254 case JEDEC_BE_D7:
255 /* Block Erase 0xd7 */
256 case JEDEC_SE:
257 /* Sector Erase */
258 case JEDEC_BYTE_PROGRAM:
259 /* Write memory byte */
260 case JEDEC_AAI_WORD_PROGRAM:
261 /* Write AAI word */
262 return 1;
263 }
264 return 0;
265}
266
Victor Dingf5054472020-08-03 16:51:17 +1000267static void ene_spi_start(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800268{
269 int cfg;
270
Victor Dingf5054472020-08-03 16:51:17 +1000271 cfg = ene_read(chip, REG_SPI_CONFIG);
Rong Changaaa1acf2012-06-21 19:21:18 +0800272 cfg |= CFG_CSn_FORCE_LOW;
273 cfg |= CFG_COMMAND_WRITE_ENABLE;
Victor Dingf5054472020-08-03 16:51:17 +1000274 ene_write(chip, REG_SPI_CONFIG, cfg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800275
Victor Dingf5054472020-08-03 16:51:17 +1000276 wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
Rong Changaaa1acf2012-06-21 19:21:18 +0800277}
278
Victor Dingf5054472020-08-03 16:51:17 +1000279static void ene_spi_end(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800280{
281 int cfg;
282
Victor Dingf5054472020-08-03 16:51:17 +1000283 cfg = ene_read(chip, REG_SPI_CONFIG);
Rong Changaaa1acf2012-06-21 19:21:18 +0800284 cfg &= ~CFG_CSn_FORCE_LOW;
285 cfg |= CFG_COMMAND_WRITE_ENABLE;
Victor Dingf5054472020-08-03 16:51:17 +1000286 ene_write(chip, REG_SPI_CONFIG, cfg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800287
Victor Dingf5054472020-08-03 16:51:17 +1000288 wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
Rong Changaaa1acf2012-06-21 19:21:18 +0800289}
290
Victor Dingf5054472020-08-03 16:51:17 +1000291static int ene_spi_wait(const ene_chip_t *chip)
Rong Changaaa1acf2012-06-21 19:21:18 +0800292{
293 struct timeval begin, now;
294
295 gettimeofday(&begin, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200296 while (ene_read(chip, REG_SPI_CONFIG) & CFG_STATUS) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800297 gettimeofday(&now, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200298 if (now.tv_sec - begin.tv_sec >= EC_COMMAND_TIMEOUT) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800299 msg_pdbg("%s: spi busy\n", __func__);
300 return 1;
301 }
302 }
303 return 0;
304}
305
Victor Ding70ba0162020-08-03 17:39:05 +1000306static int ene_pause_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800307{
308 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000309 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800310
Victor Ding70ba0162020-08-03 17:39:05 +1000311 if (!chip->ec_pause_cmd)
Rong Changd8889e52012-07-27 21:42:25 +0800312 return -1;
313
314 /* EC prepare pause */
Victor Ding70ba0162020-08-03 17:39:05 +1000315 ec_command(chip, chip->ec_pause_cmd, chip->ec_pause_data);
Rong Changd8889e52012-07-27 21:42:25 +0800316
317 gettimeofday(&begin, NULL);
318 /* Spin wait for EC ready */
Angel Pons0c0ac672021-04-16 11:16:52 +0200319 while (ene_read(chip, chip->ec_status_buf) != chip->ec_is_pausing) {
Rong Changd8889e52012-07-27 21:42:25 +0800320 gettimeofday(&now, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200321 if (now.tv_sec - begin.tv_sec >= EC_COMMAND_TIMEOUT) {
Rong Changd8889e52012-07-27 21:42:25 +0800322 msg_pdbg("%s: unable to pause ec\n", __func__);
323 return -1;
324 }
325 }
326
Victor Ding70ba0162020-08-03 17:39:05 +1000327 gettimeofday(&ctx_data->pause_begin, NULL);
328 ctx_data->ec_state = EC_STATE_IDLE;
Rong Changd8889e52012-07-27 21:42:25 +0800329 return 0;
330}
331
Victor Ding70ba0162020-08-03 17:39:05 +1000332static int ene_resume_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800333{
334 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000335 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800336
Victor Ding70ba0162020-08-03 17:39:05 +1000337 if (chip->chip_id == ENE_KB94X)
agnescheng433ff582012-09-26 12:33:35 +0800338 OUTB(0xff, ENE_KB94X_PAUSE_WAKEUP_PORT);
339 else
340 /* Trigger 8051 interrupt to resume */
Victor Ding70ba0162020-08-03 17:39:05 +1000341 ene_write(chip, REG_EC_EXTCMD, 0xff);
Rong Changd8889e52012-07-27 21:42:25 +0800342
343 gettimeofday(&begin, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200344 while (ene_read(chip, chip->ec_status_buf) != chip->ec_is_running) {
Rong Changd8889e52012-07-27 21:42:25 +0800345 gettimeofday(&now, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200346 if (now.tv_sec - begin.tv_sec >= EC_COMMAND_TIMEOUT) {
Rong Changd8889e52012-07-27 21:42:25 +0800347 msg_pdbg("%s: unable to resume ec\n", __func__);
348 return -1;
349 }
350 }
351
Victor Ding70ba0162020-08-03 17:39:05 +1000352 ctx_data->ec_state = EC_STATE_NORMAL;
Rong Changd8889e52012-07-27 21:42:25 +0800353 return 0;
354}
355
Victor Ding70ba0162020-08-03 17:39:05 +1000356static int ene_pause_timeout_check(ene_lpc_data_t *ctx_data)
agnescheng433ff582012-09-26 12:33:35 +0800357{
Victor Ding70ba0162020-08-03 17:39:05 +1000358 struct timeval pause_now;
agnescheng433ff582012-09-26 12:33:35 +0800359 gettimeofday(&pause_now, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200360 if (pause_now.tv_sec - ctx_data->pause_begin.tv_sec >= EC_PAUSE_TIMEOUT) {
361 if (ene_resume_ec(ctx_data) == 0)
Victor Ding70ba0162020-08-03 17:39:05 +1000362 ene_pause_ec(ctx_data);
agnescheng433ff582012-09-26 12:33:35 +0800363 }
364 return 0;
365}
366
Victor Ding70ba0162020-08-03 17:39:05 +1000367static int ene_reset_ec(ene_lpc_data_t *ctx_data)
Rong Changd8889e52012-07-27 21:42:25 +0800368{
369 uint8_t reg;
Rong Changd8889e52012-07-27 21:42:25 +0800370 struct timeval begin, now;
Victor Ding70ba0162020-08-03 17:39:05 +1000371 const ene_chip_t *chip = ctx_data->chip;
372
Rong Changd8889e52012-07-27 21:42:25 +0800373 gettimeofday(&begin, NULL);
374
375 /* EC prepare reset */
Victor Ding70ba0162020-08-03 17:39:05 +1000376 ec_command(chip, chip->ec_reset_cmd, chip->ec_reset_data);
Rong Changd8889e52012-07-27 21:42:25 +0800377
378 /* Spin wait for EC ready */
Angel Pons0c0ac672021-04-16 11:16:52 +0200379 while (ene_read(chip, chip->ec_status_buf) != chip->ec_is_stopping) {
Rong Changd8889e52012-07-27 21:42:25 +0800380 gettimeofday(&now, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200381 if (now.tv_sec - begin.tv_sec >= EC_COMMAND_TIMEOUT) {
Rong Changd8889e52012-07-27 21:42:25 +0800382 msg_pdbg("%s: unable to reset ec\n", __func__);
383 return -1;
384 }
385 }
386
387 /* Wait 1 second */
388 sleep(1);
389
390 /* Reset 8051 */
Victor Ding70ba0162020-08-03 17:39:05 +1000391 reg = ene_read(chip, REG_8051_CTRL);
Rong Changd8889e52012-07-27 21:42:25 +0800392 reg |= CPU_RESET;
Victor Ding70ba0162020-08-03 17:39:05 +1000393 ene_write(chip, REG_8051_CTRL, reg);
Rong Changd8889e52012-07-27 21:42:25 +0800394
Victor Ding70ba0162020-08-03 17:39:05 +1000395 ctx_data->ec_state = EC_STATE_RESET;
Rong Changd8889e52012-07-27 21:42:25 +0800396 return 0;
397}
398
Victor Ding70ba0162020-08-03 17:39:05 +1000399static int ene_enter_flash_mode(ene_lpc_data_t *ctx_data)
agnescheng433ff582012-09-26 12:33:35 +0800400{
Victor Ding70ba0162020-08-03 17:39:05 +1000401 if (ene_pause_ec(ctx_data))
402 return ene_reset_ec(ctx_data);
agnescheng433ff582012-09-26 12:33:35 +0800403 return 0;
404}
405
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700406static int ene_spi_send_command(const struct flashctx *flash,
407 unsigned int writecnt,
Rong Changaaa1acf2012-06-21 19:21:18 +0800408 unsigned int readcnt,
409 const unsigned char *writearr,
410 unsigned char *readarr)
411{
Victor Dingae44d662020-08-13 21:18:43 +1000412 unsigned int i;
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700413 int tries = EC_RESET_TRIES;
Victor Ding70ba0162020-08-03 17:39:05 +1000414 ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)flash->mst->spi.data;
415 const ene_chip_t *chip = ctx_data->chip;
Rong Changaaa1acf2012-06-21 19:21:18 +0800416
Victor Ding70ba0162020-08-03 17:39:05 +1000417 if (ctx_data->ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) {
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700418 do {
419 /* Enter reset mode if we need to write/erase */
Victor Ding70ba0162020-08-03 17:39:05 +1000420 if (ene_resume_ec(ctx_data))
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700421 continue;
422
Victor Ding70ba0162020-08-03 17:39:05 +1000423 if (!ene_reset_ec(ctx_data))
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700424 break;
425 } while (--tries > 0);
426
427 if (!tries) {
Victor Ding70ba0162020-08-03 17:39:05 +1000428 msg_perr("%s: EC failed reset, skipping write\n", __func__);
429 ctx_data->ec_state = EC_STATE_IDLE;
Shawn Nematbakhsh9c0cd8d2013-05-15 17:07:13 -0700430 return 1;
431 }
Angel Pons0c0ac672021-04-16 11:16:52 +0200432 } else if (chip->chip_id == ENE_KB94X && ctx_data->ec_state == EC_STATE_IDLE) {
Victor Ding70ba0162020-08-03 17:39:05 +1000433 ene_pause_timeout_check(ctx_data);
Angel Pons0c0ac672021-04-16 11:16:52 +0200434 }
Rong Changd8889e52012-07-27 21:42:25 +0800435
Victor Ding70ba0162020-08-03 17:39:05 +1000436 ene_spi_start(chip);
Rong Changaaa1acf2012-06-21 19:21:18 +0800437
438 for (i = 0; i < writecnt; i++) {
Victor Ding70ba0162020-08-03 17:39:05 +1000439 ene_write(chip, REG_SPI_COMMAND, writearr[i]);
440 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800441 msg_pdbg("%s: write count %d\n", __func__, i);
442 return 1;
443 }
444 }
445
446 for (i = 0; i < readcnt; i++) {
447 /* Push data by clock the serial bus */
Victor Ding70ba0162020-08-03 17:39:05 +1000448 ene_write(chip, REG_SPI_COMMAND, 0);
449 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800450 msg_pdbg("%s: read count %d\n", __func__, i);
451 return 1;
452 }
Victor Ding70ba0162020-08-03 17:39:05 +1000453 readarr[i] = ene_read(chip, REG_SPI_DATA);
454 if (ene_spi_wait(chip)) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800455 msg_pdbg("%s: read count %d\n", __func__, i);
456 return 1;
457 }
458 }
459
Victor Ding70ba0162020-08-03 17:39:05 +1000460 ene_spi_end(chip);
Rong Changaaa1acf2012-06-21 19:21:18 +0800461 return 0;
462}
463
David Hendricks93784b42016-08-09 17:00:38 -0700464static int ene_leave_flash_mode(void *data)
Rong Changaaa1acf2012-06-21 19:21:18 +0800465{
Victor Ding70ba0162020-08-03 17:39:05 +1000466 ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)data;
467 const ene_chip_t *chip = ctx_data->chip;
Rong Changd8889e52012-07-27 21:42:25 +0800468 int rv = 0;
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -0700469 uint8_t reg;
Rong Changaaa1acf2012-06-21 19:21:18 +0800470 struct timeval begin, now;
471
Victor Ding70ba0162020-08-03 17:39:05 +1000472 if (ctx_data->ec_state == EC_STATE_RESET) {
473 reg = ene_read(chip, REG_8051_CTRL);
Rong Changd8889e52012-07-27 21:42:25 +0800474 reg &= ~CPU_RESET;
Victor Ding70ba0162020-08-03 17:39:05 +1000475 ene_write(chip, REG_8051_CTRL, reg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800476
Rong Changd8889e52012-07-27 21:42:25 +0800477 gettimeofday(&begin, NULL);
478 /* EC restart */
Angel Pons0c0ac672021-04-16 11:16:52 +0200479 while (ene_read(chip, chip->ec_status_buf) != chip->ec_is_running) {
Rong Changd8889e52012-07-27 21:42:25 +0800480 gettimeofday(&now, NULL);
Angel Pons0c0ac672021-04-16 11:16:52 +0200481 if (now.tv_sec - begin.tv_sec >= EC_RESTART_TIMEOUT) {
Rong Changd8889e52012-07-27 21:42:25 +0800482 msg_pdbg("%s: ec restart busy\n", __func__);
483 rv = 1;
484 goto exit;
485 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800486 }
Rong Changd8889e52012-07-27 21:42:25 +0800487 msg_pdbg("%s: send ec restart\n", __func__);
Angel Pons0c0ac672021-04-16 11:16:52 +0200488 ec_command(chip, chip->ec_restart_cmd, chip->ec_restart_data);
Rong Changd8889e52012-07-27 21:42:25 +0800489
Victor Ding70ba0162020-08-03 17:39:05 +1000490 ctx_data->ec_state = EC_STATE_NORMAL;
Rong Changd8889e52012-07-27 21:42:25 +0800491 rv = 0;
492 goto exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800493 }
494
Victor Ding70ba0162020-08-03 17:39:05 +1000495 rv = ene_resume_ec(ctx_data);
Rong Changea1ec812012-07-21 11:41:32 +0800496
Rong Changd8889e52012-07-27 21:42:25 +0800497exit:
498 /*
499 * Trigger ec interrupt after pause/reset by sending 0x80
500 * to bios command port.
501 */
Victor Ding70ba0162020-08-03 17:39:05 +1000502 OUTB(0x80, chip->port_bios);
503 free(data);
Rong Changd8889e52012-07-27 21:42:25 +0800504 return rv;
Rong Changaaa1acf2012-06-21 19:21:18 +0800505}
506
Victor Ding70ba0162020-08-03 17:39:05 +1000507static struct spi_master spi_master_ene = {
Rong Changaaa1acf2012-06-21 19:21:18 +0800508 .max_data_read = 256,
509 .max_data_write = 256,
510 .command = ene_spi_send_command,
511 .multicommand = default_spi_send_multicommand,
512 .read = default_spi_read,
513 .write_256 = default_spi_write_256,
514};
515
Anastasia Klimchuk224c2e62021-04-28 10:08:15 +1000516static int check_params(void)
517{
518 int ret = 0;
519 char *const p = extract_programmer_param("type");
520 if (p && strcmp(p, "ec")) {
521 msg_pdbg("ene_lpc only supports \"ec\" type devices\n");
522 ret = 1;
523 }
524
525 free(p);
526 return ret;
527}
528
Edward O'Callaghan26fde5b2020-10-20 00:33:32 +1100529int ene_lpc_init()
Rong Changaaa1acf2012-06-21 19:21:18 +0800530{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700531 uint8_t hwver, ediid, i;
Victor Ding70ba0162020-08-03 17:39:05 +1000532 ene_lpc_data_t *ctx_data = NULL;
Rong Changaaa1acf2012-06-21 19:21:18 +0800533
534 msg_pdbg("%s\n", __func__);
Rong Changaaa1acf2012-06-21 19:21:18 +0800535
Victor Ding70ba0162020-08-03 17:39:05 +1000536 ctx_data = calloc(1, sizeof(ene_lpc_data_t));
537 if (!ctx_data) {
538 msg_perr("Unable to allocate space for extra context data.\n");
539 return 1;
540 }
541 ctx_data->ec_state = EC_STATE_NORMAL;
542
Anastasia Klimchuk9186d072021-04-27 11:36:10 +1000543 if (check_params())
544 goto init_err_exit;
David Hendricks2b56e472016-10-21 19:05:21 -0700545
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700546 for (i = 0; i < ENE_LAST; ++i) {
Victor Ding70ba0162020-08-03 17:39:05 +1000547 ctx_data->chip = &ene_chips[i];
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700548
Victor Ding70ba0162020-08-03 17:39:05 +1000549 hwver = ene_read(ctx_data->chip, REG_EC_HWVER);
550 ediid = ene_read(ctx_data->chip, REG_EC_EDIID);
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700551
552 if(hwver == ene_chips[i].hwver &&
553 ediid == ene_chips[i].ediid) {
554 break;
555 }
556 }
557
558 if (i == ENE_LAST) {
559 msg_pdbg("ENE EC not found (probe failed)\n");
Anastasia Klimchuk9186d072021-04-27 11:36:10 +1000560 goto init_err_exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800561 }
562
563 /* TODO: probe the EC stop protocol
564 *
565 * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c
566 */
567
Anastasia Klimchukbd250882021-04-16 14:54:41 +1000568 ene_enter_flash_mode(ctx_data);
569
570 internal_buses_supported |= BUS_LPC;
571 spi_master_ene.data = ctx_data;
Rong Changaaa1acf2012-06-21 19:21:18 +0800572
Anastasia Klimchuk9186d072021-04-27 11:36:10 +1000573 if (register_shutdown(ene_leave_flash_mode, ctx_data))
574 goto init_err_cleanup_exit;
Nico Huberf1eeda62021-05-11 17:38:14 +0200575 register_spi_master(&spi_master_ene, NULL);
Rong Changaaa1acf2012-06-21 19:21:18 +0800576 msg_pdbg("%s: successfully initialized ene\n", __func__);
Victor Ding7a5b9252020-08-04 13:53:44 +1000577
Anastasia Klimchuk9186d072021-04-27 11:36:10 +1000578 return 0;
579
580init_err_cleanup_exit:
581 ene_leave_flash_mode(ctx_data);
582 return 1;
583
584init_err_exit:
585 free(ctx_data);
586 return 1;
Rong Changaaa1acf2012-06-21 19:21:18 +0800587}
588
589#endif /* __i386__ || __x86_64__ */