174803decSYouMin Chen // SPDX-License-Identifier: GPL-2.0 274803decSYouMin Chen /* 374803decSYouMin Chen * (C) Copyright 2018 Rockchip Electronics Co., Ltd. 474803decSYouMin Chen */ 574803decSYouMin Chen 674803decSYouMin Chen #include <common.h> 774803decSYouMin Chen #include <ram.h> 874803decSYouMin Chen #include <asm/io.h> 9e1f97ec3SYouMin Chen #include <asm/arch/sdram.h> 1074803decSYouMin Chen #include <asm/arch/sdram_pctl_px30.h> 1174803decSYouMin Chen 1274803decSYouMin Chen /* 1374803decSYouMin Chen * rank = 1: cs0 1474803decSYouMin Chen * rank = 2: cs1 1574803decSYouMin Chen */ 1674803decSYouMin Chen void pctl_read_mr(void __iomem *pctl_base, u32 rank, u32 mr_num) 1774803decSYouMin Chen { 1874803decSYouMin Chen writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0); 1974803decSYouMin Chen writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1); 2074803decSYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); 2174803decSYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) 2274803decSYouMin Chen continue; 23*9442a4b3SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & PCTL2_MR_WR_BUSY) 2474803decSYouMin Chen continue; 2574803decSYouMin Chen } 2674803decSYouMin Chen 2774803decSYouMin Chen /* rank = 1: cs0 2874803decSYouMin Chen * rank = 2: cs1 2974803decSYouMin Chen * rank = 3: cs0 & cs1 3074803decSYouMin Chen * note: be careful of keep mr original val 3174803decSYouMin Chen */ 3274803decSYouMin Chen int pctl_write_mr(void __iomem *pctl_base, u32 rank, u32 mr_num, u32 arg, 3374803decSYouMin Chen u32 dramtype) 3474803decSYouMin Chen { 35*9442a4b3SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & PCTL2_MR_WR_BUSY) 3674803decSYouMin Chen continue; 3774803decSYouMin Chen if (dramtype == DDR3 || dramtype == DDR4) { 3874803decSYouMin Chen writel((mr_num << 12) | (rank << 4) | (0 << 0), 3974803decSYouMin Chen pctl_base + DDR_PCTL2_MRCTRL0); 4074803decSYouMin Chen writel(arg, pctl_base + DDR_PCTL2_MRCTRL1); 4174803decSYouMin Chen } else { 4274803decSYouMin Chen writel((rank << 4) | (0 << 0), 4374803decSYouMin Chen pctl_base + DDR_PCTL2_MRCTRL0); 4474803decSYouMin Chen writel((mr_num << 8) | (arg & 0xff), 4574803decSYouMin Chen pctl_base + DDR_PCTL2_MRCTRL1); 4674803decSYouMin Chen } 4774803decSYouMin Chen 4874803decSYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); 4974803decSYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) 5074803decSYouMin Chen continue; 51*9442a4b3SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & PCTL2_MR_WR_BUSY) 5274803decSYouMin Chen continue; 5374803decSYouMin Chen 5474803decSYouMin Chen return 0; 5574803decSYouMin Chen } 5674803decSYouMin Chen 5774803decSYouMin Chen /* 5874803decSYouMin Chen * rank : 1:cs0, 2:cs1, 3:cs0&cs1 5974803decSYouMin Chen * vrefrate: 4500: 45%, 6074803decSYouMin Chen */ 6174803decSYouMin Chen int pctl_write_vrefdq(void __iomem *pctl_base, u32 rank, u32 vrefrate, 6274803decSYouMin Chen u32 dramtype) 6374803decSYouMin Chen { 6474803decSYouMin Chen u32 tccd_l, value; 6574803decSYouMin Chen u32 dis_auto_zq = 0; 6674803decSYouMin Chen 67*9442a4b3SYouMin Chen if (dramtype != DDR4 || vrefrate < 4500 || vrefrate > 9250) 6874803decSYouMin Chen return (-1); 6974803decSYouMin Chen 7074803decSYouMin Chen tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf; 7174803decSYouMin Chen tccd_l = (tccd_l - 4) << 10; 7274803decSYouMin Chen 7374803decSYouMin Chen if (vrefrate > 7500) { 7474803decSYouMin Chen /* range 1 */ 7574803decSYouMin Chen value = ((vrefrate - 6000) / 65) | tccd_l; 7674803decSYouMin Chen } else { 7774803decSYouMin Chen /* range 2 */ 7874803decSYouMin Chen value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6); 7974803decSYouMin Chen } 8074803decSYouMin Chen 8174803decSYouMin Chen dis_auto_zq = pctl_dis_zqcs_aref(pctl_base); 8274803decSYouMin Chen 8374803decSYouMin Chen /* enable vrefdq calibratin */ 8474803decSYouMin Chen pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype); 8574803decSYouMin Chen udelay(1);/* tvrefdqe */ 8674803decSYouMin Chen /* write vrefdq value */ 8774803decSYouMin Chen pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype); 8874803decSYouMin Chen udelay(1);/* tvref_time */ 8974803decSYouMin Chen pctl_write_mr(pctl_base, rank, 6, value | (0 << 7), dramtype); 9074803decSYouMin Chen udelay(1);/* tvrefdqx */ 9174803decSYouMin Chen 9274803decSYouMin Chen pctl_rest_zqcs_aref(pctl_base, dis_auto_zq); 9374803decSYouMin Chen 9474803decSYouMin Chen return 0; 9574803decSYouMin Chen } 9674803decSYouMin Chen 9774803decSYouMin Chen static int upctl2_update_ref_reg(void __iomem *pctl_base) 9874803decSYouMin Chen { 9974803decSYouMin Chen u32 ret; 10074803decSYouMin Chen 10174803decSYouMin Chen ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1); 10274803decSYouMin Chen writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3); 10374803decSYouMin Chen 10474803decSYouMin Chen return 0; 10574803decSYouMin Chen } 10674803decSYouMin Chen 10774803decSYouMin Chen u32 pctl_dis_zqcs_aref(void __iomem *pctl_base) 10874803decSYouMin Chen { 10974803decSYouMin Chen u32 dis_auto_zq = 0; 11074803decSYouMin Chen 11174803decSYouMin Chen /* disable zqcs */ 11274803decSYouMin Chen if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) & 11374803decSYouMin Chen (1ul << 31))) { 11474803decSYouMin Chen dis_auto_zq = 1; 11574803decSYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); 11674803decSYouMin Chen } 11774803decSYouMin Chen 11874803decSYouMin Chen /* disable auto refresh */ 11974803decSYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); 12074803decSYouMin Chen 12174803decSYouMin Chen upctl2_update_ref_reg(pctl_base); 12274803decSYouMin Chen 12374803decSYouMin Chen return dis_auto_zq; 12474803decSYouMin Chen } 12574803decSYouMin Chen 12674803decSYouMin Chen void pctl_rest_zqcs_aref(void __iomem *pctl_base, u32 dis_auto_zq) 12774803decSYouMin Chen { 12874803decSYouMin Chen /* restore zqcs */ 12974803decSYouMin Chen if (dis_auto_zq) 13074803decSYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); 13174803decSYouMin Chen 13274803decSYouMin Chen /* restore auto refresh */ 13374803decSYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); 13474803decSYouMin Chen 13574803decSYouMin Chen upctl2_update_ref_reg(pctl_base); 13674803decSYouMin Chen } 13774803decSYouMin Chen 13874803decSYouMin Chen u32 pctl_remodify_sdram_params(struct ddr_pctl_regs *pctl_regs, 13974803decSYouMin Chen struct sdram_cap_info *cap_info, 14074803decSYouMin Chen u32 dram_type) 14174803decSYouMin Chen { 14274803decSYouMin Chen u32 tmp = 0, tmp_adr = 0, i; 14374803decSYouMin Chen 14474803decSYouMin Chen for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) { 14574803decSYouMin Chen if (pctl_regs->pctl[i][0] == 0) { 14674803decSYouMin Chen tmp = pctl_regs->pctl[i][1];/* MSTR */ 14774803decSYouMin Chen tmp_adr = i; 14874803decSYouMin Chen } 14974803decSYouMin Chen } 15074803decSYouMin Chen 15174803decSYouMin Chen tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12)); 15274803decSYouMin Chen 15374803decSYouMin Chen switch (cap_info->dbw) { 15474803decSYouMin Chen case 2: 15574803decSYouMin Chen tmp |= (3ul << 30); 15674803decSYouMin Chen break; 15774803decSYouMin Chen case 1: 15874803decSYouMin Chen tmp |= (2ul << 30); 15974803decSYouMin Chen break; 16074803decSYouMin Chen case 0: 16174803decSYouMin Chen default: 16274803decSYouMin Chen tmp |= (1ul << 30); 16374803decSYouMin Chen break; 16474803decSYouMin Chen } 16574803decSYouMin Chen 166*9442a4b3SYouMin Chen /* active_ranks always keep 2 rank for dfi monitor */ 16774803decSYouMin Chen tmp |= 3 << 24; 16874803decSYouMin Chen 16974803decSYouMin Chen tmp |= (2 - cap_info->bw) << 12; 17074803decSYouMin Chen 17174803decSYouMin Chen pctl_regs->pctl[tmp_adr][1] = tmp; 17274803decSYouMin Chen 17374803decSYouMin Chen return 0; 17474803decSYouMin Chen } 17574803decSYouMin Chen 17674803decSYouMin Chen int pctl_cfg(void __iomem *pctl_base, struct ddr_pctl_regs *pctl_regs, 17774803decSYouMin Chen u32 sr_idle, u32 pd_idle) 17874803decSYouMin Chen { 17974803decSYouMin Chen u32 i; 18074803decSYouMin Chen 18174803decSYouMin Chen for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) { 18274803decSYouMin Chen writel(pctl_regs->pctl[i][1], 18374803decSYouMin Chen pctl_base + pctl_regs->pctl[i][0]); 18474803decSYouMin Chen } 18574803decSYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG, 18674803decSYouMin Chen (0xff << 16) | 0x1f, 18774803decSYouMin Chen ((sr_idle & 0xff) << 16) | (pd_idle & 0x1f)); 18874803decSYouMin Chen 18974803decSYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL, 19074803decSYouMin Chen 0xfff << 16, 19174803decSYouMin Chen 5 << 16); 19274803decSYouMin Chen /* disable zqcs */ 19374803decSYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31); 19474803decSYouMin Chen 19574803decSYouMin Chen return 0; 19674803decSYouMin Chen } 19774803decSYouMin Chen 198