162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Aic94xx SAS/SATA driver sequencer interface. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 Adaptec, Inc. All rights reserved. 662306a36Sopenharmony_ci * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Parts of this code adapted from David Chaw's adp94xx_seq.c. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/gfp.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/firmware.h> 1662306a36Sopenharmony_ci#include "aic94xx_reg.h" 1762306a36Sopenharmony_ci#include "aic94xx_hwi.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "aic94xx_seq.h" 2062306a36Sopenharmony_ci#include "aic94xx_dump.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* It takes no more than 0.05 us for an instruction 2362306a36Sopenharmony_ci * to complete. So waiting for 1 us should be more than 2462306a36Sopenharmony_ci * plenty. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci#define PAUSE_DELAY 1 2762306a36Sopenharmony_ci#define PAUSE_TRIES 1000 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic const struct firmware *sequencer_fw; 3062306a36Sopenharmony_cistatic u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task, 3162306a36Sopenharmony_ci cseq_idle_loop, lseq_idle_loop; 3262306a36Sopenharmony_cistatic const u8 *cseq_code, *lseq_code; 3362306a36Sopenharmony_cistatic u32 cseq_code_size, lseq_code_size; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic u16 first_scb_site_no = 0xFFFF; 3662306a36Sopenharmony_cistatic u16 last_scb_site_no; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* ---------- Pause/Unpause CSEQ/LSEQ ---------- */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/** 4162306a36Sopenharmony_ci * asd_pause_cseq - pause the central sequencer 4262306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * Return 0 on success, negative on failure. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistatic int asd_pause_cseq(struct asd_ha_struct *asd_ha) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci int count = PAUSE_TRIES; 4962306a36Sopenharmony_ci u32 arp2ctl; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 5262306a36Sopenharmony_ci if (arp2ctl & PAUSED) 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE); 5662306a36Sopenharmony_ci do { 5762306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 5862306a36Sopenharmony_ci if (arp2ctl & PAUSED) 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci udelay(PAUSE_DELAY); 6162306a36Sopenharmony_ci } while (--count > 0); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci ASD_DPRINTK("couldn't pause CSEQ\n"); 6462306a36Sopenharmony_ci return -1; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/** 6862306a36Sopenharmony_ci * asd_unpause_cseq - unpause the central sequencer. 6962306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure. 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Return 0 on success, negative on error. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic int asd_unpause_cseq(struct asd_ha_struct *asd_ha) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci u32 arp2ctl; 7662306a36Sopenharmony_ci int count = PAUSE_TRIES; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 7962306a36Sopenharmony_ci if (!(arp2ctl & PAUSED)) 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE); 8362306a36Sopenharmony_ci do { 8462306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 8562306a36Sopenharmony_ci if (!(arp2ctl & PAUSED)) 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci udelay(PAUSE_DELAY); 8862306a36Sopenharmony_ci } while (--count > 0); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ASD_DPRINTK("couldn't unpause the CSEQ\n"); 9162306a36Sopenharmony_ci return -1; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * asd_seq_pause_lseq - pause a link sequencer 9662306a36Sopenharmony_ci * @asd_ha: pointer to a host adapter structure 9762306a36Sopenharmony_ci * @lseq: link sequencer of interest 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * Return 0 on success, negative on error. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_cistatic int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci u32 arp2ctl; 10462306a36Sopenharmony_ci int count = PAUSE_TRIES; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 10762306a36Sopenharmony_ci if (arp2ctl & PAUSED) 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE); 11162306a36Sopenharmony_ci do { 11262306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 11362306a36Sopenharmony_ci if (arp2ctl & PAUSED) 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci udelay(PAUSE_DELAY); 11662306a36Sopenharmony_ci } while (--count > 0); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq); 11962306a36Sopenharmony_ci return -1; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/** 12362306a36Sopenharmony_ci * asd_pause_lseq - pause the link sequencer(s) 12462306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 12562306a36Sopenharmony_ci * @lseq_mask: mask of link sequencers of interest 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * Return 0 on success, negative on failure. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cistatic int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci int lseq; 13262306a36Sopenharmony_ci int err = 0; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci for_each_sequencer(lseq_mask, lseq_mask, lseq) { 13562306a36Sopenharmony_ci err = asd_seq_pause_lseq(asd_ha, lseq); 13662306a36Sopenharmony_ci if (err) 13762306a36Sopenharmony_ci return err; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/** 14462306a36Sopenharmony_ci * asd_seq_unpause_lseq - unpause a link sequencer 14562306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 14662306a36Sopenharmony_ci * @lseq: link sequencer of interest 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * Return 0 on success, negative on error. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_cistatic int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci u32 arp2ctl; 15362306a36Sopenharmony_ci int count = PAUSE_TRIES; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 15662306a36Sopenharmony_ci if (!(arp2ctl & PAUSED)) 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE); 16062306a36Sopenharmony_ci do { 16162306a36Sopenharmony_ci arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 16262306a36Sopenharmony_ci if (!(arp2ctl & PAUSED)) 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci udelay(PAUSE_DELAY); 16562306a36Sopenharmony_ci } while (--count > 0); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq); 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* ---------- Downloading CSEQ/LSEQ microcode ---------- */ 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog, 17562306a36Sopenharmony_ci u32 size) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci u32 addr = CSEQ_RAM_REG_BASE_ADR; 17862306a36Sopenharmony_ci const u32 *prog = (u32 *) _prog; 17962306a36Sopenharmony_ci u32 i; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci for (i = 0; i < size; i += 4, prog++, addr += 4) { 18262306a36Sopenharmony_ci u32 val = asd_read_reg_dword(asd_ha, addr); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (le32_to_cpu(*prog) != val) { 18562306a36Sopenharmony_ci asd_printk("%s: cseq verify failed at %u " 18662306a36Sopenharmony_ci "read:0x%x, wanted:0x%x\n", 18762306a36Sopenharmony_ci pci_name(asd_ha->pcidev), 18862306a36Sopenharmony_ci i, val, le32_to_cpu(*prog)); 18962306a36Sopenharmony_ci return -1; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci ASD_DPRINTK("verified %d bytes, passed\n", size); 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * asd_verify_lseq - verify the microcode of a link sequencer 19862306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 19962306a36Sopenharmony_ci * @_prog: pointer to the microcode 20062306a36Sopenharmony_ci * @size: size of the microcode in bytes 20162306a36Sopenharmony_ci * @lseq: link sequencer of interest 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * The link sequencer code is accessed in 4 KB pages, which are selected 20462306a36Sopenharmony_ci * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register. 20562306a36Sopenharmony_ci * The 10 KB LSEQm instruction code is mapped, page at a time, at 20662306a36Sopenharmony_ci * LmSEQRAM address. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog, 20962306a36Sopenharmony_ci u32 size, int lseq) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci#define LSEQ_CODEPAGE_SIZE 4096 21262306a36Sopenharmony_ci int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE; 21362306a36Sopenharmony_ci u32 page; 21462306a36Sopenharmony_ci const u32 *prog = (u32 *) _prog; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci for (page = 0; page < pages; page++) { 21762306a36Sopenharmony_ci u32 i; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq), 22062306a36Sopenharmony_ci page << LmRAMPAGE_LSHIFT); 22162306a36Sopenharmony_ci for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE; 22262306a36Sopenharmony_ci i += 4, prog++, size-=4) { 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (le32_to_cpu(*prog) != val) { 22762306a36Sopenharmony_ci asd_printk("%s: LSEQ%d verify failed " 22862306a36Sopenharmony_ci "page:%d, offs:%d\n", 22962306a36Sopenharmony_ci pci_name(asd_ha->pcidev), 23062306a36Sopenharmony_ci lseq, page, i); 23162306a36Sopenharmony_ci return -1; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq, 23662306a36Sopenharmony_ci (int)((u8 *)prog-_prog)); 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/** 24162306a36Sopenharmony_ci * asd_verify_seq -- verify CSEQ/LSEQ microcode 24262306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 24362306a36Sopenharmony_ci * @prog: pointer to microcode 24462306a36Sopenharmony_ci * @size: size of the microcode 24562306a36Sopenharmony_ci * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * Return 0 if microcode is correct, negative on mismatch. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistatic int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog, 25062306a36Sopenharmony_ci u32 size, u8 lseq_mask) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci if (lseq_mask == 0) 25362306a36Sopenharmony_ci return asd_verify_cseq(asd_ha, prog, size); 25462306a36Sopenharmony_ci else { 25562306a36Sopenharmony_ci int lseq, err; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for_each_sequencer(lseq_mask, lseq_mask, lseq) { 25862306a36Sopenharmony_ci err = asd_verify_lseq(asd_ha, prog, size, lseq); 25962306a36Sopenharmony_ci if (err) 26062306a36Sopenharmony_ci return err; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci#define ASD_DMA_MODE_DOWNLOAD 26762306a36Sopenharmony_ci#ifdef ASD_DMA_MODE_DOWNLOAD 26862306a36Sopenharmony_ci/* This is the size of the CSEQ Mapped instruction page */ 26962306a36Sopenharmony_ci#define MAX_DMA_OVLY_COUNT ((1U << 14)-1) 27062306a36Sopenharmony_cistatic int asd_download_seq(struct asd_ha_struct *asd_ha, 27162306a36Sopenharmony_ci const u8 * const prog, u32 size, u8 lseq_mask) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci u32 comstaten; 27462306a36Sopenharmony_ci u32 reg; 27562306a36Sopenharmony_ci int page; 27662306a36Sopenharmony_ci const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT; 27762306a36Sopenharmony_ci struct asd_dma_tok *token; 27862306a36Sopenharmony_ci int err = 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (size % 4) { 28162306a36Sopenharmony_ci asd_printk("sequencer program not multiple of 4\n"); 28262306a36Sopenharmony_ci return -1; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci asd_pause_cseq(asd_ha); 28662306a36Sopenharmony_ci asd_pause_lseq(asd_ha, 0xFF); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* save, disable and clear interrupts */ 28962306a36Sopenharmony_ci comstaten = asd_read_reg_dword(asd_ha, COMSTATEN); 29062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, COMSTATEN, 0); 29162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); 29462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL); 29762306a36Sopenharmony_ci if (!token) { 29862306a36Sopenharmony_ci asd_printk("out of memory for dma SEQ download\n"); 29962306a36Sopenharmony_ci err = -ENOMEM; 30062306a36Sopenharmony_ci goto out; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci ASD_DPRINTK("dma-ing %d bytes\n", size); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci for (page = 0; page < pages; page++) { 30562306a36Sopenharmony_ci int i; 30662306a36Sopenharmony_ci u32 left = min(size-page*MAX_DMA_OVLY_COUNT, 30762306a36Sopenharmony_ci (u32)MAX_DMA_OVLY_COUNT); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left); 31062306a36Sopenharmony_ci asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle); 31162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, OVLYDMACNT, left); 31262306a36Sopenharmony_ci reg = !page ? RESETOVLYDMA : 0; 31362306a36Sopenharmony_ci reg |= (STARTOVLYDMA | OVLYHALTERR); 31462306a36Sopenharmony_ci reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); 31562306a36Sopenharmony_ci /* Start DMA. */ 31662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci for (i = PAUSE_TRIES*100; i > 0; i--) { 31962306a36Sopenharmony_ci u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL); 32062306a36Sopenharmony_ci if (!(dmadone & OVLYDMAACT)) 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci udelay(PAUSE_DELAY); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci reg = asd_read_reg_dword(asd_ha, COMSTAT); 32762306a36Sopenharmony_ci if (!(reg & OVLYDMADONE) || (reg & OVLYERR) 32862306a36Sopenharmony_ci || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){ 32962306a36Sopenharmony_ci asd_printk("%s: error DMA-ing sequencer code\n", 33062306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 33162306a36Sopenharmony_ci err = -ENODEV; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci asd_free_coherent(asd_ha, token); 33562306a36Sopenharmony_ci out: 33662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, COMSTATEN, comstaten); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci#else /* ASD_DMA_MODE_DOWNLOAD */ 34162306a36Sopenharmony_cistatic int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog, 34262306a36Sopenharmony_ci u32 size, u8 lseq_mask) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci int i; 34562306a36Sopenharmony_ci u32 reg = 0; 34662306a36Sopenharmony_ci const u32 *prog = (u32 *) _prog; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (size % 4) { 34962306a36Sopenharmony_ci asd_printk("sequencer program not multiple of 4\n"); 35062306a36Sopenharmony_ci return -1; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci asd_pause_cseq(asd_ha); 35462306a36Sopenharmony_ci asd_pause_lseq(asd_ha, 0xFF); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); 35762306a36Sopenharmony_ci reg |= PIOCMODE; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, OVLYDMACNT, size); 36062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n", 36362306a36Sopenharmony_ci lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : ""); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci for (i = 0; i < size; i += 4, prog++) 36662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, SPIODATA, *prog); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci reg = (reg & ~PIOCMODE) | OVLYHALTERR; 36962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return asd_verify_seq(asd_ha, _prog, size, lseq_mask); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci#endif /* ASD_DMA_MODE_DOWNLOAD */ 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/** 37662306a36Sopenharmony_ci * asd_seq_download_seqs - download the sequencer microcode 37762306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * Download the central and link sequencer microcode. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_cistatic int asd_seq_download_seqs(struct asd_ha_struct *asd_ha) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci int err; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (!asd_ha->hw_prof.enabled_phys) { 38662306a36Sopenharmony_ci asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev)); 38762306a36Sopenharmony_ci return -ENODEV; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Download the CSEQ */ 39162306a36Sopenharmony_ci ASD_DPRINTK("downloading CSEQ...\n"); 39262306a36Sopenharmony_ci err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0); 39362306a36Sopenharmony_ci if (err) { 39462306a36Sopenharmony_ci asd_printk("CSEQ download failed:%d\n", err); 39562306a36Sopenharmony_ci return err; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Download the Link Sequencers code. All of the Link Sequencers 39962306a36Sopenharmony_ci * microcode can be downloaded at the same time. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci ASD_DPRINTK("downloading LSEQs...\n"); 40262306a36Sopenharmony_ci err = asd_download_seq(asd_ha, lseq_code, lseq_code_size, 40362306a36Sopenharmony_ci asd_ha->hw_prof.enabled_phys); 40462306a36Sopenharmony_ci if (err) { 40562306a36Sopenharmony_ci /* Try it one at a time */ 40662306a36Sopenharmony_ci u8 lseq; 40762306a36Sopenharmony_ci u8 lseq_mask = asd_ha->hw_prof.enabled_phys; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci for_each_sequencer(lseq_mask, lseq_mask, lseq) { 41062306a36Sopenharmony_ci err = asd_download_seq(asd_ha, lseq_code, 41162306a36Sopenharmony_ci lseq_code_size, 1<<lseq); 41262306a36Sopenharmony_ci if (err) 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci if (err) 41762306a36Sopenharmony_ci asd_printk("LSEQs download failed:%d\n", err); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return err; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/* ---------- Initializing the chip, chip memory, etc. ---------- */ 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci/** 42562306a36Sopenharmony_ci * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7 42662306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_cistatic void asd_init_cseq_mip(struct asd_ha_struct *asd_ha) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci /* CSEQ Mode Independent, page 4 setup. */ 43162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF); 43262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF); 43362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF); 43462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF); 43562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF); 43662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF); 43762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF); 43862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF); 43962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF); 44062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF); 44162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_REG0, 0); 44262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_REG1, 0); 44362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_REG2, 0); 44462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0); 44562306a36Sopenharmony_ci { 44662306a36Sopenharmony_ci u8 con = asd_read_reg_byte(asd_ha, CCONEXIST); 44762306a36Sopenharmony_ci u8 val = hweight8(con); 44862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* CSEQ Mode independent, page 5 setup. */ 45362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0); 45462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0); 45562306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0); 45662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0); 45762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF); 45862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF); 45962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0); 46062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0); 46162306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0); 46262306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* CSEQ Mode independent, page 6 setup. */ 46562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0); 46662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0); 46762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0); 46862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0); 46962306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0); 47062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0); 47162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0); 47262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF); 47362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF); 47462306a36Sopenharmony_ci /* Calculate the free scb mask. */ 47562306a36Sopenharmony_ci { 47662306a36Sopenharmony_ci u16 cmdctx = asd_get_cmdctx_size(asd_ha); 47762306a36Sopenharmony_ci cmdctx = (~((cmdctx/128)-1)) >> 8; 47862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD, 48162306a36Sopenharmony_ci first_scb_site_no); 48262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL, 48362306a36Sopenharmony_ci last_scb_site_no); 48462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF); 48562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* CSEQ Mode independent, page 7 setup. */ 48862306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0); 48962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0); 49062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0); 49162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0); 49262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF); 49362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF); 49462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0); 49562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0); 49662306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0); 49762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0); 49862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0); 49962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci/** 50362306a36Sopenharmony_ci * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages 50462306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_cistatic void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci int i; 50962306a36Sopenharmony_ci int moffs; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci moffs = CSEQ_PAGE_SIZE * 2; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* CSEQ Mode dependent, modes 0-7, page 0 setup. */ 51462306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 51562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0); 51662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0); 51762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF); 51862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF); 51962306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */ 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* CSEQ Mode dependent, mode 8, page 0 setup. */ 52562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF); 52662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0); 52762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0); 52862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0); 52962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0); 53062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0); 53162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0); 53262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0); 53362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0); 53462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0); 53562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0); 53662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0); 53762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE, 53862306a36Sopenharmony_ci (u16)last_scb_site_no+1); 53962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE, 54062306a36Sopenharmony_ci (u16)asd_ha->hw_prof.max_ddbs); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* CSEQ Mode dependent, mode 8, page 1 setup. */ 54362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0); 54462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0); 54562306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0); 54662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* CSEQ Mode dependent, mode 8, page 2 setup. */ 54962306a36Sopenharmony_ci /* Tell the sequencer the bus address of the first SCB. */ 55062306a36Sopenharmony_ci asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER, 55162306a36Sopenharmony_ci asd_ha->seq.next_scb.dma_handle); 55262306a36Sopenharmony_ci ASD_DPRINTK("First SCB dma_handle: 0x%llx\n", 55362306a36Sopenharmony_ci (unsigned long long)asd_ha->seq.next_scb.dma_handle); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* Tell the sequencer the first Done List entry address. */ 55662306a36Sopenharmony_ci asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE, 55762306a36Sopenharmony_ci asd_ha->seq.actual_dl->dma_handle); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* Initialize the Q_DONE_POINTER with the least significant 56062306a36Sopenharmony_ci * 4 bytes of the first Done List address. */ 56162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER, 56262306a36Sopenharmony_ci ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle)); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */ 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/** 57062306a36Sopenharmony_ci * asd_init_cseq_scratch -- setup and init CSEQ 57162306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * Setup and initialize Central sequencers. Initialize the mode 57462306a36Sopenharmony_ci * independent and dependent scratch page to the default settings. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_cistatic void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci asd_init_cseq_mip(asd_ha); 57962306a36Sopenharmony_ci asd_init_cseq_mdp(asd_ha); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci/** 58362306a36Sopenharmony_ci * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3 58462306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 58562306a36Sopenharmony_ci * @lseq: link sequencer 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_cistatic void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci int i; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* LSEQ Mode independent page 0 setup. */ 59262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF); 59362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF); 59462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq); 59562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq), 59662306a36Sopenharmony_ci ASD_NOTIFY_ENABLE_SPINUP); 59762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000); 59862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0); 59962306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0); 60062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0); 60162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0); 60262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0); 60362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0); 60462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0); 60562306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* LSEQ Mode independent page 1 setup. */ 60862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF); 60962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF); 61062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF); 61162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF); 61262306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0); 61362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0); 61462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0); 61562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0); 61662306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0); 61762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0); 61862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0); 61962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0); 62062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0); 62162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* LSEQ Mode Independent page 2 setup. */ 62462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF); 62562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF); 62662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF); 62762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF); 62862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0); 62962306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0); 63062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0); 63162306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0); 63262306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0); 63362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0); 63462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0); 63562306a36Sopenharmony_ci for (i = 0; i < 12; i += 4) 63662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* LSEQ Mode Independent page 3 setup. */ 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Device present timer timeout */ 64162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq), 64262306a36Sopenharmony_ci ASD_DEV_PRESENT_TIMEOUT); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* SATA interlock timer disabled */ 64562306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq), 64662306a36Sopenharmony_ci ASD_SATA_INTERLOCK_TIMEOUT); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* STP shutdown timer timeout constant, IGNORED by the sequencer, 64962306a36Sopenharmony_ci * always 0. */ 65062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq), 65162306a36Sopenharmony_ci ASD_STP_SHUTDOWN_TIMEOUT); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq), 65462306a36Sopenharmony_ci ASD_SRST_ASSERT_TIMEOUT); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq), 65762306a36Sopenharmony_ci ASD_RCV_FIS_TIMEOUT); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq), 66062306a36Sopenharmony_ci ASD_ONE_MILLISEC_TIMEOUT); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* COM_INIT timer */ 66362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq), 66462306a36Sopenharmony_ci ASD_TEN_MILLISEC_TIMEOUT); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq), 66762306a36Sopenharmony_ci ASD_SMP_RCV_TIMEOUT); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/** 67162306a36Sopenharmony_ci * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages. 67262306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 67362306a36Sopenharmony_ci * @lseq: link sequencer 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_cistatic void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci int i; 67862306a36Sopenharmony_ci u32 moffs; 67962306a36Sopenharmony_ci u16 ret_addr[] = { 68062306a36Sopenharmony_ci 0xFFFF, /* mode 0 */ 68162306a36Sopenharmony_ci 0xFFFF, /* mode 1 */ 68262306a36Sopenharmony_ci mode2_task, /* mode 2 */ 68362306a36Sopenharmony_ci 0, 68462306a36Sopenharmony_ci 0xFFFF, /* mode 4/5 */ 68562306a36Sopenharmony_ci 0xFFFF, /* mode 4/5 */ 68662306a36Sopenharmony_ci }; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * Mode 0,1,2 and 4/5 have common field on page 0 for the first 69062306a36Sopenharmony_ci * 14 bytes. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 69362306a36Sopenharmony_ci moffs = i * LSEQ_MODE_SCRATCH_SIZE; 69462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs, 69562306a36Sopenharmony_ci ret_addr[i]); 69662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0); 69762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0); 69862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF); 69962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF); 70062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0); 70162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0); 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci /* 70462306a36Sopenharmony_ci * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, 70762306a36Sopenharmony_ci LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 70862306a36Sopenharmony_ci ret_addr[5]); 70962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, 71062306a36Sopenharmony_ci LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); 71162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, 71262306a36Sopenharmony_ci LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); 71362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, 71462306a36Sopenharmony_ci LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); 71562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, 71662306a36Sopenharmony_ci LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); 71762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, 71862306a36Sopenharmony_ci LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); 71962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, 72062306a36Sopenharmony_ci LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* LSEQ Mode dependent 0, page 0 setup. */ 72362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq), 72462306a36Sopenharmony_ci (u16)asd_ha->hw_prof.max_ddbs); 72562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0); 72662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0); 72762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq), 72862306a36Sopenharmony_ci (u16)last_scb_site_no+1); 72962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq), 73062306a36Sopenharmony_ci (u16) ((LmM0INTEN_MASK & 0xFFFF0000) >> 16)); 73162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2, 73262306a36Sopenharmony_ci (u16) LmM0INTEN_MASK & 0xFFFF); 73362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0); 73462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0); 73562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0); 73662306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0); 73762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* LSEQ mode dependent, mode 1, page 0 setup. */ 74062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF); 74162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0); 74262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0); 74362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0); 74462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0); 74562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0); 74662306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0); 74762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* LSEQ Mode dependent mode 2, page 0 setup */ 75062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0); 75162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0); 75262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0); 75362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0); 75462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0); 75562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* LSEQ Mode dependent, mode 4/5, page 0 setup. */ 75862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0); 75962306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0); 76062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF); 76162306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0); 76262306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0); 76362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0); 76462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0); 76562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0); 76662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0); 76762306a36Sopenharmony_ci /* 76862306a36Sopenharmony_ci * Set the desired interval between transmissions of the NOTIFY 76962306a36Sopenharmony_ci * (ENABLE SPINUP) primitive. Must be initialized to val - 1. 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq), 77262306a36Sopenharmony_ci ASD_NOTIFY_TIMEOUT - 1); 77362306a36Sopenharmony_ci /* No delay for the first NOTIFY to be sent to the attached target. */ 77462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), 77562306a36Sopenharmony_ci ASD_NOTIFY_DOWN_COUNT); 77662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(lseq), 77762306a36Sopenharmony_ci ASD_NOTIFY_DOWN_COUNT); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ 78062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 78162306a36Sopenharmony_ci int j; 78262306a36Sopenharmony_ci /* Start from Page 1 of Mode 0 and 1. */ 78362306a36Sopenharmony_ci moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE; 78462306a36Sopenharmony_ci /* All the fields of page 1 can be initialized to 0. */ 78562306a36Sopenharmony_ci for (j = 0; j < LSEQ_PAGE_SIZE; j += 4) 78662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* LSEQ Mode dependent, mode 2, page 1 setup. */ 79062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0); 79162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0); 79262306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* LSEQ Mode dependent, mode 4/5, page 1. */ 79562306a36Sopenharmony_ci for (i = 0; i < LSEQ_PAGE_SIZE; i+=4) 79662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0); 79762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF); 79862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF); 79962306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF); 80062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF); 80162306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF); 80262306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF); 80362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF); 80462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* LSEQ Mode dependent, mode 0, page 2 setup. */ 80762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0); 80862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0); 80962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0); 81062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0); 81162306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* LSEQ Mode Dependent 1, page 2 setup. */ 81462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0); 81562306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0); 81662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0); 81762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0); 81862306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* LSEQ Mode Dependent 2, page 2 setup. */ 82162306a36Sopenharmony_ci /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer, 82262306a36Sopenharmony_ci * i.e. always 0. */ 82362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0); 82462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0); 82562306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0); 82662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0); 82762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0); 82862306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* LSEQ Mode Dependent 4/5, page 2 setup. */ 83162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0); 83262306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0); 83362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0); 83462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci/** 83862306a36Sopenharmony_ci * asd_init_lseq_scratch -- setup and init link sequencers 83962306a36Sopenharmony_ci * @asd_ha: pointer to host adapter struct 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_cistatic void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci u8 lseq; 84462306a36Sopenharmony_ci u8 lseq_mask; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci lseq_mask = asd_ha->hw_prof.enabled_phys; 84762306a36Sopenharmony_ci for_each_sequencer(lseq_mask, lseq_mask, lseq) { 84862306a36Sopenharmony_ci asd_init_lseq_mip(asd_ha, lseq); 84962306a36Sopenharmony_ci asd_init_lseq_mdp(asd_ha, lseq); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci/** 85462306a36Sopenharmony_ci * asd_init_scb_sites -- initialize sequencer SCB sites (memory). 85562306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 85662306a36Sopenharmony_ci * 85762306a36Sopenharmony_ci * This should be done before initializing common CSEQ and LSEQ 85862306a36Sopenharmony_ci * scratch since those areas depend on some computed values here, 85962306a36Sopenharmony_ci * last_scb_site_no, etc. 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_cistatic void asd_init_scb_sites(struct asd_ha_struct *asd_ha) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci u16 site_no; 86462306a36Sopenharmony_ci u16 max_scbs = 0; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci for (site_no = asd_ha->hw_prof.max_scbs-1; 86762306a36Sopenharmony_ci site_no != (u16) -1; 86862306a36Sopenharmony_ci site_no--) { 86962306a36Sopenharmony_ci u16 i; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* Initialize all fields in the SCB site to 0. */ 87262306a36Sopenharmony_ci for (i = 0; i < ASD_SCB_SIZE; i += 4) 87362306a36Sopenharmony_ci asd_scbsite_write_dword(asd_ha, site_no, i, 0); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Initialize SCB Site Opcode field to invalid. */ 87662306a36Sopenharmony_ci asd_scbsite_write_byte(asd_ha, site_no, 87762306a36Sopenharmony_ci offsetof(struct scb_header, opcode), 87862306a36Sopenharmony_ci 0xFF); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* Initialize SCB Site Flags field to mean a response 88162306a36Sopenharmony_ci * frame has been received. This means inadvertent 88262306a36Sopenharmony_ci * frames received to be dropped. */ 88362306a36Sopenharmony_ci asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* Workaround needed by SEQ to fix a SATA issue is to exclude 88662306a36Sopenharmony_ci * certain SCB sites from the free list. */ 88762306a36Sopenharmony_ci if (!SCB_SITE_VALID(site_no)) 88862306a36Sopenharmony_ci continue; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (last_scb_site_no == 0) 89162306a36Sopenharmony_ci last_scb_site_no = site_no; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* For every SCB site, we need to initialize the 89462306a36Sopenharmony_ci * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS, 89562306a36Sopenharmony_ci * and SG Element Flag. */ 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* Q_NEXT field of the last SCB is invalidated. */ 89862306a36Sopenharmony_ci asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci first_scb_site_no = site_no; 90162306a36Sopenharmony_ci max_scbs++; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci asd_ha->hw_prof.max_scbs = max_scbs; 90462306a36Sopenharmony_ci ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs); 90562306a36Sopenharmony_ci ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no); 90662306a36Sopenharmony_ci ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/** 91062306a36Sopenharmony_ci * asd_init_cseq_cio - initialize CSEQ CIO registers 91162306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_cistatic void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci int i; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0); 91862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS); 91962306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0); 92062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0); 92162306a36Sopenharmony_ci asd_ha->seq.scbpro = 0; 92262306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, SCBPRO, 0); 92362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CSEQCON, 0); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* Initialize CSEQ Mode 11 Interrupt Vectors. 92662306a36Sopenharmony_ci * The addresses are 16 bit wide and in dword units. 92762306a36Sopenharmony_ci * The values of their macros are in byte units. 92862306a36Sopenharmony_ci * Thus we have to divide by 4. */ 92962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]); 93062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]); 93162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ 93462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Initialize CSEQ Scratch Page to 0x04. */ 93762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci /* Initialize CSEQ Mode[0-8] Dependent registers. */ 94062306a36Sopenharmony_ci /* Initialize Scratch Page to 0. */ 94162306a36Sopenharmony_ci for (i = 0; i < 9; i++) 94262306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* Reset the ARP2 Program Count. */ 94562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 94862306a36Sopenharmony_ci /* Initialize Mode n Link m Interrupt Enable. */ 94962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF); 95062306a36Sopenharmony_ci /* Initialize Mode n Request Mailbox. */ 95162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci/** 95662306a36Sopenharmony_ci * asd_init_lseq_cio -- initialize LmSEQ CIO registers 95762306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 95862306a36Sopenharmony_ci * @lseq: link sequencer 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_cistatic void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci u8 *sas_addr; 96362306a36Sopenharmony_ci int i; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ 96662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */ 97162306a36Sopenharmony_ci for (i = 0; i < 3; i++) 97262306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* Initialize Mode 5 SCRATCHPAGE to 0. */ 97562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0); 97862306a36Sopenharmony_ci /* Initialize Mode 0,1,2 and 5 Interrupt Enable and 97962306a36Sopenharmony_ci * Interrupt registers. */ 98062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK); 98162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF); 98262306a36Sopenharmony_ci /* Mode 1 */ 98362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK); 98462306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF); 98562306a36Sopenharmony_ci /* Mode 2 */ 98662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK); 98762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF); 98862306a36Sopenharmony_ci /* Mode 5 */ 98962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK); 99062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* Enable HW Timer status. */ 99362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* Enable Primitive Status 0 and 1. */ 99662306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK); 99762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* Enable Frame Error. */ 100062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK); 100162306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* Initialize Mode 0 Transfer Level to 512. */ 100462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512); 100562306a36Sopenharmony_ci /* Initialize Mode 1 Transfer Level to 256. */ 100662306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* Initialize Program Count. */ 100962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* Enable Blind SG Move. */ 101262306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48); 101362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq), 101462306a36Sopenharmony_ci ASD_SATA_INTERLOCK_TIMEOUT); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq)); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* Clear Primitive Status 0 and 1. */ 101962306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF); 102062306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* Clear HW Timer status. */ 102362306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* Clear DMA Errors for Mode 0 and 1. */ 102662306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF); 102762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* Clear SG DMA Errors for Mode 0 and 1. */ 103062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF); 103162306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* Clear Mode 0 Buffer Parity Error. */ 103462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* Clear Mode 0 Frame Error register. */ 103762306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* Reset LSEQ external interrupt arbiter. */ 104062306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* Set the Phy SAS for the LmSEQ WWN. */ 104362306a36Sopenharmony_ci sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr; 104462306a36Sopenharmony_ci for (i = 0; i < SAS_ADDR_SIZE; i++) 104562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */ 104862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* Set the Bus Inactivity Time Limit Timer. */ 105162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* Enable SATA Port Multiplier. */ 105462306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* Initialize Interrupt Vector[0-10] address in Mode 3. 105762306a36Sopenharmony_ci * See the comment on CSEQ_INT_* */ 105862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]); 105962306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]); 106062306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]); 106162306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]); 106262306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]); 106362306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]); 106462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]); 106562306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]); 106662306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]); 106762306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]); 106862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]); 106962306a36Sopenharmony_ci /* 107062306a36Sopenharmony_ci * Program the Link LED control, applicable only for 107162306a36Sopenharmony_ci * Chip Rev. B or later. 107262306a36Sopenharmony_ci */ 107362306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, LmCONTROL(lseq), 107462306a36Sopenharmony_ci (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms)); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci /* Set the Align Rate for SAS and STP mode. */ 107762306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT); 107862306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT); 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci/** 108362306a36Sopenharmony_ci * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox 108462306a36Sopenharmony_ci * @asd_ha: pointer to host adapter struct 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_cistatic void asd_post_init_cseq(struct asd_ha_struct *asd_ha) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci int i; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci for (i = 0; i < 8; i++) 109162306a36Sopenharmony_ci asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF); 109262306a36Sopenharmony_ci for (i = 0; i < 8; i++) 109362306a36Sopenharmony_ci asd_read_reg_dword(asd_ha, CMnRSPMBX(i)); 109462306a36Sopenharmony_ci /* Reset the external interrupt arbiter. */ 109562306a36Sopenharmony_ci asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL); 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci/** 109962306a36Sopenharmony_ci * asd_init_ddb_0 -- initialize DDB 0 110062306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 110162306a36Sopenharmony_ci * 110262306a36Sopenharmony_ci * Initialize DDB site 0 which is used internally by the sequencer. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_cistatic void asd_init_ddb_0(struct asd_ha_struct *asd_ha) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci int i; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci /* Zero out the DDB explicitly */ 110962306a36Sopenharmony_ci for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4) 111062306a36Sopenharmony_ci asd_ddbsite_write_dword(asd_ha, 0, i, 0); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 111362306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0); 111462306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 111562306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail), 111662306a36Sopenharmony_ci asd_ha->hw_prof.max_ddbs-1); 111762306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 111862306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0); 111962306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 112062306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF); 112162306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 112262306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF); 112362306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 112462306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0); 112562306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 112662306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0); 112762306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 112862306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0); 112962306a36Sopenharmony_ci asd_ddbsite_write_word(asd_ha, 0, 113062306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh), 113162306a36Sopenharmony_ci asd_ha->hw_prof.num_phys * 2); 113262306a36Sopenharmony_ci asd_ddbsite_write_byte(asd_ha, 0, 113362306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0); 113462306a36Sopenharmony_ci asd_ddbsite_write_byte(asd_ha, 0, 113562306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF); 113662306a36Sopenharmony_ci asd_ddbsite_write_byte(asd_ha, 0, 113762306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00); 113862306a36Sopenharmony_ci /* DDB 0 is reserved */ 113962306a36Sopenharmony_ci set_bit(0, asd_ha->hw_prof.ddb_bitmap); 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_cistatic void asd_seq_init_ddb_sites(struct asd_ha_struct *asd_ha) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci unsigned int i; 114562306a36Sopenharmony_ci unsigned int ddb_site; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci for (ddb_site = 0 ; ddb_site < ASD_MAX_DDBS; ddb_site++) 114862306a36Sopenharmony_ci for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) 114962306a36Sopenharmony_ci asd_ddbsite_write_dword(asd_ha, ddb_site, i, 0); 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci/** 115362306a36Sopenharmony_ci * asd_seq_setup_seqs -- setup and initialize central and link sequencers 115462306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 115562306a36Sopenharmony_ci */ 115662306a36Sopenharmony_cistatic void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci int lseq; 115962306a36Sopenharmony_ci u8 lseq_mask; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* Initialize DDB sites */ 116262306a36Sopenharmony_ci asd_seq_init_ddb_sites(asd_ha); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Initialize SCB sites. Done first to compute some values which 116562306a36Sopenharmony_ci * the rest of the init code depends on. */ 116662306a36Sopenharmony_ci asd_init_scb_sites(asd_ha); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci /* Initialize CSEQ Scratch RAM registers. */ 116962306a36Sopenharmony_ci asd_init_cseq_scratch(asd_ha); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci /* Initialize LmSEQ Scratch RAM registers. */ 117262306a36Sopenharmony_ci asd_init_lseq_scratch(asd_ha); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci /* Initialize CSEQ CIO registers. */ 117562306a36Sopenharmony_ci asd_init_cseq_cio(asd_ha); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci asd_init_ddb_0(asd_ha); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* Initialize LmSEQ CIO registers. */ 118062306a36Sopenharmony_ci lseq_mask = asd_ha->hw_prof.enabled_phys; 118162306a36Sopenharmony_ci for_each_sequencer(lseq_mask, lseq_mask, lseq) 118262306a36Sopenharmony_ci asd_init_lseq_cio(asd_ha, lseq); 118362306a36Sopenharmony_ci asd_post_init_cseq(asd_ha); 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci/** 118862306a36Sopenharmony_ci * asd_seq_start_cseq -- start the central sequencer, CSEQ 118962306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_cistatic int asd_seq_start_cseq(struct asd_ha_struct *asd_ha) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci /* Reset the ARP2 instruction to location zero. */ 119462306a36Sopenharmony_ci asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* Unpause the CSEQ */ 119762306a36Sopenharmony_ci return asd_unpause_cseq(asd_ha); 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci/** 120162306a36Sopenharmony_ci * asd_seq_start_lseq -- start a link sequencer 120262306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 120362306a36Sopenharmony_ci * @lseq: the link sequencer of interest 120462306a36Sopenharmony_ci */ 120562306a36Sopenharmony_cistatic int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci /* Reset the ARP2 instruction to location zero. */ 120862306a36Sopenharmony_ci asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* Unpause the LmSEQ */ 121162306a36Sopenharmony_ci return asd_seq_unpause_lseq(asd_ha, lseq); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ciint asd_release_firmware(void) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci release_firmware(sequencer_fw); 121762306a36Sopenharmony_ci return 0; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic int asd_request_firmware(struct asd_ha_struct *asd_ha) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci int err, i; 122362306a36Sopenharmony_ci struct sequencer_file_header header; 122462306a36Sopenharmony_ci const struct sequencer_file_header *hdr_ptr; 122562306a36Sopenharmony_ci u32 csum = 0; 122662306a36Sopenharmony_ci u16 *ptr_cseq_vecs, *ptr_lseq_vecs; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (sequencer_fw) 122962306a36Sopenharmony_ci /* already loaded */ 123062306a36Sopenharmony_ci return 0; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci err = request_firmware(&sequencer_fw, 123362306a36Sopenharmony_ci SAS_RAZOR_SEQUENCER_FW_FILE, 123462306a36Sopenharmony_ci &asd_ha->pcidev->dev); 123562306a36Sopenharmony_ci if (err) 123662306a36Sopenharmony_ci return err; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci hdr_ptr = (const struct sequencer_file_header *)sequencer_fw->data; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci header.csum = le32_to_cpu(hdr_ptr->csum); 124162306a36Sopenharmony_ci header.major = le32_to_cpu(hdr_ptr->major); 124262306a36Sopenharmony_ci header.minor = le32_to_cpu(hdr_ptr->minor); 124362306a36Sopenharmony_ci header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); 124462306a36Sopenharmony_ci header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); 124562306a36Sopenharmony_ci header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); 124662306a36Sopenharmony_ci header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size); 124762306a36Sopenharmony_ci header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset); 124862306a36Sopenharmony_ci header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size); 124962306a36Sopenharmony_ci header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset); 125062306a36Sopenharmony_ci header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size); 125162306a36Sopenharmony_ci header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task); 125262306a36Sopenharmony_ci header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop); 125362306a36Sopenharmony_ci header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci for (i = sizeof(header.csum); i < sequencer_fw->size; i++) 125662306a36Sopenharmony_ci csum += sequencer_fw->data[i]; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci if (csum != header.csum) { 125962306a36Sopenharmony_ci asd_printk("Firmware file checksum mismatch\n"); 126062306a36Sopenharmony_ci return -EINVAL; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (header.cseq_table_size != CSEQ_NUM_VECS || 126462306a36Sopenharmony_ci header.lseq_table_size != LSEQ_NUM_VECS) { 126562306a36Sopenharmony_ci asd_printk("Firmware file table size mismatch\n"); 126662306a36Sopenharmony_ci return -EINVAL; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci asd_printk("Found sequencer Firmware version %d.%d (%s)\n", 127062306a36Sopenharmony_ci header.major, header.minor, hdr_ptr->version); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (header.major != SAS_RAZOR_SEQUENCER_FW_MAJOR) { 127362306a36Sopenharmony_ci asd_printk("Firmware Major Version Mismatch;" 127462306a36Sopenharmony_ci "driver requires version %d.X", 127562306a36Sopenharmony_ci SAS_RAZOR_SEQUENCER_FW_MAJOR); 127662306a36Sopenharmony_ci return -EINVAL; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; 128062306a36Sopenharmony_ci ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; 128162306a36Sopenharmony_ci mode2_task = header.mode2_task; 128262306a36Sopenharmony_ci cseq_idle_loop = header.cseq_idle_loop; 128362306a36Sopenharmony_ci lseq_idle_loop = header.lseq_idle_loop; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci for (i = 0; i < CSEQ_NUM_VECS; i++) 128662306a36Sopenharmony_ci cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci for (i = 0; i < LSEQ_NUM_VECS; i++) 128962306a36Sopenharmony_ci lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci cseq_code = &sequencer_fw->data[header.cseq_code_offset]; 129262306a36Sopenharmony_ci cseq_code_size = header.cseq_code_size; 129362306a36Sopenharmony_ci lseq_code = &sequencer_fw->data[header.lseq_code_offset]; 129462306a36Sopenharmony_ci lseq_code_size = header.lseq_code_size; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci return 0; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ciint asd_init_seqs(struct asd_ha_struct *asd_ha) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci int err; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci err = asd_request_firmware(asd_ha); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (err) { 130662306a36Sopenharmony_ci asd_printk("Failed to load sequencer firmware file %s, error %d\n", 130762306a36Sopenharmony_ci SAS_RAZOR_SEQUENCER_FW_FILE, err); 130862306a36Sopenharmony_ci return err; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci err = asd_seq_download_seqs(asd_ha); 131262306a36Sopenharmony_ci if (err) { 131362306a36Sopenharmony_ci asd_printk("couldn't download sequencers for %s\n", 131462306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 131562306a36Sopenharmony_ci return err; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci asd_seq_setup_seqs(asd_ha); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci return 0; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ciint asd_start_seqs(struct asd_ha_struct *asd_ha) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci int err; 132662306a36Sopenharmony_ci u8 lseq_mask; 132762306a36Sopenharmony_ci int lseq; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci err = asd_seq_start_cseq(asd_ha); 133062306a36Sopenharmony_ci if (err) { 133162306a36Sopenharmony_ci asd_printk("couldn't start CSEQ for %s\n", 133262306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 133362306a36Sopenharmony_ci return err; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci lseq_mask = asd_ha->hw_prof.enabled_phys; 133762306a36Sopenharmony_ci for_each_sequencer(lseq_mask, lseq_mask, lseq) { 133862306a36Sopenharmony_ci err = asd_seq_start_lseq(asd_ha, lseq); 133962306a36Sopenharmony_ci if (err) { 134062306a36Sopenharmony_ci asd_printk("couldn't start LSEQ %d for %s\n", lseq, 134162306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 134262306a36Sopenharmony_ci return err; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci return 0; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci/** 135062306a36Sopenharmony_ci * asd_update_port_links -- update port_map_by_links and phy_is_up 135162306a36Sopenharmony_ci * @asd_ha: pointer to host adapter structure 135262306a36Sopenharmony_ci * @phy: pointer to the phy which has been added to a port 135362306a36Sopenharmony_ci * 135462306a36Sopenharmony_ci * 1) When a link reset has completed and we got BYTES DMAED with a 135562306a36Sopenharmony_ci * valid frame we call this function for that phy, to indicate that 135662306a36Sopenharmony_ci * the phy is up, i.e. we update the phy_is_up in DDB 0. The 135762306a36Sopenharmony_ci * sequencer checks phy_is_up when pending SCBs are to be sent, and 135862306a36Sopenharmony_ci * when an open address frame has been received. 135962306a36Sopenharmony_ci * 136062306a36Sopenharmony_ci * 2) When we know of ports, we call this function to update the map 136162306a36Sopenharmony_ci * of phys participaing in that port, i.e. we update the 136262306a36Sopenharmony_ci * port_map_by_links in DDB 0. When a HARD_RESET primitive has been 136362306a36Sopenharmony_ci * received, the sequencer disables all phys in that port. 136462306a36Sopenharmony_ci * port_map_by_links is also used as the conn_mask byte in the 136562306a36Sopenharmony_ci * initiator/target port DDB. 136662306a36Sopenharmony_ci */ 136762306a36Sopenharmony_civoid asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci const u8 phy_mask = (u8) phy->asd_port->phy_mask; 137062306a36Sopenharmony_ci u8 phy_is_up; 137162306a36Sopenharmony_ci u8 mask; 137262306a36Sopenharmony_ci int i, err; 137362306a36Sopenharmony_ci unsigned long flags; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); 137662306a36Sopenharmony_ci for_each_phy(phy_mask, mask, i) 137762306a36Sopenharmony_ci asd_ddbsite_write_byte(asd_ha, 0, 137862306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, 137962306a36Sopenharmony_ci port_map_by_links)+i,phy_mask); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci for (i = 0; i < 12; i++) { 138262306a36Sopenharmony_ci phy_is_up = asd_ddbsite_read_byte(asd_ha, 0, 138362306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, phy_is_up)); 138462306a36Sopenharmony_ci err = asd_ddbsite_update_byte(asd_ha, 0, 138562306a36Sopenharmony_ci offsetof(struct asd_ddb_seq_shared, phy_is_up), 138662306a36Sopenharmony_ci phy_is_up, 138762306a36Sopenharmony_ci phy_is_up | phy_mask); 138862306a36Sopenharmony_ci if (!err) 138962306a36Sopenharmony_ci break; 139062306a36Sopenharmony_ci else if (err == -EFAULT) { 139162306a36Sopenharmony_ci asd_printk("phy_is_up: parity error in DDB 0\n"); 139262306a36Sopenharmony_ci break; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (err) 139862306a36Sopenharmony_ci asd_printk("couldn't update DDB 0:error:%d\n", err); 139962306a36Sopenharmony_ci} 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ciMODULE_FIRMWARE(SAS_RAZOR_SEQUENCER_FW_FILE); 1402