xref: /aosp_15_r20/external/flashrom/ichspi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  *
4*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2008 Stefan Wildemann <[email protected]>
5*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2008 Claus Gindhart <[email protected]>
6*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2008 Dominik Geyer <[email protected]>
7*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2008 coresystems GmbH <[email protected]>
8*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
9*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2011 Stefan Tauner
10*0d6140beSAndroid Build Coastguard Worker  *
11*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
12*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
13*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; either version 2 of the License, or
14*0d6140beSAndroid Build Coastguard Worker  * (at your option) any later version.
15*0d6140beSAndroid Build Coastguard Worker  *
16*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
17*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
20*0d6140beSAndroid Build Coastguard Worker  */
21*0d6140beSAndroid Build Coastguard Worker 
22*0d6140beSAndroid Build Coastguard Worker #include <string.h>
23*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
24*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
25*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
26*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
27*0d6140beSAndroid Build Coastguard Worker #include "hwaccess_physmap.h"
28*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
29*0d6140beSAndroid Build Coastguard Worker #include "ich_descriptors.h"
30*0d6140beSAndroid Build Coastguard Worker #include "action_descriptor.h"
31*0d6140beSAndroid Build Coastguard Worker 
32*0d6140beSAndroid Build Coastguard Worker /* Apollo Lake */
33*0d6140beSAndroid Build Coastguard Worker #define APL_REG_FREG12		0xe0	/* 32 Bytes Flash Region 12 */
34*0d6140beSAndroid Build Coastguard Worker 
35*0d6140beSAndroid Build Coastguard Worker /* Sunrise Point */
36*0d6140beSAndroid Build Coastguard Worker 
37*0d6140beSAndroid Build Coastguard Worker /* Added HSFS Status bits */
38*0d6140beSAndroid Build Coastguard Worker #define HSFS_WRSDIS_OFF		11	/* 11: Flash Configuration Lock-Down */
39*0d6140beSAndroid Build Coastguard Worker #define HSFS_WRSDIS		(0x1 << HSFS_WRSDIS_OFF)
40*0d6140beSAndroid Build Coastguard Worker #define HSFS_PRR34_LOCKDN_OFF	12	/* 12: PRR3 PRR4 Lock-Down */
41*0d6140beSAndroid Build Coastguard Worker #define HSFS_PRR34_LOCKDN	(0x1 << HSFS_PRR34_LOCKDN_OFF)
42*0d6140beSAndroid Build Coastguard Worker /* HSFS_BERASE vanished */
43*0d6140beSAndroid Build Coastguard Worker 
44*0d6140beSAndroid Build Coastguard Worker /*
45*0d6140beSAndroid Build Coastguard Worker  * HSFC and HSFS 16-bit registers are combined into the 32-bit
46*0d6140beSAndroid Build Coastguard Worker  * BIOS_HSFSTS_CTL register in the Sunrise Point datasheet,
47*0d6140beSAndroid Build Coastguard Worker  * however we still treat them separately in order to reuse code.
48*0d6140beSAndroid Build Coastguard Worker  */
49*0d6140beSAndroid Build Coastguard Worker 
50*0d6140beSAndroid Build Coastguard Worker /*
51*0d6140beSAndroid Build Coastguard Worker  * HSFC Control bits
52*0d6140beSAndroid Build Coastguard Worker  *
53*0d6140beSAndroid Build Coastguard Worker  * FCYCLE is a 2 bit field (HSFC bits 1-2) on ICH9 and 4 bit field
54*0d6140beSAndroid Build Coastguard Worker  * (HSFC bits 1-4) on PCH100.
55*0d6140beSAndroid Build Coastguard Worker  *
56*0d6140beSAndroid Build Coastguard Worker  * ICH9 and PCH100 use the same FCYCLE values for flash operations,
57*0d6140beSAndroid Build Coastguard Worker  * however FCYCLE values above 3 are only supported by PCH100.
58*0d6140beSAndroid Build Coastguard Worker  *
59*0d6140beSAndroid Build Coastguard Worker  * 0: SPI Read
60*0d6140beSAndroid Build Coastguard Worker  * 2: SPI Write
61*0d6140beSAndroid Build Coastguard Worker  * 3: SPI Erase 4K
62*0d6140beSAndroid Build Coastguard Worker  * 4: SPI Erase 64K
63*0d6140beSAndroid Build Coastguard Worker  * 6: SPI RDID
64*0d6140beSAndroid Build Coastguard Worker  * 7: SPI Write Status
65*0d6140beSAndroid Build Coastguard Worker  * 8: SPI Read Status
66*0d6140beSAndroid Build Coastguard Worker  */
67*0d6140beSAndroid Build Coastguard Worker #define HSFC_FGO_OFF		0
68*0d6140beSAndroid Build Coastguard Worker #define HSFC_FGO		(0x1 << HSFC_FGO_OFF)
69*0d6140beSAndroid Build Coastguard Worker #define HSFC_FCYCLE_MASK(n)	((n) << HSFC_FCYCLE_OFF)
70*0d6140beSAndroid Build Coastguard Worker #define HSFC_FCYCLE_OFF		1
71*0d6140beSAndroid Build Coastguard Worker #define HSFC_CYCLE_READ		HSFC_FCYCLE_MASK(0x0)
72*0d6140beSAndroid Build Coastguard Worker #define HSFC_CYCLE_WRITE	HSFC_FCYCLE_MASK(0x2)
73*0d6140beSAndroid Build Coastguard Worker #define HSFC_CYCLE_BLOCK_ERASE	HSFC_FCYCLE_MASK(0x3)
74*0d6140beSAndroid Build Coastguard Worker #define HSFC_CYCLE_RDID		HSFC_FCYCLE_MASK(0x6)
75*0d6140beSAndroid Build Coastguard Worker #define HSFC_CYCLE_WR_STATUS	HSFC_FCYCLE_MASK(0x7)
76*0d6140beSAndroid Build Coastguard Worker #define HSFC_CYCLE_RD_STATUS	HSFC_FCYCLE_MASK(0x8)
77*0d6140beSAndroid Build Coastguard Worker 
78*0d6140beSAndroid Build Coastguard Worker /* PCH100 controller register definition */
79*0d6140beSAndroid Build Coastguard Worker #define PCH100_HSFC_FCYCLE_OFF		1
80*0d6140beSAndroid Build Coastguard Worker #define PCH100_HSFC_FCYCLE_BIT_WIDTH	0xf
81*0d6140beSAndroid Build Coastguard Worker #define PCH100_HSFC_FCYCLE	HSFC_FCYCLE_MASK(PCH100_HSFC_FCYCLE_BIT_WIDTH)
82*0d6140beSAndroid Build Coastguard Worker /* New HSFC Control bit */
83*0d6140beSAndroid Build Coastguard Worker #define PCH100_HSFC_WET_OFF	(21 - 16)	/* 5: Write Enable Type */
84*0d6140beSAndroid Build Coastguard Worker #define PCH100_HSFC_WET		(0x1 << PCH100_HSFC_WET_OFF)
85*0d6140beSAndroid Build Coastguard Worker 
86*0d6140beSAndroid Build Coastguard Worker #define PCH100_FADDR_FLA	0x07ffffff
87*0d6140beSAndroid Build Coastguard Worker 
88*0d6140beSAndroid Build Coastguard Worker #define PCH100_REG_DLOCK	0x0c	/* 32 Bits Discrete Lock Bits */
89*0d6140beSAndroid Build Coastguard Worker #define DLOCK_BMWAG_LOCKDN_OFF	0
90*0d6140beSAndroid Build Coastguard Worker #define DLOCK_BMWAG_LOCKDN	(0x1 << DLOCK_BMWAG_LOCKDN_OFF)
91*0d6140beSAndroid Build Coastguard Worker #define DLOCK_BMRAG_LOCKDN_OFF	1
92*0d6140beSAndroid Build Coastguard Worker #define DLOCK_BMRAG_LOCKDN	(0x1 << DLOCK_BMRAG_LOCKDN_OFF)
93*0d6140beSAndroid Build Coastguard Worker #define DLOCK_SBMWAG_LOCKDN_OFF	2
94*0d6140beSAndroid Build Coastguard Worker #define DLOCK_SBMWAG_LOCKDN	(0x1 << DLOCK_SBMWAG_LOCKDN_OFF)
95*0d6140beSAndroid Build Coastguard Worker #define DLOCK_SBMRAG_LOCKDN_OFF	3
96*0d6140beSAndroid Build Coastguard Worker #define DLOCK_SBMRAG_LOCKDN	(0x1 << DLOCK_SBMRAG_LOCKDN_OFF)
97*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR0_LOCKDN_OFF	8
98*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR0_LOCKDN	(0x1 << DLOCK_PR0_LOCKDN_OFF)
99*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR1_LOCKDN_OFF	9
100*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR1_LOCKDN	(0x1 << DLOCK_PR1_LOCKDN_OFF)
101*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR2_LOCKDN_OFF	10
102*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR2_LOCKDN	(0x1 << DLOCK_PR2_LOCKDN_OFF)
103*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR3_LOCKDN_OFF	11
104*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR3_LOCKDN	(0x1 << DLOCK_PR3_LOCKDN_OFF)
105*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR4_LOCKDN_OFF	12
106*0d6140beSAndroid Build Coastguard Worker #define DLOCK_PR4_LOCKDN	(0x1 << DLOCK_PR4_LOCKDN_OFF)
107*0d6140beSAndroid Build Coastguard Worker #define DLOCK_SSEQ_LOCKDN_OFF	16
108*0d6140beSAndroid Build Coastguard Worker #define DLOCK_SSEQ_LOCKDN	(0x1 << DLOCK_SSEQ_LOCKDN_OFF)
109*0d6140beSAndroid Build Coastguard Worker 
110*0d6140beSAndroid Build Coastguard Worker #define PCH100_REG_FPR0		0x84	/* 32 Bits Protected Range 0 */
111*0d6140beSAndroid Build Coastguard Worker #define PCH100_REG_GPR0		0x98	/* 32 Bits Global Protected Range 0 */
112*0d6140beSAndroid Build Coastguard Worker 
113*0d6140beSAndroid Build Coastguard Worker #define PCH100_REG_SSFSC	0xA0	/* 32 Bits Status (8) + Control (24) */
114*0d6140beSAndroid Build Coastguard Worker #define PCH100_REG_PREOP	0xA4	/* 16 Bits */
115*0d6140beSAndroid Build Coastguard Worker #define PCH100_REG_OPTYPE	0xA6	/* 16 Bits */
116*0d6140beSAndroid Build Coastguard Worker #define PCH100_REG_OPMENU	0xA8	/* 64 Bits */
117*0d6140beSAndroid Build Coastguard Worker 
118*0d6140beSAndroid Build Coastguard Worker /* ICH9 controller register definition */
119*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_HSFS		0x04	/* 16 Bits Hardware Sequencing Flash Status */
120*0d6140beSAndroid Build Coastguard Worker #define HSFS_FDONE_OFF		0	/* 0: Flash Cycle Done */
121*0d6140beSAndroid Build Coastguard Worker #define HSFS_FDONE		(0x1 << HSFS_FDONE_OFF)
122*0d6140beSAndroid Build Coastguard Worker #define HSFS_FCERR_OFF		1	/* 1: Flash Cycle Error */
123*0d6140beSAndroid Build Coastguard Worker #define HSFS_FCERR		(0x1 << HSFS_FCERR_OFF)
124*0d6140beSAndroid Build Coastguard Worker #define HSFS_AEL_OFF		2	/* 2: Access Error Log */
125*0d6140beSAndroid Build Coastguard Worker #define HSFS_AEL		(0x1 << HSFS_AEL_OFF)
126*0d6140beSAndroid Build Coastguard Worker #define HSFS_BERASE_OFF		3	/* 3-4: Block/Sector Erase Size */
127*0d6140beSAndroid Build Coastguard Worker #define HSFS_BERASE		(0x3 << HSFS_BERASE_OFF)
128*0d6140beSAndroid Build Coastguard Worker #define HSFS_SCIP_OFF		5	/* 5: SPI Cycle In Progress */
129*0d6140beSAndroid Build Coastguard Worker #define HSFS_SCIP		(0x1 << HSFS_SCIP_OFF)
130*0d6140beSAndroid Build Coastguard Worker 					/* 6-12: reserved */
131*0d6140beSAndroid Build Coastguard Worker #define HSFS_FDOPSS_OFF		13	/* 13: Flash Descriptor Override Pin-Strap Status */
132*0d6140beSAndroid Build Coastguard Worker #define HSFS_FDOPSS		(0x1 << HSFS_FDOPSS_OFF)
133*0d6140beSAndroid Build Coastguard Worker #define HSFS_FDV_OFF		14	/* 14: Flash Descriptor Valid */
134*0d6140beSAndroid Build Coastguard Worker #define HSFS_FDV		(0x1 << HSFS_FDV_OFF)
135*0d6140beSAndroid Build Coastguard Worker #define HSFS_FLOCKDN_OFF	15	/* 15: Flash Configuration Lock-Down */
136*0d6140beSAndroid Build Coastguard Worker #define HSFS_FLOCKDN		(0x1 << HSFS_FLOCKDN_OFF)
137*0d6140beSAndroid Build Coastguard Worker 
138*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_HSFC		0x06	/* 16 Bits Hardware Sequencing Flash Control */
139*0d6140beSAndroid Build Coastguard Worker 
140*0d6140beSAndroid Build Coastguard Worker 					/* 0: Flash Cycle Go */
141*0d6140beSAndroid Build Coastguard Worker 					/* 1-2: FLASH Cycle */
142*0d6140beSAndroid Build Coastguard Worker #define ICH9_HSFC_FCYCLE_OFF		1
143*0d6140beSAndroid Build Coastguard Worker #define ICH9_HSFC_FCYCLE_BIT_WIDTH	3
144*0d6140beSAndroid Build Coastguard Worker #define ICH9_HSFC_FCYCLE	HSFC_FCYCLE_MASK(ICH9_HSFC_FCYCLE_BIT_WIDTH)
145*0d6140beSAndroid Build Coastguard Worker 					/* 3-7: reserved */
146*0d6140beSAndroid Build Coastguard Worker #define HSFC_FDBC_OFF		8	/* 8-13: Flash Data Byte Count */
147*0d6140beSAndroid Build Coastguard Worker #define HSFC_FDBC		(0x3f << HSFC_FDBC_OFF)
148*0d6140beSAndroid Build Coastguard Worker #define HSFC_FDBC_VAL(n)	(((n) << HSFC_FDBC_OFF) & HSFC_FDBC)
149*0d6140beSAndroid Build Coastguard Worker 					/* 14: reserved */
150*0d6140beSAndroid Build Coastguard Worker #define HSFC_SME_OFF		15	/* 15: SPI SMI# Enable */
151*0d6140beSAndroid Build Coastguard Worker #define HSFC_SME		(0x1 << HSFC_SME_OFF)
152*0d6140beSAndroid Build Coastguard Worker 
153*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_FADDR		0x08	/* 32 Bits */
154*0d6140beSAndroid Build Coastguard Worker #define ICH9_FADDR_FLA		0x01ffffff
155*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_FDATA0		0x10	/* 64 Bytes */
156*0d6140beSAndroid Build Coastguard Worker 
157*0d6140beSAndroid Build Coastguard Worker #define ICH_REG_BIOS_BM_RAP	0x118	/* 16 Bits BIOS Master Read Access Permissions */
158*0d6140beSAndroid Build Coastguard Worker #define ICH_REG_BIOS_BM_WAP	0x11c	/* 16 Bits BIOS Master Write Access Permissions */
159*0d6140beSAndroid Build Coastguard Worker 
160*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_FRAP		0x50	/* 32 Bytes Flash Region Access Permissions */
161*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_FREG0		0x54	/* 32 Bytes Flash Region 0 */
162*0d6140beSAndroid Build Coastguard Worker 
163*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_PR0		0x74	/* 32 Bytes Protected Range 0 */
164*0d6140beSAndroid Build Coastguard Worker #define PR_WP_OFF		31	/* 31: write protection enable */
165*0d6140beSAndroid Build Coastguard Worker #define PR_RP_OFF		15	/* 15: read protection enable */
166*0d6140beSAndroid Build Coastguard Worker 
167*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_SSFS		0x90	/* 08 Bits */
168*0d6140beSAndroid Build Coastguard Worker #define SSFS_SCIP_OFF		0	/* SPI Cycle In Progress */
169*0d6140beSAndroid Build Coastguard Worker #define SSFS_SCIP		(0x1 << SSFS_SCIP_OFF)
170*0d6140beSAndroid Build Coastguard Worker #define SSFS_FDONE_OFF		2	/* Cycle Done Status */
171*0d6140beSAndroid Build Coastguard Worker #define SSFS_FDONE		(0x1 << SSFS_FDONE_OFF)
172*0d6140beSAndroid Build Coastguard Worker #define SSFS_FCERR_OFF		3	/* Flash Cycle Error */
173*0d6140beSAndroid Build Coastguard Worker #define SSFS_FCERR		(0x1 << SSFS_FCERR_OFF)
174*0d6140beSAndroid Build Coastguard Worker #define SSFS_AEL_OFF		4	/* Access Error Log */
175*0d6140beSAndroid Build Coastguard Worker #define SSFS_AEL		(0x1 << SSFS_AEL_OFF)
176*0d6140beSAndroid Build Coastguard Worker /* The following bits are reserved in SSFS: 1,5-7. */
177*0d6140beSAndroid Build Coastguard Worker #define SSFS_RESERVED_MASK	0x000000e2
178*0d6140beSAndroid Build Coastguard Worker 
179*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_SSFC		0x91	/* 24 Bits */
180*0d6140beSAndroid Build Coastguard Worker /* We combine SSFS and SSFC to one 32-bit word,
181*0d6140beSAndroid Build Coastguard Worker  * therefore SSFC bits are off by 8. */
182*0d6140beSAndroid Build Coastguard Worker 						/* 0: reserved */
183*0d6140beSAndroid Build Coastguard Worker #define SSFC_SCGO_OFF		(1 + 8)		/* 1: SPI Cycle Go */
184*0d6140beSAndroid Build Coastguard Worker #define SSFC_SCGO		(0x1 << SSFC_SCGO_OFF)
185*0d6140beSAndroid Build Coastguard Worker #define SSFC_ACS_OFF		(2 + 8)		/* 2: Atomic Cycle Sequence */
186*0d6140beSAndroid Build Coastguard Worker #define SSFC_ACS		(0x1 << SSFC_ACS_OFF)
187*0d6140beSAndroid Build Coastguard Worker #define SSFC_SPOP_OFF		(3 + 8)		/* 3: Sequence Prefix Opcode Pointer */
188*0d6140beSAndroid Build Coastguard Worker #define SSFC_SPOP		(0x1 << SSFC_SPOP_OFF)
189*0d6140beSAndroid Build Coastguard Worker #define SSFC_COP_OFF		(4 + 8)		/* 4-6: Cycle Opcode Pointer */
190*0d6140beSAndroid Build Coastguard Worker #define SSFC_COP		(0x7 << SSFC_COP_OFF)
191*0d6140beSAndroid Build Coastguard Worker 						/* 7: reserved */
192*0d6140beSAndroid Build Coastguard Worker #define SSFC_DBC_OFF		(8 + 8)		/* 8-13: Data Byte Count */
193*0d6140beSAndroid Build Coastguard Worker #define SSFC_DBC		(0x3f << SSFC_DBC_OFF)
194*0d6140beSAndroid Build Coastguard Worker #define SSFC_DS_OFF		(14 + 8)	/* 14: Data Cycle */
195*0d6140beSAndroid Build Coastguard Worker #define SSFC_DS			(0x1 << SSFC_DS_OFF)
196*0d6140beSAndroid Build Coastguard Worker #define SSFC_SME_OFF		(15 + 8)	/* 15: SPI SMI# Enable */
197*0d6140beSAndroid Build Coastguard Worker #define SSFC_SME		(0x1 << SSFC_SME_OFF)
198*0d6140beSAndroid Build Coastguard Worker #define SSFC_SCF_OFF		(16 + 8)	/* 16-18: SPI Cycle Frequency */
199*0d6140beSAndroid Build Coastguard Worker #define SSFC_SCF		(0x7 << SSFC_SCF_OFF)
200*0d6140beSAndroid Build Coastguard Worker #define SSFC_SCF_20MHZ		0x00000000
201*0d6140beSAndroid Build Coastguard Worker #define SSFC_SCF_33MHZ		0x01000000
202*0d6140beSAndroid Build Coastguard Worker 						/* 19-23: reserved */
203*0d6140beSAndroid Build Coastguard Worker #define SSFC_RESERVED_MASK	0xf8008100
204*0d6140beSAndroid Build Coastguard Worker 
205*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_PREOP		0x94	/* 16 Bits */
206*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_OPTYPE		0x96	/* 16 Bits */
207*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_OPMENU		0x98	/* 64 Bits */
208*0d6140beSAndroid Build Coastguard Worker 
209*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_BBAR		0xA0	/* 32 Bits BIOS Base Address Configuration */
210*0d6140beSAndroid Build Coastguard Worker #define BBAR_MASK	0x00ffff00		/* 8-23: Bottom of System Flash */
211*0d6140beSAndroid Build Coastguard Worker 
212*0d6140beSAndroid Build Coastguard Worker #define ICH8_REG_VSCC		0xC1	/* 32 Bits Vendor Specific Component Capabilities */
213*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_LVSCC		0xC4	/* 32 Bits Host Lower Vendor Specific Component Capabilities */
214*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_UVSCC		0xC8	/* 32 Bits Host Upper Vendor Specific Component Capabilities */
215*0d6140beSAndroid Build Coastguard Worker /* The individual fields of the VSCC registers are defined in the file
216*0d6140beSAndroid Build Coastguard Worker  * ich_descriptors.h. The reason is that the same layout is also used in the
217*0d6140beSAndroid Build Coastguard Worker  * flash descriptor to define the properties of the different flash chips
218*0d6140beSAndroid Build Coastguard Worker  * supported. The BIOS (or the ME?) is responsible to populate the ICH registers
219*0d6140beSAndroid Build Coastguard Worker  * with the information from the descriptor on startup depending on the actual
220*0d6140beSAndroid Build Coastguard Worker  * chip(s) detected. */
221*0d6140beSAndroid Build Coastguard Worker 
222*0d6140beSAndroid Build Coastguard Worker #define ICH9_REG_FPB		0xD0	/* 32 Bits Flash Partition Boundary */
223*0d6140beSAndroid Build Coastguard Worker #define FPB_FPBA_OFF		0	/* 0-12: Block/Sector Erase Size */
224*0d6140beSAndroid Build Coastguard Worker #define FPB_FPBA			(0x1FFF << FPB_FPBA_OFF)
225*0d6140beSAndroid Build Coastguard Worker 
226*0d6140beSAndroid Build Coastguard Worker // ICH9R SPI commands
227*0d6140beSAndroid Build Coastguard Worker #define SPI_OPCODE_TYPE_READ_NO_ADDRESS		0
228*0d6140beSAndroid Build Coastguard Worker #define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS	1
229*0d6140beSAndroid Build Coastguard Worker #define SPI_OPCODE_TYPE_READ_WITH_ADDRESS	2
230*0d6140beSAndroid Build Coastguard Worker #define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS	3
231*0d6140beSAndroid Build Coastguard Worker 
232*0d6140beSAndroid Build Coastguard Worker // ICH7 registers
233*0d6140beSAndroid Build Coastguard Worker #define ICH7_REG_SPIS		0x00	/* 16 Bits */
234*0d6140beSAndroid Build Coastguard Worker #define SPIS_SCIP		0x0001
235*0d6140beSAndroid Build Coastguard Worker #define SPIS_GRANT		0x0002
236*0d6140beSAndroid Build Coastguard Worker #define SPIS_CDS		0x0004
237*0d6140beSAndroid Build Coastguard Worker #define SPIS_FCERR		0x0008
238*0d6140beSAndroid Build Coastguard Worker #define SPIS_RESERVED_MASK	0x7ff0
239*0d6140beSAndroid Build Coastguard Worker 
240*0d6140beSAndroid Build Coastguard Worker /* VIA SPI is compatible with ICH7, but maxdata
241*0d6140beSAndroid Build Coastguard Worker    to transfer is 16 bytes.
242*0d6140beSAndroid Build Coastguard Worker 
243*0d6140beSAndroid Build Coastguard Worker    DATA byte count on ICH7 is 8:13, on VIA 8:11
244*0d6140beSAndroid Build Coastguard Worker 
245*0d6140beSAndroid Build Coastguard Worker    bit 12 is port select CS0 CS1
246*0d6140beSAndroid Build Coastguard Worker    bit 13 is FAST READ enable
247*0d6140beSAndroid Build Coastguard Worker    bit 7  is used with fast read and one shot controls CS de-assert?
248*0d6140beSAndroid Build Coastguard Worker */
249*0d6140beSAndroid Build Coastguard Worker 
250*0d6140beSAndroid Build Coastguard Worker #define ICH7_REG_SPIC		0x02	/* 16 Bits */
251*0d6140beSAndroid Build Coastguard Worker #define SPIC_SCGO		0x0002
252*0d6140beSAndroid Build Coastguard Worker #define SPIC_ACS		0x0004
253*0d6140beSAndroid Build Coastguard Worker #define SPIC_SPOP		0x0008
254*0d6140beSAndroid Build Coastguard Worker #define SPIC_DS			0x4000
255*0d6140beSAndroid Build Coastguard Worker 
256*0d6140beSAndroid Build Coastguard Worker #define ICH7_REG_SPIA		0x04	/* 32 Bits */
257*0d6140beSAndroid Build Coastguard Worker #define ICH7_REG_SPID0		0x08	/* 64 Bytes */
258*0d6140beSAndroid Build Coastguard Worker #define ICH7_REG_PREOP		0x54	/* 16 Bits */
259*0d6140beSAndroid Build Coastguard Worker #define ICH7_REG_OPTYPE		0x56	/* 16 Bits */
260*0d6140beSAndroid Build Coastguard Worker #define ICH7_REG_OPMENU		0x58	/* 64 Bits */
261*0d6140beSAndroid Build Coastguard Worker 
262*0d6140beSAndroid Build Coastguard Worker enum ich_access_protection {
263*0d6140beSAndroid Build Coastguard Worker 	NO_PROT		= 0,
264*0d6140beSAndroid Build Coastguard Worker 	READ_PROT	= 1,
265*0d6140beSAndroid Build Coastguard Worker 	WRITE_PROT	= 2,
266*0d6140beSAndroid Build Coastguard Worker 	LOCKED		= 3,
267*0d6140beSAndroid Build Coastguard Worker };
268*0d6140beSAndroid Build Coastguard Worker 
269*0d6140beSAndroid Build Coastguard Worker /* ICH SPI configuration lock-down. May be set during chipset enabling. */
270*0d6140beSAndroid Build Coastguard Worker static bool ichspi_lock = false;
271*0d6140beSAndroid Build Coastguard Worker 
272*0d6140beSAndroid Build Coastguard Worker enum ich_chipset ich_generation = CHIPSET_ICH_UNKNOWN;
273*0d6140beSAndroid Build Coastguard Worker static uint32_t ichspi_bbar;
274*0d6140beSAndroid Build Coastguard Worker 
275*0d6140beSAndroid Build Coastguard Worker static void *ich_spibar = NULL;
276*0d6140beSAndroid Build Coastguard Worker 
277*0d6140beSAndroid Build Coastguard Worker typedef struct _OPCODE {
278*0d6140beSAndroid Build Coastguard Worker 	uint8_t opcode;		//This commands spi opcode
279*0d6140beSAndroid Build Coastguard Worker 	uint8_t spi_type;	//This commands spi type
280*0d6140beSAndroid Build Coastguard Worker 	uint8_t atomic;		//Use preop: (0: none, 1: preop0, 2: preop1
281*0d6140beSAndroid Build Coastguard Worker } OPCODE;
282*0d6140beSAndroid Build Coastguard Worker 
283*0d6140beSAndroid Build Coastguard Worker /* Suggested opcode definition:
284*0d6140beSAndroid Build Coastguard Worker  * Preop 1: Write Enable
285*0d6140beSAndroid Build Coastguard Worker  * Preop 2: Write Status register enable
286*0d6140beSAndroid Build Coastguard Worker  *
287*0d6140beSAndroid Build Coastguard Worker  * OP 0: Write address
288*0d6140beSAndroid Build Coastguard Worker  * OP 1: Read Address
289*0d6140beSAndroid Build Coastguard Worker  * OP 2: ERASE block
290*0d6140beSAndroid Build Coastguard Worker  * OP 3: Read Status register
291*0d6140beSAndroid Build Coastguard Worker  * OP 4: Read ID
292*0d6140beSAndroid Build Coastguard Worker  * OP 5: Write Status register
293*0d6140beSAndroid Build Coastguard Worker  * OP 6: chip private (read JEDEC id)
294*0d6140beSAndroid Build Coastguard Worker  * OP 7: Chip erase
295*0d6140beSAndroid Build Coastguard Worker  */
296*0d6140beSAndroid Build Coastguard Worker typedef struct _OPCODES {
297*0d6140beSAndroid Build Coastguard Worker 	uint8_t preop[2];
298*0d6140beSAndroid Build Coastguard Worker 	OPCODE opcode[8];
299*0d6140beSAndroid Build Coastguard Worker } OPCODES;
300*0d6140beSAndroid Build Coastguard Worker 
301*0d6140beSAndroid Build Coastguard Worker static OPCODES *curopcodes = NULL;
302*0d6140beSAndroid Build Coastguard Worker 
303*0d6140beSAndroid Build Coastguard Worker /* HW access functions */
REGREAD32(int X)304*0d6140beSAndroid Build Coastguard Worker static uint32_t REGREAD32(int X)
305*0d6140beSAndroid Build Coastguard Worker {
306*0d6140beSAndroid Build Coastguard Worker 	return mmio_readl(ich_spibar + X);
307*0d6140beSAndroid Build Coastguard Worker }
308*0d6140beSAndroid Build Coastguard Worker 
REGREAD16(int X)309*0d6140beSAndroid Build Coastguard Worker static uint16_t REGREAD16(int X)
310*0d6140beSAndroid Build Coastguard Worker {
311*0d6140beSAndroid Build Coastguard Worker 	return mmio_readw(ich_spibar + X);
312*0d6140beSAndroid Build Coastguard Worker }
313*0d6140beSAndroid Build Coastguard Worker 
REGREAD8(int X)314*0d6140beSAndroid Build Coastguard Worker static uint16_t REGREAD8(int X)
315*0d6140beSAndroid Build Coastguard Worker {
316*0d6140beSAndroid Build Coastguard Worker 	return mmio_readb(ich_spibar + X);
317*0d6140beSAndroid Build Coastguard Worker }
318*0d6140beSAndroid Build Coastguard Worker 
319*0d6140beSAndroid Build Coastguard Worker #define REGWRITE32(off, val) mmio_writel(val, ich_spibar+(off))
320*0d6140beSAndroid Build Coastguard Worker #define REGWRITE16(off, val) mmio_writew(val, ich_spibar+(off))
321*0d6140beSAndroid Build Coastguard Worker #define REGWRITE8(off, val)  mmio_writeb(val, ich_spibar+(off))
322*0d6140beSAndroid Build Coastguard Worker 
323*0d6140beSAndroid Build Coastguard Worker /* Common SPI functions */
324*0d6140beSAndroid Build Coastguard Worker 
find_opcode(OPCODES * op,uint8_t opcode)325*0d6140beSAndroid Build Coastguard Worker static int find_opcode(OPCODES *op, uint8_t opcode)
326*0d6140beSAndroid Build Coastguard Worker {
327*0d6140beSAndroid Build Coastguard Worker 	int a;
328*0d6140beSAndroid Build Coastguard Worker 
329*0d6140beSAndroid Build Coastguard Worker 	if (op == NULL) {
330*0d6140beSAndroid Build Coastguard Worker 		msg_perr("\n%s: null OPCODES pointer!\n", __func__);
331*0d6140beSAndroid Build Coastguard Worker 		return -1;
332*0d6140beSAndroid Build Coastguard Worker 	}
333*0d6140beSAndroid Build Coastguard Worker 
334*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < 8; a++) {
335*0d6140beSAndroid Build Coastguard Worker 		if (op->opcode[a].opcode == opcode)
336*0d6140beSAndroid Build Coastguard Worker 			return a;
337*0d6140beSAndroid Build Coastguard Worker 	}
338*0d6140beSAndroid Build Coastguard Worker 
339*0d6140beSAndroid Build Coastguard Worker 	return -1;
340*0d6140beSAndroid Build Coastguard Worker }
341*0d6140beSAndroid Build Coastguard Worker 
find_preop(OPCODES * op,uint8_t preop)342*0d6140beSAndroid Build Coastguard Worker static int find_preop(OPCODES *op, uint8_t preop)
343*0d6140beSAndroid Build Coastguard Worker {
344*0d6140beSAndroid Build Coastguard Worker 	int a;
345*0d6140beSAndroid Build Coastguard Worker 
346*0d6140beSAndroid Build Coastguard Worker 	if (op == NULL) {
347*0d6140beSAndroid Build Coastguard Worker 		msg_perr("\n%s: null OPCODES pointer!\n", __func__);
348*0d6140beSAndroid Build Coastguard Worker 		return -1;
349*0d6140beSAndroid Build Coastguard Worker 	}
350*0d6140beSAndroid Build Coastguard Worker 
351*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < 2; a++) {
352*0d6140beSAndroid Build Coastguard Worker 		if (op->preop[a] == preop)
353*0d6140beSAndroid Build Coastguard Worker 			return a;
354*0d6140beSAndroid Build Coastguard Worker 	}
355*0d6140beSAndroid Build Coastguard Worker 
356*0d6140beSAndroid Build Coastguard Worker 	return -1;
357*0d6140beSAndroid Build Coastguard Worker }
358*0d6140beSAndroid Build Coastguard Worker 
359*0d6140beSAndroid Build Coastguard Worker /* for pairing opcodes with their required preop */
360*0d6140beSAndroid Build Coastguard Worker struct preop_opcode_pair {
361*0d6140beSAndroid Build Coastguard Worker 	uint8_t preop;
362*0d6140beSAndroid Build Coastguard Worker 	uint8_t opcode;
363*0d6140beSAndroid Build Coastguard Worker };
364*0d6140beSAndroid Build Coastguard Worker 
365*0d6140beSAndroid Build Coastguard Worker /* List of opcodes which need preopcodes and matching preopcodes. Unused. */
366*0d6140beSAndroid Build Coastguard Worker const struct preop_opcode_pair pops[] = {
367*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_WREN, JEDEC_BYTE_PROGRAM},
368*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_WREN, JEDEC_SE}, /* sector erase */
369*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_WREN, JEDEC_BE_52}, /* block erase */
370*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_WREN, JEDEC_BE_D8}, /* block erase */
371*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_WREN, JEDEC_CE_60}, /* chip erase */
372*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_WREN, JEDEC_CE_C7}, /* chip erase */
373*0d6140beSAndroid Build Coastguard Worker 	 /* FIXME: WRSR requires either EWSR or WREN depending on chip type. */
374*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_WREN, JEDEC_WRSR},
375*0d6140beSAndroid Build Coastguard Worker 	{JEDEC_EWSR, JEDEC_WRSR},
376*0d6140beSAndroid Build Coastguard Worker 	{0,}
377*0d6140beSAndroid Build Coastguard Worker };
378*0d6140beSAndroid Build Coastguard Worker 
379*0d6140beSAndroid Build Coastguard Worker /* Reasonable default configuration. Needs ad-hoc modifications if we
380*0d6140beSAndroid Build Coastguard Worker  * encounter unlisted opcodes. Fun.
381*0d6140beSAndroid Build Coastguard Worker  */
382*0d6140beSAndroid Build Coastguard Worker static OPCODES O_ST_M25P = {
383*0d6140beSAndroid Build Coastguard Worker 	{
384*0d6140beSAndroid Build Coastguard Worker 	 JEDEC_WREN,
385*0d6140beSAndroid Build Coastguard Worker 	 JEDEC_EWSR,
386*0d6140beSAndroid Build Coastguard Worker 	},
387*0d6140beSAndroid Build Coastguard Worker 	{
388*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Write Byte
389*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Data
390*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Erase Sector
391*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read Device Status Reg
392*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Electronic Manufacturer Signature
393*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Write Status Register
394*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read JDEC ID
395*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Bulk erase
396*0d6140beSAndroid Build Coastguard Worker 	}
397*0d6140beSAndroid Build Coastguard Worker };
398*0d6140beSAndroid Build Coastguard Worker 
399*0d6140beSAndroid Build Coastguard Worker /* List of opcodes with their corresponding spi_type
400*0d6140beSAndroid Build Coastguard Worker  * It is used to reprogram the chipset OPCODE table on-the-fly if an opcode
401*0d6140beSAndroid Build Coastguard Worker  * is needed which is currently not in the chipset OPCODE table
402*0d6140beSAndroid Build Coastguard Worker  */
403*0d6140beSAndroid Build Coastguard Worker static const OPCODE POSSIBLE_OPCODES[] = {
404*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Write Byte
405*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Data
406*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Erase Sector
407*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read Device Status Reg
408*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0},	// Read Electronic Manufacturer Signature
409*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Write Status Register
410*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0},	// Read JDEC ID
411*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Bulk erase
412*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Sector erase
413*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_BE_52, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0},	// Block erase
414*0d6140beSAndroid Build Coastguard Worker 	 {JEDEC_AAI_WORD_PROGRAM, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0},	// Auto Address Increment
415*0d6140beSAndroid Build Coastguard Worker };
416*0d6140beSAndroid Build Coastguard Worker 
417*0d6140beSAndroid Build Coastguard Worker static OPCODES O_EXISTING = {};
418*0d6140beSAndroid Build Coastguard Worker 
419*0d6140beSAndroid Build Coastguard Worker /* pretty printing functions */
prettyprint_opcodes(OPCODES * ops)420*0d6140beSAndroid Build Coastguard Worker static void prettyprint_opcodes(OPCODES *ops)
421*0d6140beSAndroid Build Coastguard Worker {
422*0d6140beSAndroid Build Coastguard Worker 	OPCODE oc;
423*0d6140beSAndroid Build Coastguard Worker 	const char *t;
424*0d6140beSAndroid Build Coastguard Worker 	const char *a;
425*0d6140beSAndroid Build Coastguard Worker 	uint8_t i;
426*0d6140beSAndroid Build Coastguard Worker 	static const char *const spi_type[4] = {
427*0d6140beSAndroid Build Coastguard Worker 		"read  w/o addr",
428*0d6140beSAndroid Build Coastguard Worker 		"write w/o addr",
429*0d6140beSAndroid Build Coastguard Worker 		"read  w/  addr",
430*0d6140beSAndroid Build Coastguard Worker 		"write w/  addr"
431*0d6140beSAndroid Build Coastguard Worker 	};
432*0d6140beSAndroid Build Coastguard Worker 	static const char *const atomic_type[3] = {
433*0d6140beSAndroid Build Coastguard Worker 		"none",
434*0d6140beSAndroid Build Coastguard Worker 		" 0  ",
435*0d6140beSAndroid Build Coastguard Worker 		" 1  "
436*0d6140beSAndroid Build Coastguard Worker 	};
437*0d6140beSAndroid Build Coastguard Worker 
438*0d6140beSAndroid Build Coastguard Worker 	if (ops == NULL)
439*0d6140beSAndroid Build Coastguard Worker 		return;
440*0d6140beSAndroid Build Coastguard Worker 
441*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("        OP        Type      Pre-OP\n");
442*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < 8; i++) {
443*0d6140beSAndroid Build Coastguard Worker 		oc = ops->opcode[i];
444*0d6140beSAndroid Build Coastguard Worker 		t = (oc.spi_type > 3) ? "invalid" : spi_type[oc.spi_type];
445*0d6140beSAndroid Build Coastguard Worker 		a = (oc.atomic > 2) ? "invalid" : atomic_type[oc.atomic];
446*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg2("op[%d]: 0x%02x, %s, %s\n", i, oc.opcode, t, a);
447*0d6140beSAndroid Build Coastguard Worker 	}
448*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("Pre-OP 0: 0x%02x, Pre-OP 1: 0x%02x\n", ops->preop[0],
449*0d6140beSAndroid Build Coastguard Worker 		 ops->preop[1]);
450*0d6140beSAndroid Build Coastguard Worker }
451*0d6140beSAndroid Build Coastguard Worker 
452*0d6140beSAndroid Build Coastguard Worker #define pprint_reg16(reg, bit, val, sep) msg_pdbg("%s=%"PRId16"" sep, #bit, (val & reg##_##bit) >> reg##_##bit##_OFF)
453*0d6140beSAndroid Build Coastguard Worker #define pprint_reg32(reg, bit, val, sep) msg_pdbg("%s=%"PRId32"" sep, #bit, (val & reg##_##bit) >> reg##_##bit##_OFF)
454*0d6140beSAndroid Build Coastguard Worker 
prettyprint_ich9_reg_hsfs(uint16_t reg_val,enum ich_chipset ich_gen)455*0d6140beSAndroid Build Coastguard Worker static void prettyprint_ich9_reg_hsfs(uint16_t reg_val, enum ich_chipset ich_gen)
456*0d6140beSAndroid Build Coastguard Worker {
457*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("HSFS: ");
458*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFS, FDONE, reg_val, ", ");
459*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFS, FCERR, reg_val, ", ");
460*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFS, AEL, reg_val, ", ");
461*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
462*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_100_SERIES_SUNRISE_POINT:
463*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C620_SERIES_LEWISBURG:
464*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C740_SERIES_EMMITSBURG:
465*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_300_SERIES_CANNON_POINT:
466*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_400_SERIES_COMET_POINT:
467*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_500_SERIES_TIGER_POINT:
468*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ELKHART_LAKE:
469*0d6140beSAndroid Build Coastguard Worker 		break;
470*0d6140beSAndroid Build Coastguard Worker 	default:
471*0d6140beSAndroid Build Coastguard Worker 		pprint_reg16(HSFS, BERASE, reg_val, ", ");
472*0d6140beSAndroid Build Coastguard Worker 		break;
473*0d6140beSAndroid Build Coastguard Worker 	}
474*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFS, SCIP, reg_val, ", ");
475*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
476*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_100_SERIES_SUNRISE_POINT:
477*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C620_SERIES_LEWISBURG:
478*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C740_SERIES_EMMITSBURG:
479*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_300_SERIES_CANNON_POINT:
480*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_400_SERIES_COMET_POINT:
481*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_500_SERIES_TIGER_POINT:
482*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ELKHART_LAKE:
483*0d6140beSAndroid Build Coastguard Worker 		pprint_reg16(HSFS, PRR34_LOCKDN, reg_val, ", ");
484*0d6140beSAndroid Build Coastguard Worker 		pprint_reg16(HSFS, WRSDIS, reg_val, ", ");
485*0d6140beSAndroid Build Coastguard Worker 		break;
486*0d6140beSAndroid Build Coastguard Worker 	default:
487*0d6140beSAndroid Build Coastguard Worker 		break;
488*0d6140beSAndroid Build Coastguard Worker 	}
489*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFS, FDOPSS, reg_val, ", ");
490*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFS, FDV, reg_val, ", ");
491*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFS, FLOCKDN, reg_val, "\n");
492*0d6140beSAndroid Build Coastguard Worker }
493*0d6140beSAndroid Build Coastguard Worker 
prettyprint_ich9_reg_hsfc(uint16_t reg_val,enum ich_chipset ich_gen)494*0d6140beSAndroid Build Coastguard Worker static void prettyprint_ich9_reg_hsfc(uint16_t reg_val, enum ich_chipset ich_gen)
495*0d6140beSAndroid Build Coastguard Worker {
496*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("HSFC: ");
497*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFC, FGO, reg_val, ", ");
498*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
499*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_100_SERIES_SUNRISE_POINT:
500*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C620_SERIES_LEWISBURG:
501*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C740_SERIES_EMMITSBURG:
502*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_300_SERIES_CANNON_POINT:
503*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_400_SERIES_COMET_POINT:
504*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_500_SERIES_TIGER_POINT:
505*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ELKHART_LAKE:
506*0d6140beSAndroid Build Coastguard Worker 		pprint_reg16(PCH100_HSFC, FCYCLE, reg_val, ", ");
507*0d6140beSAndroid Build Coastguard Worker 		pprint_reg16(PCH100_HSFC, WET, reg_val, ", ");
508*0d6140beSAndroid Build Coastguard Worker 		break;
509*0d6140beSAndroid Build Coastguard Worker 	default:
510*0d6140beSAndroid Build Coastguard Worker 		pprint_reg16(ICH9_HSFC, FCYCLE, reg_val, ", ");
511*0d6140beSAndroid Build Coastguard Worker 		break;
512*0d6140beSAndroid Build Coastguard Worker 	}
513*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFC, FDBC, reg_val, ", ");
514*0d6140beSAndroid Build Coastguard Worker 	pprint_reg16(HSFC, SME, reg_val, "\n");
515*0d6140beSAndroid Build Coastguard Worker }
516*0d6140beSAndroid Build Coastguard Worker 
prettyprint_ich9_reg_ssfs(uint32_t reg_val)517*0d6140beSAndroid Build Coastguard Worker static void prettyprint_ich9_reg_ssfs(uint32_t reg_val)
518*0d6140beSAndroid Build Coastguard Worker {
519*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("SSFS: ");
520*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFS, SCIP, reg_val, ", ");
521*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFS, FDONE, reg_val, ", ");
522*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFS, FCERR, reg_val, ", ");
523*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFS, AEL, reg_val, "\n");
524*0d6140beSAndroid Build Coastguard Worker }
525*0d6140beSAndroid Build Coastguard Worker 
prettyprint_ich9_reg_ssfc(uint32_t reg_val)526*0d6140beSAndroid Build Coastguard Worker static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
527*0d6140beSAndroid Build Coastguard Worker {
528*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("SSFC: ");
529*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFC, SCGO, reg_val, ", ");
530*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFC, ACS, reg_val, ", ");
531*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFC, SPOP, reg_val, ", ");
532*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFC, COP, reg_val, ", ");
533*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFC, DBC, reg_val, ", ");
534*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFC, SME, reg_val, ", ");
535*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(SSFC, SCF, reg_val, "\n");
536*0d6140beSAndroid Build Coastguard Worker }
537*0d6140beSAndroid Build Coastguard Worker 
prettyprint_pch100_reg_dlock(const uint32_t reg_val)538*0d6140beSAndroid Build Coastguard Worker static void prettyprint_pch100_reg_dlock(const uint32_t reg_val)
539*0d6140beSAndroid Build Coastguard Worker {
540*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("DLOCK: ");
541*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, BMWAG_LOCKDN, reg_val, ", ");
542*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, BMRAG_LOCKDN, reg_val, ", ");
543*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, SBMWAG_LOCKDN, reg_val, ", ");
544*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, SBMRAG_LOCKDN, reg_val, ",\n       ");
545*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, PR0_LOCKDN, reg_val, ", ");
546*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, PR1_LOCKDN, reg_val, ", ");
547*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, PR2_LOCKDN, reg_val, ", ");
548*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, PR3_LOCKDN, reg_val, ", ");
549*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, PR4_LOCKDN, reg_val, ",\n       ");
550*0d6140beSAndroid Build Coastguard Worker 	pprint_reg32(DLOCK, SSEQ_LOCKDN, reg_val, "\n");
551*0d6140beSAndroid Build Coastguard Worker }
552*0d6140beSAndroid Build Coastguard Worker 
553*0d6140beSAndroid Build Coastguard Worker static struct swseq_data {
554*0d6140beSAndroid Build Coastguard Worker 	size_t reg_ssfsc;
555*0d6140beSAndroid Build Coastguard Worker 	size_t reg_preop;
556*0d6140beSAndroid Build Coastguard Worker 	size_t reg_optype;
557*0d6140beSAndroid Build Coastguard Worker 	size_t reg_opmenu;
558*0d6140beSAndroid Build Coastguard Worker } swseq_data;
559*0d6140beSAndroid Build Coastguard Worker 
lookup_spi_type(uint8_t opcode)560*0d6140beSAndroid Build Coastguard Worker static uint8_t lookup_spi_type(uint8_t opcode)
561*0d6140beSAndroid Build Coastguard Worker {
562*0d6140beSAndroid Build Coastguard Worker 	unsigned int a;
563*0d6140beSAndroid Build Coastguard Worker 
564*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < ARRAY_SIZE(POSSIBLE_OPCODES); a++) {
565*0d6140beSAndroid Build Coastguard Worker 		if (POSSIBLE_OPCODES[a].opcode == opcode)
566*0d6140beSAndroid Build Coastguard Worker 			return POSSIBLE_OPCODES[a].spi_type;
567*0d6140beSAndroid Build Coastguard Worker 	}
568*0d6140beSAndroid Build Coastguard Worker 
569*0d6140beSAndroid Build Coastguard Worker 	return 0xFF;
570*0d6140beSAndroid Build Coastguard Worker }
571*0d6140beSAndroid Build Coastguard Worker 
program_opcodes(OPCODES * op,int enable_undo,enum ich_chipset ich_gen)572*0d6140beSAndroid Build Coastguard Worker static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_gen)
573*0d6140beSAndroid Build Coastguard Worker {
574*0d6140beSAndroid Build Coastguard Worker 	uint8_t a;
575*0d6140beSAndroid Build Coastguard Worker 	uint16_t preop, optype;
576*0d6140beSAndroid Build Coastguard Worker 	uint32_t opmenu[2];
577*0d6140beSAndroid Build Coastguard Worker 
578*0d6140beSAndroid Build Coastguard Worker 	/* Program Prefix Opcodes */
579*0d6140beSAndroid Build Coastguard Worker 	/* 0:7 Prefix Opcode 1 */
580*0d6140beSAndroid Build Coastguard Worker 	preop = (op->preop[0]);
581*0d6140beSAndroid Build Coastguard Worker 	/* 8:16 Prefix Opcode 2 */
582*0d6140beSAndroid Build Coastguard Worker 	preop |= ((uint16_t) op->preop[1]) << 8;
583*0d6140beSAndroid Build Coastguard Worker 
584*0d6140beSAndroid Build Coastguard Worker 	/* Program Opcode Types 0 - 7 */
585*0d6140beSAndroid Build Coastguard Worker 	optype = 0;
586*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < 8; a++) {
587*0d6140beSAndroid Build Coastguard Worker 		optype |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
588*0d6140beSAndroid Build Coastguard Worker 	}
589*0d6140beSAndroid Build Coastguard Worker 
590*0d6140beSAndroid Build Coastguard Worker 	/* Program Allowable Opcodes 0 - 3 */
591*0d6140beSAndroid Build Coastguard Worker 	opmenu[0] = 0;
592*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < 4; a++) {
593*0d6140beSAndroid Build Coastguard Worker 		opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
594*0d6140beSAndroid Build Coastguard Worker 	}
595*0d6140beSAndroid Build Coastguard Worker 
596*0d6140beSAndroid Build Coastguard Worker 	/* Program Allowable Opcodes 4 - 7 */
597*0d6140beSAndroid Build Coastguard Worker 	opmenu[1] = 0;
598*0d6140beSAndroid Build Coastguard Worker 	for (a = 4; a < 8; a++) {
599*0d6140beSAndroid Build Coastguard Worker 		opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
600*0d6140beSAndroid Build Coastguard Worker 	}
601*0d6140beSAndroid Build Coastguard Worker 
602*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08"PRIx32"%08"PRIx32"\n", __func__, preop, optype, opmenu[0], opmenu[1]);
603*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
604*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH7:
605*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_TUNNEL_CREEK:
606*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_CENTERTON:
607*0d6140beSAndroid Build Coastguard Worker 		/* Register undo only for enable_undo=1, i.e. first call. */
608*0d6140beSAndroid Build Coastguard Worker 		if (enable_undo) {
609*0d6140beSAndroid Build Coastguard Worker 			rmmio_valw(ich_spibar + ICH7_REG_PREOP);
610*0d6140beSAndroid Build Coastguard Worker 			rmmio_valw(ich_spibar + ICH7_REG_OPTYPE);
611*0d6140beSAndroid Build Coastguard Worker 			rmmio_vall(ich_spibar + ICH7_REG_OPMENU);
612*0d6140beSAndroid Build Coastguard Worker 			rmmio_vall(ich_spibar + ICH7_REG_OPMENU + 4);
613*0d6140beSAndroid Build Coastguard Worker 		}
614*0d6140beSAndroid Build Coastguard Worker 		mmio_writew(preop, ich_spibar + ICH7_REG_PREOP);
615*0d6140beSAndroid Build Coastguard Worker 		mmio_writew(optype, ich_spibar + ICH7_REG_OPTYPE);
616*0d6140beSAndroid Build Coastguard Worker 		mmio_writel(opmenu[0], ich_spibar + ICH7_REG_OPMENU);
617*0d6140beSAndroid Build Coastguard Worker 		mmio_writel(opmenu[1], ich_spibar + ICH7_REG_OPMENU + 4);
618*0d6140beSAndroid Build Coastguard Worker 		break;
619*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH8:
620*0d6140beSAndroid Build Coastguard Worker 	default:		/* Future version might behave the same */
621*0d6140beSAndroid Build Coastguard Worker 		/* Register undo only for enable_undo=1, i.e. first call. */
622*0d6140beSAndroid Build Coastguard Worker 		if (enable_undo) {
623*0d6140beSAndroid Build Coastguard Worker 			rmmio_valw(ich_spibar + swseq_data.reg_preop);
624*0d6140beSAndroid Build Coastguard Worker 			rmmio_valw(ich_spibar + swseq_data.reg_optype);
625*0d6140beSAndroid Build Coastguard Worker 			rmmio_vall(ich_spibar + swseq_data.reg_opmenu);
626*0d6140beSAndroid Build Coastguard Worker 			rmmio_vall(ich_spibar + swseq_data.reg_opmenu + 4);
627*0d6140beSAndroid Build Coastguard Worker 		}
628*0d6140beSAndroid Build Coastguard Worker 		mmio_writew(preop, ich_spibar + swseq_data.reg_preop);
629*0d6140beSAndroid Build Coastguard Worker 		mmio_writew(optype, ich_spibar + swseq_data.reg_optype);
630*0d6140beSAndroid Build Coastguard Worker 		mmio_writel(opmenu[0], ich_spibar + swseq_data.reg_opmenu);
631*0d6140beSAndroid Build Coastguard Worker 		mmio_writel(opmenu[1], ich_spibar + swseq_data.reg_opmenu + 4);
632*0d6140beSAndroid Build Coastguard Worker 		break;
633*0d6140beSAndroid Build Coastguard Worker 	}
634*0d6140beSAndroid Build Coastguard Worker 
635*0d6140beSAndroid Build Coastguard Worker 	return 0;
636*0d6140beSAndroid Build Coastguard Worker }
637*0d6140beSAndroid Build Coastguard Worker 
reprogram_opcode_on_the_fly(uint8_t opcode,unsigned int writecnt,unsigned int readcnt)638*0d6140beSAndroid Build Coastguard Worker static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
639*0d6140beSAndroid Build Coastguard Worker {
640*0d6140beSAndroid Build Coastguard Worker 	uint8_t spi_type;
641*0d6140beSAndroid Build Coastguard Worker 
642*0d6140beSAndroid Build Coastguard Worker 	spi_type = lookup_spi_type(opcode);
643*0d6140beSAndroid Build Coastguard Worker 	if (spi_type > 3) {
644*0d6140beSAndroid Build Coastguard Worker 		/* Try to guess spi type from read/write sizes.
645*0d6140beSAndroid Build Coastguard Worker 		 * The following valid writecnt/readcnt combinations exist:
646*0d6140beSAndroid Build Coastguard Worker 		 * writecnt  = 4, readcnt >= 0
647*0d6140beSAndroid Build Coastguard Worker 		 * writecnt  = 1, readcnt >= 0
648*0d6140beSAndroid Build Coastguard Worker 		 * writecnt >= 4, readcnt  = 0
649*0d6140beSAndroid Build Coastguard Worker 		 * writecnt >= 1, readcnt  = 0
650*0d6140beSAndroid Build Coastguard Worker 		 * writecnt >= 1 is guaranteed for all commands.
651*0d6140beSAndroid Build Coastguard Worker 		 */
652*0d6140beSAndroid Build Coastguard Worker 		if (readcnt == 0)
653*0d6140beSAndroid Build Coastguard Worker 			/* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
654*0d6140beSAndroid Build Coastguard Worker 			 * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
655*0d6140beSAndroid Build Coastguard Worker 			 * bytes are actual the address, they go to the bus anyhow
656*0d6140beSAndroid Build Coastguard Worker 			 */
657*0d6140beSAndroid Build Coastguard Worker 			spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
658*0d6140beSAndroid Build Coastguard Worker 		else if (writecnt == 1) // and readcnt is > 0
659*0d6140beSAndroid Build Coastguard Worker 			spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
660*0d6140beSAndroid Build Coastguard Worker 		else if (writecnt == 4) // and readcnt is > 0
661*0d6140beSAndroid Build Coastguard Worker 			spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
662*0d6140beSAndroid Build Coastguard Worker 		else // we have an invalid case
663*0d6140beSAndroid Build Coastguard Worker 			return SPI_INVALID_LENGTH;
664*0d6140beSAndroid Build Coastguard Worker 	}
665*0d6140beSAndroid Build Coastguard Worker 	int oppos = 4;	// use the original position of JEDEC_REMS
666*0d6140beSAndroid Build Coastguard Worker 	curopcodes->opcode[oppos].opcode = opcode;
667*0d6140beSAndroid Build Coastguard Worker 	curopcodes->opcode[oppos].spi_type = spi_type;
668*0d6140beSAndroid Build Coastguard Worker 	program_opcodes(curopcodes, 0, ich_generation);
669*0d6140beSAndroid Build Coastguard Worker 	oppos = find_opcode(curopcodes, opcode);
670*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
671*0d6140beSAndroid Build Coastguard Worker 	return oppos;
672*0d6140beSAndroid Build Coastguard Worker }
673*0d6140beSAndroid Build Coastguard Worker 
674*0d6140beSAndroid Build Coastguard Worker /*
675*0d6140beSAndroid Build Coastguard Worker  * Returns -1 if at least one mandatory opcode is inaccessible, 0 otherwise.
676*0d6140beSAndroid Build Coastguard Worker  * FIXME: this should also check for
677*0d6140beSAndroid Build Coastguard Worker  *   - at least one probing opcode (RDID (incl. AT25F variants?), REMS, RES?)
678*0d6140beSAndroid Build Coastguard Worker  *   - at least one erasing opcode (lots.)
679*0d6140beSAndroid Build Coastguard Worker  *   - at least one program opcode (BYTE_PROGRAM, AAI_WORD_PROGRAM, ...?)
680*0d6140beSAndroid Build Coastguard Worker  *   - necessary preops? (EWSR, WREN, ...?)
681*0d6140beSAndroid Build Coastguard Worker  */
ich_missing_opcodes(void)682*0d6140beSAndroid Build Coastguard Worker static int ich_missing_opcodes(void)
683*0d6140beSAndroid Build Coastguard Worker {
684*0d6140beSAndroid Build Coastguard Worker 	uint8_t ops[] = {
685*0d6140beSAndroid Build Coastguard Worker 		JEDEC_READ,
686*0d6140beSAndroid Build Coastguard Worker 		JEDEC_RDSR,
687*0d6140beSAndroid Build Coastguard Worker 		0
688*0d6140beSAndroid Build Coastguard Worker 	};
689*0d6140beSAndroid Build Coastguard Worker 	int i = 0;
690*0d6140beSAndroid Build Coastguard Worker 	while (ops[i] != 0) {
691*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("checking for opcode 0x%02x\n", ops[i]);
692*0d6140beSAndroid Build Coastguard Worker 		if (find_opcode(curopcodes, ops[i]) == -1)
693*0d6140beSAndroid Build Coastguard Worker 			return -1;
694*0d6140beSAndroid Build Coastguard Worker 		i++;
695*0d6140beSAndroid Build Coastguard Worker 	}
696*0d6140beSAndroid Build Coastguard Worker 	return 0;
697*0d6140beSAndroid Build Coastguard Worker }
698*0d6140beSAndroid Build Coastguard Worker 
699*0d6140beSAndroid Build Coastguard Worker /*
700*0d6140beSAndroid Build Coastguard Worker  * Try to set BBAR (BIOS Base Address Register), but read back the value in case
701*0d6140beSAndroid Build Coastguard Worker  * it didn't stick.
702*0d6140beSAndroid Build Coastguard Worker  */
ich_set_bbar(uint32_t min_addr,enum ich_chipset ich_gen)703*0d6140beSAndroid Build Coastguard Worker static void ich_set_bbar(uint32_t min_addr, enum ich_chipset ich_gen)
704*0d6140beSAndroid Build Coastguard Worker {
705*0d6140beSAndroid Build Coastguard Worker 	int bbar_off;
706*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
707*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH7:
708*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_TUNNEL_CREEK:
709*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_CENTERTON:
710*0d6140beSAndroid Build Coastguard Worker 		bbar_off = 0x50;
711*0d6140beSAndroid Build Coastguard Worker 		break;
712*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH8:
713*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_BAYTRAIL:
714*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("BBAR offset is unknown!\n");
715*0d6140beSAndroid Build Coastguard Worker 		return;
716*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH9:
717*0d6140beSAndroid Build Coastguard Worker 	default:		/* Future version might behave the same */
718*0d6140beSAndroid Build Coastguard Worker 		bbar_off = ICH9_REG_BBAR;
719*0d6140beSAndroid Build Coastguard Worker 		break;
720*0d6140beSAndroid Build Coastguard Worker 	}
721*0d6140beSAndroid Build Coastguard Worker 
722*0d6140beSAndroid Build Coastguard Worker 	ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & ~BBAR_MASK;
723*0d6140beSAndroid Build Coastguard Worker 	if (ichspi_bbar) {
724*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Reserved bits in BBAR not zero: 0x%08"PRIx32"\n",
725*0d6140beSAndroid Build Coastguard Worker 			 ichspi_bbar);
726*0d6140beSAndroid Build Coastguard Worker 	}
727*0d6140beSAndroid Build Coastguard Worker 	min_addr &= BBAR_MASK;
728*0d6140beSAndroid Build Coastguard Worker 	ichspi_bbar |= min_addr;
729*0d6140beSAndroid Build Coastguard Worker 	rmmio_writel(ichspi_bbar, ich_spibar + bbar_off);
730*0d6140beSAndroid Build Coastguard Worker 	ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & BBAR_MASK;
731*0d6140beSAndroid Build Coastguard Worker 
732*0d6140beSAndroid Build Coastguard Worker 	/* We don't have any option except complaining. And if the write
733*0d6140beSAndroid Build Coastguard Worker 	 * failed, the restore will fail as well, so no problem there.
734*0d6140beSAndroid Build Coastguard Worker 	 */
735*0d6140beSAndroid Build Coastguard Worker 	if (ichspi_bbar != min_addr)
736*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Setting BBAR to 0x%08"PRIx32" failed! New value: 0x%08"PRIx32".\n",
737*0d6140beSAndroid Build Coastguard Worker 			 min_addr, ichspi_bbar);
738*0d6140beSAndroid Build Coastguard Worker }
739*0d6140beSAndroid Build Coastguard Worker 
740*0d6140beSAndroid Build Coastguard Worker /* Create a struct OPCODES based on what we find in the locked down chipset. */
generate_opcodes(OPCODES * op,enum ich_chipset ich_gen)741*0d6140beSAndroid Build Coastguard Worker static int generate_opcodes(OPCODES * op, enum ich_chipset ich_gen)
742*0d6140beSAndroid Build Coastguard Worker {
743*0d6140beSAndroid Build Coastguard Worker 	int a;
744*0d6140beSAndroid Build Coastguard Worker 	uint16_t preop, optype;
745*0d6140beSAndroid Build Coastguard Worker 	uint32_t opmenu[2];
746*0d6140beSAndroid Build Coastguard Worker 
747*0d6140beSAndroid Build Coastguard Worker 	if (op == NULL) {
748*0d6140beSAndroid Build Coastguard Worker 		msg_perr("\n%s: null OPCODES pointer!\n", __func__);
749*0d6140beSAndroid Build Coastguard Worker 		return -1;
750*0d6140beSAndroid Build Coastguard Worker 	}
751*0d6140beSAndroid Build Coastguard Worker 
752*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
753*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH7:
754*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_TUNNEL_CREEK:
755*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_CENTERTON:
756*0d6140beSAndroid Build Coastguard Worker 		preop = REGREAD16(ICH7_REG_PREOP);
757*0d6140beSAndroid Build Coastguard Worker 		optype = REGREAD16(ICH7_REG_OPTYPE);
758*0d6140beSAndroid Build Coastguard Worker 		opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
759*0d6140beSAndroid Build Coastguard Worker 		opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
760*0d6140beSAndroid Build Coastguard Worker 		break;
761*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH8:
762*0d6140beSAndroid Build Coastguard Worker 	default:		/* Future version might behave the same */
763*0d6140beSAndroid Build Coastguard Worker 		preop = REGREAD16(swseq_data.reg_preop);
764*0d6140beSAndroid Build Coastguard Worker 		optype = REGREAD16(swseq_data.reg_optype);
765*0d6140beSAndroid Build Coastguard Worker 		opmenu[0] = REGREAD32(swseq_data.reg_opmenu);
766*0d6140beSAndroid Build Coastguard Worker 		opmenu[1] = REGREAD32(swseq_data.reg_opmenu + 4);
767*0d6140beSAndroid Build Coastguard Worker 		break;
768*0d6140beSAndroid Build Coastguard Worker 	}
769*0d6140beSAndroid Build Coastguard Worker 
770*0d6140beSAndroid Build Coastguard Worker 	op->preop[0] = (uint8_t) preop;
771*0d6140beSAndroid Build Coastguard Worker 	op->preop[1] = (uint8_t) (preop >> 8);
772*0d6140beSAndroid Build Coastguard Worker 
773*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < 8; a++) {
774*0d6140beSAndroid Build Coastguard Worker 		op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
775*0d6140beSAndroid Build Coastguard Worker 		optype >>= 2;
776*0d6140beSAndroid Build Coastguard Worker 	}
777*0d6140beSAndroid Build Coastguard Worker 
778*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < 4; a++) {
779*0d6140beSAndroid Build Coastguard Worker 		op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
780*0d6140beSAndroid Build Coastguard Worker 		opmenu[0] >>= 8;
781*0d6140beSAndroid Build Coastguard Worker 	}
782*0d6140beSAndroid Build Coastguard Worker 
783*0d6140beSAndroid Build Coastguard Worker 	for (a = 4; a < 8; a++) {
784*0d6140beSAndroid Build Coastguard Worker 		op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
785*0d6140beSAndroid Build Coastguard Worker 		opmenu[1] >>= 8;
786*0d6140beSAndroid Build Coastguard Worker 	}
787*0d6140beSAndroid Build Coastguard Worker 
788*0d6140beSAndroid Build Coastguard Worker 	/* No preopcodes used by default. */
789*0d6140beSAndroid Build Coastguard Worker 	for (a = 0; a < 8; a++)
790*0d6140beSAndroid Build Coastguard Worker 		op->opcode[a].atomic = 0;
791*0d6140beSAndroid Build Coastguard Worker 
792*0d6140beSAndroid Build Coastguard Worker 	return 0;
793*0d6140beSAndroid Build Coastguard Worker }
794*0d6140beSAndroid Build Coastguard Worker 
795*0d6140beSAndroid Build Coastguard Worker /* This function generates OPCODES from or programs OPCODES to ICH according to
796*0d6140beSAndroid Build Coastguard Worker  * the chipset's SPI configuration lock.
797*0d6140beSAndroid Build Coastguard Worker  *
798*0d6140beSAndroid Build Coastguard Worker  * It should be called before ICH sends any spi command.
799*0d6140beSAndroid Build Coastguard Worker  */
ich_init_opcodes(enum ich_chipset ich_gen)800*0d6140beSAndroid Build Coastguard Worker static int ich_init_opcodes(enum ich_chipset ich_gen)
801*0d6140beSAndroid Build Coastguard Worker {
802*0d6140beSAndroid Build Coastguard Worker 	int rc = 0;
803*0d6140beSAndroid Build Coastguard Worker 	OPCODES *curopcodes_done;
804*0d6140beSAndroid Build Coastguard Worker 
805*0d6140beSAndroid Build Coastguard Worker 	if (curopcodes)
806*0d6140beSAndroid Build Coastguard Worker 		return 0;
807*0d6140beSAndroid Build Coastguard Worker 
808*0d6140beSAndroid Build Coastguard Worker 	if (ichspi_lock) {
809*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Reading OPCODES... ");
810*0d6140beSAndroid Build Coastguard Worker 		curopcodes_done = &O_EXISTING;
811*0d6140beSAndroid Build Coastguard Worker 		rc = generate_opcodes(curopcodes_done, ich_gen);
812*0d6140beSAndroid Build Coastguard Worker 	} else {
813*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Programming OPCODES... ");
814*0d6140beSAndroid Build Coastguard Worker 		curopcodes_done = &O_ST_M25P;
815*0d6140beSAndroid Build Coastguard Worker 		rc = program_opcodes(curopcodes_done, 1, ich_gen);
816*0d6140beSAndroid Build Coastguard Worker 	}
817*0d6140beSAndroid Build Coastguard Worker 
818*0d6140beSAndroid Build Coastguard Worker 	if (rc) {
819*0d6140beSAndroid Build Coastguard Worker 		curopcodes = NULL;
820*0d6140beSAndroid Build Coastguard Worker 		msg_perr("failed\n");
821*0d6140beSAndroid Build Coastguard Worker 		return 1;
822*0d6140beSAndroid Build Coastguard Worker 	} else {
823*0d6140beSAndroid Build Coastguard Worker 		curopcodes = curopcodes_done;
824*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("done\n");
825*0d6140beSAndroid Build Coastguard Worker 		prettyprint_opcodes(curopcodes);
826*0d6140beSAndroid Build Coastguard Worker 		return 0;
827*0d6140beSAndroid Build Coastguard Worker 	}
828*0d6140beSAndroid Build Coastguard Worker }
829*0d6140beSAndroid Build Coastguard Worker 
830*0d6140beSAndroid Build Coastguard Worker /* Fill len bytes from the data array into the fdata/spid registers.
831*0d6140beSAndroid Build Coastguard Worker  *
832*0d6140beSAndroid Build Coastguard Worker  * Note that using len > flash->mst->spi.max_data_write will trash the registers
833*0d6140beSAndroid Build Coastguard Worker  * following the data registers.
834*0d6140beSAndroid Build Coastguard Worker  */
ich_fill_data(const uint8_t * data,int len,int reg0_off)835*0d6140beSAndroid Build Coastguard Worker static void ich_fill_data(const uint8_t *data, int len, int reg0_off)
836*0d6140beSAndroid Build Coastguard Worker {
837*0d6140beSAndroid Build Coastguard Worker 	uint32_t temp32 = 0;
838*0d6140beSAndroid Build Coastguard Worker 	int i;
839*0d6140beSAndroid Build Coastguard Worker 
840*0d6140beSAndroid Build Coastguard Worker 	if (len <= 0)
841*0d6140beSAndroid Build Coastguard Worker 		return;
842*0d6140beSAndroid Build Coastguard Worker 
843*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
844*0d6140beSAndroid Build Coastguard Worker 		if ((i % 4) == 0)
845*0d6140beSAndroid Build Coastguard Worker 			temp32 = 0;
846*0d6140beSAndroid Build Coastguard Worker 
847*0d6140beSAndroid Build Coastguard Worker 		temp32 |= ((uint32_t) data[i]) << ((i % 4) * 8);
848*0d6140beSAndroid Build Coastguard Worker 
849*0d6140beSAndroid Build Coastguard Worker 		if ((i % 4) == 3) /* 32 bits are full, write them to regs. */
850*0d6140beSAndroid Build Coastguard Worker 			REGWRITE32(reg0_off + (i - (i % 4)), temp32);
851*0d6140beSAndroid Build Coastguard Worker 	}
852*0d6140beSAndroid Build Coastguard Worker 	i--;
853*0d6140beSAndroid Build Coastguard Worker 	if ((i % 4) != 3) /* Write remaining data to regs. */
854*0d6140beSAndroid Build Coastguard Worker 		REGWRITE32(reg0_off + (i - (i % 4)), temp32);
855*0d6140beSAndroid Build Coastguard Worker }
856*0d6140beSAndroid Build Coastguard Worker 
857*0d6140beSAndroid Build Coastguard Worker /* Read len bytes from the fdata/spid register into the data array.
858*0d6140beSAndroid Build Coastguard Worker  *
859*0d6140beSAndroid Build Coastguard Worker  * Note that using len > flash->mst->spi.max_data_read will return garbage or
860*0d6140beSAndroid Build Coastguard Worker  * may even crash.
861*0d6140beSAndroid Build Coastguard Worker  */
ich_read_data(uint8_t * data,int len,int reg0_off)862*0d6140beSAndroid Build Coastguard Worker static void ich_read_data(uint8_t *data, int len, int reg0_off)
863*0d6140beSAndroid Build Coastguard Worker {
864*0d6140beSAndroid Build Coastguard Worker 	int i;
865*0d6140beSAndroid Build Coastguard Worker 	uint32_t temp32 = 0;
866*0d6140beSAndroid Build Coastguard Worker 
867*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
868*0d6140beSAndroid Build Coastguard Worker 		if ((i % 4) == 0)
869*0d6140beSAndroid Build Coastguard Worker 			temp32 = REGREAD32(reg0_off + i);
870*0d6140beSAndroid Build Coastguard Worker 
871*0d6140beSAndroid Build Coastguard Worker 		data[i] = (temp32 >> ((i % 4) * 8)) & 0xff;
872*0d6140beSAndroid Build Coastguard Worker 	}
873*0d6140beSAndroid Build Coastguard Worker }
874*0d6140beSAndroid Build Coastguard Worker 
ich7_run_opcode(OPCODE op,uint32_t offset,uint8_t datalength,uint8_t * data,int maxdata)875*0d6140beSAndroid Build Coastguard Worker static int ich7_run_opcode(OPCODE op, uint32_t offset,
876*0d6140beSAndroid Build Coastguard Worker 			   uint8_t datalength, uint8_t * data, int maxdata)
877*0d6140beSAndroid Build Coastguard Worker {
878*0d6140beSAndroid Build Coastguard Worker 	bool write_cmd = false;
879*0d6140beSAndroid Build Coastguard Worker 	int timeout;
880*0d6140beSAndroid Build Coastguard Worker 	uint32_t temp32;
881*0d6140beSAndroid Build Coastguard Worker 	uint16_t temp16;
882*0d6140beSAndroid Build Coastguard Worker 	uint64_t opmenu;
883*0d6140beSAndroid Build Coastguard Worker 	int opcode_index;
884*0d6140beSAndroid Build Coastguard Worker 
885*0d6140beSAndroid Build Coastguard Worker 	/* Is it a write command? */
886*0d6140beSAndroid Build Coastguard Worker 	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
887*0d6140beSAndroid Build Coastguard Worker 	    || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
888*0d6140beSAndroid Build Coastguard Worker 		write_cmd = true;
889*0d6140beSAndroid Build Coastguard Worker 	}
890*0d6140beSAndroid Build Coastguard Worker 
891*0d6140beSAndroid Build Coastguard Worker 	timeout = 100 * 60;	/* 60 ms are 9.6 million cycles at 16 MHz. */
892*0d6140beSAndroid Build Coastguard Worker 	while ((REGREAD16(ICH7_REG_SPIS) & SPIS_SCIP) && --timeout) {
893*0d6140beSAndroid Build Coastguard Worker 		default_delay(10);
894*0d6140beSAndroid Build Coastguard Worker 	}
895*0d6140beSAndroid Build Coastguard Worker 	if (!timeout) {
896*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: SCIP never cleared!\n");
897*0d6140beSAndroid Build Coastguard Worker 		return 1;
898*0d6140beSAndroid Build Coastguard Worker 	}
899*0d6140beSAndroid Build Coastguard Worker 
900*0d6140beSAndroid Build Coastguard Worker 	/* Program offset in flash into SPIA while preserving reserved bits. */
901*0d6140beSAndroid Build Coastguard Worker 	temp32 = REGREAD32(ICH7_REG_SPIA) & ~0x00FFFFFF;
902*0d6140beSAndroid Build Coastguard Worker 	REGWRITE32(ICH7_REG_SPIA, (offset & 0x00FFFFFF) | temp32);
903*0d6140beSAndroid Build Coastguard Worker 
904*0d6140beSAndroid Build Coastguard Worker 	/* Program data into SPID0 to N */
905*0d6140beSAndroid Build Coastguard Worker 	if (write_cmd && (datalength != 0))
906*0d6140beSAndroid Build Coastguard Worker 		ich_fill_data(data, datalength, ICH7_REG_SPID0);
907*0d6140beSAndroid Build Coastguard Worker 
908*0d6140beSAndroid Build Coastguard Worker 	/* Assemble SPIS */
909*0d6140beSAndroid Build Coastguard Worker 	temp16 = REGREAD16(ICH7_REG_SPIS);
910*0d6140beSAndroid Build Coastguard Worker 	/* keep reserved bits */
911*0d6140beSAndroid Build Coastguard Worker 	temp16 &= SPIS_RESERVED_MASK;
912*0d6140beSAndroid Build Coastguard Worker 	/* clear error status registers */
913*0d6140beSAndroid Build Coastguard Worker 	temp16 |= (SPIS_CDS | SPIS_FCERR);
914*0d6140beSAndroid Build Coastguard Worker 	REGWRITE16(ICH7_REG_SPIS, temp16);
915*0d6140beSAndroid Build Coastguard Worker 
916*0d6140beSAndroid Build Coastguard Worker 	/* Assemble SPIC */
917*0d6140beSAndroid Build Coastguard Worker 	temp16 = 0;
918*0d6140beSAndroid Build Coastguard Worker 
919*0d6140beSAndroid Build Coastguard Worker 	if (datalength != 0) {
920*0d6140beSAndroid Build Coastguard Worker 		temp16 |= SPIC_DS;
921*0d6140beSAndroid Build Coastguard Worker 		temp16 |= ((uint32_t) ((datalength - 1) & (maxdata - 1))) << 8;
922*0d6140beSAndroid Build Coastguard Worker 	}
923*0d6140beSAndroid Build Coastguard Worker 
924*0d6140beSAndroid Build Coastguard Worker 	/* Select opcode */
925*0d6140beSAndroid Build Coastguard Worker 	opmenu = REGREAD32(ICH7_REG_OPMENU);
926*0d6140beSAndroid Build Coastguard Worker 	opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
927*0d6140beSAndroid Build Coastguard Worker 
928*0d6140beSAndroid Build Coastguard Worker 	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
929*0d6140beSAndroid Build Coastguard Worker 		if ((opmenu & 0xff) == op.opcode) {
930*0d6140beSAndroid Build Coastguard Worker 			break;
931*0d6140beSAndroid Build Coastguard Worker 		}
932*0d6140beSAndroid Build Coastguard Worker 		opmenu >>= 8;
933*0d6140beSAndroid Build Coastguard Worker 	}
934*0d6140beSAndroid Build Coastguard Worker 	if (opcode_index == 8) {
935*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Opcode %x not found.\n", op.opcode);
936*0d6140beSAndroid Build Coastguard Worker 		return 1;
937*0d6140beSAndroid Build Coastguard Worker 	}
938*0d6140beSAndroid Build Coastguard Worker 	temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
939*0d6140beSAndroid Build Coastguard Worker 
940*0d6140beSAndroid Build Coastguard Worker 	timeout = 100 * 60;	/* 60 ms are 9.6 million cycles at 16 MHz. */
941*0d6140beSAndroid Build Coastguard Worker 	/* Handle Atomic. Atomic commands include three steps:
942*0d6140beSAndroid Build Coastguard Worker 	    - sending the preop (mainly EWSR or WREN)
943*0d6140beSAndroid Build Coastguard Worker 	    - sending the main command
944*0d6140beSAndroid Build Coastguard Worker 	    - waiting for the busy bit (WIP) to be cleared
945*0d6140beSAndroid Build Coastguard Worker 	   This means the timeout must be sufficient for chip erase
946*0d6140beSAndroid Build Coastguard Worker 	   of slow high-capacity chips.
947*0d6140beSAndroid Build Coastguard Worker 	 */
948*0d6140beSAndroid Build Coastguard Worker 	switch (op.atomic) {
949*0d6140beSAndroid Build Coastguard Worker 	case 2:
950*0d6140beSAndroid Build Coastguard Worker 		/* Select second preop. */
951*0d6140beSAndroid Build Coastguard Worker 		temp16 |= SPIC_SPOP;
952*0d6140beSAndroid Build Coastguard Worker 		/* Fall through. */
953*0d6140beSAndroid Build Coastguard Worker 	case 1:
954*0d6140beSAndroid Build Coastguard Worker 		/* Atomic command (preop+op) */
955*0d6140beSAndroid Build Coastguard Worker 		temp16 |= SPIC_ACS;
956*0d6140beSAndroid Build Coastguard Worker 		timeout = 100 * 1000 * 60;	/* 60 seconds */
957*0d6140beSAndroid Build Coastguard Worker 		break;
958*0d6140beSAndroid Build Coastguard Worker 	}
959*0d6140beSAndroid Build Coastguard Worker 
960*0d6140beSAndroid Build Coastguard Worker 	/* Start */
961*0d6140beSAndroid Build Coastguard Worker 	temp16 |= SPIC_SCGO;
962*0d6140beSAndroid Build Coastguard Worker 
963*0d6140beSAndroid Build Coastguard Worker 	/* write it */
964*0d6140beSAndroid Build Coastguard Worker 	REGWRITE16(ICH7_REG_SPIC, temp16);
965*0d6140beSAndroid Build Coastguard Worker 
966*0d6140beSAndroid Build Coastguard Worker 	/* Wait for Cycle Done Status or Flash Cycle Error. */
967*0d6140beSAndroid Build Coastguard Worker 	while (((REGREAD16(ICH7_REG_SPIS) & (SPIS_CDS | SPIS_FCERR)) == 0) &&
968*0d6140beSAndroid Build Coastguard Worker 	       --timeout) {
969*0d6140beSAndroid Build Coastguard Worker 		default_delay(10);
970*0d6140beSAndroid Build Coastguard Worker 	}
971*0d6140beSAndroid Build Coastguard Worker 	if (!timeout) {
972*0d6140beSAndroid Build Coastguard Worker 		msg_perr("timeout, ICH7_REG_SPIS=0x%04x\n", REGREAD16(ICH7_REG_SPIS));
973*0d6140beSAndroid Build Coastguard Worker 		return 1;
974*0d6140beSAndroid Build Coastguard Worker 	}
975*0d6140beSAndroid Build Coastguard Worker 
976*0d6140beSAndroid Build Coastguard Worker 	/* FIXME: make sure we do not needlessly cause transaction errors. */
977*0d6140beSAndroid Build Coastguard Worker 	temp16 = REGREAD16(ICH7_REG_SPIS);
978*0d6140beSAndroid Build Coastguard Worker 	if (temp16 & SPIS_FCERR) {
979*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Transaction error!\n");
980*0d6140beSAndroid Build Coastguard Worker 		/* keep reserved bits */
981*0d6140beSAndroid Build Coastguard Worker 		temp16 &= SPIS_RESERVED_MASK;
982*0d6140beSAndroid Build Coastguard Worker 		REGWRITE16(ICH7_REG_SPIS, temp16 | SPIS_FCERR);
983*0d6140beSAndroid Build Coastguard Worker 		return 1;
984*0d6140beSAndroid Build Coastguard Worker 	}
985*0d6140beSAndroid Build Coastguard Worker 
986*0d6140beSAndroid Build Coastguard Worker 	if ((!write_cmd) && (datalength != 0))
987*0d6140beSAndroid Build Coastguard Worker 		ich_read_data(data, datalength, ICH7_REG_SPID0);
988*0d6140beSAndroid Build Coastguard Worker 
989*0d6140beSAndroid Build Coastguard Worker 	return 0;
990*0d6140beSAndroid Build Coastguard Worker }
991*0d6140beSAndroid Build Coastguard Worker 
ich9_run_opcode(OPCODE op,uint32_t offset,uint8_t datalength,uint8_t * data)992*0d6140beSAndroid Build Coastguard Worker static int ich9_run_opcode(OPCODE op, uint32_t offset,
993*0d6140beSAndroid Build Coastguard Worker 			   uint8_t datalength, uint8_t * data)
994*0d6140beSAndroid Build Coastguard Worker {
995*0d6140beSAndroid Build Coastguard Worker 	bool write_cmd = false;
996*0d6140beSAndroid Build Coastguard Worker 	int timeout;
997*0d6140beSAndroid Build Coastguard Worker 	uint32_t temp32;
998*0d6140beSAndroid Build Coastguard Worker 	uint64_t opmenu;
999*0d6140beSAndroid Build Coastguard Worker 	int opcode_index;
1000*0d6140beSAndroid Build Coastguard Worker 
1001*0d6140beSAndroid Build Coastguard Worker 	/* Is it a write command? */
1002*0d6140beSAndroid Build Coastguard Worker 	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
1003*0d6140beSAndroid Build Coastguard Worker 	    || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
1004*0d6140beSAndroid Build Coastguard Worker 		write_cmd = true;
1005*0d6140beSAndroid Build Coastguard Worker 	}
1006*0d6140beSAndroid Build Coastguard Worker 
1007*0d6140beSAndroid Build Coastguard Worker 	timeout = 100 * 60;	/* 60 ms are 9.6 million cycles at 16 MHz. */
1008*0d6140beSAndroid Build Coastguard Worker 	while ((REGREAD8(swseq_data.reg_ssfsc) & SSFS_SCIP) && --timeout) {
1009*0d6140beSAndroid Build Coastguard Worker 		default_delay(10);
1010*0d6140beSAndroid Build Coastguard Worker 	}
1011*0d6140beSAndroid Build Coastguard Worker 	if (!timeout) {
1012*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: SCIP never cleared!\n");
1013*0d6140beSAndroid Build Coastguard Worker 		return 1;
1014*0d6140beSAndroid Build Coastguard Worker 	}
1015*0d6140beSAndroid Build Coastguard Worker 
1016*0d6140beSAndroid Build Coastguard Worker 	/* Program offset in flash into FADDR while preserve the reserved bits
1017*0d6140beSAndroid Build Coastguard Worker 	 * and clearing the 25. address bit which is only usable in hwseq. */
1018*0d6140beSAndroid Build Coastguard Worker 	temp32 = REGREAD32(ICH9_REG_FADDR) & ~0x01FFFFFF;
1019*0d6140beSAndroid Build Coastguard Worker 	REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF) | temp32);
1020*0d6140beSAndroid Build Coastguard Worker 
1021*0d6140beSAndroid Build Coastguard Worker 	/* Program data into FDATA0 to N */
1022*0d6140beSAndroid Build Coastguard Worker 	if (write_cmd && (datalength != 0))
1023*0d6140beSAndroid Build Coastguard Worker 		ich_fill_data(data, datalength, ICH9_REG_FDATA0);
1024*0d6140beSAndroid Build Coastguard Worker 
1025*0d6140beSAndroid Build Coastguard Worker 	/* Assemble SSFS + SSFC */
1026*0d6140beSAndroid Build Coastguard Worker 	temp32 = REGREAD32(swseq_data.reg_ssfsc);
1027*0d6140beSAndroid Build Coastguard Worker 	/* Keep reserved bits only */
1028*0d6140beSAndroid Build Coastguard Worker 	temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
1029*0d6140beSAndroid Build Coastguard Worker 	/* Clear cycle done and cycle error status registers */
1030*0d6140beSAndroid Build Coastguard Worker 	temp32 |= (SSFS_FDONE | SSFS_FCERR);
1031*0d6140beSAndroid Build Coastguard Worker 	REGWRITE32(swseq_data.reg_ssfsc, temp32);
1032*0d6140beSAndroid Build Coastguard Worker 
1033*0d6140beSAndroid Build Coastguard Worker 	/* Use 20 MHz */
1034*0d6140beSAndroid Build Coastguard Worker 	temp32 |= SSFC_SCF_20MHZ;
1035*0d6140beSAndroid Build Coastguard Worker 
1036*0d6140beSAndroid Build Coastguard Worker 	/* Set data byte count (DBC) and data cycle bit (DS) */
1037*0d6140beSAndroid Build Coastguard Worker 	if (datalength != 0) {
1038*0d6140beSAndroid Build Coastguard Worker 		uint32_t datatemp;
1039*0d6140beSAndroid Build Coastguard Worker 		temp32 |= SSFC_DS;
1040*0d6140beSAndroid Build Coastguard Worker 		datatemp = ((((uint32_t)datalength - 1) << SSFC_DBC_OFF) & SSFC_DBC);
1041*0d6140beSAndroid Build Coastguard Worker 		temp32 |= datatemp;
1042*0d6140beSAndroid Build Coastguard Worker 	}
1043*0d6140beSAndroid Build Coastguard Worker 
1044*0d6140beSAndroid Build Coastguard Worker 	/* Select opcode */
1045*0d6140beSAndroid Build Coastguard Worker 	opmenu = REGREAD32(swseq_data.reg_opmenu);
1046*0d6140beSAndroid Build Coastguard Worker 	opmenu |= ((uint64_t)REGREAD32(swseq_data.reg_opmenu + 4)) << 32;
1047*0d6140beSAndroid Build Coastguard Worker 
1048*0d6140beSAndroid Build Coastguard Worker 	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
1049*0d6140beSAndroid Build Coastguard Worker 		if ((opmenu & 0xff) == op.opcode) {
1050*0d6140beSAndroid Build Coastguard Worker 			break;
1051*0d6140beSAndroid Build Coastguard Worker 		}
1052*0d6140beSAndroid Build Coastguard Worker 		opmenu >>= 8;
1053*0d6140beSAndroid Build Coastguard Worker 	}
1054*0d6140beSAndroid Build Coastguard Worker 	if (opcode_index == 8) {
1055*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Opcode %x not found.\n", op.opcode);
1056*0d6140beSAndroid Build Coastguard Worker 		return 1;
1057*0d6140beSAndroid Build Coastguard Worker 	}
1058*0d6140beSAndroid Build Coastguard Worker 	temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
1059*0d6140beSAndroid Build Coastguard Worker 
1060*0d6140beSAndroid Build Coastguard Worker 	timeout = 100 * 60;	/* 60 ms are 9.6 million cycles at 16 MHz. */
1061*0d6140beSAndroid Build Coastguard Worker 	/* Handle Atomic. Atomic commands include three steps:
1062*0d6140beSAndroid Build Coastguard Worker 	    - sending the preop (mainly EWSR or WREN)
1063*0d6140beSAndroid Build Coastguard Worker 	    - sending the main command
1064*0d6140beSAndroid Build Coastguard Worker 	    - waiting for the busy bit (WIP) to be cleared
1065*0d6140beSAndroid Build Coastguard Worker 	   This means the timeout must be sufficient for chip erase
1066*0d6140beSAndroid Build Coastguard Worker 	   of slow high-capacity chips.
1067*0d6140beSAndroid Build Coastguard Worker 	 */
1068*0d6140beSAndroid Build Coastguard Worker 	switch (op.atomic) {
1069*0d6140beSAndroid Build Coastguard Worker 	case 2:
1070*0d6140beSAndroid Build Coastguard Worker 		/* Select second preop. */
1071*0d6140beSAndroid Build Coastguard Worker 		temp32 |= SSFC_SPOP;
1072*0d6140beSAndroid Build Coastguard Worker 		/* Fall through. */
1073*0d6140beSAndroid Build Coastguard Worker 	case 1:
1074*0d6140beSAndroid Build Coastguard Worker 		/* Atomic command (preop+op) */
1075*0d6140beSAndroid Build Coastguard Worker 		temp32 |= SSFC_ACS;
1076*0d6140beSAndroid Build Coastguard Worker 		timeout = 100 * 1000 * 60;	/* 60 seconds */
1077*0d6140beSAndroid Build Coastguard Worker 		break;
1078*0d6140beSAndroid Build Coastguard Worker 	}
1079*0d6140beSAndroid Build Coastguard Worker 
1080*0d6140beSAndroid Build Coastguard Worker 	/* Start */
1081*0d6140beSAndroid Build Coastguard Worker 	temp32 |= SSFC_SCGO;
1082*0d6140beSAndroid Build Coastguard Worker 
1083*0d6140beSAndroid Build Coastguard Worker 	/* write it */
1084*0d6140beSAndroid Build Coastguard Worker 	REGWRITE32(swseq_data.reg_ssfsc, temp32);
1085*0d6140beSAndroid Build Coastguard Worker 
1086*0d6140beSAndroid Build Coastguard Worker 	/* Wait for Cycle Done Status or Flash Cycle Error. */
1087*0d6140beSAndroid Build Coastguard Worker 	while (((REGREAD32(swseq_data.reg_ssfsc) & (SSFS_FDONE | SSFS_FCERR)) == 0) &&
1088*0d6140beSAndroid Build Coastguard Worker 	       --timeout) {
1089*0d6140beSAndroid Build Coastguard Worker 		default_delay(10);
1090*0d6140beSAndroid Build Coastguard Worker 	}
1091*0d6140beSAndroid Build Coastguard Worker 	if (!timeout) {
1092*0d6140beSAndroid Build Coastguard Worker 		msg_perr("timeout, REG_SSFS=0x%08"PRIx32"\n", REGREAD32(swseq_data.reg_ssfsc));
1093*0d6140beSAndroid Build Coastguard Worker 		return 1;
1094*0d6140beSAndroid Build Coastguard Worker 	}
1095*0d6140beSAndroid Build Coastguard Worker 
1096*0d6140beSAndroid Build Coastguard Worker 	/* FIXME make sure we do not needlessly cause transaction errors. */
1097*0d6140beSAndroid Build Coastguard Worker 	temp32 = REGREAD32(swseq_data.reg_ssfsc);
1098*0d6140beSAndroid Build Coastguard Worker 	if (temp32 & SSFS_FCERR) {
1099*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Transaction error!\n");
1100*0d6140beSAndroid Build Coastguard Worker 		prettyprint_ich9_reg_ssfs(temp32);
1101*0d6140beSAndroid Build Coastguard Worker 		prettyprint_ich9_reg_ssfc(temp32);
1102*0d6140beSAndroid Build Coastguard Worker 		/* keep reserved bits */
1103*0d6140beSAndroid Build Coastguard Worker 		temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
1104*0d6140beSAndroid Build Coastguard Worker 		/* Clear the transaction error. */
1105*0d6140beSAndroid Build Coastguard Worker 		REGWRITE32(swseq_data.reg_ssfsc, temp32 | SSFS_FCERR);
1106*0d6140beSAndroid Build Coastguard Worker 		return 1;
1107*0d6140beSAndroid Build Coastguard Worker 	}
1108*0d6140beSAndroid Build Coastguard Worker 
1109*0d6140beSAndroid Build Coastguard Worker 	if ((!write_cmd) && (datalength != 0))
1110*0d6140beSAndroid Build Coastguard Worker 		ich_read_data(data, datalength, ICH9_REG_FDATA0);
1111*0d6140beSAndroid Build Coastguard Worker 
1112*0d6140beSAndroid Build Coastguard Worker 	return 0;
1113*0d6140beSAndroid Build Coastguard Worker }
1114*0d6140beSAndroid Build Coastguard Worker 
run_opcode(const struct flashctx * flash,OPCODE op,uint32_t offset,uint8_t datalength,uint8_t * data)1115*0d6140beSAndroid Build Coastguard Worker static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
1116*0d6140beSAndroid Build Coastguard Worker 		      uint8_t datalength, uint8_t * data)
1117*0d6140beSAndroid Build Coastguard Worker {
1118*0d6140beSAndroid Build Coastguard Worker 	/* max_data_read == max_data_write for all Intel/VIA SPI masters */
1119*0d6140beSAndroid Build Coastguard Worker 	uint8_t maxlength = flash->mst->spi.max_data_read;
1120*0d6140beSAndroid Build Coastguard Worker 
1121*0d6140beSAndroid Build Coastguard Worker 	if (ich_generation == CHIPSET_ICH_UNKNOWN) {
1122*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: unsupported chipset\n", __func__);
1123*0d6140beSAndroid Build Coastguard Worker 		return -1;
1124*0d6140beSAndroid Build Coastguard Worker 	}
1125*0d6140beSAndroid Build Coastguard Worker 
1126*0d6140beSAndroid Build Coastguard Worker 	if (datalength > maxlength) {
1127*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Internal command size error for "
1128*0d6140beSAndroid Build Coastguard Worker 			"opcode 0x%02x, got datalength=%i, want <=%i\n",
1129*0d6140beSAndroid Build Coastguard Worker 			__func__, op.opcode, datalength, maxlength);
1130*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_LENGTH;
1131*0d6140beSAndroid Build Coastguard Worker 	}
1132*0d6140beSAndroid Build Coastguard Worker 
1133*0d6140beSAndroid Build Coastguard Worker 	switch (ich_generation) {
1134*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH7:
1135*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_TUNNEL_CREEK:
1136*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_CENTERTON:
1137*0d6140beSAndroid Build Coastguard Worker 		return ich7_run_opcode(op, offset, datalength, data, maxlength);
1138*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH8:
1139*0d6140beSAndroid Build Coastguard Worker 	default:		/* Future version might behave the same */
1140*0d6140beSAndroid Build Coastguard Worker 		return ich9_run_opcode(op, offset, datalength, data);
1141*0d6140beSAndroid Build Coastguard Worker 	}
1142*0d6140beSAndroid Build Coastguard Worker }
1143*0d6140beSAndroid Build Coastguard Worker 
ich_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)1144*0d6140beSAndroid Build Coastguard Worker static int ich_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
1145*0d6140beSAndroid Build Coastguard Worker 				unsigned int readcnt,
1146*0d6140beSAndroid Build Coastguard Worker 				const unsigned char *writearr,
1147*0d6140beSAndroid Build Coastguard Worker 				unsigned char *readarr)
1148*0d6140beSAndroid Build Coastguard Worker {
1149*0d6140beSAndroid Build Coastguard Worker 	int result;
1150*0d6140beSAndroid Build Coastguard Worker 	int opcode_index = -1;
1151*0d6140beSAndroid Build Coastguard Worker 	const unsigned char cmd = *writearr;
1152*0d6140beSAndroid Build Coastguard Worker 	OPCODE *opcode;
1153*0d6140beSAndroid Build Coastguard Worker 	uint32_t addr = 0;
1154*0d6140beSAndroid Build Coastguard Worker 	uint8_t *data;
1155*0d6140beSAndroid Build Coastguard Worker 	int count;
1156*0d6140beSAndroid Build Coastguard Worker 
1157*0d6140beSAndroid Build Coastguard Worker 	/* find cmd in opcodes-table */
1158*0d6140beSAndroid Build Coastguard Worker 	opcode_index = find_opcode(curopcodes, cmd);
1159*0d6140beSAndroid Build Coastguard Worker 	if (opcode_index == -1) {
1160*0d6140beSAndroid Build Coastguard Worker 		if (!ichspi_lock)
1161*0d6140beSAndroid Build Coastguard Worker 			opcode_index = reprogram_opcode_on_the_fly(cmd, writecnt, readcnt);
1162*0d6140beSAndroid Build Coastguard Worker 		if (opcode_index == SPI_INVALID_LENGTH) {
1163*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("OPCODE 0x%02x has unsupported length, will not execute.\n", cmd);
1164*0d6140beSAndroid Build Coastguard Worker 			return SPI_INVALID_LENGTH;
1165*0d6140beSAndroid Build Coastguard Worker 		} else if (opcode_index == -1) {
1166*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\n", cmd);
1167*0d6140beSAndroid Build Coastguard Worker 			return SPI_INVALID_OPCODE;
1168*0d6140beSAndroid Build Coastguard Worker 		}
1169*0d6140beSAndroid Build Coastguard Worker 	}
1170*0d6140beSAndroid Build Coastguard Worker 
1171*0d6140beSAndroid Build Coastguard Worker 	if (is_dry_run())
1172*0d6140beSAndroid Build Coastguard Worker 		return 0;
1173*0d6140beSAndroid Build Coastguard Worker 
1174*0d6140beSAndroid Build Coastguard Worker 	opcode = &(curopcodes->opcode[opcode_index]);
1175*0d6140beSAndroid Build Coastguard Worker 
1176*0d6140beSAndroid Build Coastguard Worker 	/* The following valid writecnt/readcnt combinations exist:
1177*0d6140beSAndroid Build Coastguard Worker 	 * writecnt  = 4, readcnt >= 0
1178*0d6140beSAndroid Build Coastguard Worker 	 * writecnt  = 1, readcnt >= 0
1179*0d6140beSAndroid Build Coastguard Worker 	 * writecnt >= 4, readcnt  = 0
1180*0d6140beSAndroid Build Coastguard Worker 	 * writecnt >= 1, readcnt  = 0
1181*0d6140beSAndroid Build Coastguard Worker 	 * writecnt >= 1 is guaranteed for all commands.
1182*0d6140beSAndroid Build Coastguard Worker 	 */
1183*0d6140beSAndroid Build Coastguard Worker 	if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS) &&
1184*0d6140beSAndroid Build Coastguard Worker 	    (writecnt != 4)) {
1185*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Internal command size error for opcode "
1186*0d6140beSAndroid Build Coastguard Worker 			"0x%02x, got writecnt=%i, want =4\n", __func__, cmd, writecnt);
1187*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_LENGTH;
1188*0d6140beSAndroid Build Coastguard Worker 	}
1189*0d6140beSAndroid Build Coastguard Worker 	if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_NO_ADDRESS) &&
1190*0d6140beSAndroid Build Coastguard Worker 	    (writecnt != 1)) {
1191*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Internal command size error for opcode "
1192*0d6140beSAndroid Build Coastguard Worker 			"0x%02x, got writecnt=%i, want =1\n", __func__, cmd, writecnt);
1193*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_LENGTH;
1194*0d6140beSAndroid Build Coastguard Worker 	}
1195*0d6140beSAndroid Build Coastguard Worker 	if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) &&
1196*0d6140beSAndroid Build Coastguard Worker 	    (writecnt < 4)) {
1197*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Internal command size error for opcode "
1198*0d6140beSAndroid Build Coastguard Worker 			"0x%02x, got writecnt=%i, want >=4\n", __func__, cmd, writecnt);
1199*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_LENGTH;
1200*0d6140beSAndroid Build Coastguard Worker 	}
1201*0d6140beSAndroid Build Coastguard Worker 	if (((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
1202*0d6140beSAndroid Build Coastguard Worker 	     (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) &&
1203*0d6140beSAndroid Build Coastguard Worker 	    (readcnt)) {
1204*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Internal command size error for opcode "
1205*0d6140beSAndroid Build Coastguard Worker 			"0x%02x, got readcnt=%i, want =0\n", __func__, cmd, readcnt);
1206*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_LENGTH;
1207*0d6140beSAndroid Build Coastguard Worker 	}
1208*0d6140beSAndroid Build Coastguard Worker 
1209*0d6140beSAndroid Build Coastguard Worker 	/* Translate read/write array/count.
1210*0d6140beSAndroid Build Coastguard Worker 	 * The maximum data length is identical for the maximum read length and
1211*0d6140beSAndroid Build Coastguard Worker 	 * for the maximum write length excluding opcode and address. Opcode and
1212*0d6140beSAndroid Build Coastguard Worker 	 * address are stored in separate registers, not in the data registers
1213*0d6140beSAndroid Build Coastguard Worker 	 * and are thus not counted towards data length. The only exception
1214*0d6140beSAndroid Build Coastguard Worker 	 * applies if the opcode definition (un)intentionally classifies said
1215*0d6140beSAndroid Build Coastguard Worker 	 * opcode incorrectly as non-address opcode or vice versa. */
1216*0d6140beSAndroid Build Coastguard Worker 	if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) {
1217*0d6140beSAndroid Build Coastguard Worker 		data = (uint8_t *) (writearr + 1);
1218*0d6140beSAndroid Build Coastguard Worker 		count = writecnt - 1;
1219*0d6140beSAndroid Build Coastguard Worker 	} else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
1220*0d6140beSAndroid Build Coastguard Worker 		data = (uint8_t *) (writearr + 4);
1221*0d6140beSAndroid Build Coastguard Worker 		count = writecnt - 4;
1222*0d6140beSAndroid Build Coastguard Worker 	} else {
1223*0d6140beSAndroid Build Coastguard Worker 		data = (uint8_t *) readarr;
1224*0d6140beSAndroid Build Coastguard Worker 		count = readcnt;
1225*0d6140beSAndroid Build Coastguard Worker 	}
1226*0d6140beSAndroid Build Coastguard Worker 
1227*0d6140beSAndroid Build Coastguard Worker 	/* if opcode-type requires an address */
1228*0d6140beSAndroid Build Coastguard Worker 	if (cmd == JEDEC_REMS || cmd == JEDEC_RES) {
1229*0d6140beSAndroid Build Coastguard Worker 		addr = ichspi_bbar;
1230*0d6140beSAndroid Build Coastguard Worker 	} else if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
1231*0d6140beSAndroid Build Coastguard Worker 	    opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
1232*0d6140beSAndroid Build Coastguard Worker 		/* BBAR may cut part of the chip off at the lower end. */
1233*0d6140beSAndroid Build Coastguard Worker 		const uint32_t valid_base = ichspi_bbar & ((flash->chip->total_size * 1024) - 1);
1234*0d6140beSAndroid Build Coastguard Worker 		const uint32_t addr_offset = ichspi_bbar - valid_base;
1235*0d6140beSAndroid Build Coastguard Worker 		/* Highest address we can program is (2^24 - 1). */
1236*0d6140beSAndroid Build Coastguard Worker 		const uint32_t valid_end = (1 << 24) - addr_offset;
1237*0d6140beSAndroid Build Coastguard Worker 
1238*0d6140beSAndroid Build Coastguard Worker 		addr = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
1239*0d6140beSAndroid Build Coastguard Worker 		const uint32_t addr_end = addr + count;
1240*0d6140beSAndroid Build Coastguard Worker 
1241*0d6140beSAndroid Build Coastguard Worker 		if (addr < valid_base ||
1242*0d6140beSAndroid Build Coastguard Worker 		    addr_end < addr || /* integer overflow check */
1243*0d6140beSAndroid Build Coastguard Worker 		    addr_end > valid_end) {
1244*0d6140beSAndroid Build Coastguard Worker 			msg_perr("%s: Addressed region 0x%06"PRIx32"-0x%06"PRIx32" not in allowed range 0x%06"PRIx32"-0x%06"PRIx32"\n",
1245*0d6140beSAndroid Build Coastguard Worker 				 __func__, addr, addr_end - 1, valid_base, valid_end - 1);
1246*0d6140beSAndroid Build Coastguard Worker 			return SPI_INVALID_ADDRESS;
1247*0d6140beSAndroid Build Coastguard Worker 		}
1248*0d6140beSAndroid Build Coastguard Worker 		addr += addr_offset;
1249*0d6140beSAndroid Build Coastguard Worker 	}
1250*0d6140beSAndroid Build Coastguard Worker 
1251*0d6140beSAndroid Build Coastguard Worker 	result = run_opcode(flash, *opcode, addr, count, data);
1252*0d6140beSAndroid Build Coastguard Worker 	if (result) {
1253*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Running OPCODE 0x%02x failed ", opcode->opcode);
1254*0d6140beSAndroid Build Coastguard Worker 		if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
1255*0d6140beSAndroid Build Coastguard Worker 		    (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS)) {
1256*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("at address 0x%06"PRIx32" ", addr);
1257*0d6140beSAndroid Build Coastguard Worker 		}
1258*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("(payload length was %d).\n", count);
1259*0d6140beSAndroid Build Coastguard Worker 
1260*0d6140beSAndroid Build Coastguard Worker 		/* Print out the data array if it contains data to write.
1261*0d6140beSAndroid Build Coastguard Worker 		 * Errors are detected before the received data is read back into
1262*0d6140beSAndroid Build Coastguard Worker 		 * the array so it won't make sense to print it then. */
1263*0d6140beSAndroid Build Coastguard Worker 		if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
1264*0d6140beSAndroid Build Coastguard Worker 		    (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) {
1265*0d6140beSAndroid Build Coastguard Worker 			int i;
1266*0d6140beSAndroid Build Coastguard Worker 			msg_pspew("The data was:\n");
1267*0d6140beSAndroid Build Coastguard Worker 			for (i = 0; i < count; i++){
1268*0d6140beSAndroid Build Coastguard Worker 				msg_pspew("%3d: 0x%02"PRIx8"\n", i, data[i]);
1269*0d6140beSAndroid Build Coastguard Worker 			}
1270*0d6140beSAndroid Build Coastguard Worker 		}
1271*0d6140beSAndroid Build Coastguard Worker 	}
1272*0d6140beSAndroid Build Coastguard Worker 
1273*0d6140beSAndroid Build Coastguard Worker 	return result;
1274*0d6140beSAndroid Build Coastguard Worker }
1275*0d6140beSAndroid Build Coastguard Worker 
1276*0d6140beSAndroid Build Coastguard Worker #define MAX_FD_REGIONS 16
1277*0d6140beSAndroid Build Coastguard Worker struct fd_region {
1278*0d6140beSAndroid Build Coastguard Worker 	const char* name;
1279*0d6140beSAndroid Build Coastguard Worker 	enum ich_access_protection level;
1280*0d6140beSAndroid Build Coastguard Worker 	uint32_t base;
1281*0d6140beSAndroid Build Coastguard Worker 	uint32_t limit;
1282*0d6140beSAndroid Build Coastguard Worker };
1283*0d6140beSAndroid Build Coastguard Worker 
1284*0d6140beSAndroid Build Coastguard Worker struct hwseq_data {
1285*0d6140beSAndroid Build Coastguard Worker 	uint32_t size_comp0;
1286*0d6140beSAndroid Build Coastguard Worker 	uint32_t size_comp1;
1287*0d6140beSAndroid Build Coastguard Worker 	uint32_t addr_mask;
1288*0d6140beSAndroid Build Coastguard Worker 	bool only_4k;
1289*0d6140beSAndroid Build Coastguard Worker 	uint32_t hsfc_fcycle;
1290*0d6140beSAndroid Build Coastguard Worker 
1291*0d6140beSAndroid Build Coastguard Worker 	struct fd_region fd_regions[MAX_FD_REGIONS];
1292*0d6140beSAndroid Build Coastguard Worker };
1293*0d6140beSAndroid Build Coastguard Worker 
get_hwseq_data_from_context(const struct flashctx * flash)1294*0d6140beSAndroid Build Coastguard Worker static struct hwseq_data *get_hwseq_data_from_context(const struct flashctx *flash)
1295*0d6140beSAndroid Build Coastguard Worker {
1296*0d6140beSAndroid Build Coastguard Worker 	return flash->mst->opaque.data;
1297*0d6140beSAndroid Build Coastguard Worker }
1298*0d6140beSAndroid Build Coastguard Worker 
1299*0d6140beSAndroid Build Coastguard Worker /* Sets FLA in FADDR to (addr & hwseq_data->addr_mask) without touching other bits. */
ich_hwseq_set_addr(uint32_t addr,uint32_t mask)1300*0d6140beSAndroid Build Coastguard Worker static void ich_hwseq_set_addr(uint32_t addr, uint32_t mask)
1301*0d6140beSAndroid Build Coastguard Worker {
1302*0d6140beSAndroid Build Coastguard Worker 	uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~mask;
1303*0d6140beSAndroid Build Coastguard Worker 	REGWRITE32(ICH9_REG_FADDR, (addr & mask) | addr_old);
1304*0d6140beSAndroid Build Coastguard Worker }
1305*0d6140beSAndroid Build Coastguard Worker 
1306*0d6140beSAndroid Build Coastguard Worker /* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes
1307*0d6140beSAndroid Build Coastguard Worker  * of the block containing this address. May return nonsense if the address is
1308*0d6140beSAndroid Build Coastguard Worker  * not valid. The erase block size for a specific address depends on the flash
1309*0d6140beSAndroid Build Coastguard Worker  * partition layout as specified by FPB and the partition properties as defined
1310*0d6140beSAndroid Build Coastguard Worker  * by UVSCC and LVSCC respectively. An alternative to implement this method
1311*0d6140beSAndroid Build Coastguard Worker  * would be by querying FPB and the respective VSCC register directly.
1312*0d6140beSAndroid Build Coastguard Worker  */
ich_hwseq_get_erase_block_size(unsigned int addr,uint32_t addr_mask,bool only_4k)1313*0d6140beSAndroid Build Coastguard Worker static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr, uint32_t addr_mask, bool only_4k)
1314*0d6140beSAndroid Build Coastguard Worker {
1315*0d6140beSAndroid Build Coastguard Worker 	uint8_t enc_berase;
1316*0d6140beSAndroid Build Coastguard Worker 	static const uint32_t dec_berase[4] = {
1317*0d6140beSAndroid Build Coastguard Worker 		256,
1318*0d6140beSAndroid Build Coastguard Worker 		4 * 1024,
1319*0d6140beSAndroid Build Coastguard Worker 		8 * 1024,
1320*0d6140beSAndroid Build Coastguard Worker 		64 * 1024
1321*0d6140beSAndroid Build Coastguard Worker 	};
1322*0d6140beSAndroid Build Coastguard Worker 
1323*0d6140beSAndroid Build Coastguard Worker 	if (only_4k) {
1324*0d6140beSAndroid Build Coastguard Worker 		return 4 * 1024;
1325*0d6140beSAndroid Build Coastguard Worker 	}
1326*0d6140beSAndroid Build Coastguard Worker 
1327*0d6140beSAndroid Build Coastguard Worker 	ich_hwseq_set_addr(addr, addr_mask);
1328*0d6140beSAndroid Build Coastguard Worker 	enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >> HSFS_BERASE_OFF;
1329*0d6140beSAndroid Build Coastguard Worker 	return dec_berase[enc_berase];
1330*0d6140beSAndroid Build Coastguard Worker }
1331*0d6140beSAndroid Build Coastguard Worker 
1332*0d6140beSAndroid Build Coastguard Worker /* Polls for Cycle Done Status, Flash Cycle Error or timeout in 8 us intervals.
1333*0d6140beSAndroid Build Coastguard Worker    Resets all error flags in HSFS.
1334*0d6140beSAndroid Build Coastguard Worker    Returns 0 if the cycle completes successfully without errors within
1335*0d6140beSAndroid Build Coastguard Worker    timeout us, 1 on errors. */
ich_hwseq_wait_for_cycle_complete(unsigned int len,enum ich_chipset ich_gen,uint32_t addr_mask)1336*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_wait_for_cycle_complete(unsigned int len, enum ich_chipset ich_gen, uint32_t addr_mask)
1337*0d6140beSAndroid Build Coastguard Worker {
1338*0d6140beSAndroid Build Coastguard Worker 	/*
1339*0d6140beSAndroid Build Coastguard Worker 	 * The SPI bus may be busy due to performing operations from other masters, hence
1340*0d6140beSAndroid Build Coastguard Worker 	 * introduce the long timeout of 30s to cover the worst case scenarios as well.
1341*0d6140beSAndroid Build Coastguard Worker 	 */
1342*0d6140beSAndroid Build Coastguard Worker 	unsigned int timeout_us = 30 * 1000 * 1000;
1343*0d6140beSAndroid Build Coastguard Worker 	uint16_t hsfs;
1344*0d6140beSAndroid Build Coastguard Worker 	uint32_t addr;
1345*0d6140beSAndroid Build Coastguard Worker 
1346*0d6140beSAndroid Build Coastguard Worker 	timeout_us /= 8; /* scale timeout duration to counter */
1347*0d6140beSAndroid Build Coastguard Worker 	while ((((hsfs = REGREAD16(ICH9_REG_HSFS)) &
1348*0d6140beSAndroid Build Coastguard Worker 		 (HSFS_FDONE | HSFS_FCERR)) == 0) &&
1349*0d6140beSAndroid Build Coastguard Worker 	       --timeout_us) {
1350*0d6140beSAndroid Build Coastguard Worker 		default_delay(8);
1351*0d6140beSAndroid Build Coastguard Worker 	}
1352*0d6140beSAndroid Build Coastguard Worker 	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
1353*0d6140beSAndroid Build Coastguard Worker 	if (!timeout_us) {
1354*0d6140beSAndroid Build Coastguard Worker 		addr = REGREAD32(ICH9_REG_FADDR) & addr_mask;
1355*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Timeout error between offset 0x%08"PRIx32" and "
1356*0d6140beSAndroid Build Coastguard Worker 			 "0x%08"PRIx32" (= 0x%08"PRIx32" + %d)!\n",
1357*0d6140beSAndroid Build Coastguard Worker 			 addr, addr + len - 1, addr, len - 1);
1358*0d6140beSAndroid Build Coastguard Worker 		prettyprint_ich9_reg_hsfs(hsfs, ich_gen);
1359*0d6140beSAndroid Build Coastguard Worker 		prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC), ich_gen);
1360*0d6140beSAndroid Build Coastguard Worker 		return 1;
1361*0d6140beSAndroid Build Coastguard Worker 	}
1362*0d6140beSAndroid Build Coastguard Worker 
1363*0d6140beSAndroid Build Coastguard Worker 	if (hsfs & HSFS_FCERR) {
1364*0d6140beSAndroid Build Coastguard Worker 		addr = REGREAD32(ICH9_REG_FADDR) & addr_mask;
1365*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Transaction error between offset 0x%08"PRIx32" and "
1366*0d6140beSAndroid Build Coastguard Worker 			 "0x%08"PRIx32" (= 0x%08"PRIx32" + %d)!\n",
1367*0d6140beSAndroid Build Coastguard Worker 			 addr, addr + len - 1, addr, len - 1);
1368*0d6140beSAndroid Build Coastguard Worker 		prettyprint_ich9_reg_hsfs(hsfs, ich_gen);
1369*0d6140beSAndroid Build Coastguard Worker 		prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC), ich_gen);
1370*0d6140beSAndroid Build Coastguard Worker 		return 1;
1371*0d6140beSAndroid Build Coastguard Worker 	}
1372*0d6140beSAndroid Build Coastguard Worker 	return 0;
1373*0d6140beSAndroid Build Coastguard Worker }
1374*0d6140beSAndroid Build Coastguard Worker 
1375*0d6140beSAndroid Build Coastguard Worker /* Fire up a transfer using the hardware sequencer. */
ich_start_hwseq_xfer(const struct flashctx * flash,uint32_t hsfc_cycle,uint32_t flash_addr,size_t len,uint32_t addr_mask)1376*0d6140beSAndroid Build Coastguard Worker static void ich_start_hwseq_xfer(const struct flashctx *flash,
1377*0d6140beSAndroid Build Coastguard Worker 		uint32_t hsfc_cycle, uint32_t flash_addr, size_t len,
1378*0d6140beSAndroid Build Coastguard Worker 		uint32_t addr_mask)
1379*0d6140beSAndroid Build Coastguard Worker {
1380*0d6140beSAndroid Build Coastguard Worker 	/* make sure HSFC register is cleared before initiate any operation */
1381*0d6140beSAndroid Build Coastguard Worker 	uint16_t hsfc = 0;
1382*0d6140beSAndroid Build Coastguard Worker 
1383*0d6140beSAndroid Build Coastguard Worker 	/* Sets flash_addr in FADDR */
1384*0d6140beSAndroid Build Coastguard Worker 	ich_hwseq_set_addr(flash_addr, addr_mask);
1385*0d6140beSAndroid Build Coastguard Worker 
1386*0d6140beSAndroid Build Coastguard Worker 	/* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */
1387*0d6140beSAndroid Build Coastguard Worker 	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
1388*0d6140beSAndroid Build Coastguard Worker 
1389*0d6140beSAndroid Build Coastguard Worker 	/* Set up transaction parameters. */
1390*0d6140beSAndroid Build Coastguard Worker 	hsfc |= hsfc_cycle;
1391*0d6140beSAndroid Build Coastguard Worker 	/*
1392*0d6140beSAndroid Build Coastguard Worker 	 * The number of bytes transferred is the value of `FDBC` plus 1, hence,
1393*0d6140beSAndroid Build Coastguard Worker 	 * subtracted 1 from the length field.
1394*0d6140beSAndroid Build Coastguard Worker 	 * As per Intel EDS, `0b` in the FDBC represents 1 byte while `0x3f`
1395*0d6140beSAndroid Build Coastguard Worker 	 * represents 64-bytes to be transferred.
1396*0d6140beSAndroid Build Coastguard Worker 	 */
1397*0d6140beSAndroid Build Coastguard Worker 	hsfc |= HSFC_FDBC_VAL(len - 1);
1398*0d6140beSAndroid Build Coastguard Worker 	hsfc |= HSFC_FGO; /* start */
1399*0d6140beSAndroid Build Coastguard Worker 	prettyprint_ich9_reg_hsfc(hsfc, ich_generation);
1400*0d6140beSAndroid Build Coastguard Worker 	REGWRITE16(ICH9_REG_HSFC, hsfc);
1401*0d6140beSAndroid Build Coastguard Worker }
1402*0d6140beSAndroid Build Coastguard Worker 
ich_wait_for_hwseq_spi_cycle_complete(void)1403*0d6140beSAndroid Build Coastguard Worker static int ich_wait_for_hwseq_spi_cycle_complete(void)
1404*0d6140beSAndroid Build Coastguard Worker {
1405*0d6140beSAndroid Build Coastguard Worker 	if (REGREAD8(ICH9_REG_HSFS) & HSFS_SCIP) {
1406*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Error: SCIP bit is unexpectedly set.\n");
1407*0d6140beSAndroid Build Coastguard Worker 		return 1;
1408*0d6140beSAndroid Build Coastguard Worker 	}
1409*0d6140beSAndroid Build Coastguard Worker 	return 0;
1410*0d6140beSAndroid Build Coastguard Worker }
1411*0d6140beSAndroid Build Coastguard Worker 
1412*0d6140beSAndroid Build Coastguard Worker /* Execute SPI flash transfer */
ich_exec_sync_hwseq_xfer(const struct flashctx * flash,uint32_t hsfc_cycle,uint32_t flash_addr,size_t len,enum ich_chipset ich_gen,uint32_t addr_mask)1413*0d6140beSAndroid Build Coastguard Worker static int ich_exec_sync_hwseq_xfer(const struct flashctx *flash, uint32_t hsfc_cycle, uint32_t flash_addr,
1414*0d6140beSAndroid Build Coastguard Worker 				size_t len, enum ich_chipset ich_gen, uint32_t addr_mask)
1415*0d6140beSAndroid Build Coastguard Worker {
1416*0d6140beSAndroid Build Coastguard Worker 	if (ich_wait_for_hwseq_spi_cycle_complete()) {
1417*0d6140beSAndroid Build Coastguard Worker 		msg_perr("SPI Transaction Timeout due to previous operation in process!\n");
1418*0d6140beSAndroid Build Coastguard Worker 		return 1;
1419*0d6140beSAndroid Build Coastguard Worker 	}
1420*0d6140beSAndroid Build Coastguard Worker 
1421*0d6140beSAndroid Build Coastguard Worker 	ich_start_hwseq_xfer(flash, hsfc_cycle, flash_addr, len, addr_mask);
1422*0d6140beSAndroid Build Coastguard Worker 	return ich_hwseq_wait_for_cycle_complete(len, ich_gen, addr_mask);
1423*0d6140beSAndroid Build Coastguard Worker }
1424*0d6140beSAndroid Build Coastguard Worker 
ich_get_region(const struct flashctx * flash,unsigned int addr,struct flash_region * region)1425*0d6140beSAndroid Build Coastguard Worker static void ich_get_region(const struct flashctx *flash, unsigned int addr, struct flash_region *region)
1426*0d6140beSAndroid Build Coastguard Worker {
1427*0d6140beSAndroid Build Coastguard Worker 	struct ich_descriptors desc = { 0 };
1428*0d6140beSAndroid Build Coastguard Worker 	const ssize_t nr = ich_number_of_regions(ich_generation, &desc.content);
1429*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1430*0d6140beSAndroid Build Coastguard Worker 	const struct fd_region *fd_regions = hwseq_data->fd_regions;
1431*0d6140beSAndroid Build Coastguard Worker 
1432*0d6140beSAndroid Build Coastguard Worker 	/*
1433*0d6140beSAndroid Build Coastguard Worker 	 * Set default values for the region. If no flash descriptor containing
1434*0d6140beSAndroid Build Coastguard Worker 	 * addr is found, these values will be used instead.
1435*0d6140beSAndroid Build Coastguard Worker 	 *
1436*0d6140beSAndroid Build Coastguard Worker 	 * The region start and end are constrained so that they do not overlap
1437*0d6140beSAndroid Build Coastguard Worker 	 * any flash descriptor regions.
1438*0d6140beSAndroid Build Coastguard Worker 	 */
1439*0d6140beSAndroid Build Coastguard Worker 	const char *name = "";
1440*0d6140beSAndroid Build Coastguard Worker 	region->read_prot  = false;
1441*0d6140beSAndroid Build Coastguard Worker 	region->write_prot = false;
1442*0d6140beSAndroid Build Coastguard Worker 	region->start = 0;
1443*0d6140beSAndroid Build Coastguard Worker 	region->end = flashrom_flash_getsize(flash);
1444*0d6140beSAndroid Build Coastguard Worker 
1445*0d6140beSAndroid Build Coastguard Worker 	for (ssize_t i = 0; i < nr; i++) {
1446*0d6140beSAndroid Build Coastguard Worker 		uint32_t base = fd_regions[i].base;
1447*0d6140beSAndroid Build Coastguard Worker 		uint32_t limit = fd_regions[i].limit;
1448*0d6140beSAndroid Build Coastguard Worker 		enum ich_access_protection level = fd_regions[i].level;
1449*0d6140beSAndroid Build Coastguard Worker 
1450*0d6140beSAndroid Build Coastguard Worker 		if (addr < base) {
1451*0d6140beSAndroid Build Coastguard Worker 			/*
1452*0d6140beSAndroid Build Coastguard Worker 			 * fd_regions[i] starts after addr, constrain
1453*0d6140beSAndroid Build Coastguard Worker 			 * region->end so that it does not overlap.
1454*0d6140beSAndroid Build Coastguard Worker 			 */
1455*0d6140beSAndroid Build Coastguard Worker 			region->end = min(region->end, base);
1456*0d6140beSAndroid Build Coastguard Worker 		} else if (addr > limit) {
1457*0d6140beSAndroid Build Coastguard Worker 			/*
1458*0d6140beSAndroid Build Coastguard Worker 			 * fd_regions[i] ends before addr, constrain
1459*0d6140beSAndroid Build Coastguard Worker 			 * region->start so that it does not overlap.
1460*0d6140beSAndroid Build Coastguard Worker 			 */
1461*0d6140beSAndroid Build Coastguard Worker 			region->start = max(region->start, limit + 1);
1462*0d6140beSAndroid Build Coastguard Worker 		} else {
1463*0d6140beSAndroid Build Coastguard Worker 			/* fd_regions[i] contains addr, copy to *region. */
1464*0d6140beSAndroid Build Coastguard Worker 			name = fd_regions[i].name;
1465*0d6140beSAndroid Build Coastguard Worker 			region->start = base;
1466*0d6140beSAndroid Build Coastguard Worker 			region->end = limit + 1;
1467*0d6140beSAndroid Build Coastguard Worker 			region->read_prot  = (level == LOCKED) || (level == READ_PROT);
1468*0d6140beSAndroid Build Coastguard Worker 			region->write_prot = (level == LOCKED) || (level == WRITE_PROT);
1469*0d6140beSAndroid Build Coastguard Worker 			break;
1470*0d6140beSAndroid Build Coastguard Worker 		}
1471*0d6140beSAndroid Build Coastguard Worker 	}
1472*0d6140beSAndroid Build Coastguard Worker 
1473*0d6140beSAndroid Build Coastguard Worker 	region->name = strdup(name);
1474*0d6140beSAndroid Build Coastguard Worker }
1475*0d6140beSAndroid Build Coastguard Worker 
1476*0d6140beSAndroid Build Coastguard Worker /* Given RDID info, return pointer to entry in flashchips[] */
flash_id_to_entry(uint32_t mfg_id,uint32_t model_id)1477*0d6140beSAndroid Build Coastguard Worker static const struct flashchip *flash_id_to_entry(uint32_t mfg_id, uint32_t model_id)
1478*0d6140beSAndroid Build Coastguard Worker {
1479*0d6140beSAndroid Build Coastguard Worker 	const struct flashchip *chip;
1480*0d6140beSAndroid Build Coastguard Worker 
1481*0d6140beSAndroid Build Coastguard Worker 	for (chip = &flashchips[0]; chip->vendor; chip++) {
1482*0d6140beSAndroid Build Coastguard Worker 		if(is_chipname_duplicate(chip))
1483*0d6140beSAndroid Build Coastguard Worker 			continue;
1484*0d6140beSAndroid Build Coastguard Worker 
1485*0d6140beSAndroid Build Coastguard Worker 		if ((chip->manufacture_id == mfg_id) &&
1486*0d6140beSAndroid Build Coastguard Worker 		    (chip->model_id == model_id) &&
1487*0d6140beSAndroid Build Coastguard Worker 		    (chip->probe == PROBE_SPI_RDID) &&
1488*0d6140beSAndroid Build Coastguard Worker 		    ((chip->bustype & BUS_SPI) == BUS_SPI))
1489*0d6140beSAndroid Build Coastguard Worker 			return chip;
1490*0d6140beSAndroid Build Coastguard Worker 	}
1491*0d6140beSAndroid Build Coastguard Worker 
1492*0d6140beSAndroid Build Coastguard Worker 	return NULL;
1493*0d6140beSAndroid Build Coastguard Worker }
1494*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_read_status(const struct flashctx * flash,enum flash_reg reg,uint8_t * value)1495*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_read_status(const struct flashctx *flash, enum flash_reg reg, uint8_t *value)
1496*0d6140beSAndroid Build Coastguard Worker {
1497*0d6140beSAndroid Build Coastguard Worker 	const int len = 1;
1498*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1499*0d6140beSAndroid Build Coastguard Worker 
1500*0d6140beSAndroid Build Coastguard Worker 	if (reg != STATUS1) {
1501*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("%s: only supports STATUS1\n", __func__);
1502*0d6140beSAndroid Build Coastguard Worker 		/*
1503*0d6140beSAndroid Build Coastguard Worker 		 * Return SPI_INVALID_OPCODE to be consistent with spi_read_register()
1504*0d6140beSAndroid Build Coastguard Worker 		 * and make error handling simpler even though this isn't a SPI master.
1505*0d6140beSAndroid Build Coastguard Worker 		 */
1506*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_OPCODE;
1507*0d6140beSAndroid Build Coastguard Worker 	}
1508*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Reading Status register\n");
1509*0d6140beSAndroid Build Coastguard Worker 
1510*0d6140beSAndroid Build Coastguard Worker 	if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_RD_STATUS, 1, len, ich_generation,
1511*0d6140beSAndroid Build Coastguard Worker 		hwseq_data->addr_mask)) {
1512*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Reading Status register failed\n!!");
1513*0d6140beSAndroid Build Coastguard Worker 		return -1;
1514*0d6140beSAndroid Build Coastguard Worker 	}
1515*0d6140beSAndroid Build Coastguard Worker 	ich_read_data(value, len, ICH9_REG_FDATA0);
1516*0d6140beSAndroid Build Coastguard Worker 
1517*0d6140beSAndroid Build Coastguard Worker 	return 0;
1518*0d6140beSAndroid Build Coastguard Worker }
1519*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_write_status(const struct flashctx * flash,enum flash_reg reg,uint8_t value)1520*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_write_status(const struct flashctx *flash, enum flash_reg reg, uint8_t value)
1521*0d6140beSAndroid Build Coastguard Worker {
1522*0d6140beSAndroid Build Coastguard Worker 	const int len = 1;
1523*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1524*0d6140beSAndroid Build Coastguard Worker 
1525*0d6140beSAndroid Build Coastguard Worker 	if (reg != STATUS1) {
1526*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("%s: only supports STATUS1\n", __func__);
1527*0d6140beSAndroid Build Coastguard Worker 		/*
1528*0d6140beSAndroid Build Coastguard Worker 		 * Return SPI_INVALID_OPCODE to be consistent with spi_write_register()
1529*0d6140beSAndroid Build Coastguard Worker 		 * and make error handling simpler even though this isn't a SPI master.
1530*0d6140beSAndroid Build Coastguard Worker 		 */
1531*0d6140beSAndroid Build Coastguard Worker 		return SPI_INVALID_OPCODE;
1532*0d6140beSAndroid Build Coastguard Worker 	}
1533*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Writing status register\n");
1534*0d6140beSAndroid Build Coastguard Worker 
1535*0d6140beSAndroid Build Coastguard Worker 	ich_fill_data(&value, len, ICH9_REG_FDATA0);
1536*0d6140beSAndroid Build Coastguard Worker 
1537*0d6140beSAndroid Build Coastguard Worker 	if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_WR_STATUS, 1, len, ich_generation,
1538*0d6140beSAndroid Build Coastguard Worker 		hwseq_data->addr_mask)) {
1539*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Writing Status register failed\n!!");
1540*0d6140beSAndroid Build Coastguard Worker 		return -1;
1541*0d6140beSAndroid Build Coastguard Worker 	}
1542*0d6140beSAndroid Build Coastguard Worker 
1543*0d6140beSAndroid Build Coastguard Worker 	return 0;
1544*0d6140beSAndroid Build Coastguard Worker }
1545*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_get_flash_id(struct flashctx * flash,enum ich_chipset ich_gen)1546*0d6140beSAndroid Build Coastguard Worker static void ich_hwseq_get_flash_id(struct flashctx *flash, enum ich_chipset ich_gen)
1547*0d6140beSAndroid Build Coastguard Worker {
1548*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1549*0d6140beSAndroid Build Coastguard Worker 	if (hwseq_data->size_comp1 != 0) {
1550*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Multiple flash components detected, skipping flash identification.\n");
1551*0d6140beSAndroid Build Coastguard Worker 		return;
1552*0d6140beSAndroid Build Coastguard Worker 	}
1553*0d6140beSAndroid Build Coastguard Worker 
1554*0d6140beSAndroid Build Coastguard Worker 	/* PCH100 or above is required for RDID, ICH9 does not support it. */
1555*0d6140beSAndroid Build Coastguard Worker 	if (hwseq_data->hsfc_fcycle != PCH100_HSFC_FCYCLE) {
1556*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("RDID cycle not supported, skipping flash identification.\n");
1557*0d6140beSAndroid Build Coastguard Worker 		return;
1558*0d6140beSAndroid Build Coastguard Worker 	}
1559*0d6140beSAndroid Build Coastguard Worker 
1560*0d6140beSAndroid Build Coastguard Worker 	/*
1561*0d6140beSAndroid Build Coastguard Worker 	 * RDID gives 3 byte output:
1562*0d6140beSAndroid Build Coastguard Worker 	 *     Byte 0: Manufacturer ID
1563*0d6140beSAndroid Build Coastguard Worker 	 *     Byte 1: Model ID (MSB)
1564*0d6140beSAndroid Build Coastguard Worker 	 *     Byte 2: Model ID (LSB)
1565*0d6140beSAndroid Build Coastguard Worker 	 */
1566*0d6140beSAndroid Build Coastguard Worker 	const int len = 3;
1567*0d6140beSAndroid Build Coastguard Worker 	uint8_t data[len];
1568*0d6140beSAndroid Build Coastguard Worker 
1569*0d6140beSAndroid Build Coastguard Worker 	if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_RDID, 1, len, ich_gen,
1570*0d6140beSAndroid Build Coastguard Worker 		hwseq_data->addr_mask)) {
1571*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Timed out waiting for RDID to complete.\n");
1572*0d6140beSAndroid Build Coastguard Worker 	}
1573*0d6140beSAndroid Build Coastguard Worker 
1574*0d6140beSAndroid Build Coastguard Worker 	ich_read_data(data, len, ICH9_REG_FDATA0);
1575*0d6140beSAndroid Build Coastguard Worker 	uint32_t mfg_id = data[0];
1576*0d6140beSAndroid Build Coastguard Worker 	uint32_t model_id = (data[1] << 8) | data[2];
1577*0d6140beSAndroid Build Coastguard Worker 
1578*0d6140beSAndroid Build Coastguard Worker 	const struct flashchip *entry = flash_id_to_entry(mfg_id, model_id);
1579*0d6140beSAndroid Build Coastguard Worker 	if (!entry) {
1580*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Unable to identify chip, mfg_id: 0x%02"PRIx32", "
1581*0d6140beSAndroid Build Coastguard Worker 				"model_id: 0x%02"PRIx32"\n", mfg_id, model_id);
1582*0d6140beSAndroid Build Coastguard Worker 		return;
1583*0d6140beSAndroid Build Coastguard Worker 	}
1584*0d6140beSAndroid Build Coastguard Worker 
1585*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Chip identified: %s\n", entry->name);
1586*0d6140beSAndroid Build Coastguard Worker 
1587*0d6140beSAndroid Build Coastguard Worker 	/* Update informational flash chip entries only */
1588*0d6140beSAndroid Build Coastguard Worker 	flash->chip->vendor = entry->vendor;
1589*0d6140beSAndroid Build Coastguard Worker 	flash->chip->name = entry->name;
1590*0d6140beSAndroid Build Coastguard Worker 	flash->chip->manufacture_id = entry->manufacture_id;
1591*0d6140beSAndroid Build Coastguard Worker 	flash->chip->model_id = entry->model_id;
1592*0d6140beSAndroid Build Coastguard Worker 	/* total_size read from flash descriptor */
1593*0d6140beSAndroid Build Coastguard Worker 	flash->chip->page_size = entry->page_size;
1594*0d6140beSAndroid Build Coastguard Worker 	flash->chip->feature_bits = entry->feature_bits;
1595*0d6140beSAndroid Build Coastguard Worker 	flash->chip->tested = entry->tested;
1596*0d6140beSAndroid Build Coastguard Worker 	/* Support writeprotect */
1597*0d6140beSAndroid Build Coastguard Worker 	flash->chip->reg_bits = entry->reg_bits;
1598*0d6140beSAndroid Build Coastguard Worker 	flash->chip->decode_range = entry->decode_range;
1599*0d6140beSAndroid Build Coastguard Worker }
1600*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_probe(struct flashctx * flash)1601*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_probe(struct flashctx *flash)
1602*0d6140beSAndroid Build Coastguard Worker {
1603*0d6140beSAndroid Build Coastguard Worker 	uint32_t total_size, boundary;
1604*0d6140beSAndroid Build Coastguard Worker 	uint32_t erase_size_low, size_low, erase_size_high, size_high;
1605*0d6140beSAndroid Build Coastguard Worker 	struct block_eraser *eraser;
1606*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1607*0d6140beSAndroid Build Coastguard Worker 
1608*0d6140beSAndroid Build Coastguard Worker 	total_size = hwseq_data->size_comp0 + hwseq_data->size_comp1;
1609*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("Hardware sequencing reports %d attached SPI flash chip",
1610*0d6140beSAndroid Build Coastguard Worker 		 (hwseq_data->size_comp1 != 0) ? 2 : 1);
1611*0d6140beSAndroid Build Coastguard Worker 	if (hwseq_data->size_comp1 != 0)
1612*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("s with a combined");
1613*0d6140beSAndroid Build Coastguard Worker 	else
1614*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg(" with a");
1615*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg(" density of %"PRId32" kB.\n", total_size / 1024);
1616*0d6140beSAndroid Build Coastguard Worker 	flash->chip->total_size = total_size / 1024;
1617*0d6140beSAndroid Build Coastguard Worker 
1618*0d6140beSAndroid Build Coastguard Worker 	eraser = &(flash->chip->block_erasers[0]);
1619*0d6140beSAndroid Build Coastguard Worker 	if (!hwseq_data->only_4k)
1620*0d6140beSAndroid Build Coastguard Worker 		boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12;
1621*0d6140beSAndroid Build Coastguard Worker 	else
1622*0d6140beSAndroid Build Coastguard Worker 		boundary = 0;
1623*0d6140beSAndroid Build Coastguard Worker 	size_high = total_size - boundary;
1624*0d6140beSAndroid Build Coastguard Worker 	erase_size_high = ich_hwseq_get_erase_block_size(boundary, hwseq_data->addr_mask, hwseq_data->only_4k);
1625*0d6140beSAndroid Build Coastguard Worker 
1626*0d6140beSAndroid Build Coastguard Worker 	if (boundary == 0) {
1627*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg2("There is only one partition containing the whole "
1628*0d6140beSAndroid Build Coastguard Worker 			 "address space (0x%06x - 0x%06"PRIx32").\n", 0, size_high-1);
1629*0d6140beSAndroid Build Coastguard Worker 		eraser->eraseblocks[0].size = erase_size_high;
1630*0d6140beSAndroid Build Coastguard Worker 		eraser->eraseblocks[0].count = size_high / erase_size_high;
1631*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg2("There are %"PRId32" erase blocks with %"PRId32" B each.\n",
1632*0d6140beSAndroid Build Coastguard Worker 			 size_high / erase_size_high, erase_size_high);
1633*0d6140beSAndroid Build Coastguard Worker 	} else {
1634*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg2("The flash address space (0x%06x - 0x%06"PRIx32") is divided "
1635*0d6140beSAndroid Build Coastguard Worker 			 "at address 0x%06"PRIx32" in two partitions.\n",
1636*0d6140beSAndroid Build Coastguard Worker 			 0, total_size-1, boundary);
1637*0d6140beSAndroid Build Coastguard Worker 		size_low = total_size - size_high;
1638*0d6140beSAndroid Build Coastguard Worker 		erase_size_low = ich_hwseq_get_erase_block_size(0, hwseq_data->addr_mask, hwseq_data->only_4k);
1639*0d6140beSAndroid Build Coastguard Worker 
1640*0d6140beSAndroid Build Coastguard Worker 		eraser->eraseblocks[0].size = erase_size_low;
1641*0d6140beSAndroid Build Coastguard Worker 		eraser->eraseblocks[0].count = size_low / erase_size_low;
1642*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("The first partition ranges from 0x%06x to 0x%06"PRIx32".\n", 0, size_low-1);
1643*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("In that range are %"PRId32" erase blocks with %"PRId32" B each.\n",
1644*0d6140beSAndroid Build Coastguard Worker 			 size_low / erase_size_low, erase_size_low);
1645*0d6140beSAndroid Build Coastguard Worker 
1646*0d6140beSAndroid Build Coastguard Worker 		eraser->eraseblocks[1].size = erase_size_high;
1647*0d6140beSAndroid Build Coastguard Worker 		eraser->eraseblocks[1].count = size_high / erase_size_high;
1648*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("The second partition ranges from 0x%06"PRIx32" to 0x%06"PRIx32".\n",
1649*0d6140beSAndroid Build Coastguard Worker 			 boundary, total_size-1);
1650*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("In that range are %"PRId32" erase blocks with %"PRId32" B each.\n",
1651*0d6140beSAndroid Build Coastguard Worker 			 size_high / erase_size_high, erase_size_high);
1652*0d6140beSAndroid Build Coastguard Worker 	}
1653*0d6140beSAndroid Build Coastguard Worker 
1654*0d6140beSAndroid Build Coastguard Worker 	/* May be overwritten by ich_hwseq_get_flash_id(). */
1655*0d6140beSAndroid Build Coastguard Worker 	flash->chip->tested = TEST_OK_PREWB;
1656*0d6140beSAndroid Build Coastguard Worker 
1657*0d6140beSAndroid Build Coastguard Worker 	ich_hwseq_get_flash_id(flash, ich_generation);
1658*0d6140beSAndroid Build Coastguard Worker 
1659*0d6140beSAndroid Build Coastguard Worker 	return 1;
1660*0d6140beSAndroid Build Coastguard Worker }
1661*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_block_erase(struct flashctx * flash,unsigned int addr,unsigned int len)1662*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
1663*0d6140beSAndroid Build Coastguard Worker 				 unsigned int len)
1664*0d6140beSAndroid Build Coastguard Worker {
1665*0d6140beSAndroid Build Coastguard Worker 	uint32_t erase_block;
1666*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1667*0d6140beSAndroid Build Coastguard Worker 
1668*0d6140beSAndroid Build Coastguard Worker 	if (is_dry_run())
1669*0d6140beSAndroid Build Coastguard Worker 		return 0;
1670*0d6140beSAndroid Build Coastguard Worker 
1671*0d6140beSAndroid Build Coastguard Worker 	erase_block = ich_hwseq_get_erase_block_size(addr, hwseq_data->addr_mask, hwseq_data->only_4k);
1672*0d6140beSAndroid Build Coastguard Worker 	if (len != erase_block) {
1673*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("Erase block size for address 0x%06x is %"PRId32" B, "
1674*0d6140beSAndroid Build Coastguard Worker 			 "but requested erase block size is %d B. "
1675*0d6140beSAndroid Build Coastguard Worker 			 "Not erasing anything.\n", addr, erase_block, len);
1676*0d6140beSAndroid Build Coastguard Worker 		return -1;
1677*0d6140beSAndroid Build Coastguard Worker 	}
1678*0d6140beSAndroid Build Coastguard Worker 
1679*0d6140beSAndroid Build Coastguard Worker 	/* Although the hardware supports this (it would erase the whole block
1680*0d6140beSAndroid Build Coastguard Worker 	 * containing the address) we play safe here. */
1681*0d6140beSAndroid Build Coastguard Worker 	if (addr % erase_block != 0) {
1682*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("Erase address 0x%06x is not aligned to the erase "
1683*0d6140beSAndroid Build Coastguard Worker 			 "block boundary (any multiple of %"PRId32"). "
1684*0d6140beSAndroid Build Coastguard Worker 			 "Not erasing anything.\n", addr, erase_block);
1685*0d6140beSAndroid Build Coastguard Worker 		return -1;
1686*0d6140beSAndroid Build Coastguard Worker 	}
1687*0d6140beSAndroid Build Coastguard Worker 
1688*0d6140beSAndroid Build Coastguard Worker 	if (addr + len > flash->chip->total_size * 1024) {
1689*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Request to erase some inaccessible memory address(es)"
1690*0d6140beSAndroid Build Coastguard Worker 			 " (addr=0x%x, len=%d). Not erasing anything.\n", addr, len);
1691*0d6140beSAndroid Build Coastguard Worker 		return -1;
1692*0d6140beSAndroid Build Coastguard Worker 	}
1693*0d6140beSAndroid Build Coastguard Worker 
1694*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Erasing %d bytes starting at 0x%06x.\n", len, addr);
1695*0d6140beSAndroid Build Coastguard Worker 
1696*0d6140beSAndroid Build Coastguard Worker 	if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_BLOCK_ERASE, addr, 1, ich_generation,
1697*0d6140beSAndroid Build Coastguard Worker 		hwseq_data->addr_mask))
1698*0d6140beSAndroid Build Coastguard Worker 		return -1;
1699*0d6140beSAndroid Build Coastguard Worker 	return 0;
1700*0d6140beSAndroid Build Coastguard Worker }
1701*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_read(struct flashctx * flash,uint8_t * buf,unsigned int addr,unsigned int len)1702*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
1703*0d6140beSAndroid Build Coastguard Worker 			  unsigned int addr, unsigned int len)
1704*0d6140beSAndroid Build Coastguard Worker {
1705*0d6140beSAndroid Build Coastguard Worker 	uint8_t block_len;
1706*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1707*0d6140beSAndroid Build Coastguard Worker 
1708*0d6140beSAndroid Build Coastguard Worker 	if (addr + len > flash->chip->total_size * 1024) {
1709*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Request to read from an inaccessible memory address "
1710*0d6140beSAndroid Build Coastguard Worker 			 "(addr=0x%x, len=%d).\n", addr, len);
1711*0d6140beSAndroid Build Coastguard Worker 		return -1;
1712*0d6140beSAndroid Build Coastguard Worker 	}
1713*0d6140beSAndroid Build Coastguard Worker 
1714*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Reading %d bytes starting at 0x%06x.\n", len, addr);
1715*0d6140beSAndroid Build Coastguard Worker 	/* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */
1716*0d6140beSAndroid Build Coastguard Worker 	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
1717*0d6140beSAndroid Build Coastguard Worker 
1718*0d6140beSAndroid Build Coastguard Worker 	while (len > 0) {
1719*0d6140beSAndroid Build Coastguard Worker 		/* Obey programmer limit... */
1720*0d6140beSAndroid Build Coastguard Worker 		block_len = min(len, flash->mst->opaque.max_data_read);
1721*0d6140beSAndroid Build Coastguard Worker 		/* as well as flash chip page borders as demanded in the Intel datasheets. */
1722*0d6140beSAndroid Build Coastguard Worker 		block_len = min(block_len, 256 - (addr & 0xFF));
1723*0d6140beSAndroid Build Coastguard Worker 
1724*0d6140beSAndroid Build Coastguard Worker 		if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_READ, addr, block_len, ich_generation,
1725*0d6140beSAndroid Build Coastguard Worker 			hwseq_data->addr_mask))
1726*0d6140beSAndroid Build Coastguard Worker 			return 1;
1727*0d6140beSAndroid Build Coastguard Worker 		ich_read_data(buf, block_len, ICH9_REG_FDATA0);
1728*0d6140beSAndroid Build Coastguard Worker 		addr += block_len;
1729*0d6140beSAndroid Build Coastguard Worker 		buf += block_len;
1730*0d6140beSAndroid Build Coastguard Worker 		len -= block_len;
1731*0d6140beSAndroid Build Coastguard Worker 	}
1732*0d6140beSAndroid Build Coastguard Worker 	return 0;
1733*0d6140beSAndroid Build Coastguard Worker }
1734*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_write(struct flashctx * flash,const uint8_t * buf,unsigned int addr,unsigned int len)1735*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned int addr, unsigned int len)
1736*0d6140beSAndroid Build Coastguard Worker {
1737*0d6140beSAndroid Build Coastguard Worker 	uint8_t block_len;
1738*0d6140beSAndroid Build Coastguard Worker 	const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
1739*0d6140beSAndroid Build Coastguard Worker 
1740*0d6140beSAndroid Build Coastguard Worker 	if (addr + len > flash->chip->total_size * 1024) {
1741*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Request to write to an inaccessible memory address "
1742*0d6140beSAndroid Build Coastguard Worker 			 "(addr=0x%x, len=%d).\n", addr, len);
1743*0d6140beSAndroid Build Coastguard Worker 		return -1;
1744*0d6140beSAndroid Build Coastguard Worker 	}
1745*0d6140beSAndroid Build Coastguard Worker 
1746*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Writing %d bytes starting at 0x%06x.\n", len, addr);
1747*0d6140beSAndroid Build Coastguard Worker 	/* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */
1748*0d6140beSAndroid Build Coastguard Worker 	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
1749*0d6140beSAndroid Build Coastguard Worker 
1750*0d6140beSAndroid Build Coastguard Worker 	while (len > 0) {
1751*0d6140beSAndroid Build Coastguard Worker 		/* Obey programmer limit... */
1752*0d6140beSAndroid Build Coastguard Worker 		block_len = min(len, flash->mst->opaque.max_data_write);
1753*0d6140beSAndroid Build Coastguard Worker 		/* as well as flash chip page borders as demanded in the Intel datasheets. */
1754*0d6140beSAndroid Build Coastguard Worker 		block_len = min(block_len, 256 - (addr & 0xFF));
1755*0d6140beSAndroid Build Coastguard Worker 		ich_fill_data(buf, block_len, ICH9_REG_FDATA0);
1756*0d6140beSAndroid Build Coastguard Worker 
1757*0d6140beSAndroid Build Coastguard Worker 		if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_WRITE, addr, block_len, ich_generation,
1758*0d6140beSAndroid Build Coastguard Worker 			hwseq_data->addr_mask))
1759*0d6140beSAndroid Build Coastguard Worker 			return -1;
1760*0d6140beSAndroid Build Coastguard Worker 		addr += block_len;
1761*0d6140beSAndroid Build Coastguard Worker 		buf += block_len;
1762*0d6140beSAndroid Build Coastguard Worker 		len -= block_len;
1763*0d6140beSAndroid Build Coastguard Worker 	}
1764*0d6140beSAndroid Build Coastguard Worker 	return 0;
1765*0d6140beSAndroid Build Coastguard Worker }
1766*0d6140beSAndroid Build Coastguard Worker 
ich_hwseq_shutdown(void * data)1767*0d6140beSAndroid Build Coastguard Worker static int ich_hwseq_shutdown(void *data)
1768*0d6140beSAndroid Build Coastguard Worker {
1769*0d6140beSAndroid Build Coastguard Worker 	free(data);
1770*0d6140beSAndroid Build Coastguard Worker 	return 0;
1771*0d6140beSAndroid Build Coastguard Worker }
1772*0d6140beSAndroid Build Coastguard Worker 
ich_spi_send_multicommand(const struct flashctx * flash,struct spi_command * cmds)1773*0d6140beSAndroid Build Coastguard Worker static int ich_spi_send_multicommand(const struct flashctx *flash,
1774*0d6140beSAndroid Build Coastguard Worker 				     struct spi_command *cmds)
1775*0d6140beSAndroid Build Coastguard Worker {
1776*0d6140beSAndroid Build Coastguard Worker 	int ret = 0;
1777*0d6140beSAndroid Build Coastguard Worker 	int i;
1778*0d6140beSAndroid Build Coastguard Worker 	int oppos, preoppos;
1779*0d6140beSAndroid Build Coastguard Worker 	for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) {
1780*0d6140beSAndroid Build Coastguard Worker 		if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) {
1781*0d6140beSAndroid Build Coastguard Worker 			/* Next command is valid. */
1782*0d6140beSAndroid Build Coastguard Worker 			preoppos = find_preop(curopcodes, cmds->writearr[0]);
1783*0d6140beSAndroid Build Coastguard Worker 			oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]);
1784*0d6140beSAndroid Build Coastguard Worker 			if ((oppos == -1) && (preoppos != -1)) {
1785*0d6140beSAndroid Build Coastguard Worker 				/* Current command is listed as preopcode in
1786*0d6140beSAndroid Build Coastguard Worker 				 * ICH struct OPCODES, but next command is not
1787*0d6140beSAndroid Build Coastguard Worker 				 * listed as opcode in that struct.
1788*0d6140beSAndroid Build Coastguard Worker 				 * Check for command sanity, then
1789*0d6140beSAndroid Build Coastguard Worker 				 * try to reprogram the ICH opcode list.
1790*0d6140beSAndroid Build Coastguard Worker 				 */
1791*0d6140beSAndroid Build Coastguard Worker 				if (find_preop(curopcodes,
1792*0d6140beSAndroid Build Coastguard Worker 					       (cmds + 1)->writearr[0]) != -1) {
1793*0d6140beSAndroid Build Coastguard Worker 					msg_perr("%s: Two subsequent "
1794*0d6140beSAndroid Build Coastguard Worker 						"preopcodes 0x%02x and 0x%02x, "
1795*0d6140beSAndroid Build Coastguard Worker 						"ignoring the first.\n",
1796*0d6140beSAndroid Build Coastguard Worker 						__func__, cmds->writearr[0],
1797*0d6140beSAndroid Build Coastguard Worker 						(cmds + 1)->writearr[0]);
1798*0d6140beSAndroid Build Coastguard Worker 					continue;
1799*0d6140beSAndroid Build Coastguard Worker 				}
1800*0d6140beSAndroid Build Coastguard Worker 				/* If the chipset is locked down, we'll fail
1801*0d6140beSAndroid Build Coastguard Worker 				 * during execution of the next command anyway.
1802*0d6140beSAndroid Build Coastguard Worker 				 * No need to bother with fixups.
1803*0d6140beSAndroid Build Coastguard Worker 				 */
1804*0d6140beSAndroid Build Coastguard Worker 				if (!ichspi_lock) {
1805*0d6140beSAndroid Build Coastguard Worker 					oppos = reprogram_opcode_on_the_fly((cmds + 1)->writearr[0], (cmds + 1)->writecnt, (cmds + 1)->readcnt);
1806*0d6140beSAndroid Build Coastguard Worker 					if (oppos == -1)
1807*0d6140beSAndroid Build Coastguard Worker 						continue;
1808*0d6140beSAndroid Build Coastguard Worker 					curopcodes->opcode[oppos].atomic = preoppos + 1;
1809*0d6140beSAndroid Build Coastguard Worker 					continue;
1810*0d6140beSAndroid Build Coastguard Worker 				}
1811*0d6140beSAndroid Build Coastguard Worker 			}
1812*0d6140beSAndroid Build Coastguard Worker 			if ((oppos != -1) && (preoppos != -1)) {
1813*0d6140beSAndroid Build Coastguard Worker 				/* Current command is listed as preopcode in
1814*0d6140beSAndroid Build Coastguard Worker 				 * ICH struct OPCODES and next command is listed
1815*0d6140beSAndroid Build Coastguard Worker 				 * as opcode in that struct. Match them up.
1816*0d6140beSAndroid Build Coastguard Worker 				 */
1817*0d6140beSAndroid Build Coastguard Worker 				curopcodes->opcode[oppos].atomic = preoppos + 1;
1818*0d6140beSAndroid Build Coastguard Worker 				continue;
1819*0d6140beSAndroid Build Coastguard Worker 			}
1820*0d6140beSAndroid Build Coastguard Worker 			/* If none of the above if-statements about oppos or
1821*0d6140beSAndroid Build Coastguard Worker 			 * preoppos matched, this is a normal opcode.
1822*0d6140beSAndroid Build Coastguard Worker 			 */
1823*0d6140beSAndroid Build Coastguard Worker 		}
1824*0d6140beSAndroid Build Coastguard Worker 		ret = ich_spi_send_command(flash, cmds->writecnt, cmds->readcnt,
1825*0d6140beSAndroid Build Coastguard Worker 					   cmds->writearr, cmds->readarr);
1826*0d6140beSAndroid Build Coastguard Worker 		/* Reset the type of all opcodes to non-atomic. */
1827*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < 8; i++)
1828*0d6140beSAndroid Build Coastguard Worker 			curopcodes->opcode[i].atomic = 0;
1829*0d6140beSAndroid Build Coastguard Worker 	}
1830*0d6140beSAndroid Build Coastguard Worker 	return ret;
1831*0d6140beSAndroid Build Coastguard Worker }
1832*0d6140beSAndroid Build Coastguard Worker 
ich_spi_probe_opcode(const struct flashctx * flash,uint8_t opcode)1833*0d6140beSAndroid Build Coastguard Worker static bool ich_spi_probe_opcode(const struct flashctx *flash, uint8_t opcode)
1834*0d6140beSAndroid Build Coastguard Worker {
1835*0d6140beSAndroid Build Coastguard Worker 	int ret = find_opcode(curopcodes, opcode);
1836*0d6140beSAndroid Build Coastguard Worker 	if ((ret == -1) && (lookup_spi_type(opcode) <= 3))
1837*0d6140beSAndroid Build Coastguard Worker 		/* opcode is in POSSIBLE_OPCODES, report supported. */
1838*0d6140beSAndroid Build Coastguard Worker 		return true;
1839*0d6140beSAndroid Build Coastguard Worker 	return ret >= 0;
1840*0d6140beSAndroid Build Coastguard Worker }
1841*0d6140beSAndroid Build Coastguard Worker 
1842*0d6140beSAndroid Build Coastguard Worker #define ICH_BMWAG(x) ((x >> 24) & 0xff)
1843*0d6140beSAndroid Build Coastguard Worker #define ICH_BMRAG(x) ((x >> 16) & 0xff)
1844*0d6140beSAndroid Build Coastguard Worker #define ICH_BRWA(x)  ((x >>  8) & 0xff)
1845*0d6140beSAndroid Build Coastguard Worker #define ICH_BRRA(x)  ((x >>  0) & 0xff)
1846*0d6140beSAndroid Build Coastguard Worker 
1847*0d6140beSAndroid Build Coastguard Worker static const enum ich_access_protection access_perms_to_protection[] = {
1848*0d6140beSAndroid Build Coastguard Worker 	LOCKED, WRITE_PROT, READ_PROT, NO_PROT
1849*0d6140beSAndroid Build Coastguard Worker };
1850*0d6140beSAndroid Build Coastguard Worker static const char *const access_names[] = {
1851*0d6140beSAndroid Build Coastguard Worker 	"read-write", "write-only", "read-only", "locked"
1852*0d6140beSAndroid Build Coastguard Worker };
1853*0d6140beSAndroid Build Coastguard Worker 
1854*0d6140beSAndroid Build Coastguard Worker #define EMBEDDED_CONTROLLER_REGION	8
1855*0d6140beSAndroid Build Coastguard Worker 
ec_region_rwperms(unsigned int i)1856*0d6140beSAndroid Build Coastguard Worker static enum ich_access_protection ec_region_rwperms(unsigned int i)
1857*0d6140beSAndroid Build Coastguard Worker {
1858*0d6140beSAndroid Build Coastguard Worker 	/*
1859*0d6140beSAndroid Build Coastguard Worker 	 * Use Flash Descriptor Observe register to determine if
1860*0d6140beSAndroid Build Coastguard Worker 	 * the EC region can be written by the BIOS master.
1861*0d6140beSAndroid Build Coastguard Worker 	 */
1862*0d6140beSAndroid Build Coastguard Worker 	int rwperms = NO_PROT;
1863*0d6140beSAndroid Build Coastguard Worker 
1864*0d6140beSAndroid Build Coastguard Worker 	struct ich_descriptors desc;
1865*0d6140beSAndroid Build Coastguard Worker 	memset(&desc, 0, sizeof(desc));
1866*0d6140beSAndroid Build Coastguard Worker 
1867*0d6140beSAndroid Build Coastguard Worker 	/* Region is RW if flash descriptor override is set */
1868*0d6140beSAndroid Build Coastguard Worker 	uint16_t freg = REGREAD16(ICH9_REG_HSFS);
1869*0d6140beSAndroid Build Coastguard Worker 	if ((freg & HSFS_FDV) && !(freg & HSFS_FDOPSS)) {
1870*0d6140beSAndroid Build Coastguard Worker 		rwperms = NO_PROT;
1871*0d6140beSAndroid Build Coastguard Worker 	} else if (read_ich_descriptors_via_fdo(ich_generation, ich_spibar, &desc) == ICH_RET_OK) {
1872*0d6140beSAndroid Build Coastguard Worker 		const struct ich_desc_master *const mstr = &desc.master;
1873*0d6140beSAndroid Build Coastguard Worker 		int bios_ec_r = mstr->mstr[i].read  & BIT(16); /* BIOS_EC_r in PCH100+ */
1874*0d6140beSAndroid Build Coastguard Worker 		int bios_ec_w = mstr->mstr[i].write & BIT(28); /* BIOS_EC_w in PCH100+ */
1875*0d6140beSAndroid Build Coastguard Worker 		if (bios_ec_r && bios_ec_w)
1876*0d6140beSAndroid Build Coastguard Worker 			rwperms = NO_PROT;
1877*0d6140beSAndroid Build Coastguard Worker 		else if (bios_ec_r && !bios_ec_w)
1878*0d6140beSAndroid Build Coastguard Worker 			rwperms = WRITE_PROT;
1879*0d6140beSAndroid Build Coastguard Worker 		else if (!bios_ec_r && bios_ec_w)
1880*0d6140beSAndroid Build Coastguard Worker 			rwperms = READ_PROT;
1881*0d6140beSAndroid Build Coastguard Worker 		else
1882*0d6140beSAndroid Build Coastguard Worker 			rwperms = LOCKED;
1883*0d6140beSAndroid Build Coastguard Worker 	}
1884*0d6140beSAndroid Build Coastguard Worker 
1885*0d6140beSAndroid Build Coastguard Worker 	return rwperms;
1886*0d6140beSAndroid Build Coastguard Worker }
1887*0d6140beSAndroid Build Coastguard Worker 
ich_get_bios_region_access(uint16_t * region_read_access,uint16_t * region_write_access)1888*0d6140beSAndroid Build Coastguard Worker static void ich_get_bios_region_access(uint16_t *region_read_access,
1889*0d6140beSAndroid Build Coastguard Worker 				       uint16_t *region_write_access)
1890*0d6140beSAndroid Build Coastguard Worker {
1891*0d6140beSAndroid Build Coastguard Worker 	uint32_t tmp;
1892*0d6140beSAndroid Build Coastguard Worker 	*region_read_access = 0;
1893*0d6140beSAndroid Build Coastguard Worker 	*region_write_access = 0;
1894*0d6140beSAndroid Build Coastguard Worker 
1895*0d6140beSAndroid Build Coastguard Worker 	if (ich_generation >= CHIPSET_METEOR_LAKE) {
1896*0d6140beSAndroid Build Coastguard Worker 		/*
1897*0d6140beSAndroid Build Coastguard Worker 		 * Starting from Meteor Lake, we need to fetch the region
1898*0d6140beSAndroid Build Coastguard Worker 		 * read/write access permissions from the BIOS_BM registers
1899*0d6140beSAndroid Build Coastguard Worker 		 * because we need to support FREG9 or above.
1900*0d6140beSAndroid Build Coastguard Worker 		 */
1901*0d6140beSAndroid Build Coastguard Worker 		*region_read_access = mmio_readw(ich_spibar + ICH_REG_BIOS_BM_RAP);
1902*0d6140beSAndroid Build Coastguard Worker 		*region_write_access = mmio_readw(ich_spibar + ICH_REG_BIOS_BM_WAP);
1903*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x118: 0x%04"PRIx16" (BIOS_BM_RAP)\n", *region_read_access);
1904*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x11a: 0x%04"PRIx16" (BIOS_BM_WAP)\n", *region_write_access);
1905*0d6140beSAndroid Build Coastguard Worker 	} else {
1906*0d6140beSAndroid Build Coastguard Worker 		/*
1907*0d6140beSAndroid Build Coastguard Worker 		 * FRAP - Flash Regions Access Permissions Register
1908*0d6140beSAndroid Build Coastguard Worker 		 * Bit Descriptions:
1909*0d6140beSAndroid Build Coastguard Worker 		 * 31:24 BIOS Master Write Access Grant (BMWAG)
1910*0d6140beSAndroid Build Coastguard Worker 		 * 23:16 BIOS Master Read Access Grant (BMRAG)
1911*0d6140beSAndroid Build Coastguard Worker 		 * 15:8 BIOS Region Write Access (BRWA)
1912*0d6140beSAndroid Build Coastguard Worker 		 * 7:0 BIOS Region Read Access (BRRA)
1913*0d6140beSAndroid Build Coastguard Worker 		 */
1914*0d6140beSAndroid Build Coastguard Worker 		tmp = mmio_readl(ich_spibar + ICH9_REG_FRAP);
1915*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x50: 0x%08"PRIx32" (FRAP)\n", tmp);
1916*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("BMWAG 0x%02"PRIx32", ", ICH_BMWAG(tmp));
1917*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("BMRAG 0x%02"PRIx32", ", ICH_BMRAG(tmp));
1918*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("BRWA 0x%02"PRIx32", ", ICH_BRWA(tmp));
1919*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("BRRA 0x%02"PRIx32"\n", ICH_BRRA(tmp));
1920*0d6140beSAndroid Build Coastguard Worker 
1921*0d6140beSAndroid Build Coastguard Worker 		*region_read_access = (uint16_t)ICH_BRRA(tmp);
1922*0d6140beSAndroid Build Coastguard Worker 		*region_write_access = (uint16_t)ICH_BRWA(tmp);
1923*0d6140beSAndroid Build Coastguard Worker 	}
1924*0d6140beSAndroid Build Coastguard Worker }
1925*0d6140beSAndroid Build Coastguard Worker 
ich_get_defined_region_count(void)1926*0d6140beSAndroid Build Coastguard Worker static unsigned int ich_get_defined_region_count(void) {
1927*0d6140beSAndroid Build Coastguard Worker 	return (ich_generation >= CHIPSET_METEOR_LAKE) ? 16 : 8;
1928*0d6140beSAndroid Build Coastguard Worker }
1929*0d6140beSAndroid Build Coastguard Worker 
ich9_handle_region_access(struct fd_region * fd_regions,uint16_t region_read_access,uint16_t region_write_access,unsigned int i)1930*0d6140beSAndroid Build Coastguard Worker static enum ich_access_protection ich9_handle_region_access(struct fd_region *fd_regions,
1931*0d6140beSAndroid Build Coastguard Worker 							    uint16_t region_read_access,
1932*0d6140beSAndroid Build Coastguard Worker 							    uint16_t region_write_access,
1933*0d6140beSAndroid Build Coastguard Worker 							    unsigned int i)
1934*0d6140beSAndroid Build Coastguard Worker {
1935*0d6140beSAndroid Build Coastguard Worker 	static const char *const region_names[] = {
1936*0d6140beSAndroid Build Coastguard Worker 		"Flash Descriptor", "BIOS", "Management Engine",
1937*0d6140beSAndroid Build Coastguard Worker 		"Gigabit Ethernet", "Platform Data", "Device Expansion",
1938*0d6140beSAndroid Build Coastguard Worker 		"BIOS2", "unknown", "EC/BMC", "Device Expansion 2",
1939*0d6140beSAndroid Build Coastguard Worker 		"Innovation Engine", "10GbE0", "10GbE1", "unknown", "unknown", "PTT",
1940*0d6140beSAndroid Build Coastguard Worker 	};
1941*0d6140beSAndroid Build Coastguard Worker 	const char *const region_name = i < ARRAY_SIZE(region_names) ? region_names[i] : "unknown";
1942*0d6140beSAndroid Build Coastguard Worker 
1943*0d6140beSAndroid Build Coastguard Worker 	uint32_t base, limit;
1944*0d6140beSAndroid Build Coastguard Worker 	unsigned int rwperms_idx;
1945*0d6140beSAndroid Build Coastguard Worker 	enum ich_access_protection rwperms;
1946*0d6140beSAndroid Build Coastguard Worker 	const int offset = i < 12
1947*0d6140beSAndroid Build Coastguard Worker 		? ICH9_REG_FREG0 + i * 4
1948*0d6140beSAndroid Build Coastguard Worker 		: APL_REG_FREG12 + (i - 12) * 4;
1949*0d6140beSAndroid Build Coastguard Worker 	uint32_t freg = mmio_readl(ich_spibar + offset);
1950*0d6140beSAndroid Build Coastguard Worker 
1951*0d6140beSAndroid Build Coastguard Worker 	base  = ICH_FREG_BASE(freg);
1952*0d6140beSAndroid Build Coastguard Worker 	limit = ICH_FREG_LIMIT(freg);
1953*0d6140beSAndroid Build Coastguard Worker 	if (base > limit || (freg == 0 && i > 0)) {
1954*0d6140beSAndroid Build Coastguard Worker 		/* this FREG is disabled */
1955*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg2("0x%02X: 0x%08"PRIx32" FREG%u: %s region is unused.\n",
1956*0d6140beSAndroid Build Coastguard Worker 			  offset, freg, i, region_name);
1957*0d6140beSAndroid Build Coastguard Worker 		return NO_PROT;
1958*0d6140beSAndroid Build Coastguard Worker 	}
1959*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%02X: 0x%08"PRIx32" ", offset, freg);
1960*0d6140beSAndroid Build Coastguard Worker 
1961*0d6140beSAndroid Build Coastguard Worker 	if (i < ich_get_defined_region_count()) {
1962*0d6140beSAndroid Build Coastguard Worker 		rwperms_idx = (((region_write_access >> i) & 1) << 1) |
1963*0d6140beSAndroid Build Coastguard Worker 			      (((region_read_access >> i) & 1) << 0);
1964*0d6140beSAndroid Build Coastguard Worker 		rwperms = access_perms_to_protection[rwperms_idx];
1965*0d6140beSAndroid Build Coastguard Worker 	} else if (i == EMBEDDED_CONTROLLER_REGION && ich_generation >= CHIPSET_100_SERIES_SUNRISE_POINT) {
1966*0d6140beSAndroid Build Coastguard Worker 		rwperms = ec_region_rwperms(i);
1967*0d6140beSAndroid Build Coastguard Worker 	} else {
1968*0d6140beSAndroid Build Coastguard Worker 		/* Datasheets might not define all the access bits for regions. We
1969*0d6140beSAndroid Build Coastguard Worker 		   can't rely on the actual descriptor settings either as there
1970*0d6140beSAndroid Build Coastguard Worker 		   are several overrides for them (those by other masters are
1971*0d6140beSAndroid Build Coastguard Worker 		   not even readable by us, *shrug*). */
1972*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("FREG%u: %s region (0x%08"PRIx32"-0x%08"PRIx32") has unknown permissions.\n",
1973*0d6140beSAndroid Build Coastguard Worker 				i, region_name, base, limit);
1974*0d6140beSAndroid Build Coastguard Worker 		return NO_PROT;
1975*0d6140beSAndroid Build Coastguard Worker 	}
1976*0d6140beSAndroid Build Coastguard Worker 	msg_pinfo("FREG%u: %s region (0x%08"PRIx32"-0x%08"PRIx32") is %s.\n", i,
1977*0d6140beSAndroid Build Coastguard Worker 		  region_name, base, limit, access_names[rwperms]);
1978*0d6140beSAndroid Build Coastguard Worker 
1979*0d6140beSAndroid Build Coastguard Worker 	/* Save region attributes for use by ich_get_region(). */
1980*0d6140beSAndroid Build Coastguard Worker 	fd_regions[i].base = base;
1981*0d6140beSAndroid Build Coastguard Worker 	fd_regions[i].limit = limit;
1982*0d6140beSAndroid Build Coastguard Worker 	fd_regions[i].level = rwperms;
1983*0d6140beSAndroid Build Coastguard Worker 	fd_regions[i].name = region_name;
1984*0d6140beSAndroid Build Coastguard Worker 
1985*0d6140beSAndroid Build Coastguard Worker 	return rwperms;
1986*0d6140beSAndroid Build Coastguard Worker }
1987*0d6140beSAndroid Build Coastguard Worker 
1988*0d6140beSAndroid Build Coastguard Worker 	/* In contrast to FRAP and the master section of the descriptor the bits
1989*0d6140beSAndroid Build Coastguard Worker 	 * in the PR registers have an inverted meaning. The bits in FRAP
1990*0d6140beSAndroid Build Coastguard Worker 	 * indicate read and write access _grant_. Here they indicate read
1991*0d6140beSAndroid Build Coastguard Worker 	 * and write _protection_ respectively. If both bits are 0 the address
1992*0d6140beSAndroid Build Coastguard Worker 	 * bits are ignored.
1993*0d6140beSAndroid Build Coastguard Worker 	 */
1994*0d6140beSAndroid Build Coastguard Worker #define ICH_PR_PERMS(pr)	(((~((pr) >> PR_RP_OFF) & 1) << 0) | \
1995*0d6140beSAndroid Build Coastguard Worker 				 ((~((pr) >> PR_WP_OFF) & 1) << 1))
1996*0d6140beSAndroid Build Coastguard Worker 
ich9_handle_pr(const size_t reg_pr0,unsigned int i)1997*0d6140beSAndroid Build Coastguard Worker static enum ich_access_protection ich9_handle_pr(const size_t reg_pr0, unsigned int i)
1998*0d6140beSAndroid Build Coastguard Worker {
1999*0d6140beSAndroid Build Coastguard Worker 	uint8_t off = reg_pr0 + (i * 4);
2000*0d6140beSAndroid Build Coastguard Worker 	uint32_t pr = mmio_readl(ich_spibar + off);
2001*0d6140beSAndroid Build Coastguard Worker 	unsigned int rwperms_idx = ICH_PR_PERMS(pr);
2002*0d6140beSAndroid Build Coastguard Worker 	enum ich_access_protection rwperms = access_perms_to_protection[rwperms_idx];
2003*0d6140beSAndroid Build Coastguard Worker 
2004*0d6140beSAndroid Build Coastguard Worker 	/* From 5 on we have GPR registers and start from 0 again. */
2005*0d6140beSAndroid Build Coastguard Worker 	const char *const prefix = i >= 5 ? "G" : "";
2006*0d6140beSAndroid Build Coastguard Worker 	if (i >= 5)
2007*0d6140beSAndroid Build Coastguard Worker 		i -= 5;
2008*0d6140beSAndroid Build Coastguard Worker 
2009*0d6140beSAndroid Build Coastguard Worker 	if (rwperms == NO_PROT) {
2010*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg2("0x%02"PRIX8": 0x%08"PRIx32" (%sPR%u is unused)\n", off, pr, prefix, i);
2011*0d6140beSAndroid Build Coastguard Worker 		return NO_PROT;
2012*0d6140beSAndroid Build Coastguard Worker 	}
2013*0d6140beSAndroid Build Coastguard Worker 
2014*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%02"PRIX8": 0x%08"PRIx32" ", off, pr);
2015*0d6140beSAndroid Build Coastguard Worker 	msg_pwarn("%sPR%u: Warning: 0x%08"PRIx32"-0x%08"PRIx32" is %s.\n", prefix, i, ICH_FREG_BASE(pr),
2016*0d6140beSAndroid Build Coastguard Worker 		  ICH_FREG_LIMIT(pr), access_names[rwperms]);
2017*0d6140beSAndroid Build Coastguard Worker 
2018*0d6140beSAndroid Build Coastguard Worker 	return rwperms;
2019*0d6140beSAndroid Build Coastguard Worker }
2020*0d6140beSAndroid Build Coastguard Worker 
2021*0d6140beSAndroid Build Coastguard Worker /* Set/Clear the read and write protection enable bits of PR register @i
2022*0d6140beSAndroid Build Coastguard Worker  * according to @read_prot and @write_prot. */
ich9_set_pr(const size_t reg_pr0,int i,int read_prot,int write_prot)2023*0d6140beSAndroid Build Coastguard Worker static void ich9_set_pr(const size_t reg_pr0, int i, int read_prot, int write_prot)
2024*0d6140beSAndroid Build Coastguard Worker {
2025*0d6140beSAndroid Build Coastguard Worker 	void *addr = ich_spibar + reg_pr0 + (i * 4);
2026*0d6140beSAndroid Build Coastguard Worker 	uint32_t old = mmio_readl(addr);
2027*0d6140beSAndroid Build Coastguard Worker 	uint32_t new;
2028*0d6140beSAndroid Build Coastguard Worker 
2029*0d6140beSAndroid Build Coastguard Worker 	msg_gspew("PR%u is 0x%08"PRIx32"", i, old);
2030*0d6140beSAndroid Build Coastguard Worker 	new = old & ~((1 << PR_RP_OFF) | (1 << PR_WP_OFF));
2031*0d6140beSAndroid Build Coastguard Worker 	if (read_prot)
2032*0d6140beSAndroid Build Coastguard Worker 		new |= (1 << PR_RP_OFF);
2033*0d6140beSAndroid Build Coastguard Worker 	if (write_prot)
2034*0d6140beSAndroid Build Coastguard Worker 		new |= (1 << PR_WP_OFF);
2035*0d6140beSAndroid Build Coastguard Worker 	if (old == new) {
2036*0d6140beSAndroid Build Coastguard Worker 		msg_gspew(" already.\n");
2037*0d6140beSAndroid Build Coastguard Worker 		return;
2038*0d6140beSAndroid Build Coastguard Worker 	}
2039*0d6140beSAndroid Build Coastguard Worker 	msg_gspew(", trying to set it to 0x%08"PRIx32" ", new);
2040*0d6140beSAndroid Build Coastguard Worker 	rmmio_writel(new, addr);
2041*0d6140beSAndroid Build Coastguard Worker 	msg_gspew("resulted in 0x%08"PRIx32".\n", mmio_readl(addr));
2042*0d6140beSAndroid Build Coastguard Worker }
2043*0d6140beSAndroid Build Coastguard Worker 
2044*0d6140beSAndroid Build Coastguard Worker static const struct spi_master spi_master_ich = {
2045*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= 64,
2046*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= 64,
2047*0d6140beSAndroid Build Coastguard Worker 	.command	= ich_spi_send_command,
2048*0d6140beSAndroid Build Coastguard Worker 	.multicommand	= ich_spi_send_multicommand,
2049*0d6140beSAndroid Build Coastguard Worker 	.map_flash_region	= physmap,
2050*0d6140beSAndroid Build Coastguard Worker 	.unmap_flash_region	= physunmap,
2051*0d6140beSAndroid Build Coastguard Worker 	.read		= default_spi_read,
2052*0d6140beSAndroid Build Coastguard Worker 	.write_256	= default_spi_write_256,
2053*0d6140beSAndroid Build Coastguard Worker 	.probe_opcode	= ich_spi_probe_opcode,
2054*0d6140beSAndroid Build Coastguard Worker };
2055*0d6140beSAndroid Build Coastguard Worker 
2056*0d6140beSAndroid Build Coastguard Worker static const struct opaque_master opaque_master_ich_hwseq = {
2057*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= 64,
2058*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= 64,
2059*0d6140beSAndroid Build Coastguard Worker 	.probe		= ich_hwseq_probe,
2060*0d6140beSAndroid Build Coastguard Worker 	.read		= ich_hwseq_read,
2061*0d6140beSAndroid Build Coastguard Worker 	.write		= ich_hwseq_write,
2062*0d6140beSAndroid Build Coastguard Worker 	.erase		= ich_hwseq_block_erase,
2063*0d6140beSAndroid Build Coastguard Worker 	.read_register	= ich_hwseq_read_status,
2064*0d6140beSAndroid Build Coastguard Worker 	.write_register	= ich_hwseq_write_status,
2065*0d6140beSAndroid Build Coastguard Worker 	.get_region	= ich_get_region,
2066*0d6140beSAndroid Build Coastguard Worker 	.shutdown	= ich_hwseq_shutdown,
2067*0d6140beSAndroid Build Coastguard Worker };
2068*0d6140beSAndroid Build Coastguard Worker 
init_ich7_spi(void * spibar,enum ich_chipset ich_gen)2069*0d6140beSAndroid Build Coastguard Worker static int init_ich7_spi(void *spibar, enum ich_chipset ich_gen)
2070*0d6140beSAndroid Build Coastguard Worker {
2071*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
2072*0d6140beSAndroid Build Coastguard Worker 
2073*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x00: 0x%04"PRIx16"     (SPIS)\n",	mmio_readw(spibar + 0));
2074*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x02: 0x%04"PRIx16"     (SPIC)\n",	mmio_readw(spibar + 2));
2075*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x04: 0x%08"PRIx32" (SPIA)\n",	mmio_readl(spibar + 4));
2076*0d6140beSAndroid Build Coastguard Worker 
2077*0d6140beSAndroid Build Coastguard Worker 	ichspi_bbar = mmio_readl(spibar + 0x50);
2078*0d6140beSAndroid Build Coastguard Worker 
2079*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x50: 0x%08"PRIx32" (BBAR)\n",	ichspi_bbar);
2080*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x54: 0x%04"PRIx16"     (PREOP)\n",	mmio_readw(spibar + 0x54));
2081*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x56: 0x%04"PRIx16"     (OPTYPE)\n",	mmio_readw(spibar + 0x56));
2082*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x58: 0x%08"PRIx32" (OPMENU)\n",	mmio_readl(spibar + 0x58));
2083*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x5c: 0x%08"PRIx32" (OPMENU+4)\n",	mmio_readl(spibar + 0x5c));
2084*0d6140beSAndroid Build Coastguard Worker 
2085*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < 3; i++) {
2086*0d6140beSAndroid Build Coastguard Worker 		int offs;
2087*0d6140beSAndroid Build Coastguard Worker 		offs = 0x60 + (i * 4);
2088*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x%02x: 0x%08"PRIx32" (PBR%u)\n", offs, mmio_readl(spibar + offs), i);
2089*0d6140beSAndroid Build Coastguard Worker 	}
2090*0d6140beSAndroid Build Coastguard Worker 	if (mmio_readw(spibar) & (1 << 15)) {
2091*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("WARNING: SPI Configuration Lockdown activated.\n");
2092*0d6140beSAndroid Build Coastguard Worker 		ichspi_lock = true;
2093*0d6140beSAndroid Build Coastguard Worker 	}
2094*0d6140beSAndroid Build Coastguard Worker 	ich_init_opcodes(ich_gen);
2095*0d6140beSAndroid Build Coastguard Worker 	ich_set_bbar(0, ich_gen);
2096*0d6140beSAndroid Build Coastguard Worker 	register_spi_master(&spi_master_ich, NULL);
2097*0d6140beSAndroid Build Coastguard Worker 
2098*0d6140beSAndroid Build Coastguard Worker 	return 0;
2099*0d6140beSAndroid Build Coastguard Worker }
2100*0d6140beSAndroid Build Coastguard Worker 
2101*0d6140beSAndroid Build Coastguard Worker enum ich_spi_mode {
2102*0d6140beSAndroid Build Coastguard Worker 	ich_auto,
2103*0d6140beSAndroid Build Coastguard Worker 	ich_hwseq,
2104*0d6140beSAndroid Build Coastguard Worker 	ich_swseq
2105*0d6140beSAndroid Build Coastguard Worker };
2106*0d6140beSAndroid Build Coastguard Worker 
get_ich_spi_mode_param(const struct programmer_cfg * cfg,enum ich_spi_mode * ich_spi_mode)2107*0d6140beSAndroid Build Coastguard Worker static int get_ich_spi_mode_param(const struct programmer_cfg *cfg, enum ich_spi_mode *ich_spi_mode)
2108*0d6140beSAndroid Build Coastguard Worker {
2109*0d6140beSAndroid Build Coastguard Worker 	char *const arg = extract_programmer_param_str(cfg, "ich_spi_mode");
2110*0d6140beSAndroid Build Coastguard Worker 	if (!arg) {
2111*0d6140beSAndroid Build Coastguard Worker 		return 0;
2112*0d6140beSAndroid Build Coastguard Worker 	} else if (!strcmp(arg, "hwseq")) {
2113*0d6140beSAndroid Build Coastguard Worker 		*ich_spi_mode = ich_hwseq;
2114*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("user selected hwseq\n");
2115*0d6140beSAndroid Build Coastguard Worker 	} else if (!strcmp(arg, "swseq")) {
2116*0d6140beSAndroid Build Coastguard Worker 		*ich_spi_mode = ich_swseq;
2117*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("user selected swseq\n");
2118*0d6140beSAndroid Build Coastguard Worker 	} else if (!strcmp(arg, "auto")) {
2119*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("user selected auto\n");
2120*0d6140beSAndroid Build Coastguard Worker 		*ich_spi_mode = ich_auto;
2121*0d6140beSAndroid Build Coastguard Worker 	} else if (!strlen(arg)) {
2122*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Missing argument for ich_spi_mode.\n");
2123*0d6140beSAndroid Build Coastguard Worker 		free(arg);
2124*0d6140beSAndroid Build Coastguard Worker 		return ERROR_FLASHROM_FATAL;
2125*0d6140beSAndroid Build Coastguard Worker 	} else {
2126*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unknown argument for ich_spi_mode: %s\n", arg);
2127*0d6140beSAndroid Build Coastguard Worker 		free(arg);
2128*0d6140beSAndroid Build Coastguard Worker 		return ERROR_FLASHROM_FATAL;
2129*0d6140beSAndroid Build Coastguard Worker 	}
2130*0d6140beSAndroid Build Coastguard Worker 	free(arg);
2131*0d6140beSAndroid Build Coastguard Worker 
2132*0d6140beSAndroid Build Coastguard Worker 	return 0;
2133*0d6140beSAndroid Build Coastguard Worker }
2134*0d6140beSAndroid Build Coastguard Worker 
init_chipset_properties(struct swseq_data * swseq,struct hwseq_data * hwseq,size_t * num_freg,size_t * num_pr,size_t * reg_pr0,enum ich_chipset ich_gen)2135*0d6140beSAndroid Build Coastguard Worker static void init_chipset_properties(struct swseq_data *swseq, struct hwseq_data *hwseq,
2136*0d6140beSAndroid Build Coastguard Worker 					size_t *num_freg, size_t *num_pr, size_t *reg_pr0,
2137*0d6140beSAndroid Build Coastguard Worker 					enum ich_chipset ich_gen)
2138*0d6140beSAndroid Build Coastguard Worker {
2139*0d6140beSAndroid Build Coastguard Worker 	/* Moving registers / bits */
2140*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
2141*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_100_SERIES_SUNRISE_POINT:
2142*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C620_SERIES_LEWISBURG:
2143*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C740_SERIES_EMMITSBURG:
2144*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_300_SERIES_CANNON_POINT:
2145*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_400_SERIES_COMET_POINT:
2146*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_500_SERIES_TIGER_POINT:
2147*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_600_SERIES_ALDER_POINT:
2148*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_700_SERIES_RAPTOR_POINT:
2149*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_APOLLO_LAKE:
2150*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_GEMINI_LAKE:
2151*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_JASPER_LAKE:
2152*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ELKHART_LAKE:
2153*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_METEOR_LAKE:
2154*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_PANTHER_LAKE:
2155*0d6140beSAndroid Build Coastguard Worker 		*num_pr			= 6;	/* Includes GPR0 */
2156*0d6140beSAndroid Build Coastguard Worker 		*reg_pr0		= PCH100_REG_FPR0;
2157*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_ssfsc	= PCH100_REG_SSFSC;
2158*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_preop	= PCH100_REG_PREOP;
2159*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_optype	= PCH100_REG_OPTYPE;
2160*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_opmenu	= PCH100_REG_OPMENU;
2161*0d6140beSAndroid Build Coastguard Worker 		hwseq->addr_mask	= PCH100_FADDR_FLA;
2162*0d6140beSAndroid Build Coastguard Worker 		hwseq->only_4k		= true;
2163*0d6140beSAndroid Build Coastguard Worker 		hwseq->hsfc_fcycle	= PCH100_HSFC_FCYCLE;
2164*0d6140beSAndroid Build Coastguard Worker 		break;
2165*0d6140beSAndroid Build Coastguard Worker 	default:
2166*0d6140beSAndroid Build Coastguard Worker 		*num_pr			= 5;
2167*0d6140beSAndroid Build Coastguard Worker 		*reg_pr0		= ICH9_REG_PR0;
2168*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_ssfsc	= ICH9_REG_SSFS;
2169*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_preop	= ICH9_REG_PREOP;
2170*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_optype	= ICH9_REG_OPTYPE;
2171*0d6140beSAndroid Build Coastguard Worker 		swseq->reg_opmenu	= ICH9_REG_OPMENU;
2172*0d6140beSAndroid Build Coastguard Worker 		hwseq->addr_mask	= ICH9_FADDR_FLA;
2173*0d6140beSAndroid Build Coastguard Worker 		hwseq->only_4k		= false;
2174*0d6140beSAndroid Build Coastguard Worker 		hwseq->hsfc_fcycle	= ICH9_HSFC_FCYCLE;
2175*0d6140beSAndroid Build Coastguard Worker 		break;
2176*0d6140beSAndroid Build Coastguard Worker 	}
2177*0d6140beSAndroid Build Coastguard Worker 
2178*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
2179*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_100_SERIES_SUNRISE_POINT:
2180*0d6140beSAndroid Build Coastguard Worker 		*num_freg = 10;
2181*0d6140beSAndroid Build Coastguard Worker 		break;
2182*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C620_SERIES_LEWISBURG:
2183*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C740_SERIES_EMMITSBURG:
2184*0d6140beSAndroid Build Coastguard Worker 		*num_freg = 12;	/* 12 MMIO regs, but 16 regions in FD spec */
2185*0d6140beSAndroid Build Coastguard Worker 		break;
2186*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_300_SERIES_CANNON_POINT:
2187*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_400_SERIES_COMET_POINT:
2188*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_500_SERIES_TIGER_POINT:
2189*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_600_SERIES_ALDER_POINT:
2190*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_700_SERIES_RAPTOR_POINT:
2191*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_APOLLO_LAKE:
2192*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_GEMINI_LAKE:
2193*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_JASPER_LAKE:
2194*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ELKHART_LAKE:
2195*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_METEOR_LAKE:
2196*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_PANTHER_LAKE:
2197*0d6140beSAndroid Build Coastguard Worker 		*num_freg = 16;
2198*0d6140beSAndroid Build Coastguard Worker 		break;
2199*0d6140beSAndroid Build Coastguard Worker 	default:
2200*0d6140beSAndroid Build Coastguard Worker 		*num_freg = 5;
2201*0d6140beSAndroid Build Coastguard Worker 		break;
2202*0d6140beSAndroid Build Coastguard Worker 	}
2203*0d6140beSAndroid Build Coastguard Worker }
2204*0d6140beSAndroid Build Coastguard Worker 
init_ich_default(const struct programmer_cfg * cfg,void * spibar,enum ich_chipset ich_gen)2205*0d6140beSAndroid Build Coastguard Worker static int init_ich_default(const struct programmer_cfg *cfg, void *spibar, enum ich_chipset ich_gen)
2206*0d6140beSAndroid Build Coastguard Worker {
2207*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
2208*0d6140beSAndroid Build Coastguard Worker 	uint16_t tmp2;
2209*0d6140beSAndroid Build Coastguard Worker 	uint32_t tmp;
2210*0d6140beSAndroid Build Coastguard Worker 	int ich_spi_rw_restricted = 0;
2211*0d6140beSAndroid Build Coastguard Worker 	bool desc_valid = false;
2212*0d6140beSAndroid Build Coastguard Worker 	struct ich_descriptors desc = { 0 };
2213*0d6140beSAndroid Build Coastguard Worker 	enum ich_spi_mode ich_spi_mode = ich_auto;
2214*0d6140beSAndroid Build Coastguard Worker 	size_t num_freg, num_pr, reg_pr0;
2215*0d6140beSAndroid Build Coastguard Worker 	struct hwseq_data hwseq_data = { 0 };
2216*0d6140beSAndroid Build Coastguard Worker 	init_chipset_properties(&swseq_data, &hwseq_data, &num_freg, &num_pr, &reg_pr0, ich_gen);
2217*0d6140beSAndroid Build Coastguard Worker 
2218*0d6140beSAndroid Build Coastguard Worker 	int ret = get_ich_spi_mode_param(cfg, &ich_spi_mode);
2219*0d6140beSAndroid Build Coastguard Worker 	if (ret)
2220*0d6140beSAndroid Build Coastguard Worker 		return ret;
2221*0d6140beSAndroid Build Coastguard Worker 
2222*0d6140beSAndroid Build Coastguard Worker 	tmp2 = mmio_readw(spibar + ICH9_REG_HSFS);
2223*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
2224*0d6140beSAndroid Build Coastguard Worker 	prettyprint_ich9_reg_hsfs(tmp2, ich_gen);
2225*0d6140beSAndroid Build Coastguard Worker 	if (tmp2 & HSFS_FLOCKDN) {
2226*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("SPI Configuration is locked down.\n");
2227*0d6140beSAndroid Build Coastguard Worker 		ichspi_lock = true;
2228*0d6140beSAndroid Build Coastguard Worker 	}
2229*0d6140beSAndroid Build Coastguard Worker 	if (tmp2 & HSFS_FDV)
2230*0d6140beSAndroid Build Coastguard Worker 		desc_valid = true;
2231*0d6140beSAndroid Build Coastguard Worker 	if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
2232*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("The Flash Descriptor Override Strap-Pin is set. Restrictions implied by\n"
2233*0d6140beSAndroid Build Coastguard Worker 			  "the Master Section of the flash descriptor are NOT in effect. Please note\n"
2234*0d6140beSAndroid Build Coastguard Worker 			  "that Protected Range (PR) restrictions still apply.\n");
2235*0d6140beSAndroid Build Coastguard Worker 	ich_init_opcodes(ich_gen);
2236*0d6140beSAndroid Build Coastguard Worker 
2237*0d6140beSAndroid Build Coastguard Worker 	if (desc_valid) {
2238*0d6140beSAndroid Build Coastguard Worker 		tmp2 = mmio_readw(spibar + ICH9_REG_HSFC);
2239*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x06: 0x%04"PRIx16" (HSFC)\n", tmp2);
2240*0d6140beSAndroid Build Coastguard Worker 		prettyprint_ich9_reg_hsfc(tmp2, ich_gen);
2241*0d6140beSAndroid Build Coastguard Worker 	}
2242*0d6140beSAndroid Build Coastguard Worker 
2243*0d6140beSAndroid Build Coastguard Worker 	tmp = mmio_readl(spibar + ICH9_REG_FADDR);
2244*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("0x08: 0x%08"PRIx32" (FADDR)\n", tmp);
2245*0d6140beSAndroid Build Coastguard Worker 
2246*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
2247*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_100_SERIES_SUNRISE_POINT:
2248*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C620_SERIES_LEWISBURG:
2249*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_C740_SERIES_EMMITSBURG:
2250*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_300_SERIES_CANNON_POINT:
2251*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_400_SERIES_COMET_POINT:
2252*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_500_SERIES_TIGER_POINT:
2253*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_600_SERIES_ALDER_POINT:
2254*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_700_SERIES_RAPTOR_POINT:
2255*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_APOLLO_LAKE:
2256*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_GEMINI_LAKE:
2257*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_JASPER_LAKE:
2258*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ELKHART_LAKE:
2259*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_METEOR_LAKE:
2260*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_PANTHER_LAKE:
2261*0d6140beSAndroid Build Coastguard Worker 		tmp = mmio_readl(spibar + PCH100_REG_DLOCK);
2262*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x0c: 0x%08"PRIx32" (DLOCK)\n", tmp);
2263*0d6140beSAndroid Build Coastguard Worker 		prettyprint_pch100_reg_dlock(tmp);
2264*0d6140beSAndroid Build Coastguard Worker 		break;
2265*0d6140beSAndroid Build Coastguard Worker 	default:
2266*0d6140beSAndroid Build Coastguard Worker 		break;
2267*0d6140beSAndroid Build Coastguard Worker 	}
2268*0d6140beSAndroid Build Coastguard Worker 
2269*0d6140beSAndroid Build Coastguard Worker 	if (desc_valid) {
2270*0d6140beSAndroid Build Coastguard Worker 		/* Get the region access data from FRAP/BIOS_BM */
2271*0d6140beSAndroid Build Coastguard Worker 		uint16_t region_read_access, region_write_access;
2272*0d6140beSAndroid Build Coastguard Worker 		ich_get_bios_region_access(&region_read_access, &region_write_access);
2273*0d6140beSAndroid Build Coastguard Worker 
2274*0d6140beSAndroid Build Coastguard Worker 		/* Handle FREGx and region access registers */
2275*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < num_freg; i++)
2276*0d6140beSAndroid Build Coastguard Worker 			ich_spi_rw_restricted |= ich9_handle_region_access(hwseq_data.fd_regions,
2277*0d6140beSAndroid Build Coastguard Worker 									   region_read_access,
2278*0d6140beSAndroid Build Coastguard Worker 									   region_write_access, i);
2279*0d6140beSAndroid Build Coastguard Worker 		if (ich_spi_rw_restricted)
2280*0d6140beSAndroid Build Coastguard Worker 			msg_pinfo("Not all flash regions are freely accessible by flashrom. This is "
2281*0d6140beSAndroid Build Coastguard Worker 				  "most likely\ndue to an active ME. Please see "
2282*0d6140beSAndroid Build Coastguard Worker 				  "https://flashrom.org/ME for details.\n");
2283*0d6140beSAndroid Build Coastguard Worker 	}
2284*0d6140beSAndroid Build Coastguard Worker 
2285*0d6140beSAndroid Build Coastguard Worker 	/* Handle PR registers */
2286*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < num_pr; i++) {
2287*0d6140beSAndroid Build Coastguard Worker 		/* if not locked down try to disable PR locks first */
2288*0d6140beSAndroid Build Coastguard Worker 		if (!ichspi_lock)
2289*0d6140beSAndroid Build Coastguard Worker 			ich9_set_pr(reg_pr0, i, 0, 0);
2290*0d6140beSAndroid Build Coastguard Worker 		ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
2291*0d6140beSAndroid Build Coastguard Worker 	}
2292*0d6140beSAndroid Build Coastguard Worker 
2293*0d6140beSAndroid Build Coastguard Worker 	switch (ich_spi_rw_restricted) {
2294*0d6140beSAndroid Build Coastguard Worker 	case WRITE_PROT:
2295*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("At least some flash regions are write protected. For write operations,\n"
2296*0d6140beSAndroid Build Coastguard Worker 			  "you should use a flash layout and include only writable regions. See\n"
2297*0d6140beSAndroid Build Coastguard Worker 			  "manpage for more details.\n");
2298*0d6140beSAndroid Build Coastguard Worker 		break;
2299*0d6140beSAndroid Build Coastguard Worker 	case READ_PROT:
2300*0d6140beSAndroid Build Coastguard Worker 	case LOCKED:
2301*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
2302*0d6140beSAndroid Build Coastguard Worker 			  "layout and include only accessible regions. For write operations, you'll\n"
2303*0d6140beSAndroid Build Coastguard Worker 			  "additionally need the --noverify-all switch. See manpage for more details.\n");
2304*0d6140beSAndroid Build Coastguard Worker 		break;
2305*0d6140beSAndroid Build Coastguard Worker 	}
2306*0d6140beSAndroid Build Coastguard Worker 
2307*0d6140beSAndroid Build Coastguard Worker 	tmp = mmio_readl(spibar + swseq_data.reg_ssfsc);
2308*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%zx: 0x%02"PRIx32" (SSFS)\n", swseq_data.reg_ssfsc, tmp & 0xff);
2309*0d6140beSAndroid Build Coastguard Worker 	prettyprint_ich9_reg_ssfs(tmp);
2310*0d6140beSAndroid Build Coastguard Worker 	if (tmp & SSFS_FCERR) {
2311*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Clearing SSFS.FCERR\n");
2312*0d6140beSAndroid Build Coastguard Worker 		mmio_writeb(SSFS_FCERR, spibar + swseq_data.reg_ssfsc);
2313*0d6140beSAndroid Build Coastguard Worker 	}
2314*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%zx: 0x%06"PRIx32" (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
2315*0d6140beSAndroid Build Coastguard Worker 	prettyprint_ich9_reg_ssfc(tmp);
2316*0d6140beSAndroid Build Coastguard Worker 
2317*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%zx: 0x%04"PRIx16" (PREOP)\n",
2318*0d6140beSAndroid Build Coastguard Worker 		 swseq_data.reg_preop, mmio_readw(spibar + swseq_data.reg_preop));
2319*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%zx: 0x%04"PRIx16" (OPTYPE)\n",
2320*0d6140beSAndroid Build Coastguard Worker 		 swseq_data.reg_optype, mmio_readw(spibar + swseq_data.reg_optype));
2321*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%zx: 0x%08"PRIx32" (OPMENU)\n",
2322*0d6140beSAndroid Build Coastguard Worker 		 swseq_data.reg_opmenu, mmio_readl(spibar + swseq_data.reg_opmenu));
2323*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x%zx: 0x%08"PRIx32" (OPMENU+4)\n",
2324*0d6140beSAndroid Build Coastguard Worker 		 swseq_data.reg_opmenu + 4, mmio_readl(spibar + swseq_data.reg_opmenu + 4));
2325*0d6140beSAndroid Build Coastguard Worker 
2326*0d6140beSAndroid Build Coastguard Worker 	if (desc_valid) {
2327*0d6140beSAndroid Build Coastguard Worker 		switch (ich_gen) {
2328*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_ICH8:
2329*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_100_SERIES_SUNRISE_POINT:
2330*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_C620_SERIES_LEWISBURG:
2331*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_C740_SERIES_EMMITSBURG:
2332*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_300_SERIES_CANNON_POINT:
2333*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_400_SERIES_COMET_POINT:
2334*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_500_SERIES_TIGER_POINT:
2335*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_600_SERIES_ALDER_POINT:
2336*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_700_SERIES_RAPTOR_POINT:
2337*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_APOLLO_LAKE:
2338*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_GEMINI_LAKE:
2339*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_JASPER_LAKE:
2340*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_BAYTRAIL:
2341*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_ELKHART_LAKE:
2342*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_METEOR_LAKE:
2343*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_PANTHER_LAKE:
2344*0d6140beSAndroid Build Coastguard Worker 			break;
2345*0d6140beSAndroid Build Coastguard Worker 		default:
2346*0d6140beSAndroid Build Coastguard Worker 			ichspi_bbar = mmio_readl(spibar + ICH9_REG_BBAR);
2347*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("0x%x: 0x%08"PRIx32" (BBAR)\n", ICH9_REG_BBAR, ichspi_bbar);
2348*0d6140beSAndroid Build Coastguard Worker 			ich_set_bbar(0, ich_gen);
2349*0d6140beSAndroid Build Coastguard Worker 			break;
2350*0d6140beSAndroid Build Coastguard Worker 		}
2351*0d6140beSAndroid Build Coastguard Worker 
2352*0d6140beSAndroid Build Coastguard Worker 		if (ich_gen == CHIPSET_ICH8) {
2353*0d6140beSAndroid Build Coastguard Worker 			tmp = mmio_readl(spibar + ICH8_REG_VSCC);
2354*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("0x%x: 0x%08"PRIx32" (VSCC)\n", ICH8_REG_VSCC, tmp);
2355*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("VSCC: ");
2356*0d6140beSAndroid Build Coastguard Worker 			prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
2357*0d6140beSAndroid Build Coastguard Worker 		} else {
2358*0d6140beSAndroid Build Coastguard Worker 			tmp = mmio_readl(spibar + ICH9_REG_LVSCC);
2359*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("0x%x: 0x%08"PRIx32" (LVSCC)\n", ICH9_REG_LVSCC, tmp);
2360*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("LVSCC: ");
2361*0d6140beSAndroid Build Coastguard Worker 			prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
2362*0d6140beSAndroid Build Coastguard Worker 
2363*0d6140beSAndroid Build Coastguard Worker 			tmp = mmio_readl(spibar + ICH9_REG_UVSCC);
2364*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("0x%x: 0x%08"PRIx32" (UVSCC)\n", ICH9_REG_UVSCC, tmp);
2365*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("UVSCC: ");
2366*0d6140beSAndroid Build Coastguard Worker 			prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, false);
2367*0d6140beSAndroid Build Coastguard Worker 		}
2368*0d6140beSAndroid Build Coastguard Worker 
2369*0d6140beSAndroid Build Coastguard Worker 		switch (ich_gen) {
2370*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_ICH8:
2371*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_100_SERIES_SUNRISE_POINT:
2372*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_C620_SERIES_LEWISBURG:
2373*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_C740_SERIES_EMMITSBURG:
2374*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_300_SERIES_CANNON_POINT:
2375*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_400_SERIES_COMET_POINT:
2376*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_500_SERIES_TIGER_POINT:
2377*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_600_SERIES_ALDER_POINT:
2378*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_700_SERIES_RAPTOR_POINT:
2379*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_APOLLO_LAKE:
2380*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_GEMINI_LAKE:
2381*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_JASPER_LAKE:
2382*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_ELKHART_LAKE:
2383*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_METEOR_LAKE:
2384*0d6140beSAndroid Build Coastguard Worker 		case CHIPSET_PANTHER_LAKE:
2385*0d6140beSAndroid Build Coastguard Worker 			break;
2386*0d6140beSAndroid Build Coastguard Worker 		default:
2387*0d6140beSAndroid Build Coastguard Worker 			tmp = mmio_readl(spibar + ICH9_REG_FPB);
2388*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("0x%x: 0x%08"PRIx32" (FPB)\n", ICH9_REG_FPB, tmp);
2389*0d6140beSAndroid Build Coastguard Worker 			break;
2390*0d6140beSAndroid Build Coastguard Worker 		}
2391*0d6140beSAndroid Build Coastguard Worker 
2392*0d6140beSAndroid Build Coastguard Worker 		if (read_ich_descriptors_via_fdo(ich_gen, spibar, &desc) == ICH_RET_OK)
2393*0d6140beSAndroid Build Coastguard Worker 			prettyprint_ich_descriptors(ich_gen, &desc);
2394*0d6140beSAndroid Build Coastguard Worker 
2395*0d6140beSAndroid Build Coastguard Worker 		/* If the descriptor is valid and indicates multiple
2396*0d6140beSAndroid Build Coastguard Worker 		 * flash devices we need to use hwseq to be able to
2397*0d6140beSAndroid Build Coastguard Worker 		 * access the second flash device.
2398*0d6140beSAndroid Build Coastguard Worker 		 */
2399*0d6140beSAndroid Build Coastguard Worker 		if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
2400*0d6140beSAndroid Build Coastguard Worker 			msg_pinfo("Enabling hardware sequencing due to multiple flash chips detected.\n");
2401*0d6140beSAndroid Build Coastguard Worker 			ich_spi_mode = ich_hwseq;
2402*0d6140beSAndroid Build Coastguard Worker 		}
2403*0d6140beSAndroid Build Coastguard Worker 	}
2404*0d6140beSAndroid Build Coastguard Worker 
2405*0d6140beSAndroid Build Coastguard Worker 	if (ich_spi_mode == ich_auto && ichspi_lock &&
2406*0d6140beSAndroid Build Coastguard Worker 	    ich_missing_opcodes()) {
2407*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Enabling hardware sequencing because "
2408*0d6140beSAndroid Build Coastguard Worker 			  "some important opcode is locked.\n");
2409*0d6140beSAndroid Build Coastguard Worker 		ich_spi_mode = ich_hwseq;
2410*0d6140beSAndroid Build Coastguard Worker 	}
2411*0d6140beSAndroid Build Coastguard Worker 
2412*0d6140beSAndroid Build Coastguard Worker 	if (ich_spi_mode == ich_auto &&
2413*0d6140beSAndroid Build Coastguard Worker 	    (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT ||
2414*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_300_SERIES_CANNON_POINT ||
2415*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_400_SERIES_COMET_POINT ||
2416*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_500_SERIES_TIGER_POINT ||
2417*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_600_SERIES_ALDER_POINT ||
2418*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_700_SERIES_RAPTOR_POINT ||
2419*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_C740_SERIES_EMMITSBURG)) {
2420*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling hardware sequencing by default for 100+ series PCH.\n");
2421*0d6140beSAndroid Build Coastguard Worker 		ich_spi_mode = ich_hwseq;
2422*0d6140beSAndroid Build Coastguard Worker 	}
2423*0d6140beSAndroid Build Coastguard Worker 
2424*0d6140beSAndroid Build Coastguard Worker 	if (ich_spi_mode == ich_auto &&
2425*0d6140beSAndroid Build Coastguard Worker 	    (ich_gen == CHIPSET_APOLLO_LAKE ||
2426*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_GEMINI_LAKE ||
2427*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_JASPER_LAKE ||
2428*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_ELKHART_LAKE ||
2429*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_METEOR_LAKE ||
2430*0d6140beSAndroid Build Coastguard Worker 	     ich_gen == CHIPSET_PANTHER_LAKE)) {
2431*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling hardware sequencing by default for Apollo/Gemini/Jasper/Elkhart/Meteor/Panther Lake.\n");
2432*0d6140beSAndroid Build Coastguard Worker 		ich_spi_mode = ich_hwseq;
2433*0d6140beSAndroid Build Coastguard Worker 	}
2434*0d6140beSAndroid Build Coastguard Worker 
2435*0d6140beSAndroid Build Coastguard Worker 	if (ich_spi_mode == ich_hwseq) {
2436*0d6140beSAndroid Build Coastguard Worker 		if (!desc_valid) {
2437*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Hardware sequencing was requested "
2438*0d6140beSAndroid Build Coastguard Worker 				 "but the flash descriptor is not valid. Aborting.\n");
2439*0d6140beSAndroid Build Coastguard Worker 			return ERROR_FLASHROM_FATAL;
2440*0d6140beSAndroid Build Coastguard Worker 		}
2441*0d6140beSAndroid Build Coastguard Worker 
2442*0d6140beSAndroid Build Coastguard Worker 		int tmpi = getFCBA_component_density(ich_gen, &desc, 0);
2443*0d6140beSAndroid Build Coastguard Worker 		if (tmpi < 0) {
2444*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Could not determine density of flash component %d.\n", 0);
2445*0d6140beSAndroid Build Coastguard Worker 			return ERROR_FLASHROM_FATAL;
2446*0d6140beSAndroid Build Coastguard Worker 		}
2447*0d6140beSAndroid Build Coastguard Worker 		hwseq_data.size_comp0 = tmpi;
2448*0d6140beSAndroid Build Coastguard Worker 
2449*0d6140beSAndroid Build Coastguard Worker 		tmpi = getFCBA_component_density(ich_gen, &desc, 1);
2450*0d6140beSAndroid Build Coastguard Worker 		if (tmpi < 0) {
2451*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Could not determine density of flash component %d.\n", 1);
2452*0d6140beSAndroid Build Coastguard Worker 			return ERROR_FLASHROM_FATAL;
2453*0d6140beSAndroid Build Coastguard Worker 		}
2454*0d6140beSAndroid Build Coastguard Worker 		hwseq_data.size_comp1 = tmpi;
2455*0d6140beSAndroid Build Coastguard Worker 
2456*0d6140beSAndroid Build Coastguard Worker 		struct hwseq_data *opaque_hwseq_data = calloc(1, sizeof(struct hwseq_data));
2457*0d6140beSAndroid Build Coastguard Worker 		if (!opaque_hwseq_data)
2458*0d6140beSAndroid Build Coastguard Worker 			return ERROR_FLASHROM_FATAL;
2459*0d6140beSAndroid Build Coastguard Worker 		memcpy(opaque_hwseq_data, &hwseq_data, sizeof(*opaque_hwseq_data));
2460*0d6140beSAndroid Build Coastguard Worker 		register_opaque_master(&opaque_master_ich_hwseq, opaque_hwseq_data);
2461*0d6140beSAndroid Build Coastguard Worker 	} else {
2462*0d6140beSAndroid Build Coastguard Worker 		register_spi_master(&spi_master_ich, NULL);
2463*0d6140beSAndroid Build Coastguard Worker 	}
2464*0d6140beSAndroid Build Coastguard Worker 
2465*0d6140beSAndroid Build Coastguard Worker 	return 0;
2466*0d6140beSAndroid Build Coastguard Worker }
2467*0d6140beSAndroid Build Coastguard Worker 
ich_init_spi(const struct programmer_cfg * cfg,void * spibar,enum ich_chipset ich_gen)2468*0d6140beSAndroid Build Coastguard Worker int ich_init_spi(const struct programmer_cfg *cfg, void *spibar, enum ich_chipset ich_gen)
2469*0d6140beSAndroid Build Coastguard Worker {
2470*0d6140beSAndroid Build Coastguard Worker 	ich_generation = ich_gen;
2471*0d6140beSAndroid Build Coastguard Worker 	ich_spibar = spibar;
2472*0d6140beSAndroid Build Coastguard Worker 
2473*0d6140beSAndroid Build Coastguard Worker 	switch (ich_gen) {
2474*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH7:
2475*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_TUNNEL_CREEK:
2476*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_CENTERTON:
2477*0d6140beSAndroid Build Coastguard Worker 		return init_ich7_spi(spibar, ich_gen);
2478*0d6140beSAndroid Build Coastguard Worker 	case CHIPSET_ICH8:
2479*0d6140beSAndroid Build Coastguard Worker 	default:	/* Future version might behave the same */
2480*0d6140beSAndroid Build Coastguard Worker 		return init_ich_default(cfg, spibar, ich_gen);
2481*0d6140beSAndroid Build Coastguard Worker 	}
2482*0d6140beSAndroid Build Coastguard Worker }
2483*0d6140beSAndroid Build Coastguard Worker 
2484*0d6140beSAndroid Build Coastguard Worker static const struct spi_master spi_master_via = {
2485*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= 16,
2486*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= 16,
2487*0d6140beSAndroid Build Coastguard Worker 	.command	= ich_spi_send_command,
2488*0d6140beSAndroid Build Coastguard Worker 	.multicommand	= ich_spi_send_multicommand,
2489*0d6140beSAndroid Build Coastguard Worker 	.map_flash_region	= physmap,
2490*0d6140beSAndroid Build Coastguard Worker 	.unmap_flash_region	= physunmap,
2491*0d6140beSAndroid Build Coastguard Worker 	.read		= default_spi_read,
2492*0d6140beSAndroid Build Coastguard Worker 	.write_256	= default_spi_write_256,
2493*0d6140beSAndroid Build Coastguard Worker 	.probe_opcode	= ich_spi_probe_opcode,
2494*0d6140beSAndroid Build Coastguard Worker };
2495*0d6140beSAndroid Build Coastguard Worker 
via_init_spi(uint32_t mmio_base)2496*0d6140beSAndroid Build Coastguard Worker int via_init_spi(uint32_t mmio_base)
2497*0d6140beSAndroid Build Coastguard Worker {
2498*0d6140beSAndroid Build Coastguard Worker 	int i;
2499*0d6140beSAndroid Build Coastguard Worker 
2500*0d6140beSAndroid Build Coastguard Worker 	ich_spibar = rphysmap("VIA SPI MMIO registers", mmio_base, 0x70);
2501*0d6140beSAndroid Build Coastguard Worker 	if (ich_spibar == ERROR_PTR)
2502*0d6140beSAndroid Build Coastguard Worker 		return ERROR_FLASHROM_FATAL;
2503*0d6140beSAndroid Build Coastguard Worker 	/* Do we really need no write enable? Like the LPC one at D17F0 0x40 */
2504*0d6140beSAndroid Build Coastguard Worker 
2505*0d6140beSAndroid Build Coastguard Worker 	/* Not sure if it speaks all these bus protocols. */
2506*0d6140beSAndroid Build Coastguard Worker 	internal_buses_supported &= BUS_LPC | BUS_FWH;
2507*0d6140beSAndroid Build Coastguard Worker 	ich_generation = CHIPSET_ICH7;
2508*0d6140beSAndroid Build Coastguard Worker 	register_spi_master(&spi_master_via, NULL);
2509*0d6140beSAndroid Build Coastguard Worker 
2510*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x00: 0x%04"PRIx16" (SPIS)\n",	mmio_readw(ich_spibar + 0));
2511*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x02: 0x%04"PRIx16" (SPIC)\n",	mmio_readw(ich_spibar + 2));
2512*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x04: 0x%08"PRIx32" (SPIA)\n",	mmio_readl(ich_spibar + 4));
2513*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
2514*0d6140beSAndroid Build Coastguard Worker 		int offs;
2515*0d6140beSAndroid Build Coastguard Worker 		offs = 8 + (i * 8);
2516*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x%02x: 0x%08"PRIx32" (SPID%d)\n", offs, mmio_readl(ich_spibar + offs), i);
2517*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x%02x: 0x%08"PRIx32" (SPID%d+4)\n", offs + 4,
2518*0d6140beSAndroid Build Coastguard Worker 			 mmio_readl(ich_spibar + offs + 4), i);
2519*0d6140beSAndroid Build Coastguard Worker 	}
2520*0d6140beSAndroid Build Coastguard Worker 	ichspi_bbar = mmio_readl(ich_spibar + 0x50);
2521*0d6140beSAndroid Build Coastguard Worker 
2522*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x50: 0x%08"PRIx32" (BBAR)\n",	ichspi_bbar);
2523*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x54: 0x%04"PRIx16" (PREOP)\n",	mmio_readw(ich_spibar + 0x54));
2524*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x56: 0x%04"PRIx16" (OPTYPE)\n",	mmio_readw(ich_spibar + 0x56));
2525*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x58: 0x%08"PRIx32" (OPMENU)\n",	mmio_readl(ich_spibar + 0x58));
2526*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x5c: 0x%08"PRIx32" (OPMENU+4)\n",	mmio_readl(ich_spibar + 0x5c));
2527*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < 3; i++) {
2528*0d6140beSAndroid Build Coastguard Worker 		int offs;
2529*0d6140beSAndroid Build Coastguard Worker 		offs = 0x60 + (i * 4);
2530*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("0x%02x: 0x%08"PRIx32" (PBR%d)\n", offs, mmio_readl(ich_spibar + offs), i);
2531*0d6140beSAndroid Build Coastguard Worker 	}
2532*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("0x6c: 0x%04x     (CLOCK/DEBUG)\n", mmio_readw(ich_spibar + 0x6c));
2533*0d6140beSAndroid Build Coastguard Worker 	if (mmio_readw(ich_spibar) & (1 << 15)) {
2534*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Warning: SPI Configuration Lockdown activated.\n");
2535*0d6140beSAndroid Build Coastguard Worker 		ichspi_lock = true;
2536*0d6140beSAndroid Build Coastguard Worker 	}
2537*0d6140beSAndroid Build Coastguard Worker 
2538*0d6140beSAndroid Build Coastguard Worker 	ich_set_bbar(0, ich_generation);
2539*0d6140beSAndroid Build Coastguard Worker 	ich_init_opcodes(ich_generation);
2540*0d6140beSAndroid Build Coastguard Worker 
2541*0d6140beSAndroid Build Coastguard Worker 	return 0;
2542*0d6140beSAndroid Build Coastguard Worker }
2543