blob: 8e0462e1581fa5a75efbfd7164d5508f3a513a80 [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>
37#include <string.h>
38#include <unistd.h>
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -070039#include <sys/time.h>
Rong Changaaa1acf2012-06-21 19:21:18 +080040
41#include "chipdrivers.h"
42#include "flash.h"
43#include "programmer.h"
44#include "spi.h"
45
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070046/* Supported ENE ECs, ENE_LAST should always be LAST member */
47enum ene_chip_id {
48 ENE_KB932 = 0,
49 ENE_KB94X,
50 ENE_LAST
51};
52
Rong Changd8889e52012-07-27 21:42:25 +080053/* EC state */
54enum ene_ec_state {
55 EC_STATE_NORMAL,
56 EC_STATE_IDLE,
57 EC_STATE_RESET,
58 EC_STATE_UNKNOWN
59};
60
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070061/* chip-specific parameters */
62typedef struct {
63 enum ene_chip_id chip_id;
64 uint8_t hwver;
65 uint8_t ediid;
Rong Changd8889e52012-07-27 21:42:25 +080066 uint32_t port_bios;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070067 uint32_t port_ec_command;
68 uint32_t port_ec_data;
69 uint8_t ec_reset_cmd;
70 uint8_t ec_reset_data;
71 uint8_t ec_restart_cmd;
72 uint8_t ec_restart_data;
Rong Changd8889e52012-07-27 21:42:25 +080073 uint8_t ec_pause_cmd;
74 uint8_t ec_pause_data;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070075 uint16_t ec_status_buf;
76 uint8_t ec_is_stopping;
77 uint8_t ec_is_running;
Rong Changd8889e52012-07-27 21:42:25 +080078 uint8_t ec_is_pausing;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070079 uint32_t port_io_base;
80} ene_chip;
81
82/* table of supported chips + parameters */
83static ene_chip ene_chips[] = {
84 { ENE_KB932, /* chip_id */
85 0xa2, 0x02, /* hwver + ediid */
Rong Changd8889e52012-07-27 21:42:25 +080086 0x66, /* port_bios */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070087 0x6c, 0x68, /* port_ec_{command,data} */
88 0x59, 0xf2, /* ec_reset_{cmd,data} */
89 0x59, 0xf9, /* ec_restart_{cmd,data} */
Rong Changd8889e52012-07-27 21:42:25 +080090 0x59, 0xf1, /* ec_pause_{cmd,data} */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070091 0xf554, /* ec_status_buf */
92 0xa5, 0x00, /* ec_is_{stopping,running} masks */
Rong Changd8889e52012-07-27 21:42:25 +080093 0x33, /* ec_is_pausing mask */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070094 0xfd60 }, /* port_io_base */
95
Rong Changd8889e52012-07-27 21:42:25 +080096 { ENE_KB94X, /* chip_id */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070097 0xa3, 0x05, /* hwver + ediid */
Rong Changd8889e52012-07-27 21:42:25 +080098 0x66, /* port_bios */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -070099 0x66, 0x68, /* port_ec_{command,data} */
100 0x7d, 0x10, /* ec_reset_{cmd,data} */
101 0x7f, 0x10, /* ec_restart_{cmd,data} */
Rong Changd8889e52012-07-27 21:42:25 +0800102 /*
103 * TODO(rongchang): Add KB94X pause mode support
104 */
105 0,0, /* ec_pause_{cmd,data} */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700106 0xf710, /* ec_status_buf */
107 0x02, 0x00, /* ec_is_{stopping,running} masks */
Rong Changd8889e52012-07-27 21:42:25 +0800108 0, /* ec_is_pausing mask */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700109 0x0380 }, /* port_io_base */
110};
111
112/* pointer to table entry of identified chip */
113static ene_chip *found_chip;
Rong Changd8889e52012-07-27 21:42:25 +0800114/* current ec state */
115static enum ene_ec_state ec_state = EC_STATE_NORMAL;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700116
Rong Changaaa1acf2012-06-21 19:21:18 +0800117#define REG_EC_HWVER 0xff00
118#define REG_EC_FWVER 0xff01
119#define REG_EC_EDIID 0xff24
120#define REG_8051_CTRL 0xff14
Rong Changd8889e52012-07-27 21:42:25 +0800121#define REG_EC_EXTCMD 0xff10
Rong Changaaa1acf2012-06-21 19:21:18 +0800122
Rong Changaaa1acf2012-06-21 19:21:18 +0800123#define CPU_RESET 1
124
125/* Hwardware registers */
126#define REG_SPI_DATA 0xfeab
127#define REG_SPI_COMMAND 0xfeac
128#define REG_SPI_CONFIG 0xfead
129#define CFG_CSn_FORCE_LOW (1 << 4)
130#define CFG_COMMAND_WRITE_ENABLE (1 << 3)
131#define CFG_STATUS (1 << 1)
132#define CFG_ENABLE_BUSY_STATUS_CHECK (1 << 0)
133
134/* Timeout */
135#define EC_COMMAND_TIMEOUT 4
136#define EC_RESTART_TIMEOUT 10
137#define ENE_SPI_DELAY_CYCLE 4
138
Rong Changaaa1acf2012-06-21 19:21:18 +0800139static const uint8_t mask_input_buffer_full = 2;
140static const uint8_t mask_output_buffer_full = 1;
141
Rong Changaaa1acf2012-06-21 19:21:18 +0800142const int port_ene_bank = 1;
143const int port_ene_offset = 2;
144const int port_ene_data = 3;
145
146static void ec_command(uint8_t cmd, uint8_t data)
147{
148 struct timeval begin, now;
149
150 /* Spin wait for EC input buffer empty */
151 gettimeofday(&begin, NULL);
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700152 while (INB(found_chip->port_ec_command) & mask_input_buffer_full) {
Rong Changaaa1acf2012-06-21 19:21:18 +0800153 gettimeofday(&now, NULL);
154 if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
155 msg_pdbg("%s: buf not empty\n", __func__);
156 return;
157 }
158 }
159 /* Write command */
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700160 OUTB(cmd, found_chip->port_ec_command);
Rong Changaaa1acf2012-06-21 19:21:18 +0800161
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700162 if (found_chip->chip_id == ENE_KB932) {
163 /* Spin wait for EC input buffer empty */
164 gettimeofday(&begin, NULL);
165 while (INB(found_chip->port_ec_command) &
166 mask_input_buffer_full) {
167 gettimeofday(&now, NULL);
168 if ((now.tv_sec - begin.tv_sec) >=
169 EC_COMMAND_TIMEOUT) {
170 msg_pdbg("%s: buf not empty\n", __func__);
171 return;
172 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800173 }
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700174 /* Write data */
175 OUTB(data, found_chip->port_ec_data);
Rong Changaaa1acf2012-06-21 19:21:18 +0800176 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800177}
178
179static uint8_t ene_read(uint16_t addr)
180{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700181 uint8_t bank;
182 uint8_t offset;
183 uint8_t data;
184 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800185
186 bank = addr >> 8;
187 offset = addr & 0xff;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700188 port_io_base = found_chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800189
190 OUTB(bank, port_io_base + port_ene_bank);
191 OUTB(offset, port_io_base + port_ene_offset);
192 data = INB(port_io_base + port_ene_data);
193
194 return data;
195}
196
197static void ene_write(uint16_t addr, uint8_t data)
198{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700199 uint8_t bank;
200 uint8_t offset;
201 uint32_t port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800202
203 bank = addr >> 8;
204 offset = addr & 0xff;
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700205 port_io_base = found_chip->port_io_base;
Rong Changaaa1acf2012-06-21 19:21:18 +0800206
207 OUTB(bank, port_io_base + port_ene_bank);
208 OUTB(offset, port_io_base + port_ene_offset);
209
210 OUTB(data, port_io_base + port_ene_data);
211}
212
213/**
214 * wait_cycles, wait for n LPC bus clock cycles
215 *
216 * @param n: number of LPC cycles to wait
217 * @return void
218 */
219void wait_cycles(int n)
220{
221 while (n--)
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700222 INB(found_chip->port_io_base + port_ene_bank);
Rong Changaaa1acf2012-06-21 19:21:18 +0800223}
224
Rong Changd8889e52012-07-27 21:42:25 +0800225static int is_spicmd_write(uint8_t cmd)
226{
227 switch (cmd) {
Rong Chang7797e4c2012-08-19 00:40:49 +0800228 case JEDEC_WREN:
229 /* Chip Write Enable */
230 case JEDEC_EWSR:
231 /* Write Status Enable */
Rong Changd8889e52012-07-27 21:42:25 +0800232 case JEDEC_CE_60:
233 /* Chip Erase 0x60 */
234 case JEDEC_CE_C7:
235 /* Chip Erase 0xc7 */
236 case JEDEC_BE_52:
237 /* Block Erase 0x52 */
238 case JEDEC_BE_D8:
239 /* Block Erase 0xd8 */
240 case JEDEC_BE_D7:
241 /* Block Erase 0xd7 */
242 case JEDEC_SE:
243 /* Sector Erase */
244 case JEDEC_BYTE_PROGRAM:
245 /* Write memory byte */
246 case JEDEC_AAI_WORD_PROGRAM:
247 /* Write AAI word */
248 return 1;
249 }
250 return 0;
251}
252
Rong Changaaa1acf2012-06-21 19:21:18 +0800253static void ene_spi_start(void)
254{
255 int cfg;
256
257 cfg = ene_read(REG_SPI_CONFIG);
258 cfg |= CFG_CSn_FORCE_LOW;
259 cfg |= CFG_COMMAND_WRITE_ENABLE;
260 ene_write(REG_SPI_CONFIG, cfg);
261
262 wait_cycles(ENE_SPI_DELAY_CYCLE);
263}
264
265static void ene_spi_end(void)
266{
267 int cfg;
268
269 cfg = ene_read(REG_SPI_CONFIG);
270 cfg &= ~CFG_CSn_FORCE_LOW;
271 cfg |= CFG_COMMAND_WRITE_ENABLE;
272 ene_write(REG_SPI_CONFIG, cfg);
273
274 wait_cycles(ENE_SPI_DELAY_CYCLE);
275}
276
277static int ene_spi_wait(void)
278{
279 struct timeval begin, now;
280
281 gettimeofday(&begin, NULL);
282 while(ene_read(REG_SPI_CONFIG) & CFG_STATUS) {
283 gettimeofday(&now, NULL);
284 if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
285 msg_pdbg("%s: spi busy\n", __func__);
286 return 1;
287 }
288 }
289 return 0;
290}
291
Rong Changd8889e52012-07-27 21:42:25 +0800292static int ene_pause_ec(void)
293{
294 struct timeval begin, now;
295
296 if (!found_chip->ec_pause_cmd)
297 return -1;
298
299 /* EC prepare pause */
300 ec_command(found_chip->ec_pause_cmd, found_chip->ec_pause_data);
301
302 gettimeofday(&begin, NULL);
303 /* Spin wait for EC ready */
304 while (ene_read(found_chip->ec_status_buf) !=
305 found_chip->ec_is_pausing) {
306 gettimeofday(&now, NULL);
307 if ((now.tv_sec - begin.tv_sec) >=
308 EC_COMMAND_TIMEOUT) {
309 msg_pdbg("%s: unable to pause ec\n", __func__);
310 return -1;
311 }
312 }
313
314 ec_state = EC_STATE_IDLE;
315 return 0;
316}
317
318static int ene_resume_ec(void)
319{
320 struct timeval begin, now;
321
322 /* Trigger 8051 interrupt to resume */
323 ene_write(REG_EC_EXTCMD, 0xff);
324
325 gettimeofday(&begin, NULL);
326 while (ene_read(found_chip->ec_status_buf) !=
327 found_chip->ec_is_running) {
328 gettimeofday(&now, NULL);
329 if ((now.tv_sec - begin.tv_sec) >=
330 EC_COMMAND_TIMEOUT) {
331 msg_pdbg("%s: unable to resume ec\n", __func__);
332 return -1;
333 }
334 }
335
336 ec_state = EC_STATE_NORMAL;
337 return 0;
338}
339
340static int ene_reset_ec(void)
341{
342 uint8_t reg;
343
344 struct timeval begin, now;
345 gettimeofday(&begin, NULL);
346
347 /* EC prepare reset */
348 ec_command(found_chip->ec_reset_cmd, found_chip->ec_reset_data);
349
350 /* Spin wait for EC ready */
351 while (ene_read(found_chip->ec_status_buf) !=
352 found_chip->ec_is_stopping) {
353 gettimeofday(&now, NULL);
354 if ((now.tv_sec - begin.tv_sec) >=
355 EC_COMMAND_TIMEOUT) {
356 msg_pdbg("%s: unable to reset ec\n", __func__);
357 return -1;
358 }
359 }
360
361 /* Wait 1 second */
362 sleep(1);
363
364 /* Reset 8051 */
365 reg = ene_read(REG_8051_CTRL);
366 reg |= CPU_RESET;
367 ene_write(REG_8051_CTRL, reg);
368
369 ec_state = EC_STATE_RESET;
370 return 0;
371}
372
Rong Changaaa1acf2012-06-21 19:21:18 +0800373static int ene_spi_send_command(unsigned int writecnt,
374 unsigned int readcnt,
375 const unsigned char *writearr,
376 unsigned char *readarr)
377{
Rong Changaaa1acf2012-06-21 19:21:18 +0800378 int i;
379
Rong Changd8889e52012-07-27 21:42:25 +0800380 if (ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) {
381 /* Enter reset mode if we need to write/erase */
382 ene_resume_ec();
383 ene_reset_ec();
384 }
385
Rong Changaaa1acf2012-06-21 19:21:18 +0800386 ene_spi_start();
387
388 for (i = 0; i < writecnt; i++) {
389 ene_write(REG_SPI_COMMAND, writearr[i]);
390 if (ene_spi_wait()) {
391 msg_pdbg("%s: write count %d\n", __func__, i);
392 return 1;
393 }
394 }
395
396 for (i = 0; i < readcnt; i++) {
397 /* Push data by clock the serial bus */
398 ene_write(REG_SPI_COMMAND, 0);
399 if (ene_spi_wait()) {
400 msg_pdbg("%s: read count %d\n", __func__, i);
401 return 1;
402 }
403 readarr[i] = ene_read(REG_SPI_DATA);
404 if (ene_spi_wait()) {
405 msg_pdbg("%s: read count %d\n", __func__, i);
406 return 1;
407 }
408 }
409
410 ene_spi_end();
411 return 0;
412}
413
414static int ene_enter_flash_mode(void)
415{
Rong Changd8889e52012-07-27 21:42:25 +0800416 if (ene_pause_ec())
417 return ene_reset_ec();
Rong Changaaa1acf2012-06-21 19:21:18 +0800418 return 0;
419}
420
421static int ene_leave_flash_mode(void *data)
422{
Rong Changd8889e52012-07-27 21:42:25 +0800423 int rv = 0;
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -0700424 uint8_t reg;
Rong Changaaa1acf2012-06-21 19:21:18 +0800425 struct timeval begin, now;
426
Rong Changd8889e52012-07-27 21:42:25 +0800427 if (ec_state == EC_STATE_RESET) {
428 reg = ene_read(REG_8051_CTRL);
429 reg &= ~CPU_RESET;
430 ene_write(REG_8051_CTRL, reg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800431
Rong Changd8889e52012-07-27 21:42:25 +0800432 gettimeofday(&begin, NULL);
433 /* EC restart */
434 while (ene_read(found_chip->ec_status_buf) !=
435 found_chip->ec_is_running) {
436 gettimeofday(&now, NULL);
437 if ((now.tv_sec - begin.tv_sec) >=
438 EC_RESTART_TIMEOUT) {
439 msg_pdbg("%s: ec restart busy\n", __func__);
440 rv = 1;
441 goto exit;
442 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800443 }
Rong Changd8889e52012-07-27 21:42:25 +0800444 msg_pdbg("%s: send ec restart\n", __func__);
445 ec_command(found_chip->ec_restart_cmd,
446 found_chip->ec_restart_data);
447
448 ec_state = EC_STATE_NORMAL;
449 rv = 0;
450 goto exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800451 }
452
Rong Changd8889e52012-07-27 21:42:25 +0800453 rv = ene_resume_ec();
Rong Changea1ec812012-07-21 11:41:32 +0800454
Rong Changd8889e52012-07-27 21:42:25 +0800455exit:
456 /*
457 * Trigger ec interrupt after pause/reset by sending 0x80
458 * to bios command port.
459 */
460 OUTB(0x80, found_chip->port_bios);
461 return rv;
Rong Changaaa1acf2012-06-21 19:21:18 +0800462}
463
464static const struct spi_programmer spi_programmer_ene = {
465 .type = SPI_CONTROLLER_ENE,
466 .max_data_read = 256,
467 .max_data_write = 256,
468 .command = ene_spi_send_command,
469 .multicommand = default_spi_send_multicommand,
470 .read = default_spi_read,
471 .write_256 = default_spi_write_256,
472};
473
474int ene_probe_spi_flash(const char *name)
475{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700476 uint8_t hwver, ediid, i;
Rong Changaaa1acf2012-06-21 19:21:18 +0800477
478 msg_pdbg("%s\n", __func__);
Rong Changaaa1acf2012-06-21 19:21:18 +0800479
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700480 for (i = 0; i < ENE_LAST; ++i) {
481 found_chip = &ene_chips[i];
482
483 hwver = ene_read(REG_EC_HWVER);
484 ediid = ene_read(REG_EC_EDIID);
485
486 if(hwver == ene_chips[i].hwver &&
487 ediid == ene_chips[i].ediid) {
488 break;
489 }
490 }
491
492 if (i == ENE_LAST) {
493 msg_pdbg("ENE EC not found (probe failed)\n");
Rong Changaaa1acf2012-06-21 19:21:18 +0800494 return 0;
495 }
496
497 /* TODO: probe the EC stop protocol
498 *
499 * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c
500 */
501
502
503 if (register_shutdown(ene_leave_flash_mode, NULL))
504 return 1;
505
506 ene_enter_flash_mode();
507
508 buses_supported |= BUS_LPC;
509 register_spi_programmer(&spi_programmer_ene);
510 msg_pdbg("%s: successfully initialized ene\n", __func__);
511 return 0;
512}
513
514#endif /* __i386__ || __x86_64__ */
515