18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Aic94xx SAS/SATA driver access to shared data structures and memory
48c2ecf20Sopenharmony_ci * maps.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
78c2ecf20Sopenharmony_ci * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/pci.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "aic94xx.h"
158c2ecf20Sopenharmony_ci#include "aic94xx_reg.h"
168c2ecf20Sopenharmony_ci#include "aic94xx_sds.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* ---------- OCM stuff ---------- */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct asd_ocm_dir_ent {
218c2ecf20Sopenharmony_ci	u8 type;
228c2ecf20Sopenharmony_ci	u8 offs[3];
238c2ecf20Sopenharmony_ci	u8 _r1;
248c2ecf20Sopenharmony_ci	u8 size[3];
258c2ecf20Sopenharmony_ci} __attribute__ ((packed));
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistruct asd_ocm_dir {
288c2ecf20Sopenharmony_ci	char sig[2];
298c2ecf20Sopenharmony_ci	u8   _r1[2];
308c2ecf20Sopenharmony_ci	u8   major;          /* 0 */
318c2ecf20Sopenharmony_ci	u8   minor;          /* 0 */
328c2ecf20Sopenharmony_ci	u8   _r2;
338c2ecf20Sopenharmony_ci	u8   num_de;
348c2ecf20Sopenharmony_ci	struct asd_ocm_dir_ent entry[15];
358c2ecf20Sopenharmony_ci} __attribute__ ((packed));
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define	OCM_DE_OCM_DIR			0x00
388c2ecf20Sopenharmony_ci#define	OCM_DE_WIN_DRVR			0x01
398c2ecf20Sopenharmony_ci#define	OCM_DE_BIOS_CHIM		0x02
408c2ecf20Sopenharmony_ci#define	OCM_DE_RAID_ENGN		0x03
418c2ecf20Sopenharmony_ci#define	OCM_DE_BIOS_INTL		0x04
428c2ecf20Sopenharmony_ci#define	OCM_DE_BIOS_CHIM_OSM		0x05
438c2ecf20Sopenharmony_ci#define	OCM_DE_BIOS_CHIM_DYNAMIC	0x06
448c2ecf20Sopenharmony_ci#define	OCM_DE_ADDC2C_RES0		0x07
458c2ecf20Sopenharmony_ci#define	OCM_DE_ADDC2C_RES1		0x08
468c2ecf20Sopenharmony_ci#define	OCM_DE_ADDC2C_RES2		0x09
478c2ecf20Sopenharmony_ci#define	OCM_DE_ADDC2C_RES3		0x0A
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define OCM_INIT_DIR_ENTRIES	5
508c2ecf20Sopenharmony_ci/***************************************************************************
518c2ecf20Sopenharmony_ci*  OCM directory default
528c2ecf20Sopenharmony_ci***************************************************************************/
538c2ecf20Sopenharmony_cistatic struct asd_ocm_dir OCMDirInit =
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	.sig = {0x4D, 0x4F},	/* signature */
568c2ecf20Sopenharmony_ci	.num_de = OCM_INIT_DIR_ENTRIES,	/* no. of directory entries */
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/***************************************************************************
608c2ecf20Sopenharmony_ci*  OCM directory Entries default
618c2ecf20Sopenharmony_ci***************************************************************************/
628c2ecf20Sopenharmony_cistatic struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] =
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	{
658c2ecf20Sopenharmony_ci		.type = (OCM_DE_ADDC2C_RES0),	/* Entry type  */
668c2ecf20Sopenharmony_ci		.offs = {128},			/* Offset */
678c2ecf20Sopenharmony_ci		.size = {0, 4},			/* size */
688c2ecf20Sopenharmony_ci	},
698c2ecf20Sopenharmony_ci	{
708c2ecf20Sopenharmony_ci		.type = (OCM_DE_ADDC2C_RES1),	/* Entry type  */
718c2ecf20Sopenharmony_ci		.offs = {128, 4},		/* Offset */
728c2ecf20Sopenharmony_ci		.size = {0, 4},			/* size */
738c2ecf20Sopenharmony_ci	},
748c2ecf20Sopenharmony_ci	{
758c2ecf20Sopenharmony_ci		.type = (OCM_DE_ADDC2C_RES2),	/* Entry type  */
768c2ecf20Sopenharmony_ci		.offs = {128, 8},		/* Offset */
778c2ecf20Sopenharmony_ci		.size = {0, 4},			/* size */
788c2ecf20Sopenharmony_ci	},
798c2ecf20Sopenharmony_ci	{
808c2ecf20Sopenharmony_ci		.type = (OCM_DE_ADDC2C_RES3),	/* Entry type  */
818c2ecf20Sopenharmony_ci		.offs = {128, 12},		/* Offset */
828c2ecf20Sopenharmony_ci		.size = {0, 4},			/* size */
838c2ecf20Sopenharmony_ci	},
848c2ecf20Sopenharmony_ci	{
858c2ecf20Sopenharmony_ci		.type = (OCM_DE_WIN_DRVR),	/* Entry type  */
868c2ecf20Sopenharmony_ci		.offs = {128, 16},		/* Offset */
878c2ecf20Sopenharmony_ci		.size = {128, 235, 1},		/* size */
888c2ecf20Sopenharmony_ci	},
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistruct asd_bios_chim_struct {
928c2ecf20Sopenharmony_ci	char sig[4];
938c2ecf20Sopenharmony_ci	u8   major;          /* 1 */
948c2ecf20Sopenharmony_ci	u8   minor;          /* 0 */
958c2ecf20Sopenharmony_ci	u8   bios_major;
968c2ecf20Sopenharmony_ci	u8   bios_minor;
978c2ecf20Sopenharmony_ci	__le32  bios_build;
988c2ecf20Sopenharmony_ci	u8   flags;
998c2ecf20Sopenharmony_ci	u8   pci_slot;
1008c2ecf20Sopenharmony_ci	__le16  ue_num;
1018c2ecf20Sopenharmony_ci	__le16  ue_size;
1028c2ecf20Sopenharmony_ci	u8  _r[14];
1038c2ecf20Sopenharmony_ci	/* The unit element array is right here.
1048c2ecf20Sopenharmony_ci	 */
1058c2ecf20Sopenharmony_ci} __attribute__ ((packed));
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/**
1088c2ecf20Sopenharmony_ci * asd_read_ocm_seg - read an on chip memory (OCM) segment
1098c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
1108c2ecf20Sopenharmony_ci * @buffer: where to write the read data
1118c2ecf20Sopenharmony_ci * @offs: offset into OCM where to read from
1128c2ecf20Sopenharmony_ci * @size: how many bytes to read
1138c2ecf20Sopenharmony_ci *
1148c2ecf20Sopenharmony_ci * Return the number of bytes not read. Return 0 on success.
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_cistatic int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
1178c2ecf20Sopenharmony_ci			    u32 offs, int size)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	u8 *p = buffer;
1208c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
1218c2ecf20Sopenharmony_ci		asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
1228c2ecf20Sopenharmony_ci	else {
1238c2ecf20Sopenharmony_ci		for ( ; size > 0; size--, offs++, p++)
1248c2ecf20Sopenharmony_ci			*p = asd_read_ocm_byte(asd_ha, offs);
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci	return size;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int asd_read_ocm_dir(struct asd_ha_struct *asd_ha,
1308c2ecf20Sopenharmony_ci			    struct asd_ocm_dir *dir, u32 offs)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir));
1338c2ecf20Sopenharmony_ci	if (err) {
1348c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't read ocm segment\n");
1358c2ecf20Sopenharmony_ci		return err;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (dir->sig[0] != 'M' || dir->sig[1] != 'O') {
1398c2ecf20Sopenharmony_ci		ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n",
1408c2ecf20Sopenharmony_ci			    dir->sig[0], dir->sig[1]);
1418c2ecf20Sopenharmony_ci		return -ENOENT;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	if (dir->major != 0) {
1448c2ecf20Sopenharmony_ci		asd_printk("unsupported major version of ocm dir:0x%x\n",
1458c2ecf20Sopenharmony_ci			   dir->major);
1468c2ecf20Sopenharmony_ci		return -ENOENT;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci	dir->num_de &= 0xf;
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/**
1538c2ecf20Sopenharmony_ci * asd_write_ocm_seg - write an on chip memory (OCM) segment
1548c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
1558c2ecf20Sopenharmony_ci * @buffer: where to read the write data
1568c2ecf20Sopenharmony_ci * @offs: offset into OCM to write to
1578c2ecf20Sopenharmony_ci * @size: how many bytes to write
1588c2ecf20Sopenharmony_ci *
1598c2ecf20Sopenharmony_ci * Return the number of bytes not written. Return 0 on success.
1608c2ecf20Sopenharmony_ci */
1618c2ecf20Sopenharmony_cistatic void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
1628c2ecf20Sopenharmony_ci			    u32 offs, int size)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	u8 *p = buffer;
1658c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
1668c2ecf20Sopenharmony_ci		asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
1678c2ecf20Sopenharmony_ci	else {
1688c2ecf20Sopenharmony_ci		for ( ; size > 0; size--, offs++, p++)
1698c2ecf20Sopenharmony_ci			asd_write_ocm_byte(asd_ha, offs, *p);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci	return;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16))
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type,
1778c2ecf20Sopenharmony_ci			      u32 *offs, u32 *size)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int i;
1808c2ecf20Sopenharmony_ci	struct asd_ocm_dir_ent *ent;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	for (i = 0; i < dir->num_de; i++) {
1838c2ecf20Sopenharmony_ci		if (dir->entry[i].type == type)
1848c2ecf20Sopenharmony_ci			break;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci	if (i >= dir->num_de)
1878c2ecf20Sopenharmony_ci		return -ENOENT;
1888c2ecf20Sopenharmony_ci	ent = &dir->entry[i];
1898c2ecf20Sopenharmony_ci	*offs = (u32) THREE_TO_NUM(ent->offs);
1908c2ecf20Sopenharmony_ci	*size = (u32) THREE_TO_NUM(ent->size);
1918c2ecf20Sopenharmony_ci	return 0;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci#define OCM_BIOS_CHIM_DE  2
1958c2ecf20Sopenharmony_ci#define BC_BIOS_PRESENT   1
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int asd_get_bios_chim(struct asd_ha_struct *asd_ha,
1988c2ecf20Sopenharmony_ci			     struct asd_ocm_dir *dir)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	int err;
2018c2ecf20Sopenharmony_ci	struct asd_bios_chim_struct *bc_struct;
2028c2ecf20Sopenharmony_ci	u32 offs, size;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size);
2058c2ecf20Sopenharmony_ci	if (err) {
2068c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n");
2078c2ecf20Sopenharmony_ci		goto out;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci	err = -ENOMEM;
2108c2ecf20Sopenharmony_ci	bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL);
2118c2ecf20Sopenharmony_ci	if (!bc_struct) {
2128c2ecf20Sopenharmony_ci		asd_printk("no memory for bios_chim struct\n");
2138c2ecf20Sopenharmony_ci		goto out;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci	err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs,
2168c2ecf20Sopenharmony_ci			       sizeof(*bc_struct));
2178c2ecf20Sopenharmony_ci	if (err) {
2188c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't read ocm segment\n");
2198c2ecf20Sopenharmony_ci		goto out2;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci	if (strncmp(bc_struct->sig, "SOIB", 4)
2228c2ecf20Sopenharmony_ci	    && strncmp(bc_struct->sig, "IPSA", 4)) {
2238c2ecf20Sopenharmony_ci		ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n",
2248c2ecf20Sopenharmony_ci			    bc_struct->sig[0], bc_struct->sig[1],
2258c2ecf20Sopenharmony_ci			    bc_struct->sig[2], bc_struct->sig[3]);
2268c2ecf20Sopenharmony_ci		err = -ENOENT;
2278c2ecf20Sopenharmony_ci		goto out2;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci	if (bc_struct->major != 1) {
2308c2ecf20Sopenharmony_ci		asd_printk("BIOS_CHIM unsupported major version:0x%x\n",
2318c2ecf20Sopenharmony_ci			   bc_struct->major);
2328c2ecf20Sopenharmony_ci		err = -ENOENT;
2338c2ecf20Sopenharmony_ci		goto out2;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	if (bc_struct->flags & BC_BIOS_PRESENT) {
2368c2ecf20Sopenharmony_ci		asd_ha->hw_prof.bios.present = 1;
2378c2ecf20Sopenharmony_ci		asd_ha->hw_prof.bios.maj = bc_struct->bios_major;
2388c2ecf20Sopenharmony_ci		asd_ha->hw_prof.bios.min = bc_struct->bios_minor;
2398c2ecf20Sopenharmony_ci		asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build);
2408c2ecf20Sopenharmony_ci		ASD_DPRINTK("BIOS present (%d,%d), %d\n",
2418c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.bios.maj,
2428c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.bios.min,
2438c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.bios.bld);
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num);
2468c2ecf20Sopenharmony_ci	asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size);
2478c2ecf20Sopenharmony_ci	ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num,
2488c2ecf20Sopenharmony_ci		    asd_ha->hw_prof.ue.size);
2498c2ecf20Sopenharmony_ci	size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size;
2508c2ecf20Sopenharmony_ci	if (size > 0) {
2518c2ecf20Sopenharmony_ci		err = -ENOMEM;
2528c2ecf20Sopenharmony_ci		asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL);
2538c2ecf20Sopenharmony_ci		if (!asd_ha->hw_prof.ue.area)
2548c2ecf20Sopenharmony_ci			goto out2;
2558c2ecf20Sopenharmony_ci		err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area,
2568c2ecf20Sopenharmony_ci				       offs + sizeof(*bc_struct), size);
2578c2ecf20Sopenharmony_ci		if (err) {
2588c2ecf20Sopenharmony_ci			kfree(asd_ha->hw_prof.ue.area);
2598c2ecf20Sopenharmony_ci			asd_ha->hw_prof.ue.area = NULL;
2608c2ecf20Sopenharmony_ci			asd_ha->hw_prof.ue.num  = 0;
2618c2ecf20Sopenharmony_ci			asd_ha->hw_prof.ue.size = 0;
2628c2ecf20Sopenharmony_ci			ASD_DPRINTK("couldn't read ue entries(%d)\n", err);
2638c2ecf20Sopenharmony_ci		}
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ciout2:
2668c2ecf20Sopenharmony_ci	kfree(bc_struct);
2678c2ecf20Sopenharmony_ciout:
2688c2ecf20Sopenharmony_ci	return err;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic void
2728c2ecf20Sopenharmony_ciasd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	int i;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* Zero OCM */
2778c2ecf20Sopenharmony_ci	for (i = 0; i < OCM_MAX_SIZE; i += 4)
2788c2ecf20Sopenharmony_ci		asd_write_ocm_dword(asd_ha, i, 0);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Write Dir */
2818c2ecf20Sopenharmony_ci	asd_write_ocm_seg(asd_ha, &OCMDirInit, 0,
2828c2ecf20Sopenharmony_ci			  sizeof(struct asd_ocm_dir));
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* Write Dir Entries */
2858c2ecf20Sopenharmony_ci	for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++)
2868c2ecf20Sopenharmony_ci		asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i],
2878c2ecf20Sopenharmony_ci				  sizeof(struct asd_ocm_dir) +
2888c2ecf20Sopenharmony_ci				  (i * sizeof(struct asd_ocm_dir_ent))
2898c2ecf20Sopenharmony_ci				  , sizeof(struct asd_ocm_dir_ent));
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int
2948c2ecf20Sopenharmony_ciasd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	struct pci_dev *pcidev = asd_ha->pcidev;
2978c2ecf20Sopenharmony_ci	u32 reg;
2988c2ecf20Sopenharmony_ci	int err = 0;
2998c2ecf20Sopenharmony_ci	u32 v;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* check if OCM has been initialized by BIOS */
3028c2ecf20Sopenharmony_ci	reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (!(reg & OCMINITIALIZED)) {
3058c2ecf20Sopenharmony_ci		err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v);
3068c2ecf20Sopenharmony_ci		if (err) {
3078c2ecf20Sopenharmony_ci			asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n",
3088c2ecf20Sopenharmony_ci					pci_name(pcidev));
3098c2ecf20Sopenharmony_ci			goto out;
3108c2ecf20Sopenharmony_ci		}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		printk(KERN_INFO "OCM is not initialized by BIOS,"
3138c2ecf20Sopenharmony_ci		       "reinitialize it and ignore it, current IntrptStatus"
3148c2ecf20Sopenharmony_ci		       "is 0x%x\n", v);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		if (v)
3178c2ecf20Sopenharmony_ci			err = pci_write_config_dword(pcidev,
3188c2ecf20Sopenharmony_ci						     PCIC_INTRPT_STAT, v);
3198c2ecf20Sopenharmony_ci		if (err) {
3208c2ecf20Sopenharmony_ci			asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n",
3218c2ecf20Sopenharmony_ci					pci_name(pcidev));
3228c2ecf20Sopenharmony_ci			goto out;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		asd_hwi_initialize_ocm_dir(asd_ha);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ciout:
3298c2ecf20Sopenharmony_ci	return err;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci/**
3338c2ecf20Sopenharmony_ci * asd_read_ocm - read on chip memory (OCM)
3348c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
3358c2ecf20Sopenharmony_ci */
3368c2ecf20Sopenharmony_ciint asd_read_ocm(struct asd_ha_struct *asd_ha)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	int err;
3398c2ecf20Sopenharmony_ci	struct asd_ocm_dir *dir;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (asd_hwi_check_ocm_access(asd_ha))
3428c2ecf20Sopenharmony_ci		return -1;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	dir = kmalloc(sizeof(*dir), GFP_KERNEL);
3458c2ecf20Sopenharmony_ci	if (!dir) {
3468c2ecf20Sopenharmony_ci		asd_printk("no memory for ocm dir\n");
3478c2ecf20Sopenharmony_ci		return -ENOMEM;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	err = asd_read_ocm_dir(asd_ha, dir, 0);
3518c2ecf20Sopenharmony_ci	if (err)
3528c2ecf20Sopenharmony_ci		goto out;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	err = asd_get_bios_chim(asd_ha, dir);
3558c2ecf20Sopenharmony_ciout:
3568c2ecf20Sopenharmony_ci	kfree(dir);
3578c2ecf20Sopenharmony_ci	return err;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/* ---------- FLASH stuff ---------- */
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci#define FLASH_RESET			0xF0
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci#define ASD_FLASH_SIZE                  0x200000
3658c2ecf20Sopenharmony_ci#define FLASH_DIR_COOKIE                "*** ADAPTEC FLASH DIRECTORY *** "
3668c2ecf20Sopenharmony_ci#define FLASH_NEXT_ENTRY_OFFS		0x2000
3678c2ecf20Sopenharmony_ci#define FLASH_MAX_DIR_ENTRIES		32
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci#define FLASH_DE_TYPE_MASK              0x3FFFFFFF
3708c2ecf20Sopenharmony_ci#define FLASH_DE_MS                     0x120
3718c2ecf20Sopenharmony_ci#define FLASH_DE_CTRL_A_USER            0xE0
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistruct asd_flash_de {
3748c2ecf20Sopenharmony_ci	__le32   type;
3758c2ecf20Sopenharmony_ci	__le32   offs;
3768c2ecf20Sopenharmony_ci	__le32   pad_size;
3778c2ecf20Sopenharmony_ci	__le32   image_size;
3788c2ecf20Sopenharmony_ci	__le32   chksum;
3798c2ecf20Sopenharmony_ci	u8       _r[12];
3808c2ecf20Sopenharmony_ci	u8       version[32];
3818c2ecf20Sopenharmony_ci} __attribute__ ((packed));
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistruct asd_flash_dir {
3848c2ecf20Sopenharmony_ci	u8    cookie[32];
3858c2ecf20Sopenharmony_ci	__le32   rev;		  /* 2 */
3868c2ecf20Sopenharmony_ci	__le32   chksum;
3878c2ecf20Sopenharmony_ci	__le32   chksum_antidote;
3888c2ecf20Sopenharmony_ci	__le32   bld;
3898c2ecf20Sopenharmony_ci	u8    bld_id[32];	  /* build id data */
3908c2ecf20Sopenharmony_ci	u8    ver_data[32];	  /* date and time of build */
3918c2ecf20Sopenharmony_ci	__le32   ae_mask;
3928c2ecf20Sopenharmony_ci	__le32   v_mask;
3938c2ecf20Sopenharmony_ci	__le32   oc_mask;
3948c2ecf20Sopenharmony_ci	u8    _r[20];
3958c2ecf20Sopenharmony_ci	struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES];
3968c2ecf20Sopenharmony_ci} __attribute__ ((packed));
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistruct asd_manuf_sec {
3998c2ecf20Sopenharmony_ci	char  sig[2];		  /* 'S', 'M' */
4008c2ecf20Sopenharmony_ci	u16   offs_next;
4018c2ecf20Sopenharmony_ci	u8    maj;           /* 0 */
4028c2ecf20Sopenharmony_ci	u8    min;           /* 0 */
4038c2ecf20Sopenharmony_ci	u16   chksum;
4048c2ecf20Sopenharmony_ci	u16   size;
4058c2ecf20Sopenharmony_ci	u8    _r[6];
4068c2ecf20Sopenharmony_ci	u8    sas_addr[SAS_ADDR_SIZE];
4078c2ecf20Sopenharmony_ci	u8    pcba_sn[ASD_PCBA_SN_SIZE];
4088c2ecf20Sopenharmony_ci	/* Here start the other segments */
4098c2ecf20Sopenharmony_ci	u8    linked_list[];
4108c2ecf20Sopenharmony_ci} __attribute__ ((packed));
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistruct asd_manuf_phy_desc {
4138c2ecf20Sopenharmony_ci	u8    state;         /* low 4 bits */
4148c2ecf20Sopenharmony_ci#define MS_PHY_STATE_ENABLED    0
4158c2ecf20Sopenharmony_ci#define MS_PHY_STATE_REPORTED   1
4168c2ecf20Sopenharmony_ci#define MS_PHY_STATE_HIDDEN     2
4178c2ecf20Sopenharmony_ci	u8    phy_id;
4188c2ecf20Sopenharmony_ci	u16   _r;
4198c2ecf20Sopenharmony_ci	u8    phy_control_0; /* mode 5 reg 0x160 */
4208c2ecf20Sopenharmony_ci	u8    phy_control_1; /* mode 5 reg 0x161 */
4218c2ecf20Sopenharmony_ci	u8    phy_control_2; /* mode 5 reg 0x162 */
4228c2ecf20Sopenharmony_ci	u8    phy_control_3; /* mode 5 reg 0x163 */
4238c2ecf20Sopenharmony_ci} __attribute__ ((packed));
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistruct asd_manuf_phy_param {
4268c2ecf20Sopenharmony_ci	char  sig[2];		  /* 'P', 'M' */
4278c2ecf20Sopenharmony_ci	u16   next;
4288c2ecf20Sopenharmony_ci	u8    maj;           /* 0 */
4298c2ecf20Sopenharmony_ci	u8    min;           /* 2 */
4308c2ecf20Sopenharmony_ci	u8    num_phy_desc;  /* 8 */
4318c2ecf20Sopenharmony_ci	u8    phy_desc_size; /* 8 */
4328c2ecf20Sopenharmony_ci	u8    _r[3];
4338c2ecf20Sopenharmony_ci	u8    usage_model_id;
4348c2ecf20Sopenharmony_ci	u32   _r2;
4358c2ecf20Sopenharmony_ci	struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS];
4368c2ecf20Sopenharmony_ci} __attribute__ ((packed));
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci#if 0
4398c2ecf20Sopenharmony_cistatic const char *asd_sb_type[] = {
4408c2ecf20Sopenharmony_ci	"unknown",
4418c2ecf20Sopenharmony_ci	"SGPIO",
4428c2ecf20Sopenharmony_ci	[2 ... 0x7F] = "unknown",
4438c2ecf20Sopenharmony_ci	[0x80] = "ADPT_I2C",
4448c2ecf20Sopenharmony_ci	[0x81 ... 0xFF] = "VENDOR_UNIQUExx"
4458c2ecf20Sopenharmony_ci};
4468c2ecf20Sopenharmony_ci#endif
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistruct asd_ms_sb_desc {
4498c2ecf20Sopenharmony_ci	u8    type;
4508c2ecf20Sopenharmony_ci	u8    node_desc_index;
4518c2ecf20Sopenharmony_ci	u8    conn_desc_index;
4528c2ecf20Sopenharmony_ci	u8    _recvd[];
4538c2ecf20Sopenharmony_ci} __attribute__ ((packed));
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci#if 0
4568c2ecf20Sopenharmony_cistatic const char *asd_conn_type[] = {
4578c2ecf20Sopenharmony_ci	[0 ... 7] = "unknown",
4588c2ecf20Sopenharmony_ci	"SFF8470",
4598c2ecf20Sopenharmony_ci	"SFF8482",
4608c2ecf20Sopenharmony_ci	"SFF8484",
4618c2ecf20Sopenharmony_ci	[0x80] = "PCIX_DAUGHTER0",
4628c2ecf20Sopenharmony_ci	[0x81] = "SAS_DAUGHTER0",
4638c2ecf20Sopenharmony_ci	[0x82 ... 0xFF] = "VENDOR_UNIQUExx"
4648c2ecf20Sopenharmony_ci};
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic const char *asd_conn_location[] = {
4678c2ecf20Sopenharmony_ci	"unknown",
4688c2ecf20Sopenharmony_ci	"internal",
4698c2ecf20Sopenharmony_ci	"external",
4708c2ecf20Sopenharmony_ci	"board_to_board",
4718c2ecf20Sopenharmony_ci};
4728c2ecf20Sopenharmony_ci#endif
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistruct asd_ms_conn_desc {
4758c2ecf20Sopenharmony_ci	u8    type;
4768c2ecf20Sopenharmony_ci	u8    location;
4778c2ecf20Sopenharmony_ci	u8    num_sideband_desc;
4788c2ecf20Sopenharmony_ci	u8    size_sideband_desc;
4798c2ecf20Sopenharmony_ci	u32   _resvd;
4808c2ecf20Sopenharmony_ci	u8    name[16];
4818c2ecf20Sopenharmony_ci	struct asd_ms_sb_desc sb_desc[];
4828c2ecf20Sopenharmony_ci} __attribute__ ((packed));
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistruct asd_nd_phy_desc {
4858c2ecf20Sopenharmony_ci	u8    vp_attch_type;
4868c2ecf20Sopenharmony_ci	u8    attch_specific[];
4878c2ecf20Sopenharmony_ci} __attribute__ ((packed));
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci#if 0
4908c2ecf20Sopenharmony_cistatic const char *asd_node_type[] = {
4918c2ecf20Sopenharmony_ci	"IOP",
4928c2ecf20Sopenharmony_ci	"IO_CONTROLLER",
4938c2ecf20Sopenharmony_ci	"EXPANDER",
4948c2ecf20Sopenharmony_ci	"PORT_MULTIPLIER",
4958c2ecf20Sopenharmony_ci	"PORT_MULTIPLEXER",
4968c2ecf20Sopenharmony_ci	"MULTI_DROP_I2C_BUS",
4978c2ecf20Sopenharmony_ci};
4988c2ecf20Sopenharmony_ci#endif
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistruct asd_ms_node_desc {
5018c2ecf20Sopenharmony_ci	u8    type;
5028c2ecf20Sopenharmony_ci	u8    num_phy_desc;
5038c2ecf20Sopenharmony_ci	u8    size_phy_desc;
5048c2ecf20Sopenharmony_ci	u8    _resvd;
5058c2ecf20Sopenharmony_ci	u8    name[16];
5068c2ecf20Sopenharmony_ci	struct asd_nd_phy_desc phy_desc[];
5078c2ecf20Sopenharmony_ci} __attribute__ ((packed));
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistruct asd_ms_conn_map {
5108c2ecf20Sopenharmony_ci	char  sig[2];		  /* 'M', 'C' */
5118c2ecf20Sopenharmony_ci	__le16 next;
5128c2ecf20Sopenharmony_ci	u8    maj;		  /* 0 */
5138c2ecf20Sopenharmony_ci	u8    min;		  /* 0 */
5148c2ecf20Sopenharmony_ci	__le16 cm_size;		  /* size of this struct */
5158c2ecf20Sopenharmony_ci	u8    num_conn;
5168c2ecf20Sopenharmony_ci	u8    conn_size;
5178c2ecf20Sopenharmony_ci	u8    num_nodes;
5188c2ecf20Sopenharmony_ci	u8    usage_model_id;
5198c2ecf20Sopenharmony_ci	u32   _resvd;
5208c2ecf20Sopenharmony_ci	struct asd_ms_conn_desc conn_desc[0];
5218c2ecf20Sopenharmony_ci	struct asd_ms_node_desc node_desc[];
5228c2ecf20Sopenharmony_ci} __attribute__ ((packed));
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistruct asd_ctrla_phy_entry {
5258c2ecf20Sopenharmony_ci	u8    sas_addr[SAS_ADDR_SIZE];
5268c2ecf20Sopenharmony_ci	u8    sas_link_rates;  /* max in hi bits, min in low bits */
5278c2ecf20Sopenharmony_ci	u8    flags;
5288c2ecf20Sopenharmony_ci	u8    sata_link_rates;
5298c2ecf20Sopenharmony_ci	u8    _r[5];
5308c2ecf20Sopenharmony_ci} __attribute__ ((packed));
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistruct asd_ctrla_phy_settings {
5338c2ecf20Sopenharmony_ci	u8    id0;		  /* P'h'y */
5348c2ecf20Sopenharmony_ci	u8    _r;
5358c2ecf20Sopenharmony_ci	u16   next;
5368c2ecf20Sopenharmony_ci	u8    num_phys;	      /* number of PHYs in the PCI function */
5378c2ecf20Sopenharmony_ci	u8    _r2[3];
5388c2ecf20Sopenharmony_ci	struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS];
5398c2ecf20Sopenharmony_ci} __attribute__ ((packed));
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistruct asd_ll_el {
5428c2ecf20Sopenharmony_ci	u8   id0;
5438c2ecf20Sopenharmony_ci	u8   id1;
5448c2ecf20Sopenharmony_ci	__le16  next;
5458c2ecf20Sopenharmony_ci	u8   something_here[];
5468c2ecf20Sopenharmony_ci} __attribute__ ((packed));
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic int asd_poll_flash(struct asd_ha_struct *asd_ha)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	int c;
5518c2ecf20Sopenharmony_ci	u8 d;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	for (c = 5000; c > 0; c--) {
5548c2ecf20Sopenharmony_ci		d  = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
5558c2ecf20Sopenharmony_ci		d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
5568c2ecf20Sopenharmony_ci		if (!d)
5578c2ecf20Sopenharmony_ci			return 0;
5588c2ecf20Sopenharmony_ci		udelay(5);
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci	return -ENOENT;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic int asd_reset_flash(struct asd_ha_struct *asd_ha)
5648c2ecf20Sopenharmony_ci{
5658c2ecf20Sopenharmony_ci	int err;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	err = asd_poll_flash(asd_ha);
5688c2ecf20Sopenharmony_ci	if (err)
5698c2ecf20Sopenharmony_ci		return err;
5708c2ecf20Sopenharmony_ci	asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET);
5718c2ecf20Sopenharmony_ci	err = asd_poll_flash(asd_ha);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	return err;
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic int asd_read_flash_seg(struct asd_ha_struct *asd_ha,
5778c2ecf20Sopenharmony_ci			      void *buffer, u32 offs, int size)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs,
5808c2ecf20Sopenharmony_ci			    size);
5818c2ecf20Sopenharmony_ci	return 0;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci/**
5858c2ecf20Sopenharmony_ci * asd_find_flash_dir - finds and reads the flash directory
5868c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
5878c2ecf20Sopenharmony_ci * @flash_dir: pointer to flash directory structure
5888c2ecf20Sopenharmony_ci *
5898c2ecf20Sopenharmony_ci * If found, the flash directory segment will be copied to
5908c2ecf20Sopenharmony_ci * @flash_dir.  Return 1 if found, 0 if not.
5918c2ecf20Sopenharmony_ci */
5928c2ecf20Sopenharmony_cistatic int asd_find_flash_dir(struct asd_ha_struct *asd_ha,
5938c2ecf20Sopenharmony_ci			      struct asd_flash_dir *flash_dir)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	u32 v;
5968c2ecf20Sopenharmony_ci	for (v = 0; v < ASD_FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
5978c2ecf20Sopenharmony_ci		asd_read_flash_seg(asd_ha, flash_dir, v,
5988c2ecf20Sopenharmony_ci				   sizeof(FLASH_DIR_COOKIE)-1);
5998c2ecf20Sopenharmony_ci		if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE,
6008c2ecf20Sopenharmony_ci			   sizeof(FLASH_DIR_COOKIE)-1) == 0) {
6018c2ecf20Sopenharmony_ci			asd_ha->hw_prof.flash.dir_offs = v;
6028c2ecf20Sopenharmony_ci			asd_read_flash_seg(asd_ha, flash_dir, v,
6038c2ecf20Sopenharmony_ci					   sizeof(*flash_dir));
6048c2ecf20Sopenharmony_ci			return 1;
6058c2ecf20Sopenharmony_ci		}
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci	return 0;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic int asd_flash_getid(struct asd_ha_struct *asd_ha)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	int err = 0;
6138c2ecf20Sopenharmony_ci	u32 reg;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR,
6188c2ecf20Sopenharmony_ci				  &asd_ha->hw_prof.flash.bar)) {
6198c2ecf20Sopenharmony_ci		asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n",
6208c2ecf20Sopenharmony_ci			   pci_name(asd_ha->pcidev));
6218c2ecf20Sopenharmony_ci		return -ENOENT;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.present = 1;
6248c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0;
6258c2ecf20Sopenharmony_ci	err = asd_reset_flash(asd_ha);
6268c2ecf20Sopenharmony_ci	if (err) {
6278c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't reset flash(%d)\n", err);
6288c2ecf20Sopenharmony_ci		return err;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci	return 0;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic u16 asd_calc_flash_chksum(u16 *p, int size)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	u16 chksum = 0;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	while (size-- > 0)
6388c2ecf20Sopenharmony_ci		chksum += *p++;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	return chksum;
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type,
6458c2ecf20Sopenharmony_ci			     u32 *offs, u32 *size)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	int i;
6488c2ecf20Sopenharmony_ci	struct asd_flash_de *de;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) {
6518c2ecf20Sopenharmony_ci		u32 type = le32_to_cpu(flash_dir->dir_entry[i].type);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		type &= FLASH_DE_TYPE_MASK;
6548c2ecf20Sopenharmony_ci		if (type == entry_type)
6558c2ecf20Sopenharmony_ci			break;
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci	if (i >= FLASH_MAX_DIR_ENTRIES)
6588c2ecf20Sopenharmony_ci		return -ENOENT;
6598c2ecf20Sopenharmony_ci	de = &flash_dir->dir_entry[i];
6608c2ecf20Sopenharmony_ci	*offs = le32_to_cpu(de->offs);
6618c2ecf20Sopenharmony_ci	*size = le32_to_cpu(de->pad_size);
6628c2ecf20Sopenharmony_ci	return 0;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic int asd_validate_ms(struct asd_manuf_sec *ms)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	if (ms->sig[0] != 'S' || ms->sig[1] != 'M') {
6688c2ecf20Sopenharmony_ci		ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n",
6698c2ecf20Sopenharmony_ci			    ms->sig[0], ms->sig[1]);
6708c2ecf20Sopenharmony_ci		return -ENOENT;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci	if (ms->maj != 0) {
6738c2ecf20Sopenharmony_ci		asd_printk("unsupported manuf. sector. major version:%x\n",
6748c2ecf20Sopenharmony_ci			   ms->maj);
6758c2ecf20Sopenharmony_ci		return -ENOENT;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci	ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next);
6788c2ecf20Sopenharmony_ci	ms->chksum = le16_to_cpu((__force __le16) ms->chksum);
6798c2ecf20Sopenharmony_ci	ms->size = le16_to_cpu((__force __le16) ms->size);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) {
6828c2ecf20Sopenharmony_ci		asd_printk("failed manuf sector checksum\n");
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	return 0;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cistatic int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha,
6898c2ecf20Sopenharmony_ci			       struct asd_manuf_sec *ms)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE);
6928c2ecf20Sopenharmony_ci	return 0;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistatic int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha,
6968c2ecf20Sopenharmony_ci			      struct asd_manuf_sec *ms)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE);
6998c2ecf20Sopenharmony_ci	asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0';
7008c2ecf20Sopenharmony_ci	return 0;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci/**
7048c2ecf20Sopenharmony_ci * asd_find_ll_by_id - find a linked list entry by its id
7058c2ecf20Sopenharmony_ci * @start: void pointer to the first element in the linked list
7068c2ecf20Sopenharmony_ci * @id0: the first byte of the id  (offs 0)
7078c2ecf20Sopenharmony_ci * @id1: the second byte of the id (offs 1)
7088c2ecf20Sopenharmony_ci *
7098c2ecf20Sopenharmony_ci * @start has to be the _base_ element start, since the
7108c2ecf20Sopenharmony_ci * linked list entries's offset is from this pointer.
7118c2ecf20Sopenharmony_ci * Some linked list entries use only the first id, in which case
7128c2ecf20Sopenharmony_ci * you can pass 0xFF for the second.
7138c2ecf20Sopenharmony_ci */
7148c2ecf20Sopenharmony_cistatic void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct asd_ll_el *el = start;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	do {
7198c2ecf20Sopenharmony_ci		switch (id1) {
7208c2ecf20Sopenharmony_ci		default:
7218c2ecf20Sopenharmony_ci			if (el->id1 == id1)
7228c2ecf20Sopenharmony_ci		case 0xFF:
7238c2ecf20Sopenharmony_ci				if (el->id0 == id0)
7248c2ecf20Sopenharmony_ci					return el;
7258c2ecf20Sopenharmony_ci		}
7268c2ecf20Sopenharmony_ci		el = start + le16_to_cpu(el->next);
7278c2ecf20Sopenharmony_ci	} while (el != start);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	return NULL;
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci/**
7338c2ecf20Sopenharmony_ci * asd_ms_get_phy_params - get phy parameters from the manufacturing sector
7348c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
7358c2ecf20Sopenharmony_ci * @manuf_sec: pointer to the manufacturing sector
7368c2ecf20Sopenharmony_ci *
7378c2ecf20Sopenharmony_ci * The manufacturing sector contans also the linked list of sub-segments,
7388c2ecf20Sopenharmony_ci * since when it was read, its size was taken from the flash directory,
7398c2ecf20Sopenharmony_ci * not from the structure size.
7408c2ecf20Sopenharmony_ci *
7418c2ecf20Sopenharmony_ci * HIDDEN phys do not count in the total count.  REPORTED phys cannot
7428c2ecf20Sopenharmony_ci * be enabled but are reported and counted towards the total.
7438c2ecf20Sopenharmony_ci * ENABLED phys are enabled by default and count towards the total.
7448c2ecf20Sopenharmony_ci * The absolute total phy number is ASD_MAX_PHYS.  hw_prof->num_phys
7458c2ecf20Sopenharmony_ci * merely specifies the number of phys the host adapter decided to
7468c2ecf20Sopenharmony_ci * report.  E.g., it is possible for phys 0, 1 and 2 to be HIDDEN,
7478c2ecf20Sopenharmony_ci * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENABLED.
7488c2ecf20Sopenharmony_ci * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2
7498c2ecf20Sopenharmony_ci * are actually enabled (enabled by default, max number of phys
7508c2ecf20Sopenharmony_ci * enableable in this case).
7518c2ecf20Sopenharmony_ci */
7528c2ecf20Sopenharmony_cistatic int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha,
7538c2ecf20Sopenharmony_ci				 struct asd_manuf_sec *manuf_sec)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	int i;
7568c2ecf20Sopenharmony_ci	int en_phys = 0;
7578c2ecf20Sopenharmony_ci	int rep_phys = 0;
7588c2ecf20Sopenharmony_ci	struct asd_manuf_phy_param *phy_param;
7598c2ecf20Sopenharmony_ci	struct asd_manuf_phy_param dflt_phy_param;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M');
7628c2ecf20Sopenharmony_ci	if (!phy_param) {
7638c2ecf20Sopenharmony_ci		ASD_DPRINTK("ms: no phy parameters found\n");
7648c2ecf20Sopenharmony_ci		ASD_DPRINTK("ms: Creating default phy parameters\n");
7658c2ecf20Sopenharmony_ci		dflt_phy_param.sig[0] = 'P';
7668c2ecf20Sopenharmony_ci		dflt_phy_param.sig[1] = 'M';
7678c2ecf20Sopenharmony_ci		dflt_phy_param.maj = 0;
7688c2ecf20Sopenharmony_ci		dflt_phy_param.min = 2;
7698c2ecf20Sopenharmony_ci		dflt_phy_param.num_phy_desc = 8;
7708c2ecf20Sopenharmony_ci		dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc);
7718c2ecf20Sopenharmony_ci		for (i =0; i < ASD_MAX_PHYS; i++) {
7728c2ecf20Sopenharmony_ci			dflt_phy_param.phy_desc[i].state = 0;
7738c2ecf20Sopenharmony_ci			dflt_phy_param.phy_desc[i].phy_id = i;
7748c2ecf20Sopenharmony_ci			dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6;
7758c2ecf20Sopenharmony_ci			dflt_phy_param.phy_desc[i].phy_control_1 = 0x10;
7768c2ecf20Sopenharmony_ci			dflt_phy_param.phy_desc[i].phy_control_2 = 0x43;
7778c2ecf20Sopenharmony_ci			dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb;
7788c2ecf20Sopenharmony_ci		}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci		phy_param = &dflt_phy_param;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (phy_param->maj != 0) {
7858c2ecf20Sopenharmony_ci		asd_printk("unsupported manuf. phy param major version:0x%x\n",
7868c2ecf20Sopenharmony_ci			   phy_param->maj);
7878c2ecf20Sopenharmony_ci		return -ENOENT;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc);
7918c2ecf20Sopenharmony_ci	asd_ha->hw_prof.enabled_phys = 0;
7928c2ecf20Sopenharmony_ci	for (i = 0; i < phy_param->num_phy_desc; i++) {
7938c2ecf20Sopenharmony_ci		struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i];
7948c2ecf20Sopenharmony_ci		switch (pd->state & 0xF) {
7958c2ecf20Sopenharmony_ci		case MS_PHY_STATE_HIDDEN:
7968c2ecf20Sopenharmony_ci			ASD_DPRINTK("ms: phy%d: HIDDEN\n", i);
7978c2ecf20Sopenharmony_ci			continue;
7988c2ecf20Sopenharmony_ci		case MS_PHY_STATE_REPORTED:
7998c2ecf20Sopenharmony_ci			ASD_DPRINTK("ms: phy%d: REPORTED\n", i);
8008c2ecf20Sopenharmony_ci			asd_ha->hw_prof.enabled_phys &= ~(1 << i);
8018c2ecf20Sopenharmony_ci			rep_phys++;
8028c2ecf20Sopenharmony_ci			continue;
8038c2ecf20Sopenharmony_ci		case MS_PHY_STATE_ENABLED:
8048c2ecf20Sopenharmony_ci			ASD_DPRINTK("ms: phy%d: ENABLED\n", i);
8058c2ecf20Sopenharmony_ci			asd_ha->hw_prof.enabled_phys |= (1 << i);
8068c2ecf20Sopenharmony_ci			en_phys++;
8078c2ecf20Sopenharmony_ci			break;
8088c2ecf20Sopenharmony_ci		}
8098c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0;
8108c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1;
8118c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2;
8128c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3;
8138c2ecf20Sopenharmony_ci	}
8148c2ecf20Sopenharmony_ci	asd_ha->hw_prof.max_phys = rep_phys + en_phys;
8158c2ecf20Sopenharmony_ci	asd_ha->hw_prof.num_phys = en_phys;
8168c2ecf20Sopenharmony_ci	ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n",
8178c2ecf20Sopenharmony_ci		    asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys);
8188c2ecf20Sopenharmony_ci	ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys);
8198c2ecf20Sopenharmony_ci	return 0;
8208c2ecf20Sopenharmony_ci}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_cistatic int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha,
8238c2ecf20Sopenharmony_ci				    struct asd_manuf_sec *manuf_sec)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct asd_ms_conn_map *cm;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	cm = asd_find_ll_by_id(manuf_sec, 'M', 'C');
8288c2ecf20Sopenharmony_ci	if (!cm) {
8298c2ecf20Sopenharmony_ci		ASD_DPRINTK("ms: no connector map found\n");
8308c2ecf20Sopenharmony_ci		return 0;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (cm->maj != 0) {
8348c2ecf20Sopenharmony_ci		ASD_DPRINTK("ms: unsupported: connector map major version 0x%x"
8358c2ecf20Sopenharmony_ci			    "\n", cm->maj);
8368c2ecf20Sopenharmony_ci		return -ENOENT;
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	/* XXX */
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	return 0;
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/**
8468c2ecf20Sopenharmony_ci * asd_process_ms - find and extract information from the manufacturing sector
8478c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
8488c2ecf20Sopenharmony_ci * @flash_dir: pointer to the flash directory
8498c2ecf20Sopenharmony_ci */
8508c2ecf20Sopenharmony_cistatic int asd_process_ms(struct asd_ha_struct *asd_ha,
8518c2ecf20Sopenharmony_ci			  struct asd_flash_dir *flash_dir)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	int err;
8548c2ecf20Sopenharmony_ci	struct asd_manuf_sec *manuf_sec;
8558c2ecf20Sopenharmony_ci	u32 offs, size;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size);
8588c2ecf20Sopenharmony_ci	if (err) {
8598c2ecf20Sopenharmony_ci		ASD_DPRINTK("Couldn't find the manuf. sector\n");
8608c2ecf20Sopenharmony_ci		goto out;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if (size == 0)
8648c2ecf20Sopenharmony_ci		goto out;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	err = -ENOMEM;
8678c2ecf20Sopenharmony_ci	manuf_sec = kmalloc(size, GFP_KERNEL);
8688c2ecf20Sopenharmony_ci	if (!manuf_sec) {
8698c2ecf20Sopenharmony_ci		ASD_DPRINTK("no mem for manuf sector\n");
8708c2ecf20Sopenharmony_ci		goto out;
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size);
8748c2ecf20Sopenharmony_ci	if (err) {
8758c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n",
8768c2ecf20Sopenharmony_ci			    offs, size);
8778c2ecf20Sopenharmony_ci		goto out2;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	err = asd_validate_ms(manuf_sec);
8818c2ecf20Sopenharmony_ci	if (err) {
8828c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't validate manuf sector\n");
8838c2ecf20Sopenharmony_ci		goto out2;
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	err = asd_ms_get_sas_addr(asd_ha, manuf_sec);
8878c2ecf20Sopenharmony_ci	if (err) {
8888c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't read the SAS_ADDR\n");
8898c2ecf20Sopenharmony_ci		goto out2;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci	ASD_DPRINTK("manuf sect SAS_ADDR %llx\n",
8928c2ecf20Sopenharmony_ci		    SAS_ADDR(asd_ha->hw_prof.sas_addr));
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	err = asd_ms_get_pcba_sn(asd_ha, manuf_sec);
8958c2ecf20Sopenharmony_ci	if (err) {
8968c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't read the PCBA SN\n");
8978c2ecf20Sopenharmony_ci		goto out2;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci	ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	err = asd_ms_get_phy_params(asd_ha, manuf_sec);
9028c2ecf20Sopenharmony_ci	if (err) {
9038c2ecf20Sopenharmony_ci		ASD_DPRINTK("ms: couldn't get phy parameters\n");
9048c2ecf20Sopenharmony_ci		goto out2;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	err = asd_ms_get_connector_map(asd_ha, manuf_sec);
9088c2ecf20Sopenharmony_ci	if (err) {
9098c2ecf20Sopenharmony_ci		ASD_DPRINTK("ms: couldn't get connector map\n");
9108c2ecf20Sopenharmony_ci		goto out2;
9118c2ecf20Sopenharmony_ci	}
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ciout2:
9148c2ecf20Sopenharmony_ci	kfree(manuf_sec);
9158c2ecf20Sopenharmony_ciout:
9168c2ecf20Sopenharmony_ci	return err;
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_cistatic int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha,
9208c2ecf20Sopenharmony_ci					  struct asd_ctrla_phy_settings *ps)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	int i;
9238c2ecf20Sopenharmony_ci	for (i = 0; i < ps->num_phys; i++) {
9248c2ecf20Sopenharmony_ci		struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i];
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		if (!PHY_ENABLED(asd_ha, i))
9278c2ecf20Sopenharmony_ci			continue;
9288c2ecf20Sopenharmony_ci		if (*(u64 *)pe->sas_addr == 0) {
9298c2ecf20Sopenharmony_ci			asd_ha->hw_prof.enabled_phys &= ~(1 << i);
9308c2ecf20Sopenharmony_ci			continue;
9318c2ecf20Sopenharmony_ci		}
9328c2ecf20Sopenharmony_ci		/* This is the SAS address which should be sent in IDENTIFY. */
9338c2ecf20Sopenharmony_ci		memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr,
9348c2ecf20Sopenharmony_ci		       SAS_ADDR_SIZE);
9358c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
9368c2ecf20Sopenharmony_ci			(pe->sas_link_rates & 0xF0) >> 4;
9378c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
9388c2ecf20Sopenharmony_ci			(pe->sas_link_rates & 0x0F);
9398c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
9408c2ecf20Sopenharmony_ci			(pe->sata_link_rates & 0xF0) >> 4;
9418c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
9428c2ecf20Sopenharmony_ci			(pe->sata_link_rates & 0x0F);
9438c2ecf20Sopenharmony_ci		asd_ha->hw_prof.phy_desc[i].flags = pe->flags;
9448c2ecf20Sopenharmony_ci		ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x,"
9458c2ecf20Sopenharmony_ci			    " sata rate:0x%x-0x%x, flags:0x%x\n",
9468c2ecf20Sopenharmony_ci			    i,
9478c2ecf20Sopenharmony_ci			    SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr),
9488c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.phy_desc[i].max_sas_lrate,
9498c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.phy_desc[i].min_sas_lrate,
9508c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.phy_desc[i].max_sata_lrate,
9518c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.phy_desc[i].min_sata_lrate,
9528c2ecf20Sopenharmony_ci			    asd_ha->hw_prof.phy_desc[i].flags);
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return 0;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci/**
9598c2ecf20Sopenharmony_ci * asd_process_ctrl_a_user - process CTRL-A user settings
9608c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
9618c2ecf20Sopenharmony_ci * @flash_dir: pointer to the flash directory
9628c2ecf20Sopenharmony_ci */
9638c2ecf20Sopenharmony_cistatic int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
9648c2ecf20Sopenharmony_ci				   struct asd_flash_dir *flash_dir)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	int err, i;
9678c2ecf20Sopenharmony_ci	u32 offs, size;
9688c2ecf20Sopenharmony_ci	struct asd_ll_el *el = NULL;
9698c2ecf20Sopenharmony_ci	struct asd_ctrla_phy_settings *ps;
9708c2ecf20Sopenharmony_ci	struct asd_ctrla_phy_settings dflt_ps;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size);
9738c2ecf20Sopenharmony_ci	if (err) {
9748c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't find CTRL-A user settings section\n");
9758c2ecf20Sopenharmony_ci		ASD_DPRINTK("Creating default CTRL-A user settings section\n");
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci		dflt_ps.id0 = 'h';
9788c2ecf20Sopenharmony_ci		dflt_ps.num_phys = 8;
9798c2ecf20Sopenharmony_ci		for (i =0; i < ASD_MAX_PHYS; i++) {
9808c2ecf20Sopenharmony_ci			memcpy(dflt_ps.phy_ent[i].sas_addr,
9818c2ecf20Sopenharmony_ci			       asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
9828c2ecf20Sopenharmony_ci			dflt_ps.phy_ent[i].sas_link_rates = 0x98;
9838c2ecf20Sopenharmony_ci			dflt_ps.phy_ent[i].flags = 0x0;
9848c2ecf20Sopenharmony_ci			dflt_ps.phy_ent[i].sata_link_rates = 0x0;
9858c2ecf20Sopenharmony_ci		}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci		size = sizeof(struct asd_ctrla_phy_settings);
9888c2ecf20Sopenharmony_ci		ps = &dflt_ps;
9898c2ecf20Sopenharmony_ci		goto out_process;
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (size == 0)
9938c2ecf20Sopenharmony_ci		goto out;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	err = -ENOMEM;
9968c2ecf20Sopenharmony_ci	el = kmalloc(size, GFP_KERNEL);
9978c2ecf20Sopenharmony_ci	if (!el) {
9988c2ecf20Sopenharmony_ci		ASD_DPRINTK("no mem for ctrla user settings section\n");
9998c2ecf20Sopenharmony_ci		goto out;
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	err = asd_read_flash_seg(asd_ha, (void *)el, offs, size);
10038c2ecf20Sopenharmony_ci	if (err) {
10048c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't read ctrla phy settings section\n");
10058c2ecf20Sopenharmony_ci		goto out2;
10068c2ecf20Sopenharmony_ci	}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	err = -ENOENT;
10098c2ecf20Sopenharmony_ci	ps = asd_find_ll_by_id(el, 'h', 0xFF);
10108c2ecf20Sopenharmony_ci	if (!ps) {
10118c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
10128c2ecf20Sopenharmony_ci		goto out2;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ciout_process:
10158c2ecf20Sopenharmony_ci	err = asd_process_ctrla_phy_settings(asd_ha, ps);
10168c2ecf20Sopenharmony_ci	if (err) {
10178c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't process ctrla phy settings\n");
10188c2ecf20Sopenharmony_ci		goto out2;
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ciout2:
10218c2ecf20Sopenharmony_ci	kfree(el);
10228c2ecf20Sopenharmony_ciout:
10238c2ecf20Sopenharmony_ci	return err;
10248c2ecf20Sopenharmony_ci}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci/**
10278c2ecf20Sopenharmony_ci * asd_read_flash - read flash memory
10288c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
10298c2ecf20Sopenharmony_ci */
10308c2ecf20Sopenharmony_ciint asd_read_flash(struct asd_ha_struct *asd_ha)
10318c2ecf20Sopenharmony_ci{
10328c2ecf20Sopenharmony_ci	int err;
10338c2ecf20Sopenharmony_ci	struct asd_flash_dir *flash_dir;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	err = asd_flash_getid(asd_ha);
10368c2ecf20Sopenharmony_ci	if (err)
10378c2ecf20Sopenharmony_ci		return err;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL);
10408c2ecf20Sopenharmony_ci	if (!flash_dir)
10418c2ecf20Sopenharmony_ci		return -ENOMEM;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	err = -ENOENT;
10448c2ecf20Sopenharmony_ci	if (!asd_find_flash_dir(asd_ha, flash_dir)) {
10458c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't find flash directory\n");
10468c2ecf20Sopenharmony_ci		goto out;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	if (le32_to_cpu(flash_dir->rev) != 2) {
10508c2ecf20Sopenharmony_ci		asd_printk("unsupported flash dir version:0x%x\n",
10518c2ecf20Sopenharmony_ci			   le32_to_cpu(flash_dir->rev));
10528c2ecf20Sopenharmony_ci		goto out;
10538c2ecf20Sopenharmony_ci	}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	err = asd_process_ms(asd_ha, flash_dir);
10568c2ecf20Sopenharmony_ci	if (err) {
10578c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't process manuf sector settings\n");
10588c2ecf20Sopenharmony_ci		goto out;
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	err = asd_process_ctrl_a_user(asd_ha, flash_dir);
10628c2ecf20Sopenharmony_ci	if (err) {
10638c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't process CTRL-A user settings\n");
10648c2ecf20Sopenharmony_ci		goto out;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ciout:
10688c2ecf20Sopenharmony_ci	kfree(flash_dir);
10698c2ecf20Sopenharmony_ci	return err;
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci/**
10738c2ecf20Sopenharmony_ci * asd_verify_flash_seg - verify data with flash memory
10748c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
10758c2ecf20Sopenharmony_ci * @src: pointer to the source data to be verified
10768c2ecf20Sopenharmony_ci * @dest_offset: offset from flash memory
10778c2ecf20Sopenharmony_ci * @bytes_to_verify: total bytes to verify
10788c2ecf20Sopenharmony_ci */
10798c2ecf20Sopenharmony_ciint asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
10808c2ecf20Sopenharmony_ci			 const void *src, u32 dest_offset, u32 bytes_to_verify)
10818c2ecf20Sopenharmony_ci{
10828c2ecf20Sopenharmony_ci	const u8 *src_buf;
10838c2ecf20Sopenharmony_ci	u8 flash_char;
10848c2ecf20Sopenharmony_ci	int err;
10858c2ecf20Sopenharmony_ci	u32 nv_offset, reg, i;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	reg = asd_ha->hw_prof.flash.bar;
10888c2ecf20Sopenharmony_ci	src_buf = NULL;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	err = FLASH_OK;
10918c2ecf20Sopenharmony_ci	nv_offset = dest_offset;
10928c2ecf20Sopenharmony_ci	src_buf = (const u8 *)src;
10938c2ecf20Sopenharmony_ci	for (i = 0; i < bytes_to_verify; i++) {
10948c2ecf20Sopenharmony_ci		flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i);
10958c2ecf20Sopenharmony_ci		if (flash_char != src_buf[i]) {
10968c2ecf20Sopenharmony_ci			err = FAIL_VERIFY;
10978c2ecf20Sopenharmony_ci			break;
10988c2ecf20Sopenharmony_ci		}
10998c2ecf20Sopenharmony_ci	}
11008c2ecf20Sopenharmony_ci	return err;
11018c2ecf20Sopenharmony_ci}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci/**
11048c2ecf20Sopenharmony_ci * asd_write_flash_seg - write data into flash memory
11058c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
11068c2ecf20Sopenharmony_ci * @src: pointer to the source data to be written
11078c2ecf20Sopenharmony_ci * @dest_offset: offset from flash memory
11088c2ecf20Sopenharmony_ci * @bytes_to_write: total bytes to write
11098c2ecf20Sopenharmony_ci */
11108c2ecf20Sopenharmony_ciint asd_write_flash_seg(struct asd_ha_struct *asd_ha,
11118c2ecf20Sopenharmony_ci			const void *src, u32 dest_offset, u32 bytes_to_write)
11128c2ecf20Sopenharmony_ci{
11138c2ecf20Sopenharmony_ci	const u8 *src_buf;
11148c2ecf20Sopenharmony_ci	u32 nv_offset, reg, i;
11158c2ecf20Sopenharmony_ci	int err;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	reg = asd_ha->hw_prof.flash.bar;
11188c2ecf20Sopenharmony_ci	src_buf = NULL;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	err = asd_check_flash_type(asd_ha);
11218c2ecf20Sopenharmony_ci	if (err) {
11228c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err);
11238c2ecf20Sopenharmony_ci		return err;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	nv_offset = dest_offset;
11278c2ecf20Sopenharmony_ci	err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write);
11288c2ecf20Sopenharmony_ci	if (err) {
11298c2ecf20Sopenharmony_ci		ASD_DPRINTK("Erase failed at offset:0x%x\n",
11308c2ecf20Sopenharmony_ci			nv_offset);
11318c2ecf20Sopenharmony_ci		return err;
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	err = asd_reset_flash(asd_ha);
11358c2ecf20Sopenharmony_ci	if (err) {
11368c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
11378c2ecf20Sopenharmony_ci		return err;
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	src_buf = (const u8 *)src;
11418c2ecf20Sopenharmony_ci	for (i = 0; i < bytes_to_write; i++) {
11428c2ecf20Sopenharmony_ci		/* Setup program command sequence */
11438c2ecf20Sopenharmony_ci		switch (asd_ha->hw_prof.flash.method) {
11448c2ecf20Sopenharmony_ci		case FLASH_METHOD_A:
11458c2ecf20Sopenharmony_ci		{
11468c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11478c2ecf20Sopenharmony_ci					(reg + 0xAAA), 0xAA);
11488c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11498c2ecf20Sopenharmony_ci					(reg + 0x555), 0x55);
11508c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11518c2ecf20Sopenharmony_ci					(reg + 0xAAA), 0xA0);
11528c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11538c2ecf20Sopenharmony_ci					(reg + nv_offset + i),
11548c2ecf20Sopenharmony_ci					(*(src_buf + i)));
11558c2ecf20Sopenharmony_ci			break;
11568c2ecf20Sopenharmony_ci		}
11578c2ecf20Sopenharmony_ci		case FLASH_METHOD_B:
11588c2ecf20Sopenharmony_ci		{
11598c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11608c2ecf20Sopenharmony_ci					(reg + 0x555), 0xAA);
11618c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11628c2ecf20Sopenharmony_ci					(reg + 0x2AA), 0x55);
11638c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11648c2ecf20Sopenharmony_ci					(reg + 0x555), 0xA0);
11658c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha,
11668c2ecf20Sopenharmony_ci					(reg + nv_offset + i),
11678c2ecf20Sopenharmony_ci					(*(src_buf + i)));
11688c2ecf20Sopenharmony_ci			break;
11698c2ecf20Sopenharmony_ci		}
11708c2ecf20Sopenharmony_ci		default:
11718c2ecf20Sopenharmony_ci			break;
11728c2ecf20Sopenharmony_ci		}
11738c2ecf20Sopenharmony_ci		if (asd_chk_write_status(asd_ha,
11748c2ecf20Sopenharmony_ci				(nv_offset + i), 0) != 0) {
11758c2ecf20Sopenharmony_ci			ASD_DPRINTK("aicx: Write failed at offset:0x%x\n",
11768c2ecf20Sopenharmony_ci				reg + nv_offset + i);
11778c2ecf20Sopenharmony_ci			return FAIL_WRITE_FLASH;
11788c2ecf20Sopenharmony_ci		}
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	err = asd_reset_flash(asd_ha);
11828c2ecf20Sopenharmony_ci	if (err) {
11838c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
11848c2ecf20Sopenharmony_ci		return err;
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci	return 0;
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ciint asd_chk_write_status(struct asd_ha_struct *asd_ha,
11908c2ecf20Sopenharmony_ci	 u32 sector_addr, u8 erase_flag)
11918c2ecf20Sopenharmony_ci{
11928c2ecf20Sopenharmony_ci	u32 reg;
11938c2ecf20Sopenharmony_ci	u32 loop_cnt;
11948c2ecf20Sopenharmony_ci	u8  nv_data1, nv_data2;
11958c2ecf20Sopenharmony_ci	u8  toggle_bit1;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	/*
11988c2ecf20Sopenharmony_ci	 * Read from DQ2 requires sector address
11998c2ecf20Sopenharmony_ci	 * while it's dont care for DQ6
12008c2ecf20Sopenharmony_ci	 */
12018c2ecf20Sopenharmony_ci	reg = asd_ha->hw_prof.flash.bar;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) {
12048c2ecf20Sopenharmony_ci		nv_data1 = asd_read_reg_byte(asd_ha, reg);
12058c2ecf20Sopenharmony_ci		nv_data2 = asd_read_reg_byte(asd_ha, reg);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci		toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
12088c2ecf20Sopenharmony_ci				 ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci		if (toggle_bit1 == 0) {
12118c2ecf20Sopenharmony_ci			return 0;
12128c2ecf20Sopenharmony_ci		} else {
12138c2ecf20Sopenharmony_ci			if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) {
12148c2ecf20Sopenharmony_ci				nv_data1 = asd_read_reg_byte(asd_ha,
12158c2ecf20Sopenharmony_ci								reg);
12168c2ecf20Sopenharmony_ci				nv_data2 = asd_read_reg_byte(asd_ha,
12178c2ecf20Sopenharmony_ci								reg);
12188c2ecf20Sopenharmony_ci				toggle_bit1 =
12198c2ecf20Sopenharmony_ci				((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
12208c2ecf20Sopenharmony_ci				^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci				if (toggle_bit1 == 0)
12238c2ecf20Sopenharmony_ci					return 0;
12248c2ecf20Sopenharmony_ci			}
12258c2ecf20Sopenharmony_ci		}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci		/*
12288c2ecf20Sopenharmony_ci		 * ERASE is a sector-by-sector operation and requires
12298c2ecf20Sopenharmony_ci		 * more time to finish while WRITE is byte-byte-byte
12308c2ecf20Sopenharmony_ci		 * operation and takes lesser time to finish.
12318c2ecf20Sopenharmony_ci		 *
12328c2ecf20Sopenharmony_ci		 * For some strange reason a reduced ERASE delay gives different
12338c2ecf20Sopenharmony_ci		 * behaviour across different spirit boards. Hence we set
12348c2ecf20Sopenharmony_ci		 * a optimum balance of 50mus for ERASE which works well
12358c2ecf20Sopenharmony_ci		 * across all boards.
12368c2ecf20Sopenharmony_ci		 */
12378c2ecf20Sopenharmony_ci		if (erase_flag) {
12388c2ecf20Sopenharmony_ci			udelay(FLASH_STATUS_ERASE_DELAY_COUNT);
12398c2ecf20Sopenharmony_ci		} else {
12408c2ecf20Sopenharmony_ci			udelay(FLASH_STATUS_WRITE_DELAY_COUNT);
12418c2ecf20Sopenharmony_ci		}
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci	return -1;
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci/**
12478c2ecf20Sopenharmony_ci * asd_hwi_erase_nv_sector - Erase the flash memory sectors.
12488c2ecf20Sopenharmony_ci * @asd_ha: pointer to the host adapter structure
12498c2ecf20Sopenharmony_ci * @flash_addr: pointer to offset from flash memory
12508c2ecf20Sopenharmony_ci * @size: total bytes to erase.
12518c2ecf20Sopenharmony_ci */
12528c2ecf20Sopenharmony_ciint asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size)
12538c2ecf20Sopenharmony_ci{
12548c2ecf20Sopenharmony_ci	u32 reg;
12558c2ecf20Sopenharmony_ci	u32 sector_addr;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	reg = asd_ha->hw_prof.flash.bar;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* sector staring address */
12608c2ecf20Sopenharmony_ci	sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	/*
12638c2ecf20Sopenharmony_ci	 * Erasing an flash sector needs to be done in six consecutive
12648c2ecf20Sopenharmony_ci	 * write cyles.
12658c2ecf20Sopenharmony_ci	 */
12668c2ecf20Sopenharmony_ci	while (sector_addr < flash_addr+size) {
12678c2ecf20Sopenharmony_ci		switch (asd_ha->hw_prof.flash.method) {
12688c2ecf20Sopenharmony_ci		case FLASH_METHOD_A:
12698c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
12708c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
12718c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80);
12728c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
12738c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
12748c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
12758c2ecf20Sopenharmony_ci			break;
12768c2ecf20Sopenharmony_ci		case FLASH_METHOD_B:
12778c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
12788c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
12798c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80);
12808c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
12818c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
12828c2ecf20Sopenharmony_ci			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
12838c2ecf20Sopenharmony_ci			break;
12848c2ecf20Sopenharmony_ci		default:
12858c2ecf20Sopenharmony_ci			break;
12868c2ecf20Sopenharmony_ci		}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci		if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0)
12898c2ecf20Sopenharmony_ci			return FAIL_ERASE_FLASH;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci		sector_addr += FLASH_SECTOR_SIZE;
12928c2ecf20Sopenharmony_ci	}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	return 0;
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ciint asd_check_flash_type(struct asd_ha_struct *asd_ha)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	u8 manuf_id;
13008c2ecf20Sopenharmony_ci	u8 dev_id;
13018c2ecf20Sopenharmony_ci	u8 sec_prot;
13028c2ecf20Sopenharmony_ci	u32 inc;
13038c2ecf20Sopenharmony_ci	u32 reg;
13048c2ecf20Sopenharmony_ci	int err;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	/* get Flash memory base address */
13078c2ecf20Sopenharmony_ci	reg = asd_ha->hw_prof.flash.bar;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	/* Determine flash info */
13108c2ecf20Sopenharmony_ci	err = asd_reset_flash(asd_ha);
13118c2ecf20Sopenharmony_ci	if (err) {
13128c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
13138c2ecf20Sopenharmony_ci		return err;
13148c2ecf20Sopenharmony_ci	}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN;
13178c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN;
13188c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	/* Get flash info. This would most likely be AMD Am29LV family flash.
13218c2ecf20Sopenharmony_ci	 * First try the sequence for word mode.  It is the same as for
13228c2ecf20Sopenharmony_ci	 * 008B (byte mode only), 160B (word mode) and 800D (word mode).
13238c2ecf20Sopenharmony_ci	 */
13248c2ecf20Sopenharmony_ci	inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
13258c2ecf20Sopenharmony_ci	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
13268c2ecf20Sopenharmony_ci	asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
13278c2ecf20Sopenharmony_ci	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
13288c2ecf20Sopenharmony_ci	manuf_id = asd_read_reg_byte(asd_ha, reg);
13298c2ecf20Sopenharmony_ci	dev_id = asd_read_reg_byte(asd_ha, reg + inc);
13308c2ecf20Sopenharmony_ci	sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
13318c2ecf20Sopenharmony_ci	/* Get out of autoselect mode. */
13328c2ecf20Sopenharmony_ci	err = asd_reset_flash(asd_ha);
13338c2ecf20Sopenharmony_ci	if (err) {
13348c2ecf20Sopenharmony_ci		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
13358c2ecf20Sopenharmony_ci		return err;
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci	ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) "
13388c2ecf20Sopenharmony_ci		"sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot);
13398c2ecf20Sopenharmony_ci	err = asd_reset_flash(asd_ha);
13408c2ecf20Sopenharmony_ci	if (err != 0)
13418c2ecf20Sopenharmony_ci		return err;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	switch (manuf_id) {
13448c2ecf20Sopenharmony_ci	case FLASH_MANUF_ID_AMD:
13458c2ecf20Sopenharmony_ci		switch (sec_prot) {
13468c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_AM29LV800DT:
13478c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_AM29LV640MT:
13488c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_AM29F800B:
13498c2ecf20Sopenharmony_ci			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
13508c2ecf20Sopenharmony_ci			break;
13518c2ecf20Sopenharmony_ci		default:
13528c2ecf20Sopenharmony_ci			break;
13538c2ecf20Sopenharmony_ci		}
13548c2ecf20Sopenharmony_ci		break;
13558c2ecf20Sopenharmony_ci	case FLASH_MANUF_ID_ST:
13568c2ecf20Sopenharmony_ci		switch (sec_prot) {
13578c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_STM29W800DT:
13588c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_STM29LV640:
13598c2ecf20Sopenharmony_ci			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
13608c2ecf20Sopenharmony_ci			break;
13618c2ecf20Sopenharmony_ci		default:
13628c2ecf20Sopenharmony_ci			break;
13638c2ecf20Sopenharmony_ci		}
13648c2ecf20Sopenharmony_ci		break;
13658c2ecf20Sopenharmony_ci	case FLASH_MANUF_ID_FUJITSU:
13668c2ecf20Sopenharmony_ci		switch (sec_prot) {
13678c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_MBM29LV800TE:
13688c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_MBM29DL800TA:
13698c2ecf20Sopenharmony_ci			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
13708c2ecf20Sopenharmony_ci			break;
13718c2ecf20Sopenharmony_ci		}
13728c2ecf20Sopenharmony_ci		break;
13738c2ecf20Sopenharmony_ci	case FLASH_MANUF_ID_MACRONIX:
13748c2ecf20Sopenharmony_ci		switch (sec_prot) {
13758c2ecf20Sopenharmony_ci		case FLASH_DEV_ID_MX29LV800BT:
13768c2ecf20Sopenharmony_ci			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
13778c2ecf20Sopenharmony_ci			break;
13788c2ecf20Sopenharmony_ci		}
13798c2ecf20Sopenharmony_ci		break;
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) {
13838c2ecf20Sopenharmony_ci		err = asd_reset_flash(asd_ha);
13848c2ecf20Sopenharmony_ci		if (err) {
13858c2ecf20Sopenharmony_ci			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
13868c2ecf20Sopenharmony_ci			return err;
13878c2ecf20Sopenharmony_ci		}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci		/* Issue Unlock sequence for AM29LV008BT */
13908c2ecf20Sopenharmony_ci		asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
13918c2ecf20Sopenharmony_ci		asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
13928c2ecf20Sopenharmony_ci		asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90);
13938c2ecf20Sopenharmony_ci		manuf_id = asd_read_reg_byte(asd_ha, reg);
13948c2ecf20Sopenharmony_ci		dev_id = asd_read_reg_byte(asd_ha, reg + inc);
13958c2ecf20Sopenharmony_ci		sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci		ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot"
13988c2ecf20Sopenharmony_ci			"(0x%x)\n", manuf_id, dev_id, sec_prot);
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci		err = asd_reset_flash(asd_ha);
14018c2ecf20Sopenharmony_ci		if (err != 0) {
14028c2ecf20Sopenharmony_ci			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
14038c2ecf20Sopenharmony_ci			return err;
14048c2ecf20Sopenharmony_ci		}
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci		switch (manuf_id) {
14078c2ecf20Sopenharmony_ci		case FLASH_MANUF_ID_AMD:
14088c2ecf20Sopenharmony_ci			switch (dev_id) {
14098c2ecf20Sopenharmony_ci			case FLASH_DEV_ID_AM29LV008BT:
14108c2ecf20Sopenharmony_ci				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
14118c2ecf20Sopenharmony_ci				break;
14128c2ecf20Sopenharmony_ci			default:
14138c2ecf20Sopenharmony_ci				break;
14148c2ecf20Sopenharmony_ci			}
14158c2ecf20Sopenharmony_ci			break;
14168c2ecf20Sopenharmony_ci		case FLASH_MANUF_ID_ST:
14178c2ecf20Sopenharmony_ci			switch (dev_id) {
14188c2ecf20Sopenharmony_ci			case FLASH_DEV_ID_STM29008:
14198c2ecf20Sopenharmony_ci				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
14208c2ecf20Sopenharmony_ci				break;
14218c2ecf20Sopenharmony_ci			default:
14228c2ecf20Sopenharmony_ci				break;
14238c2ecf20Sopenharmony_ci			}
14248c2ecf20Sopenharmony_ci			break;
14258c2ecf20Sopenharmony_ci		case FLASH_MANUF_ID_FUJITSU:
14268c2ecf20Sopenharmony_ci			switch (dev_id) {
14278c2ecf20Sopenharmony_ci			case FLASH_DEV_ID_MBM29LV008TA:
14288c2ecf20Sopenharmony_ci				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
14298c2ecf20Sopenharmony_ci				break;
14308c2ecf20Sopenharmony_ci			}
14318c2ecf20Sopenharmony_ci			break;
14328c2ecf20Sopenharmony_ci		case FLASH_MANUF_ID_INTEL:
14338c2ecf20Sopenharmony_ci			switch (dev_id) {
14348c2ecf20Sopenharmony_ci			case FLASH_DEV_ID_I28LV00TAT:
14358c2ecf20Sopenharmony_ci				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
14368c2ecf20Sopenharmony_ci				break;
14378c2ecf20Sopenharmony_ci			}
14388c2ecf20Sopenharmony_ci			break;
14398c2ecf20Sopenharmony_ci		case FLASH_MANUF_ID_MACRONIX:
14408c2ecf20Sopenharmony_ci			switch (dev_id) {
14418c2ecf20Sopenharmony_ci			case FLASH_DEV_ID_I28LV00TAT:
14428c2ecf20Sopenharmony_ci				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
14438c2ecf20Sopenharmony_ci				break;
14448c2ecf20Sopenharmony_ci			}
14458c2ecf20Sopenharmony_ci			break;
14468c2ecf20Sopenharmony_ci		default:
14478c2ecf20Sopenharmony_ci			return FAIL_FIND_FLASH_ID;
14488c2ecf20Sopenharmony_ci		}
14498c2ecf20Sopenharmony_ci	}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN)
14528c2ecf20Sopenharmony_ci	      return FAIL_FIND_FLASH_ID;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.manuf = manuf_id;
14558c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.dev_id = dev_id;
14568c2ecf20Sopenharmony_ci	asd_ha->hw_prof.flash.sec_prot = sec_prot;
14578c2ecf20Sopenharmony_ci	return 0;
14588c2ecf20Sopenharmony_ci}
1459