Newer
Older
/*
* This file is part of the flashrom project.
*
* Copyright (C) 2008 Stefan Wildemann <stefan.wildemann@kontron.com>
* Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.com>
* Copyright (C) 2008 Dominik Geyer <dominik.geyer@kontron.com>
* Copyright (C) 2008 coresystems GmbH <info@coresystems.de>
* Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
* Copyright (C) 2011 Stefan Tauner
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#if defined(__i386__) || defined(__x86_64__)
#include <stdlib.h>
#include "ich_descriptors.h"
/* Apollo Lake */
#define APL_REG_FREG12 0xe0 /* 32 Bytes Flash Region 12 */
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* Sunrise Point */
/* Added HSFS Status bits */
#define HSFS_WRSDIS_OFF 11 /* 11: Flash Configuration Lock-Down */
#define HSFS_WRSDIS (0x1 << HSFS_WRSDIS_OFF)
#define HSFS_PRR34_LOCKDN_OFF 12 /* 12: PRR3 PRR4 Lock-Down */
#define HSFS_PRR34_LOCKDN (0x1 << HSFS_PRR34_LOCKDN_OFF)
/* HSFS_BERASE vanished */
/*
* HSFC and HSFS 16-bit registers are combined into the 32-bit
* BIOS_HSFSTS_CTL register in the Sunrise Point datasheet,
* however we still treat them separately in order to reuse code.
*/
/* Changed HSFC Control bits */
#define PCH100_HSFC_FCYCLE_OFF (17 - 16) /* 1-4: FLASH Cycle */
#define PCH100_HSFC_FCYCLE (0xf << PCH100_HSFC_FCYCLE_OFF)
/* New HSFC Control bit */
#define HSFC_WET_OFF (21 - 16) /* 5: Write Enable Type */
#define HSFC_WET (0x1 << HSFC_WET_OFF)
#define PCH100_FADDR_FLA 0x07ffffff
#define PCH100_REG_DLOCK 0x0c /* 32 Bits Discrete Lock Bits */
#define DLOCK_BMWAG_LOCKDN_OFF 0
#define DLOCK_BMWAG_LOCKDN (0x1 << DLOCK_BMWAG_LOCKDN_OFF)
#define DLOCK_BMRAG_LOCKDN_OFF 1
#define DLOCK_BMRAG_LOCKDN (0x1 << DLOCK_BMRAG_LOCKDN_OFF)
#define DLOCK_SBMWAG_LOCKDN_OFF 2
#define DLOCK_SBMWAG_LOCKDN (0x1 << DLOCK_SBMWAG_LOCKDN_OFF)
#define DLOCK_SBMRAG_LOCKDN_OFF 3
#define DLOCK_SBMRAG_LOCKDN (0x1 << DLOCK_SBMRAG_LOCKDN_OFF)
#define DLOCK_PR0_LOCKDN_OFF 8
#define DLOCK_PR0_LOCKDN (0x1 << DLOCK_PR0_LOCKDN_OFF)
#define DLOCK_PR1_LOCKDN_OFF 9
#define DLOCK_PR1_LOCKDN (0x1 << DLOCK_PR1_LOCKDN_OFF)
#define DLOCK_PR2_LOCKDN_OFF 10
#define DLOCK_PR2_LOCKDN (0x1 << DLOCK_PR2_LOCKDN_OFF)
#define DLOCK_PR3_LOCKDN_OFF 11
#define DLOCK_PR3_LOCKDN (0x1 << DLOCK_PR3_LOCKDN_OFF)
#define DLOCK_PR4_LOCKDN_OFF 12
#define DLOCK_PR4_LOCKDN (0x1 << DLOCK_PR4_LOCKDN_OFF)
#define DLOCK_SSEQ_LOCKDN_OFF 16
#define DLOCK_SSEQ_LOCKDN (0x1 << DLOCK_SSEQ_LOCKDN_OFF)
#define PCH100_REG_FPR0 0x84 /* 32 Bits Protected Range 0 */
#define PCH100_REG_GPR0 0x98 /* 32 Bits Global Protected Range 0 */
#define PCH100_REG_SSFSC 0xA0 /* 32 Bits Status (8) + Control (24) */
#define PCH100_REG_PREOP 0xA4 /* 16 Bits */
#define PCH100_REG_OPTYPE 0xA6 /* 16 Bits */
#define PCH100_REG_OPMENU 0xA8 /* 64 Bits */
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#define ICH9_REG_HSFS 0x04 /* 16 Bits Hardware Sequencing Flash Status */
#define HSFS_FDONE_OFF 0 /* 0: Flash Cycle Done */
#define HSFS_FDONE (0x1 << HSFS_FDONE_OFF)
#define HSFS_FCERR_OFF 1 /* 1: Flash Cycle Error */
#define HSFS_FCERR (0x1 << HSFS_FCERR_OFF)
#define HSFS_AEL_OFF 2 /* 2: Access Error Log */
#define HSFS_AEL (0x1 << HSFS_AEL_OFF)
#define HSFS_BERASE_OFF 3 /* 3-4: Block/Sector Erase Size */
#define HSFS_BERASE (0x3 << HSFS_BERASE_OFF)
#define HSFS_SCIP_OFF 5 /* 5: SPI Cycle In Progress */
#define HSFS_SCIP (0x1 << HSFS_SCIP_OFF)
/* 6-12: reserved */
#define HSFS_FDOPSS_OFF 13 /* 13: Flash Descriptor Override Pin-Strap Status */
#define HSFS_FDOPSS (0x1 << HSFS_FDOPSS_OFF)
#define HSFS_FDV_OFF 14 /* 14: Flash Descriptor Valid */
#define HSFS_FDV (0x1 << HSFS_FDV_OFF)
#define HSFS_FLOCKDN_OFF 15 /* 15: Flash Configuration Lock-Down */
#define HSFS_FLOCKDN (0x1 << HSFS_FLOCKDN_OFF)
#define ICH9_REG_HSFC 0x06 /* 16 Bits Hardware Sequencing Flash Control */
#define HSFC_FGO_OFF 0 /* 0: Flash Cycle Go */
#define HSFC_FGO (0x1 << HSFC_FGO_OFF)
#define HSFC_FCYCLE_OFF 1 /* 1-2: FLASH Cycle */
#define HSFC_FCYCLE (0x3 << HSFC_FCYCLE_OFF)
/* 3-7: reserved */
#define HSFC_FDBC_OFF 8 /* 8-13: Flash Data Byte Count */
#define HSFC_FDBC (0x3f << HSFC_FDBC_OFF)
/* 14: reserved */
#define HSFC_SME_OFF 15 /* 15: SPI SMI# Enable */
#define HSFC_SME (0x1 << HSFC_SME_OFF)
#define ICH9_REG_FADDR 0x08 /* 32 Bits */
#define ICH9_REG_FDATA0 0x10 /* 64 Bytes */
#define ICH9_REG_FRAP 0x50 /* 32 Bytes Flash Region Access Permissions */
#define ICH9_REG_FREG0 0x54 /* 32 Bytes Flash Region 0 */
#define ICH9_REG_PR0 0x74 /* 32 Bytes Protected Range 0 */
#define PR_WP_OFF 31 /* 31: write protection enable */
#define PR_RP_OFF 15 /* 15: read protection enable */
#define ICH9_REG_SSFS 0x90 /* 08 Bits */
#define SSFS_SCIP_OFF 0 /* SPI Cycle In Progress */
#define SSFS_SCIP (0x1 << SSFS_SCIP_OFF)
#define SSFS_FDONE_OFF 2 /* Cycle Done Status */
#define SSFS_FDONE (0x1 << SSFS_FDONE_OFF)
#define SSFS_FCERR_OFF 3 /* Flash Cycle Error */
#define SSFS_FCERR (0x1 << SSFS_FCERR_OFF)
#define SSFS_AEL_OFF 4 /* Access Error Log */
#define SSFS_AEL (0x1 << SSFS_AEL_OFF)
/* The following bits are reserved in SSFS: 1,5-7. */
#define SSFS_RESERVED_MASK 0x000000e2
#define ICH9_REG_SSFC 0x91 /* 24 Bits */
/* We combine SSFS and SSFC to one 32-bit word,
* therefore SSFC bits are off by 8. */
/* 0: reserved */
#define SSFC_SCGO_OFF (1 + 8) /* 1: SPI Cycle Go */
#define SSFC_SCGO (0x1 << SSFC_SCGO_OFF)
#define SSFC_ACS_OFF (2 + 8) /* 2: Atomic Cycle Sequence */
#define SSFC_ACS (0x1 << SSFC_ACS_OFF)
#define SSFC_SPOP_OFF (3 + 8) /* 3: Sequence Prefix Opcode Pointer */
#define SSFC_SPOP (0x1 << SSFC_SPOP_OFF)
#define SSFC_COP_OFF (4 + 8) /* 4-6: Cycle Opcode Pointer */
#define SSFC_COP (0x7 << SSFC_COP_OFF)
/* 7: reserved */
#define SSFC_DBC_OFF (8 + 8) /* 8-13: Data Byte Count */
#define SSFC_DBC (0x3f << SSFC_DBC_OFF)
#define SSFC_DS_OFF (14 + 8) /* 14: Data Cycle */
#define SSFC_DS (0x1 << SSFC_DS_OFF)
#define SSFC_SME_OFF (15 + 8) /* 15: SPI SMI# Enable */
#define SSFC_SME (0x1 << SSFC_SME_OFF)
#define SSFC_SCF_OFF (16 + 8) /* 16-18: SPI Cycle Frequency */
#define SSFC_SCF (0x7 << SSFC_SCF_OFF)
#define SSFC_SCF_20MHZ 0x00000000
#define SSFC_SCF_33MHZ 0x01000000
/* 19-23: reserved */
#define SSFC_RESERVED_MASK 0xf8008100
#define ICH9_REG_PREOP 0x94 /* 16 Bits */
#define ICH9_REG_OPTYPE 0x96 /* 16 Bits */
#define ICH9_REG_OPMENU 0x98 /* 64 Bits */
#define ICH9_REG_BBAR 0xA0 /* 32 Bits BIOS Base Address Configuration */
#define BBAR_MASK 0x00ffff00 /* 8-23: Bottom of System Flash */
#define ICH8_REG_VSCC 0xC1 /* 32 Bits Vendor Specific Component Capabilities */
#define ICH9_REG_LVSCC 0xC4 /* 32 Bits Host Lower Vendor Specific Component Capabilities */
#define ICH9_REG_UVSCC 0xC8 /* 32 Bits Host Upper Vendor Specific Component Capabilities */
/* The individual fields of the VSCC registers are defined in the file
* ich_descriptors.h. The reason is that the same layout is also used in the
* flash descriptor to define the properties of the different flash chips
* supported. The BIOS (or the ME?) is responsible to populate the ICH registers
* with the information from the descriptor on startup depending on the actual
* chip(s) detected. */
#define ICH9_REG_FPB 0xD0 /* 32 Bits Flash Partition Boundary */
#define FPB_FPBA_OFF 0 /* 0-12: Block/Sector Erase Size */
#define FPB_FPBA (0x1FFF << FPB_FPBA_OFF)
#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
#define ICH7_REG_SPIS 0x00 /* 16 Bits */
#define SPIS_SCIP 0x0001
#define SPIS_GRANT 0x0002
#define SPIS_CDS 0x0004
#define SPIS_FCERR 0x0008
#define SPIS_RESERVED_MASK 0x7ff0
/* VIA SPI is compatible with ICH7, but maxdata
to transfer is 16 bytes.
DATA byte count on ICH7 is 8:13, on VIA 8:11
bit 12 is port select CS0 CS1
bit 13 is FAST READ enable
bit 7 is used with fast read and one shot controls CS de-assert?
*/
#define ICH7_REG_SPIC 0x02 /* 16 Bits */
#define SPIC_SCGO 0x0002
#define SPIC_ACS 0x0004
#define SPIC_SPOP 0x0008
#define SPIC_DS 0x4000
#define ICH7_REG_SPIA 0x04 /* 32 Bits */
#define ICH7_REG_SPID0 0x08 /* 64 Bytes */
#define ICH7_REG_PREOP 0x54 /* 16 Bits */
#define ICH7_REG_OPTYPE 0x56 /* 16 Bits */
#define ICH7_REG_OPMENU 0x58 /* 64 Bits */
enum ich_access_protection {
NO_PROT = 0,
READ_PROT = 1,
WRITE_PROT = 2,
LOCKED = 3,
};
FENG yu ning
committed
/* ICH SPI configuration lock-down. May be set during chipset enabling. */
FENG yu ning
committed
Stefan Tauner
committed
static enum ich_chipset ich_generation = CHIPSET_ICH_UNKNOWN;
static void *ich_spibar = NULL;
Carl-Daniel Hailfinger
committed
typedef struct _OPCODE {
uint8_t opcode; //This commands spi opcode
uint8_t spi_type; //This commands spi type
uint8_t atomic; //Use preop: (0: none, 1: preop0, 2: preop1
} OPCODE;
/* Suggested opcode definition:
* Preop 1: Write Enable
* Preop 2: Write Status register enable
*
* OP 0: Write address
* OP 1: Read Address
* OP 2: ERASE block
* OP 3: Read Status register
* OP 4: Read ID
* OP 5: Write Status register
* OP 6: chip private (read JEDEC id)
* OP 7: Chip erase
*/
typedef struct _OPCODES {
uint8_t preop[2];
OPCODE opcode[8];
} OPCODES;
static OPCODES *curopcodes = NULL;
static uint32_t REGREAD32(int X)
Carl-Daniel Hailfinger
committed
return mmio_readl(ich_spibar + X);
static uint16_t REGREAD16(int X)
Carl-Daniel Hailfinger
committed
return mmio_readw(ich_spibar + X);
static uint16_t REGREAD8(int X)
{
return mmio_readb(ich_spibar + X);
}
#define REGWRITE32(off, val) mmio_writel(val, ich_spibar+(off))
#define REGWRITE16(off, val) mmio_writew(val, ich_spibar+(off))
#define REGWRITE8(off, val) mmio_writeb(val, ich_spibar+(off))
static int find_opcode(OPCODES *op, uint8_t opcode);
static int find_preop(OPCODES *op, uint8_t preop);
static int program_opcodes(OPCODES *op, int enable_undo);
Carl-Daniel Hailfinger
committed
static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data);
/* for pairing opcodes with their required preop */
struct preop_opcode_pair {
uint8_t preop;
uint8_t opcode;
};
/* List of opcodes which need preopcodes and matching preopcodes. Unused. */
Carl-Daniel Hailfinger
committed
const struct preop_opcode_pair pops[] = {
{JEDEC_WREN, JEDEC_BYTE_PROGRAM},
{JEDEC_WREN, JEDEC_SE}, /* sector erase */
{JEDEC_WREN, JEDEC_BE_52}, /* block erase */
{JEDEC_WREN, JEDEC_BE_D8}, /* block erase */
{JEDEC_WREN, JEDEC_CE_60}, /* chip erase */
{JEDEC_WREN, JEDEC_CE_C7}, /* chip erase */
/* FIXME: WRSR requires either EWSR or WREN depending on chip type. */
{JEDEC_WREN, JEDEC_WRSR},
{JEDEC_EWSR, JEDEC_WRSR},
{0,}
};
/* Reasonable default configuration. Needs ad-hoc modifications if we
* encounter unlisted opcodes. Fun.
*/
Carl-Daniel Hailfinger
committed
static OPCODES O_ST_M25P = {
JEDEC_EWSR,
},
{JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Write Byte
{JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
{JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Erase Sector
{JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
{JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature
{JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Write Status Register
{JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
{JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Bulk erase
}
/* List of opcodes with their corresponding spi_type
* It is used to reprogram the chipset OPCODE table on-the-fly if an opcode
* is needed which is currently not in the chipset OPCODE table
*/
static OPCODE POSSIBLE_OPCODES[] = {
{JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Write Byte
{JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
{JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Erase Sector
{JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
{JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature
{JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Write Status Register
{JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
{JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Bulk erase
{JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Sector erase
{JEDEC_BE_52, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Block erase
{JEDEC_AAI_WORD_PROGRAM, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Auto Address Increment
};
Carl-Daniel Hailfinger
committed
static OPCODES O_EXISTING = {};
FENG yu ning
committed
/* pretty printing functions */
static void prettyprint_opcodes(OPCODES *ops)
{
OPCODE oc;
uint8_t i;
static const char *const spi_type[4] = {
"read w/o addr",
"write w/o addr",
"read w/ addr",
"write w/ addr"
};
static const char *const atomic_type[3] = {
"none",
" 0 ",
" 1 "
};
if (ops == NULL)
return;
msg_pdbg2(" OP Type Pre-OP\n");
for (i = 0; i < 8; i++) {
oc = ops->opcode[i];
t = (oc.spi_type > 3) ? "invalid" : spi_type[oc.spi_type];
a = (oc.atomic > 2) ? "invalid" : atomic_type[oc.atomic];
msg_pdbg2("op[%d]: 0x%02x, %s, %s\n", i, oc.opcode, t, a);
msg_pdbg2("Pre-OP 0: 0x%02x, Pre-OP 1: 0x%02x\n", ops->preop[0],
ops->preop[1]);
#define _pprint_reg(bit, mask, off, val, sep) msg_pdbg("%s=%d" sep, #bit, (val & mask) >> off)
#define pprint_reg(reg, bit, val, sep) _pprint_reg(bit, reg##_##bit, reg##_##bit##_OFF, val, sep)
static void prettyprint_ich9_reg_hsfs(uint16_t reg_val)
{
msg_pdbg("HSFS: ");
pprint_reg(HSFS, FDONE, reg_val, ", ");
pprint_reg(HSFS, FCERR, reg_val, ", ");
pprint_reg(HSFS, AEL, reg_val, ", ");
switch (ich_generation) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
break;
default:
pprint_reg(HSFS, BERASE, reg_val, ", ");
pprint_reg(HSFS, SCIP, reg_val, ", ");
switch (ich_generation) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
pprint_reg(HSFS, PRR34_LOCKDN, reg_val, ", ");
pprint_reg(HSFS, WRSDIS, reg_val, ", ");
break;
default:
break;
pprint_reg(HSFS, FDOPSS, reg_val, ", ");
pprint_reg(HSFS, FDV, reg_val, ", ");
pprint_reg(HSFS, FLOCKDN, reg_val, "\n");
}
static void prettyprint_ich9_reg_hsfc(uint16_t reg_val)
{
msg_pdbg("HSFC: ");
pprint_reg(HSFC, FGO, reg_val, ", ");
switch (ich_generation) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
_pprint_reg(HSFC, PCH100_HSFC_FCYCLE, PCH100_HSFC_FCYCLE_OFF, reg_val, ", ");
pprint_reg(HSFC, WET, reg_val, ", ");
break;
default:
pprint_reg(HSFC, FCYCLE, reg_val, ", ");
break;
pprint_reg(HSFC, FDBC, reg_val, ", ");
pprint_reg(HSFC, SME, reg_val, "\n");
}
static void prettyprint_ich9_reg_ssfs(uint32_t reg_val)
{
msg_pdbg("SSFS: ");
pprint_reg(SSFS, SCIP, reg_val, ", ");
pprint_reg(SSFS, FDONE, reg_val, ", ");
pprint_reg(SSFS, FCERR, reg_val, ", ");
pprint_reg(SSFS, AEL, reg_val, "\n");
}
static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
{
msg_pdbg("SSFC: ");
pprint_reg(SSFC, SCGO, reg_val, ", ");
pprint_reg(SSFC, ACS, reg_val, ", ");
pprint_reg(SSFC, SPOP, reg_val, ", ");
pprint_reg(SSFC, COP, reg_val, ", ");
pprint_reg(SSFC, DBC, reg_val, ", ");
pprint_reg(SSFC, SME, reg_val, ", ");
pprint_reg(SSFC, SCF, reg_val, "\n");
}
static void prettyprint_pch100_reg_dlock(const uint32_t reg_val)
{
msg_pdbg("DLOCK: ");
pprint_reg(DLOCK, BMWAG_LOCKDN, reg_val, ", ");
pprint_reg(DLOCK, BMRAG_LOCKDN, reg_val, ", ");
pprint_reg(DLOCK, SBMWAG_LOCKDN, reg_val, ", ");
pprint_reg(DLOCK, SBMRAG_LOCKDN, reg_val, ",\n ");
pprint_reg(DLOCK, PR0_LOCKDN, reg_val, ", ");
pprint_reg(DLOCK, PR1_LOCKDN, reg_val, ", ");
pprint_reg(DLOCK, PR2_LOCKDN, reg_val, ", ");
pprint_reg(DLOCK, PR3_LOCKDN, reg_val, ", ");
pprint_reg(DLOCK, PR4_LOCKDN, reg_val, ",\n ");
pprint_reg(DLOCK, SSEQ_LOCKDN, reg_val, "\n");
}
static struct {
size_t reg_ssfsc;
size_t reg_preop;
size_t reg_optype;
size_t reg_opmenu;
} swseq_data;
static uint8_t lookup_spi_type(uint8_t opcode)
{
for (a = 0; a < ARRAY_SIZE(POSSIBLE_OPCODES); a++) {
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
if (POSSIBLE_OPCODES[a].opcode == opcode)
return POSSIBLE_OPCODES[a].spi_type;
}
return 0xFF;
}
static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
{
uint8_t spi_type;
spi_type = lookup_spi_type(opcode);
if (spi_type > 3) {
/* Try to guess spi type from read/write sizes.
* The following valid writecnt/readcnt combinations exist:
* writecnt = 4, readcnt >= 0
* writecnt = 1, readcnt >= 0
* writecnt >= 4, readcnt = 0
* writecnt >= 1, readcnt = 0
* writecnt >= 1 is guaranteed for all commands.
*/
if (readcnt == 0)
/* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
* or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
* bytes are actual the address, they go to the bus anyhow
*/
spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
else if (writecnt == 1) // and readcnt is > 0
spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
else if (writecnt == 4) // and readcnt is > 0
spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
Stefan Tauner
committed
else // we have an invalid case
return SPI_INVALID_LENGTH;
}
int oppos = 2; // use original JEDEC_BE_D8 offset
curopcodes->opcode[oppos].opcode = opcode;
curopcodes->opcode[oppos].spi_type = spi_type;
program_opcodes(curopcodes, 0);
oppos = find_opcode(curopcodes, opcode);
msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
Stefan Tauner
committed
return oppos;
static int find_opcode(OPCODES *op, uint8_t opcode)
FENG yu ning
committed
{
int a;
if (op == NULL) {
msg_perr("\n%s: null OPCODES pointer!\n", __func__);
return -1;
}
FENG yu ning
committed
for (a = 0; a < 8; a++) {
if (op->opcode[a].opcode == opcode)
return a;
}
return -1;
}
static int find_preop(OPCODES *op, uint8_t preop)
FENG yu ning
committed
{
int a;
if (op == NULL) {
msg_perr("\n%s: null OPCODES pointer!\n", __func__);
return -1;
}
FENG yu ning
committed
for (a = 0; a < 2; a++) {
if (op->preop[a] == preop)
return a;
}
return -1;
}
/* Create a struct OPCODES based on what we find in the locked down chipset. */
FENG yu ning
committed
{
FENG yu ning
committed
uint16_t preop, optype;
uint32_t opmenu[2];
if (op == NULL) {
msg_perr("\n%s: null OPCODES pointer!\n", __func__);
FENG yu ning
committed
return -1;
}
Stefan Tauner
committed
switch (ich_generation) {
case CHIPSET_ICH7:
case CHIPSET_TUNNEL_CREEK:
case CHIPSET_CENTERTON:
FENG yu ning
committed
preop = REGREAD16(ICH7_REG_PREOP);
optype = REGREAD16(ICH7_REG_OPTYPE);
opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
break;
Stefan Tauner
committed
case CHIPSET_ICH8:
default: /* Future version might behave the same */
preop = REGREAD16(swseq_data.reg_preop);
optype = REGREAD16(swseq_data.reg_optype);
opmenu[0] = REGREAD32(swseq_data.reg_opmenu);
opmenu[1] = REGREAD32(swseq_data.reg_opmenu + 4);
FENG yu ning
committed
break;
}
op->preop[0] = (uint8_t) preop;
op->preop[1] = (uint8_t) (preop >> 8);
for (a = 0; a < 8; a++) {
op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
optype >>= 2;
}
for (a = 0; a < 4; a++) {
op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
opmenu[0] >>= 8;
}
for (a = 4; a < 8; a++) {
op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
opmenu[1] >>= 8;
}
/* No preopcodes used by default. */
for (a = 0; a < 8; a++)
FENG yu ning
committed
op->opcode[a].atomic = 0;
return 0;
}
static int program_opcodes(OPCODES *op, int enable_undo)
Stefan Reinauer
committed
uint16_t preop, optype;
uint32_t opmenu[2];
/* Program Prefix Opcodes */
/* 0:7 Prefix Opcode 1 */
Stefan Reinauer
committed
preop = (op->preop[0]);
Stefan Reinauer
committed
preop |= ((uint16_t) op->preop[1]) << 8;
Stefan Reinauer
committed
optype = 0;
Stefan Reinauer
committed
optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
Stefan Reinauer
committed
opmenu[0] = 0;
Stefan Reinauer
committed
opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
Stefan Reinauer
committed
opmenu[1] = 0;
Stefan Reinauer
committed
opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
Stefan Tauner
committed
switch (ich_generation) {
case CHIPSET_ICH7:
case CHIPSET_TUNNEL_CREEK:
case CHIPSET_CENTERTON:
/* Register undo only for enable_undo=1, i.e. first call. */
if (enable_undo) {
rmmio_valw(ich_spibar + ICH7_REG_PREOP);
rmmio_valw(ich_spibar + ICH7_REG_OPTYPE);
rmmio_vall(ich_spibar + ICH7_REG_OPMENU);
rmmio_vall(ich_spibar + ICH7_REG_OPMENU + 4);
}
mmio_writew(preop, ich_spibar + ICH7_REG_PREOP);
mmio_writew(optype, ich_spibar + ICH7_REG_OPTYPE);
mmio_writel(opmenu[0], ich_spibar + ICH7_REG_OPMENU);
mmio_writel(opmenu[1], ich_spibar + ICH7_REG_OPMENU + 4);
Stefan Reinauer
committed
break;
Stefan Tauner
committed
case CHIPSET_ICH8:
default: /* Future version might behave the same */
/* Register undo only for enable_undo=1, i.e. first call. */
if (enable_undo) {
rmmio_valw(ich_spibar + swseq_data.reg_preop);
rmmio_valw(ich_spibar + swseq_data.reg_optype);
rmmio_vall(ich_spibar + swseq_data.reg_opmenu);
rmmio_vall(ich_spibar + swseq_data.reg_opmenu + 4);
mmio_writew(preop, ich_spibar + swseq_data.reg_preop);
mmio_writew(optype, ich_spibar + swseq_data.reg_optype);
mmio_writel(opmenu[0], ich_spibar + swseq_data.reg_opmenu);
mmio_writel(opmenu[1], ich_spibar + swseq_data.reg_opmenu + 4);
Stefan Reinauer
committed
break;
/*
* Returns -1 if at least one mandatory opcode is inaccessible, 0 otherwise.
* FIXME: this should also check for
* - at least one probing opcode (RDID (incl. AT25F variants?), REMS, RES?)
* - at least one erasing opcode (lots.)
* - at least one program opcode (BYTE_PROGRAM, AAI_WORD_PROGRAM, ...?)
* - necessary preops? (EWSR, WREN, ...?)
*/
static int ich_missing_opcodes(void)
{
uint8_t ops[] = {
JEDEC_READ,
JEDEC_RDSR,
0
};
int i = 0;
while (ops[i] != 0) {
msg_pspew("checking for opcode 0x%02x\n", ops[i]);
if (find_opcode(curopcodes, ops[i]) == -1)
return -1;
i++;
}
return 0;
}
/*
* Try to set BBAR (BIOS Base Address Register), but read back the value in case
* it didn't stick.
*/
Stefan Tauner
committed
static void ich_set_bbar(uint32_t min_addr)
switch (ich_generation) {
Stefan Tauner
committed
case CHIPSET_ICH7:
case CHIPSET_TUNNEL_CREEK:
case CHIPSET_CENTERTON:
Stefan Tauner
committed
case CHIPSET_ICH8:
case CHIPSET_BAYTRAIL:
msg_pdbg("BBAR offset is unknown!\n");
Stefan Tauner
committed
case CHIPSET_ICH9:
default: /* Future version might behave the same */
ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & ~BBAR_MASK;
if (ichspi_bbar) {
msg_pdbg("Reserved bits in BBAR not zero: 0x%08x\n",
ichspi_bbar);
min_addr &= BBAR_MASK;
ichspi_bbar |= min_addr;
rmmio_writel(ichspi_bbar, ich_spibar + bbar_off);
ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & BBAR_MASK;
/* We don't have any option except complaining. And if the write
* failed, the restore will fail as well, so no problem there.
*/
if (ichspi_bbar != min_addr)
msg_perr("Setting BBAR to 0x%08x failed! New value: 0x%08x.\n",
min_addr, ichspi_bbar);
/* Read len bytes from the fdata/spid register into the data array.
*
* Note that using len > flash->mst->spi.max_data_read will return garbage or
* may even crash.
*/
Carl-Daniel Hailfinger
committed
static void ich_read_data(uint8_t *data, int len, int reg0_off)
int i;
uint32_t temp32 = 0;
for (i = 0; i < len; i++) {
if ((i % 4) == 0)
temp32 = REGREAD32(reg0_off + i);
data[i] = (temp32 >> ((i % 4) * 8)) & 0xff;
}
}
/* Fill len bytes from the data array into the fdata/spid registers.
*
* Note that using len > flash->mst->spi.max_data_write will trash the registers
* following the data registers.
*/
static void ich_fill_data(const uint8_t *data, int len, int reg0_off)
{
uint32_t temp32 = 0;
int i;
if (len <= 0)
return;
for (i = 0; i < len; i++) {
if ((i % 4) == 0)
temp32 = 0;
temp32 |= ((uint32_t) data[i]) << ((i % 4) * 8);
if ((i % 4) == 3) /* 32 bits are full, write them to regs. */
REGWRITE32(reg0_off + (i - (i % 4)), temp32);
}
i--;
if ((i % 4) != 3) /* Write remaining data to regs. */
REGWRITE32(reg0_off + (i - (i % 4)), temp32);
}
/* This function generates OPCODES from or programs OPCODES to ICH according to
* the chipset's SPI configuration lock.
FENG yu ning
committed
*
* It should be called before ICH sends any spi command.
FENG yu ning
committed
*/
static int ich_init_opcodes(void)
FENG yu ning
committed
{
int rc = 0;
OPCODES *curopcodes_done;
if (curopcodes)
return 0;
if (ichspi_lock) {
msg_pdbg("Reading OPCODES... ");
FENG yu ning
committed
curopcodes_done = &O_EXISTING;
FENG yu ning
committed
} else {
msg_pdbg("Programming OPCODES... ");
FENG yu ning
committed
curopcodes_done = &O_ST_M25P;
rc = program_opcodes(curopcodes_done, 1);
FENG yu ning
committed
}
if (rc) {
curopcodes = NULL;
msg_perr("failed\n");
FENG yu ning
committed
return 1;
} else {
curopcodes = curopcodes_done;
msg_pdbg("done\n");
prettyprint_opcodes(curopcodes);
FENG yu ning
committed
return 0;
}
}
Stefan Reinauer
committed
static int ich7_run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data, int maxdata)
uint32_t temp32;
Stefan Reinauer
committed
uint64_t opmenu;
int opcode_index;
/* Is it a write command? */
if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
|| (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
write_cmd = 1;
}
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
while ((REGREAD16(ICH7_REG_SPIS) & SPIS_SCIP) && --timeout) {
programmer_delay(10);
}
if (!timeout) {
msg_perr("Error: SCIP never cleared!\n");
return 1;
}
/* Program offset in flash into SPIA while preserving reserved bits. */
temp32 = REGREAD32(ICH7_REG_SPIA) & ~0x00FFFFFF;
REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF) | temp32);
/* Program data into SPID0 to N */
if (write_cmd && (datalength != 0))
ich_fill_data(data, datalength, ICH7_REG_SPID0);
temp16 = REGREAD16(ICH7_REG_SPIS);
/* keep reserved bits */
temp16 &= SPIS_RESERVED_MASK;
temp16 |= (SPIS_CDS | SPIS_FCERR);
REGWRITE16(ICH7_REG_SPIS, temp16);
/* Assemble SPIC */
temp16 = 0;
if (datalength != 0) {
temp16 |= SPIC_DS;
temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
Stefan Reinauer
committed
opmenu = REGREAD32(ICH7_REG_OPMENU);
opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
for (opcode_index = 0; opcode_index < 8; opcode_index++) {
if ((opmenu & 0xff) == op.opcode) {
Stefan Reinauer
committed
break;
}
opmenu >>= 8;
}
if (opcode_index == 8) {
msg_pdbg("Opcode %x not found.\n", op.opcode);
Stefan Reinauer
committed
return 1;
}
temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
/* Handle Atomic. Atomic commands include three steps:
- sending the preop (mainly EWSR or WREN)
- sending the main command
- waiting for the busy bit (WIP) to be cleared
This means the timeout must be sufficient for chip erase
of slow high-capacity chips.
switch (op.atomic) {
case 2:
/* Select second preop. */
temp16 |= SPIC_SPOP;
case 1:
/* Atomic command (preop+op) */
timeout = 100 * 1000 * 60; /* 60 seconds */
}
/* Start */
temp16 |= SPIC_SCGO;
/* write it */
REGWRITE16(ICH7_REG_SPIC, temp16);
/* Wait for Cycle Done Status or Flash Cycle Error. */
while (((REGREAD16(ICH7_REG_SPIS) & (SPIS_CDS | SPIS_FCERR)) == 0) &&
--timeout) {
msg_perr("timeout, ICH7_REG_SPIS=0x%04x\n",
REGREAD16(ICH7_REG_SPIS));
return 1;
/* FIXME: make sure we do not needlessly cause transaction errors. */
temp16 = REGREAD16(ICH7_REG_SPIS);
if (temp16 & SPIS_FCERR) {
msg_perr("Transaction error!\n");
/* keep reserved bits */
temp16 &= SPIS_RESERVED_MASK;
REGWRITE16(ICH7_REG_SPIS, temp16 | SPIS_FCERR);
if ((!write_cmd) && (datalength != 0))
ich_read_data(data, datalength, ICH7_REG_SPID0);
Stefan Reinauer
committed
static int ich9_run_opcode(OPCODE op, uint32_t offset,
Stefan Reinauer
committed
int timeout;
Stefan Reinauer
committed
uint64_t opmenu;
int opcode_index;
/* Is it a write command? */
if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
|| (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
write_cmd = 1;
}
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
while ((REGREAD8(swseq_data.reg_ssfsc) & SSFS_SCIP) && --timeout) {
programmer_delay(10);
}
if (!timeout) {
msg_perr("Error: SCIP never cleared!\n");
return 1;
}
/* Program offset in flash into FADDR while preserve the reserved bits
* and clearing the 25. address bit which is only useable in hwseq. */
temp32 = REGREAD32(ICH9_REG_FADDR) & ~0x01FFFFFF;
REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF) | temp32);
/* Program data into FDATA0 to N */
if (write_cmd && (datalength != 0))
ich_fill_data(data, datalength, ICH9_REG_FDATA0);
temp32 = REGREAD32(swseq_data.reg_ssfsc);
/* Keep reserved bits only */
temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
/* Clear cycle done and cycle error status registers */
temp32 |= (SSFS_FDONE | SSFS_FCERR);
REGWRITE32(swseq_data.reg_ssfsc, temp32);
/* Set data byte count (DBC) and data cycle bit (DS) */
if (datalength != 0) {
uint32_t datatemp;
temp32 |= SSFC_DS;
datatemp = ((((uint32_t)datalength - 1) << SSFC_DBC_OFF) &