1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2018 NXP 4 */ 5 6 #include <common.h> 7 #include <errno.h> 8 #include <asm/io.h> 9 #include <asm/arch/ddr.h> 10 #include <asm/arch/clock.h> 11 #include <asm/arch/ddr.h> 12 #include <asm/arch/lpddr4_define.h> 13 14 static inline void poll_pmu_message_ready(void) 15 { 16 unsigned int reg; 17 18 do { 19 reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0004); 20 } while (reg & 0x1); 21 } 22 23 static inline void ack_pmu_message_receive(void) 24 { 25 unsigned int reg; 26 27 reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0031, 0x0); 28 29 do { 30 reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0004); 31 } while (!(reg & 0x1)); 32 33 reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0031, 0x1); 34 } 35 36 static inline unsigned int get_mail(void) 37 { 38 unsigned int reg; 39 40 poll_pmu_message_ready(); 41 42 reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0032); 43 44 ack_pmu_message_receive(); 45 46 return reg; 47 } 48 49 static inline unsigned int get_stream_message(void) 50 { 51 unsigned int reg, reg2; 52 53 poll_pmu_message_ready(); 54 55 reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0032); 56 57 reg2 = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0034); 58 59 reg2 = (reg2 << 16) | reg; 60 61 ack_pmu_message_receive(); 62 63 return reg2; 64 } 65 66 static inline void decode_major_message(unsigned int mail) 67 { 68 debug("[PMU Major message = 0x%08x]\n", mail); 69 } 70 71 static inline void decode_streaming_message(void) 72 { 73 unsigned int string_index, arg __maybe_unused; 74 int i = 0; 75 76 string_index = get_stream_message(); 77 debug("PMU String index = 0x%08x\n", string_index); 78 while (i < (string_index & 0xffff)) { 79 arg = get_stream_message(); 80 debug("arg[%d] = 0x%08x\n", i, arg); 81 i++; 82 } 83 84 debug("\n"); 85 } 86 87 void wait_ddrphy_training_complete(void) 88 { 89 unsigned int mail; 90 91 while (1) { 92 mail = get_mail(); 93 decode_major_message(mail); 94 if (mail == 0x08) { 95 decode_streaming_message(); 96 } else if (mail == 0x07) { 97 debug("Training PASS\n"); 98 break; 99 } else if (mail == 0xff) { 100 printf("Training FAILED\n"); 101 break; 102 } 103 } 104 } 105 106 void ddrphy_init_set_dfi_clk(unsigned int drate) 107 { 108 switch (drate) { 109 case 3200: 110 dram_pll_init(MHZ(800)); 111 dram_disable_bypass(); 112 break; 113 case 3000: 114 dram_pll_init(MHZ(750)); 115 dram_disable_bypass(); 116 break; 117 case 2400: 118 dram_pll_init(MHZ(600)); 119 dram_disable_bypass(); 120 break; 121 case 1600: 122 dram_pll_init(MHZ(400)); 123 dram_disable_bypass(); 124 break; 125 case 667: 126 dram_pll_init(MHZ(167)); 127 dram_disable_bypass(); 128 break; 129 case 400: 130 dram_enable_bypass(MHZ(400)); 131 break; 132 case 100: 133 dram_enable_bypass(MHZ(100)); 134 break; 135 default: 136 return; 137 } 138 } 139 140 void ddrphy_init_read_msg_block(enum fw_type type) 141 { 142 } 143 144 void lpddr4_mr_write(unsigned int mr_rank, unsigned int mr_addr, 145 unsigned int mr_data) 146 { 147 unsigned int tmp; 148 /* 149 * 1. Poll MRSTAT.mr_wr_busy until it is 0. 150 * This checks that there is no outstanding MR transaction. 151 * No writes should be performed to MRCTRL0 and MRCTRL1 if 152 * MRSTAT.mr_wr_busy = 1. 153 */ 154 do { 155 tmp = reg32_read(DDRC_MRSTAT(0)); 156 } while (tmp & 0x1); 157 /* 158 * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank and 159 * (for MRWs) MRCTRL1.mr_data to define the MR transaction. 160 */ 161 reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4)); 162 reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data); 163 reg32setbit(DDRC_MRCTRL0(0), 31); 164 } 165 166 unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr) 167 { 168 unsigned int tmp; 169 170 reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x1); 171 do { 172 tmp = reg32_read(DDRC_MRSTAT(0)); 173 } while (tmp & 0x1); 174 175 reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4) | 0x1); 176 reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8)); 177 reg32setbit(DDRC_MRCTRL0(0), 31); 178 do { 179 tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0)); 180 } while ((tmp & 0x8) == 0); 181 tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0)); 182 tmp = tmp & 0xff; 183 reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4); 184 185 return tmp; 186 } 187