1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause 2/* 3 * (C) Copyright 2020-2021 SiFive, Inc. 4 * 5 * Authors: 6 * Pragnesh Patel <pragnesh.patel@sifive.com> 7 */ 8 9#include <common.h> 10#include <dm.h> 11#include <fdtdec.h> 12#include <init.h> 13#include <ram.h> 14#include <syscon.h> 15#include <asm/global_data.h> 16#include <asm/io.h> 17#include <clk.h> 18#include <wait_bit.h> 19#include <linux/bitops.h> 20 21#define DENALI_CTL_0 0 22#define DENALI_CTL_21 21 23#define DENALI_CTL_120 120 24#define DENALI_CTL_132 132 25#define DENALI_CTL_136 136 26#define DENALI_CTL_170 170 27#define DENALI_CTL_181 181 28#define DENALI_CTL_182 182 29#define DENALI_CTL_184 184 30#define DENALI_CTL_208 208 31#define DENALI_CTL_209 209 32#define DENALI_CTL_210 210 33#define DENALI_CTL_212 212 34#define DENALI_CTL_214 214 35#define DENALI_CTL_216 216 36#define DENALI_CTL_224 224 37#define DENALI_CTL_225 225 38#define DENALI_CTL_260 260 39 40#define DENALI_PHY_1152 1152 41#define DENALI_PHY_1214 1214 42 43#define DRAM_CLASS_OFFSET 8 44#define DRAM_CLASS_DDR4 0xA 45#define OPTIMAL_RMODW_EN_OFFSET 0 46#define DISABLE_RD_INTERLEAVE_OFFSET 16 47#define OUT_OF_RANGE_OFFSET 1 48#define MULTIPLE_OUT_OF_RANGE_OFFSET 2 49#define PORT_COMMAND_CHANNEL_ERROR_OFFSET 7 50#define MC_INIT_COMPLETE_OFFSET 8 51#define LEVELING_OPERATION_COMPLETED_OFFSET 22 52#define DFI_PHY_WRLELV_MODE_OFFSET 24 53#define DFI_PHY_RDLVL_MODE_OFFSET 24 54#define DFI_PHY_RDLVL_GATE_MODE_OFFSET 0 55#define VREF_EN_OFFSET 24 56#define PORT_ADDR_PROTECTION_EN_OFFSET 0 57#define AXI0_ADDRESS_RANGE_ENABLE 8 58#define AXI0_RANGE_PROT_BITS_0_OFFSET 24 59#define RDLVL_EN_OFFSET 16 60#define RDLVL_GATE_EN_OFFSET 24 61#define WRLVL_EN_OFFSET 0 62 63#define PHY_RX_CAL_DQ0_0_OFFSET 0 64#define PHY_RX_CAL_DQ1_0_OFFSET 16 65 66DECLARE_GLOBAL_DATA_PTR; 67 68struct sifive_ddrctl { 69 volatile u32 denali_ctl[265]; 70}; 71 72struct sifive_ddrphy { 73 volatile u32 denali_phy[1215]; 74}; 75 76/** 77 * struct sifive_ddr_info 78 * 79 * @dev : pointer for the device 80 * @info : UCLASS RAM information 81 * @ctl : DDR controller base address 82 * @phy : DDR PHY base address 83 * @ctrl : DDR control base address 84 * @physical_filter_ctrl : DDR physical filter control base address 85 */ 86struct sifive_ddr_info { 87 struct udevice *dev; 88 struct ram_info info; 89 struct sifive_ddrctl *ctl; 90 struct sifive_ddrphy *phy; 91 struct clk ddr_clk; 92 u32 *physical_filter_ctrl; 93}; 94 95#if defined(CONFIG_SPL_BUILD) 96struct sifive_ddr_params { 97 struct sifive_ddrctl pctl_regs; 98 struct sifive_ddrphy phy_regs; 99}; 100 101struct sifive_dmc_plat { 102 struct sifive_ddr_params ddr_params; 103}; 104 105/* 106 * TODO : It can be possible to use common sdram_copy_to_reg() API 107 * n: Unit bytes 108 */ 109static void sdram_copy_to_reg(volatile u32 *dest, 110 volatile u32 *src, u32 n) 111{ 112 int i; 113 114 for (i = 0; i < n / sizeof(u32); i++) { 115 writel(*src, dest); 116 src++; 117 dest++; 118 } 119} 120 121static void sifive_ddr_setup_range_protection(volatile u32 *ctl, u64 end_addr) 122{ 123 u32 end_addr_16kblocks = ((end_addr >> 14) & 0x7FFFFF) - 1; 124 125 writel(0x0, DENALI_CTL_209 + ctl); 126 writel(end_addr_16kblocks, DENALI_CTL_210 + ctl); 127 writel(0x0, DENALI_CTL_212 + ctl); 128 writel(0x0, DENALI_CTL_214 + ctl); 129 writel(0x0, DENALI_CTL_216 + ctl); 130 setbits_le32(DENALI_CTL_224 + ctl, 131 0x3 << AXI0_RANGE_PROT_BITS_0_OFFSET); 132 writel(0xFFFFFFFF, DENALI_CTL_225 + ctl); 133 setbits_le32(DENALI_CTL_208 + ctl, 0x1 << AXI0_ADDRESS_RANGE_ENABLE); 134 setbits_le32(DENALI_CTL_208 + ctl, 135 0x1 << PORT_ADDR_PROTECTION_EN_OFFSET); 136} 137 138static void sifive_ddr_start(volatile u32 *ctl, u32 *physical_filter_ctrl, 139 u64 ddr_end) 140{ 141 volatile u64 *filterreg = (volatile u64 *)physical_filter_ctrl; 142 143 setbits_le32(DENALI_CTL_0 + ctl, 0x1); 144 145 wait_for_bit_le32((void *)ctl + DENALI_CTL_132, 146 BIT(MC_INIT_COMPLETE_OFFSET), false, 100, false); 147 148 /* Disable the BusBlocker in front of the controller AXI slave ports */ 149 filterreg[0] = 0x0f00000000000000UL | (ddr_end >> 2); 150} 151 152static void sifive_ddr_check_errata(u32 regbase, u32 updownreg) 153{ 154 u64 fails = 0; 155 u32 dq = 0; 156 u32 down, up; 157 u8 failc0, failc1; 158 u32 phy_rx_cal_dqn_0_offset; 159 160 for (u32 bit = 0; bit < 2; bit++) { 161 if (bit == 0) { 162 phy_rx_cal_dqn_0_offset = 163 PHY_RX_CAL_DQ0_0_OFFSET; 164 } else { 165 phy_rx_cal_dqn_0_offset = 166 PHY_RX_CAL_DQ1_0_OFFSET; 167 } 168 169 down = (updownreg >> 170 phy_rx_cal_dqn_0_offset) & 0x3F; 171 up = (updownreg >> 172 (phy_rx_cal_dqn_0_offset + 6)) & 173 0x3F; 174 175 failc0 = ((down == 0) && (up == 0x3F)); 176 failc1 = ((up == 0) && (down == 0x3F)); 177 178 /* print error message on failure */ 179 if (failc0 || failc1) { 180 if (fails == 0) 181 printf("DDR error in fixing up\n"); 182 183 fails |= (1 << dq); 184 185 char slicelsc = '0'; 186 char slicemsc = '0'; 187 188 slicelsc += (dq % 10); 189 slicemsc += (dq / 10); 190 printf("S "); 191 printf("%c", slicemsc); 192 printf("%c", slicelsc); 193 194 if (failc0) 195 printf("U"); 196 else 197 printf("D"); 198 199 printf("\n"); 200 } 201 dq++; 202 } 203} 204 205static u64 sifive_ddr_phy_fixup(volatile u32 *ddrphyreg) 206{ 207 u32 slicebase = 0; 208 209 /* check errata condition */ 210 for (u32 slice = 0; slice < 8; slice++) { 211 u32 regbase = slicebase + 34; 212 213 for (u32 reg = 0; reg < 4; reg++) { 214 u32 updownreg = readl(regbase + reg + ddrphyreg); 215 216 sifive_ddr_check_errata(regbase, updownreg); 217 } 218 slicebase += 128; 219 } 220 221 return(0); 222} 223 224static u32 sifive_ddr_get_dram_class(volatile u32 *ctl) 225{ 226 u32 reg = readl(DENALI_CTL_0 + ctl); 227 228 return ((reg >> DRAM_CLASS_OFFSET) & 0xF); 229} 230 231static int sifive_ddr_setup(struct udevice *dev) 232{ 233 struct sifive_ddr_info *priv = dev_get_priv(dev); 234 struct sifive_dmc_plat *plat = dev_get_plat(dev); 235 struct sifive_ddr_params *params = &plat->ddr_params; 236 volatile u32 *denali_ctl = priv->ctl->denali_ctl; 237 volatile u32 *denali_phy = priv->phy->denali_phy; 238 const u64 ddr_size = priv->info.size; 239 const u64 ddr_end = priv->info.base + ddr_size; 240 int ret, i; 241 u32 physet; 242 243 ret = dev_read_u32_array(dev, "sifive,ddr-params", 244 (u32 *)&plat->ddr_params, 245 sizeof(plat->ddr_params) / sizeof(u32)); 246 if (ret) { 247 printf("%s: Cannot read sifive,ddr-params %d\n", 248 __func__, ret); 249 return ret; 250 } 251 252 sdram_copy_to_reg(priv->ctl->denali_ctl, 253 params->pctl_regs.denali_ctl, 254 sizeof(struct sifive_ddrctl)); 255 256 /* phy reset */ 257 for (i = DENALI_PHY_1152; i <= DENALI_PHY_1214; i++) { 258 physet = params->phy_regs.denali_phy[i]; 259 priv->phy->denali_phy[i] = physet; 260 } 261 262 for (i = 0; i < DENALI_PHY_1152; i++) { 263 physet = params->phy_regs.denali_phy[i]; 264 priv->phy->denali_phy[i] = physet; 265 } 266 267 /* Disable read interleave DENALI_CTL_120 */ 268 setbits_le32(DENALI_CTL_120 + denali_ctl, 269 1 << DISABLE_RD_INTERLEAVE_OFFSET); 270 271 /* Disable optimal read/modify/write logic DENALI_CTL_21 */ 272 clrbits_le32(DENALI_CTL_21 + denali_ctl, 1 << OPTIMAL_RMODW_EN_OFFSET); 273 274 /* Enable write Leveling DENALI_CTL_170 */ 275 setbits_le32(DENALI_CTL_170 + denali_ctl, (1 << WRLVL_EN_OFFSET) 276 | (1 << DFI_PHY_WRLELV_MODE_OFFSET)); 277 278 /* Enable read leveling DENALI_CTL_181 and DENALI_CTL_260 */ 279 setbits_le32(DENALI_CTL_181 + denali_ctl, 280 1 << DFI_PHY_RDLVL_MODE_OFFSET); 281 setbits_le32(DENALI_CTL_260 + denali_ctl, 1 << RDLVL_EN_OFFSET); 282 283 /* Enable read leveling gate DENALI_CTL_260 and DENALI_CTL_182 */ 284 setbits_le32(DENALI_CTL_260 + denali_ctl, 1 << RDLVL_GATE_EN_OFFSET); 285 setbits_le32(DENALI_CTL_182 + denali_ctl, 286 1 << DFI_PHY_RDLVL_GATE_MODE_OFFSET); 287 288 if (sifive_ddr_get_dram_class(denali_ctl) == DRAM_CLASS_DDR4) { 289 /* Enable vref training DENALI_CTL_184 */ 290 setbits_le32(DENALI_CTL_184 + denali_ctl, 1 << VREF_EN_OFFSET); 291 } 292 293 /* Mask off leveling completion interrupt DENALI_CTL_136 */ 294 setbits_le32(DENALI_CTL_136 + denali_ctl, 295 1 << LEVELING_OPERATION_COMPLETED_OFFSET); 296 297 /* Mask off MC init complete interrupt DENALI_CTL_136 */ 298 setbits_le32(DENALI_CTL_136 + denali_ctl, 1 << MC_INIT_COMPLETE_OFFSET); 299 300 /* Mask off out of range interrupts DENALI_CTL_136 */ 301 setbits_le32(DENALI_CTL_136 + denali_ctl, (1 << OUT_OF_RANGE_OFFSET) 302 | (1 << MULTIPLE_OUT_OF_RANGE_OFFSET)); 303 304 /* set up range protection */ 305 sifive_ddr_setup_range_protection(denali_ctl, priv->info.size); 306 307 /* Mask off port command error interrupt DENALI_CTL_136 */ 308 setbits_le32(DENALI_CTL_136 + denali_ctl, 309 1 << PORT_COMMAND_CHANNEL_ERROR_OFFSET); 310 311 sifive_ddr_start(denali_ctl, priv->physical_filter_ctrl, ddr_end); 312 313 sifive_ddr_phy_fixup(denali_phy); 314 315 /* check size */ 316 priv->info.size = get_ram_size((long *)(uintptr_t)priv->info.base, 317 ddr_size); 318 319 debug("%s : %lx\n", __func__, (uintptr_t)priv->info.size); 320 321 /* check memory access for all memory */ 322 if (priv->info.size != ddr_size) { 323 printf("DDR invalid size : 0x%lx, expected 0x%lx\n", 324 (uintptr_t)priv->info.size, (uintptr_t)ddr_size); 325 return -EINVAL; 326 } 327 328 return 0; 329} 330#endif 331 332static int sifive_ddr_probe(struct udevice *dev) 333{ 334 struct sifive_ddr_info *priv = dev_get_priv(dev); 335 336 /* Read memory base and size from DT */ 337 fdtdec_setup_mem_size_base(); 338 priv->info.base = gd->ram_base; 339 priv->info.size = gd->ram_size; 340 341#if defined(CONFIG_SPL_BUILD) 342 int ret; 343 u32 clock = 0; 344 345 debug("sifive DDR probe\n"); 346 priv->dev = dev; 347 348 ret = clk_get_by_index(dev, 0, &priv->ddr_clk); 349 if (ret) { 350 debug("clk get failed %d\n", ret); 351 return ret; 352 } 353 354 ret = dev_read_u32(dev, "clock-frequency", &clock); 355 if (ret) { 356 debug("clock-frequency not found in dt %d\n", ret); 357 return ret; 358 } else { 359 ret = clk_set_rate(&priv->ddr_clk, clock); 360 if (ret < 0) { 361 debug("Could not set DDR clock\n"); 362 return ret; 363 } 364 } 365 366 ret = clk_enable(&priv->ddr_clk); 367 if (ret < 0) { 368 debug("Could not enable DDR clock\n"); 369 return ret; 370 } 371 372 priv->ctl = (struct sifive_ddrctl *)dev_read_addr_index_ptr(dev, 0); 373 priv->phy = (struct sifive_ddrphy *)dev_read_addr_index_ptr(dev, 1); 374 priv->physical_filter_ctrl = (u32 *)dev_read_addr_index_ptr(dev, 2); 375 376 return sifive_ddr_setup(dev); 377#endif 378 379 return 0; 380} 381 382static int sifive_ddr_get_info(struct udevice *dev, struct ram_info *info) 383{ 384 struct sifive_ddr_info *priv = dev_get_priv(dev); 385 386 *info = priv->info; 387 388 return 0; 389} 390 391static struct ram_ops sifive_ddr_ops = { 392 .get_info = sifive_ddr_get_info, 393}; 394 395static const struct udevice_id sifive_ddr_ids[] = { 396 { .compatible = "sifive,fu540-c000-ddr" }, 397 { .compatible = "sifive,fu740-c000-ddr" }, 398 { } 399}; 400 401U_BOOT_DRIVER(sifive_ddr) = { 402 .name = "sifive_ddr", 403 .id = UCLASS_RAM, 404 .of_match = sifive_ddr_ids, 405 .ops = &sifive_ddr_ops, 406 .probe = sifive_ddr_probe, 407 .priv_auto = sizeof(struct sifive_ddr_info), 408#if defined(CONFIG_SPL_BUILD) 409 .plat_auto = sizeof(struct sifive_dmc_plat), 410#endif 411}; 412