blob: 31ad5d4140394da7df579f368db953a7c9a60837 [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) {
228 case JEDEC_CE_60:
229 /* Chip Erase 0x60 */
230 case JEDEC_CE_C7:
231 /* Chip Erase 0xc7 */
232 case JEDEC_BE_52:
233 /* Block Erase 0x52 */
234 case JEDEC_BE_D8:
235 /* Block Erase 0xd8 */
236 case JEDEC_BE_D7:
237 /* Block Erase 0xd7 */
238 case JEDEC_SE:
239 /* Sector Erase */
240 case JEDEC_BYTE_PROGRAM:
241 /* Write memory byte */
242 case JEDEC_AAI_WORD_PROGRAM:
243 /* Write AAI word */
244 return 1;
245 }
246 return 0;
247}
248
Rong Changaaa1acf2012-06-21 19:21:18 +0800249static void ene_spi_start(void)
250{
251 int cfg;
252
253 cfg = ene_read(REG_SPI_CONFIG);
254 cfg |= CFG_CSn_FORCE_LOW;
255 cfg |= CFG_COMMAND_WRITE_ENABLE;
256 ene_write(REG_SPI_CONFIG, cfg);
257
258 wait_cycles(ENE_SPI_DELAY_CYCLE);
259}
260
261static void ene_spi_end(void)
262{
263 int cfg;
264
265 cfg = ene_read(REG_SPI_CONFIG);
266 cfg &= ~CFG_CSn_FORCE_LOW;
267 cfg |= CFG_COMMAND_WRITE_ENABLE;
268 ene_write(REG_SPI_CONFIG, cfg);
269
270 wait_cycles(ENE_SPI_DELAY_CYCLE);
271}
272
273static int ene_spi_wait(void)
274{
275 struct timeval begin, now;
276
277 gettimeofday(&begin, NULL);
278 while(ene_read(REG_SPI_CONFIG) & CFG_STATUS) {
279 gettimeofday(&now, NULL);
280 if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
281 msg_pdbg("%s: spi busy\n", __func__);
282 return 1;
283 }
284 }
285 return 0;
286}
287
Rong Changd8889e52012-07-27 21:42:25 +0800288static int ene_pause_ec(void)
289{
290 struct timeval begin, now;
291
292 if (!found_chip->ec_pause_cmd)
293 return -1;
294
295 /* EC prepare pause */
296 ec_command(found_chip->ec_pause_cmd, found_chip->ec_pause_data);
297
298 gettimeofday(&begin, NULL);
299 /* Spin wait for EC ready */
300 while (ene_read(found_chip->ec_status_buf) !=
301 found_chip->ec_is_pausing) {
302 gettimeofday(&now, NULL);
303 if ((now.tv_sec - begin.tv_sec) >=
304 EC_COMMAND_TIMEOUT) {
305 msg_pdbg("%s: unable to pause ec\n", __func__);
306 return -1;
307 }
308 }
309
310 ec_state = EC_STATE_IDLE;
311 return 0;
312}
313
314static int ene_resume_ec(void)
315{
316 struct timeval begin, now;
317
318 /* Trigger 8051 interrupt to resume */
319 ene_write(REG_EC_EXTCMD, 0xff);
320
321 gettimeofday(&begin, NULL);
322 while (ene_read(found_chip->ec_status_buf) !=
323 found_chip->ec_is_running) {
324 gettimeofday(&now, NULL);
325 if ((now.tv_sec - begin.tv_sec) >=
326 EC_COMMAND_TIMEOUT) {
327 msg_pdbg("%s: unable to resume ec\n", __func__);
328 return -1;
329 }
330 }
331
332 ec_state = EC_STATE_NORMAL;
333 return 0;
334}
335
336static int ene_reset_ec(void)
337{
338 uint8_t reg;
339
340 struct timeval begin, now;
341 gettimeofday(&begin, NULL);
342
343 /* EC prepare reset */
344 ec_command(found_chip->ec_reset_cmd, found_chip->ec_reset_data);
345
346 /* Spin wait for EC ready */
347 while (ene_read(found_chip->ec_status_buf) !=
348 found_chip->ec_is_stopping) {
349 gettimeofday(&now, NULL);
350 if ((now.tv_sec - begin.tv_sec) >=
351 EC_COMMAND_TIMEOUT) {
352 msg_pdbg("%s: unable to reset ec\n", __func__);
353 return -1;
354 }
355 }
356
357 /* Wait 1 second */
358 sleep(1);
359
360 /* Reset 8051 */
361 reg = ene_read(REG_8051_CTRL);
362 reg |= CPU_RESET;
363 ene_write(REG_8051_CTRL, reg);
364
365 ec_state = EC_STATE_RESET;
366 return 0;
367}
368
Rong Changaaa1acf2012-06-21 19:21:18 +0800369static int ene_spi_send_command(unsigned int writecnt,
370 unsigned int readcnt,
371 const unsigned char *writearr,
372 unsigned char *readarr)
373{
Rong Changaaa1acf2012-06-21 19:21:18 +0800374 int i;
375
Rong Changd8889e52012-07-27 21:42:25 +0800376 if (ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) {
377 /* Enter reset mode if we need to write/erase */
378 ene_resume_ec();
379 ene_reset_ec();
380 }
381
Rong Changaaa1acf2012-06-21 19:21:18 +0800382 ene_spi_start();
383
384 for (i = 0; i < writecnt; i++) {
385 ene_write(REG_SPI_COMMAND, writearr[i]);
386 if (ene_spi_wait()) {
387 msg_pdbg("%s: write count %d\n", __func__, i);
388 return 1;
389 }
390 }
391
392 for (i = 0; i < readcnt; i++) {
393 /* Push data by clock the serial bus */
394 ene_write(REG_SPI_COMMAND, 0);
395 if (ene_spi_wait()) {
396 msg_pdbg("%s: read count %d\n", __func__, i);
397 return 1;
398 }
399 readarr[i] = ene_read(REG_SPI_DATA);
400 if (ene_spi_wait()) {
401 msg_pdbg("%s: read count %d\n", __func__, i);
402 return 1;
403 }
404 }
405
406 ene_spi_end();
407 return 0;
408}
409
410static int ene_enter_flash_mode(void)
411{
Rong Changd8889e52012-07-27 21:42:25 +0800412 if (ene_pause_ec())
413 return ene_reset_ec();
Rong Changaaa1acf2012-06-21 19:21:18 +0800414 return 0;
415}
416
417static int ene_leave_flash_mode(void *data)
418{
Rong Changd8889e52012-07-27 21:42:25 +0800419 int rv = 0;
Shawn Nematbakhshb903dfd2012-07-24 15:27:00 -0700420 uint8_t reg;
Rong Changaaa1acf2012-06-21 19:21:18 +0800421 struct timeval begin, now;
422
Rong Changd8889e52012-07-27 21:42:25 +0800423 if (ec_state == EC_STATE_RESET) {
424 reg = ene_read(REG_8051_CTRL);
425 reg &= ~CPU_RESET;
426 ene_write(REG_8051_CTRL, reg);
Rong Changaaa1acf2012-06-21 19:21:18 +0800427
Rong Changd8889e52012-07-27 21:42:25 +0800428 gettimeofday(&begin, NULL);
429 /* EC restart */
430 while (ene_read(found_chip->ec_status_buf) !=
431 found_chip->ec_is_running) {
432 gettimeofday(&now, NULL);
433 if ((now.tv_sec - begin.tv_sec) >=
434 EC_RESTART_TIMEOUT) {
435 msg_pdbg("%s: ec restart busy\n", __func__);
436 rv = 1;
437 goto exit;
438 }
Rong Changaaa1acf2012-06-21 19:21:18 +0800439 }
Rong Changd8889e52012-07-27 21:42:25 +0800440 msg_pdbg("%s: send ec restart\n", __func__);
441 ec_command(found_chip->ec_restart_cmd,
442 found_chip->ec_restart_data);
443
444 ec_state = EC_STATE_NORMAL;
445 rv = 0;
446 goto exit;
Rong Changaaa1acf2012-06-21 19:21:18 +0800447 }
448
Rong Changd8889e52012-07-27 21:42:25 +0800449 rv = ene_resume_ec();
Rong Changea1ec812012-07-21 11:41:32 +0800450
Rong Changd8889e52012-07-27 21:42:25 +0800451exit:
452 /*
453 * Trigger ec interrupt after pause/reset by sending 0x80
454 * to bios command port.
455 */
456 OUTB(0x80, found_chip->port_bios);
457 return rv;
Rong Changaaa1acf2012-06-21 19:21:18 +0800458}
459
460static const struct spi_programmer spi_programmer_ene = {
461 .type = SPI_CONTROLLER_ENE,
462 .max_data_read = 256,
463 .max_data_write = 256,
464 .command = ene_spi_send_command,
465 .multicommand = default_spi_send_multicommand,
466 .read = default_spi_read,
467 .write_256 = default_spi_write_256,
468};
469
470int ene_probe_spi_flash(const char *name)
471{
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700472 uint8_t hwver, ediid, i;
Rong Changaaa1acf2012-06-21 19:21:18 +0800473
474 msg_pdbg("%s\n", __func__);
Rong Changaaa1acf2012-06-21 19:21:18 +0800475
Shawn Nematbakhsh36046f52012-07-26 09:42:36 -0700476 for (i = 0; i < ENE_LAST; ++i) {
477 found_chip = &ene_chips[i];
478
479 hwver = ene_read(REG_EC_HWVER);
480 ediid = ene_read(REG_EC_EDIID);
481
482 if(hwver == ene_chips[i].hwver &&
483 ediid == ene_chips[i].ediid) {
484 break;
485 }
486 }
487
488 if (i == ENE_LAST) {
489 msg_pdbg("ENE EC not found (probe failed)\n");
Rong Changaaa1acf2012-06-21 19:21:18 +0800490 return 0;
491 }
492
493 /* TODO: probe the EC stop protocol
494 *
495 * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c
496 */
497
498
499 if (register_shutdown(ene_leave_flash_mode, NULL))
500 return 1;
501
502 ene_enter_flash_mode();
503
504 buses_supported |= BUS_LPC;
505 register_spi_programmer(&spi_programmer_ene);
506 msg_pdbg("%s: successfully initialized ene\n", __func__);
507 return 0;
508}
509
510#endif /* __i386__ || __x86_64__ */
511