123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) Marvell International Ltd. and its affiliates
- */
- #include <common.h>
- #include <i2c.h>
- #include <spl.h>
- #include <asm/io.h>
- #include <asm/arch/cpu.h>
- #include <asm/arch/soc.h>
- #include "ddr3_hw_training.h"
- #include "xor.h"
- #include "xor_regs.h"
- static void ddr3_flush_l1_line(u32 line);
- extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
- extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
- #if defined(MV88F78X60)
- extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
- #endif
- extern u32 pbs_dq_mapping[PUP_NUM_64BIT][DQ_NUM];
- #if defined(MV88F78X60) || defined(MV88F672X)
- /* PBS locked dq (per pup) */
- u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
- u32 pbs_locked_dm[MAX_PUP_NUM] = { 0 };
- u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
- int per_bit_data[MAX_PUP_NUM][DQ_NUM];
- #endif
- static u32 sdram_data[LEN_KILLER_PATTERN] __aligned(32) = { 0 };
- static struct crc_dma_desc dma_desc __aligned(32) = { 0 };
- #define XOR_TIMEOUT 0x8000000
- struct xor_channel_t {
- struct crc_dma_desc *desc;
- unsigned long desc_phys_addr;
- };
- #define XOR_CAUSE_DONE_MASK(chan) ((0x1 | 0x2) << (chan * 16))
- void xor_waiton_eng(int chan)
- {
- int timeout;
- timeout = 0;
- while (!(reg_read(XOR_CAUSE_REG(XOR_UNIT(chan))) &
- XOR_CAUSE_DONE_MASK(XOR_CHAN(chan)))) {
- if (timeout > XOR_TIMEOUT)
- goto timeout;
- timeout++;
- }
- timeout = 0;
- while (mv_xor_state_get(chan) != MV_IDLE) {
- if (timeout > XOR_TIMEOUT)
- goto timeout;
- timeout++;
- }
- /* Clear int */
- reg_write(XOR_CAUSE_REG(XOR_UNIT(chan)),
- ~(XOR_CAUSE_DONE_MASK(XOR_CHAN(chan))));
- timeout:
- return;
- }
- static int special_compare_pattern(u32 uj)
- {
- if ((uj == 30) || (uj == 31) || (uj == 61) || (uj == 62) ||
- (uj == 93) || (uj == 94) || (uj == 126) || (uj == 127))
- return 1;
- return 0;
- }
- /*
- * Compare code extracted as its used by multiple functions. This
- * reduces code-size and makes it easier to maintain it. Additionally
- * the code is not indented that much and therefore easier to read.
- */
- static void compare_pattern_v1(u32 uj, u32 *pup, u32 *pattern,
- u32 pup_groups, int debug_dqs)
- {
- u32 val;
- u32 uk;
- u32 var1;
- u32 var2;
- __maybe_unused u32 dq;
- if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0xFF)) {
- for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
- val = CMP_BYTE_SHIFT * uk;
- var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
- var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
- if (var1 != var2) {
- *pup |= (1 << (uk + (PUP_NUM_32BIT *
- (uj % pup_groups))));
- #ifdef MV_DEBUG_DQS
- if (!debug_dqs)
- continue;
- for (dq = 0; dq < DQ_NUM; dq++) {
- val = uk + (PUP_NUM_32BIT *
- (uj % pup_groups));
- if (((var1 >> dq) & 0x1) !=
- ((var2 >> dq) & 0x1))
- per_bit_data[val][dq] = 1;
- else
- per_bit_data[val][dq] = 0;
- }
- #endif
- }
- }
- }
- }
- static void compare_pattern_v2(u32 uj, u32 *pup, u32 *pattern)
- {
- u32 val;
- u32 uk;
- u32 var1;
- u32 var2;
- if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0x3)) {
- /* Found error */
- for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
- val = CMP_BYTE_SHIFT * uk;
- var1 = (sdram_data[uj] >> val) & CMP_BYTE_MASK;
- var2 = (pattern[uj] >> val) & CMP_BYTE_MASK;
- if (var1 != var2)
- *pup |= (1 << (uk % PUP_NUM_16BIT));
- }
- }
- }
- /*
- * Name: ddr3_sdram_compare
- * Desc: Execute compare per PUP
- * Args: unlock_pup Bit array of the unlock pups
- * new_locked_pup Output bit array of the pups with failed compare
- * pattern Pattern to compare
- * pattern_len Length of pattern (in bytes)
- * sdram_offset offset address to the SDRAM
- * write write to the SDRAM before read
- * mask compare pattern with mask;
- * mask_pattern Mask to compare pattern
- *
- * Notes:
- * Returns: MV_OK if success, other error code if fail.
- */
- int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
- u32 *new_locked_pup, u32 *pattern,
- u32 pattern_len, u32 sdram_offset, int write,
- int mask, u32 *mask_pattern,
- int special_compare)
- {
- u32 uj;
- __maybe_unused u32 pup_groups;
- __maybe_unused u32 dq;
- #if !defined(MV88F67XX)
- if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
- pup_groups = 2;
- else
- pup_groups = 1;
- #endif
- ddr3_reset_phy_read_fifo();
- /* Check if need to write to sdram before read */
- if (write == 1)
- ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
- ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
- /* Compare read result to write */
- for (uj = 0; uj < pattern_len; uj++) {
- if (special_compare && special_compare_pattern(uj))
- continue;
- #if defined(MV88F78X60) || defined(MV88F672X)
- compare_pattern_v1(uj, new_locked_pup, pattern, pup_groups, 1);
- #elif defined(MV88F67XX)
- compare_pattern_v2(uj, new_locked_pup, pattern);
- #endif
- }
- return MV_OK;
- }
- #if defined(MV88F78X60) || defined(MV88F672X)
- /*
- * Name: ddr3_sdram_dm_compare
- * Desc: Execute compare per PUP
- * Args: unlock_pup Bit array of the unlock pups
- * new_locked_pup Output bit array of the pups with failed compare
- * pattern Pattern to compare
- * pattern_len Length of pattern (in bytes)
- * sdram_offset offset address to the SDRAM
- * write write to the SDRAM before read
- * mask compare pattern with mask;
- * mask_pattern Mask to compare pattern
- *
- * Notes:
- * Returns: MV_OK if success, other error code if fail.
- */
- int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
- u32 *new_locked_pup, u32 *pattern,
- u32 sdram_offset)
- {
- u32 uj, uk, var1, var2, pup_groups;
- u32 val;
- u32 pup = 0;
- if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
- pup_groups = 2;
- else
- pup_groups = 1;
- ddr3_dram_sram_burst((u32)pattern, SDRAM_PBS_TX_OFFS,
- LEN_PBS_PATTERN);
- ddr3_dram_sram_burst(SDRAM_PBS_TX_OFFS, (u32)sdram_data,
- LEN_PBS_PATTERN);
- /* Validate the correctness of the results */
- for (uj = 0; uj < LEN_PBS_PATTERN; uj++)
- compare_pattern_v1(uj, &pup, pattern, pup_groups, 0);
- /* Test the DM Signals */
- *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10) = 0x12345678;
- *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14) = 0x12345678;
- sdram_data[0] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10);
- sdram_data[1] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14);
- for (uj = 0; uj < 2; uj++) {
- if (((sdram_data[uj]) != (pattern[uj])) &&
- (*new_locked_pup != 0xFF)) {
- for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
- val = CMP_BYTE_SHIFT * uk;
- var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
- var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
- if (var1 != var2) {
- *new_locked_pup |= (1 << (uk +
- (PUP_NUM_32BIT * (uj % pup_groups))));
- *new_locked_pup |= pup;
- }
- }
- }
- }
- return MV_OK;
- }
- /*
- * Name: ddr3_sdram_pbs_compare
- * Desc: Execute SRAM compare per PUP and DQ.
- * Args: pup_locked bit array of locked pups
- * is_tx Indicate whether Rx or Tx
- * pbs_pattern_idx Index of PBS pattern
- * pbs_curr_val The PBS value
- * pbs_lock_val The value to set to locked PBS
- * skew_array Global array to update with the compare results
- * ai_unlock_pup_dq_array bit array of the locked / unlocked pups per dq.
- * Notes:
- * Returns: MV_OK if success, other error code if fail.
- */
- int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked,
- int is_tx, u32 pbs_pattern_idx,
- u32 pbs_curr_val, u32 pbs_lock_val,
- u32 *skew_array, u8 *unlock_pup_dq_array,
- u32 ecc)
- {
- /* bit array failed dq per pup for current compare */
- u32 pbs_write_pup[DQ_NUM] = { 0 };
- u32 update_pup; /* pup as HW convention */
- u32 max_pup; /* maximal pup index */
- u32 pup_addr;
- u32 ui, dq, pup;
- int var1, var2;
- u32 sdram_offset, pup_groups, tmp_pup;
- u32 *pattern_ptr;
- u32 val;
- /* Choose pattern */
- switch (dram_info->ddr_width) {
- #if defined(MV88F672X)
- case 16:
- pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
- break;
- #endif
- case 32:
- pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
- break;
- #if defined(MV88F78X60)
- case 64:
- pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
- break;
- #endif
- default:
- return MV_FAIL;
- }
- max_pup = dram_info->num_of_std_pups;
- sdram_offset = SDRAM_PBS_I_OFFS + pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS;
- if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
- pup_groups = 2;
- else
- pup_groups = 1;
- ddr3_reset_phy_read_fifo();
- /* Check if need to write to sdram before read */
- if (is_tx == 1) {
- ddr3_dram_sram_burst((u32)pattern_ptr, sdram_offset,
- LEN_PBS_PATTERN);
- }
- ddr3_dram_sram_read(sdram_offset, (u32)sdram_data, LEN_PBS_PATTERN);
- /* Compare read result to write */
- for (ui = 0; ui < LEN_PBS_PATTERN; ui++) {
- if ((sdram_data[ui]) != (pattern_ptr[ui])) {
- /* found error */
- /* error in low pup group */
- for (pup = 0; pup < PUP_NUM_32BIT; pup++) {
- val = CMP_BYTE_SHIFT * pup;
- var1 = ((sdram_data[ui] >> val) &
- CMP_BYTE_MASK);
- var2 = ((pattern_ptr[ui] >> val) &
- CMP_BYTE_MASK);
- if (var1 != var2) {
- if (dram_info->ddr_width > 16) {
- tmp_pup = (pup + PUP_NUM_32BIT *
- (ui % pup_groups));
- } else {
- tmp_pup = (pup % PUP_NUM_16BIT);
- }
- update_pup = (1 << tmp_pup);
- if (ecc && (update_pup != 0x1))
- continue;
- /*
- * Pup is failed - Go over all DQs and
- * look for failures
- */
- for (dq = 0; dq < DQ_NUM; dq++) {
- val = tmp_pup * (1 - ecc) +
- ecc * ECC_PUP;
- if (((var1 >> dq) & 0x1) !=
- ((var2 >> dq) & 0x1)) {
- if (pbs_locked_dq[val][dq] == 1 &&
- pbs_locked_value[val][dq] != pbs_curr_val)
- continue;
- /*
- * Activate write to
- * update PBS to
- * pbs_lock_val
- */
- pbs_write_pup[dq] |=
- update_pup;
- /*
- * Update the
- * unlock_pup_dq_array
- */
- unlock_pup_dq_array[dq] &=
- ~update_pup;
- /*
- * Lock PBS value for
- * failed bits in
- * compare operation
- */
- skew_array[tmp_pup * DQ_NUM + dq] =
- pbs_curr_val;
- }
- }
- }
- }
- }
- }
- pup_addr = (is_tx == 1) ? PUP_PBS_TX : PUP_PBS_RX;
- /* Set last failed bits PBS to min / max pbs value */
- for (dq = 0; dq < DQ_NUM; dq++) {
- for (pup = 0; pup < max_pup; pup++) {
- if (pbs_write_pup[dq] & (1 << pup)) {
- val = pup * (1 - ecc) + ecc * ECC_PUP;
- if (pbs_locked_dq[val][dq] == 1 &&
- pbs_locked_value[val][dq] != pbs_curr_val)
- continue;
- /* Mark the dq as locked */
- pbs_locked_dq[val][dq] = 1;
- pbs_locked_value[val][dq] = pbs_curr_val;
- ddr3_write_pup_reg(pup_addr +
- pbs_dq_mapping[val][dq],
- CS0, val, 0, pbs_lock_val);
- }
- }
- }
- return MV_OK;
- }
- #endif
- /*
- * Name: ddr3_sdram_direct_compare
- * Desc: Execute compare per PUP without DMA (no burst mode)
- * Args: unlock_pup Bit array of the unlock pups
- * new_locked_pup Output bit array of the pups with failed compare
- * pattern Pattern to compare
- * pattern_len Length of pattern (in bytes)
- * sdram_offset offset address to the SDRAM
- * write write to the SDRAM before read
- * mask compare pattern with mask;
- * auiMaskPatter Mask to compare pattern
- *
- * Notes:
- * Returns: MV_OK if success, other error code if fail.
- */
- int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
- u32 *new_locked_pup, u32 *pattern,
- u32 pattern_len, u32 sdram_offset,
- int write, int mask, u32 *mask_pattern)
- {
- u32 uj, uk, pup_groups;
- u32 *sdram_addr; /* used to read from SDRAM */
- sdram_addr = (u32 *)sdram_offset;
- if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
- pup_groups = 2;
- else
- pup_groups = 1;
- /* Check if need to write before read */
- if (write == 1) {
- for (uk = 0; uk < pattern_len; uk++) {
- *sdram_addr = pattern[uk];
- sdram_addr++;
- }
- }
- sdram_addr = (u32 *)sdram_offset;
- for (uk = 0; uk < pattern_len; uk++) {
- sdram_data[uk] = *sdram_addr;
- sdram_addr++;
- }
- /* Compare read result to write */
- for (uj = 0; uj < pattern_len; uj++) {
- if (dram_info->ddr_width > 16) {
- compare_pattern_v1(uj, new_locked_pup, pattern,
- pup_groups, 0);
- } else {
- compare_pattern_v2(uj, new_locked_pup, pattern);
- }
- }
- return MV_OK;
- }
- /*
- * Name: ddr3_dram_sram_burst
- * Desc: Read from the SDRAM in burst of 64 bytes
- * Args: src
- * dst
- * Notes: Using the XOR mechanism
- * Returns: MV_OK if success, other error code if fail.
- */
- int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len)
- {
- u32 chan, byte_count, cs_num, byte;
- struct xor_channel_t channel;
- chan = 0;
- byte_count = len * 4;
- /* Wait for previous transfer completion */
- while (mv_xor_state_get(chan) != MV_IDLE)
- ;
- /* Build the channel descriptor */
- channel.desc = &dma_desc;
- /* Enable Address Override and set correct src and dst */
- if (src < SRAM_BASE) {
- /* src is DRAM CS, dst is SRAM */
- cs_num = (src / (1 + SDRAM_CS_SIZE));
- reg_write(XOR_ADDR_OVRD_REG(0, 0),
- ((cs_num << 1) | (1 << 0)));
- channel.desc->src_addr0 = (src % (1 + SDRAM_CS_SIZE));
- channel.desc->dst_addr = dst;
- } else {
- /* src is SRAM, dst is DRAM CS */
- cs_num = (dst / (1 + SDRAM_CS_SIZE));
- reg_write(XOR_ADDR_OVRD_REG(0, 0),
- ((cs_num << 25) | (1 << 24)));
- channel.desc->src_addr0 = (src);
- channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
- channel.desc->src_addr0 = src;
- channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
- }
- channel.desc->src_addr1 = 0;
- channel.desc->byte_cnt = byte_count;
- channel.desc->next_desc_ptr = 0;
- channel.desc->status = 1 << 31;
- channel.desc->desc_cmd = 0x0;
- channel.desc_phys_addr = (unsigned long)&dma_desc;
- ddr3_flush_l1_line((u32)&dma_desc);
- /* Issue the transfer */
- if (mv_xor_transfer(chan, MV_DMA, channel.desc_phys_addr) != MV_OK)
- return MV_FAIL;
- /* Wait for completion */
- xor_waiton_eng(chan);
- if (dst > SRAM_BASE) {
- for (byte = 0; byte < byte_count; byte += 0x20)
- cache_inv(dst + byte);
- }
- return MV_OK;
- }
- /*
- * Name: ddr3_flush_l1_line
- * Desc:
- * Args:
- * Notes:
- * Returns: MV_OK if success, other error code if fail.
- */
- static void ddr3_flush_l1_line(u32 line)
- {
- u32 reg;
- #if defined(MV88F672X)
- reg = 1;
- #else
- reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR) &
- (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
- #ifdef MV88F67XX
- reg = ~reg & (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
- #endif
- #endif
- if (reg) {
- /* V7 Arch mode */
- flush_l1_v7(line);
- flush_l1_v7(line + CACHE_LINE_SIZE);
- } else {
- /* V6 Arch mode */
- flush_l1_v6(line);
- flush_l1_v6(line + CACHE_LINE_SIZE);
- }
- }
- int ddr3_dram_sram_read(u32 src, u32 dst, u32 len)
- {
- u32 ui;
- u32 *dst_ptr, *src_ptr;
- dst_ptr = (u32 *)dst;
- src_ptr = (u32 *)src;
- for (ui = 0; ui < len; ui++) {
- *dst_ptr = *src_ptr;
- dst_ptr++;
- src_ptr++;
- }
- return MV_OK;
- }
- int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
- u32 *new_locked_pup, u32 *pattern,
- u32 pattern_len, u32 sdram_offset, int write,
- int mask, u32 *mask_pattern,
- int special_compare)
- {
- u32 uj, pup_groups;
- if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
- pup_groups = 2;
- else
- pup_groups = 1;
- ddr3_reset_phy_read_fifo();
- /* Check if need to write to sdram before read */
- if (write == 1)
- ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
- ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
- /* Compare read result to write */
- for (uj = 0; uj < pattern_len; uj++) {
- if (special_compare && special_compare_pattern(uj))
- continue;
- if (dram_info->ddr_width > 16) {
- compare_pattern_v1(uj, new_locked_pup, pattern,
- pup_groups, 1);
- } else {
- compare_pattern_v2(uj, new_locked_pup, pattern);
- }
- }
- return MV_OK;
- }
- void ddr3_reset_phy_read_fifo(void)
- {
- u32 reg;
- /* reset read FIFO */
- reg = reg_read(REG_DRAM_TRAINING_ADDR);
- /* Start Auto Read Leveling procedure */
- reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
- /* 0x15B0 - Training Register */
- reg_write(REG_DRAM_TRAINING_ADDR, reg);
- reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
- reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
- (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
- /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset */
- /* 0x15B8 - Training SW 2 Register */
- reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
- do {
- reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
- (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
- } while (reg); /* Wait for '0' */
- reg = reg_read(REG_DRAM_TRAINING_ADDR);
- /* Clear Auto Read Leveling procedure */
- reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
- /* 0x15B0 - Training Register */
- reg_write(REG_DRAM_TRAINING_ADDR, reg);
- }
|