1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright 2021-2022 NXP 3*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 4*91f16700Schasinglulu * 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <errno.h> 8*91f16700Schasinglulu #include <stdint.h> 9*91f16700Schasinglulu #include <stdio.h> 10*91f16700Schasinglulu #include <stdlib.h> 11*91f16700Schasinglulu #include <string.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <common/debug.h> 14*91f16700Schasinglulu #include "csr.h" 15*91f16700Schasinglulu #include <ddr.h> 16*91f16700Schasinglulu #include "ddr4fw.h" 17*91f16700Schasinglulu #include <drivers/delay_timer.h> 18*91f16700Schasinglulu #ifdef NXP_WARM_BOOT 19*91f16700Schasinglulu #include <fspi_api.h> 20*91f16700Schasinglulu #endif 21*91f16700Schasinglulu #include "input.h" 22*91f16700Schasinglulu #include <lib/mmio.h> 23*91f16700Schasinglulu #include <lib/utils.h> 24*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h> 25*91f16700Schasinglulu #ifdef DDR_PHY_DEBUG 26*91f16700Schasinglulu #include "messages.h" 27*91f16700Schasinglulu #endif 28*91f16700Schasinglulu #ifdef NXP_WARM_BOOT 29*91f16700Schasinglulu #include "phy.h" 30*91f16700Schasinglulu #endif 31*91f16700Schasinglulu #include "pie.h" 32*91f16700Schasinglulu 33*91f16700Schasinglulu #define TIMEOUTDEFAULT 500 34*91f16700Schasinglulu #define MAP_PHY_ADDR(pstate, n, instance, offset, c) \ 35*91f16700Schasinglulu ((((pstate * n) + instance + c) << 12) + offset) 36*91f16700Schasinglulu 37*91f16700Schasinglulu static uint32_t map_phy_addr_space(uint32_t addr) 38*91f16700Schasinglulu { 39*91f16700Schasinglulu /* 23 bit addressing */ 40*91f16700Schasinglulu uint32_t pstate = (addr & U(0x700000)) >> 20U; /* bit 22:20 */ 41*91f16700Schasinglulu uint32_t block_type = (addr & U(0x0f0000)) >> 16U; /* bit 19:16 */ 42*91f16700Schasinglulu uint32_t instance = (addr & U(0x00f000)) >> 12U; /* bit 15:12 */ 43*91f16700Schasinglulu uint32_t offset = (addr & U(0x000fff)); /* bit 11:0 */ 44*91f16700Schasinglulu 45*91f16700Schasinglulu switch (block_type) { 46*91f16700Schasinglulu case 0x0: /* 0x0 : ANIB */ 47*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 12, instance, offset, 0); 48*91f16700Schasinglulu case 0x1: /* 0x1 : DBYTE */ 49*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 10, instance, offset, 0x30); 50*91f16700Schasinglulu case 0x2: /* 0x2 : MASTER */ 51*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 1, 0, offset, 0x58); 52*91f16700Schasinglulu case 0x4: /* 0x4 : ACSM */ 53*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 1, 0, offset, 0x5c); 54*91f16700Schasinglulu case 0x5: /* 0x5 : μCTL Memory */ 55*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 0, instance, offset, 0x60); 56*91f16700Schasinglulu case 0x7: /* 0x7 : PPGC */ 57*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 0, 0, offset, 0x68); 58*91f16700Schasinglulu case 0x9: /* 0x9 : INITENG */ 59*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 1, 0, offset, 0x69); 60*91f16700Schasinglulu case 0xc: /* 0xC : DRTUB */ 61*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 0, 0, offset, 0x6d); 62*91f16700Schasinglulu case 0xd: /* 0xD : APB Only */ 63*91f16700Schasinglulu return MAP_PHY_ADDR(pstate, 0, 0, offset, 0x6e); 64*91f16700Schasinglulu default: 65*91f16700Schasinglulu printf("ERR: Invalid block_type = 0x%x\n", block_type); 66*91f16700Schasinglulu return 0; 67*91f16700Schasinglulu } 68*91f16700Schasinglulu } 69*91f16700Schasinglulu 70*91f16700Schasinglulu static inline uint16_t *phy_io_addr(void *phy, uint32_t addr) 71*91f16700Schasinglulu { 72*91f16700Schasinglulu return phy + (map_phy_addr_space(addr) << 2); 73*91f16700Schasinglulu } 74*91f16700Schasinglulu 75*91f16700Schasinglulu static inline void phy_io_write16(uint16_t *phy, uint32_t addr, uint16_t data) 76*91f16700Schasinglulu { 77*91f16700Schasinglulu mmio_write_16((uintptr_t)phy_io_addr(phy, addr), data); 78*91f16700Schasinglulu #ifdef DEBUG_PHY_IO 79*91f16700Schasinglulu printf("0x%06x,0x%x\n", addr, data); 80*91f16700Schasinglulu #endif 81*91f16700Schasinglulu } 82*91f16700Schasinglulu 83*91f16700Schasinglulu static inline uint16_t phy_io_read16(uint16_t *phy, uint32_t addr) 84*91f16700Schasinglulu { 85*91f16700Schasinglulu uint16_t reg = mmio_read_16((uintptr_t) phy_io_addr(phy, addr)); 86*91f16700Schasinglulu 87*91f16700Schasinglulu #ifdef DEBUG_PHY_IO 88*91f16700Schasinglulu printf("R: 0x%06x,0x%x\n", addr, reg); 89*91f16700Schasinglulu #endif 90*91f16700Schasinglulu 91*91f16700Schasinglulu return reg; 92*91f16700Schasinglulu } 93*91f16700Schasinglulu 94*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 95*91f16700Schasinglulu 96*91f16700Schasinglulu #define CDD_VAL_READ_ADDR (0x054012) 97*91f16700Schasinglulu #define CDD_DATA_LEN (60) 98*91f16700Schasinglulu 99*91f16700Schasinglulu static void read_phy_reg(uint16_t *phy, uint32_t addr, 100*91f16700Schasinglulu uint16_t *buf, uint32_t len) 101*91f16700Schasinglulu { 102*91f16700Schasinglulu uint32_t i = 0U; 103*91f16700Schasinglulu 104*91f16700Schasinglulu for (i = 0U; i < len/2; i++) { 105*91f16700Schasinglulu buf[i] = phy_io_read16(phy, (addr + i)); 106*91f16700Schasinglulu } 107*91f16700Schasinglulu } 108*91f16700Schasinglulu 109*91f16700Schasinglulu static uint32_t findrank(uint32_t cs_in_use) 110*91f16700Schasinglulu { 111*91f16700Schasinglulu uint32_t val = 0U; 112*91f16700Schasinglulu 113*91f16700Schasinglulu switch (cs_in_use) { 114*91f16700Schasinglulu case U(0xf): 115*91f16700Schasinglulu val = 4U; 116*91f16700Schasinglulu break; 117*91f16700Schasinglulu case U(0x3): 118*91f16700Schasinglulu val = 2U; 119*91f16700Schasinglulu break; 120*91f16700Schasinglulu case U(0x1): 121*91f16700Schasinglulu val = 1U; 122*91f16700Schasinglulu break; 123*91f16700Schasinglulu default: 124*91f16700Schasinglulu printf("Error - Invalid cs_in_use value\n"); 125*91f16700Schasinglulu } 126*91f16700Schasinglulu return val; 127*91f16700Schasinglulu } 128*91f16700Schasinglulu 129*91f16700Schasinglulu static uint8_t findmax(uint8_t *buf, uint32_t len) 130*91f16700Schasinglulu { 131*91f16700Schasinglulu uint8_t max = 0U; 132*91f16700Schasinglulu uint32_t i = 0U; 133*91f16700Schasinglulu 134*91f16700Schasinglulu for (i = 0U; i < len; i++) { 135*91f16700Schasinglulu if (buf[i] > max) { 136*91f16700Schasinglulu max = buf[i]; 137*91f16700Schasinglulu } 138*91f16700Schasinglulu } 139*91f16700Schasinglulu 140*91f16700Schasinglulu return max; 141*91f16700Schasinglulu } 142*91f16700Schasinglulu 143*91f16700Schasinglulu static void get_cdd_val(uint16_t **phy_ptr, uint32_t rank, uint32_t freq, 144*91f16700Schasinglulu uint32_t *tcfg0, uint32_t *tcfg4) 145*91f16700Schasinglulu { 146*91f16700Schasinglulu uint8_t cdd[CDD_DATA_LEN+4] = {0U}; 147*91f16700Schasinglulu uint32_t i, val = 0U; 148*91f16700Schasinglulu uint16_t *phy; 149*91f16700Schasinglulu uint8_t buf[16] = {U(0x0)}; 150*91f16700Schasinglulu uint8_t trr = 0U, tww = 0U, trw = 0U, twr = 0U; 151*91f16700Schasinglulu uint8_t rrmax = 0U, wwmax = 0U, rwmax = 0U, wrmax = 0U; 152*91f16700Schasinglulu uint8_t tmp = U(0x0); 153*91f16700Schasinglulu uint8_t *c = NULL; 154*91f16700Schasinglulu 155*91f16700Schasinglulu for (i = 0U; i < NUM_OF_DDRC; i++) { 156*91f16700Schasinglulu 157*91f16700Schasinglulu phy = phy_ptr[i]; 158*91f16700Schasinglulu if (phy == NULL) { 159*91f16700Schasinglulu continue; 160*91f16700Schasinglulu } 161*91f16700Schasinglulu 162*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | 163*91f16700Schasinglulu csr_micro_cont_mux_sel_addr, U(0x0)); 164*91f16700Schasinglulu 165*91f16700Schasinglulu read_phy_reg(phy, CDD_VAL_READ_ADDR, 166*91f16700Schasinglulu (uint16_t *)&cdd, CDD_DATA_LEN); 167*91f16700Schasinglulu 168*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | 169*91f16700Schasinglulu csr_micro_cont_mux_sel_addr, U(0x1)); 170*91f16700Schasinglulu 171*91f16700Schasinglulu /* CDD values and address 172*91f16700Schasinglulu * 173*91f16700Schasinglulu * 0x054012 0x24 cdd[0] CDD[X][X] 174*91f16700Schasinglulu * 0x054012 0x25 cdd[1] RR[3][2] 175*91f16700Schasinglulu * 0x054013 0x26 cdd[2] RR[3][1] 176*91f16700Schasinglulu * 0x054013 0x27 cdd[3] RR[3][0] 177*91f16700Schasinglulu * 0x054014 0x28 cdd[4] RR[2][3] 178*91f16700Schasinglulu * 0x054014 0x29 cdd[5] RR[2][1] 179*91f16700Schasinglulu * 0x054015 0x2a cdd[6] RR[2][0] 180*91f16700Schasinglulu * 0x054015 0x2b cdd[7] RR[1][3] 181*91f16700Schasinglulu * 0x054016 0x2c cdd[8] RR[1][2] 182*91f16700Schasinglulu * 0x054016 0x2d cdd[9] RR[1][0] 183*91f16700Schasinglulu * 0x054017 0x2e cdd[10] RR[0][3] 184*91f16700Schasinglulu * 0x054017 0x2f cdd[11] RR[0][2] 185*91f16700Schasinglulu * 0x054018 0x30 cdd[12] RR[0][1] 186*91f16700Schasinglulu 187*91f16700Schasinglulu * 0x054018 0x31 cdd[13] WW[3][2] 188*91f16700Schasinglulu * 0x054019 0x32 cdd[14] WW[3][1] 189*91f16700Schasinglulu * 0x054019 0x33 cdd[15] WW[3][0] 190*91f16700Schasinglulu * 0x05401a 0x34 cdd[16] WW[2][3] 191*91f16700Schasinglulu * 0x05401a 0x35 cdd[17] WW[2][1] 192*91f16700Schasinglulu * 0x05401b 0x36 cdd[18] WW[2][0] 193*91f16700Schasinglulu * 0x05401b 0x37 cdd[19] WW[1][3] 194*91f16700Schasinglulu * 0x05401c 0x38 cdd[20] WW[1][2] 195*91f16700Schasinglulu * 0x05401c 0x39 cdd[21] WW[1][0] 196*91f16700Schasinglulu * 0x05401d 0x3a cdd[22] WW[0][3] 197*91f16700Schasinglulu * 0x05401d 0x3b cdd[23] WW[0][2] 198*91f16700Schasinglulu * 0x05401e 0x3c cdd[24] WW[0][1] 199*91f16700Schasinglulu 200*91f16700Schasinglulu * 0x05401e 0x3d cdd[25] RW[3][3] 201*91f16700Schasinglulu * 0x05401f 0x3e cdd[26] RW[3][2] 202*91f16700Schasinglulu * 0x05401f 0x3f cdd[27] RW[3][1] 203*91f16700Schasinglulu * 0x054020 0x40 cdd[28] RW[3][0] 204*91f16700Schasinglulu * 0x054020 0x41 cdd[29] RW[2][3] 205*91f16700Schasinglulu * 0x054021 0x42 cdd[30] RW[2][2] 206*91f16700Schasinglulu * 0x054021 0x43 cdd[31] RW[2][1] 207*91f16700Schasinglulu * 0x054022 0x44 cdd[32] RW[2][0] 208*91f16700Schasinglulu * 0x054022 0x45 cdd[33] RW[1][3] 209*91f16700Schasinglulu * 0x054023 0x46 cdd[34] RW[1][2] 210*91f16700Schasinglulu * 0x054023 0x47 cdd[35] RW[1][1] 211*91f16700Schasinglulu * 0x054024 0x48 cdd[36] RW[1][0] 212*91f16700Schasinglulu * 0x054024 0x49 cdd[37] RW[0][3] 213*91f16700Schasinglulu * 0x054025 0x4a cdd[38] RW[0][2] 214*91f16700Schasinglulu * 0x054025 0x4b cdd[39] RW[0][1] 215*91f16700Schasinglulu * 0x054026 0x4c cdd[40] RW[0][0] 216*91f16700Schasinglulu 217*91f16700Schasinglulu * 0x054026 0x4d cdd[41] WR[3][3] 218*91f16700Schasinglulu * 0x054027 0x4e cdd[42] WR[3][2] 219*91f16700Schasinglulu * 0x054027 0x4f cdd[43] WR[3][1] 220*91f16700Schasinglulu * 0x054028 0x50 cdd[44] WR[3][0] 221*91f16700Schasinglulu * 0x054028 0x51 cdd[45] WR[2][3] 222*91f16700Schasinglulu * 0x054029 0x52 cdd[46] WR[2][2] 223*91f16700Schasinglulu * 0x054029 0x53 cdd[47] WR[2][1] 224*91f16700Schasinglulu * 0x05402a 0x54 cdd[48] WR[2][0] 225*91f16700Schasinglulu * 0x05402a 0x55 cdd[49] WR[1][3] 226*91f16700Schasinglulu * 0x05402b 0x56 cdd[50] WR[1][2] 227*91f16700Schasinglulu * 0x05402b 0x57 cdd[51] WR[1][1] 228*91f16700Schasinglulu * 0x05402c 0x58 cdd[52] WR[1][0] 229*91f16700Schasinglulu * 0x05402c 0x59 cdd[53] WR[0][3] 230*91f16700Schasinglulu * 0x05402d 0x5a cdd[54] WR[0][2] 231*91f16700Schasinglulu * 0x05402d 0x5b cdd[55] WR[0][1] 232*91f16700Schasinglulu * 0x05402e 0x5c cdd[56] WR[0][0] 233*91f16700Schasinglulu * 0x05402e 0x5d cdd[57] CDD[Y][Y] 234*91f16700Schasinglulu */ 235*91f16700Schasinglulu 236*91f16700Schasinglulu switch (rank) { 237*91f16700Schasinglulu case 1U: 238*91f16700Schasinglulu tmp = rwmax; 239*91f16700Schasinglulu rwmax = cdd[40]; 240*91f16700Schasinglulu if (tmp > rwmax) { 241*91f16700Schasinglulu rwmax = tmp; 242*91f16700Schasinglulu } 243*91f16700Schasinglulu 244*91f16700Schasinglulu break; 245*91f16700Schasinglulu 246*91f16700Schasinglulu case 2U: 247*91f16700Schasinglulu buf[0] = cdd[12]; 248*91f16700Schasinglulu buf[1] = cdd[9]; 249*91f16700Schasinglulu tmp = rrmax; 250*91f16700Schasinglulu rrmax = findmax(buf, 2U); 251*91f16700Schasinglulu if (tmp > rrmax) { 252*91f16700Schasinglulu rrmax = tmp; 253*91f16700Schasinglulu } 254*91f16700Schasinglulu 255*91f16700Schasinglulu buf[0] = cdd[24]; 256*91f16700Schasinglulu buf[1] = cdd[21]; 257*91f16700Schasinglulu tmp = wwmax; 258*91f16700Schasinglulu wwmax = findmax(buf, 2U); 259*91f16700Schasinglulu if (tmp > wwmax) { 260*91f16700Schasinglulu wwmax = tmp; 261*91f16700Schasinglulu } 262*91f16700Schasinglulu 263*91f16700Schasinglulu buf[0] = cdd[40]; 264*91f16700Schasinglulu buf[1] = cdd[39]; 265*91f16700Schasinglulu buf[2] = cdd[36]; 266*91f16700Schasinglulu buf[3] = cdd[35]; 267*91f16700Schasinglulu tmp = rwmax; 268*91f16700Schasinglulu rwmax = findmax(buf, 4U); 269*91f16700Schasinglulu if (tmp > rwmax) { 270*91f16700Schasinglulu rwmax = tmp; 271*91f16700Schasinglulu } 272*91f16700Schasinglulu 273*91f16700Schasinglulu wrmax = wwmax; 274*91f16700Schasinglulu 275*91f16700Schasinglulu break; 276*91f16700Schasinglulu 277*91f16700Schasinglulu case 4U: 278*91f16700Schasinglulu tmp = rrmax; 279*91f16700Schasinglulu c = &cdd[1]; 280*91f16700Schasinglulu rrmax = findmax(c, 12U); 281*91f16700Schasinglulu if (tmp > rrmax) { 282*91f16700Schasinglulu rrmax = tmp; 283*91f16700Schasinglulu } 284*91f16700Schasinglulu 285*91f16700Schasinglulu tmp = wwmax; 286*91f16700Schasinglulu c = &cdd[13]; 287*91f16700Schasinglulu wwmax = findmax(c, 12U); 288*91f16700Schasinglulu if (tmp > wwmax) { 289*91f16700Schasinglulu wwmax = tmp; 290*91f16700Schasinglulu } 291*91f16700Schasinglulu 292*91f16700Schasinglulu tmp = rwmax; 293*91f16700Schasinglulu c = &cdd[25]; 294*91f16700Schasinglulu rwmax = findmax(c, 16U); 295*91f16700Schasinglulu if (tmp > rwmax) { 296*91f16700Schasinglulu rwmax = tmp; 297*91f16700Schasinglulu } 298*91f16700Schasinglulu 299*91f16700Schasinglulu wrmax = wwmax; 300*91f16700Schasinglulu 301*91f16700Schasinglulu break; 302*91f16700Schasinglulu 303*91f16700Schasinglulu } 304*91f16700Schasinglulu } 305*91f16700Schasinglulu 306*91f16700Schasinglulu rrmax += 3U; 307*91f16700Schasinglulu wwmax += 4U; 308*91f16700Schasinglulu 309*91f16700Schasinglulu if (wwmax > 7U) { 310*91f16700Schasinglulu wwmax = 7U; 311*91f16700Schasinglulu } 312*91f16700Schasinglulu 313*91f16700Schasinglulu if (rrmax > 7U) { 314*91f16700Schasinglulu rrmax = 7U; 315*91f16700Schasinglulu } 316*91f16700Schasinglulu 317*91f16700Schasinglulu if (wrmax > U(0xf)) { 318*91f16700Schasinglulu wrmax = 0U; 319*91f16700Schasinglulu } 320*91f16700Schasinglulu 321*91f16700Schasinglulu if (rwmax > U(0x7)) { 322*91f16700Schasinglulu rwmax = U(0x7); 323*91f16700Schasinglulu } 324*91f16700Schasinglulu 325*91f16700Schasinglulu val = *tcfg0; 326*91f16700Schasinglulu tww = (val >> 24U) & U(0x3); 327*91f16700Schasinglulu trr = (val >> 26U) & U(0x3); 328*91f16700Schasinglulu twr = (val >> 28U) & U(0x3); 329*91f16700Schasinglulu trw = (val >> 30U) & U(0x3); 330*91f16700Schasinglulu 331*91f16700Schasinglulu val = *tcfg4; 332*91f16700Schasinglulu tww = tww | (((val >> 8U) & U(0x1)) << 2U); 333*91f16700Schasinglulu trr = trr | (((val >> 10U) & U(0x1)) << 2U); 334*91f16700Schasinglulu twr = twr | (((val >> 12U) & U(0x1)) << 2U); 335*91f16700Schasinglulu trw = trw | (((val >> 14U) & U(0x3)) << 2U); 336*91f16700Schasinglulu 337*91f16700Schasinglulu if (trr > rrmax) { 338*91f16700Schasinglulu rrmax = trr; 339*91f16700Schasinglulu } 340*91f16700Schasinglulu 341*91f16700Schasinglulu if (tww > wwmax) { 342*91f16700Schasinglulu wwmax = tww; 343*91f16700Schasinglulu } 344*91f16700Schasinglulu 345*91f16700Schasinglulu if (trw > rwmax) { 346*91f16700Schasinglulu rwmax = trw; 347*91f16700Schasinglulu } 348*91f16700Schasinglulu 349*91f16700Schasinglulu if (twr > wrmax) { 350*91f16700Schasinglulu wrmax = twr; 351*91f16700Schasinglulu } 352*91f16700Schasinglulu 353*91f16700Schasinglulu debug("CDD rrmax %x wwmax %x rwmax %x wrmax %x\n", 354*91f16700Schasinglulu rrmax, wwmax, rwmax, wrmax); 355*91f16700Schasinglulu 356*91f16700Schasinglulu val = ((wwmax & U(0x3)) << 24U) 357*91f16700Schasinglulu | ((rrmax & U(0x3)) << 26U) 358*91f16700Schasinglulu | ((wrmax & U(0x3)) << 28U) 359*91f16700Schasinglulu | ((rwmax & U(0x3)) << 30U); 360*91f16700Schasinglulu 361*91f16700Schasinglulu *tcfg0 = (*tcfg0 & U(0x00FFFFFF)) | (val); 362*91f16700Schasinglulu 363*91f16700Schasinglulu val = (((wwmax >> 2U) & U(0x1)) << 8U) 364*91f16700Schasinglulu | (((rrmax >> 2U) & U(0x1)) << 10U) 365*91f16700Schasinglulu | (((wrmax >> 2U) & U(0x1)) << 12U) 366*91f16700Schasinglulu | (((rwmax >> 2U) & U(0x3)) << 14U); 367*91f16700Schasinglulu 368*91f16700Schasinglulu *tcfg4 = (*tcfg4 & U(0xffff00ff)) | val; 369*91f16700Schasinglulu } 370*91f16700Schasinglulu #endif 371*91f16700Schasinglulu 372*91f16700Schasinglulu #ifdef NXP_WARM_BOOT 373*91f16700Schasinglulu int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store, 374*91f16700Schasinglulu uint32_t num_of_phy, int train2d 375*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 376*91f16700Schasinglulu , struct ddr_ctrl_reg_values *ddrctrl_regs 377*91f16700Schasinglulu #endif 378*91f16700Schasinglulu ) 379*91f16700Schasinglulu 380*91f16700Schasinglulu { 381*91f16700Schasinglulu uint16_t *phy = NULL, value = 0x0; 382*91f16700Schasinglulu uint32_t size = 1U, num_of_regs = 1U, phy_store = 0U; 383*91f16700Schasinglulu int i = 0, j = 0, ret = -EINVAL; 384*91f16700Schasinglulu 385*91f16700Schasinglulu ret = xspi_sector_erase(address_to_store, PHY_ERASE_SIZE); 386*91f16700Schasinglulu if (ret != 0) { 387*91f16700Schasinglulu return -EINVAL; 388*91f16700Schasinglulu } 389*91f16700Schasinglulu 390*91f16700Schasinglulu for (j = 0; j < num_of_phy; j++) { 391*91f16700Schasinglulu /* Save training values of all PHYs */ 392*91f16700Schasinglulu phy = phy_ptr[j]; 393*91f16700Schasinglulu size = sizeof(training_1D_values); 394*91f16700Schasinglulu num_of_regs = ARRAY_SIZE(training_1D_values); 395*91f16700Schasinglulu 396*91f16700Schasinglulu /* Enable access to the internal CSRs */ 397*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | 398*91f16700Schasinglulu csr_micro_cont_mux_sel_addr, 0x0); 399*91f16700Schasinglulu /* Enable clocks in case they were disabled. */ 400*91f16700Schasinglulu phy_io_write16(phy, t_drtub | 401*91f16700Schasinglulu csr_ucclk_hclk_enables_addr, 0x3); 402*91f16700Schasinglulu if (train2d != 0) { 403*91f16700Schasinglulu /* Address to store training values is 404*91f16700Schasinglulu * to be appended for next PHY 405*91f16700Schasinglulu */ 406*91f16700Schasinglulu phy_store = address_to_store + (j * 407*91f16700Schasinglulu (sizeof(training_1D_values) + 408*91f16700Schasinglulu sizeof(training_2D_values))); 409*91f16700Schasinglulu } else { 410*91f16700Schasinglulu phy_store = address_to_store + (j * 411*91f16700Schasinglulu (sizeof(training_1D_values))); 412*91f16700Schasinglulu } 413*91f16700Schasinglulu debug("Saving 1D Training reg val at: %d\n", phy_store); 414*91f16700Schasinglulu for (i = 0; i < num_of_regs; i++) { 415*91f16700Schasinglulu value = phy_io_read16(phy, training_1D_values[i].addr); 416*91f16700Schasinglulu #ifdef DEBUG_WARM_RESET 417*91f16700Schasinglulu debug("%d. Reg: %x, value: %x PHY: %p\n", i, 418*91f16700Schasinglulu training_1D_values[i].addr, value, 419*91f16700Schasinglulu phy_io_addr(phy, 420*91f16700Schasinglulu training_1D_values[i].addr)); 421*91f16700Schasinglulu #endif 422*91f16700Schasinglulu training_1D_values[i].data = value; 423*91f16700Schasinglulu } 424*91f16700Schasinglulu /* Storing 1D training values on flash */ 425*91f16700Schasinglulu ret = xspi_write(phy_store, (void *)training_1D_values, size); 426*91f16700Schasinglulu if (train2d != 0) { 427*91f16700Schasinglulu phy_store = phy_store+size; 428*91f16700Schasinglulu size = sizeof(training_2D_values); 429*91f16700Schasinglulu num_of_regs = ARRAY_SIZE(training_2D_values); 430*91f16700Schasinglulu debug("Saving 2D Training reg val at:%d\n", phy_store); 431*91f16700Schasinglulu for (i = 0; i < num_of_regs; i++) { 432*91f16700Schasinglulu value = phy_io_read16(phy, 433*91f16700Schasinglulu training_2D_values[i].addr); 434*91f16700Schasinglulu training_2D_values[i].data = value; 435*91f16700Schasinglulu #ifdef DEBUG_WARM_RESET 436*91f16700Schasinglulu debug("%d.2D addr:0x%x,val:0x%x,PHY:0x%p\n", 437*91f16700Schasinglulu i, training_2D_values[i].addr, 438*91f16700Schasinglulu value, phy_io_addr(phy, 439*91f16700Schasinglulu training_2D_values[i].addr)); 440*91f16700Schasinglulu #endif 441*91f16700Schasinglulu } 442*91f16700Schasinglulu /* Storing 2D training values on flash */ 443*91f16700Schasinglulu ret = xspi_write(phy_store, training_2D_values, 444*91f16700Schasinglulu size); 445*91f16700Schasinglulu } 446*91f16700Schasinglulu 447*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 448*91f16700Schasinglulu /* Save DDR control register Timing CFG 0 and 4 */ 449*91f16700Schasinglulu phy_store += size; 450*91f16700Schasinglulu size = sizeof(ddrctrl_regs); 451*91f16700Schasinglulu if (ret != 0) { 452*91f16700Schasinglulu ret = xspi_write(phy_store, ddrctrl_regs, size); 453*91f16700Schasinglulu } 454*91f16700Schasinglulu #endif 455*91f16700Schasinglulu /* Disable clocks in case they were disabled. */ 456*91f16700Schasinglulu phy_io_write16(phy, t_drtub | 457*91f16700Schasinglulu csr_ucclk_hclk_enables_addr, 0x0); 458*91f16700Schasinglulu /* Disable access to the internal CSRs */ 459*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | 460*91f16700Schasinglulu csr_micro_cont_mux_sel_addr, 0x1); 461*91f16700Schasinglulu } 462*91f16700Schasinglulu if (ret != 0) { 463*91f16700Schasinglulu return -EINVAL; 464*91f16700Schasinglulu } 465*91f16700Schasinglulu 466*91f16700Schasinglulu return 0; 467*91f16700Schasinglulu } 468*91f16700Schasinglulu 469*91f16700Schasinglulu int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore, 470*91f16700Schasinglulu uint32_t num_of_phy, int train2d 471*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 472*91f16700Schasinglulu , struct ddr_ctrl_reg_values *ddrctrl_regs 473*91f16700Schasinglulu #endif 474*91f16700Schasinglulu ) 475*91f16700Schasinglulu { 476*91f16700Schasinglulu uint16_t *phy = NULL; 477*91f16700Schasinglulu uint32_t size = 1U, num_of_regs = 1U, phy_store = 0U; 478*91f16700Schasinglulu int i = 0, j = 0, ret = -EINVAL; 479*91f16700Schasinglulu 480*91f16700Schasinglulu debug("Restoring Training register values\n"); 481*91f16700Schasinglulu for (j = 0; j < num_of_phy; j++) { 482*91f16700Schasinglulu phy = phy_ptr[j]; 483*91f16700Schasinglulu size = sizeof(training_1D_values); 484*91f16700Schasinglulu num_of_regs = ARRAY_SIZE(training_1D_values); 485*91f16700Schasinglulu if (train2d != 0) { 486*91f16700Schasinglulu /* The address to restore training values is 487*91f16700Schasinglulu * to be appended for next PHY 488*91f16700Schasinglulu */ 489*91f16700Schasinglulu phy_store = address_to_restore + (j * 490*91f16700Schasinglulu (sizeof(training_1D_values) + 491*91f16700Schasinglulu sizeof(training_2D_values))); 492*91f16700Schasinglulu } else { 493*91f16700Schasinglulu phy_store = address_to_restore + (j * 494*91f16700Schasinglulu (sizeof(training_1D_values))); 495*91f16700Schasinglulu } 496*91f16700Schasinglulu /* Enable access to the internal CSRs */ 497*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | 498*91f16700Schasinglulu csr_micro_cont_mux_sel_addr, 0x0); 499*91f16700Schasinglulu /* Enable clocks in case they were disabled. */ 500*91f16700Schasinglulu phy_io_write16(phy, t_drtub | 501*91f16700Schasinglulu csr_ucclk_hclk_enables_addr, 0x3); 502*91f16700Schasinglulu 503*91f16700Schasinglulu /* Reading 1D training values from flash*/ 504*91f16700Schasinglulu ret = xspi_read(phy_store, (uint32_t *)training_1D_values, 505*91f16700Schasinglulu size); 506*91f16700Schasinglulu if (ret != 0) { 507*91f16700Schasinglulu #ifdef DEBUG_WARM_RESET 508*91f16700Schasinglulu debug("Unable to Read 1D training values %d\n", 509*91f16700Schasinglulu ret); 510*91f16700Schasinglulu #endif 511*91f16700Schasinglulu return -EINVAL; 512*91f16700Schasinglulu } 513*91f16700Schasinglulu 514*91f16700Schasinglulu debug("Restoring 1D Training reg val at:%08x\n", phy_store); 515*91f16700Schasinglulu for (i = 0; i < num_of_regs; i++) { 516*91f16700Schasinglulu phy_io_write16(phy, training_1D_values[i].addr, 517*91f16700Schasinglulu training_1D_values[i].data); 518*91f16700Schasinglulu #ifdef DEBUG_WARM_RESET 519*91f16700Schasinglulu debug("%d. Reg: %x, value: %x PHY: %p\n", i, 520*91f16700Schasinglulu training_1D_values[i].addr, 521*91f16700Schasinglulu training_1D_values[i].data, 522*91f16700Schasinglulu phy_io_addr(phy, 523*91f16700Schasinglulu training_1D_values[i].addr)); 524*91f16700Schasinglulu #endif 525*91f16700Schasinglulu } 526*91f16700Schasinglulu if (train2d != 0) { 527*91f16700Schasinglulu phy_store = phy_store + size; 528*91f16700Schasinglulu size = sizeof(training_2D_values); 529*91f16700Schasinglulu num_of_regs = ARRAY_SIZE(training_2D_values); 530*91f16700Schasinglulu /* Reading 2D training values from flash */ 531*91f16700Schasinglulu ret = xspi_read(phy_store, 532*91f16700Schasinglulu (uint32_t *)training_2D_values, size); 533*91f16700Schasinglulu 534*91f16700Schasinglulu if (ret != 0) { 535*91f16700Schasinglulu #ifdef DEBUG_WARM_RESET 536*91f16700Schasinglulu debug("Unable to Read 2D training values %d\n", 537*91f16700Schasinglulu ret); 538*91f16700Schasinglulu #endif 539*91f16700Schasinglulu return -EINVAL; 540*91f16700Schasinglulu } 541*91f16700Schasinglulu 542*91f16700Schasinglulu debug("Restoring 2D Training reg val at:%08x\n", 543*91f16700Schasinglulu phy_store); 544*91f16700Schasinglulu for (i = 0; i < num_of_regs; i++) { 545*91f16700Schasinglulu phy_io_write16(phy, training_2D_values[i].addr, 546*91f16700Schasinglulu training_2D_values[i].data); 547*91f16700Schasinglulu #ifdef DEBUG_WARM_RESET 548*91f16700Schasinglulu debug("%d. Reg: %x, value: %x PHY: %p\n", i, 549*91f16700Schasinglulu training_2D_values[i].addr, 550*91f16700Schasinglulu training_2D_values[i].data, 551*91f16700Schasinglulu phy_io_addr(phy, 552*91f16700Schasinglulu training_1D_values[i].addr)); 553*91f16700Schasinglulu #endif 554*91f16700Schasinglulu } 555*91f16700Schasinglulu } 556*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 557*91f16700Schasinglulu phy_store = phy_store + size; 558*91f16700Schasinglulu size = sizeof(ddrctrl_regs); 559*91f16700Schasinglulu ret = xspi_read(phy_store, (uint32_t *)ddrctrl_regs, size); 560*91f16700Schasinglulu #endif 561*91f16700Schasinglulu /* Disable clocks in case they were disabled. */ 562*91f16700Schasinglulu phy_io_write16(phy, t_drtub | 563*91f16700Schasinglulu csr_ucclk_hclk_enables_addr, 0x0); 564*91f16700Schasinglulu /* Disable access to the internal CSRs */ 565*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | 566*91f16700Schasinglulu csr_micro_cont_mux_sel_addr, 0x1); 567*91f16700Schasinglulu } 568*91f16700Schasinglulu if (ret != 0) { 569*91f16700Schasinglulu return -EINVAL; 570*91f16700Schasinglulu } 571*91f16700Schasinglulu return 0; 572*91f16700Schasinglulu } 573*91f16700Schasinglulu #endif 574*91f16700Schasinglulu 575*91f16700Schasinglulu static void load_pieimage(uint16_t *phy, 576*91f16700Schasinglulu enum dimm_types dimm_type) 577*91f16700Schasinglulu { 578*91f16700Schasinglulu int i; 579*91f16700Schasinglulu int size; 580*91f16700Schasinglulu const struct pie *image = NULL; 581*91f16700Schasinglulu 582*91f16700Schasinglulu switch (dimm_type) { 583*91f16700Schasinglulu case UDIMM: 584*91f16700Schasinglulu case SODIMM: 585*91f16700Schasinglulu case NODIMM: 586*91f16700Schasinglulu image = pie_udimm; 587*91f16700Schasinglulu size = ARRAY_SIZE(pie_udimm); 588*91f16700Schasinglulu break; 589*91f16700Schasinglulu case RDIMM: 590*91f16700Schasinglulu image = pie_rdimm; 591*91f16700Schasinglulu size = ARRAY_SIZE(pie_rdimm); 592*91f16700Schasinglulu break; 593*91f16700Schasinglulu case LRDIMM: 594*91f16700Schasinglulu image = pie_lrdimm; 595*91f16700Schasinglulu size = ARRAY_SIZE(pie_lrdimm); 596*91f16700Schasinglulu break; 597*91f16700Schasinglulu default: 598*91f16700Schasinglulu printf("Unsupported DIMM type\n"); 599*91f16700Schasinglulu break; 600*91f16700Schasinglulu } 601*91f16700Schasinglulu 602*91f16700Schasinglulu if (image != NULL) { 603*91f16700Schasinglulu for (i = 0; i < size; i++) 604*91f16700Schasinglulu phy_io_write16(phy, image[i].addr, image[i].data); 605*91f16700Schasinglulu } 606*91f16700Schasinglulu } 607*91f16700Schasinglulu 608*91f16700Schasinglulu static void prog_acsm_playback(uint16_t *phy, 609*91f16700Schasinglulu const struct input *input, const void *msg) 610*91f16700Schasinglulu { 611*91f16700Schasinglulu int vec; 612*91f16700Schasinglulu const struct ddr4r1d *msg_blk; 613*91f16700Schasinglulu uint16_t acsmplayback[2][3]; 614*91f16700Schasinglulu uint32_t f0rc0a; 615*91f16700Schasinglulu uint32_t f0rc3x; 616*91f16700Schasinglulu uint32_t f0rc5x; 617*91f16700Schasinglulu 618*91f16700Schasinglulu if (input->basic.dimm_type != RDIMM) { 619*91f16700Schasinglulu return; 620*91f16700Schasinglulu } 621*91f16700Schasinglulu 622*91f16700Schasinglulu msg_blk = msg; 623*91f16700Schasinglulu f0rc0a = (msg_blk->f0rc0a_d0 & U(0xf)) | U(0xa0); 624*91f16700Schasinglulu f0rc3x = (msg_blk->f0rc3x_d0 & U(0xff)) | U(0x300); 625*91f16700Schasinglulu f0rc5x = (input->adv.phy_gen2_umctl_f0rc5x & U(0xff)) | U(0x500); 626*91f16700Schasinglulu 627*91f16700Schasinglulu acsmplayback[0][0] = U(0x3ff) & f0rc0a; 628*91f16700Schasinglulu acsmplayback[1][0] = (U(0x1c00) & f0rc0a) >> 10U; 629*91f16700Schasinglulu acsmplayback[0][1] = U(0x3ff) & f0rc3x; 630*91f16700Schasinglulu acsmplayback[1][1] = (U(0x1c00) & f0rc3x) >> 10U; 631*91f16700Schasinglulu acsmplayback[0][2] = U(0x3ff) & f0rc5x; 632*91f16700Schasinglulu acsmplayback[1][2] = (U(0x1c00) & f0rc5x) >> 10U; 633*91f16700Schasinglulu for (vec = 0; vec < 3; vec++) { 634*91f16700Schasinglulu phy_io_write16(phy, t_acsm | (csr_acsm_playback0x0_addr + 635*91f16700Schasinglulu (vec << 1)), acsmplayback[0][vec]); 636*91f16700Schasinglulu phy_io_write16(phy, t_acsm | (csr_acsm_playback1x0_addr + 637*91f16700Schasinglulu (vec << 1)), acsmplayback[1][vec]); 638*91f16700Schasinglulu } 639*91f16700Schasinglulu } 640*91f16700Schasinglulu 641*91f16700Schasinglulu static void prog_acsm_ctr(uint16_t *phy, 642*91f16700Schasinglulu const struct input *input) 643*91f16700Schasinglulu { 644*91f16700Schasinglulu if (input->basic.dimm_type != RDIMM) { 645*91f16700Schasinglulu return; 646*91f16700Schasinglulu } 647*91f16700Schasinglulu 648*91f16700Schasinglulu phy_io_write16(phy, t_acsm | csr_acsm_ctrl13_addr, 649*91f16700Schasinglulu 0xf << csr_acsm_cke_enb_lsb); 650*91f16700Schasinglulu 651*91f16700Schasinglulu phy_io_write16(phy, t_acsm | csr_acsm_ctrl0_addr, 652*91f16700Schasinglulu csr_acsm_par_mode_mask | csr_acsm_2t_mode_mask); 653*91f16700Schasinglulu } 654*91f16700Schasinglulu 655*91f16700Schasinglulu static void prog_cal_rate_run(uint16_t *phy, 656*91f16700Schasinglulu const struct input *input) 657*91f16700Schasinglulu { 658*91f16700Schasinglulu int cal_rate; 659*91f16700Schasinglulu int cal_interval; 660*91f16700Schasinglulu int cal_once; 661*91f16700Schasinglulu uint32_t addr; 662*91f16700Schasinglulu 663*91f16700Schasinglulu cal_interval = input->adv.cal_interval; 664*91f16700Schasinglulu cal_once = input->adv.cal_once; 665*91f16700Schasinglulu cal_rate = 0x1 << csr_cal_run_lsb | 666*91f16700Schasinglulu cal_once << csr_cal_once_lsb | 667*91f16700Schasinglulu cal_interval << csr_cal_interval_lsb; 668*91f16700Schasinglulu addr = t_master | csr_cal_rate_addr; 669*91f16700Schasinglulu phy_io_write16(phy, addr, cal_rate); 670*91f16700Schasinglulu } 671*91f16700Schasinglulu 672*91f16700Schasinglulu static void prog_seq0bdly0(uint16_t *phy, 673*91f16700Schasinglulu const struct input *input) 674*91f16700Schasinglulu { 675*91f16700Schasinglulu int ps_count[4]; 676*91f16700Schasinglulu int frq; 677*91f16700Schasinglulu uint32_t addr; 678*91f16700Schasinglulu int lower_freq_opt = 0; 679*91f16700Schasinglulu 680*91f16700Schasinglulu __unused const soc_info_t *soc_info; 681*91f16700Schasinglulu 682*91f16700Schasinglulu frq = input->basic.frequency >> 1; 683*91f16700Schasinglulu ps_count[0] = frq >> 3; /* 0.5 * frq / 4*/ 684*91f16700Schasinglulu if (input->basic.frequency < 400) { 685*91f16700Schasinglulu lower_freq_opt = (input->basic.dimm_type == RDIMM) ? 7 : 3; 686*91f16700Schasinglulu } else if (input->basic.frequency < 533) { 687*91f16700Schasinglulu lower_freq_opt = (input->basic.dimm_type == RDIMM) ? 14 : 11; 688*91f16700Schasinglulu } 689*91f16700Schasinglulu 690*91f16700Schasinglulu /* 1.0 * frq / 4 - lower_freq */ 691*91f16700Schasinglulu ps_count[1] = (frq >> 2) - lower_freq_opt; 692*91f16700Schasinglulu ps_count[2] = (frq << 1) + (frq >> 1); /* 10.0 * frq / 4 */ 693*91f16700Schasinglulu 694*91f16700Schasinglulu #ifdef DDR_PLL_FIX 695*91f16700Schasinglulu soc_info = get_soc_info(); 696*91f16700Schasinglulu if (soc_info->svr_reg.bf.maj_ver == 1) { 697*91f16700Schasinglulu ps_count[0] = 0x520; /* seq0bdly0 */ 698*91f16700Schasinglulu ps_count[1] = 0xa41; /* seq0bdly1 */ 699*91f16700Schasinglulu ps_count[2] = 0x668a; /* seq0bdly2 */ 700*91f16700Schasinglulu } 701*91f16700Schasinglulu #endif 702*91f16700Schasinglulu if (frq > 266) { 703*91f16700Schasinglulu ps_count[3] = 44; 704*91f16700Schasinglulu } else if (frq > 200) { 705*91f16700Schasinglulu ps_count[3] = 33; 706*91f16700Schasinglulu } else { 707*91f16700Schasinglulu ps_count[3] = 16; 708*91f16700Schasinglulu } 709*91f16700Schasinglulu 710*91f16700Schasinglulu addr = t_master | csr_seq0bdly0_addr; 711*91f16700Schasinglulu phy_io_write16(phy, addr, ps_count[0]); 712*91f16700Schasinglulu 713*91f16700Schasinglulu debug("seq0bdly0 = 0x%x\n", phy_io_read16(phy, addr)); 714*91f16700Schasinglulu 715*91f16700Schasinglulu addr = t_master | csr_seq0bdly1_addr; 716*91f16700Schasinglulu phy_io_write16(phy, addr, ps_count[1]); 717*91f16700Schasinglulu 718*91f16700Schasinglulu debug("seq0bdly1 = 0x%x\n", phy_io_read16(phy, addr)); 719*91f16700Schasinglulu 720*91f16700Schasinglulu addr = t_master | csr_seq0bdly2_addr; 721*91f16700Schasinglulu phy_io_write16(phy, addr, ps_count[2]); 722*91f16700Schasinglulu 723*91f16700Schasinglulu debug("seq0bdly2 = 0x%x\n", phy_io_read16(phy, addr)); 724*91f16700Schasinglulu 725*91f16700Schasinglulu addr = t_master | csr_seq0bdly3_addr; 726*91f16700Schasinglulu phy_io_write16(phy, addr, ps_count[3]); 727*91f16700Schasinglulu 728*91f16700Schasinglulu debug("seq0bdly3 = 0x%x\n", phy_io_read16(phy, addr)); 729*91f16700Schasinglulu } 730*91f16700Schasinglulu 731*91f16700Schasinglulu /* Only RDIMM requires msg_blk */ 732*91f16700Schasinglulu static void i_load_pie(uint16_t **phy_ptr, 733*91f16700Schasinglulu const struct input *input, 734*91f16700Schasinglulu const void *msg) 735*91f16700Schasinglulu { 736*91f16700Schasinglulu int i; 737*91f16700Schasinglulu uint16_t *phy; 738*91f16700Schasinglulu 739*91f16700Schasinglulu for (i = 0; i < NUM_OF_DDRC; i++) { 740*91f16700Schasinglulu phy = phy_ptr[i]; 741*91f16700Schasinglulu if (phy == NULL) { 742*91f16700Schasinglulu continue; 743*91f16700Schasinglulu } 744*91f16700Schasinglulu 745*91f16700Schasinglulu phy_io_write16(phy, 746*91f16700Schasinglulu t_apbonly | csr_micro_cont_mux_sel_addr, 747*91f16700Schasinglulu 0U); 748*91f16700Schasinglulu 749*91f16700Schasinglulu load_pieimage(phy, input->basic.dimm_type); 750*91f16700Schasinglulu 751*91f16700Schasinglulu prog_seq0bdly0(phy, input); 752*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag0_addr, 753*91f16700Schasinglulu U(0x0000)); 754*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag1_addr, 755*91f16700Schasinglulu U(0x0173)); 756*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag2_addr, 757*91f16700Schasinglulu U(0x0060)); 758*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag3_addr, 759*91f16700Schasinglulu U(0x6110)); 760*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag4_addr, 761*91f16700Schasinglulu U(0x2152)); 762*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag5_addr, 763*91f16700Schasinglulu U(0xdfbd)); 764*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag6_addr, 765*91f16700Schasinglulu input->basic.dimm_type == RDIMM && 766*91f16700Schasinglulu input->adv.phy_gen2_umctl_opt == 1U ? 767*91f16700Schasinglulu U(0x6000) : U(0xffff)); 768*91f16700Schasinglulu phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag7_addr, 769*91f16700Schasinglulu U(0x6152)); 770*91f16700Schasinglulu prog_acsm_playback(phy, input, msg); /* rdimm */ 771*91f16700Schasinglulu prog_acsm_ctr(phy, input); /* rdimm */ 772*91f16700Schasinglulu 773*91f16700Schasinglulu phy_io_write16(phy, t_master | csr_cal_zap_addr, U(0x1)); 774*91f16700Schasinglulu prog_cal_rate_run(phy, input); 775*91f16700Schasinglulu 776*91f16700Schasinglulu phy_io_write16(phy, t_drtub | csr_ucclk_hclk_enables_addr, 777*91f16700Schasinglulu input->basic.dimm_type == RDIMM ? U(0x2) : 0U); 778*91f16700Schasinglulu 779*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | csr_micro_cont_mux_sel_addr, 1U); 780*91f16700Schasinglulu } 781*91f16700Schasinglulu } 782*91f16700Schasinglulu 783*91f16700Schasinglulu static void phy_gen2_init_input(struct input *input) 784*91f16700Schasinglulu { 785*91f16700Schasinglulu int i; 786*91f16700Schasinglulu 787*91f16700Schasinglulu input->adv.dram_byte_swap = 0; 788*91f16700Schasinglulu input->adv.ext_cal_res_val = 0; 789*91f16700Schasinglulu input->adv.tx_slew_rise_dq = 0xf; 790*91f16700Schasinglulu input->adv.tx_slew_fall_dq = 0xf; 791*91f16700Schasinglulu input->adv.tx_slew_rise_ac = 0xf; 792*91f16700Schasinglulu input->adv.tx_slew_fall_ac = 0xf; 793*91f16700Schasinglulu input->adv.mem_alert_en = 0; 794*91f16700Schasinglulu input->adv.mem_alert_puimp = 5; 795*91f16700Schasinglulu input->adv.mem_alert_vref_level = 0x29; 796*91f16700Schasinglulu input->adv.mem_alert_sync_bypass = 0; 797*91f16700Schasinglulu input->adv.cal_interval = 0x9; 798*91f16700Schasinglulu input->adv.cal_once = 0; 799*91f16700Schasinglulu input->adv.dis_dyn_adr_tri = 0; 800*91f16700Schasinglulu input->adv.is2ttiming = 0; 801*91f16700Schasinglulu input->adv.d4rx_preamble_length = 0; 802*91f16700Schasinglulu input->adv.d4tx_preamble_length = 0; 803*91f16700Schasinglulu 804*91f16700Schasinglulu for (i = 0; i < 7; i++) { 805*91f16700Schasinglulu debug("mr[%d] = 0x%x\n", i, input->mr[i]); 806*91f16700Schasinglulu } 807*91f16700Schasinglulu 808*91f16700Schasinglulu debug("input->cs_d0 = 0x%x\n", input->cs_d0); 809*91f16700Schasinglulu debug("input->cs_d1 = 0x%x\n", input->cs_d1); 810*91f16700Schasinglulu debug("input->mirror = 0x%x\n", input->mirror); 811*91f16700Schasinglulu debug("PHY ODT impedance = %d ohm\n", input->adv.odtimpedance); 812*91f16700Schasinglulu debug("PHY DQ driver impedance = %d ohm\n", input->adv.tx_impedance); 813*91f16700Schasinglulu debug("PHY Addr driver impedance = %d ohm\n", input->adv.atx_impedance); 814*91f16700Schasinglulu 815*91f16700Schasinglulu for (i = 0; i < 4; i++) { 816*91f16700Schasinglulu debug("odt[%d] = 0x%x\n", i, input->odt[i]); 817*91f16700Schasinglulu } 818*91f16700Schasinglulu 819*91f16700Schasinglulu if (input->basic.dimm_type == RDIMM) { 820*91f16700Schasinglulu for (i = 0; i < 16; i++) { 821*91f16700Schasinglulu debug("input->rcw[%d] = 0x%x\n", i, input->rcw[i]); 822*91f16700Schasinglulu } 823*91f16700Schasinglulu debug("input->rcw3x = 0x%x\n", input->rcw3x); 824*91f16700Schasinglulu } 825*91f16700Schasinglulu } 826*91f16700Schasinglulu 827*91f16700Schasinglulu /* 828*91f16700Schasinglulu * All protocols share the same base structure of message block. 829*91f16700Schasinglulu * RDIMM and LRDIMM have more entries defined than UDIMM. 830*91f16700Schasinglulu * Create message blocks for 1D and 2D training. 831*91f16700Schasinglulu * Update len with message block size. 832*91f16700Schasinglulu */ 833*91f16700Schasinglulu static int phy_gen2_msg_init(void *msg_1d, 834*91f16700Schasinglulu void *msg_2d, 835*91f16700Schasinglulu const struct input *input) 836*91f16700Schasinglulu { 837*91f16700Schasinglulu struct ddr4u1d *msg_blk = msg_1d; 838*91f16700Schasinglulu struct ddr4u2d *msg_blk_2d = msg_2d; 839*91f16700Schasinglulu struct ddr4r1d *msg_blk_r; 840*91f16700Schasinglulu struct ddr4lr1d *msg_blk_lr; 841*91f16700Schasinglulu 842*91f16700Schasinglulu switch (input->basic.dimm_type) { 843*91f16700Schasinglulu case UDIMM: 844*91f16700Schasinglulu case SODIMM: 845*91f16700Schasinglulu case NODIMM: 846*91f16700Schasinglulu msg_blk->dram_type = U(0x2); 847*91f16700Schasinglulu break; 848*91f16700Schasinglulu case RDIMM: 849*91f16700Schasinglulu msg_blk->dram_type = U(0x4); 850*91f16700Schasinglulu break; 851*91f16700Schasinglulu case LRDIMM: 852*91f16700Schasinglulu msg_blk->dram_type = U(0x5); 853*91f16700Schasinglulu break; 854*91f16700Schasinglulu default: 855*91f16700Schasinglulu ERROR("Unsupported DIMM type\n"); 856*91f16700Schasinglulu return -EINVAL; 857*91f16700Schasinglulu } 858*91f16700Schasinglulu msg_blk->pstate = 0U; 859*91f16700Schasinglulu 860*91f16700Schasinglulu /*Enable quickRd2D, a substage of read deskew, to 1D training.*/ 861*91f16700Schasinglulu msg_blk->reserved00 = U(0x20); 862*91f16700Schasinglulu 863*91f16700Schasinglulu /*Enable High-Effort WrDQ1D.*/ 864*91f16700Schasinglulu msg_blk->reserved00 |= U(0x40); 865*91f16700Schasinglulu 866*91f16700Schasinglulu /* Enable 1D extra effort training.*/ 867*91f16700Schasinglulu msg_blk->reserved1c[3] = U(0x3); 868*91f16700Schasinglulu 869*91f16700Schasinglulu if (input->basic.dimm_type == LRDIMM) { 870*91f16700Schasinglulu msg_blk->sequence_ctrl = U(0x3f1f); 871*91f16700Schasinglulu } else { 872*91f16700Schasinglulu msg_blk->sequence_ctrl = U(0x031f); 873*91f16700Schasinglulu } 874*91f16700Schasinglulu msg_blk->phy_config_override = 0U; 875*91f16700Schasinglulu #ifdef DDR_PHY_DEBUG 876*91f16700Schasinglulu msg_blk->hdt_ctrl = U(0x5); 877*91f16700Schasinglulu #else 878*91f16700Schasinglulu msg_blk->hdt_ctrl = U(0xc9); 879*91f16700Schasinglulu #endif 880*91f16700Schasinglulu msg_blk->msg_misc = U(0x0); 881*91f16700Schasinglulu msg_blk->dfimrlmargin = U(0x1); 882*91f16700Schasinglulu msg_blk->phy_vref = input->vref ? input->vref : U(0x61); 883*91f16700Schasinglulu msg_blk->cs_present = input->cs_d0 | input->cs_d1; 884*91f16700Schasinglulu msg_blk->cs_present_d0 = input->cs_d0; 885*91f16700Schasinglulu msg_blk->cs_present_d1 = input->cs_d1; 886*91f16700Schasinglulu if (input->mirror != 0) { 887*91f16700Schasinglulu msg_blk->addr_mirror = U(0x0a); /* odd CS are mirrored */ 888*91f16700Schasinglulu } 889*91f16700Schasinglulu msg_blk->share2dvref_result = 1U; 890*91f16700Schasinglulu 891*91f16700Schasinglulu msg_blk->acsm_odt_ctrl0 = input->odt[0]; 892*91f16700Schasinglulu msg_blk->acsm_odt_ctrl1 = input->odt[1]; 893*91f16700Schasinglulu msg_blk->acsm_odt_ctrl2 = input->odt[2]; 894*91f16700Schasinglulu msg_blk->acsm_odt_ctrl3 = input->odt[3]; 895*91f16700Schasinglulu msg_blk->enabled_dqs = (input->basic.num_active_dbyte_dfi0 + 896*91f16700Schasinglulu input->basic.num_active_dbyte_dfi1) * 8; 897*91f16700Schasinglulu msg_blk->x16present = input->basic.dram_data_width == 0x10 ? 898*91f16700Schasinglulu msg_blk->cs_present : 0; 899*91f16700Schasinglulu msg_blk->d4misc = U(0x1); 900*91f16700Schasinglulu msg_blk->cs_setup_gddec = U(0x1); 901*91f16700Schasinglulu msg_blk->rtt_nom_wr_park0 = 0U; 902*91f16700Schasinglulu msg_blk->rtt_nom_wr_park1 = 0U; 903*91f16700Schasinglulu msg_blk->rtt_nom_wr_park2 = 0U; 904*91f16700Schasinglulu msg_blk->rtt_nom_wr_park3 = 0U; 905*91f16700Schasinglulu msg_blk->rtt_nom_wr_park4 = 0U; 906*91f16700Schasinglulu msg_blk->rtt_nom_wr_park5 = 0U; 907*91f16700Schasinglulu msg_blk->rtt_nom_wr_park6 = 0U; 908*91f16700Schasinglulu msg_blk->rtt_nom_wr_park7 = 0U; 909*91f16700Schasinglulu msg_blk->mr0 = input->mr[0]; 910*91f16700Schasinglulu msg_blk->mr1 = input->mr[1]; 911*91f16700Schasinglulu msg_blk->mr2 = input->mr[2]; 912*91f16700Schasinglulu msg_blk->mr3 = input->mr[3]; 913*91f16700Schasinglulu msg_blk->mr4 = input->mr[4]; 914*91f16700Schasinglulu msg_blk->mr5 = input->mr[5]; 915*91f16700Schasinglulu msg_blk->mr6 = input->mr[6]; 916*91f16700Schasinglulu if ((msg_blk->mr4 & U(0x1c0)) != 0U) { 917*91f16700Schasinglulu ERROR("Setting DRAM CAL mode is not supported\n"); 918*91f16700Schasinglulu } 919*91f16700Schasinglulu 920*91f16700Schasinglulu msg_blk->alt_cas_l = 0U; 921*91f16700Schasinglulu msg_blk->alt_wcas_l = 0U; 922*91f16700Schasinglulu 923*91f16700Schasinglulu msg_blk->dramfreq = input->basic.frequency * 2U; 924*91f16700Schasinglulu msg_blk->pll_bypass_en = input->basic.pll_bypass; 925*91f16700Schasinglulu msg_blk->dfi_freq_ratio = input->basic.dfi_freq_ratio == 0U ? 1U : 926*91f16700Schasinglulu input->basic.dfi_freq_ratio == 1U ? 2U : 927*91f16700Schasinglulu 4U; 928*91f16700Schasinglulu msg_blk->bpznres_val = input->adv.ext_cal_res_val; 929*91f16700Schasinglulu msg_blk->disabled_dbyte = 0U; 930*91f16700Schasinglulu 931*91f16700Schasinglulu debug("msg_blk->dram_type = 0x%x\n", msg_blk->dram_type); 932*91f16700Schasinglulu debug("msg_blk->sequence_ctrl = 0x%x\n", msg_blk->sequence_ctrl); 933*91f16700Schasinglulu debug("msg_blk->phy_cfg = 0x%x\n", msg_blk->phy_cfg); 934*91f16700Schasinglulu debug("msg_blk->x16present = 0x%x\n", msg_blk->x16present); 935*91f16700Schasinglulu debug("msg_blk->dramfreq = 0x%x\n", msg_blk->dramfreq); 936*91f16700Schasinglulu debug("msg_blk->pll_bypass_en = 0x%x\n", msg_blk->pll_bypass_en); 937*91f16700Schasinglulu debug("msg_blk->dfi_freq_ratio = 0x%x\n", msg_blk->dfi_freq_ratio); 938*91f16700Schasinglulu debug("msg_blk->phy_odt_impedance = 0x%x\n", 939*91f16700Schasinglulu msg_blk->phy_odt_impedance); 940*91f16700Schasinglulu debug("msg_blk->phy_drv_impedance = 0x%x\n", 941*91f16700Schasinglulu msg_blk->phy_drv_impedance); 942*91f16700Schasinglulu debug("msg_blk->bpznres_val = 0x%x\n", msg_blk->bpznres_val); 943*91f16700Schasinglulu debug("msg_blk->enabled_dqs = 0x%x\n", msg_blk->enabled_dqs); 944*91f16700Schasinglulu debug("msg_blk->acsm_odt_ctrl0 = 0x%x\n", msg_blk->acsm_odt_ctrl0); 945*91f16700Schasinglulu debug("msg_blk->acsm_odt_ctrl1 = 0x%x\n", msg_blk->acsm_odt_ctrl1); 946*91f16700Schasinglulu debug("msg_blk->acsm_odt_ctrl2 = 0x%x\n", msg_blk->acsm_odt_ctrl2); 947*91f16700Schasinglulu debug("msg_blk->acsm_odt_ctrl3 = 0x%x\n", msg_blk->acsm_odt_ctrl3); 948*91f16700Schasinglulu 949*91f16700Schasinglulu /* RDIMM only */ 950*91f16700Schasinglulu if (input->basic.dimm_type == RDIMM || 951*91f16700Schasinglulu input->basic.dimm_type == LRDIMM) { 952*91f16700Schasinglulu msg_blk_r = (struct ddr4r1d *)msg_blk; 953*91f16700Schasinglulu if (msg_blk_r->cs_present_d0 != 0U) { 954*91f16700Schasinglulu msg_blk_r->f0rc00_d0 = input->rcw[0]; 955*91f16700Schasinglulu msg_blk_r->f0rc01_d0 = input->rcw[1]; 956*91f16700Schasinglulu msg_blk_r->f0rc02_d0 = input->rcw[2]; 957*91f16700Schasinglulu msg_blk_r->f0rc03_d0 = input->rcw[3]; 958*91f16700Schasinglulu msg_blk_r->f0rc04_d0 = input->rcw[4]; 959*91f16700Schasinglulu msg_blk_r->f0rc05_d0 = input->rcw[5]; 960*91f16700Schasinglulu msg_blk_r->f0rc06_d0 = input->rcw[6]; 961*91f16700Schasinglulu msg_blk_r->f0rc07_d0 = input->rcw[7]; 962*91f16700Schasinglulu msg_blk_r->f0rc08_d0 = input->rcw[8]; 963*91f16700Schasinglulu msg_blk_r->f0rc09_d0 = input->rcw[9]; 964*91f16700Schasinglulu msg_blk_r->f0rc0a_d0 = input->rcw[10]; 965*91f16700Schasinglulu msg_blk_r->f0rc0b_d0 = input->rcw[11]; 966*91f16700Schasinglulu msg_blk_r->f0rc0c_d0 = input->rcw[12]; 967*91f16700Schasinglulu msg_blk_r->f0rc0d_d0 = input->rcw[13]; 968*91f16700Schasinglulu msg_blk_r->f0rc0e_d0 = input->rcw[14]; 969*91f16700Schasinglulu msg_blk_r->f0rc0f_d0 = input->rcw[15]; 970*91f16700Schasinglulu msg_blk_r->f0rc3x_d0 = input->rcw3x; 971*91f16700Schasinglulu } 972*91f16700Schasinglulu if (msg_blk_r->cs_present_d1 != 0) { 973*91f16700Schasinglulu msg_blk_r->f0rc00_d1 = input->rcw[0]; 974*91f16700Schasinglulu msg_blk_r->f0rc01_d1 = input->rcw[1]; 975*91f16700Schasinglulu msg_blk_r->f0rc02_d1 = input->rcw[2]; 976*91f16700Schasinglulu msg_blk_r->f0rc03_d1 = input->rcw[3]; 977*91f16700Schasinglulu msg_blk_r->f0rc04_d1 = input->rcw[4]; 978*91f16700Schasinglulu msg_blk_r->f0rc05_d1 = input->rcw[5]; 979*91f16700Schasinglulu msg_blk_r->f0rc06_d1 = input->rcw[6]; 980*91f16700Schasinglulu msg_blk_r->f0rc07_d1 = input->rcw[7]; 981*91f16700Schasinglulu msg_blk_r->f0rc08_d1 = input->rcw[8]; 982*91f16700Schasinglulu msg_blk_r->f0rc09_d1 = input->rcw[9]; 983*91f16700Schasinglulu msg_blk_r->f0rc0a_d1 = input->rcw[10]; 984*91f16700Schasinglulu msg_blk_r->f0rc0b_d1 = input->rcw[11]; 985*91f16700Schasinglulu msg_blk_r->f0rc0c_d1 = input->rcw[12]; 986*91f16700Schasinglulu msg_blk_r->f0rc0d_d1 = input->rcw[13]; 987*91f16700Schasinglulu msg_blk_r->f0rc0e_d1 = input->rcw[14]; 988*91f16700Schasinglulu msg_blk_r->f0rc0f_d1 = input->rcw[15]; 989*91f16700Schasinglulu msg_blk_r->f0rc3x_d1 = input->rcw3x; 990*91f16700Schasinglulu } 991*91f16700Schasinglulu if (input->basic.dimm_type == LRDIMM) { 992*91f16700Schasinglulu msg_blk_lr = (struct ddr4lr1d *)msg_blk; 993*91f16700Schasinglulu msg_blk_lr->bc0a_d0 = msg_blk_lr->f0rc0a_d0; 994*91f16700Schasinglulu msg_blk_lr->bc0a_d1 = msg_blk_lr->f0rc0a_d1; 995*91f16700Schasinglulu msg_blk_lr->f0bc6x_d0 = msg_blk_lr->f0rc3x_d0; 996*91f16700Schasinglulu msg_blk_lr->f0bc6x_d1 = msg_blk_lr->f0rc3x_d1; 997*91f16700Schasinglulu } 998*91f16700Schasinglulu } 999*91f16700Schasinglulu 1000*91f16700Schasinglulu /* below is different for 1D and 2D message block */ 1001*91f16700Schasinglulu if (input->basic.train2d != 0) { 1002*91f16700Schasinglulu memcpy(msg_blk_2d, msg_blk, sizeof(struct ddr4u1d)); 1003*91f16700Schasinglulu /*High-Effort WrDQ1D is applicable to 2D traning also*/ 1004*91f16700Schasinglulu msg_blk_2d->reserved00 |= U(0x40); 1005*91f16700Schasinglulu msg_blk_2d->sequence_ctrl = U(0x0061); 1006*91f16700Schasinglulu msg_blk_2d->rx2d_train_opt = 0U; 1007*91f16700Schasinglulu msg_blk_2d->tx2d_train_opt = 0U; 1008*91f16700Schasinglulu msg_blk_2d->share2dvref_result = 1U; 1009*91f16700Schasinglulu msg_blk_2d->delay_weight2d = U(0x20); 1010*91f16700Schasinglulu msg_blk_2d->voltage_weight2d = U(0x80); 1011*91f16700Schasinglulu debug("rx2d_train_opt %d, tx2d_train_opt %d\n", 1012*91f16700Schasinglulu msg_blk_2d->rx2d_train_opt, 1013*91f16700Schasinglulu msg_blk_2d->tx2d_train_opt); 1014*91f16700Schasinglulu } 1015*91f16700Schasinglulu 1016*91f16700Schasinglulu msg_blk->phy_cfg = (((msg_blk->mr3 & U(0x8)) != 0U) || 1017*91f16700Schasinglulu ((msg_blk_2d->mr3 & 0x8) != 0U)) ? 0U 1018*91f16700Schasinglulu : input->adv.is2ttiming; 1019*91f16700Schasinglulu 1020*91f16700Schasinglulu return 0; 1021*91f16700Schasinglulu } 1022*91f16700Schasinglulu 1023*91f16700Schasinglulu static void prog_tx_pre_drv_mode(uint16_t *phy, 1024*91f16700Schasinglulu const struct input *input) 1025*91f16700Schasinglulu { 1026*91f16700Schasinglulu int lane, byte, b_addr, c_addr, p_addr; 1027*91f16700Schasinglulu int tx_slew_rate, tx_pre_p, tx_pre_n; 1028*91f16700Schasinglulu int tx_pre_drv_mode = 0x2; 1029*91f16700Schasinglulu uint32_t addr; 1030*91f16700Schasinglulu 1031*91f16700Schasinglulu /* Program TxPreDrvMode with 0x2 */ 1032*91f16700Schasinglulu /* FIXME: TxPreDrvMode depends on DramType? */ 1033*91f16700Schasinglulu tx_pre_p = input->adv.tx_slew_rise_dq; 1034*91f16700Schasinglulu tx_pre_n = input->adv.tx_slew_fall_dq; 1035*91f16700Schasinglulu tx_slew_rate = tx_pre_drv_mode << csr_tx_pre_drv_mode_lsb | 1036*91f16700Schasinglulu tx_pre_p << csr_tx_pre_p_lsb | 1037*91f16700Schasinglulu tx_pre_n << csr_tx_pre_n_lsb; 1038*91f16700Schasinglulu p_addr = 0; 1039*91f16700Schasinglulu for (byte = 0; byte < input->basic.num_dbyte; byte++) { 1040*91f16700Schasinglulu c_addr = byte << 12; 1041*91f16700Schasinglulu for (lane = 0; lane <= 1; lane++) { 1042*91f16700Schasinglulu b_addr = lane << 8; 1043*91f16700Schasinglulu addr = p_addr | t_dbyte | c_addr | b_addr | 1044*91f16700Schasinglulu csr_tx_slew_rate_addr; 1045*91f16700Schasinglulu phy_io_write16(phy, addr, tx_slew_rate); 1046*91f16700Schasinglulu } 1047*91f16700Schasinglulu } 1048*91f16700Schasinglulu } 1049*91f16700Schasinglulu 1050*91f16700Schasinglulu static void prog_atx_pre_drv_mode(uint16_t *phy, 1051*91f16700Schasinglulu const struct input *input) 1052*91f16700Schasinglulu { 1053*91f16700Schasinglulu int anib, c_addr; 1054*91f16700Schasinglulu int atx_slew_rate, atx_pre_p, atx_pre_n, atx_pre_drv_mode, 1055*91f16700Schasinglulu ck_anib_inst[2]; 1056*91f16700Schasinglulu uint32_t addr; 1057*91f16700Schasinglulu 1058*91f16700Schasinglulu atx_pre_n = input->adv.tx_slew_fall_ac; 1059*91f16700Schasinglulu atx_pre_p = input->adv.tx_slew_rise_ac; 1060*91f16700Schasinglulu 1061*91f16700Schasinglulu if (input->basic.num_anib == 8) { 1062*91f16700Schasinglulu ck_anib_inst[0] = 1; 1063*91f16700Schasinglulu ck_anib_inst[1] = 1; 1064*91f16700Schasinglulu } else if (input->basic.num_anib == 10 || input->basic.num_anib == 12 || 1065*91f16700Schasinglulu input->basic.num_anib == 13) { 1066*91f16700Schasinglulu ck_anib_inst[0] = 4; 1067*91f16700Schasinglulu ck_anib_inst[1] = 5; 1068*91f16700Schasinglulu } else { 1069*91f16700Schasinglulu ERROR("Invalid number of aNIBs: %d\n", input->basic.num_anib); 1070*91f16700Schasinglulu return; 1071*91f16700Schasinglulu } 1072*91f16700Schasinglulu 1073*91f16700Schasinglulu for (anib = 0; anib < input->basic.num_anib; anib++) { 1074*91f16700Schasinglulu c_addr = anib << 12; 1075*91f16700Schasinglulu if (anib == ck_anib_inst[0] || anib == ck_anib_inst[1]) { 1076*91f16700Schasinglulu atx_pre_drv_mode = 0; 1077*91f16700Schasinglulu } else { 1078*91f16700Schasinglulu atx_pre_drv_mode = 3; 1079*91f16700Schasinglulu } 1080*91f16700Schasinglulu atx_slew_rate = atx_pre_drv_mode << csr_atx_pre_drv_mode_lsb | 1081*91f16700Schasinglulu atx_pre_n << csr_atx_pre_n_lsb | 1082*91f16700Schasinglulu atx_pre_p << csr_atx_pre_p_lsb; 1083*91f16700Schasinglulu addr = t_anib | c_addr | csr_atx_slew_rate_addr; 1084*91f16700Schasinglulu phy_io_write16(phy, addr, atx_slew_rate); 1085*91f16700Schasinglulu } 1086*91f16700Schasinglulu } 1087*91f16700Schasinglulu 1088*91f16700Schasinglulu static void prog_enable_cs_multicast(uint16_t *phy, 1089*91f16700Schasinglulu const struct input *input) 1090*91f16700Schasinglulu { 1091*91f16700Schasinglulu uint32_t addr = t_master | csr_enable_cs_multicast_addr; 1092*91f16700Schasinglulu 1093*91f16700Schasinglulu if (input->basic.dimm_type != RDIMM && 1094*91f16700Schasinglulu input->basic.dimm_type != LRDIMM) { 1095*91f16700Schasinglulu return; 1096*91f16700Schasinglulu } 1097*91f16700Schasinglulu 1098*91f16700Schasinglulu phy_io_write16(phy, addr, input->adv.cast_cs_to_cid); 1099*91f16700Schasinglulu } 1100*91f16700Schasinglulu 1101*91f16700Schasinglulu static void prog_dfi_rd_data_cs_dest_map(uint16_t *phy, 1102*91f16700Schasinglulu unsigned int ip_rev, 1103*91f16700Schasinglulu const struct input *input, 1104*91f16700Schasinglulu const struct ddr4lr1d *msg) 1105*91f16700Schasinglulu { 1106*91f16700Schasinglulu const struct ddr4lr1d *msg_blk; 1107*91f16700Schasinglulu uint16_t dfi_xxdestm0 = 0U; 1108*91f16700Schasinglulu uint16_t dfi_xxdestm1 = 0U; 1109*91f16700Schasinglulu uint16_t dfi_xxdestm2 = 0U; 1110*91f16700Schasinglulu uint16_t dfi_xxdestm3 = 0U; 1111*91f16700Schasinglulu uint16_t dfi_rd_data_cs_dest_map; 1112*91f16700Schasinglulu uint16_t dfi_wr_data_cs_dest_map; 1113*91f16700Schasinglulu __unused const soc_info_t *soc_info; 1114*91f16700Schasinglulu 1115*91f16700Schasinglulu #ifdef ERRATA_DDR_A011396 1116*91f16700Schasinglulu /* Only apply to DDRC 5.05.00 */ 1117*91f16700Schasinglulu soc_info = get_soc_info(); 1118*91f16700Schasinglulu if ((soc_info->svr_reg.bf.maj_ver == 1U) && (ip_rev == U(0x50500))) { 1119*91f16700Schasinglulu phy_io_write16(phy, 1120*91f16700Schasinglulu t_master | csr_dfi_rd_data_cs_dest_map_addr, 1121*91f16700Schasinglulu 0U); 1122*91f16700Schasinglulu return; 1123*91f16700Schasinglulu } 1124*91f16700Schasinglulu #endif 1125*91f16700Schasinglulu 1126*91f16700Schasinglulu msg_blk = msg; 1127*91f16700Schasinglulu 1128*91f16700Schasinglulu switch (input->basic.dimm_type) { 1129*91f16700Schasinglulu case UDIMM: 1130*91f16700Schasinglulu case SODIMM: 1131*91f16700Schasinglulu case NODIMM: 1132*91f16700Schasinglulu if ((msg_blk->msg_misc & U(0x40)) != 0U) { 1133*91f16700Schasinglulu dfi_rd_data_cs_dest_map = U(0xa0); 1134*91f16700Schasinglulu dfi_wr_data_cs_dest_map = U(0xa0); 1135*91f16700Schasinglulu 1136*91f16700Schasinglulu phy_io_write16(phy, 1137*91f16700Schasinglulu t_master | csr_dfi_rd_data_cs_dest_map_addr, 1138*91f16700Schasinglulu dfi_rd_data_cs_dest_map); 1139*91f16700Schasinglulu phy_io_write16(phy, 1140*91f16700Schasinglulu t_master | csr_dfi_wr_data_cs_dest_map_addr, 1141*91f16700Schasinglulu dfi_wr_data_cs_dest_map); 1142*91f16700Schasinglulu } 1143*91f16700Schasinglulu break; 1144*91f16700Schasinglulu case LRDIMM: 1145*91f16700Schasinglulu if (msg->cs_present_d1 != 0U) { 1146*91f16700Schasinglulu dfi_xxdestm2 = 1U; 1147*91f16700Schasinglulu dfi_xxdestm3 = 1U; 1148*91f16700Schasinglulu } 1149*91f16700Schasinglulu 1150*91f16700Schasinglulu dfi_rd_data_cs_dest_map = 1151*91f16700Schasinglulu dfi_xxdestm0 << csr_dfi_rd_destm0_lsb | 1152*91f16700Schasinglulu dfi_xxdestm1 << csr_dfi_rd_destm1_lsb | 1153*91f16700Schasinglulu dfi_xxdestm2 << csr_dfi_rd_destm2_lsb | 1154*91f16700Schasinglulu dfi_xxdestm3 << csr_dfi_rd_destm3_lsb; 1155*91f16700Schasinglulu dfi_wr_data_cs_dest_map = 1156*91f16700Schasinglulu dfi_xxdestm0 << csr_dfi_wr_destm0_lsb | 1157*91f16700Schasinglulu dfi_xxdestm1 << csr_dfi_wr_destm1_lsb | 1158*91f16700Schasinglulu dfi_xxdestm2 << csr_dfi_wr_destm2_lsb | 1159*91f16700Schasinglulu dfi_xxdestm3 << csr_dfi_wr_destm3_lsb; 1160*91f16700Schasinglulu phy_io_write16(phy, t_master | csr_dfi_rd_data_cs_dest_map_addr, 1161*91f16700Schasinglulu dfi_rd_data_cs_dest_map); 1162*91f16700Schasinglulu phy_io_write16(phy, t_master | csr_dfi_wr_data_cs_dest_map_addr, 1163*91f16700Schasinglulu dfi_wr_data_cs_dest_map); 1164*91f16700Schasinglulu 1165*91f16700Schasinglulu break; 1166*91f16700Schasinglulu default: 1167*91f16700Schasinglulu break; 1168*91f16700Schasinglulu } 1169*91f16700Schasinglulu } 1170*91f16700Schasinglulu 1171*91f16700Schasinglulu static void prog_pll_ctrl(uint16_t *phy, 1172*91f16700Schasinglulu const struct input *input) 1173*91f16700Schasinglulu { 1174*91f16700Schasinglulu uint32_t addr; 1175*91f16700Schasinglulu int pll_ctrl1 = 0x21; /* 000100001b */ 1176*91f16700Schasinglulu int pll_ctrl4 = 0x17f; /* 101111111b */ 1177*91f16700Schasinglulu int pll_test_mode = 0x24; /* 00100100b */ 1178*91f16700Schasinglulu 1179*91f16700Schasinglulu addr = t_master | csr_pll_ctrl1_addr; 1180*91f16700Schasinglulu phy_io_write16(phy, addr, pll_ctrl1); 1181*91f16700Schasinglulu 1182*91f16700Schasinglulu debug("pll_ctrl1 = 0x%x\n", phy_io_read16(phy, addr)); 1183*91f16700Schasinglulu 1184*91f16700Schasinglulu addr = t_master | csr_pll_test_mode_addr; 1185*91f16700Schasinglulu phy_io_write16(phy, addr, pll_test_mode); 1186*91f16700Schasinglulu 1187*91f16700Schasinglulu debug("pll_test_mode = 0x%x\n", phy_io_read16(phy, addr)); 1188*91f16700Schasinglulu 1189*91f16700Schasinglulu addr = t_master | csr_pll_ctrl4_addr; 1190*91f16700Schasinglulu phy_io_write16(phy, addr, pll_ctrl4); 1191*91f16700Schasinglulu 1192*91f16700Schasinglulu debug("pll_ctrl4 = 0x%x\n", phy_io_read16(phy, addr)); 1193*91f16700Schasinglulu } 1194*91f16700Schasinglulu 1195*91f16700Schasinglulu static void prog_pll_ctrl2(uint16_t *phy, 1196*91f16700Schasinglulu const struct input *input) 1197*91f16700Schasinglulu { 1198*91f16700Schasinglulu int pll_ctrl2; 1199*91f16700Schasinglulu uint32_t addr = t_master | csr_pll_ctrl2_addr; 1200*91f16700Schasinglulu 1201*91f16700Schasinglulu if (input->basic.frequency / 2 < 235) { 1202*91f16700Schasinglulu pll_ctrl2 = 0x7; 1203*91f16700Schasinglulu } else if (input->basic.frequency / 2 < 313) { 1204*91f16700Schasinglulu pll_ctrl2 = 0x6; 1205*91f16700Schasinglulu } else if (input->basic.frequency / 2 < 469) { 1206*91f16700Schasinglulu pll_ctrl2 = 0xb; 1207*91f16700Schasinglulu } else if (input->basic.frequency / 2 < 625) { 1208*91f16700Schasinglulu pll_ctrl2 = 0xa; 1209*91f16700Schasinglulu } else if (input->basic.frequency / 2 < 938) { 1210*91f16700Schasinglulu pll_ctrl2 = 0x19; 1211*91f16700Schasinglulu } else if (input->basic.frequency / 2 < 1067) { 1212*91f16700Schasinglulu pll_ctrl2 = 0x18; 1213*91f16700Schasinglulu } else { 1214*91f16700Schasinglulu pll_ctrl2 = 0x19; 1215*91f16700Schasinglulu } 1216*91f16700Schasinglulu 1217*91f16700Schasinglulu phy_io_write16(phy, addr, pll_ctrl2); 1218*91f16700Schasinglulu 1219*91f16700Schasinglulu debug("pll_ctrl2 = 0x%x\n", phy_io_read16(phy, addr)); 1220*91f16700Schasinglulu } 1221*91f16700Schasinglulu 1222*91f16700Schasinglulu static void prog_dll_lck_param(uint16_t *phy, const struct input *input) 1223*91f16700Schasinglulu { 1224*91f16700Schasinglulu uint32_t addr = t_master | csr_dll_lockparam_addr; 1225*91f16700Schasinglulu 1226*91f16700Schasinglulu phy_io_write16(phy, addr, U(0x212)); 1227*91f16700Schasinglulu debug("dll_lck_param = 0x%x\n", phy_io_read16(phy, addr)); 1228*91f16700Schasinglulu } 1229*91f16700Schasinglulu 1230*91f16700Schasinglulu static void prog_dll_gain_ctl(uint16_t *phy, const struct input *input) 1231*91f16700Schasinglulu { 1232*91f16700Schasinglulu uint32_t addr = t_master | csr_dll_gain_ctl_addr; 1233*91f16700Schasinglulu 1234*91f16700Schasinglulu phy_io_write16(phy, addr, U(0x61)); 1235*91f16700Schasinglulu debug("dll_gain_ctl = 0x%x\n", phy_io_read16(phy, addr)); 1236*91f16700Schasinglulu } 1237*91f16700Schasinglulu 1238*91f16700Schasinglulu static void prog_pll_pwr_dn(uint16_t *phy, 1239*91f16700Schasinglulu const struct input *input) 1240*91f16700Schasinglulu { 1241*91f16700Schasinglulu uint32_t addr; 1242*91f16700Schasinglulu 1243*91f16700Schasinglulu addr = t_master | csr_pll_pwr_dn_addr; 1244*91f16700Schasinglulu phy_io_write16(phy, addr, 0U); 1245*91f16700Schasinglulu 1246*91f16700Schasinglulu debug("pll_pwrdn = 0x%x\n", phy_io_read16(phy, addr)); 1247*91f16700Schasinglulu } 1248*91f16700Schasinglulu 1249*91f16700Schasinglulu static void prog_ard_ptr_init_val(uint16_t *phy, 1250*91f16700Schasinglulu const struct input *input) 1251*91f16700Schasinglulu { 1252*91f16700Schasinglulu int ard_ptr_init_val; 1253*91f16700Schasinglulu uint32_t addr = t_master | csr_ard_ptr_init_val_addr; 1254*91f16700Schasinglulu 1255*91f16700Schasinglulu if (input->basic.frequency >= 933) { 1256*91f16700Schasinglulu ard_ptr_init_val = 0x2; 1257*91f16700Schasinglulu } else { 1258*91f16700Schasinglulu ard_ptr_init_val = 0x1; 1259*91f16700Schasinglulu } 1260*91f16700Schasinglulu 1261*91f16700Schasinglulu phy_io_write16(phy, addr, ard_ptr_init_val); 1262*91f16700Schasinglulu } 1263*91f16700Schasinglulu 1264*91f16700Schasinglulu static void prog_dqs_preamble_control(uint16_t *phy, 1265*91f16700Schasinglulu const struct input *input) 1266*91f16700Schasinglulu { 1267*91f16700Schasinglulu int data; 1268*91f16700Schasinglulu uint32_t addr = t_master | csr_dqs_preamble_control_addr; 1269*91f16700Schasinglulu const int wdqsextension = 0; 1270*91f16700Schasinglulu const int lp4sttc_pre_bridge_rx_en = 0; 1271*91f16700Schasinglulu const int lp4postamble_ext = 0; 1272*91f16700Schasinglulu const int lp4tgl_two_tck_tx_dqs_pre = 0; 1273*91f16700Schasinglulu const int position_dfe_init = 2; 1274*91f16700Schasinglulu const int dll_rx_preamble_mode = 1; 1275*91f16700Schasinglulu int two_tck_tx_dqs_pre = input->adv.d4tx_preamble_length; 1276*91f16700Schasinglulu int two_tck_rx_dqs_pre = input->adv.d4rx_preamble_length; 1277*91f16700Schasinglulu 1278*91f16700Schasinglulu data = wdqsextension << csr_wdqsextension_lsb | 1279*91f16700Schasinglulu lp4sttc_pre_bridge_rx_en << csr_lp4sttc_pre_bridge_rx_en_lsb | 1280*91f16700Schasinglulu lp4postamble_ext << csr_lp4postamble_ext_lsb | 1281*91f16700Schasinglulu lp4tgl_two_tck_tx_dqs_pre << csr_lp4tgl_two_tck_tx_dqs_pre_lsb | 1282*91f16700Schasinglulu position_dfe_init << csr_position_dfe_init_lsb | 1283*91f16700Schasinglulu two_tck_tx_dqs_pre << csr_two_tck_tx_dqs_pre_lsb | 1284*91f16700Schasinglulu two_tck_rx_dqs_pre << csr_two_tck_rx_dqs_pre_lsb; 1285*91f16700Schasinglulu phy_io_write16(phy, addr, data); 1286*91f16700Schasinglulu 1287*91f16700Schasinglulu data = dll_rx_preamble_mode << csr_dll_rx_preamble_mode_lsb; 1288*91f16700Schasinglulu addr = t_master | csr_dbyte_dll_mode_cntrl_addr; 1289*91f16700Schasinglulu phy_io_write16(phy, addr, data); 1290*91f16700Schasinglulu } 1291*91f16700Schasinglulu 1292*91f16700Schasinglulu static void prog_proc_odt_time_ctl(uint16_t *phy, 1293*91f16700Schasinglulu const struct input *input) 1294*91f16700Schasinglulu { 1295*91f16700Schasinglulu int proc_odt_time_ctl; 1296*91f16700Schasinglulu uint32_t addr = t_master | csr_proc_odt_time_ctl_addr; 1297*91f16700Schasinglulu 1298*91f16700Schasinglulu if (input->adv.wdqsext != 0) { 1299*91f16700Schasinglulu proc_odt_time_ctl = 0x3; 1300*91f16700Schasinglulu } else if (input->basic.frequency <= 933) { 1301*91f16700Schasinglulu proc_odt_time_ctl = 0xa; 1302*91f16700Schasinglulu } else if (input->basic.frequency <= 1200) { 1303*91f16700Schasinglulu if (input->adv.d4rx_preamble_length == 1) { 1304*91f16700Schasinglulu proc_odt_time_ctl = 0x2; 1305*91f16700Schasinglulu } else { 1306*91f16700Schasinglulu proc_odt_time_ctl = 0x6; 1307*91f16700Schasinglulu } 1308*91f16700Schasinglulu } else { 1309*91f16700Schasinglulu if (input->adv.d4rx_preamble_length == 1) { 1310*91f16700Schasinglulu proc_odt_time_ctl = 0x3; 1311*91f16700Schasinglulu } else { 1312*91f16700Schasinglulu proc_odt_time_ctl = 0x7; 1313*91f16700Schasinglulu } 1314*91f16700Schasinglulu } 1315*91f16700Schasinglulu phy_io_write16(phy, addr, proc_odt_time_ctl); 1316*91f16700Schasinglulu } 1317*91f16700Schasinglulu 1318*91f16700Schasinglulu static const struct impedance_mapping map[] = { 1319*91f16700Schasinglulu { 29, 0x3f }, 1320*91f16700Schasinglulu { 31, 0x3e }, 1321*91f16700Schasinglulu { 33, 0x3b }, 1322*91f16700Schasinglulu { 36, 0x3a }, 1323*91f16700Schasinglulu { 39, 0x39 }, 1324*91f16700Schasinglulu { 42, 0x38 }, 1325*91f16700Schasinglulu { 46, 0x1b }, 1326*91f16700Schasinglulu { 51, 0x1a }, 1327*91f16700Schasinglulu { 57, 0x19 }, 1328*91f16700Schasinglulu { 64, 0x18 }, 1329*91f16700Schasinglulu { 74, 0x0b }, 1330*91f16700Schasinglulu { 88, 0x0a }, 1331*91f16700Schasinglulu { 108, 0x09 }, 1332*91f16700Schasinglulu { 140, 0x08 }, 1333*91f16700Schasinglulu { 200, 0x03 }, 1334*91f16700Schasinglulu { 360, 0x02 }, 1335*91f16700Schasinglulu { 481, 0x01 }, 1336*91f16700Schasinglulu {} 1337*91f16700Schasinglulu }; 1338*91f16700Schasinglulu 1339*91f16700Schasinglulu static int map_impedance(int strength) 1340*91f16700Schasinglulu { 1341*91f16700Schasinglulu const struct impedance_mapping *tbl = map; 1342*91f16700Schasinglulu int val = 0; 1343*91f16700Schasinglulu 1344*91f16700Schasinglulu if (strength == 0) { 1345*91f16700Schasinglulu return 0; 1346*91f16700Schasinglulu } 1347*91f16700Schasinglulu 1348*91f16700Schasinglulu while (tbl->ohm != 0U) { 1349*91f16700Schasinglulu if (strength < tbl->ohm) { 1350*91f16700Schasinglulu val = tbl->code; 1351*91f16700Schasinglulu break; 1352*91f16700Schasinglulu } 1353*91f16700Schasinglulu tbl++; 1354*91f16700Schasinglulu } 1355*91f16700Schasinglulu 1356*91f16700Schasinglulu return val; 1357*91f16700Schasinglulu } 1358*91f16700Schasinglulu 1359*91f16700Schasinglulu static int map_odtstren_p(int strength, int hard_macro_ver) 1360*91f16700Schasinglulu { 1361*91f16700Schasinglulu int val = -1; 1362*91f16700Schasinglulu 1363*91f16700Schasinglulu if (hard_macro_ver == 4) { 1364*91f16700Schasinglulu if (strength == 0) { 1365*91f16700Schasinglulu val = 0; 1366*91f16700Schasinglulu } else if (strength == 120) { 1367*91f16700Schasinglulu val = 0x8; 1368*91f16700Schasinglulu } else if (strength == 60) { 1369*91f16700Schasinglulu val = 0x18; 1370*91f16700Schasinglulu } else if (strength == 40) { 1371*91f16700Schasinglulu val = 0x38; 1372*91f16700Schasinglulu } else { 1373*91f16700Schasinglulu printf("error: unsupported ODTStrenP %d\n", strength); 1374*91f16700Schasinglulu } 1375*91f16700Schasinglulu } else { 1376*91f16700Schasinglulu val = map_impedance(strength); 1377*91f16700Schasinglulu } 1378*91f16700Schasinglulu 1379*91f16700Schasinglulu return val; 1380*91f16700Schasinglulu } 1381*91f16700Schasinglulu 1382*91f16700Schasinglulu static void prog_tx_odt_drv_stren(uint16_t *phy, 1383*91f16700Schasinglulu const struct input *input) 1384*91f16700Schasinglulu { 1385*91f16700Schasinglulu int lane, byte, b_addr, c_addr; 1386*91f16700Schasinglulu int tx_odt_drv_stren; 1387*91f16700Schasinglulu int odtstren_p, odtstren_n; 1388*91f16700Schasinglulu uint32_t addr; 1389*91f16700Schasinglulu 1390*91f16700Schasinglulu odtstren_p = map_odtstren_p(input->adv.odtimpedance, 1391*91f16700Schasinglulu input->basic.hard_macro_ver); 1392*91f16700Schasinglulu if (odtstren_p < 0) { 1393*91f16700Schasinglulu return; 1394*91f16700Schasinglulu } 1395*91f16700Schasinglulu 1396*91f16700Schasinglulu odtstren_n = 0; /* always high-z */ 1397*91f16700Schasinglulu tx_odt_drv_stren = odtstren_n << csr_odtstren_n_lsb | odtstren_p; 1398*91f16700Schasinglulu for (byte = 0; byte < input->basic.num_dbyte; byte++) { 1399*91f16700Schasinglulu c_addr = byte << 12; 1400*91f16700Schasinglulu for (lane = 0; lane <= 1; lane++) { 1401*91f16700Schasinglulu b_addr = lane << 8; 1402*91f16700Schasinglulu addr = t_dbyte | c_addr | b_addr | 1403*91f16700Schasinglulu csr_tx_odt_drv_stren_addr; 1404*91f16700Schasinglulu phy_io_write16(phy, addr, tx_odt_drv_stren); 1405*91f16700Schasinglulu } 1406*91f16700Schasinglulu } 1407*91f16700Schasinglulu } 1408*91f16700Schasinglulu 1409*91f16700Schasinglulu static int map_drvstren_fsdq_p(int strength, int hard_macro_ver) 1410*91f16700Schasinglulu { 1411*91f16700Schasinglulu int val = -1; 1412*91f16700Schasinglulu 1413*91f16700Schasinglulu if (hard_macro_ver == 4) { 1414*91f16700Schasinglulu if (strength == 0) { 1415*91f16700Schasinglulu val = 0x07; 1416*91f16700Schasinglulu } else if (strength == 120) { 1417*91f16700Schasinglulu val = 0x0F; 1418*91f16700Schasinglulu } else if (strength == 60) { 1419*91f16700Schasinglulu val = 0x1F; 1420*91f16700Schasinglulu } else if (strength == 40) { 1421*91f16700Schasinglulu val = 0x3F; 1422*91f16700Schasinglulu } else { 1423*91f16700Schasinglulu printf("error: unsupported drv_stren_fSDq_p %d\n", 1424*91f16700Schasinglulu strength); 1425*91f16700Schasinglulu } 1426*91f16700Schasinglulu } else { 1427*91f16700Schasinglulu val = map_impedance(strength); 1428*91f16700Schasinglulu } 1429*91f16700Schasinglulu 1430*91f16700Schasinglulu return val; 1431*91f16700Schasinglulu } 1432*91f16700Schasinglulu 1433*91f16700Schasinglulu static int map_drvstren_fsdq_n(int strength, int hard_macro_ver) 1434*91f16700Schasinglulu { 1435*91f16700Schasinglulu int val = -1; 1436*91f16700Schasinglulu 1437*91f16700Schasinglulu if (hard_macro_ver == 4) { 1438*91f16700Schasinglulu if (strength == 0) { 1439*91f16700Schasinglulu val = 0x00; 1440*91f16700Schasinglulu } else if (strength == 120) { 1441*91f16700Schasinglulu val = 0x08; 1442*91f16700Schasinglulu } else if (strength == 60) { 1443*91f16700Schasinglulu val = 0x18; 1444*91f16700Schasinglulu } else if (strength == 40) { 1445*91f16700Schasinglulu val = 0x38; 1446*91f16700Schasinglulu } else { 1447*91f16700Schasinglulu printf("error: unsupported drvStrenFSDqN %d\n", 1448*91f16700Schasinglulu strength); 1449*91f16700Schasinglulu } 1450*91f16700Schasinglulu } else { 1451*91f16700Schasinglulu val = map_impedance(strength); 1452*91f16700Schasinglulu } 1453*91f16700Schasinglulu 1454*91f16700Schasinglulu return val; 1455*91f16700Schasinglulu } 1456*91f16700Schasinglulu 1457*91f16700Schasinglulu static void prog_tx_impedance_ctrl1(uint16_t *phy, 1458*91f16700Schasinglulu const struct input *input) 1459*91f16700Schasinglulu { 1460*91f16700Schasinglulu int lane, byte, b_addr, c_addr; 1461*91f16700Schasinglulu int tx_impedance_ctrl1; 1462*91f16700Schasinglulu int drv_stren_fsdq_p, drv_stren_fsdq_n; 1463*91f16700Schasinglulu uint32_t addr; 1464*91f16700Schasinglulu 1465*91f16700Schasinglulu drv_stren_fsdq_p = map_drvstren_fsdq_p(input->adv.tx_impedance, 1466*91f16700Schasinglulu input->basic.hard_macro_ver); 1467*91f16700Schasinglulu drv_stren_fsdq_n = map_drvstren_fsdq_n(input->adv.tx_impedance, 1468*91f16700Schasinglulu input->basic.hard_macro_ver); 1469*91f16700Schasinglulu tx_impedance_ctrl1 = drv_stren_fsdq_n << csr_drv_stren_fsdq_n_lsb | 1470*91f16700Schasinglulu drv_stren_fsdq_p << csr_drv_stren_fsdq_p_lsb; 1471*91f16700Schasinglulu 1472*91f16700Schasinglulu for (byte = 0; byte < input->basic.num_dbyte; byte++) { 1473*91f16700Schasinglulu c_addr = byte << 12; 1474*91f16700Schasinglulu for (lane = 0; lane <= 1; lane++) { 1475*91f16700Schasinglulu b_addr = lane << 8; 1476*91f16700Schasinglulu addr = t_dbyte | c_addr | b_addr | 1477*91f16700Schasinglulu csr_tx_impedance_ctrl1_addr; 1478*91f16700Schasinglulu phy_io_write16(phy, addr, tx_impedance_ctrl1); 1479*91f16700Schasinglulu } 1480*91f16700Schasinglulu } 1481*91f16700Schasinglulu } 1482*91f16700Schasinglulu 1483*91f16700Schasinglulu static int map_adrv_stren_p(int strength, int hard_macro_ver) 1484*91f16700Schasinglulu { 1485*91f16700Schasinglulu int val = -1; 1486*91f16700Schasinglulu 1487*91f16700Schasinglulu if (hard_macro_ver == 4) { 1488*91f16700Schasinglulu if (strength == 120) { 1489*91f16700Schasinglulu val = 0x1c; 1490*91f16700Schasinglulu } else if (strength == 60) { 1491*91f16700Schasinglulu val = 0x1d; 1492*91f16700Schasinglulu } else if (strength == 40) { 1493*91f16700Schasinglulu val = 0x1f; 1494*91f16700Schasinglulu } else { 1495*91f16700Schasinglulu printf("error: unsupported aDrv_stren_p %d\n", 1496*91f16700Schasinglulu strength); 1497*91f16700Schasinglulu } 1498*91f16700Schasinglulu } else { 1499*91f16700Schasinglulu if (strength == 120) { 1500*91f16700Schasinglulu val = 0x00; 1501*91f16700Schasinglulu } else if (strength == 60) { 1502*91f16700Schasinglulu val = 0x01; 1503*91f16700Schasinglulu } else if (strength == 40) { 1504*91f16700Schasinglulu val = 0x03; 1505*91f16700Schasinglulu } else if (strength == 30) { 1506*91f16700Schasinglulu val = 0x07; 1507*91f16700Schasinglulu } else if (strength == 24) { 1508*91f16700Schasinglulu val = 0x0f; 1509*91f16700Schasinglulu } else if (strength == 20) { 1510*91f16700Schasinglulu val = 0x1f; 1511*91f16700Schasinglulu } else { 1512*91f16700Schasinglulu printf("error: unsupported aDrv_stren_p %d\n", 1513*91f16700Schasinglulu strength); 1514*91f16700Schasinglulu } 1515*91f16700Schasinglulu } 1516*91f16700Schasinglulu 1517*91f16700Schasinglulu return val; 1518*91f16700Schasinglulu } 1519*91f16700Schasinglulu 1520*91f16700Schasinglulu static int map_adrv_stren_n(int strength, int hard_macro_ver) 1521*91f16700Schasinglulu { 1522*91f16700Schasinglulu int val = -1; 1523*91f16700Schasinglulu 1524*91f16700Schasinglulu if (hard_macro_ver == 4) { 1525*91f16700Schasinglulu if (strength == 120) { 1526*91f16700Schasinglulu val = 0x00; 1527*91f16700Schasinglulu } else if (strength == 60) { 1528*91f16700Schasinglulu val = 0x01; 1529*91f16700Schasinglulu } else if (strength == 40) { 1530*91f16700Schasinglulu val = 0x03; 1531*91f16700Schasinglulu } else { 1532*91f16700Schasinglulu printf("Error: unsupported ADrvStrenP %d\n", strength); 1533*91f16700Schasinglulu } 1534*91f16700Schasinglulu } else { 1535*91f16700Schasinglulu if (strength == 120) { 1536*91f16700Schasinglulu val = 0x00; 1537*91f16700Schasinglulu } else if (strength == 60) { 1538*91f16700Schasinglulu val = 0x01; 1539*91f16700Schasinglulu } else if (strength == 40) { 1540*91f16700Schasinglulu val = 0x03; 1541*91f16700Schasinglulu } else if (strength == 30) { 1542*91f16700Schasinglulu val = 0x07; 1543*91f16700Schasinglulu } else if (strength == 24) { 1544*91f16700Schasinglulu val = 0x0f; 1545*91f16700Schasinglulu } else if (strength == 20) { 1546*91f16700Schasinglulu val = 0x1f; 1547*91f16700Schasinglulu } else { 1548*91f16700Schasinglulu printf("Error: unsupported ADrvStrenP %d\n", strength); 1549*91f16700Schasinglulu } 1550*91f16700Schasinglulu } 1551*91f16700Schasinglulu 1552*91f16700Schasinglulu return val; 1553*91f16700Schasinglulu } 1554*91f16700Schasinglulu 1555*91f16700Schasinglulu static void prog_atx_impedance(uint16_t *phy, 1556*91f16700Schasinglulu const struct input *input) 1557*91f16700Schasinglulu { 1558*91f16700Schasinglulu int anib, c_addr; 1559*91f16700Schasinglulu int atx_impedance; 1560*91f16700Schasinglulu int adrv_stren_p; 1561*91f16700Schasinglulu int adrv_stren_n; 1562*91f16700Schasinglulu uint32_t addr; 1563*91f16700Schasinglulu 1564*91f16700Schasinglulu if (input->basic.hard_macro_ver == 4 && 1565*91f16700Schasinglulu input->adv.atx_impedance == 20) { 1566*91f16700Schasinglulu printf("Error:ATxImpedance has to be 40 for HardMacroVer 4\n"); 1567*91f16700Schasinglulu return; 1568*91f16700Schasinglulu } 1569*91f16700Schasinglulu 1570*91f16700Schasinglulu adrv_stren_p = map_adrv_stren_p(input->adv.atx_impedance, 1571*91f16700Schasinglulu input->basic.hard_macro_ver); 1572*91f16700Schasinglulu adrv_stren_n = map_adrv_stren_n(input->adv.atx_impedance, 1573*91f16700Schasinglulu input->basic.hard_macro_ver); 1574*91f16700Schasinglulu atx_impedance = adrv_stren_n << csr_adrv_stren_n_lsb | 1575*91f16700Schasinglulu adrv_stren_p << csr_adrv_stren_p_lsb; 1576*91f16700Schasinglulu for (anib = 0; anib < input->basic.num_anib; anib++) { 1577*91f16700Schasinglulu c_addr = anib << 12; 1578*91f16700Schasinglulu addr = t_anib | c_addr | csr_atx_impedance_addr; 1579*91f16700Schasinglulu phy_io_write16(phy, addr, atx_impedance); 1580*91f16700Schasinglulu } 1581*91f16700Schasinglulu } 1582*91f16700Schasinglulu 1583*91f16700Schasinglulu static void prog_dfi_mode(uint16_t *phy, 1584*91f16700Schasinglulu const struct input *input) 1585*91f16700Schasinglulu { 1586*91f16700Schasinglulu int dfi_mode; 1587*91f16700Schasinglulu uint32_t addr; 1588*91f16700Schasinglulu 1589*91f16700Schasinglulu if (input->basic.dfi1exists == 1) { 1590*91f16700Schasinglulu dfi_mode = 0x5; /* DFI1 exists but disabled */ 1591*91f16700Schasinglulu } else { 1592*91f16700Schasinglulu dfi_mode = 0x1; /* DFI1 does not physically exists */ 1593*91f16700Schasinglulu } 1594*91f16700Schasinglulu addr = t_master | csr_dfi_mode_addr; 1595*91f16700Schasinglulu phy_io_write16(phy, addr, dfi_mode); 1596*91f16700Schasinglulu } 1597*91f16700Schasinglulu 1598*91f16700Schasinglulu static void prog_acx4_anib_dis(uint16_t *phy, const struct input *input) 1599*91f16700Schasinglulu { 1600*91f16700Schasinglulu uint32_t addr; 1601*91f16700Schasinglulu 1602*91f16700Schasinglulu addr = t_master | csr_acx4_anib_dis_addr; 1603*91f16700Schasinglulu phy_io_write16(phy, addr, 0x0); 1604*91f16700Schasinglulu debug("%s 0x%x\n", __func__, phy_io_read16(phy, addr)); 1605*91f16700Schasinglulu } 1606*91f16700Schasinglulu 1607*91f16700Schasinglulu static void prog_dfi_camode(uint16_t *phy, 1608*91f16700Schasinglulu const struct input *input) 1609*91f16700Schasinglulu { 1610*91f16700Schasinglulu int dfi_camode = 2; 1611*91f16700Schasinglulu uint32_t addr = t_master | csr_dfi_camode_addr; 1612*91f16700Schasinglulu 1613*91f16700Schasinglulu phy_io_write16(phy, addr, dfi_camode); 1614*91f16700Schasinglulu } 1615*91f16700Schasinglulu 1616*91f16700Schasinglulu static void prog_cal_drv_str0(uint16_t *phy, 1617*91f16700Schasinglulu const struct input *input) 1618*91f16700Schasinglulu { 1619*91f16700Schasinglulu int cal_drv_str0; 1620*91f16700Schasinglulu int cal_drv_str_pd50; 1621*91f16700Schasinglulu int cal_drv_str_pu50; 1622*91f16700Schasinglulu uint32_t addr; 1623*91f16700Schasinglulu 1624*91f16700Schasinglulu cal_drv_str_pu50 = input->adv.ext_cal_res_val; 1625*91f16700Schasinglulu cal_drv_str_pd50 = cal_drv_str_pu50; 1626*91f16700Schasinglulu cal_drv_str0 = cal_drv_str_pu50 << csr_cal_drv_str_pu50_lsb | 1627*91f16700Schasinglulu cal_drv_str_pd50; 1628*91f16700Schasinglulu addr = t_master | csr_cal_drv_str0_addr; 1629*91f16700Schasinglulu phy_io_write16(phy, addr, cal_drv_str0); 1630*91f16700Schasinglulu } 1631*91f16700Schasinglulu 1632*91f16700Schasinglulu static void prog_cal_uclk_info(uint16_t *phy, 1633*91f16700Schasinglulu const struct input *input) 1634*91f16700Schasinglulu { 1635*91f16700Schasinglulu int cal_uclk_ticks_per1u_s; 1636*91f16700Schasinglulu uint32_t addr; 1637*91f16700Schasinglulu 1638*91f16700Schasinglulu cal_uclk_ticks_per1u_s = input->basic.frequency >> 1; 1639*91f16700Schasinglulu if (cal_uclk_ticks_per1u_s < 24) { 1640*91f16700Schasinglulu cal_uclk_ticks_per1u_s = 24; 1641*91f16700Schasinglulu } 1642*91f16700Schasinglulu 1643*91f16700Schasinglulu addr = t_master | csr_cal_uclk_info_addr; 1644*91f16700Schasinglulu phy_io_write16(phy, addr, cal_uclk_ticks_per1u_s); 1645*91f16700Schasinglulu } 1646*91f16700Schasinglulu 1647*91f16700Schasinglulu static void prog_cal_rate(uint16_t *phy, 1648*91f16700Schasinglulu const struct input *input) 1649*91f16700Schasinglulu { 1650*91f16700Schasinglulu int cal_rate; 1651*91f16700Schasinglulu int cal_interval; 1652*91f16700Schasinglulu int cal_once; 1653*91f16700Schasinglulu uint32_t addr; 1654*91f16700Schasinglulu 1655*91f16700Schasinglulu cal_interval = input->adv.cal_interval; 1656*91f16700Schasinglulu cal_once = input->adv.cal_once; 1657*91f16700Schasinglulu cal_rate = cal_once << csr_cal_once_lsb | 1658*91f16700Schasinglulu cal_interval << csr_cal_interval_lsb; 1659*91f16700Schasinglulu addr = t_master | csr_cal_rate_addr; 1660*91f16700Schasinglulu phy_io_write16(phy, addr, cal_rate); 1661*91f16700Schasinglulu } 1662*91f16700Schasinglulu 1663*91f16700Schasinglulu static void prog_vref_in_global(uint16_t *phy, 1664*91f16700Schasinglulu const struct input *input, 1665*91f16700Schasinglulu const struct ddr4u1d *msg) 1666*91f16700Schasinglulu { 1667*91f16700Schasinglulu int vref_in_global; 1668*91f16700Schasinglulu int global_vref_in_dac = 0; 1669*91f16700Schasinglulu int global_vref_in_sel = 0; 1670*91f16700Schasinglulu uint32_t addr; 1671*91f16700Schasinglulu 1672*91f16700Schasinglulu /* 1673*91f16700Schasinglulu * phy_vref_prcnt = msg->phy_vref / 128.0 1674*91f16700Schasinglulu * global_vref_in_dac = (phy_vref_prcnt - 0.345) / 0.005; 1675*91f16700Schasinglulu */ 1676*91f16700Schasinglulu global_vref_in_dac = (msg->phy_vref * 1000 - 345 * 128 + 320) / 1677*91f16700Schasinglulu (5 * 128); 1678*91f16700Schasinglulu 1679*91f16700Schasinglulu vref_in_global = global_vref_in_dac << csr_global_vref_in_dac_lsb | 1680*91f16700Schasinglulu global_vref_in_sel; 1681*91f16700Schasinglulu addr = t_master | csr_vref_in_global_addr; 1682*91f16700Schasinglulu phy_io_write16(phy, addr, vref_in_global); 1683*91f16700Schasinglulu } 1684*91f16700Schasinglulu 1685*91f16700Schasinglulu static void prog_dq_dqs_rcv_cntrl(uint16_t *phy, 1686*91f16700Schasinglulu const struct input *input) 1687*91f16700Schasinglulu { 1688*91f16700Schasinglulu int lane, byte, b_addr, c_addr; 1689*91f16700Schasinglulu int dq_dqs_rcv_cntrl; 1690*91f16700Schasinglulu int gain_curr_adj_defval = 0xb; 1691*91f16700Schasinglulu int major_mode_dbyte = 3; 1692*91f16700Schasinglulu int dfe_ctrl_defval = 0; 1693*91f16700Schasinglulu int ext_vref_range_defval = 0; 1694*91f16700Schasinglulu int sel_analog_vref = 1; 1695*91f16700Schasinglulu uint32_t addr; 1696*91f16700Schasinglulu 1697*91f16700Schasinglulu #ifdef ERRATA_DDR_A050958 1698*91f16700Schasinglulu gain_curr_adj_defval = 0x1f; 1699*91f16700Schasinglulu #endif 1700*91f16700Schasinglulu 1701*91f16700Schasinglulu dq_dqs_rcv_cntrl = gain_curr_adj_defval << csr_gain_curr_adj_lsb | 1702*91f16700Schasinglulu major_mode_dbyte << csr_major_mode_dbyte_lsb | 1703*91f16700Schasinglulu dfe_ctrl_defval << csr_dfe_ctrl_lsb | 1704*91f16700Schasinglulu ext_vref_range_defval << csr_ext_vref_range_lsb | 1705*91f16700Schasinglulu sel_analog_vref << csr_sel_analog_vref_lsb; 1706*91f16700Schasinglulu for (byte = 0; byte < input->basic.num_dbyte; byte++) { 1707*91f16700Schasinglulu c_addr = byte << 12; 1708*91f16700Schasinglulu for (lane = 0; lane <= 1; lane++) { 1709*91f16700Schasinglulu b_addr = lane << 8; 1710*91f16700Schasinglulu addr = t_dbyte | c_addr | b_addr | 1711*91f16700Schasinglulu csr_dq_dqs_rcv_cntrl_addr; 1712*91f16700Schasinglulu phy_io_write16(phy, addr, dq_dqs_rcv_cntrl); 1713*91f16700Schasinglulu } 1714*91f16700Schasinglulu } 1715*91f16700Schasinglulu } 1716*91f16700Schasinglulu 1717*91f16700Schasinglulu static void prog_mem_alert_control(uint16_t *phy, 1718*91f16700Schasinglulu const struct input *input) 1719*91f16700Schasinglulu { 1720*91f16700Schasinglulu int mem_alert_control; 1721*91f16700Schasinglulu int mem_alert_control2; 1722*91f16700Schasinglulu int malertpu_en; 1723*91f16700Schasinglulu int malertrx_en; 1724*91f16700Schasinglulu int malertvref_level; 1725*91f16700Schasinglulu int malertpu_stren; 1726*91f16700Schasinglulu int malertsync_bypass; 1727*91f16700Schasinglulu int malertdisable_val_defval = 1; 1728*91f16700Schasinglulu uint32_t addr; 1729*91f16700Schasinglulu 1730*91f16700Schasinglulu if (input->basic.dram_type == DDR4 && input->adv.mem_alert_en == 1) { 1731*91f16700Schasinglulu malertpu_en = 1; 1732*91f16700Schasinglulu malertrx_en = 1; 1733*91f16700Schasinglulu malertpu_stren = input->adv.mem_alert_puimp; 1734*91f16700Schasinglulu malertvref_level = input->adv.mem_alert_vref_level; 1735*91f16700Schasinglulu malertsync_bypass = input->adv.mem_alert_sync_bypass; 1736*91f16700Schasinglulu mem_alert_control = malertdisable_val_defval << 14 | 1737*91f16700Schasinglulu malertrx_en << 13 | 1738*91f16700Schasinglulu malertpu_en << 12 | 1739*91f16700Schasinglulu malertpu_stren << 8 | 1740*91f16700Schasinglulu malertvref_level; 1741*91f16700Schasinglulu mem_alert_control2 = malertsync_bypass << 1742*91f16700Schasinglulu csr_malertsync_bypass_lsb; 1743*91f16700Schasinglulu addr = t_master | csr_mem_alert_control_addr; 1744*91f16700Schasinglulu phy_io_write16(phy, addr, mem_alert_control); 1745*91f16700Schasinglulu addr = t_master | csr_mem_alert_control2_addr; 1746*91f16700Schasinglulu phy_io_write16(phy, addr, mem_alert_control2); 1747*91f16700Schasinglulu } 1748*91f16700Schasinglulu } 1749*91f16700Schasinglulu 1750*91f16700Schasinglulu static void prog_dfi_freq_ratio(uint16_t *phy, 1751*91f16700Schasinglulu const struct input *input) 1752*91f16700Schasinglulu { 1753*91f16700Schasinglulu int dfi_freq_ratio; 1754*91f16700Schasinglulu uint32_t addr = t_master | csr_dfi_freq_ratio_addr; 1755*91f16700Schasinglulu 1756*91f16700Schasinglulu dfi_freq_ratio = input->basic.dfi_freq_ratio; 1757*91f16700Schasinglulu phy_io_write16(phy, addr, dfi_freq_ratio); 1758*91f16700Schasinglulu } 1759*91f16700Schasinglulu 1760*91f16700Schasinglulu static void prog_tristate_mode_ca(uint16_t *phy, 1761*91f16700Schasinglulu const struct input *input) 1762*91f16700Schasinglulu { 1763*91f16700Schasinglulu int tristate_mode_ca; 1764*91f16700Schasinglulu int dis_dyn_adr_tri; 1765*91f16700Schasinglulu int ddr2tmode; 1766*91f16700Schasinglulu int ck_dis_val_def = 1; 1767*91f16700Schasinglulu uint32_t addr = t_master | csr_tristate_mode_ca_addr; 1768*91f16700Schasinglulu 1769*91f16700Schasinglulu dis_dyn_adr_tri = input->adv.dis_dyn_adr_tri; 1770*91f16700Schasinglulu ddr2tmode = input->adv.is2ttiming; 1771*91f16700Schasinglulu tristate_mode_ca = ck_dis_val_def << csr_ck_dis_val_lsb | 1772*91f16700Schasinglulu ddr2tmode << csr_ddr2tmode_lsb | 1773*91f16700Schasinglulu dis_dyn_adr_tri << csr_dis_dyn_adr_tri_lsb; 1774*91f16700Schasinglulu phy_io_write16(phy, addr, tristate_mode_ca); 1775*91f16700Schasinglulu } 1776*91f16700Schasinglulu 1777*91f16700Schasinglulu static void prog_dfi_xlat(uint16_t *phy, 1778*91f16700Schasinglulu const struct input *input) 1779*91f16700Schasinglulu { 1780*91f16700Schasinglulu uint16_t loop_vector; 1781*91f16700Schasinglulu int dfifreqxlat_dat; 1782*91f16700Schasinglulu int pllbypass_dat; 1783*91f16700Schasinglulu uint32_t addr; 1784*91f16700Schasinglulu 1785*91f16700Schasinglulu /* fIXME: Shall unused P1, P2, P3 be bypassed? */ 1786*91f16700Schasinglulu pllbypass_dat = input->basic.pll_bypass; /* only [0] is used */ 1787*91f16700Schasinglulu for (loop_vector = 0; loop_vector < 8; loop_vector++) { 1788*91f16700Schasinglulu if (loop_vector == 0) { 1789*91f16700Schasinglulu dfifreqxlat_dat = pllbypass_dat + 0x5555; 1790*91f16700Schasinglulu } else if (loop_vector == 7) { 1791*91f16700Schasinglulu dfifreqxlat_dat = 0xf000; 1792*91f16700Schasinglulu } else { 1793*91f16700Schasinglulu dfifreqxlat_dat = 0x5555; 1794*91f16700Schasinglulu } 1795*91f16700Schasinglulu addr = t_master | (csr_dfi_freq_xlat0_addr + loop_vector); 1796*91f16700Schasinglulu phy_io_write16(phy, addr, dfifreqxlat_dat); 1797*91f16700Schasinglulu } 1798*91f16700Schasinglulu } 1799*91f16700Schasinglulu 1800*91f16700Schasinglulu static void prog_dbyte_misc_mode(uint16_t *phy, 1801*91f16700Schasinglulu const struct input *input, 1802*91f16700Schasinglulu const struct ddr4u1d *msg) 1803*91f16700Schasinglulu { 1804*91f16700Schasinglulu int dbyte_misc_mode; 1805*91f16700Schasinglulu int dq_dqs_rcv_cntrl1; 1806*91f16700Schasinglulu int dq_dqs_rcv_cntrl1_1; 1807*91f16700Schasinglulu int byte, c_addr; 1808*91f16700Schasinglulu uint32_t addr; 1809*91f16700Schasinglulu 1810*91f16700Schasinglulu dbyte_misc_mode = 0x1 << csr_dbyte_disable_lsb; 1811*91f16700Schasinglulu dq_dqs_rcv_cntrl1 = 0x1ff << csr_power_down_rcvr_lsb | 1812*91f16700Schasinglulu 0x1 << csr_power_down_rcvr_dqs_lsb | 1813*91f16700Schasinglulu 0x1 << csr_rx_pad_standby_en_lsb; 1814*91f16700Schasinglulu dq_dqs_rcv_cntrl1_1 = (0x100 << csr_power_down_rcvr_lsb | 1815*91f16700Schasinglulu csr_rx_pad_standby_en_mask); 1816*91f16700Schasinglulu for (byte = 0; byte < input->basic.num_dbyte; byte++) { 1817*91f16700Schasinglulu c_addr = byte << 12; 1818*91f16700Schasinglulu if (byte <= input->basic.num_active_dbyte_dfi0 - 1) { 1819*91f16700Schasinglulu /* disable RDBI lane if not used. */ 1820*91f16700Schasinglulu if ((input->basic.dram_data_width != 4) && 1821*91f16700Schasinglulu (((msg->mr5 >> 12) & 0x1) == 0)) { 1822*91f16700Schasinglulu addr = t_dbyte 1823*91f16700Schasinglulu | c_addr 1824*91f16700Schasinglulu | csr_dq_dqs_rcv_cntrl1_addr; 1825*91f16700Schasinglulu phy_io_write16(phy, addr, dq_dqs_rcv_cntrl1_1); 1826*91f16700Schasinglulu } 1827*91f16700Schasinglulu } else { 1828*91f16700Schasinglulu addr = t_dbyte | c_addr | csr_dbyte_misc_mode_addr; 1829*91f16700Schasinglulu phy_io_write16(phy, addr, dbyte_misc_mode); 1830*91f16700Schasinglulu addr = t_dbyte | c_addr | csr_dq_dqs_rcv_cntrl1_addr; 1831*91f16700Schasinglulu phy_io_write16(phy, addr, dq_dqs_rcv_cntrl1); 1832*91f16700Schasinglulu } 1833*91f16700Schasinglulu } 1834*91f16700Schasinglulu } 1835*91f16700Schasinglulu 1836*91f16700Schasinglulu static void prog_master_x4config(uint16_t *phy, 1837*91f16700Schasinglulu const struct input *input) 1838*91f16700Schasinglulu { 1839*91f16700Schasinglulu int master_x4config; 1840*91f16700Schasinglulu int x4tg; 1841*91f16700Schasinglulu uint32_t addr = t_master | csr_master_x4config_addr; 1842*91f16700Schasinglulu 1843*91f16700Schasinglulu x4tg = input->basic.dram_data_width == 4 ? 0xf : 0; 1844*91f16700Schasinglulu master_x4config = x4tg << csr_x4tg_lsb; 1845*91f16700Schasinglulu phy_io_write16(phy, addr, master_x4config); 1846*91f16700Schasinglulu } 1847*91f16700Schasinglulu 1848*91f16700Schasinglulu static void prog_dmipin_present(uint16_t *phy, 1849*91f16700Schasinglulu const struct input *input, 1850*91f16700Schasinglulu const struct ddr4u1d *msg) 1851*91f16700Schasinglulu { 1852*91f16700Schasinglulu int dmipin_present; 1853*91f16700Schasinglulu uint32_t addr = t_master | csr_dmipin_present_addr; 1854*91f16700Schasinglulu 1855*91f16700Schasinglulu dmipin_present = (msg->mr5 >> 12) & 0x1; 1856*91f16700Schasinglulu phy_io_write16(phy, addr, dmipin_present); 1857*91f16700Schasinglulu } 1858*91f16700Schasinglulu 1859*91f16700Schasinglulu static void prog_dfi_phyupd(uint16_t *phy, 1860*91f16700Schasinglulu const struct input *input) 1861*91f16700Schasinglulu { 1862*91f16700Schasinglulu int dfiphyupd_dat; 1863*91f16700Schasinglulu uint32_t addr; 1864*91f16700Schasinglulu 1865*91f16700Schasinglulu addr = t_master | (csr_dfiphyupd_addr); 1866*91f16700Schasinglulu dfiphyupd_dat = phy_io_read16(phy, addr) & 1867*91f16700Schasinglulu ~csr_dfiphyupd_threshold_mask; 1868*91f16700Schasinglulu 1869*91f16700Schasinglulu phy_io_write16(phy, addr, dfiphyupd_dat); 1870*91f16700Schasinglulu } 1871*91f16700Schasinglulu 1872*91f16700Schasinglulu static void prog_cal_misc2(uint16_t *phy, 1873*91f16700Schasinglulu const struct input *input) 1874*91f16700Schasinglulu { 1875*91f16700Schasinglulu int cal_misc2_dat, cal_drv_pdth_data, cal_offsets_dat; 1876*91f16700Schasinglulu uint32_t addr; 1877*91f16700Schasinglulu 1878*91f16700Schasinglulu addr = t_master | (csr_cal_misc2_addr); 1879*91f16700Schasinglulu cal_misc2_dat = phy_io_read16(phy, addr) | 1880*91f16700Schasinglulu (1 << csr_cal_misc2_err_dis); 1881*91f16700Schasinglulu 1882*91f16700Schasinglulu phy_io_write16(phy, addr, cal_misc2_dat); 1883*91f16700Schasinglulu 1884*91f16700Schasinglulu addr = t_master | (csr_cal_offsets_addr); 1885*91f16700Schasinglulu 1886*91f16700Schasinglulu cal_drv_pdth_data = 0x9 << 6; 1887*91f16700Schasinglulu cal_offsets_dat = (phy_io_read16(phy, addr) & ~csr_cal_drv_pdth_mask) 1888*91f16700Schasinglulu | cal_drv_pdth_data; 1889*91f16700Schasinglulu 1890*91f16700Schasinglulu phy_io_write16(phy, addr, cal_offsets_dat); 1891*91f16700Schasinglulu } 1892*91f16700Schasinglulu 1893*91f16700Schasinglulu static int c_init_phy_config(uint16_t **phy_ptr, 1894*91f16700Schasinglulu unsigned int ip_rev, 1895*91f16700Schasinglulu const struct input *input, 1896*91f16700Schasinglulu const void *msg) 1897*91f16700Schasinglulu { 1898*91f16700Schasinglulu int i; 1899*91f16700Schasinglulu uint16_t *phy; 1900*91f16700Schasinglulu __unused const soc_info_t *soc_info; 1901*91f16700Schasinglulu 1902*91f16700Schasinglulu for (i = 0; i < NUM_OF_DDRC; i++) { 1903*91f16700Schasinglulu phy = phy_ptr[i]; 1904*91f16700Schasinglulu if (phy == NULL) { 1905*91f16700Schasinglulu continue; 1906*91f16700Schasinglulu } 1907*91f16700Schasinglulu 1908*91f16700Schasinglulu debug("Initialize PHY %d config\n", i); 1909*91f16700Schasinglulu prog_dfi_phyupd(phy, input); 1910*91f16700Schasinglulu prog_cal_misc2(phy, input); 1911*91f16700Schasinglulu prog_tx_pre_drv_mode(phy, input); 1912*91f16700Schasinglulu prog_atx_pre_drv_mode(phy, input); 1913*91f16700Schasinglulu prog_enable_cs_multicast(phy, input); /* rdimm and lrdimm */ 1914*91f16700Schasinglulu prog_dfi_rd_data_cs_dest_map(phy, ip_rev, input, msg); 1915*91f16700Schasinglulu prog_pll_ctrl2(phy, input); 1916*91f16700Schasinglulu #ifdef DDR_PLL_FIX 1917*91f16700Schasinglulu soc_info = get_soc_info(); 1918*91f16700Schasinglulu debug("SOC_SI_REV = %x\n", soc_info->svr_reg.bf.maj_ver); 1919*91f16700Schasinglulu if (soc_info->svr_reg.bf.maj_ver == 1) { 1920*91f16700Schasinglulu prog_pll_pwr_dn(phy, input); 1921*91f16700Schasinglulu 1922*91f16700Schasinglulu /*Enable FFE aka TxEqualizationMode for rev1 SI*/ 1923*91f16700Schasinglulu phy_io_write16(phy, 0x010048, 0x1); 1924*91f16700Schasinglulu } 1925*91f16700Schasinglulu #endif 1926*91f16700Schasinglulu prog_ard_ptr_init_val(phy, input); 1927*91f16700Schasinglulu prog_dqs_preamble_control(phy, input); 1928*91f16700Schasinglulu prog_dll_lck_param(phy, input); 1929*91f16700Schasinglulu prog_dll_gain_ctl(phy, input); 1930*91f16700Schasinglulu prog_proc_odt_time_ctl(phy, input); 1931*91f16700Schasinglulu prog_tx_odt_drv_stren(phy, input); 1932*91f16700Schasinglulu prog_tx_impedance_ctrl1(phy, input); 1933*91f16700Schasinglulu prog_atx_impedance(phy, input); 1934*91f16700Schasinglulu prog_dfi_mode(phy, input); 1935*91f16700Schasinglulu prog_dfi_camode(phy, input); 1936*91f16700Schasinglulu prog_cal_drv_str0(phy, input); 1937*91f16700Schasinglulu prog_cal_uclk_info(phy, input); 1938*91f16700Schasinglulu prog_cal_rate(phy, input); 1939*91f16700Schasinglulu prog_vref_in_global(phy, input, msg); 1940*91f16700Schasinglulu prog_dq_dqs_rcv_cntrl(phy, input); 1941*91f16700Schasinglulu prog_mem_alert_control(phy, input); 1942*91f16700Schasinglulu prog_dfi_freq_ratio(phy, input); 1943*91f16700Schasinglulu prog_tristate_mode_ca(phy, input); 1944*91f16700Schasinglulu prog_dfi_xlat(phy, input); 1945*91f16700Schasinglulu prog_dbyte_misc_mode(phy, input, msg); 1946*91f16700Schasinglulu prog_master_x4config(phy, input); 1947*91f16700Schasinglulu prog_dmipin_present(phy, input, msg); 1948*91f16700Schasinglulu prog_acx4_anib_dis(phy, input); 1949*91f16700Schasinglulu } 1950*91f16700Schasinglulu 1951*91f16700Schasinglulu return 0; 1952*91f16700Schasinglulu } 1953*91f16700Schasinglulu 1954*91f16700Schasinglulu static uint32_t get_mail(uint16_t *phy, int stream) 1955*91f16700Schasinglulu { 1956*91f16700Schasinglulu int timeout; 1957*91f16700Schasinglulu uint32_t mail = 0U; 1958*91f16700Schasinglulu 1959*91f16700Schasinglulu timeout = TIMEOUTDEFAULT; 1960*91f16700Schasinglulu while (((--timeout) != 0) && 1961*91f16700Schasinglulu ((phy_io_read16(phy, t_apbonly | csr_uct_shadow_regs) 1962*91f16700Schasinglulu & uct_write_prot_shadow_mask) != 0)) { 1963*91f16700Schasinglulu mdelay(10); 1964*91f16700Schasinglulu } 1965*91f16700Schasinglulu if (timeout == 0) { 1966*91f16700Schasinglulu ERROR("Timeout getting mail from PHY\n"); 1967*91f16700Schasinglulu return 0xFFFF; 1968*91f16700Schasinglulu } 1969*91f16700Schasinglulu 1970*91f16700Schasinglulu mail = phy_io_read16(phy, t_apbonly | 1971*91f16700Schasinglulu csr_uct_write_only_shadow); 1972*91f16700Schasinglulu if (stream != 0) { 1973*91f16700Schasinglulu mail |= phy_io_read16(phy, t_apbonly | 1974*91f16700Schasinglulu csr_uct_dat_write_only_shadow) << 16; 1975*91f16700Schasinglulu } 1976*91f16700Schasinglulu 1977*91f16700Schasinglulu /* Ack */ 1978*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | csr_dct_write_prot, 0); 1979*91f16700Schasinglulu 1980*91f16700Schasinglulu timeout = TIMEOUTDEFAULT; 1981*91f16700Schasinglulu while (((--timeout) != 0) && 1982*91f16700Schasinglulu ((phy_io_read16(phy, t_apbonly | csr_uct_shadow_regs) 1983*91f16700Schasinglulu & uct_write_prot_shadow_mask) == 0)) { 1984*91f16700Schasinglulu mdelay(1); 1985*91f16700Schasinglulu } 1986*91f16700Schasinglulu if (timeout == 0) { 1987*91f16700Schasinglulu ERROR("Timeout ack PHY mail\n"); 1988*91f16700Schasinglulu } 1989*91f16700Schasinglulu 1990*91f16700Schasinglulu /* completed */ 1991*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | csr_dct_write_prot, 1U); 1992*91f16700Schasinglulu 1993*91f16700Schasinglulu return mail; 1994*91f16700Schasinglulu } 1995*91f16700Schasinglulu 1996*91f16700Schasinglulu #ifdef DDR_PHY_DEBUG 1997*91f16700Schasinglulu static const char *lookup_msg(uint32_t index, int train2d) 1998*91f16700Schasinglulu { 1999*91f16700Schasinglulu int i; 2000*91f16700Schasinglulu int size; 2001*91f16700Schasinglulu const struct phy_msg *messages; 2002*91f16700Schasinglulu const char *ptr = NULL; 2003*91f16700Schasinglulu 2004*91f16700Schasinglulu if (train2d != 0) { 2005*91f16700Schasinglulu messages = messages_2d; 2006*91f16700Schasinglulu size = ARRAY_SIZE(messages_2d); 2007*91f16700Schasinglulu } else { 2008*91f16700Schasinglulu messages = messages_1d; 2009*91f16700Schasinglulu size = ARRAY_SIZE(messages_1d); 2010*91f16700Schasinglulu } 2011*91f16700Schasinglulu for (i = 0; i < size; i++) { 2012*91f16700Schasinglulu if (messages[i].index == index) { 2013*91f16700Schasinglulu ptr = messages[i].msg; 2014*91f16700Schasinglulu break; 2015*91f16700Schasinglulu } 2016*91f16700Schasinglulu } 2017*91f16700Schasinglulu 2018*91f16700Schasinglulu return ptr; 2019*91f16700Schasinglulu } 2020*91f16700Schasinglulu #endif 2021*91f16700Schasinglulu 2022*91f16700Schasinglulu #define MAX_ARGS 32 2023*91f16700Schasinglulu static void decode_stream_message(uint16_t *phy, int train2d) 2024*91f16700Schasinglulu { 2025*91f16700Schasinglulu uint32_t index __unused; 2026*91f16700Schasinglulu 2027*91f16700Schasinglulu __unused const char *format; 2028*91f16700Schasinglulu __unused uint32_t args[MAX_ARGS]; 2029*91f16700Schasinglulu __unused int i; 2030*91f16700Schasinglulu 2031*91f16700Schasinglulu #ifdef DDR_PHY_DEBUG 2032*91f16700Schasinglulu index = get_mail(phy, 1); 2033*91f16700Schasinglulu if ((index & 0xffff) > MAX_ARGS) { /* up to MAX_ARGS args so far */ 2034*91f16700Schasinglulu printf("Program error in %s\n", __func__); 2035*91f16700Schasinglulu } 2036*91f16700Schasinglulu for (i = 0; i < (index & 0xffff) && i < MAX_ARGS; i++) { 2037*91f16700Schasinglulu args[i] = get_mail(phy, 1); 2038*91f16700Schasinglulu } 2039*91f16700Schasinglulu 2040*91f16700Schasinglulu format = lookup_msg(index, train2d); 2041*91f16700Schasinglulu if (format != NULL) { 2042*91f16700Schasinglulu printf("0x%08x: ", index); 2043*91f16700Schasinglulu printf(format, args[0], args[1], args[2], args[3], args[4], 2044*91f16700Schasinglulu args[5], args[6], args[7], args[8], args[9], args[10], 2045*91f16700Schasinglulu args[11], args[12], args[13], args[14], args[15], 2046*91f16700Schasinglulu args[16], args[17], args[18], args[19], args[20], 2047*91f16700Schasinglulu args[21], args[22], args[23], args[24], args[25], 2048*91f16700Schasinglulu args[26], args[27], args[28], args[29], args[30], 2049*91f16700Schasinglulu args[31]); 2050*91f16700Schasinglulu } 2051*91f16700Schasinglulu #endif 2052*91f16700Schasinglulu } 2053*91f16700Schasinglulu 2054*91f16700Schasinglulu static int wait_fw_done(uint16_t *phy, int train2d) 2055*91f16700Schasinglulu { 2056*91f16700Schasinglulu uint32_t mail = 0U; 2057*91f16700Schasinglulu 2058*91f16700Schasinglulu while (mail == U(0x0)) { 2059*91f16700Schasinglulu mail = get_mail(phy, 0); 2060*91f16700Schasinglulu switch (mail) { 2061*91f16700Schasinglulu case U(0x7): 2062*91f16700Schasinglulu debug("%s Training completed\n", train2d ? "2D" : "1D"); 2063*91f16700Schasinglulu break; 2064*91f16700Schasinglulu case U(0xff): 2065*91f16700Schasinglulu debug("%s Training failure\n", train2d ? "2D" : "1D"); 2066*91f16700Schasinglulu break; 2067*91f16700Schasinglulu case U(0x0): 2068*91f16700Schasinglulu debug("End of initialization\n"); 2069*91f16700Schasinglulu mail = 0U; 2070*91f16700Schasinglulu break; 2071*91f16700Schasinglulu case U(0x1): 2072*91f16700Schasinglulu debug("End of fine write leveling\n"); 2073*91f16700Schasinglulu mail = 0U; 2074*91f16700Schasinglulu break; 2075*91f16700Schasinglulu case U(0x2): 2076*91f16700Schasinglulu debug("End of read enable training\n"); 2077*91f16700Schasinglulu mail = 0U; 2078*91f16700Schasinglulu break; 2079*91f16700Schasinglulu case U(0x3): 2080*91f16700Schasinglulu debug("End of read delay center optimization\n"); 2081*91f16700Schasinglulu mail = 0U; 2082*91f16700Schasinglulu break; 2083*91f16700Schasinglulu case U(0x4): 2084*91f16700Schasinglulu debug("End of write delay center optimization\n"); 2085*91f16700Schasinglulu mail = 0U; 2086*91f16700Schasinglulu break; 2087*91f16700Schasinglulu case U(0x5): 2088*91f16700Schasinglulu debug("End of 2D read delay/voltage center optimztn\n"); 2089*91f16700Schasinglulu mail = 0U; 2090*91f16700Schasinglulu break; 2091*91f16700Schasinglulu case U(0x6): 2092*91f16700Schasinglulu debug("End of 2D write delay/voltage center optmztn\n"); 2093*91f16700Schasinglulu mail = 0U; 2094*91f16700Schasinglulu break; 2095*91f16700Schasinglulu case U(0x8): 2096*91f16700Schasinglulu decode_stream_message(phy, train2d); 2097*91f16700Schasinglulu mail = 0U; 2098*91f16700Schasinglulu break; 2099*91f16700Schasinglulu case U(0x9): 2100*91f16700Schasinglulu debug("End of max read latency training\n"); 2101*91f16700Schasinglulu mail = 0U; 2102*91f16700Schasinglulu break; 2103*91f16700Schasinglulu case U(0xa): 2104*91f16700Schasinglulu debug("End of read dq deskew training\n"); 2105*91f16700Schasinglulu mail = 0U; 2106*91f16700Schasinglulu break; 2107*91f16700Schasinglulu case U(0xc): 2108*91f16700Schasinglulu debug("End of LRDIMM Specific training, including:\n"); 2109*91f16700Schasinglulu debug("/tDWL, MREP, MRD and MWD\n"); 2110*91f16700Schasinglulu mail = 0U; 2111*91f16700Schasinglulu break; 2112*91f16700Schasinglulu case U(0xd): 2113*91f16700Schasinglulu debug("End of CA training\n"); 2114*91f16700Schasinglulu mail = 0U; 2115*91f16700Schasinglulu break; 2116*91f16700Schasinglulu case U(0xfd): 2117*91f16700Schasinglulu debug("End of MPR read delay center optimization\n"); 2118*91f16700Schasinglulu mail = 0U; 2119*91f16700Schasinglulu break; 2120*91f16700Schasinglulu case U(0xfe): 2121*91f16700Schasinglulu debug("End of Write leveling coarse delay\n"); 2122*91f16700Schasinglulu mail = 0U; 2123*91f16700Schasinglulu break; 2124*91f16700Schasinglulu case U(0xffff): 2125*91f16700Schasinglulu debug("Timed out\n"); 2126*91f16700Schasinglulu break; 2127*91f16700Schasinglulu default: 2128*91f16700Schasinglulu mail = 0U; 2129*91f16700Schasinglulu break; 2130*91f16700Schasinglulu } 2131*91f16700Schasinglulu } 2132*91f16700Schasinglulu 2133*91f16700Schasinglulu if (mail == U(0x7)) { 2134*91f16700Schasinglulu return 0; 2135*91f16700Schasinglulu } else if (mail == U(0xff)) { 2136*91f16700Schasinglulu return -EIO; 2137*91f16700Schasinglulu } else if (mail == U(0xffff)) { 2138*91f16700Schasinglulu return -ETIMEDOUT; 2139*91f16700Schasinglulu } 2140*91f16700Schasinglulu 2141*91f16700Schasinglulu debug("PHY_GEN2 FW: Unxpected mail = 0x%x\n", mail); 2142*91f16700Schasinglulu 2143*91f16700Schasinglulu return -EINVAL; 2144*91f16700Schasinglulu } 2145*91f16700Schasinglulu 2146*91f16700Schasinglulu static int g_exec_fw(uint16_t **phy_ptr, int train2d, struct input *input) 2147*91f16700Schasinglulu { 2148*91f16700Schasinglulu int ret = -EINVAL; 2149*91f16700Schasinglulu int i; 2150*91f16700Schasinglulu uint16_t *phy; 2151*91f16700Schasinglulu 2152*91f16700Schasinglulu for (i = 0; i < NUM_OF_DDRC; i++) { 2153*91f16700Schasinglulu phy = phy_ptr[i]; 2154*91f16700Schasinglulu if (phy == NULL) { 2155*91f16700Schasinglulu continue; 2156*91f16700Schasinglulu } 2157*91f16700Schasinglulu debug("Applying PLL optimal settings\n"); 2158*91f16700Schasinglulu prog_pll_ctrl2(phy, input); 2159*91f16700Schasinglulu prog_pll_ctrl(phy, input); 2160*91f16700Schasinglulu phy_io_write16(phy, 2161*91f16700Schasinglulu t_apbonly | csr_micro_cont_mux_sel_addr, 2162*91f16700Schasinglulu 0x1); 2163*91f16700Schasinglulu phy_io_write16(phy, 2164*91f16700Schasinglulu t_apbonly | csr_micro_reset_addr, 2165*91f16700Schasinglulu csr_reset_to_micro_mask | 2166*91f16700Schasinglulu csr_stall_to_micro_mask); 2167*91f16700Schasinglulu phy_io_write16(phy, 2168*91f16700Schasinglulu t_apbonly | csr_micro_reset_addr, 2169*91f16700Schasinglulu csr_stall_to_micro_mask); 2170*91f16700Schasinglulu phy_io_write16(phy, 2171*91f16700Schasinglulu t_apbonly | csr_micro_reset_addr, 2172*91f16700Schasinglulu 0); 2173*91f16700Schasinglulu 2174*91f16700Schasinglulu ret = wait_fw_done(phy, train2d); 2175*91f16700Schasinglulu if (ret == -ETIMEDOUT) { 2176*91f16700Schasinglulu ERROR("Wait timed out: Firmware execution on PHY %d\n", 2177*91f16700Schasinglulu i); 2178*91f16700Schasinglulu } 2179*91f16700Schasinglulu } 2180*91f16700Schasinglulu return ret; 2181*91f16700Schasinglulu } 2182*91f16700Schasinglulu 2183*91f16700Schasinglulu static inline int send_fw(uint16_t *phy, 2184*91f16700Schasinglulu uint32_t dst, 2185*91f16700Schasinglulu uint16_t *img, 2186*91f16700Schasinglulu uint32_t size) 2187*91f16700Schasinglulu { 2188*91f16700Schasinglulu uint32_t i; 2189*91f16700Schasinglulu 2190*91f16700Schasinglulu if ((size % 2U) != 0U) { 2191*91f16700Schasinglulu ERROR("Wrong image size 0x%x\n", size); 2192*91f16700Schasinglulu return -EINVAL; 2193*91f16700Schasinglulu } 2194*91f16700Schasinglulu 2195*91f16700Schasinglulu for (i = 0U; i < size / 2; i++) { 2196*91f16700Schasinglulu phy_io_write16(phy, dst + i, *(img + i)); 2197*91f16700Schasinglulu } 2198*91f16700Schasinglulu 2199*91f16700Schasinglulu return 0; 2200*91f16700Schasinglulu } 2201*91f16700Schasinglulu 2202*91f16700Schasinglulu static int load_fw(uint16_t **phy_ptr, 2203*91f16700Schasinglulu struct input *input, 2204*91f16700Schasinglulu int train2d, 2205*91f16700Schasinglulu void *msg, 2206*91f16700Schasinglulu size_t len, 2207*91f16700Schasinglulu uintptr_t phy_gen2_fw_img_buf, 2208*91f16700Schasinglulu int (*img_loadr)(unsigned int, uintptr_t *, uint32_t *), 2209*91f16700Schasinglulu uint32_t warm_boot_flag) 2210*91f16700Schasinglulu { 2211*91f16700Schasinglulu uint32_t imem_id, dmem_id; 2212*91f16700Schasinglulu uintptr_t image_buf; 2213*91f16700Schasinglulu uint32_t size; 2214*91f16700Schasinglulu int ret; 2215*91f16700Schasinglulu int i; 2216*91f16700Schasinglulu uint16_t *phy; 2217*91f16700Schasinglulu 2218*91f16700Schasinglulu switch (input->basic.dimm_type) { 2219*91f16700Schasinglulu case UDIMM: 2220*91f16700Schasinglulu case SODIMM: 2221*91f16700Schasinglulu case NODIMM: 2222*91f16700Schasinglulu imem_id = train2d ? DDR_IMEM_UDIMM_2D_IMAGE_ID : 2223*91f16700Schasinglulu DDR_IMEM_UDIMM_1D_IMAGE_ID; 2224*91f16700Schasinglulu dmem_id = train2d ? DDR_DMEM_UDIMM_2D_IMAGE_ID : 2225*91f16700Schasinglulu DDR_DMEM_UDIMM_1D_IMAGE_ID; 2226*91f16700Schasinglulu break; 2227*91f16700Schasinglulu case RDIMM: 2228*91f16700Schasinglulu imem_id = train2d ? DDR_IMEM_RDIMM_2D_IMAGE_ID : 2229*91f16700Schasinglulu DDR_IMEM_RDIMM_1D_IMAGE_ID; 2230*91f16700Schasinglulu dmem_id = train2d ? DDR_DMEM_RDIMM_2D_IMAGE_ID : 2231*91f16700Schasinglulu DDR_DMEM_RDIMM_1D_IMAGE_ID; 2232*91f16700Schasinglulu break; 2233*91f16700Schasinglulu default: 2234*91f16700Schasinglulu ERROR("Unsupported DIMM type\n"); 2235*91f16700Schasinglulu return -EINVAL; 2236*91f16700Schasinglulu } 2237*91f16700Schasinglulu 2238*91f16700Schasinglulu size = PHY_GEN2_MAX_IMAGE_SIZE; 2239*91f16700Schasinglulu image_buf = (uintptr_t)phy_gen2_fw_img_buf; 2240*91f16700Schasinglulu ret = img_loadr(imem_id, &image_buf, &size); 2241*91f16700Schasinglulu if (ret != 0) { 2242*91f16700Schasinglulu ERROR("Failed to load %d firmware.\n", imem_id); 2243*91f16700Schasinglulu return ret; 2244*91f16700Schasinglulu } 2245*91f16700Schasinglulu debug("Loaded Imaged id %d of size %x at address %lx\n", 2246*91f16700Schasinglulu imem_id, size, image_buf); 2247*91f16700Schasinglulu 2248*91f16700Schasinglulu for (i = 0; i < NUM_OF_DDRC; i++) { 2249*91f16700Schasinglulu phy = phy_ptr[i]; 2250*91f16700Schasinglulu if (phy == NULL) { 2251*91f16700Schasinglulu continue; 2252*91f16700Schasinglulu } 2253*91f16700Schasinglulu 2254*91f16700Schasinglulu if (warm_boot_flag != DDR_WARM_BOOT) { 2255*91f16700Schasinglulu if (train2d == 0) { 2256*91f16700Schasinglulu phy_io_write16(phy, t_master | 2257*91f16700Schasinglulu csr_mem_reset_l_addr, 2258*91f16700Schasinglulu csr_protect_mem_reset_mask); 2259*91f16700Schasinglulu } 2260*91f16700Schasinglulu } 2261*91f16700Schasinglulu /* Enable access to the internal CSRs */ 2262*91f16700Schasinglulu phy_io_write16(phy, t_apbonly | csr_micro_cont_mux_sel_addr, 0); 2263*91f16700Schasinglulu 2264*91f16700Schasinglulu ret = send_fw(phy, PHY_GEN2_IMEM_ADDR, 2265*91f16700Schasinglulu (uint16_t *)image_buf, size); 2266*91f16700Schasinglulu if (ret != 0) { 2267*91f16700Schasinglulu return ret; 2268*91f16700Schasinglulu } 2269*91f16700Schasinglulu } 2270*91f16700Schasinglulu 2271*91f16700Schasinglulu size = PHY_GEN2_MAX_IMAGE_SIZE; 2272*91f16700Schasinglulu image_buf = (uintptr_t)phy_gen2_fw_img_buf; 2273*91f16700Schasinglulu ret = img_loadr(dmem_id, &image_buf, &size); 2274*91f16700Schasinglulu if (ret != 0) { 2275*91f16700Schasinglulu ERROR("Failed to load %d firmware.\n", dmem_id); 2276*91f16700Schasinglulu return ret; 2277*91f16700Schasinglulu } 2278*91f16700Schasinglulu debug("Loaded Imaged id %d of size %x at address %lx\n", 2279*91f16700Schasinglulu dmem_id, size, image_buf); 2280*91f16700Schasinglulu image_buf += len; 2281*91f16700Schasinglulu size -= len; 2282*91f16700Schasinglulu 2283*91f16700Schasinglulu for (i = 0; i < NUM_OF_DDRC; i++) { 2284*91f16700Schasinglulu phy = phy_ptr[i]; 2285*91f16700Schasinglulu if (phy == NULL) { 2286*91f16700Schasinglulu continue; 2287*91f16700Schasinglulu } 2288*91f16700Schasinglulu 2289*91f16700Schasinglulu ret = send_fw(phy, PHY_GEN2_DMEM_ADDR, msg, len); 2290*91f16700Schasinglulu if (ret != 0) { 2291*91f16700Schasinglulu return ret; 2292*91f16700Schasinglulu } 2293*91f16700Schasinglulu 2294*91f16700Schasinglulu ret = send_fw(phy, PHY_GEN2_DMEM_ADDR + len / 2, 2295*91f16700Schasinglulu (uint16_t *)image_buf, size); 2296*91f16700Schasinglulu if (ret != 0) { 2297*91f16700Schasinglulu return ret; 2298*91f16700Schasinglulu } 2299*91f16700Schasinglulu } 2300*91f16700Schasinglulu 2301*91f16700Schasinglulu return ret; 2302*91f16700Schasinglulu } 2303*91f16700Schasinglulu 2304*91f16700Schasinglulu static void parse_odt(const unsigned int val, 2305*91f16700Schasinglulu const int read, 2306*91f16700Schasinglulu const int i, 2307*91f16700Schasinglulu const unsigned int cs_d0, 2308*91f16700Schasinglulu const unsigned int cs_d1, 2309*91f16700Schasinglulu unsigned int *odt) 2310*91f16700Schasinglulu { 2311*91f16700Schasinglulu int shift = read ? 4 : 0; 2312*91f16700Schasinglulu int j; 2313*91f16700Schasinglulu 2314*91f16700Schasinglulu if (i < 0 || i > 3) { 2315*91f16700Schasinglulu printf("Error: invalid chip-select value\n"); 2316*91f16700Schasinglulu return; 2317*91f16700Schasinglulu } 2318*91f16700Schasinglulu switch (val) { 2319*91f16700Schasinglulu case DDR_ODT_CS: 2320*91f16700Schasinglulu odt[i] |= (1 << i) << shift; 2321*91f16700Schasinglulu break; 2322*91f16700Schasinglulu case DDR_ODT_ALL_OTHER_CS: 2323*91f16700Schasinglulu for (j = 0; j < DDRC_NUM_CS; j++) { 2324*91f16700Schasinglulu if (i == j) { 2325*91f16700Schasinglulu continue; 2326*91f16700Schasinglulu } 2327*91f16700Schasinglulu if (((cs_d0 | cs_d1) & (1 << j)) == 0) { 2328*91f16700Schasinglulu continue; 2329*91f16700Schasinglulu } 2330*91f16700Schasinglulu odt[j] |= (1 << i) << shift; 2331*91f16700Schasinglulu } 2332*91f16700Schasinglulu break; 2333*91f16700Schasinglulu case DDR_ODT_CS_AND_OTHER_DIMM: 2334*91f16700Schasinglulu odt[i] |= (1 << i) << 4; 2335*91f16700Schasinglulu /* fallthrough */ 2336*91f16700Schasinglulu case DDR_ODT_OTHER_DIMM: 2337*91f16700Schasinglulu for (j = 0; j < DDRC_NUM_CS; j++) { 2338*91f16700Schasinglulu if ((((cs_d0 & (1 << i)) != 0) && 2339*91f16700Schasinglulu ((cs_d1 & (1 << j)) != 0)) || 2340*91f16700Schasinglulu (((cs_d1 & (1 << i)) != 0) && 2341*91f16700Schasinglulu ((cs_d0 & (1 << j)) != 0))) { 2342*91f16700Schasinglulu odt[j] |= (1 << i) << shift; 2343*91f16700Schasinglulu } 2344*91f16700Schasinglulu } 2345*91f16700Schasinglulu break; 2346*91f16700Schasinglulu case DDR_ODT_ALL: 2347*91f16700Schasinglulu for (j = 0; j < DDRC_NUM_CS; j++) { 2348*91f16700Schasinglulu if (((cs_d0 | cs_d1) & (1 << j)) == 0) { 2349*91f16700Schasinglulu continue; 2350*91f16700Schasinglulu } 2351*91f16700Schasinglulu odt[j] |= (1 << i) << shift; 2352*91f16700Schasinglulu } 2353*91f16700Schasinglulu break; 2354*91f16700Schasinglulu case DDR_ODT_SAME_DIMM: 2355*91f16700Schasinglulu for (j = 0; j < DDRC_NUM_CS; j++) { 2356*91f16700Schasinglulu if ((((cs_d0 & (1 << i)) != 0) && 2357*91f16700Schasinglulu ((cs_d0 & (1 << j)) != 0)) || 2358*91f16700Schasinglulu (((cs_d1 & (1 << i)) != 0) && 2359*91f16700Schasinglulu ((cs_d1 & (1 << j)) != 0))) { 2360*91f16700Schasinglulu odt[j] |= (1 << i) << shift; 2361*91f16700Schasinglulu } 2362*91f16700Schasinglulu } 2363*91f16700Schasinglulu break; 2364*91f16700Schasinglulu case DDR_ODT_OTHER_CS_ONSAMEDIMM: 2365*91f16700Schasinglulu for (j = 0; j < DDRC_NUM_CS; j++) { 2366*91f16700Schasinglulu if (i == j) { 2367*91f16700Schasinglulu continue; 2368*91f16700Schasinglulu } 2369*91f16700Schasinglulu if ((((cs_d0 & (1 << i)) != 0) && 2370*91f16700Schasinglulu ((cs_d0 & (1 << j)) != 0)) || 2371*91f16700Schasinglulu (((cs_d1 & (1 << i)) != 0) && 2372*91f16700Schasinglulu ((cs_d1 & (1 << j)) != 0))) { 2373*91f16700Schasinglulu odt[j] |= (1 << i) << shift; 2374*91f16700Schasinglulu } 2375*91f16700Schasinglulu } 2376*91f16700Schasinglulu break; 2377*91f16700Schasinglulu case DDR_ODT_NEVER: 2378*91f16700Schasinglulu break; 2379*91f16700Schasinglulu default: 2380*91f16700Schasinglulu break; 2381*91f16700Schasinglulu } 2382*91f16700Schasinglulu } 2383*91f16700Schasinglulu 2384*91f16700Schasinglulu #ifdef DEBUG_DDR_INPUT_CONFIG 2385*91f16700Schasinglulu char *dram_types_str[] = { 2386*91f16700Schasinglulu "DDR4", 2387*91f16700Schasinglulu "DDR3", 2388*91f16700Schasinglulu "LDDDR4", 2389*91f16700Schasinglulu "LPDDR3", 2390*91f16700Schasinglulu "LPDDR2", 2391*91f16700Schasinglulu "DDR5" 2392*91f16700Schasinglulu }; 2393*91f16700Schasinglulu 2394*91f16700Schasinglulu char *dimm_types_str[] = { 2395*91f16700Schasinglulu "UDIMM", 2396*91f16700Schasinglulu "SODIMM", 2397*91f16700Schasinglulu "RDIMM", 2398*91f16700Schasinglulu "LRDIMM", 2399*91f16700Schasinglulu "NODIMM", 2400*91f16700Schasinglulu }; 2401*91f16700Schasinglulu 2402*91f16700Schasinglulu 2403*91f16700Schasinglulu static void print_jason_format(struct input *input, 2404*91f16700Schasinglulu struct ddr4u1d *msg_1d, 2405*91f16700Schasinglulu struct ddr4u2d *msg_2d) 2406*91f16700Schasinglulu { 2407*91f16700Schasinglulu 2408*91f16700Schasinglulu printf("\n{"); 2409*91f16700Schasinglulu printf("\n \"dram_type\": \"%s\",", dram_types_str[input->basic.dram_type]); 2410*91f16700Schasinglulu printf("\n \"dimm_type\": \"%s\",", dimm_types_str[input->basic.dimm_type]); 2411*91f16700Schasinglulu printf("\n \"hard_macro_ver\": \"%d\",", input->basic.hard_macro_ver); 2412*91f16700Schasinglulu printf("\n \"num_dbyte\": \"0x%04x\",", (unsigned int)input->basic.num_dbyte); 2413*91f16700Schasinglulu printf("\n \"num_active_dbyte_dfi0\": \"0x%04x\",", (unsigned int)input->basic.num_active_dbyte_dfi0); 2414*91f16700Schasinglulu printf("\n \"num_anib\": \"0x%04x\",", (unsigned int)input->basic.num_anib); 2415*91f16700Schasinglulu printf("\n \"num_rank_dfi0\": \"0x%04x\",", (unsigned int)input->basic.num_rank_dfi0); 2416*91f16700Schasinglulu printf("\n \"num_pstates\": \"0x%04x\",", (unsigned int)input->basic.num_pstates); 2417*91f16700Schasinglulu printf("\n \"frequency\": \"%d\",", input->basic.frequency); 2418*91f16700Schasinglulu printf("\n \"pll_bypass\": \"0x%04x\",", (unsigned int)input->basic.dfi_freq_ratio); 2419*91f16700Schasinglulu printf("\n \"dfi_freq_ratio\": \"0x%04x\",", (unsigned int)input->basic.dfi_freq_ratio); 2420*91f16700Schasinglulu printf("\n \"dfi1_exists\": \"0x%04x\",", (unsigned int)input->basic.dfi1exists); 2421*91f16700Schasinglulu printf("\n \"dram_data_width\": \"0x%04x\",", (unsigned int)input->basic.dram_data_width); 2422*91f16700Schasinglulu printf("\n \"dram_byte_swap\": \"0x%04x\",", (unsigned int)input->adv.dram_byte_swap); 2423*91f16700Schasinglulu printf("\n \"ext_cal_res_val\": \"0x%04x\",", (unsigned int)input->adv.ext_cal_res_val); 2424*91f16700Schasinglulu printf("\n \"tx_slew_rise_dq\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_rise_dq); 2425*91f16700Schasinglulu printf("\n \"tx_slew_fall_dq\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_fall_dq); 2426*91f16700Schasinglulu printf("\n \"tx_slew_rise_ac\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_rise_ac); 2427*91f16700Schasinglulu printf("\n \"tx_slew_fall_ac\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_fall_ac); 2428*91f16700Schasinglulu printf("\n \"odt_impedance\": \"%d\",", input->adv.odtimpedance); 2429*91f16700Schasinglulu printf("\n \"tx_impedance\": \"%d\",", input->adv.tx_impedance); 2430*91f16700Schasinglulu printf("\n \"atx_impedance\": \"%d\",", input->adv.atx_impedance); 2431*91f16700Schasinglulu printf("\n \"mem_alert_en\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_en); 2432*91f16700Schasinglulu printf("\n \"mem_alert_pu_imp\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_puimp); 2433*91f16700Schasinglulu printf("\n \"mem_alert_vref_level\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_vref_level); 2434*91f16700Schasinglulu printf("\n \"mem_alert_sync_bypass\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_sync_bypass); 2435*91f16700Schasinglulu printf("\n \"cal_interval\": \"0x%04x\",", (unsigned int)input->adv.cal_interval); 2436*91f16700Schasinglulu printf("\n \"cal_once\": \"0x%04x\",", (unsigned int)input->adv.cal_once); 2437*91f16700Schasinglulu printf("\n \"dis_dyn_adr_tri\": \"0x%04x\",", (unsigned int)input->adv.dis_dyn_adr_tri); 2438*91f16700Schasinglulu printf("\n \"is2t_timing\": \"0x%04x\",", (unsigned int)input->adv.is2ttiming); 2439*91f16700Schasinglulu printf("\n \"d4rx_preabmle_length\": \"0x%04x\",", (unsigned int)input->adv.d4rx_preamble_length); 2440*91f16700Schasinglulu printf("\n \"d4tx_preamble_length\": \"0x%04x\",", (unsigned int)input->adv.d4tx_preamble_length); 2441*91f16700Schasinglulu printf("\n \"msg_misc\": \"0x%02x\",", (unsigned int)msg_1d->msg_misc); 2442*91f16700Schasinglulu printf("\n \"reserved00\": \"0x%01x\",", (unsigned int)msg_1d->reserved00); 2443*91f16700Schasinglulu printf("\n \"hdt_ctrl\": \"0x%02x\",", (unsigned int)msg_1d->hdt_ctrl); 2444*91f16700Schasinglulu printf("\n \"cs_present\": \"0x%02x\",", (unsigned int)msg_1d->cs_present); 2445*91f16700Schasinglulu printf("\n \"phy_vref\": \"0x%02x\",", (unsigned int)msg_1d->phy_vref); 2446*91f16700Schasinglulu printf("\n \"dfi_mrl_margin\": \"0x%02x\",", (unsigned int)msg_1d->dfimrlmargin); 2447*91f16700Schasinglulu printf("\n \"addr_mirror\": \"0x%02x\",", (unsigned int)msg_1d->addr_mirror); 2448*91f16700Schasinglulu printf("\n \"wr_odt_pat_rank0\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl0 & 0x0f)); 2449*91f16700Schasinglulu printf("\n \"wr_odt_pat_rank1\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl1 & 0x0f)); 2450*91f16700Schasinglulu printf("\n \"wr_odt_pat_rank2\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl2 & 0x0f)); 2451*91f16700Schasinglulu printf("\n \"wr_odt_pat_rank3\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl3 & 0x0f)); 2452*91f16700Schasinglulu printf("\n \"rd_odt_pat_rank0\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl0 & 0xf0)); 2453*91f16700Schasinglulu printf("\n \"rd_odt_pat_rank1\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl1 & 0xf0)); 2454*91f16700Schasinglulu printf("\n \"rd_odt_pat_rank2\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl2 & 0xf0)); 2455*91f16700Schasinglulu printf("\n \"rd_odt_pat_rank3\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl3 & 0xf0)); 2456*91f16700Schasinglulu printf("\n \"d4_misc\": \"0x%01x\",", (unsigned int)msg_1d->d4misc); 2457*91f16700Schasinglulu printf("\n \"share_2d_vref_results\": \"0x%01x\",", (unsigned int)msg_1d->share2dvref_result); 2458*91f16700Schasinglulu printf("\n \"sequence_ctrl\": \"0x%04x\",", (unsigned int)msg_1d->sequence_ctrl); 2459*91f16700Schasinglulu printf("\n \"mr0\": \"0x%04x\",", (unsigned int)msg_1d->mr0); 2460*91f16700Schasinglulu printf("\n \"mr1\": \"0x%04x\",", (unsigned int)msg_1d->mr1); 2461*91f16700Schasinglulu printf("\n \"mr2\": \"0x%04x\",", (unsigned int)msg_1d->mr2); 2462*91f16700Schasinglulu printf("\n \"mr3\": \"0x%04x\",", (unsigned int)msg_1d->mr3); 2463*91f16700Schasinglulu printf("\n \"mr4\": \"0x%04x\",", (unsigned int)msg_1d->mr4); 2464*91f16700Schasinglulu printf("\n \"mr5\": \"0x%04x\",", (unsigned int)msg_1d->mr5); 2465*91f16700Schasinglulu printf("\n \"mr6\": \"0x%04x\",", (unsigned int)msg_1d->mr6); 2466*91f16700Schasinglulu printf("\n \"alt_cal_l\": \"0x%04x\",", (unsigned int)msg_1d->alt_cas_l); 2467*91f16700Schasinglulu printf("\n \"alt_wcal_l\": \"0x%04x\",", (unsigned int)msg_1d->alt_wcas_l); 2468*91f16700Schasinglulu printf("\n \"sequence_ctrl_2d\": \"0x%04x\",", (unsigned int)msg_2d->sequence_ctrl); 2469*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park0\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park0); 2470*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park1\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park1); 2471*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park2\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park2); 2472*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park3\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park3); 2473*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park4\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park4); 2474*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park5\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park5); 2475*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park6\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park6); 2476*91f16700Schasinglulu printf("\n \"rtt_nom_wr_park7\": \"0x%01x\"", (unsigned int)msg_1d->rtt_nom_wr_park7); 2477*91f16700Schasinglulu printf("\n}"); 2478*91f16700Schasinglulu printf("\n"); 2479*91f16700Schasinglulu } 2480*91f16700Schasinglulu #endif 2481*91f16700Schasinglulu 2482*91f16700Schasinglulu int compute_ddr_phy(struct ddr_info *priv) 2483*91f16700Schasinglulu { 2484*91f16700Schasinglulu const unsigned long clk = priv->clk; 2485*91f16700Schasinglulu const struct memctl_opt *popts = &priv->opt; 2486*91f16700Schasinglulu const struct ddr_conf *conf = &priv->conf; 2487*91f16700Schasinglulu const struct dimm_params *dimm_param = &priv->dimm; 2488*91f16700Schasinglulu struct ddr_cfg_regs *regs = &priv->ddr_reg; 2489*91f16700Schasinglulu int ret; 2490*91f16700Schasinglulu static struct input input; 2491*91f16700Schasinglulu static struct ddr4u1d msg_1d; 2492*91f16700Schasinglulu static struct ddr4u2d msg_2d; 2493*91f16700Schasinglulu unsigned int i; 2494*91f16700Schasinglulu unsigned int odt_rd, odt_wr; 2495*91f16700Schasinglulu __unused const soc_info_t *soc_info; 2496*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 2497*91f16700Schasinglulu unsigned int tcfg0, tcfg4, rank; 2498*91f16700Schasinglulu #ifdef NXP_WARM_BOOT 2499*91f16700Schasinglulu struct ddr_ctrl_reg_values ddrctrl_regs; 2500*91f16700Schasinglulu #endif 2501*91f16700Schasinglulu #endif 2502*91f16700Schasinglulu 2503*91f16700Schasinglulu if (dimm_param == NULL) { 2504*91f16700Schasinglulu ERROR("Empty DIMM parameters.\n"); 2505*91f16700Schasinglulu return -EINVAL; 2506*91f16700Schasinglulu } 2507*91f16700Schasinglulu 2508*91f16700Schasinglulu zeromem(&input, sizeof(input)); 2509*91f16700Schasinglulu zeromem(&msg_1d, sizeof(msg_1d)); 2510*91f16700Schasinglulu zeromem(&msg_2d, sizeof(msg_2d)); 2511*91f16700Schasinglulu 2512*91f16700Schasinglulu input.basic.dram_type = DDR4; 2513*91f16700Schasinglulu /* FIXME: Add condition for LRDIMM */ 2514*91f16700Schasinglulu input.basic.dimm_type = (dimm_param->rdimm != 0) ? RDIMM : UDIMM; 2515*91f16700Schasinglulu input.basic.num_dbyte = dimm_param->primary_sdram_width / 8 + 2516*91f16700Schasinglulu dimm_param->ec_sdram_width / 8; 2517*91f16700Schasinglulu input.basic.num_active_dbyte_dfi0 = input.basic.num_dbyte; 2518*91f16700Schasinglulu input.basic.num_rank_dfi0 = dimm_param->n_ranks; 2519*91f16700Schasinglulu input.basic.dram_data_width = dimm_param->device_width; 2520*91f16700Schasinglulu input.basic.hard_macro_ver = 0xa; 2521*91f16700Schasinglulu input.basic.num_pstates = 1; 2522*91f16700Schasinglulu input.basic.dfi_freq_ratio = 1; 2523*91f16700Schasinglulu input.basic.num_anib = 0xc; 2524*91f16700Schasinglulu input.basic.train2d = popts->skip2d ? 0 : 1; 2525*91f16700Schasinglulu input.basic.frequency = (int) (clk / 2000000ul); 2526*91f16700Schasinglulu debug("frequency = %dMHz\n", input.basic.frequency); 2527*91f16700Schasinglulu input.cs_d0 = conf->cs_on_dimm[0]; 2528*91f16700Schasinglulu #if DDRC_NUM_DIMM > 1 2529*91f16700Schasinglulu input.cs_d1 = conf->cs_on_dimm[1]; 2530*91f16700Schasinglulu #endif 2531*91f16700Schasinglulu input.mirror = dimm_param->mirrored_dimm; 2532*91f16700Schasinglulu input.mr[0] = regs->sdram_mode[0] & U(0xffff); 2533*91f16700Schasinglulu input.mr[1] = regs->sdram_mode[0] >> 16U; 2534*91f16700Schasinglulu input.mr[2] = regs->sdram_mode[1] >> 16U; 2535*91f16700Schasinglulu input.mr[3] = regs->sdram_mode[1] & U(0xffff); 2536*91f16700Schasinglulu input.mr[4] = regs->sdram_mode[8] >> 16U; 2537*91f16700Schasinglulu input.mr[5] = regs->sdram_mode[8] & U(0xffff); 2538*91f16700Schasinglulu input.mr[6] = regs->sdram_mode[9] >> 16U; 2539*91f16700Schasinglulu input.vref = popts->vref_phy; 2540*91f16700Schasinglulu debug("Vref_phy = %d percent\n", (input.vref * 100U) >> 7U); 2541*91f16700Schasinglulu for (i = 0U; i < DDRC_NUM_CS; i++) { 2542*91f16700Schasinglulu if ((regs->cs[i].config & SDRAM_CS_CONFIG_EN) == 0U) { 2543*91f16700Schasinglulu continue; 2544*91f16700Schasinglulu } 2545*91f16700Schasinglulu odt_rd = (regs->cs[i].config >> 20U) & U(0x7); 2546*91f16700Schasinglulu odt_wr = (regs->cs[i].config >> 16U) & U(0x7); 2547*91f16700Schasinglulu parse_odt(odt_rd, true, i, input.cs_d0, input.cs_d1, 2548*91f16700Schasinglulu input.odt); 2549*91f16700Schasinglulu parse_odt(odt_wr, false, i, input.cs_d0, input.cs_d1, 2550*91f16700Schasinglulu input.odt); 2551*91f16700Schasinglulu } 2552*91f16700Schasinglulu 2553*91f16700Schasinglulu /* Do not set sdram_cfg[RD_EN] or sdram_cfg2[RCW_EN] for RDIMM */ 2554*91f16700Schasinglulu if (dimm_param->rdimm != 0U) { 2555*91f16700Schasinglulu regs->sdram_cfg[0] &= ~(1 << 28U); 2556*91f16700Schasinglulu regs->sdram_cfg[1] &= ~(1 << 2U); 2557*91f16700Schasinglulu input.rcw[0] = (regs->sdram_rcw[0] >> 28U) & U(0xf); 2558*91f16700Schasinglulu input.rcw[1] = (regs->sdram_rcw[0] >> 24U) & U(0xf); 2559*91f16700Schasinglulu input.rcw[2] = (regs->sdram_rcw[0] >> 20U) & U(0xf); 2560*91f16700Schasinglulu input.rcw[3] = (regs->sdram_rcw[0] >> 16U) & U(0xf); 2561*91f16700Schasinglulu input.rcw[4] = (regs->sdram_rcw[0] >> 12U) & U(0xf); 2562*91f16700Schasinglulu input.rcw[5] = (regs->sdram_rcw[0] >> 8U) & U(0xf); 2563*91f16700Schasinglulu input.rcw[6] = (regs->sdram_rcw[0] >> 4U) & U(0xf); 2564*91f16700Schasinglulu input.rcw[7] = (regs->sdram_rcw[0] >> 0U) & U(0xf); 2565*91f16700Schasinglulu input.rcw[8] = (regs->sdram_rcw[1] >> 28U) & U(0xf); 2566*91f16700Schasinglulu input.rcw[9] = (regs->sdram_rcw[1] >> 24U) & U(0xf); 2567*91f16700Schasinglulu input.rcw[10] = (regs->sdram_rcw[1] >> 20U) & U(0xf); 2568*91f16700Schasinglulu input.rcw[11] = (regs->sdram_rcw[1] >> 16U) & U(0xf); 2569*91f16700Schasinglulu input.rcw[12] = (regs->sdram_rcw[1] >> 12U) & U(0xf); 2570*91f16700Schasinglulu input.rcw[13] = (regs->sdram_rcw[1] >> 8U) & U(0xf); 2571*91f16700Schasinglulu input.rcw[14] = (regs->sdram_rcw[1] >> 4U) & U(0xf); 2572*91f16700Schasinglulu input.rcw[15] = (regs->sdram_rcw[1] >> 0U) & U(0xf); 2573*91f16700Schasinglulu input.rcw3x = (regs->sdram_rcw[2] >> 8U) & U(0xff); 2574*91f16700Schasinglulu } 2575*91f16700Schasinglulu 2576*91f16700Schasinglulu input.adv.odtimpedance = popts->odt ? popts->odt : 60; 2577*91f16700Schasinglulu input.adv.tx_impedance = popts->phy_tx_impedance ? 2578*91f16700Schasinglulu popts->phy_tx_impedance : 28; 2579*91f16700Schasinglulu input.adv.atx_impedance = popts->phy_atx_impedance ? 2580*91f16700Schasinglulu popts->phy_atx_impedance : 30; 2581*91f16700Schasinglulu 2582*91f16700Schasinglulu debug("Initializing input adv data structure\n"); 2583*91f16700Schasinglulu phy_gen2_init_input(&input); 2584*91f16700Schasinglulu 2585*91f16700Schasinglulu debug("Initializing message block\n"); 2586*91f16700Schasinglulu ret = phy_gen2_msg_init(&msg_1d, &msg_2d, &input); 2587*91f16700Schasinglulu if (ret != 0) { 2588*91f16700Schasinglulu ERROR("Init msg failed (error code %d)\n", ret); 2589*91f16700Schasinglulu return ret; 2590*91f16700Schasinglulu } 2591*91f16700Schasinglulu 2592*91f16700Schasinglulu ret = c_init_phy_config(priv->phy, priv->ip_rev, &input, &msg_1d); 2593*91f16700Schasinglulu if (ret != 0) { 2594*91f16700Schasinglulu ERROR("Init PHY failed (error code %d)\n", ret); 2595*91f16700Schasinglulu return ret; 2596*91f16700Schasinglulu } 2597*91f16700Schasinglulu #ifdef NXP_WARM_BOOT 2598*91f16700Schasinglulu debug("Warm boot flag value %0x\n", priv->warm_boot_flag); 2599*91f16700Schasinglulu if (priv->warm_boot_flag == DDR_WARM_BOOT) { 2600*91f16700Schasinglulu debug("Restoring the Phy training data\n"); 2601*91f16700Schasinglulu // Restore the training data 2602*91f16700Schasinglulu ret = restore_phy_training_values(priv->phy, 2603*91f16700Schasinglulu PHY_TRAINING_REGS_ON_FLASH, 2604*91f16700Schasinglulu priv->num_ctlrs, 2605*91f16700Schasinglulu input.basic.train2d 2606*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 2607*91f16700Schasinglulu , &ddrctrl_regs 2608*91f16700Schasinglulu #endif 2609*91f16700Schasinglulu ); 2610*91f16700Schasinglulu if (ret != 0) { 2611*91f16700Schasinglulu ERROR("Restoring of training data failed %d\n", ret); 2612*91f16700Schasinglulu return ret; 2613*91f16700Schasinglulu } 2614*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 2615*91f16700Schasinglulu regs->timing_cfg[0] = ddrctrl_regs.timing_cfg0; 2616*91f16700Schasinglulu regs->timing_cfg[4] = ddrctrl_regs.timing_cfg4; 2617*91f16700Schasinglulu #endif 2618*91f16700Schasinglulu } else { 2619*91f16700Schasinglulu #endif 2620*91f16700Schasinglulu /* Mapping IMG buffer firstly */ 2621*91f16700Schasinglulu ret = mmap_add_dynamic_region(priv->phy_gen2_fw_img_buf, 2622*91f16700Schasinglulu priv->phy_gen2_fw_img_buf, 2623*91f16700Schasinglulu PHY_GEN2_MAX_IMAGE_SIZE, 2624*91f16700Schasinglulu MT_MEMORY | MT_RW | MT_SECURE); 2625*91f16700Schasinglulu if (ret != 0) { 2626*91f16700Schasinglulu ERROR("Failed to add dynamic memory region.\n"); 2627*91f16700Schasinglulu return ret; 2628*91f16700Schasinglulu } 2629*91f16700Schasinglulu 2630*91f16700Schasinglulu debug("Load 1D firmware\n"); 2631*91f16700Schasinglulu ret = load_fw(priv->phy, &input, 0, &msg_1d, 2632*91f16700Schasinglulu sizeof(struct ddr4u1d), priv->phy_gen2_fw_img_buf, 2633*91f16700Schasinglulu priv->img_loadr, priv->warm_boot_flag); 2634*91f16700Schasinglulu if (ret != 0) { 2635*91f16700Schasinglulu ERROR("Loading firmware failed (error code %d)\n", ret); 2636*91f16700Schasinglulu return ret; 2637*91f16700Schasinglulu } 2638*91f16700Schasinglulu 2639*91f16700Schasinglulu debug("Execute firmware\n"); 2640*91f16700Schasinglulu ret = g_exec_fw(priv->phy, 0, &input); 2641*91f16700Schasinglulu if (ret != 0) { 2642*91f16700Schasinglulu ERROR("Execution FW failed (error code %d)\n", ret); 2643*91f16700Schasinglulu } 2644*91f16700Schasinglulu 2645*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 2646*91f16700Schasinglulu soc_info = get_soc_info(); 2647*91f16700Schasinglulu if (soc_info->svr_reg.bf.maj_ver == 2) { 2648*91f16700Schasinglulu tcfg0 = regs->timing_cfg[0]; 2649*91f16700Schasinglulu tcfg4 = regs->timing_cfg[4]; 2650*91f16700Schasinglulu rank = findrank(conf->cs_in_use); 2651*91f16700Schasinglulu get_cdd_val(priv->phy, rank, input.basic.frequency, 2652*91f16700Schasinglulu &tcfg0, &tcfg4); 2653*91f16700Schasinglulu regs->timing_cfg[0] = tcfg0; 2654*91f16700Schasinglulu regs->timing_cfg[4] = tcfg4; 2655*91f16700Schasinglulu } 2656*91f16700Schasinglulu #endif 2657*91f16700Schasinglulu 2658*91f16700Schasinglulu if ((ret == 0) && (input.basic.train2d != 0)) { 2659*91f16700Schasinglulu /* 2D training starts here */ 2660*91f16700Schasinglulu debug("Load 2D firmware\n"); 2661*91f16700Schasinglulu ret = load_fw(priv->phy, &input, 1, &msg_2d, 2662*91f16700Schasinglulu sizeof(struct ddr4u2d), 2663*91f16700Schasinglulu priv->phy_gen2_fw_img_buf, 2664*91f16700Schasinglulu priv->img_loadr, 2665*91f16700Schasinglulu priv->warm_boot_flag); 2666*91f16700Schasinglulu if (ret != 0) { 2667*91f16700Schasinglulu ERROR("Loading fw failed (err code %d)\n", ret); 2668*91f16700Schasinglulu } else { 2669*91f16700Schasinglulu debug("Execute 2D firmware\n"); 2670*91f16700Schasinglulu ret = g_exec_fw(priv->phy, 1, &input); 2671*91f16700Schasinglulu if (ret != 0) { 2672*91f16700Schasinglulu ERROR("Execution FW failed (err %d)\n", 2673*91f16700Schasinglulu ret); 2674*91f16700Schasinglulu } 2675*91f16700Schasinglulu } 2676*91f16700Schasinglulu } 2677*91f16700Schasinglulu #ifdef NXP_WARM_BOOT 2678*91f16700Schasinglulu if (priv->warm_boot_flag != DDR_WRM_BOOT_NT_SUPPORTED && 2679*91f16700Schasinglulu ret == 0) { 2680*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 2681*91f16700Schasinglulu ddrctrl_regs.timing_cfg0 = regs->timing_cfg[0]; 2682*91f16700Schasinglulu ddrctrl_regs.timing_cfg4 = regs->timing_cfg[4]; 2683*91f16700Schasinglulu #endif 2684*91f16700Schasinglulu debug("save the phy training data\n"); 2685*91f16700Schasinglulu //Save training data TBD 2686*91f16700Schasinglulu ret = save_phy_training_values(priv->phy, 2687*91f16700Schasinglulu PHY_TRAINING_REGS_ON_FLASH, 2688*91f16700Schasinglulu priv->num_ctlrs, 2689*91f16700Schasinglulu input.basic.train2d 2690*91f16700Schasinglulu #ifdef NXP_APPLY_MAX_CDD 2691*91f16700Schasinglulu , &ddrctrl_regs 2692*91f16700Schasinglulu #endif 2693*91f16700Schasinglulu ); 2694*91f16700Schasinglulu if (ret != 0) { 2695*91f16700Schasinglulu ERROR("Saving training data failed."); 2696*91f16700Schasinglulu ERROR("Warm boot will fail. Error=%d.\n", ret); 2697*91f16700Schasinglulu } 2698*91f16700Schasinglulu } 2699*91f16700Schasinglulu } /* else */ 2700*91f16700Schasinglulu #endif 2701*91f16700Schasinglulu 2702*91f16700Schasinglulu if (ret == 0) { 2703*91f16700Schasinglulu debug("Load PIE\n"); 2704*91f16700Schasinglulu i_load_pie(priv->phy, &input, &msg_1d); 2705*91f16700Schasinglulu 2706*91f16700Schasinglulu NOTICE("DDR4 %s with %d-rank %d-bit bus (x%d)\n", 2707*91f16700Schasinglulu input.basic.dimm_type == RDIMM ? "RDIMM" : 2708*91f16700Schasinglulu input.basic.dimm_type == LRDIMM ? "LRDIMM" : 2709*91f16700Schasinglulu "UDIMM", 2710*91f16700Schasinglulu dimm_param->n_ranks, 2711*91f16700Schasinglulu dimm_param->primary_sdram_width, 2712*91f16700Schasinglulu dimm_param->device_width); 2713*91f16700Schasinglulu } 2714*91f16700Schasinglulu #ifdef DEBUG_DDR_INPUT_CONFIG 2715*91f16700Schasinglulu print_jason_format(&input, &msg_1d, &msg_2d); 2716*91f16700Schasinglulu #endif 2717*91f16700Schasinglulu 2718*91f16700Schasinglulu return ret; 2719*91f16700Schasinglulu } 2720