12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472 |
- /*
- * Copyright (C) 2013, Intel Corporation
- * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
- *
- * Ported from Intel released Quark UEFI BIOS
- * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
- *
- * SPDX-License-Identifier: Intel
- */
- #include <common.h>
- #include <asm/arch/device.h>
- #include <asm/arch/mrc.h>
- #include <asm/arch/msg_port.h>
- #include <asm/arch/quark.h>
- #include "mrc_util.h"
- #include "hte.h"
- #include "smc.h"
- static const uint8_t vref_codes[64] = {
- /* lowest to highest */
- 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
- 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
- 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
- 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
- };
- void mrc_write_mask(u32 unit, u32 addr, u32 data, u32 mask)
- {
- msg_port_write(unit, addr,
- (msg_port_read(unit, addr) & ~(mask)) |
- ((data) & (mask)));
- }
- void mrc_alt_write_mask(u32 unit, u32 addr, u32 data, u32 mask)
- {
- msg_port_alt_write(unit, addr,
- (msg_port_alt_read(unit, addr) & ~(mask)) |
- ((data) & (mask)));
- }
- void mrc_post_code(uint8_t major, uint8_t minor)
- {
- /* send message to UART */
- DPF(D_INFO, "POST: 0x%01x%02x\n", major, minor);
- /* error check */
- if (major == 0xee)
- hang();
- }
- /* Delay number of nanoseconds */
- void delay_n(uint32_t ns)
- {
- /* 1000 MHz clock has 1ns period --> no conversion required */
- uint64_t final_tsc = rdtsc();
- final_tsc += ((get_tbclk_mhz() * ns) / 1000);
- while (rdtsc() < final_tsc)
- ;
- }
- /* Delay number of microseconds */
- void delay_u(uint32_t ms)
- {
- /* 64-bit math is not an option, just use loops */
- while (ms--)
- delay_n(1000);
- }
- /* Select Memory Manager as the source for PRI interface */
- void select_mem_mgr(void)
- {
- u32 dco;
- ENTERFN();
- dco = msg_port_read(MEM_CTLR, DCO);
- dco &= ~DCO_PMICTL;
- msg_port_write(MEM_CTLR, DCO, dco);
- LEAVEFN();
- }
- /* Select HTE as the source for PRI interface */
- void select_hte(void)
- {
- u32 dco;
- ENTERFN();
- dco = msg_port_read(MEM_CTLR, DCO);
- dco |= DCO_PMICTL;
- msg_port_write(MEM_CTLR, DCO, dco);
- LEAVEFN();
- }
- /*
- * Send DRAM command
- * data should be formated using DCMD_Xxxx macro or emrsXCommand structure
- */
- void dram_init_command(uint32_t data)
- {
- qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, data);
- qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG, 0);
- msg_port_setup(MSG_OP_DRAM_INIT, MEM_CTLR, 0);
- DPF(D_REGWR, "WR32 %03X %08X %08X\n", MEM_CTLR, 0, data);
- }
- /* Send DRAM wake command using special MCU side-band WAKE opcode */
- void dram_wake_command(void)
- {
- ENTERFN();
- msg_port_setup(MSG_OP_DRAM_WAKE, MEM_CTLR, 0);
- LEAVEFN();
- }
- void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane)
- {
- /* send message to UART */
- DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane);
- }
- /*
- * This function will program the RCVEN delays
- *
- * (currently doesn't comprehend rank)
- */
- void set_rcvn(uint8_t channel, uint8_t rank,
- uint8_t byte_lane, uint32_t pi_count)
- {
- uint32_t reg;
- uint32_t msk;
- uint32_t temp;
- ENTERFN();
- DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n",
- channel, rank, byte_lane, pi_count);
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
- * BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
- */
- reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- msk = (byte_lane & 1) ? 0xf00000 : 0xf00;
- temp = (byte_lane & 1) ? (pi_count / HALF_CLK) << 20 :
- (pi_count / HALF_CLK) << 8;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* Adjust PI_COUNT */
- pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
- * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
- */
- reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- msk = 0x3f000000;
- temp = pi_count << 24;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /*
- * DEADBAND
- * BL0/1 -> B01DBCTL1[08/11] (+1 select)
- * BL0/1 -> B01DBCTL1[02/05] (enable)
- */
- reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- msk = 0x00;
- temp = 0x00;
- /* enable */
- msk |= (byte_lane & 1) ? (1 << 5) : (1 << 2);
- if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
- temp |= msk;
- /* select */
- msk |= (byte_lane & 1) ? (1 << 11) : (1 << 8);
- if (pi_count < EARLY_DB)
- temp |= msk;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* error check */
- if (pi_count > 0x3f) {
- training_message(channel, rank, byte_lane);
- mrc_post_code(0xee, 0xe0);
- }
- LEAVEFN();
- }
- /*
- * This function will return the current RCVEN delay on the given
- * channel, rank, byte_lane as an absolute PI count.
- *
- * (currently doesn't comprehend rank)
- */
- uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane)
- {
- uint32_t reg;
- uint32_t temp;
- uint32_t pi_count;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
- * BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
- */
- reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= (byte_lane & 1) ? 20 : 8;
- temp &= 0xf;
- /* Adjust PI_COUNT */
- pi_count = temp * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
- * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
- */
- reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= 24;
- temp &= 0x3f;
- /* Adjust PI_COUNT */
- pi_count += temp;
- LEAVEFN();
- return pi_count;
- }
- /*
- * This function will program the RDQS delays based on an absolute
- * amount of PIs.
- *
- * (currently doesn't comprehend rank)
- */
- void set_rdqs(uint8_t channel, uint8_t rank,
- uint8_t byte_lane, uint32_t pi_count)
- {
- uint32_t reg;
- uint32_t msk;
- uint32_t temp;
- ENTERFN();
- DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n",
- channel, rank, byte_lane, pi_count);
- /*
- * PI (1/128 MCLK)
- * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
- * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
- */
- reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- msk = 0x7f;
- temp = pi_count << 0;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* error check (shouldn't go above 0x3F) */
- if (pi_count > 0x47) {
- training_message(channel, rank, byte_lane);
- mrc_post_code(0xee, 0xe1);
- }
- LEAVEFN();
- }
- /*
- * This function will return the current RDQS delay on the given
- * channel, rank, byte_lane as an absolute PI count.
- *
- * (currently doesn't comprehend rank)
- */
- uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane)
- {
- uint32_t reg;
- uint32_t temp;
- uint32_t pi_count;
- ENTERFN();
- /*
- * PI (1/128 MCLK)
- * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
- * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
- */
- reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- temp = msg_port_alt_read(DDRPHY, reg);
- /* Adjust PI_COUNT */
- pi_count = temp & 0x7f;
- LEAVEFN();
- return pi_count;
- }
- /*
- * This function will program the WDQS delays based on an absolute
- * amount of PIs.
- *
- * (currently doesn't comprehend rank)
- */
- void set_wdqs(uint8_t channel, uint8_t rank,
- uint8_t byte_lane, uint32_t pi_count)
- {
- uint32_t reg;
- uint32_t msk;
- uint32_t temp;
- ENTERFN();
- DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n",
- channel, rank, byte_lane, pi_count);
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
- * BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
- */
- reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- msk = (byte_lane & 1) ? 0xf0000 : 0xf0;
- temp = pi_count / HALF_CLK;
- temp <<= (byte_lane & 1) ? 16 : 4;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* Adjust PI_COUNT */
- pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
- * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
- */
- reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- msk = 0x3f0000;
- temp = pi_count << 16;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /*
- * DEADBAND
- * BL0/1 -> B01DBCTL1[07/10] (+1 select)
- * BL0/1 -> B01DBCTL1[01/04] (enable)
- */
- reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- msk = 0x00;
- temp = 0x00;
- /* enable */
- msk |= (byte_lane & 1) ? (1 << 4) : (1 << 1);
- if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
- temp |= msk;
- /* select */
- msk |= (byte_lane & 1) ? (1 << 10) : (1 << 7);
- if (pi_count < EARLY_DB)
- temp |= msk;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* error check */
- if (pi_count > 0x3f) {
- training_message(channel, rank, byte_lane);
- mrc_post_code(0xee, 0xe2);
- }
- LEAVEFN();
- }
- /*
- * This function will return the amount of WDQS delay on the given
- * channel, rank, byte_lane as an absolute PI count.
- *
- * (currently doesn't comprehend rank)
- */
- uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane)
- {
- uint32_t reg;
- uint32_t temp;
- uint32_t pi_count;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
- * BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
- */
- reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= (byte_lane & 1) ? 16 : 4;
- temp &= 0xf;
- /* Adjust PI_COUNT */
- pi_count = (temp * HALF_CLK);
- /*
- * PI (1/64 MCLK, 1 PIs)
- * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
- * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
- */
- reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= 16;
- temp &= 0x3f;
- /* Adjust PI_COUNT */
- pi_count += temp;
- LEAVEFN();
- return pi_count;
- }
- /*
- * This function will program the WDQ delays based on an absolute
- * number of PIs.
- *
- * (currently doesn't comprehend rank)
- */
- void set_wdq(uint8_t channel, uint8_t rank,
- uint8_t byte_lane, uint32_t pi_count)
- {
- uint32_t reg;
- uint32_t msk;
- uint32_t temp;
- ENTERFN();
- DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n",
- channel, rank, byte_lane, pi_count);
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
- * BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
- */
- reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- msk = (byte_lane & 1) ? 0xf000 : 0xf;
- temp = pi_count / HALF_CLK;
- temp <<= (byte_lane & 1) ? 12 : 0;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* Adjust PI_COUNT */
- pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
- * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
- */
- reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- msk = 0x3f00;
- temp = pi_count << 8;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /*
- * DEADBAND
- * BL0/1 -> B01DBCTL1[06/09] (+1 select)
- * BL0/1 -> B01DBCTL1[00/03] (enable)
- */
- reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- msk = 0x00;
- temp = 0x00;
- /* enable */
- msk |= (byte_lane & 1) ? (1 << 3) : (1 << 0);
- if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
- temp |= msk;
- /* select */
- msk |= (byte_lane & 1) ? (1 << 9) : (1 << 6);
- if (pi_count < EARLY_DB)
- temp |= msk;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* error check */
- if (pi_count > 0x3f) {
- training_message(channel, rank, byte_lane);
- mrc_post_code(0xee, 0xe3);
- }
- LEAVEFN();
- }
- /*
- * This function will return the amount of WDQ delay on the given
- * channel, rank, byte_lane as an absolute PI count.
- *
- * (currently doesn't comprehend rank)
- */
- uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane)
- {
- uint32_t reg;
- uint32_t temp;
- uint32_t pi_count;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
- * BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
- */
- reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= (byte_lane & 1) ? 12 : 0;
- temp &= 0xf;
- /* Adjust PI_COUNT */
- pi_count = temp * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
- * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
- */
- reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
- reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= 8;
- temp &= 0x3f;
- /* Adjust PI_COUNT */
- pi_count += temp;
- LEAVEFN();
- return pi_count;
- }
- /*
- * This function will program the WCMD delays based on an absolute
- * number of PIs.
- */
- void set_wcmd(uint8_t channel, uint32_t pi_count)
- {
- uint32_t reg;
- uint32_t msk;
- uint32_t temp;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * CMDPTRREG[11:08] (0x0-0xF)
- */
- reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
- msk = 0xf00;
- temp = pi_count / HALF_CLK;
- temp <<= 8;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* Adjust PI_COUNT */
- pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
- * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
- * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
- * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
- * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
- * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
- * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
- * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
- */
- reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
- msk = 0x3f3f3f3f;
- temp = (pi_count << 24) | (pi_count << 16) |
- (pi_count << 8) | (pi_count << 0);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- reg = CMDDLLPICODER0 + channel * DDRIOCCC_CH_OFFSET; /* PO */
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /*
- * DEADBAND
- * CMDCFGREG0[17] (+1 select)
- * CMDCFGREG0[16] (enable)
- */
- reg = CMDCFGREG0 + channel * DDRIOCCC_CH_OFFSET;
- msk = 0x00;
- temp = 0x00;
- /* enable */
- msk |= (1 << 16);
- if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
- temp |= msk;
- /* select */
- msk |= (1 << 17);
- if (pi_count < EARLY_DB)
- temp |= msk;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* error check */
- if (pi_count > 0x3f)
- mrc_post_code(0xee, 0xe4);
- LEAVEFN();
- }
- /*
- * This function will return the amount of WCMD delay on the given
- * channel as an absolute PI count.
- */
- uint32_t get_wcmd(uint8_t channel)
- {
- uint32_t reg;
- uint32_t temp;
- uint32_t pi_count;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * CMDPTRREG[11:08] (0x0-0xF)
- */
- reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= 8;
- temp &= 0xf;
- /* Adjust PI_COUNT */
- pi_count = temp * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
- * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
- * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
- * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
- * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
- * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
- * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
- * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
- */
- reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= 16;
- temp &= 0x3f;
- /* Adjust PI_COUNT */
- pi_count += temp;
- LEAVEFN();
- return pi_count;
- }
- /*
- * This function will program the WCLK delays based on an absolute
- * number of PIs.
- */
- void set_wclk(uint8_t channel, uint8_t rank, uint32_t pi_count)
- {
- uint32_t reg;
- uint32_t msk;
- uint32_t temp;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * CCPTRREG[15:12] -> CLK1 (0x0-0xF)
- * CCPTRREG[11:08] -> CLK0 (0x0-0xF)
- */
- reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
- msk = 0xff00;
- temp = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* Adjust PI_COUNT */
- pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
- * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
- */
- reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0;
- reg += (channel * DDRIOCCC_CH_OFFSET);
- msk = 0x3f3f00;
- temp = (pi_count << 16) | (pi_count << 8);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- reg = rank ? ECCB1DLLPICODER1 : ECCB1DLLPICODER1;
- reg += (channel * DDRIOCCC_CH_OFFSET);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- reg = rank ? ECCB1DLLPICODER2 : ECCB1DLLPICODER2;
- reg += (channel * DDRIOCCC_CH_OFFSET);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- reg = rank ? ECCB1DLLPICODER3 : ECCB1DLLPICODER3;
- reg += (channel * DDRIOCCC_CH_OFFSET);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /*
- * DEADBAND
- * CCCFGREG1[11:08] (+1 select)
- * CCCFGREG1[03:00] (enable)
- */
- reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
- msk = 0x00;
- temp = 0x00;
- /* enable */
- msk |= 0xf;
- if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
- temp |= msk;
- /* select */
- msk |= 0xf00;
- if (pi_count < EARLY_DB)
- temp |= msk;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* error check */
- if (pi_count > 0x3f)
- mrc_post_code(0xee, 0xe5);
- LEAVEFN();
- }
- /*
- * This function will return the amout of WCLK delay on the given
- * channel, rank as an absolute PI count.
- */
- uint32_t get_wclk(uint8_t channel, uint8_t rank)
- {
- uint32_t reg;
- uint32_t temp;
- uint32_t pi_count;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * CCPTRREG[15:12] -> CLK1 (0x0-0xF)
- * CCPTRREG[11:08] -> CLK0 (0x0-0xF)
- */
- reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= rank ? 12 : 8;
- temp &= 0xf;
- /* Adjust PI_COUNT */
- pi_count = temp * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
- * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
- */
- reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0;
- reg += (channel * DDRIOCCC_CH_OFFSET);
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= rank ? 16 : 8;
- temp &= 0x3f;
- pi_count += temp;
- LEAVEFN();
- return pi_count;
- }
- /*
- * This function will program the WCTL delays based on an absolute
- * number of PIs.
- *
- * (currently doesn't comprehend rank)
- */
- void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count)
- {
- uint32_t reg;
- uint32_t msk;
- uint32_t temp;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * CCPTRREG[31:28] (0x0-0xF)
- * CCPTRREG[27:24] (0x0-0xF)
- */
- reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
- msk = 0xff000000;
- temp = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* Adjust PI_COUNT */
- pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
- * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
- */
- reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
- msk = 0x3f000000;
- temp = (pi_count << 24);
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- reg = ECCB1DLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- reg = ECCB1DLLPICODER2 + channel * DDRIOCCC_CH_OFFSET;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- reg = ECCB1DLLPICODER3 + channel * DDRIOCCC_CH_OFFSET;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /*
- * DEADBAND
- * CCCFGREG1[13:12] (+1 select)
- * CCCFGREG1[05:04] (enable)
- */
- reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
- msk = 0x00;
- temp = 0x00;
- /* enable */
- msk |= 0x30;
- if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
- temp |= msk;
- /* select */
- msk |= 0x3000;
- if (pi_count < EARLY_DB)
- temp |= msk;
- mrc_alt_write_mask(DDRPHY, reg, temp, msk);
- /* error check */
- if (pi_count > 0x3f)
- mrc_post_code(0xee, 0xe6);
- LEAVEFN();
- }
- /*
- * This function will return the amount of WCTL delay on the given
- * channel, rank as an absolute PI count.
- *
- * (currently doesn't comprehend rank)
- */
- uint32_t get_wctl(uint8_t channel, uint8_t rank)
- {
- uint32_t reg;
- uint32_t temp;
- uint32_t pi_count;
- ENTERFN();
- /*
- * RDPTR (1/2 MCLK, 64 PIs)
- * CCPTRREG[31:28] (0x0-0xF)
- * CCPTRREG[27:24] (0x0-0xF)
- */
- reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= 24;
- temp &= 0xf;
- /* Adjust PI_COUNT */
- pi_count = temp * HALF_CLK;
- /*
- * PI (1/64 MCLK, 1 PIs)
- * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
- * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
- */
- reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
- temp = msg_port_alt_read(DDRPHY, reg);
- temp >>= 24;
- temp &= 0x3f;
- /* Adjust PI_COUNT */
- pi_count += temp;
- LEAVEFN();
- return pi_count;
- }
- /*
- * This function will program the internal Vref setting in a given
- * byte lane in a given channel.
- */
- void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting)
- {
- uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
- ENTERFN();
- DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n",
- channel, byte_lane, setting);
- mrc_alt_write_mask(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
- (byte_lane >> 1) * DDRIODQ_BL_OFFSET,
- vref_codes[setting] << 2, 0xfc);
- /*
- * need to wait ~300ns for Vref to settle
- * (check that this is necessary)
- */
- delay_n(300);
- /* ??? may need to clear pointers ??? */
- LEAVEFN();
- }
- /*
- * This function will return the internal Vref setting for the given
- * channel, byte_lane.
- */
- uint32_t get_vref(uint8_t channel, uint8_t byte_lane)
- {
- uint8_t j;
- uint32_t ret_val = sizeof(vref_codes) / 2;
- uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
- uint32_t temp;
- ENTERFN();
- temp = msg_port_alt_read(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
- (byte_lane >> 1) * DDRIODQ_BL_OFFSET);
- temp >>= 2;
- temp &= 0x3f;
- for (j = 0; j < sizeof(vref_codes); j++) {
- if (vref_codes[j] == temp) {
- ret_val = j;
- break;
- }
- }
- LEAVEFN();
- return ret_val;
- }
- /*
- * This function will return a 32-bit address in the desired
- * channel and rank.
- */
- uint32_t get_addr(uint8_t channel, uint8_t rank)
- {
- uint32_t offset = 32 * 1024 * 1024; /* 32MB */
- /* Begin product specific code */
- if (channel > 0) {
- DPF(D_ERROR, "ILLEGAL CHANNEL\n");
- DEAD_LOOP();
- }
- if (rank > 1) {
- DPF(D_ERROR, "ILLEGAL RANK\n");
- DEAD_LOOP();
- }
- /* use 256MB lowest density as per DRP == 0x0003 */
- offset += rank * (256 * 1024 * 1024);
- return offset;
- }
- /*
- * This function will sample the DQTRAINSTS registers in the given
- * channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'.
- *
- * It will return an encoded 32-bit date in which each bit corresponds to
- * the sampled value on the byte lane.
- */
- uint32_t sample_dqs(struct mrc_params *mrc_params, uint8_t channel,
- uint8_t rank, bool rcvn)
- {
- uint8_t j; /* just a counter */
- uint8_t bl; /* which BL in the module (always 2 per module) */
- uint8_t bl_grp; /* which BL module */
- /* byte lane divisor */
- uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
- uint32_t msk[2]; /* BLx in module */
- /* DQTRAINSTS register contents for each sample */
- uint32_t sampled_val[SAMPLE_SIZE];
- uint32_t num_0s; /* tracks the number of '0' samples */
- uint32_t num_1s; /* tracks the number of '1' samples */
- uint32_t ret_val = 0x00; /* assume all '0' samples */
- uint32_t address = get_addr(channel, rank);
- /* initialise msk[] */
- msk[0] = rcvn ? (1 << 1) : (1 << 9); /* BL0 */
- msk[1] = rcvn ? (1 << 0) : (1 << 8); /* BL1 */
- /* cycle through each byte lane group */
- for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++) {
- /* take SAMPLE_SIZE samples */
- for (j = 0; j < SAMPLE_SIZE; j++) {
- hte_mem_op(address, mrc_params->first_run,
- rcvn ? 0 : 1);
- mrc_params->first_run = 0;
- /*
- * record the contents of the proper
- * DQTRAINSTS register
- */
- sampled_val[j] = msg_port_alt_read(DDRPHY,
- DQTRAINSTS +
- bl_grp * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET);
- }
- /*
- * look for a majority value (SAMPLE_SIZE / 2) + 1
- * on the byte lane and set that value in the corresponding
- * ret_val bit
- */
- for (bl = 0; bl < 2; bl++) {
- num_0s = 0x00; /* reset '0' tracker for byte lane */
- num_1s = 0x00; /* reset '1' tracker for byte lane */
- for (j = 0; j < SAMPLE_SIZE; j++) {
- if (sampled_val[j] & msk[bl])
- num_1s++;
- else
- num_0s++;
- }
- if (num_1s > num_0s)
- ret_val |= (1 << (bl + bl_grp * 2));
- }
- }
- /*
- * "ret_val.0" contains the status of BL0
- * "ret_val.1" contains the status of BL1
- * "ret_val.2" contains the status of BL2
- * etc.
- */
- return ret_val;
- }
- /* This function will find the rising edge transition on RCVN or WDQS */
- void find_rising_edge(struct mrc_params *mrc_params, uint32_t delay[],
- uint8_t channel, uint8_t rank, bool rcvn)
- {
- bool all_edges_found; /* determines stop condition */
- bool direction[NUM_BYTE_LANES]; /* direction indicator */
- uint8_t sample; /* sample counter */
- uint8_t bl; /* byte lane counter */
- /* byte lane divisor */
- uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
- uint32_t sample_result[SAMPLE_CNT]; /* results of sample_dqs() */
- uint32_t temp;
- uint32_t transition_pattern;
- ENTERFN();
- /* select hte and request initial configuration */
- select_hte();
- mrc_params->first_run = 1;
- /* Take 3 sample points (T1,T2,T3) to obtain a transition pattern */
- for (sample = 0; sample < SAMPLE_CNT; sample++) {
- /* program the desired delays for sample */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- /* increase sample delay by 26 PI (0.2 CLK) */
- if (rcvn) {
- set_rcvn(channel, rank, bl,
- delay[bl] + sample * SAMPLE_DLY);
- } else {
- set_wdqs(channel, rank, bl,
- delay[bl] + sample * SAMPLE_DLY);
- }
- }
- /* take samples (Tsample_i) */
- sample_result[sample] = sample_dqs(mrc_params,
- channel, rank, rcvn);
- DPF(D_TRN,
- "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n",
- rcvn ? "RCVN" : "WDQS", channel, rank, sample,
- sample * SAMPLE_DLY, sample_result[sample]);
- }
- /*
- * This pattern will help determine where we landed and ultimately
- * how to place RCVEN/WDQS.
- */
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- /* build transition_pattern (MSB is 1st sample) */
- transition_pattern = 0;
- for (sample = 0; sample < SAMPLE_CNT; sample++) {
- transition_pattern |=
- ((sample_result[sample] & (1 << bl)) >> bl) <<
- (SAMPLE_CNT - 1 - sample);
- }
- DPF(D_TRN, "=== transition pattern %d\n", transition_pattern);
- /*
- * set up to look for rising edge based on
- * transition_pattern
- */
- switch (transition_pattern) {
- case 0: /* sampled 0->0->0 */
- /* move forward from T3 looking for 0->1 */
- delay[bl] += 2 * SAMPLE_DLY;
- direction[bl] = FORWARD;
- break;
- case 1: /* sampled 0->0->1 */
- case 5: /* sampled 1->0->1 (bad duty cycle) *HSD#237503* */
- /* move forward from T2 looking for 0->1 */
- delay[bl] += 1 * SAMPLE_DLY;
- direction[bl] = FORWARD;
- break;
- case 2: /* sampled 0->1->0 (bad duty cycle) *HSD#237503* */
- case 3: /* sampled 0->1->1 */
- /* move forward from T1 looking for 0->1 */
- delay[bl] += 0 * SAMPLE_DLY;
- direction[bl] = FORWARD;
- break;
- case 4: /* sampled 1->0->0 (assumes BL8, HSD#234975) */
- /* move forward from T3 looking for 0->1 */
- delay[bl] += 2 * SAMPLE_DLY;
- direction[bl] = FORWARD;
- break;
- case 6: /* sampled 1->1->0 */
- case 7: /* sampled 1->1->1 */
- /* move backward from T1 looking for 1->0 */
- delay[bl] += 0 * SAMPLE_DLY;
- direction[bl] = BACKWARD;
- break;
- default:
- mrc_post_code(0xee, 0xee);
- break;
- }
- /* program delays */
- if (rcvn)
- set_rcvn(channel, rank, bl, delay[bl]);
- else
- set_wdqs(channel, rank, bl, delay[bl]);
- }
- /*
- * Based on the observed transition pattern on the byte lane,
- * begin looking for a rising edge with single PI granularity.
- */
- do {
- all_edges_found = true; /* assume all byte lanes passed */
- /* take a sample */
- temp = sample_dqs(mrc_params, channel, rank, rcvn);
- /* check all each byte lane for proper edge */
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- if (temp & (1 << bl)) {
- /* sampled "1" */
- if (direction[bl] == BACKWARD) {
- /*
- * keep looking for edge
- * on this byte lane
- */
- all_edges_found = false;
- delay[bl] -= 1;
- if (rcvn) {
- set_rcvn(channel, rank,
- bl, delay[bl]);
- } else {
- set_wdqs(channel, rank,
- bl, delay[bl]);
- }
- }
- } else {
- /* sampled "0" */
- if (direction[bl] == FORWARD) {
- /*
- * keep looking for edge
- * on this byte lane
- */
- all_edges_found = false;
- delay[bl] += 1;
- if (rcvn) {
- set_rcvn(channel, rank,
- bl, delay[bl]);
- } else {
- set_wdqs(channel, rank,
- bl, delay[bl]);
- }
- }
- }
- }
- } while (!all_edges_found);
- /* restore DDR idle state */
- dram_init_command(DCMD_PREA(rank));
- DPF(D_TRN, "Delay %03X %03X %03X %03X\n",
- delay[0], delay[1], delay[2], delay[3]);
- LEAVEFN();
- }
- /*
- * This function will return a 32 bit mask that will be used to
- * check for byte lane failures.
- */
- uint32_t byte_lane_mask(struct mrc_params *mrc_params)
- {
- uint32_t j;
- uint32_t ret_val = 0x00;
- /*
- * set ret_val based on NUM_BYTE_LANES such that you will check
- * only BL0 in result
- *
- * (each bit in result represents a byte lane)
- */
- for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES)
- ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES));
- /*
- * HSD#235037
- * need to adjust the mask for 16-bit mode
- */
- if (mrc_params->channel_width == X16)
- ret_val |= (ret_val << 2);
- return ret_val;
- }
- /*
- * Check memory executing simple write/read/verify at the specified address.
- *
- * Bits in the result indicate failure on specific byte lane.
- */
- uint32_t check_rw_coarse(struct mrc_params *mrc_params, uint32_t address)
- {
- uint32_t result = 0;
- uint8_t first_run = 0;
- if (mrc_params->hte_setup) {
- mrc_params->hte_setup = 0;
- first_run = 1;
- select_hte();
- }
- result = hte_basic_write_read(mrc_params, address, first_run,
- WRITE_TRAIN);
- DPF(D_TRN, "check_rw_coarse result is %x\n", result);
- return result;
- }
- /*
- * Check memory executing write/read/verify of many data patterns
- * at the specified address. Bits in the result indicate failure
- * on specific byte lane.
- */
- uint32_t check_bls_ex(struct mrc_params *mrc_params, uint32_t address)
- {
- uint32_t result;
- uint8_t first_run = 0;
- if (mrc_params->hte_setup) {
- mrc_params->hte_setup = 0;
- first_run = 1;
- select_hte();
- }
- result = hte_write_stress_bit_lanes(mrc_params, address, first_run);
- DPF(D_TRN, "check_bls_ex result is %x\n", result);
- return result;
- }
- /*
- * 32-bit LFSR with characteristic polynomial: X^32 + X^22 +X^2 + X^1
- *
- * The function takes pointer to previous 32 bit value and
- * modifies it to next value.
- */
- void lfsr32(uint32_t *lfsr_ptr)
- {
- uint32_t bit;
- uint32_t lfsr;
- int i;
- lfsr = *lfsr_ptr;
- for (i = 0; i < 32; i++) {
- bit = 1 ^ (lfsr & 1);
- bit = bit ^ ((lfsr & 2) >> 1);
- bit = bit ^ ((lfsr & 4) >> 2);
- bit = bit ^ ((lfsr & 0x400000) >> 22);
- lfsr = ((lfsr >> 1) | (bit << 31));
- }
- *lfsr_ptr = lfsr;
- }
- /* Clear the pointers in a given byte lane in a given channel */
- void clear_pointers(void)
- {
- uint8_t channel;
- uint8_t bl;
- ENTERFN();
- for (channel = 0; channel < NUM_CHANNELS; channel++) {
- for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
- mrc_alt_write_mask(DDRPHY,
- B01PTRCTL1 +
- channel * DDRIODQ_CH_OFFSET +
- (bl >> 1) * DDRIODQ_BL_OFFSET,
- ~(1 << 8), (1 << 8));
- mrc_alt_write_mask(DDRPHY,
- B01PTRCTL1 +
- channel * DDRIODQ_CH_OFFSET +
- (bl >> 1) * DDRIODQ_BL_OFFSET,
- (1 << 8), (1 << 8));
- }
- }
- LEAVEFN();
- }
- static void print_timings_internal(uint8_t algo, uint8_t channel, uint8_t rank,
- uint8_t bl_divisor)
- {
- uint8_t bl;
- switch (algo) {
- case RCVN:
- DPF(D_INFO, "\nRCVN[%02d:%02d]", channel, rank);
- break;
- case WDQS:
- DPF(D_INFO, "\nWDQS[%02d:%02d]", channel, rank);
- break;
- case WDQX:
- DPF(D_INFO, "\nWDQx[%02d:%02d]", channel, rank);
- break;
- case RDQS:
- DPF(D_INFO, "\nRDQS[%02d:%02d]", channel, rank);
- break;
- case VREF:
- DPF(D_INFO, "\nVREF[%02d:%02d]", channel, rank);
- break;
- case WCMD:
- DPF(D_INFO, "\nWCMD[%02d:%02d]", channel, rank);
- break;
- case WCTL:
- DPF(D_INFO, "\nWCTL[%02d:%02d]", channel, rank);
- break;
- case WCLK:
- DPF(D_INFO, "\nWCLK[%02d:%02d]", channel, rank);
- break;
- default:
- break;
- }
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- switch (algo) {
- case RCVN:
- DPF(D_INFO, " %03d", get_rcvn(channel, rank, bl));
- break;
- case WDQS:
- DPF(D_INFO, " %03d", get_wdqs(channel, rank, bl));
- break;
- case WDQX:
- DPF(D_INFO, " %03d", get_wdq(channel, rank, bl));
- break;
- case RDQS:
- DPF(D_INFO, " %03d", get_rdqs(channel, rank, bl));
- break;
- case VREF:
- DPF(D_INFO, " %03d", get_vref(channel, bl));
- break;
- case WCMD:
- DPF(D_INFO, " %03d", get_wcmd(channel));
- break;
- case WCTL:
- DPF(D_INFO, " %03d", get_wctl(channel, rank));
- break;
- case WCLK:
- DPF(D_INFO, " %03d", get_wclk(channel, rank));
- break;
- default:
- break;
- }
- }
- }
- void print_timings(struct mrc_params *mrc_params)
- {
- uint8_t algo;
- uint8_t channel;
- uint8_t rank;
- uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
- DPF(D_INFO, "\n---------------------------");
- DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3");
- DPF(D_INFO, "\n===========================");
- for (algo = 0; algo < MAX_ALGOS; algo++) {
- for (channel = 0; channel < NUM_CHANNELS; channel++) {
- if (mrc_params->channel_enables & (1 << channel)) {
- for (rank = 0; rank < NUM_RANKS; rank++) {
- if (mrc_params->rank_enables &
- (1 << rank)) {
- print_timings_internal(algo,
- channel, rank,
- bl_divisor);
- }
- }
- }
- }
- }
- DPF(D_INFO, "\n---------------------------");
- DPF(D_INFO, "\n");
- }
|