1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Aic94xx SAS/SATA driver access to shared data structures and memory
4*4882a593Smuzhiyun * maps.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
7*4882a593Smuzhiyun * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/pci.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "aic94xx.h"
15*4882a593Smuzhiyun #include "aic94xx_reg.h"
16*4882a593Smuzhiyun #include "aic94xx_sds.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /* ---------- OCM stuff ---------- */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun struct asd_ocm_dir_ent {
21*4882a593Smuzhiyun u8 type;
22*4882a593Smuzhiyun u8 offs[3];
23*4882a593Smuzhiyun u8 _r1;
24*4882a593Smuzhiyun u8 size[3];
25*4882a593Smuzhiyun } __attribute__ ((packed));
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct asd_ocm_dir {
28*4882a593Smuzhiyun char sig[2];
29*4882a593Smuzhiyun u8 _r1[2];
30*4882a593Smuzhiyun u8 major; /* 0 */
31*4882a593Smuzhiyun u8 minor; /* 0 */
32*4882a593Smuzhiyun u8 _r2;
33*4882a593Smuzhiyun u8 num_de;
34*4882a593Smuzhiyun struct asd_ocm_dir_ent entry[15];
35*4882a593Smuzhiyun } __attribute__ ((packed));
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define OCM_DE_OCM_DIR 0x00
38*4882a593Smuzhiyun #define OCM_DE_WIN_DRVR 0x01
39*4882a593Smuzhiyun #define OCM_DE_BIOS_CHIM 0x02
40*4882a593Smuzhiyun #define OCM_DE_RAID_ENGN 0x03
41*4882a593Smuzhiyun #define OCM_DE_BIOS_INTL 0x04
42*4882a593Smuzhiyun #define OCM_DE_BIOS_CHIM_OSM 0x05
43*4882a593Smuzhiyun #define OCM_DE_BIOS_CHIM_DYNAMIC 0x06
44*4882a593Smuzhiyun #define OCM_DE_ADDC2C_RES0 0x07
45*4882a593Smuzhiyun #define OCM_DE_ADDC2C_RES1 0x08
46*4882a593Smuzhiyun #define OCM_DE_ADDC2C_RES2 0x09
47*4882a593Smuzhiyun #define OCM_DE_ADDC2C_RES3 0x0A
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #define OCM_INIT_DIR_ENTRIES 5
50*4882a593Smuzhiyun /***************************************************************************
51*4882a593Smuzhiyun * OCM directory default
52*4882a593Smuzhiyun ***************************************************************************/
53*4882a593Smuzhiyun static struct asd_ocm_dir OCMDirInit =
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun .sig = {0x4D, 0x4F}, /* signature */
56*4882a593Smuzhiyun .num_de = OCM_INIT_DIR_ENTRIES, /* no. of directory entries */
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /***************************************************************************
60*4882a593Smuzhiyun * OCM directory Entries default
61*4882a593Smuzhiyun ***************************************************************************/
62*4882a593Smuzhiyun static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] =
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun .type = (OCM_DE_ADDC2C_RES0), /* Entry type */
66*4882a593Smuzhiyun .offs = {128}, /* Offset */
67*4882a593Smuzhiyun .size = {0, 4}, /* size */
68*4882a593Smuzhiyun },
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun .type = (OCM_DE_ADDC2C_RES1), /* Entry type */
71*4882a593Smuzhiyun .offs = {128, 4}, /* Offset */
72*4882a593Smuzhiyun .size = {0, 4}, /* size */
73*4882a593Smuzhiyun },
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun .type = (OCM_DE_ADDC2C_RES2), /* Entry type */
76*4882a593Smuzhiyun .offs = {128, 8}, /* Offset */
77*4882a593Smuzhiyun .size = {0, 4}, /* size */
78*4882a593Smuzhiyun },
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun .type = (OCM_DE_ADDC2C_RES3), /* Entry type */
81*4882a593Smuzhiyun .offs = {128, 12}, /* Offset */
82*4882a593Smuzhiyun .size = {0, 4}, /* size */
83*4882a593Smuzhiyun },
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun .type = (OCM_DE_WIN_DRVR), /* Entry type */
86*4882a593Smuzhiyun .offs = {128, 16}, /* Offset */
87*4882a593Smuzhiyun .size = {128, 235, 1}, /* size */
88*4882a593Smuzhiyun },
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun struct asd_bios_chim_struct {
92*4882a593Smuzhiyun char sig[4];
93*4882a593Smuzhiyun u8 major; /* 1 */
94*4882a593Smuzhiyun u8 minor; /* 0 */
95*4882a593Smuzhiyun u8 bios_major;
96*4882a593Smuzhiyun u8 bios_minor;
97*4882a593Smuzhiyun __le32 bios_build;
98*4882a593Smuzhiyun u8 flags;
99*4882a593Smuzhiyun u8 pci_slot;
100*4882a593Smuzhiyun __le16 ue_num;
101*4882a593Smuzhiyun __le16 ue_size;
102*4882a593Smuzhiyun u8 _r[14];
103*4882a593Smuzhiyun /* The unit element array is right here.
104*4882a593Smuzhiyun */
105*4882a593Smuzhiyun } __attribute__ ((packed));
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /**
108*4882a593Smuzhiyun * asd_read_ocm_seg - read an on chip memory (OCM) segment
109*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
110*4882a593Smuzhiyun * @buffer: where to write the read data
111*4882a593Smuzhiyun * @offs: offset into OCM where to read from
112*4882a593Smuzhiyun * @size: how many bytes to read
113*4882a593Smuzhiyun *
114*4882a593Smuzhiyun * Return the number of bytes not read. Return 0 on success.
115*4882a593Smuzhiyun */
asd_read_ocm_seg(struct asd_ha_struct * asd_ha,void * buffer,u32 offs,int size)116*4882a593Smuzhiyun static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
117*4882a593Smuzhiyun u32 offs, int size)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun u8 *p = buffer;
120*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
121*4882a593Smuzhiyun asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
122*4882a593Smuzhiyun else {
123*4882a593Smuzhiyun for ( ; size > 0; size--, offs++, p++)
124*4882a593Smuzhiyun *p = asd_read_ocm_byte(asd_ha, offs);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun return size;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
asd_read_ocm_dir(struct asd_ha_struct * asd_ha,struct asd_ocm_dir * dir,u32 offs)129*4882a593Smuzhiyun static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha,
130*4882a593Smuzhiyun struct asd_ocm_dir *dir, u32 offs)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir));
133*4882a593Smuzhiyun if (err) {
134*4882a593Smuzhiyun ASD_DPRINTK("couldn't read ocm segment\n");
135*4882a593Smuzhiyun return err;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (dir->sig[0] != 'M' || dir->sig[1] != 'O') {
139*4882a593Smuzhiyun ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n",
140*4882a593Smuzhiyun dir->sig[0], dir->sig[1]);
141*4882a593Smuzhiyun return -ENOENT;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun if (dir->major != 0) {
144*4882a593Smuzhiyun asd_printk("unsupported major version of ocm dir:0x%x\n",
145*4882a593Smuzhiyun dir->major);
146*4882a593Smuzhiyun return -ENOENT;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun dir->num_de &= 0xf;
149*4882a593Smuzhiyun return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /**
153*4882a593Smuzhiyun * asd_write_ocm_seg - write an on chip memory (OCM) segment
154*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
155*4882a593Smuzhiyun * @buffer: where to read the write data
156*4882a593Smuzhiyun * @offs: offset into OCM to write to
157*4882a593Smuzhiyun * @size: how many bytes to write
158*4882a593Smuzhiyun *
159*4882a593Smuzhiyun * Return the number of bytes not written. Return 0 on success.
160*4882a593Smuzhiyun */
asd_write_ocm_seg(struct asd_ha_struct * asd_ha,void * buffer,u32 offs,int size)161*4882a593Smuzhiyun static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
162*4882a593Smuzhiyun u32 offs, int size)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun u8 *p = buffer;
165*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
166*4882a593Smuzhiyun asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
167*4882a593Smuzhiyun else {
168*4882a593Smuzhiyun for ( ; size > 0; size--, offs++, p++)
169*4882a593Smuzhiyun asd_write_ocm_byte(asd_ha, offs, *p);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun return;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun #define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16))
175*4882a593Smuzhiyun
asd_find_dir_entry(struct asd_ocm_dir * dir,u8 type,u32 * offs,u32 * size)176*4882a593Smuzhiyun static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type,
177*4882a593Smuzhiyun u32 *offs, u32 *size)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun int i;
180*4882a593Smuzhiyun struct asd_ocm_dir_ent *ent;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun for (i = 0; i < dir->num_de; i++) {
183*4882a593Smuzhiyun if (dir->entry[i].type == type)
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun if (i >= dir->num_de)
187*4882a593Smuzhiyun return -ENOENT;
188*4882a593Smuzhiyun ent = &dir->entry[i];
189*4882a593Smuzhiyun *offs = (u32) THREE_TO_NUM(ent->offs);
190*4882a593Smuzhiyun *size = (u32) THREE_TO_NUM(ent->size);
191*4882a593Smuzhiyun return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun #define OCM_BIOS_CHIM_DE 2
195*4882a593Smuzhiyun #define BC_BIOS_PRESENT 1
196*4882a593Smuzhiyun
asd_get_bios_chim(struct asd_ha_struct * asd_ha,struct asd_ocm_dir * dir)197*4882a593Smuzhiyun static int asd_get_bios_chim(struct asd_ha_struct *asd_ha,
198*4882a593Smuzhiyun struct asd_ocm_dir *dir)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun int err;
201*4882a593Smuzhiyun struct asd_bios_chim_struct *bc_struct;
202*4882a593Smuzhiyun u32 offs, size;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size);
205*4882a593Smuzhiyun if (err) {
206*4882a593Smuzhiyun ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n");
207*4882a593Smuzhiyun goto out;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun err = -ENOMEM;
210*4882a593Smuzhiyun bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL);
211*4882a593Smuzhiyun if (!bc_struct) {
212*4882a593Smuzhiyun asd_printk("no memory for bios_chim struct\n");
213*4882a593Smuzhiyun goto out;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs,
216*4882a593Smuzhiyun sizeof(*bc_struct));
217*4882a593Smuzhiyun if (err) {
218*4882a593Smuzhiyun ASD_DPRINTK("couldn't read ocm segment\n");
219*4882a593Smuzhiyun goto out2;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun if (strncmp(bc_struct->sig, "SOIB", 4)
222*4882a593Smuzhiyun && strncmp(bc_struct->sig, "IPSA", 4)) {
223*4882a593Smuzhiyun ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n",
224*4882a593Smuzhiyun bc_struct->sig[0], bc_struct->sig[1],
225*4882a593Smuzhiyun bc_struct->sig[2], bc_struct->sig[3]);
226*4882a593Smuzhiyun err = -ENOENT;
227*4882a593Smuzhiyun goto out2;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun if (bc_struct->major != 1) {
230*4882a593Smuzhiyun asd_printk("BIOS_CHIM unsupported major version:0x%x\n",
231*4882a593Smuzhiyun bc_struct->major);
232*4882a593Smuzhiyun err = -ENOENT;
233*4882a593Smuzhiyun goto out2;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun if (bc_struct->flags & BC_BIOS_PRESENT) {
236*4882a593Smuzhiyun asd_ha->hw_prof.bios.present = 1;
237*4882a593Smuzhiyun asd_ha->hw_prof.bios.maj = bc_struct->bios_major;
238*4882a593Smuzhiyun asd_ha->hw_prof.bios.min = bc_struct->bios_minor;
239*4882a593Smuzhiyun asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build);
240*4882a593Smuzhiyun ASD_DPRINTK("BIOS present (%d,%d), %d\n",
241*4882a593Smuzhiyun asd_ha->hw_prof.bios.maj,
242*4882a593Smuzhiyun asd_ha->hw_prof.bios.min,
243*4882a593Smuzhiyun asd_ha->hw_prof.bios.bld);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num);
246*4882a593Smuzhiyun asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size);
247*4882a593Smuzhiyun ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num,
248*4882a593Smuzhiyun asd_ha->hw_prof.ue.size);
249*4882a593Smuzhiyun size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size;
250*4882a593Smuzhiyun if (size > 0) {
251*4882a593Smuzhiyun err = -ENOMEM;
252*4882a593Smuzhiyun asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL);
253*4882a593Smuzhiyun if (!asd_ha->hw_prof.ue.area)
254*4882a593Smuzhiyun goto out2;
255*4882a593Smuzhiyun err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area,
256*4882a593Smuzhiyun offs + sizeof(*bc_struct), size);
257*4882a593Smuzhiyun if (err) {
258*4882a593Smuzhiyun kfree(asd_ha->hw_prof.ue.area);
259*4882a593Smuzhiyun asd_ha->hw_prof.ue.area = NULL;
260*4882a593Smuzhiyun asd_ha->hw_prof.ue.num = 0;
261*4882a593Smuzhiyun asd_ha->hw_prof.ue.size = 0;
262*4882a593Smuzhiyun ASD_DPRINTK("couldn't read ue entries(%d)\n", err);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun out2:
266*4882a593Smuzhiyun kfree(bc_struct);
267*4882a593Smuzhiyun out:
268*4882a593Smuzhiyun return err;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun static void
asd_hwi_initialize_ocm_dir(struct asd_ha_struct * asd_ha)272*4882a593Smuzhiyun asd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun int i;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* Zero OCM */
277*4882a593Smuzhiyun for (i = 0; i < OCM_MAX_SIZE; i += 4)
278*4882a593Smuzhiyun asd_write_ocm_dword(asd_ha, i, 0);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* Write Dir */
281*4882a593Smuzhiyun asd_write_ocm_seg(asd_ha, &OCMDirInit, 0,
282*4882a593Smuzhiyun sizeof(struct asd_ocm_dir));
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* Write Dir Entries */
285*4882a593Smuzhiyun for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++)
286*4882a593Smuzhiyun asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i],
287*4882a593Smuzhiyun sizeof(struct asd_ocm_dir) +
288*4882a593Smuzhiyun (i * sizeof(struct asd_ocm_dir_ent))
289*4882a593Smuzhiyun , sizeof(struct asd_ocm_dir_ent));
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun static int
asd_hwi_check_ocm_access(struct asd_ha_struct * asd_ha)294*4882a593Smuzhiyun asd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun struct pci_dev *pcidev = asd_ha->pcidev;
297*4882a593Smuzhiyun u32 reg;
298*4882a593Smuzhiyun int err = 0;
299*4882a593Smuzhiyun u32 v;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* check if OCM has been initialized by BIOS */
302*4882a593Smuzhiyun reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (!(reg & OCMINITIALIZED)) {
305*4882a593Smuzhiyun err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v);
306*4882a593Smuzhiyun if (err) {
307*4882a593Smuzhiyun asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n",
308*4882a593Smuzhiyun pci_name(pcidev));
309*4882a593Smuzhiyun goto out;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun printk(KERN_INFO "OCM is not initialized by BIOS,"
313*4882a593Smuzhiyun "reinitialize it and ignore it, current IntrptStatus"
314*4882a593Smuzhiyun "is 0x%x\n", v);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (v)
317*4882a593Smuzhiyun err = pci_write_config_dword(pcidev,
318*4882a593Smuzhiyun PCIC_INTRPT_STAT, v);
319*4882a593Smuzhiyun if (err) {
320*4882a593Smuzhiyun asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n",
321*4882a593Smuzhiyun pci_name(pcidev));
322*4882a593Smuzhiyun goto out;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun asd_hwi_initialize_ocm_dir(asd_ha);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun out:
329*4882a593Smuzhiyun return err;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /**
333*4882a593Smuzhiyun * asd_read_ocm - read on chip memory (OCM)
334*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
335*4882a593Smuzhiyun */
asd_read_ocm(struct asd_ha_struct * asd_ha)336*4882a593Smuzhiyun int asd_read_ocm(struct asd_ha_struct *asd_ha)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun int err;
339*4882a593Smuzhiyun struct asd_ocm_dir *dir;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (asd_hwi_check_ocm_access(asd_ha))
342*4882a593Smuzhiyun return -1;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun dir = kmalloc(sizeof(*dir), GFP_KERNEL);
345*4882a593Smuzhiyun if (!dir) {
346*4882a593Smuzhiyun asd_printk("no memory for ocm dir\n");
347*4882a593Smuzhiyun return -ENOMEM;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun err = asd_read_ocm_dir(asd_ha, dir, 0);
351*4882a593Smuzhiyun if (err)
352*4882a593Smuzhiyun goto out;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun err = asd_get_bios_chim(asd_ha, dir);
355*4882a593Smuzhiyun out:
356*4882a593Smuzhiyun kfree(dir);
357*4882a593Smuzhiyun return err;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* ---------- FLASH stuff ---------- */
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun #define FLASH_RESET 0xF0
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun #define ASD_FLASH_SIZE 0x200000
365*4882a593Smuzhiyun #define FLASH_DIR_COOKIE "*** ADAPTEC FLASH DIRECTORY *** "
366*4882a593Smuzhiyun #define FLASH_NEXT_ENTRY_OFFS 0x2000
367*4882a593Smuzhiyun #define FLASH_MAX_DIR_ENTRIES 32
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun #define FLASH_DE_TYPE_MASK 0x3FFFFFFF
370*4882a593Smuzhiyun #define FLASH_DE_MS 0x120
371*4882a593Smuzhiyun #define FLASH_DE_CTRL_A_USER 0xE0
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun struct asd_flash_de {
374*4882a593Smuzhiyun __le32 type;
375*4882a593Smuzhiyun __le32 offs;
376*4882a593Smuzhiyun __le32 pad_size;
377*4882a593Smuzhiyun __le32 image_size;
378*4882a593Smuzhiyun __le32 chksum;
379*4882a593Smuzhiyun u8 _r[12];
380*4882a593Smuzhiyun u8 version[32];
381*4882a593Smuzhiyun } __attribute__ ((packed));
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun struct asd_flash_dir {
384*4882a593Smuzhiyun u8 cookie[32];
385*4882a593Smuzhiyun __le32 rev; /* 2 */
386*4882a593Smuzhiyun __le32 chksum;
387*4882a593Smuzhiyun __le32 chksum_antidote;
388*4882a593Smuzhiyun __le32 bld;
389*4882a593Smuzhiyun u8 bld_id[32]; /* build id data */
390*4882a593Smuzhiyun u8 ver_data[32]; /* date and time of build */
391*4882a593Smuzhiyun __le32 ae_mask;
392*4882a593Smuzhiyun __le32 v_mask;
393*4882a593Smuzhiyun __le32 oc_mask;
394*4882a593Smuzhiyun u8 _r[20];
395*4882a593Smuzhiyun struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES];
396*4882a593Smuzhiyun } __attribute__ ((packed));
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun struct asd_manuf_sec {
399*4882a593Smuzhiyun char sig[2]; /* 'S', 'M' */
400*4882a593Smuzhiyun u16 offs_next;
401*4882a593Smuzhiyun u8 maj; /* 0 */
402*4882a593Smuzhiyun u8 min; /* 0 */
403*4882a593Smuzhiyun u16 chksum;
404*4882a593Smuzhiyun u16 size;
405*4882a593Smuzhiyun u8 _r[6];
406*4882a593Smuzhiyun u8 sas_addr[SAS_ADDR_SIZE];
407*4882a593Smuzhiyun u8 pcba_sn[ASD_PCBA_SN_SIZE];
408*4882a593Smuzhiyun /* Here start the other segments */
409*4882a593Smuzhiyun u8 linked_list[];
410*4882a593Smuzhiyun } __attribute__ ((packed));
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun struct asd_manuf_phy_desc {
413*4882a593Smuzhiyun u8 state; /* low 4 bits */
414*4882a593Smuzhiyun #define MS_PHY_STATE_ENABLED 0
415*4882a593Smuzhiyun #define MS_PHY_STATE_REPORTED 1
416*4882a593Smuzhiyun #define MS_PHY_STATE_HIDDEN 2
417*4882a593Smuzhiyun u8 phy_id;
418*4882a593Smuzhiyun u16 _r;
419*4882a593Smuzhiyun u8 phy_control_0; /* mode 5 reg 0x160 */
420*4882a593Smuzhiyun u8 phy_control_1; /* mode 5 reg 0x161 */
421*4882a593Smuzhiyun u8 phy_control_2; /* mode 5 reg 0x162 */
422*4882a593Smuzhiyun u8 phy_control_3; /* mode 5 reg 0x163 */
423*4882a593Smuzhiyun } __attribute__ ((packed));
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun struct asd_manuf_phy_param {
426*4882a593Smuzhiyun char sig[2]; /* 'P', 'M' */
427*4882a593Smuzhiyun u16 next;
428*4882a593Smuzhiyun u8 maj; /* 0 */
429*4882a593Smuzhiyun u8 min; /* 2 */
430*4882a593Smuzhiyun u8 num_phy_desc; /* 8 */
431*4882a593Smuzhiyun u8 phy_desc_size; /* 8 */
432*4882a593Smuzhiyun u8 _r[3];
433*4882a593Smuzhiyun u8 usage_model_id;
434*4882a593Smuzhiyun u32 _r2;
435*4882a593Smuzhiyun struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS];
436*4882a593Smuzhiyun } __attribute__ ((packed));
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun #if 0
439*4882a593Smuzhiyun static const char *asd_sb_type[] = {
440*4882a593Smuzhiyun "unknown",
441*4882a593Smuzhiyun "SGPIO",
442*4882a593Smuzhiyun [2 ... 0x7F] = "unknown",
443*4882a593Smuzhiyun [0x80] = "ADPT_I2C",
444*4882a593Smuzhiyun [0x81 ... 0xFF] = "VENDOR_UNIQUExx"
445*4882a593Smuzhiyun };
446*4882a593Smuzhiyun #endif
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun struct asd_ms_sb_desc {
449*4882a593Smuzhiyun u8 type;
450*4882a593Smuzhiyun u8 node_desc_index;
451*4882a593Smuzhiyun u8 conn_desc_index;
452*4882a593Smuzhiyun u8 _recvd[];
453*4882a593Smuzhiyun } __attribute__ ((packed));
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun #if 0
456*4882a593Smuzhiyun static const char *asd_conn_type[] = {
457*4882a593Smuzhiyun [0 ... 7] = "unknown",
458*4882a593Smuzhiyun "SFF8470",
459*4882a593Smuzhiyun "SFF8482",
460*4882a593Smuzhiyun "SFF8484",
461*4882a593Smuzhiyun [0x80] = "PCIX_DAUGHTER0",
462*4882a593Smuzhiyun [0x81] = "SAS_DAUGHTER0",
463*4882a593Smuzhiyun [0x82 ... 0xFF] = "VENDOR_UNIQUExx"
464*4882a593Smuzhiyun };
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun static const char *asd_conn_location[] = {
467*4882a593Smuzhiyun "unknown",
468*4882a593Smuzhiyun "internal",
469*4882a593Smuzhiyun "external",
470*4882a593Smuzhiyun "board_to_board",
471*4882a593Smuzhiyun };
472*4882a593Smuzhiyun #endif
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun struct asd_ms_conn_desc {
475*4882a593Smuzhiyun u8 type;
476*4882a593Smuzhiyun u8 location;
477*4882a593Smuzhiyun u8 num_sideband_desc;
478*4882a593Smuzhiyun u8 size_sideband_desc;
479*4882a593Smuzhiyun u32 _resvd;
480*4882a593Smuzhiyun u8 name[16];
481*4882a593Smuzhiyun struct asd_ms_sb_desc sb_desc[];
482*4882a593Smuzhiyun } __attribute__ ((packed));
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun struct asd_nd_phy_desc {
485*4882a593Smuzhiyun u8 vp_attch_type;
486*4882a593Smuzhiyun u8 attch_specific[];
487*4882a593Smuzhiyun } __attribute__ ((packed));
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun #if 0
490*4882a593Smuzhiyun static const char *asd_node_type[] = {
491*4882a593Smuzhiyun "IOP",
492*4882a593Smuzhiyun "IO_CONTROLLER",
493*4882a593Smuzhiyun "EXPANDER",
494*4882a593Smuzhiyun "PORT_MULTIPLIER",
495*4882a593Smuzhiyun "PORT_MULTIPLEXER",
496*4882a593Smuzhiyun "MULTI_DROP_I2C_BUS",
497*4882a593Smuzhiyun };
498*4882a593Smuzhiyun #endif
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun struct asd_ms_node_desc {
501*4882a593Smuzhiyun u8 type;
502*4882a593Smuzhiyun u8 num_phy_desc;
503*4882a593Smuzhiyun u8 size_phy_desc;
504*4882a593Smuzhiyun u8 _resvd;
505*4882a593Smuzhiyun u8 name[16];
506*4882a593Smuzhiyun struct asd_nd_phy_desc phy_desc[];
507*4882a593Smuzhiyun } __attribute__ ((packed));
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun struct asd_ms_conn_map {
510*4882a593Smuzhiyun char sig[2]; /* 'M', 'C' */
511*4882a593Smuzhiyun __le16 next;
512*4882a593Smuzhiyun u8 maj; /* 0 */
513*4882a593Smuzhiyun u8 min; /* 0 */
514*4882a593Smuzhiyun __le16 cm_size; /* size of this struct */
515*4882a593Smuzhiyun u8 num_conn;
516*4882a593Smuzhiyun u8 conn_size;
517*4882a593Smuzhiyun u8 num_nodes;
518*4882a593Smuzhiyun u8 usage_model_id;
519*4882a593Smuzhiyun u32 _resvd;
520*4882a593Smuzhiyun struct asd_ms_conn_desc conn_desc[0];
521*4882a593Smuzhiyun struct asd_ms_node_desc node_desc[];
522*4882a593Smuzhiyun } __attribute__ ((packed));
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun struct asd_ctrla_phy_entry {
525*4882a593Smuzhiyun u8 sas_addr[SAS_ADDR_SIZE];
526*4882a593Smuzhiyun u8 sas_link_rates; /* max in hi bits, min in low bits */
527*4882a593Smuzhiyun u8 flags;
528*4882a593Smuzhiyun u8 sata_link_rates;
529*4882a593Smuzhiyun u8 _r[5];
530*4882a593Smuzhiyun } __attribute__ ((packed));
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun struct asd_ctrla_phy_settings {
533*4882a593Smuzhiyun u8 id0; /* P'h'y */
534*4882a593Smuzhiyun u8 _r;
535*4882a593Smuzhiyun u16 next;
536*4882a593Smuzhiyun u8 num_phys; /* number of PHYs in the PCI function */
537*4882a593Smuzhiyun u8 _r2[3];
538*4882a593Smuzhiyun struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS];
539*4882a593Smuzhiyun } __attribute__ ((packed));
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun struct asd_ll_el {
542*4882a593Smuzhiyun u8 id0;
543*4882a593Smuzhiyun u8 id1;
544*4882a593Smuzhiyun __le16 next;
545*4882a593Smuzhiyun u8 something_here[];
546*4882a593Smuzhiyun } __attribute__ ((packed));
547*4882a593Smuzhiyun
asd_poll_flash(struct asd_ha_struct * asd_ha)548*4882a593Smuzhiyun static int asd_poll_flash(struct asd_ha_struct *asd_ha)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun int c;
551*4882a593Smuzhiyun u8 d;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun for (c = 5000; c > 0; c--) {
554*4882a593Smuzhiyun d = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
555*4882a593Smuzhiyun d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
556*4882a593Smuzhiyun if (!d)
557*4882a593Smuzhiyun return 0;
558*4882a593Smuzhiyun udelay(5);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun return -ENOENT;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
asd_reset_flash(struct asd_ha_struct * asd_ha)563*4882a593Smuzhiyun static int asd_reset_flash(struct asd_ha_struct *asd_ha)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun int err;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun err = asd_poll_flash(asd_ha);
568*4882a593Smuzhiyun if (err)
569*4882a593Smuzhiyun return err;
570*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET);
571*4882a593Smuzhiyun err = asd_poll_flash(asd_ha);
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun return err;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
asd_read_flash_seg(struct asd_ha_struct * asd_ha,void * buffer,u32 offs,int size)576*4882a593Smuzhiyun static int asd_read_flash_seg(struct asd_ha_struct *asd_ha,
577*4882a593Smuzhiyun void *buffer, u32 offs, int size)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs,
580*4882a593Smuzhiyun size);
581*4882a593Smuzhiyun return 0;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun /**
585*4882a593Smuzhiyun * asd_find_flash_dir - finds and reads the flash directory
586*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
587*4882a593Smuzhiyun * @flash_dir: pointer to flash directory structure
588*4882a593Smuzhiyun *
589*4882a593Smuzhiyun * If found, the flash directory segment will be copied to
590*4882a593Smuzhiyun * @flash_dir. Return 1 if found, 0 if not.
591*4882a593Smuzhiyun */
asd_find_flash_dir(struct asd_ha_struct * asd_ha,struct asd_flash_dir * flash_dir)592*4882a593Smuzhiyun static int asd_find_flash_dir(struct asd_ha_struct *asd_ha,
593*4882a593Smuzhiyun struct asd_flash_dir *flash_dir)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun u32 v;
596*4882a593Smuzhiyun for (v = 0; v < ASD_FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
597*4882a593Smuzhiyun asd_read_flash_seg(asd_ha, flash_dir, v,
598*4882a593Smuzhiyun sizeof(FLASH_DIR_COOKIE)-1);
599*4882a593Smuzhiyun if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE,
600*4882a593Smuzhiyun sizeof(FLASH_DIR_COOKIE)-1) == 0) {
601*4882a593Smuzhiyun asd_ha->hw_prof.flash.dir_offs = v;
602*4882a593Smuzhiyun asd_read_flash_seg(asd_ha, flash_dir, v,
603*4882a593Smuzhiyun sizeof(*flash_dir));
604*4882a593Smuzhiyun return 1;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun return 0;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
asd_flash_getid(struct asd_ha_struct * asd_ha)610*4882a593Smuzhiyun static int asd_flash_getid(struct asd_ha_struct *asd_ha)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun int err = 0;
613*4882a593Smuzhiyun u32 reg;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR,
618*4882a593Smuzhiyun &asd_ha->hw_prof.flash.bar)) {
619*4882a593Smuzhiyun asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n",
620*4882a593Smuzhiyun pci_name(asd_ha->pcidev));
621*4882a593Smuzhiyun return -ENOENT;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun asd_ha->hw_prof.flash.present = 1;
624*4882a593Smuzhiyun asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0;
625*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
626*4882a593Smuzhiyun if (err) {
627*4882a593Smuzhiyun ASD_DPRINTK("couldn't reset flash(%d)\n", err);
628*4882a593Smuzhiyun return err;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun return 0;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
asd_calc_flash_chksum(u16 * p,int size)633*4882a593Smuzhiyun static u16 asd_calc_flash_chksum(u16 *p, int size)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun u16 chksum = 0;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun while (size-- > 0)
638*4882a593Smuzhiyun chksum += *p++;
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun return chksum;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun
asd_find_flash_de(struct asd_flash_dir * flash_dir,u32 entry_type,u32 * offs,u32 * size)644*4882a593Smuzhiyun static int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type,
645*4882a593Smuzhiyun u32 *offs, u32 *size)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun int i;
648*4882a593Smuzhiyun struct asd_flash_de *de;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) {
651*4882a593Smuzhiyun u32 type = le32_to_cpu(flash_dir->dir_entry[i].type);
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun type &= FLASH_DE_TYPE_MASK;
654*4882a593Smuzhiyun if (type == entry_type)
655*4882a593Smuzhiyun break;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun if (i >= FLASH_MAX_DIR_ENTRIES)
658*4882a593Smuzhiyun return -ENOENT;
659*4882a593Smuzhiyun de = &flash_dir->dir_entry[i];
660*4882a593Smuzhiyun *offs = le32_to_cpu(de->offs);
661*4882a593Smuzhiyun *size = le32_to_cpu(de->pad_size);
662*4882a593Smuzhiyun return 0;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
asd_validate_ms(struct asd_manuf_sec * ms)665*4882a593Smuzhiyun static int asd_validate_ms(struct asd_manuf_sec *ms)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun if (ms->sig[0] != 'S' || ms->sig[1] != 'M') {
668*4882a593Smuzhiyun ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n",
669*4882a593Smuzhiyun ms->sig[0], ms->sig[1]);
670*4882a593Smuzhiyun return -ENOENT;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun if (ms->maj != 0) {
673*4882a593Smuzhiyun asd_printk("unsupported manuf. sector. major version:%x\n",
674*4882a593Smuzhiyun ms->maj);
675*4882a593Smuzhiyun return -ENOENT;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next);
678*4882a593Smuzhiyun ms->chksum = le16_to_cpu((__force __le16) ms->chksum);
679*4882a593Smuzhiyun ms->size = le16_to_cpu((__force __le16) ms->size);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) {
682*4882a593Smuzhiyun asd_printk("failed manuf sector checksum\n");
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun return 0;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
asd_ms_get_sas_addr(struct asd_ha_struct * asd_ha,struct asd_manuf_sec * ms)688*4882a593Smuzhiyun static int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha,
689*4882a593Smuzhiyun struct asd_manuf_sec *ms)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE);
692*4882a593Smuzhiyun return 0;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun
asd_ms_get_pcba_sn(struct asd_ha_struct * asd_ha,struct asd_manuf_sec * ms)695*4882a593Smuzhiyun static int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha,
696*4882a593Smuzhiyun struct asd_manuf_sec *ms)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE);
699*4882a593Smuzhiyun asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0';
700*4882a593Smuzhiyun return 0;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun /**
704*4882a593Smuzhiyun * asd_find_ll_by_id - find a linked list entry by its id
705*4882a593Smuzhiyun * @start: void pointer to the first element in the linked list
706*4882a593Smuzhiyun * @id0: the first byte of the id (offs 0)
707*4882a593Smuzhiyun * @id1: the second byte of the id (offs 1)
708*4882a593Smuzhiyun *
709*4882a593Smuzhiyun * @start has to be the _base_ element start, since the
710*4882a593Smuzhiyun * linked list entries's offset is from this pointer.
711*4882a593Smuzhiyun * Some linked list entries use only the first id, in which case
712*4882a593Smuzhiyun * you can pass 0xFF for the second.
713*4882a593Smuzhiyun */
asd_find_ll_by_id(void * const start,const u8 id0,const u8 id1)714*4882a593Smuzhiyun static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun struct asd_ll_el *el = start;
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun do {
719*4882a593Smuzhiyun switch (id1) {
720*4882a593Smuzhiyun default:
721*4882a593Smuzhiyun if (el->id1 == id1)
722*4882a593Smuzhiyun case 0xFF:
723*4882a593Smuzhiyun if (el->id0 == id0)
724*4882a593Smuzhiyun return el;
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun el = start + le16_to_cpu(el->next);
727*4882a593Smuzhiyun } while (el != start);
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun return NULL;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /**
733*4882a593Smuzhiyun * asd_ms_get_phy_params - get phy parameters from the manufacturing sector
734*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
735*4882a593Smuzhiyun * @manuf_sec: pointer to the manufacturing sector
736*4882a593Smuzhiyun *
737*4882a593Smuzhiyun * The manufacturing sector contans also the linked list of sub-segments,
738*4882a593Smuzhiyun * since when it was read, its size was taken from the flash directory,
739*4882a593Smuzhiyun * not from the structure size.
740*4882a593Smuzhiyun *
741*4882a593Smuzhiyun * HIDDEN phys do not count in the total count. REPORTED phys cannot
742*4882a593Smuzhiyun * be enabled but are reported and counted towards the total.
743*4882a593Smuzhiyun * ENABLED phys are enabled by default and count towards the total.
744*4882a593Smuzhiyun * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys
745*4882a593Smuzhiyun * merely specifies the number of phys the host adapter decided to
746*4882a593Smuzhiyun * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN,
747*4882a593Smuzhiyun * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENABLED.
748*4882a593Smuzhiyun * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2
749*4882a593Smuzhiyun * are actually enabled (enabled by default, max number of phys
750*4882a593Smuzhiyun * enableable in this case).
751*4882a593Smuzhiyun */
asd_ms_get_phy_params(struct asd_ha_struct * asd_ha,struct asd_manuf_sec * manuf_sec)752*4882a593Smuzhiyun static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha,
753*4882a593Smuzhiyun struct asd_manuf_sec *manuf_sec)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun int i;
756*4882a593Smuzhiyun int en_phys = 0;
757*4882a593Smuzhiyun int rep_phys = 0;
758*4882a593Smuzhiyun struct asd_manuf_phy_param *phy_param;
759*4882a593Smuzhiyun struct asd_manuf_phy_param dflt_phy_param;
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M');
762*4882a593Smuzhiyun if (!phy_param) {
763*4882a593Smuzhiyun ASD_DPRINTK("ms: no phy parameters found\n");
764*4882a593Smuzhiyun ASD_DPRINTK("ms: Creating default phy parameters\n");
765*4882a593Smuzhiyun dflt_phy_param.sig[0] = 'P';
766*4882a593Smuzhiyun dflt_phy_param.sig[1] = 'M';
767*4882a593Smuzhiyun dflt_phy_param.maj = 0;
768*4882a593Smuzhiyun dflt_phy_param.min = 2;
769*4882a593Smuzhiyun dflt_phy_param.num_phy_desc = 8;
770*4882a593Smuzhiyun dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc);
771*4882a593Smuzhiyun for (i =0; i < ASD_MAX_PHYS; i++) {
772*4882a593Smuzhiyun dflt_phy_param.phy_desc[i].state = 0;
773*4882a593Smuzhiyun dflt_phy_param.phy_desc[i].phy_id = i;
774*4882a593Smuzhiyun dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6;
775*4882a593Smuzhiyun dflt_phy_param.phy_desc[i].phy_control_1 = 0x10;
776*4882a593Smuzhiyun dflt_phy_param.phy_desc[i].phy_control_2 = 0x43;
777*4882a593Smuzhiyun dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb;
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun phy_param = &dflt_phy_param;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun if (phy_param->maj != 0) {
785*4882a593Smuzhiyun asd_printk("unsupported manuf. phy param major version:0x%x\n",
786*4882a593Smuzhiyun phy_param->maj);
787*4882a593Smuzhiyun return -ENOENT;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc);
791*4882a593Smuzhiyun asd_ha->hw_prof.enabled_phys = 0;
792*4882a593Smuzhiyun for (i = 0; i < phy_param->num_phy_desc; i++) {
793*4882a593Smuzhiyun struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i];
794*4882a593Smuzhiyun switch (pd->state & 0xF) {
795*4882a593Smuzhiyun case MS_PHY_STATE_HIDDEN:
796*4882a593Smuzhiyun ASD_DPRINTK("ms: phy%d: HIDDEN\n", i);
797*4882a593Smuzhiyun continue;
798*4882a593Smuzhiyun case MS_PHY_STATE_REPORTED:
799*4882a593Smuzhiyun ASD_DPRINTK("ms: phy%d: REPORTED\n", i);
800*4882a593Smuzhiyun asd_ha->hw_prof.enabled_phys &= ~(1 << i);
801*4882a593Smuzhiyun rep_phys++;
802*4882a593Smuzhiyun continue;
803*4882a593Smuzhiyun case MS_PHY_STATE_ENABLED:
804*4882a593Smuzhiyun ASD_DPRINTK("ms: phy%d: ENABLED\n", i);
805*4882a593Smuzhiyun asd_ha->hw_prof.enabled_phys |= (1 << i);
806*4882a593Smuzhiyun en_phys++;
807*4882a593Smuzhiyun break;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0;
810*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1;
811*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2;
812*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun asd_ha->hw_prof.max_phys = rep_phys + en_phys;
815*4882a593Smuzhiyun asd_ha->hw_prof.num_phys = en_phys;
816*4882a593Smuzhiyun ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n",
817*4882a593Smuzhiyun asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys);
818*4882a593Smuzhiyun ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys);
819*4882a593Smuzhiyun return 0;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
asd_ms_get_connector_map(struct asd_ha_struct * asd_ha,struct asd_manuf_sec * manuf_sec)822*4882a593Smuzhiyun static int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha,
823*4882a593Smuzhiyun struct asd_manuf_sec *manuf_sec)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun struct asd_ms_conn_map *cm;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun cm = asd_find_ll_by_id(manuf_sec, 'M', 'C');
828*4882a593Smuzhiyun if (!cm) {
829*4882a593Smuzhiyun ASD_DPRINTK("ms: no connector map found\n");
830*4882a593Smuzhiyun return 0;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun if (cm->maj != 0) {
834*4882a593Smuzhiyun ASD_DPRINTK("ms: unsupported: connector map major version 0x%x"
835*4882a593Smuzhiyun "\n", cm->maj);
836*4882a593Smuzhiyun return -ENOENT;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun /* XXX */
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun return 0;
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun /**
846*4882a593Smuzhiyun * asd_process_ms - find and extract information from the manufacturing sector
847*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
848*4882a593Smuzhiyun * @flash_dir: pointer to the flash directory
849*4882a593Smuzhiyun */
asd_process_ms(struct asd_ha_struct * asd_ha,struct asd_flash_dir * flash_dir)850*4882a593Smuzhiyun static int asd_process_ms(struct asd_ha_struct *asd_ha,
851*4882a593Smuzhiyun struct asd_flash_dir *flash_dir)
852*4882a593Smuzhiyun {
853*4882a593Smuzhiyun int err;
854*4882a593Smuzhiyun struct asd_manuf_sec *manuf_sec;
855*4882a593Smuzhiyun u32 offs, size;
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size);
858*4882a593Smuzhiyun if (err) {
859*4882a593Smuzhiyun ASD_DPRINTK("Couldn't find the manuf. sector\n");
860*4882a593Smuzhiyun goto out;
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun if (size == 0)
864*4882a593Smuzhiyun goto out;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun err = -ENOMEM;
867*4882a593Smuzhiyun manuf_sec = kmalloc(size, GFP_KERNEL);
868*4882a593Smuzhiyun if (!manuf_sec) {
869*4882a593Smuzhiyun ASD_DPRINTK("no mem for manuf sector\n");
870*4882a593Smuzhiyun goto out;
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size);
874*4882a593Smuzhiyun if (err) {
875*4882a593Smuzhiyun ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n",
876*4882a593Smuzhiyun offs, size);
877*4882a593Smuzhiyun goto out2;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun err = asd_validate_ms(manuf_sec);
881*4882a593Smuzhiyun if (err) {
882*4882a593Smuzhiyun ASD_DPRINTK("couldn't validate manuf sector\n");
883*4882a593Smuzhiyun goto out2;
884*4882a593Smuzhiyun }
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun err = asd_ms_get_sas_addr(asd_ha, manuf_sec);
887*4882a593Smuzhiyun if (err) {
888*4882a593Smuzhiyun ASD_DPRINTK("couldn't read the SAS_ADDR\n");
889*4882a593Smuzhiyun goto out2;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun ASD_DPRINTK("manuf sect SAS_ADDR %llx\n",
892*4882a593Smuzhiyun SAS_ADDR(asd_ha->hw_prof.sas_addr));
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun err = asd_ms_get_pcba_sn(asd_ha, manuf_sec);
895*4882a593Smuzhiyun if (err) {
896*4882a593Smuzhiyun ASD_DPRINTK("couldn't read the PCBA SN\n");
897*4882a593Smuzhiyun goto out2;
898*4882a593Smuzhiyun }
899*4882a593Smuzhiyun ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn);
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun err = asd_ms_get_phy_params(asd_ha, manuf_sec);
902*4882a593Smuzhiyun if (err) {
903*4882a593Smuzhiyun ASD_DPRINTK("ms: couldn't get phy parameters\n");
904*4882a593Smuzhiyun goto out2;
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun err = asd_ms_get_connector_map(asd_ha, manuf_sec);
908*4882a593Smuzhiyun if (err) {
909*4882a593Smuzhiyun ASD_DPRINTK("ms: couldn't get connector map\n");
910*4882a593Smuzhiyun goto out2;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun out2:
914*4882a593Smuzhiyun kfree(manuf_sec);
915*4882a593Smuzhiyun out:
916*4882a593Smuzhiyun return err;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
asd_process_ctrla_phy_settings(struct asd_ha_struct * asd_ha,struct asd_ctrla_phy_settings * ps)919*4882a593Smuzhiyun static int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha,
920*4882a593Smuzhiyun struct asd_ctrla_phy_settings *ps)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun int i;
923*4882a593Smuzhiyun for (i = 0; i < ps->num_phys; i++) {
924*4882a593Smuzhiyun struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i];
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun if (!PHY_ENABLED(asd_ha, i))
927*4882a593Smuzhiyun continue;
928*4882a593Smuzhiyun if (*(u64 *)pe->sas_addr == 0) {
929*4882a593Smuzhiyun asd_ha->hw_prof.enabled_phys &= ~(1 << i);
930*4882a593Smuzhiyun continue;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun /* This is the SAS address which should be sent in IDENTIFY. */
933*4882a593Smuzhiyun memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr,
934*4882a593Smuzhiyun SAS_ADDR_SIZE);
935*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
936*4882a593Smuzhiyun (pe->sas_link_rates & 0xF0) >> 4;
937*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
938*4882a593Smuzhiyun (pe->sas_link_rates & 0x0F);
939*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
940*4882a593Smuzhiyun (pe->sata_link_rates & 0xF0) >> 4;
941*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
942*4882a593Smuzhiyun (pe->sata_link_rates & 0x0F);
943*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].flags = pe->flags;
944*4882a593Smuzhiyun ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x,"
945*4882a593Smuzhiyun " sata rate:0x%x-0x%x, flags:0x%x\n",
946*4882a593Smuzhiyun i,
947*4882a593Smuzhiyun SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr),
948*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].max_sas_lrate,
949*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].min_sas_lrate,
950*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].max_sata_lrate,
951*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].min_sata_lrate,
952*4882a593Smuzhiyun asd_ha->hw_prof.phy_desc[i].flags);
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun return 0;
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun /**
959*4882a593Smuzhiyun * asd_process_ctrl_a_user - process CTRL-A user settings
960*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
961*4882a593Smuzhiyun * @flash_dir: pointer to the flash directory
962*4882a593Smuzhiyun */
asd_process_ctrl_a_user(struct asd_ha_struct * asd_ha,struct asd_flash_dir * flash_dir)963*4882a593Smuzhiyun static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
964*4882a593Smuzhiyun struct asd_flash_dir *flash_dir)
965*4882a593Smuzhiyun {
966*4882a593Smuzhiyun int err, i;
967*4882a593Smuzhiyun u32 offs, size;
968*4882a593Smuzhiyun struct asd_ll_el *el = NULL;
969*4882a593Smuzhiyun struct asd_ctrla_phy_settings *ps;
970*4882a593Smuzhiyun struct asd_ctrla_phy_settings dflt_ps;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size);
973*4882a593Smuzhiyun if (err) {
974*4882a593Smuzhiyun ASD_DPRINTK("couldn't find CTRL-A user settings section\n");
975*4882a593Smuzhiyun ASD_DPRINTK("Creating default CTRL-A user settings section\n");
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun dflt_ps.id0 = 'h';
978*4882a593Smuzhiyun dflt_ps.num_phys = 8;
979*4882a593Smuzhiyun for (i =0; i < ASD_MAX_PHYS; i++) {
980*4882a593Smuzhiyun memcpy(dflt_ps.phy_ent[i].sas_addr,
981*4882a593Smuzhiyun asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
982*4882a593Smuzhiyun dflt_ps.phy_ent[i].sas_link_rates = 0x98;
983*4882a593Smuzhiyun dflt_ps.phy_ent[i].flags = 0x0;
984*4882a593Smuzhiyun dflt_ps.phy_ent[i].sata_link_rates = 0x0;
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun size = sizeof(struct asd_ctrla_phy_settings);
988*4882a593Smuzhiyun ps = &dflt_ps;
989*4882a593Smuzhiyun goto out_process;
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun if (size == 0)
993*4882a593Smuzhiyun goto out;
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun err = -ENOMEM;
996*4882a593Smuzhiyun el = kmalloc(size, GFP_KERNEL);
997*4882a593Smuzhiyun if (!el) {
998*4882a593Smuzhiyun ASD_DPRINTK("no mem for ctrla user settings section\n");
999*4882a593Smuzhiyun goto out;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun err = asd_read_flash_seg(asd_ha, (void *)el, offs, size);
1003*4882a593Smuzhiyun if (err) {
1004*4882a593Smuzhiyun ASD_DPRINTK("couldn't read ctrla phy settings section\n");
1005*4882a593Smuzhiyun goto out2;
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun err = -ENOENT;
1009*4882a593Smuzhiyun ps = asd_find_ll_by_id(el, 'h', 0xFF);
1010*4882a593Smuzhiyun if (!ps) {
1011*4882a593Smuzhiyun ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
1012*4882a593Smuzhiyun goto out2;
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun out_process:
1015*4882a593Smuzhiyun err = asd_process_ctrla_phy_settings(asd_ha, ps);
1016*4882a593Smuzhiyun if (err) {
1017*4882a593Smuzhiyun ASD_DPRINTK("couldn't process ctrla phy settings\n");
1018*4882a593Smuzhiyun goto out2;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun out2:
1021*4882a593Smuzhiyun kfree(el);
1022*4882a593Smuzhiyun out:
1023*4882a593Smuzhiyun return err;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun /**
1027*4882a593Smuzhiyun * asd_read_flash - read flash memory
1028*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
1029*4882a593Smuzhiyun */
asd_read_flash(struct asd_ha_struct * asd_ha)1030*4882a593Smuzhiyun int asd_read_flash(struct asd_ha_struct *asd_ha)
1031*4882a593Smuzhiyun {
1032*4882a593Smuzhiyun int err;
1033*4882a593Smuzhiyun struct asd_flash_dir *flash_dir;
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun err = asd_flash_getid(asd_ha);
1036*4882a593Smuzhiyun if (err)
1037*4882a593Smuzhiyun return err;
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL);
1040*4882a593Smuzhiyun if (!flash_dir)
1041*4882a593Smuzhiyun return -ENOMEM;
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun err = -ENOENT;
1044*4882a593Smuzhiyun if (!asd_find_flash_dir(asd_ha, flash_dir)) {
1045*4882a593Smuzhiyun ASD_DPRINTK("couldn't find flash directory\n");
1046*4882a593Smuzhiyun goto out;
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun
1049*4882a593Smuzhiyun if (le32_to_cpu(flash_dir->rev) != 2) {
1050*4882a593Smuzhiyun asd_printk("unsupported flash dir version:0x%x\n",
1051*4882a593Smuzhiyun le32_to_cpu(flash_dir->rev));
1052*4882a593Smuzhiyun goto out;
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun
1055*4882a593Smuzhiyun err = asd_process_ms(asd_ha, flash_dir);
1056*4882a593Smuzhiyun if (err) {
1057*4882a593Smuzhiyun ASD_DPRINTK("couldn't process manuf sector settings\n");
1058*4882a593Smuzhiyun goto out;
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun err = asd_process_ctrl_a_user(asd_ha, flash_dir);
1062*4882a593Smuzhiyun if (err) {
1063*4882a593Smuzhiyun ASD_DPRINTK("couldn't process CTRL-A user settings\n");
1064*4882a593Smuzhiyun goto out;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun out:
1068*4882a593Smuzhiyun kfree(flash_dir);
1069*4882a593Smuzhiyun return err;
1070*4882a593Smuzhiyun }
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun /**
1073*4882a593Smuzhiyun * asd_verify_flash_seg - verify data with flash memory
1074*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
1075*4882a593Smuzhiyun * @src: pointer to the source data to be verified
1076*4882a593Smuzhiyun * @dest_offset: offset from flash memory
1077*4882a593Smuzhiyun * @bytes_to_verify: total bytes to verify
1078*4882a593Smuzhiyun */
asd_verify_flash_seg(struct asd_ha_struct * asd_ha,const void * src,u32 dest_offset,u32 bytes_to_verify)1079*4882a593Smuzhiyun int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
1080*4882a593Smuzhiyun const void *src, u32 dest_offset, u32 bytes_to_verify)
1081*4882a593Smuzhiyun {
1082*4882a593Smuzhiyun const u8 *src_buf;
1083*4882a593Smuzhiyun u8 flash_char;
1084*4882a593Smuzhiyun int err;
1085*4882a593Smuzhiyun u32 nv_offset, reg, i;
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun reg = asd_ha->hw_prof.flash.bar;
1088*4882a593Smuzhiyun src_buf = NULL;
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun err = FLASH_OK;
1091*4882a593Smuzhiyun nv_offset = dest_offset;
1092*4882a593Smuzhiyun src_buf = (const u8 *)src;
1093*4882a593Smuzhiyun for (i = 0; i < bytes_to_verify; i++) {
1094*4882a593Smuzhiyun flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i);
1095*4882a593Smuzhiyun if (flash_char != src_buf[i]) {
1096*4882a593Smuzhiyun err = FAIL_VERIFY;
1097*4882a593Smuzhiyun break;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun return err;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun
1103*4882a593Smuzhiyun /**
1104*4882a593Smuzhiyun * asd_write_flash_seg - write data into flash memory
1105*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
1106*4882a593Smuzhiyun * @src: pointer to the source data to be written
1107*4882a593Smuzhiyun * @dest_offset: offset from flash memory
1108*4882a593Smuzhiyun * @bytes_to_write: total bytes to write
1109*4882a593Smuzhiyun */
asd_write_flash_seg(struct asd_ha_struct * asd_ha,const void * src,u32 dest_offset,u32 bytes_to_write)1110*4882a593Smuzhiyun int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
1111*4882a593Smuzhiyun const void *src, u32 dest_offset, u32 bytes_to_write)
1112*4882a593Smuzhiyun {
1113*4882a593Smuzhiyun const u8 *src_buf;
1114*4882a593Smuzhiyun u32 nv_offset, reg, i;
1115*4882a593Smuzhiyun int err;
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun reg = asd_ha->hw_prof.flash.bar;
1118*4882a593Smuzhiyun src_buf = NULL;
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun err = asd_check_flash_type(asd_ha);
1121*4882a593Smuzhiyun if (err) {
1122*4882a593Smuzhiyun ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err);
1123*4882a593Smuzhiyun return err;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun nv_offset = dest_offset;
1127*4882a593Smuzhiyun err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write);
1128*4882a593Smuzhiyun if (err) {
1129*4882a593Smuzhiyun ASD_DPRINTK("Erase failed at offset:0x%x\n",
1130*4882a593Smuzhiyun nv_offset);
1131*4882a593Smuzhiyun return err;
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
1135*4882a593Smuzhiyun if (err) {
1136*4882a593Smuzhiyun ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
1137*4882a593Smuzhiyun return err;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun src_buf = (const u8 *)src;
1141*4882a593Smuzhiyun for (i = 0; i < bytes_to_write; i++) {
1142*4882a593Smuzhiyun /* Setup program command sequence */
1143*4882a593Smuzhiyun switch (asd_ha->hw_prof.flash.method) {
1144*4882a593Smuzhiyun case FLASH_METHOD_A:
1145*4882a593Smuzhiyun {
1146*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1147*4882a593Smuzhiyun (reg + 0xAAA), 0xAA);
1148*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1149*4882a593Smuzhiyun (reg + 0x555), 0x55);
1150*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1151*4882a593Smuzhiyun (reg + 0xAAA), 0xA0);
1152*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1153*4882a593Smuzhiyun (reg + nv_offset + i),
1154*4882a593Smuzhiyun (*(src_buf + i)));
1155*4882a593Smuzhiyun break;
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun case FLASH_METHOD_B:
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1160*4882a593Smuzhiyun (reg + 0x555), 0xAA);
1161*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1162*4882a593Smuzhiyun (reg + 0x2AA), 0x55);
1163*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1164*4882a593Smuzhiyun (reg + 0x555), 0xA0);
1165*4882a593Smuzhiyun asd_write_reg_byte(asd_ha,
1166*4882a593Smuzhiyun (reg + nv_offset + i),
1167*4882a593Smuzhiyun (*(src_buf + i)));
1168*4882a593Smuzhiyun break;
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun default:
1171*4882a593Smuzhiyun break;
1172*4882a593Smuzhiyun }
1173*4882a593Smuzhiyun if (asd_chk_write_status(asd_ha,
1174*4882a593Smuzhiyun (nv_offset + i), 0) != 0) {
1175*4882a593Smuzhiyun ASD_DPRINTK("aicx: Write failed at offset:0x%x\n",
1176*4882a593Smuzhiyun reg + nv_offset + i);
1177*4882a593Smuzhiyun return FAIL_WRITE_FLASH;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun }
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
1182*4882a593Smuzhiyun if (err) {
1183*4882a593Smuzhiyun ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
1184*4882a593Smuzhiyun return err;
1185*4882a593Smuzhiyun }
1186*4882a593Smuzhiyun return 0;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun
asd_chk_write_status(struct asd_ha_struct * asd_ha,u32 sector_addr,u8 erase_flag)1189*4882a593Smuzhiyun int asd_chk_write_status(struct asd_ha_struct *asd_ha,
1190*4882a593Smuzhiyun u32 sector_addr, u8 erase_flag)
1191*4882a593Smuzhiyun {
1192*4882a593Smuzhiyun u32 reg;
1193*4882a593Smuzhiyun u32 loop_cnt;
1194*4882a593Smuzhiyun u8 nv_data1, nv_data2;
1195*4882a593Smuzhiyun u8 toggle_bit1;
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun /*
1198*4882a593Smuzhiyun * Read from DQ2 requires sector address
1199*4882a593Smuzhiyun * while it's dont care for DQ6
1200*4882a593Smuzhiyun */
1201*4882a593Smuzhiyun reg = asd_ha->hw_prof.flash.bar;
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) {
1204*4882a593Smuzhiyun nv_data1 = asd_read_reg_byte(asd_ha, reg);
1205*4882a593Smuzhiyun nv_data2 = asd_read_reg_byte(asd_ha, reg);
1206*4882a593Smuzhiyun
1207*4882a593Smuzhiyun toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
1208*4882a593Smuzhiyun ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun if (toggle_bit1 == 0) {
1211*4882a593Smuzhiyun return 0;
1212*4882a593Smuzhiyun } else {
1213*4882a593Smuzhiyun if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) {
1214*4882a593Smuzhiyun nv_data1 = asd_read_reg_byte(asd_ha,
1215*4882a593Smuzhiyun reg);
1216*4882a593Smuzhiyun nv_data2 = asd_read_reg_byte(asd_ha,
1217*4882a593Smuzhiyun reg);
1218*4882a593Smuzhiyun toggle_bit1 =
1219*4882a593Smuzhiyun ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
1220*4882a593Smuzhiyun ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun if (toggle_bit1 == 0)
1223*4882a593Smuzhiyun return 0;
1224*4882a593Smuzhiyun }
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun /*
1228*4882a593Smuzhiyun * ERASE is a sector-by-sector operation and requires
1229*4882a593Smuzhiyun * more time to finish while WRITE is byte-byte-byte
1230*4882a593Smuzhiyun * operation and takes lesser time to finish.
1231*4882a593Smuzhiyun *
1232*4882a593Smuzhiyun * For some strange reason a reduced ERASE delay gives different
1233*4882a593Smuzhiyun * behaviour across different spirit boards. Hence we set
1234*4882a593Smuzhiyun * a optimum balance of 50mus for ERASE which works well
1235*4882a593Smuzhiyun * across all boards.
1236*4882a593Smuzhiyun */
1237*4882a593Smuzhiyun if (erase_flag) {
1238*4882a593Smuzhiyun udelay(FLASH_STATUS_ERASE_DELAY_COUNT);
1239*4882a593Smuzhiyun } else {
1240*4882a593Smuzhiyun udelay(FLASH_STATUS_WRITE_DELAY_COUNT);
1241*4882a593Smuzhiyun }
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun return -1;
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun /**
1247*4882a593Smuzhiyun * asd_hwi_erase_nv_sector - Erase the flash memory sectors.
1248*4882a593Smuzhiyun * @asd_ha: pointer to the host adapter structure
1249*4882a593Smuzhiyun * @flash_addr: pointer to offset from flash memory
1250*4882a593Smuzhiyun * @size: total bytes to erase.
1251*4882a593Smuzhiyun */
asd_erase_nv_sector(struct asd_ha_struct * asd_ha,u32 flash_addr,u32 size)1252*4882a593Smuzhiyun int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size)
1253*4882a593Smuzhiyun {
1254*4882a593Smuzhiyun u32 reg;
1255*4882a593Smuzhiyun u32 sector_addr;
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun reg = asd_ha->hw_prof.flash.bar;
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun /* sector staring address */
1260*4882a593Smuzhiyun sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK;
1261*4882a593Smuzhiyun
1262*4882a593Smuzhiyun /*
1263*4882a593Smuzhiyun * Erasing an flash sector needs to be done in six consecutive
1264*4882a593Smuzhiyun * write cyles.
1265*4882a593Smuzhiyun */
1266*4882a593Smuzhiyun while (sector_addr < flash_addr+size) {
1267*4882a593Smuzhiyun switch (asd_ha->hw_prof.flash.method) {
1268*4882a593Smuzhiyun case FLASH_METHOD_A:
1269*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
1270*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
1271*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80);
1272*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
1273*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
1274*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
1275*4882a593Smuzhiyun break;
1276*4882a593Smuzhiyun case FLASH_METHOD_B:
1277*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
1278*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
1279*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80);
1280*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
1281*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
1282*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
1283*4882a593Smuzhiyun break;
1284*4882a593Smuzhiyun default:
1285*4882a593Smuzhiyun break;
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun
1288*4882a593Smuzhiyun if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0)
1289*4882a593Smuzhiyun return FAIL_ERASE_FLASH;
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun sector_addr += FLASH_SECTOR_SIZE;
1292*4882a593Smuzhiyun }
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun return 0;
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun
asd_check_flash_type(struct asd_ha_struct * asd_ha)1297*4882a593Smuzhiyun int asd_check_flash_type(struct asd_ha_struct *asd_ha)
1298*4882a593Smuzhiyun {
1299*4882a593Smuzhiyun u8 manuf_id;
1300*4882a593Smuzhiyun u8 dev_id;
1301*4882a593Smuzhiyun u8 sec_prot;
1302*4882a593Smuzhiyun u32 inc;
1303*4882a593Smuzhiyun u32 reg;
1304*4882a593Smuzhiyun int err;
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun /* get Flash memory base address */
1307*4882a593Smuzhiyun reg = asd_ha->hw_prof.flash.bar;
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun /* Determine flash info */
1310*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
1311*4882a593Smuzhiyun if (err) {
1312*4882a593Smuzhiyun ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
1313*4882a593Smuzhiyun return err;
1314*4882a593Smuzhiyun }
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN;
1317*4882a593Smuzhiyun asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN;
1318*4882a593Smuzhiyun asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN;
1319*4882a593Smuzhiyun
1320*4882a593Smuzhiyun /* Get flash info. This would most likely be AMD Am29LV family flash.
1321*4882a593Smuzhiyun * First try the sequence for word mode. It is the same as for
1322*4882a593Smuzhiyun * 008B (byte mode only), 160B (word mode) and 800D (word mode).
1323*4882a593Smuzhiyun */
1324*4882a593Smuzhiyun inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
1325*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
1326*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
1327*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
1328*4882a593Smuzhiyun manuf_id = asd_read_reg_byte(asd_ha, reg);
1329*4882a593Smuzhiyun dev_id = asd_read_reg_byte(asd_ha, reg + inc);
1330*4882a593Smuzhiyun sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
1331*4882a593Smuzhiyun /* Get out of autoselect mode. */
1332*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
1333*4882a593Smuzhiyun if (err) {
1334*4882a593Smuzhiyun ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
1335*4882a593Smuzhiyun return err;
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) "
1338*4882a593Smuzhiyun "sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot);
1339*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
1340*4882a593Smuzhiyun if (err != 0)
1341*4882a593Smuzhiyun return err;
1342*4882a593Smuzhiyun
1343*4882a593Smuzhiyun switch (manuf_id) {
1344*4882a593Smuzhiyun case FLASH_MANUF_ID_AMD:
1345*4882a593Smuzhiyun switch (sec_prot) {
1346*4882a593Smuzhiyun case FLASH_DEV_ID_AM29LV800DT:
1347*4882a593Smuzhiyun case FLASH_DEV_ID_AM29LV640MT:
1348*4882a593Smuzhiyun case FLASH_DEV_ID_AM29F800B:
1349*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
1350*4882a593Smuzhiyun break;
1351*4882a593Smuzhiyun default:
1352*4882a593Smuzhiyun break;
1353*4882a593Smuzhiyun }
1354*4882a593Smuzhiyun break;
1355*4882a593Smuzhiyun case FLASH_MANUF_ID_ST:
1356*4882a593Smuzhiyun switch (sec_prot) {
1357*4882a593Smuzhiyun case FLASH_DEV_ID_STM29W800DT:
1358*4882a593Smuzhiyun case FLASH_DEV_ID_STM29LV640:
1359*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
1360*4882a593Smuzhiyun break;
1361*4882a593Smuzhiyun default:
1362*4882a593Smuzhiyun break;
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun break;
1365*4882a593Smuzhiyun case FLASH_MANUF_ID_FUJITSU:
1366*4882a593Smuzhiyun switch (sec_prot) {
1367*4882a593Smuzhiyun case FLASH_DEV_ID_MBM29LV800TE:
1368*4882a593Smuzhiyun case FLASH_DEV_ID_MBM29DL800TA:
1369*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
1370*4882a593Smuzhiyun break;
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun break;
1373*4882a593Smuzhiyun case FLASH_MANUF_ID_MACRONIX:
1374*4882a593Smuzhiyun switch (sec_prot) {
1375*4882a593Smuzhiyun case FLASH_DEV_ID_MX29LV800BT:
1376*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
1377*4882a593Smuzhiyun break;
1378*4882a593Smuzhiyun }
1379*4882a593Smuzhiyun break;
1380*4882a593Smuzhiyun }
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) {
1383*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
1384*4882a593Smuzhiyun if (err) {
1385*4882a593Smuzhiyun ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
1386*4882a593Smuzhiyun return err;
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun /* Issue Unlock sequence for AM29LV008BT */
1390*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
1391*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
1392*4882a593Smuzhiyun asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90);
1393*4882a593Smuzhiyun manuf_id = asd_read_reg_byte(asd_ha, reg);
1394*4882a593Smuzhiyun dev_id = asd_read_reg_byte(asd_ha, reg + inc);
1395*4882a593Smuzhiyun sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot"
1398*4882a593Smuzhiyun "(0x%x)\n", manuf_id, dev_id, sec_prot);
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun err = asd_reset_flash(asd_ha);
1401*4882a593Smuzhiyun if (err != 0) {
1402*4882a593Smuzhiyun ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
1403*4882a593Smuzhiyun return err;
1404*4882a593Smuzhiyun }
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun switch (manuf_id) {
1407*4882a593Smuzhiyun case FLASH_MANUF_ID_AMD:
1408*4882a593Smuzhiyun switch (dev_id) {
1409*4882a593Smuzhiyun case FLASH_DEV_ID_AM29LV008BT:
1410*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
1411*4882a593Smuzhiyun break;
1412*4882a593Smuzhiyun default:
1413*4882a593Smuzhiyun break;
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun break;
1416*4882a593Smuzhiyun case FLASH_MANUF_ID_ST:
1417*4882a593Smuzhiyun switch (dev_id) {
1418*4882a593Smuzhiyun case FLASH_DEV_ID_STM29008:
1419*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
1420*4882a593Smuzhiyun break;
1421*4882a593Smuzhiyun default:
1422*4882a593Smuzhiyun break;
1423*4882a593Smuzhiyun }
1424*4882a593Smuzhiyun break;
1425*4882a593Smuzhiyun case FLASH_MANUF_ID_FUJITSU:
1426*4882a593Smuzhiyun switch (dev_id) {
1427*4882a593Smuzhiyun case FLASH_DEV_ID_MBM29LV008TA:
1428*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
1429*4882a593Smuzhiyun break;
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun break;
1432*4882a593Smuzhiyun case FLASH_MANUF_ID_INTEL:
1433*4882a593Smuzhiyun switch (dev_id) {
1434*4882a593Smuzhiyun case FLASH_DEV_ID_I28LV00TAT:
1435*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
1436*4882a593Smuzhiyun break;
1437*4882a593Smuzhiyun }
1438*4882a593Smuzhiyun break;
1439*4882a593Smuzhiyun case FLASH_MANUF_ID_MACRONIX:
1440*4882a593Smuzhiyun switch (dev_id) {
1441*4882a593Smuzhiyun case FLASH_DEV_ID_I28LV00TAT:
1442*4882a593Smuzhiyun asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
1443*4882a593Smuzhiyun break;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun break;
1446*4882a593Smuzhiyun default:
1447*4882a593Smuzhiyun return FAIL_FIND_FLASH_ID;
1448*4882a593Smuzhiyun }
1449*4882a593Smuzhiyun }
1450*4882a593Smuzhiyun
1451*4882a593Smuzhiyun if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN)
1452*4882a593Smuzhiyun return FAIL_FIND_FLASH_ID;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun asd_ha->hw_prof.flash.manuf = manuf_id;
1455*4882a593Smuzhiyun asd_ha->hw_prof.flash.dev_id = dev_id;
1456*4882a593Smuzhiyun asd_ha->hw_prof.flash.sec_prot = sec_prot;
1457*4882a593Smuzhiyun return 0;
1458*4882a593Smuzhiyun }
1459