| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * (C) Copyright 2022 - Analog Devices, Inc. |
| * |
| * Written and/or maintained by Timesys Corporation |
| * |
| * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com> |
| * Contact: Greg Malysa <greg.malysa@timesys.com> |
| */ |
| |
| #include <asm/io.h> |
| #include <asm/arch-adi/sc5xx/sc5xx.h> |
| #include <linux/types.h> |
| #include "clkinit.h" |
| #include "dmcinit.h" |
| |
| #define REG_DMC0_BASE 0x31070000 |
| #define REG_DMC1_BASE 0x31073000 |
| |
| #define REG_DMC_CTL 0x0004 // Control Register |
| #define REG_DMC_STAT 0x0008 // Status Register |
| #define REG_DMC_CFG 0x0040 // Configuration Register |
| #define REG_DMC_TR0 0x0044 // Timing 0 Register |
| #define REG_DMC_TR1 0x0048 // Timing 1 Register |
| #define REG_DMC_TR2 0x004C // Timing 2 Register |
| #define REG_DMC_MR 0x0060 // Shadow MR Register (DDR3) |
| #define REG_DMC_EMR1 0x0064 // Shadow EMR1 Register |
| #define REG_DMC_EMR2 0x0068 // Shadow EMR2 Register |
| #define REG_DMC_EMR3 0x006C |
| #define REG_DMC_DLLCTL 0x0080 // DLL Control Register |
| #define REG_DMC_DT_CALIB_ADDR 0x0090 // Data Calibration Address Register |
| #define REG_DMC_CPHY_CTL 0x01C0 // Controller to PHY Interface Register |
| |
| /* SC57x && SC58x DMC REGs */ |
| #define REG_DMC_PHY_CTL0 0x1000 // PHY Control 0 Register |
| #define REG_DMC_PHY_CTL1 0x1004 // PHY Control 1 Register |
| #define REG_DMC_PHY_CTL2 0x1008 // PHY Control 2 Register |
| #define REG_DMC_PHY_CTL3 0x100c // PHY Control 3 Register |
| #define REG_DMC_PHY_CTL4 0x1010 // PHY Control 4 Register |
| #define REG_DMC_CAL_PADCTL0 0x1034 // CALIBRATION PAD CTL 0 Register |
| #define REG_DMC_CAL_PADCTL2 0x103C // CALIBRATION PAD CTL2 Register |
| /* END */ |
| |
| /* SC59x DMC REGs */ |
| #define REG_DMC_DDR_LANE0_CTL0 0x1000 // Data Lane 0 Control Register 0 |
| #define REG_DMC_DDR_LANE0_CTL1 0x1004 // Data Lane 0 Control Register 1 |
| #define REG_DMC_DDR_LANE1_CTL0 0x100C // Data Lane 1 Control Register 0 |
| #define REG_DMC_DDR_LANE1_CTL1 0x1010 // Data Lane 1 Control Register 1 |
| #define REG_DMC_DDR_ROOT_CTL 0x1018 // DDR ROOT Module Control Register |
| #define REG_DMC_DDR_ZQ_CTL0 0x1034 // DDR Calibration Control Register 0 |
| #define REG_DMC_DDR_ZQ_CTL1 0x1038 // DDR Calibration Control Register 1 |
| #define REG_DMC_DDR_ZQ_CTL2 0x103C // DDR Calibration Control Register 2 |
| #define REG_DMC_DDR_CA_CTL 0x1068 // DDR CA Lane Control Register |
| /* END */ |
| |
| #define REG_DMC_DDR_SCRATCH_2 0x1074 |
| #define REG_DMC_DDR_SCRATCH_3 0x1078 |
| #define REG_DMC_DDR_SCRATCH_6 0x1084 |
| #define REG_DMC_DDR_SCRATCH_7 0x1088 |
| |
| #define REG_DMC_DDR_SCRATCH_STAT0 0x107C |
| #define REG_DMC_DDR_SCRATCH_STAT1 0x1080 |
| |
| #define DMC0_DATA_CALIB_ADD 0x80000000 |
| #define DMC1_DATA_CALIB_ADD 0xC0000000 |
| |
| #define BITM_DMC_CFG_EXTBANK 0x0000F000 /* External Banks */ |
| #define ENUM_DMC_CFG_EXTBANK1 0x00000000 /* EXTBANK: 1 External Bank */ |
| #define BITM_DMC_CFG_SDRSIZE 0x00000F00 /* SDRAM Size */ |
| #define ENUM_DMC_CFG_SDRSIZE64 0x00000000 /* SDRSIZE: 64M Bit SDRAM (LPDDR Only) */ |
| #define ENUM_DMC_CFG_SDRSIZE128 0x00000100 /* SDRSIZE: 128M Bit SDRAM (LPDDR Only) */ |
| #define ENUM_DMC_CFG_SDRSIZE256 0x00000200 /* SDRSIZE: 256M Bit SDRAM */ |
| #define ENUM_DMC_CFG_SDRSIZE512 0x00000300 /* SDRSIZE: 512M Bit SDRAM */ |
| #define ENUM_DMC_CFG_SDRSIZE1G 0x00000400 /* SDRSIZE: 1G Bit SDRAM */ |
| #define ENUM_DMC_CFG_SDRSIZE2G 0x00000500 /* SDRSIZE: 2G Bit SDRAM */ |
| #define ENUM_DMC_CFG_SDRSIZE4G 0x00000600 /* SDRSIZE: 4G Bit SDRAM */ |
| #define ENUM_DMC_CFG_SDRSIZE8G 0x00000700 /* SDRSIZE: 8G Bit SDRAM */ |
| #define BITM_DMC_CFG_SDRWID 0x000000F0 /* SDRAM Width */ |
| #define ENUM_DMC_CFG_SDRWID16 0x00000020 /* SDRWID: 16-Bit Wide SDRAM */ |
| #define BITM_DMC_CFG_IFWID 0x0000000F /* Interface Width */ |
| #define ENUM_DMC_CFG_IFWID16 0x00000002 /* IFWID: 16-Bit Wide Interface */ |
| |
| #define BITM_DMC_CTL_DDR3EN 0x00000001 |
| #define BITM_DMC_CTL_INIT 0x00000004 |
| #define BITP_DMC_STAT_INITDONE 2 /* Initialization Done */ |
| #define BITM_DMC_STAT_INITDONE 0x00000004 |
| |
| #define BITP_DMC_CTL_AL_EN 27 |
| #define BITP_DMC_CTL_ZQCL 25 /* ZQ Calibration Long */ |
| #define BITP_DMC_CTL_ZQCS 24 /* ZQ Calibration Short */ |
| #define BITP_DMC_CTL_DLLCAL 13 /* DLL Calibration Start */ |
| #define BITP_DMC_CTL_PPREF 12 /* Postpone Refresh */ |
| #define BITP_DMC_CTL_RDTOWR 9 /* Read-to-Write Cycle */ |
| #define BITP_DMC_CTL_ADDRMODE 8 /* Addressing (Page/Bank) Mode */ |
| #define BITP_DMC_CTL_RESET 7 /* Reset SDRAM */ |
| #define BITP_DMC_CTL_PREC 6 /* Precharge */ |
| #define BITP_DMC_CTL_DPDREQ 5 /* Deep Power Down Request */ |
| #define BITP_DMC_CTL_PDREQ 4 /* Power Down Request */ |
| #define BITP_DMC_CTL_SRREQ 3 /* Self Refresh Request */ |
| #define BITP_DMC_CTL_INIT 2 /* Initialize DRAM Start */ |
| #define BITP_DMC_CTL_LPDDR 1 /* Low Power DDR Mode */ |
| #define BITP_DMC_CTL_DDR3EN 0 /* DDR3 Mode */ |
| |
| #ifdef CONFIG_TARGET_SC584_EZKIT |
| #define DMC_PADCTL2_VALUE 0x0078283C |
| #elif CONFIG_TARGET_SC573_EZKIT |
| #define DMC_PADCTL2_VALUE 0x00782828 |
| #elif CONFIG_TARGET_SC589_MINI || CONFIG_TARGET_SC589_EZKIT |
| #define DMC_PADCTL2_VALUE 0x00783C3C |
| #elif defined(CONFIG_SC57X) || defined(CONFIG_SC58X) |
| #error "PADCTL2 not specified for custom board!" |
| #else |
| //Newer DMC. Legacy calibration obsolete |
| #define DMC_PADCTL2_VALUE 0x0 |
| #endif |
| |
| #define DMC_CPHYCTL_VALUE 0x0000001A |
| |
| #define BITP_DMC_MR1_QOFF 12 /* Output Buffer Enable */ |
| #define BITP_DMC_MR1_TDQS 11 /* Termination Data Strobe */ |
| #define BITP_DMC_MR1_RTT2 9 /* Rtt_nom */ |
| #define BITP_DMC_MR1_WL 7 /* Write Leveling Enable. */ |
| #define BITP_DMC_MR1_RTT1 6 /* Rtt_nom */ |
| #define BITP_DMC_MR1_DIC1 5 /* Output Driver Impedance Control */ |
| #define BITP_DMC_MR1_AL 3 /* Additive Latency */ |
| #define BITP_DMC_MR1_RTT0 2 /* Rtt_nom */ |
| #define BITP_DMC_MR1_DIC0 1 /* Output Driver Impedance control */ |
| #define BITP_DMC_MR1_DLLEN 0 /* DLL Enable */ |
| |
| #define BITP_DMC_MR2_CWL 3 /* CAS write Latency */ |
| |
| #define BITP_DMC_TR0_TMRD 28 /* Timing Mode Register Delay */ |
| #define BITP_DMC_TR0_TRC 20 /* Timing Row Cycle */ |
| #define BITP_DMC_TR0_TRAS 12 /* Timing Row Active Time */ |
| #define BITP_DMC_TR0_TRP 8 /* Timing RAS Precharge. */ |
| #define BITP_DMC_TR0_TWTR 4 /* Timing Write to Read */ |
| #define BITP_DMC_TR0_TRCD 0 /* Timing RAS to CAS Delay */ |
| |
| #define BITP_DMC_TR1_TRRD 28 /* Timing Read-Read Delay */ |
| #define BITP_DMC_TR1_TRFC 16 /* Timing Refresh-to-Command */ |
| #define BITP_DMC_TR1_TREF 0 /* Timing Refresh Interval */ |
| |
| #define BITP_DMC_TR2_TCKE 20 /* Timing Clock Enable */ |
| #define BITP_DMC_TR2_TXP 16 /* Timing Exit Powerdown */ |
| #define BITP_DMC_TR2_TWR 12 /* Timing Write Recovery */ |
| #define BITP_DMC_TR2_TRTP 8 /* Timing Read-to-Precharge */ |
| #define BITP_DMC_TR2_TFAW 0 /* Timing Four-Activated-Window */ |
| |
| #define BITP_DMC_MR_PD 12 /* Active Powerdown Mode */ |
| #define BITP_DMC_MR_WRRECOV 9 /* Write Recovery */ |
| #define BITP_DMC_MR_DLLRST 8 /* DLL Reset */ |
| #define BITP_DMC_MR_CL 4 /* CAS Latency */ |
| #define BITP_DMC_MR_CL0 2 /* CAS Latency */ |
| #define BITP_DMC_MR_BLEN 0 /* Burst Length */ |
| |
| #define BITP_DMC_DLLCTL_DATACYC 8 /* Data Cycles */ |
| #define BITP_DMC_DLLCTL_DLLCALRDCNT 0 /* DLL Calibration RD Count */ |
| |
| #define BITM_DMC_DLLCTL_DATACYC 0x00000F00 /* Data Cycles */ |
| #define BITM_DMC_DLLCTL_DLLCALRDCNT 0x000000FF /* DLL Calib RD Count */ |
| |
| #define BITP_DMC_STAT_PHYRDPHASE 20 /* PHY Read Phase */ |
| |
| #define BITM_DMC_DDR_LANE0_CTL0_CB_RSTDAT 0x08000000 /* Rst Data Pads */ |
| #define BITM_DMC_DDR_LANE1_CTL0_CB_RSTDAT 0x08000000 /* Rst Data Pads */ |
| #define BITM_DMC_DDR_LANE0_CTL1_COMP_DCYCLE 0x00000002 /* Compute Dcycle */ |
| #define BITM_DMC_DDR_LANE1_CTL1_COMP_DCYCLE 0x00000002 /* Compute Dcycle */ |
| #define BITM_DMC_DDR_LANE1_CTL0_CB_RSTDLL 0x00000100 /* Rst Lane DLL */ |
| #define BITM_DMC_DDR_LANE0_CTL0_CB_RSTDLL 0x00000100 /* Rst Lane DLL */ |
| #define BITP_DMC_DDR_ROOT_CTL_PIPE_OFSTDCYCLE 10 /* Pipeline offset for PHYC_DATACYCLE */ |
| #define BITM_DMC_DDR_ROOT_CTL_SW_REFRESH 0x00002000 /* Refresh Lane DLL Code */ |
| #define BITM_DMC_DDR_CA_CTL_SW_REFRESH 0x00004000 /* Refresh Lane DLL Code */ |
| |
| #define BITP_DMC_CTL_RL_DQS 26 /* RL_DQS */ |
| #define BITM_DMC_CTL_RL_DQS 0x04000000 /* RL_DQS */ |
| #define BITP_DMC_EMR3_MPR 2 /* Multi Purpose Read Enable (Read Leveling)*/ |
| #define BITM_DMC_EMR3_MPR 0x00000004 /* Multi Purpose Read Enable (Read Leveling)*/ |
| #define BITM_DMC_MR1_WL 0x00000080 /* Write Leveling Enable.*/ |
| #define BITM_DMC_STAT_PHYRDPHASE 0x00F00000 /* PHY Read Phase */ |
| |
| #define BITP_DMC_DDR_LANE0_CTL1_BYPCODE 10 |
| #define BITM_DMC_DDR_LANE0_CTL1_BYPCODE 0x00007C00 |
| #define BITP_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN 15 |
| #define BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN 0x00008000 |
| |
| #define DMC_ZQCTL0_VALUE 0x00785A64 |
| #define DMC_ZQCTL1_VALUE 0 |
| #define DMC_ZQCTL2_VALUE 0x70000000 |
| |
| #define DMC_TRIG_CALIB 0 |
| #define DMC_OFSTDCYCLE 2 |
| |
| #define BITP_DMC_CAL_PADCTL0_RTTCALEN 31 /* RTT Calibration Enable */ |
| #define BITP_DMC_CAL_PADCTL0_PDCALEN 30 /* PULLDOWN Calib Enable */ |
| #define BITP_DMC_CAL_PADCTL0_PUCALEN 29 /* PULLUP Calib Enable */ |
| #define BITP_DMC_CAL_PADCTL0_CALSTRT 28 /* Start New Calib ( Hardware Cleared) */ |
| #define BITM_DMC_CAL_PADCTL0_RTTCALEN 0x80000000 /* RTT Calibration Enable */ |
| #define BITM_DMC_CAL_PADCTL0_PDCALEN 0x40000000 /* PULLDOWN Calib Enable */ |
| #define BITM_DMC_CAL_PADCTL0_PUCALEN 0x20000000 /* PULLUP Calib Enable */ |
| #define BITM_DMC_CAL_PADCTL0_CALSTRT 0x10000000 /* Start New Calib ( Hardware Cleared) */ |
| #define ENUM_DMC_PHY_CTL4_DDR3 0x00000000 /* DDRMODE: DDR3 Mode */ |
| #define ENUM_DMC_PHY_CTL4_DDR2 0x00000001 /* DDRMODE: DDR2 Mode */ |
| #define ENUM_DMC_PHY_CTL4_LPDDR 0x00000003 /* DDRMODE: LPDDR Mode */ |
| |
| #define BITP_DMC_DDR_ZQ_CTL0_IMPRTT 16 /* Data/DQS ODT */ |
| #define BITP_DMC_DDR_ZQ_CTL0_IMPWRDQ 8 /* Data/DQS/DM/CLK Drive Strength */ |
| #define BITP_DMC_DDR_ZQ_CTL0_IMPWRADD 0 /* Address/Command Drive Strength */ |
| #define BITM_DMC_DDR_ZQ_CTL0_IMPRTT 0x00FF0000 /* Data/DQS ODT */ |
| #define BITM_DMC_DDR_ZQ_CTL0_IMPWRDQ 0x0000FF00 /* Data/DQS/DM/CLK Drive Strength */ |
| #define BITM_DMC_DDR_ZQ_CTL0_IMPWRADD 0x000000FF /* Address/Command Drive Strength */ |
| |
| #define BITM_DMC_DDR_ROOT_CTL_TRIG_RD_XFER_ALL 0x00200000 /* All Lane Read Status */ |
| |
| #if defined(CONFIG_ADI_USE_DDR2) |
| #define DMC_MR0_VALUE \ |
| ((DMC_BL / 4 + 1) << BITP_DMC_MR_BLEN) | \ |
| (DMC_CL << BITP_DMC_MR_CL) | \ |
| (DMC_WRRECOV << BITP_DMC_MR_WRRECOV) |
| |
| #define DMC_MR1_VALUE \ |
| (DMC_MR1_AL << BITP_DMC_MR1_AL | 0x04) \ |
| |
| #define DMC_MR2_VALUE 0 |
| #define DMC_MR3_VALUE 0 |
| |
| #define DMC_CTL_VALUE \ |
| (DMC_RDTOWR << BITP_DMC_CTL_RDTOWR) | \ |
| (1 << BITP_DMC_CTL_DLLCAL) | \ |
| (BITM_DMC_CTL_INIT) |
| #else |
| #define DMC_MR0_VALUE \ |
| (0 << BITP_DMC_MR_BLEN) | \ |
| (DMC_CL0 << BITP_DMC_MR_CL0) | \ |
| (DMC_CL123 << BITP_DMC_MR_CL) | \ |
| (DMC_WRRECOV << BITP_DMC_MR_WRRECOV) | \ |
| (1 << BITP_DMC_MR_DLLRST) |
| |
| #define DMC_MR1_VALUE \ |
| (DMC_MR1_DLLEN << BITP_DMC_MR1_DLLEN) | \ |
| (DMC_MR1_DIC0 << BITP_DMC_MR1_DIC0) | \ |
| (DMC_MR1_RTT0 << BITP_DMC_MR1_RTT0) | \ |
| (DMC_MR1_AL << BITP_DMC_MR1_AL) | \ |
| (DMC_MR1_DIC1 << BITP_DMC_MR1_DIC1) | \ |
| (DMC_MR1_RTT1 << BITP_DMC_MR1_RTT1) | \ |
| (DMC_MR1_RTT2 << BITP_DMC_MR1_RTT2) | \ |
| (DMC_MR1_WL << BITP_DMC_MR1_WL) | \ |
| (DMC_MR1_TDQS << BITP_DMC_MR1_TDQS) | \ |
| (DMC_MR1_QOFF << BITP_DMC_MR1_QOFF) |
| |
| #define DMC_MR2_VALUE \ |
| ((DMC_WL) << BITP_DMC_MR2_CWL) |
| |
| #define DMC_MR3_VALUE \ |
| ((DMC_WL) << BITP_DMC_MR2_CWL) |
| |
| #define DMC_CTL_VALUE \ |
| (DMC_RDTOWR << BITP_DMC_CTL_RDTOWR) | \ |
| (BITM_DMC_CTL_INIT) | \ |
| (BITM_DMC_CTL_DDR3EN) | \ |
| (DMC_CTL_AL_EN << BITP_DMC_CTL_AL_EN) |
| #endif |
| |
| #define DMC_DLLCTL_VALUE \ |
| (DMC_DATACYC << BITP_DMC_DLLCTL_DATACYC) | \ |
| (DMC_DLLCALRDCNT << BITP_DMC_DLLCTL_DLLCALRDCNT) |
| |
| #define DMC_CFG_VALUE \ |
| ENUM_DMC_CFG_IFWID16 | \ |
| ENUM_DMC_CFG_SDRWID16 | \ |
| SDR_CHIP_SIZE | \ |
| ENUM_DMC_CFG_EXTBANK1 |
| |
| #define DMC_TR0_VALUE \ |
| (DMC_TRCD << BITP_DMC_TR0_TRCD) | \ |
| (DMC_TWTR << BITP_DMC_TR0_TWTR) | \ |
| (DMC_TRP << BITP_DMC_TR0_TRP) | \ |
| (DMC_TRAS << BITP_DMC_TR0_TRAS) | \ |
| (DMC_TRC << BITP_DMC_TR0_TRC) | \ |
| (DMC_TMRD << BITP_DMC_TR0_TMRD) |
| |
| #define DMC_TR1_VALUE \ |
| (DMC_TREF << BITP_DMC_TR1_TREF) | \ |
| (DMC_TRFC << BITP_DMC_TR1_TRFC) | \ |
| (DMC_TRRD << BITP_DMC_TR1_TRRD) |
| |
| #define DMC_TR2_VALUE \ |
| (DMC_TFAW << BITP_DMC_TR2_TFAW) | \ |
| (DMC_TRTP << BITP_DMC_TR2_TRTP) | \ |
| (DMC_TWR << BITP_DMC_TR2_TWR) | \ |
| (DMC_TXP << BITP_DMC_TR2_TXP) | \ |
| (DMC_TCKE << BITP_DMC_TR2_TCKE) |
| |
| enum DDR_MODE { |
| DDR3_MODE, |
| DDR2_MODE, |
| LPDDR_MODE, |
| }; |
| |
| enum CALIBRATION_MODE { |
| CALIBRATION_LEGACY, |
| CALIBRATION_METHOD1, |
| CALIBRATION_METHOD2, |
| }; |
| |
| static struct dmc_param { |
| phys_addr_t reg; |
| u32 ddr_mode; |
| u32 padctl2_value; |
| u32 dmc_cphyctl_value; |
| u32 dmc_cfg_value; |
| u32 dmc_dllctl_value; |
| u32 dmc_ctl_value; |
| u32 dmc_tr0_value; |
| u32 dmc_tr1_value; |
| u32 dmc_tr2_value; |
| u32 dmc_mr0_value; |
| u32 dmc_mr1_value; |
| u32 dmc_mr2_value; |
| u32 dmc_mr3_value; |
| u32 dmc_zqctl0_value; |
| u32 dmc_zqctl1_value; |
| u32 dmc_zqctl2_value; |
| u32 dmc_data_calib_add_value; |
| bool phy_init_required; |
| bool anomaly_20000037_applicable; |
| enum CALIBRATION_MODE calib_mode; |
| } dmc; |
| |
| #ifdef CONFIG_SC59X_64 |
| #define DQS_DEFAULT_DELAY 3ul |
| |
| #define DELAYTRIM 1 |
| #define LANE0_DQS_DELAY 1 |
| #define LANE1_DQS_DELAY 1 |
| |
| #define CLKDIR 0ul |
| |
| #define DQSTRIM 0 |
| #define DQSCODE 0ul |
| |
| #define CLKTRIM 0 |
| #define CLKCODE 0ul |
| #endif |
| |
| static inline void calibration_legacy(void) |
| { |
| u32 temp; |
| |
| /* 1. Set DDR mode to DDR3/DDR2/LPDDR in DMCx_PHY_CTL4 register */ |
| if (dmc.ddr_mode == DDR3_MODE) |
| writel(ENUM_DMC_PHY_CTL4_DDR3, dmc.reg + REG_DMC_PHY_CTL4); |
| else if (dmc.ddr_mode == DDR2_MODE) |
| writel(ENUM_DMC_PHY_CTL4_DDR2, dmc.reg + REG_DMC_PHY_CTL4); |
| else if (dmc.ddr_mode == LPDDR_MODE) |
| writel(ENUM_DMC_PHY_CTL4_LPDDR, dmc.reg + REG_DMC_PHY_CTL4); |
| |
| /* |
| * 2. Make sure that the bits 6, 7, 25, and 27 of the DMC_PHY_ |
| * CTL3 register are set |
| */ |
| writel(0x0A0000C0, dmc.reg + REG_DMC_PHY_CTL3); |
| |
| /* |
| * 3. For DDR2/DDR3 mode, make sure that the bits 0, 1, 2, 3 of |
| * the DMC_PHY_CTL0 register and the bits 26, 27, 28, 29, 30, 31 |
| * of the DMC_PHY_CTL2 are set. |
| */ |
| if (dmc.ddr_mode == DDR3_MODE || |
| dmc.ddr_mode == DDR2_MODE) { |
| writel(0XFC000000, dmc.reg + REG_DMC_PHY_CTL2); |
| writel(0x0000000f, dmc.reg + REG_DMC_PHY_CTL0); |
| } |
| |
| writel(0x00000000, dmc.reg + REG_DMC_PHY_CTL1); |
| |
| /* 4. For DDR3 mode, set bit 1 and configure bits [5:2] of the |
| * DMC_CPHY_CTL register with WL=CWL+AL in DCLK cycles. |
| */ |
| if (dmc.ddr_mode == DDR3_MODE) |
| writel(dmc.dmc_cphyctl_value, dmc.reg + REG_DMC_CPHY_CTL); |
| /* 5. Perform On Die Termination(ODT) & Driver Impedance Calibration */ |
| if (dmc.ddr_mode == LPDDR_MODE) { |
| /* Bypass processor ODT */ |
| writel(0x80000, dmc.reg + REG_DMC_PHY_CTL1); |
| } else { |
| /* Set bits RTTCALEN, PDCALEN, PUCALEN of register */ |
| temp = BITM_DMC_CAL_PADCTL0_RTTCALEN | |
| BITM_DMC_CAL_PADCTL0_PDCALEN | |
| BITM_DMC_CAL_PADCTL0_PUCALEN; |
| writel(temp, dmc.reg + REG_DMC_CAL_PADCTL0); |
| /* Configure ODT and drive impedance values in the |
| * DMCx_CAL_PADCTL2 register |
| */ |
| writel(dmc.padctl2_value, dmc.reg + REG_DMC_CAL_PADCTL2); |
| /* start calibration */ |
| temp |= BITM_DMC_CAL_PADCTL0_CALSTRT; |
| writel(temp, dmc.reg + REG_DMC_CAL_PADCTL0); |
| /* Wait for PAD calibration to complete - 300 DCLK cycle. |
| * Worst case: CCLK=450 MHz, DCLK=125 MHz |
| */ |
| dmcdelay(300); |
| } |
| } |
| |
| static inline void calibration_method1(void) |
| { |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| writel(dmc.dmc_zqctl0_value, dmc.reg + REG_DMC_DDR_ZQ_CTL0); |
| writel(dmc.dmc_zqctl1_value, dmc.reg + REG_DMC_DDR_ZQ_CTL1); |
| writel(dmc.dmc_zqctl2_value, dmc.reg + REG_DMC_DDR_ZQ_CTL2); |
| |
| /* Generate the trigger */ |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| writel(0x00010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(8000u); |
| |
| /* The [31:26] bits may change if pad ring changes */ |
| writel(0x0C000001ul | DMC_TRIG_CALIB, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(8000u); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| #endif |
| } |
| |
| static inline void calibration_method2(void) |
| { |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| u32 stat_value = 0x0u; |
| u32 drv_pu, drv_pd, odt_pu, odt_pd; |
| u32 ro_dt, clk_dqs_drv_impedance; |
| u32 temp; |
| |
| /* Reset trigger */ |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| |
| /* Writing internal registers in calib pad to zero. Calib mode set |
| * to 1 [26], trig M1 S1 write [16], this enables usage of scratch |
| * registers instead of ZQCTL registers |
| */ |
| writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| |
| /* TRIGGER FOR M2-S2 WRITE -> slave id 31:26 trig m2,s2 write |
| * bit 1->1 slave1 address is 4 |
| */ |
| writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| |
| /* reset Trigger */ |
| writel(0x0u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0u, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| |
| /* write to slave 1, make the power down bit high */ |
| writel(0x1ul << 12, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| dmcdelay(2500u); |
| |
| /* Calib mode set to 1 [26], trig M1 S1 write [16] */ |
| writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| |
| writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| writel(0x0, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| |
| /* for slave 0 */ |
| writel(dmc.dmc_zqctl0_value, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| |
| /* Calib mode set to 1 [26], trig M1 S1 write [16] */ |
| writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| |
| writel(0x0C000002ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| |
| /* writing to slave 1 |
| * calstrt is 0, but other programming is done |
| * |
| * make power down LOW again, to kickstart BIAS circuit |
| */ |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| writel(0x30000000ul, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| |
| /* write to ca_ctl lane, calib mode set to 1 [26], |
| * trig M1 S1 write [16] |
| */ |
| writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| |
| /* copies data to lane controller slave |
| * TRIGGER FOR M2-S2 WRITE -> slave id 31:26 |
| * trig m2,s2 write bit 1->1 |
| * slave1 address is 4 |
| */ |
| writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| |
| /* reset Trigger */ |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3); |
| writel(0x50000000ul, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| writel(0x0C000004u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| writel(BITM_DMC_DDR_ROOT_CTL_TRIG_RD_XFER_ALL, |
| dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| // calculate ODT PU and PD values |
| stat_value = ((readl(dmc.reg + REG_DMC_DDR_SCRATCH_7) & 0x0000FFFFu) << |
| 16); |
| stat_value |= ((readl(dmc.reg + REG_DMC_DDR_SCRATCH_6) & 0xFFFF0000u) >> |
| 16); |
| clk_dqs_drv_impedance = ((dmc.dmc_zqctl0_value) & |
| BITM_DMC_DDR_ZQ_CTL0_IMPWRDQ) >> BITP_DMC_DDR_ZQ_CTL0_IMPWRDQ; |
| ro_dt = ((dmc.dmc_zqctl0_value) & BITM_DMC_DDR_ZQ_CTL0_IMPRTT) >> |
| BITP_DMC_DDR_ZQ_CTL0_IMPRTT; |
| drv_pu = stat_value & 0x0000003Fu; |
| drv_pd = (stat_value >> 12) & 0x0000003Fu; |
| odt_pu = (drv_pu * clk_dqs_drv_impedance) / ro_dt; |
| odt_pd = (drv_pd * clk_dqs_drv_impedance) / ro_dt; |
| temp = ((1uL << 24) | |
| ((drv_pd & 0x0000003Fu)) | |
| ((odt_pd & 0x0000003Fu) << 6) | |
| ((drv_pu & 0x0000003Fu) << 12) | |
| ((odt_pu & 0x0000003Fu) << 18)); |
| temp |= readl(dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| writel(temp, dmc.reg + REG_DMC_DDR_SCRATCH_2); |
| writel(0x0C010000u, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| writel(0x08000002u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| writel(0x04010000u, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| writel(0x80000002u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(2500u); |
| writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL); |
| writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| #endif |
| } |
| |
| static inline void adi_dmc_lane_reset(bool reset, uint32_t dmc_no) |
| { |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| u32 temp; |
| phys_addr_t base = (dmc_no == 0) ? REG_DMC0_BASE : REG_DMC1_BASE; |
| phys_addr_t ln0 = base + REG_DMC_DDR_LANE0_CTL0; |
| phys_addr_t ln1 = base + REG_DMC_DDR_LANE1_CTL0; |
| |
| if (reset) { |
| temp = readl(ln0); |
| temp |= BITM_DMC_DDR_LANE0_CTL0_CB_RSTDLL; |
| writel(temp, ln0); |
| |
| temp = readl(ln1); |
| temp |= BITM_DMC_DDR_LANE1_CTL0_CB_RSTDLL; |
| writel(temp, ln1); |
| } else { |
| temp = readl(ln0); |
| temp &= ~BITM_DMC_DDR_LANE0_CTL0_CB_RSTDLL; |
| writel(temp, ln0); |
| |
| temp = readl(ln1); |
| temp &= ~BITM_DMC_DDR_LANE1_CTL0_CB_RSTDLL; |
| writel(temp, ln1); |
| } |
| dmcdelay(9000u); |
| #endif |
| } |
| |
| void adi_dmc_reset_lanes(bool reset) |
| { |
| if (!IS_ENABLED(CONFIG_ADI_USE_DDR2)) { |
| if (IS_ENABLED(CONFIG_SC59X) || IS_ENABLED(CONFIG_SC59X_64)) { |
| if (IS_ENABLED(CONFIG_ADI_USE_DMC0)) |
| adi_dmc_lane_reset(reset, 0); |
| if (IS_ENABLED(CONFIG_ADI_USE_DMC1)) |
| adi_dmc_lane_reset(reset, 1); |
| } |
| else { |
| u32 temp = reset ? 0x800 : 0x0; |
| |
| if (IS_ENABLED(CONFIG_ADI_USE_DMC0)) |
| writel(temp, REG_DMC0_BASE + REG_DMC_PHY_CTL0); |
| if (IS_ENABLED(CONFIG_ADI_USE_DMC1)) |
| writel(temp, REG_DMC1_BASE + REG_DMC_PHY_CTL0); |
| } |
| } |
| } |
| |
| static inline void dmc_controller_init(void) |
| { |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| u32 phyphase, rd_cnt, t_EMR1, t_EMR3, t_CTL, data_cyc, temp; |
| #endif |
| |
| /* 1. Program the DMC controller registers: DMCx_CFG, DMCx_TR0, |
| * DMCx_TR1, DMCx_TR2, DMCx_MR(DDR2/LPDDR)/DMCx_MR0(DDR3), |
| * DMCx_EMR1(DDR2)/DMCx_MR1(DDR3), |
| * DMCx_EMR2(DDR2)/DMCx_EMR(LPDDR)/DMCx_MR2(DDR3) |
| */ |
| writel(dmc.dmc_cfg_value, dmc.reg + REG_DMC_CFG); |
| writel(dmc.dmc_tr0_value, dmc.reg + REG_DMC_TR0); |
| writel(dmc.dmc_tr1_value, dmc.reg + REG_DMC_TR1); |
| writel(dmc.dmc_tr2_value, dmc.reg + REG_DMC_TR2); |
| writel(dmc.dmc_mr0_value, dmc.reg + REG_DMC_MR); |
| writel(dmc.dmc_mr1_value, dmc.reg + REG_DMC_EMR1); |
| writel(dmc.dmc_mr2_value, dmc.reg + REG_DMC_EMR2); |
| |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| writel(dmc.dmc_mr3_value, dmc.reg + REG_DMC_EMR3); |
| writel(dmc.dmc_dllctl_value, dmc.reg + REG_DMC_DLLCTL); |
| dmcdelay(2000u); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_CA_CTL); |
| temp |= BITM_DMC_DDR_CA_CTL_SW_REFRESH; |
| writel(temp, dmc.reg + REG_DMC_DDR_CA_CTL); |
| dmcdelay(5u); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| temp |= BITM_DMC_DDR_ROOT_CTL_SW_REFRESH | |
| (DMC_OFSTDCYCLE << BITP_DMC_DDR_ROOT_CTL_PIPE_OFSTDCYCLE); |
| writel(temp, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| #endif |
| |
| /* 2. Make sure that the REG_DMC_DT_CALIB_ADDR register is programmed |
| * to an unused DMC location corresponding to a burst of 16 bytes |
| * (by default it is the starting address of the DMC address range). |
| */ |
| #ifndef CONFIG_SC59X |
| writel(dmc.dmc_data_calib_add_value, dmc.reg + REG_DMC_DT_CALIB_ADDR); |
| #endif |
| /* 3. Program the DMCx_CTL register with INIT bit set to start |
| * the DMC initialization sequence |
| */ |
| writel(dmc.dmc_ctl_value, dmc.reg + REG_DMC_CTL); |
| /* 4. Wait for the DMC initialization to complete by polling |
| * DMCx_STAT.INITDONE bit. |
| */ |
| |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| dmcdelay(722000u); |
| |
| /* Add necessary delay depending on the configuration */ |
| t_EMR1 = (dmc.dmc_mr1_value & BITM_DMC_MR1_WL) >> BITP_DMC_MR1_WL; |
| |
| dmcdelay(600u); |
| if (t_EMR1 != 0u) |
| while ((readl(dmc.reg + REG_DMC_EMR1) & BITM_DMC_MR1_WL) != 0) |
| ; |
| |
| t_EMR3 = (dmc.dmc_mr3_value & BITM_DMC_EMR3_MPR) >> |
| BITP_DMC_EMR3_MPR; |
| dmcdelay(2000u); |
| if (t_EMR3 != 0u) |
| while ((readl(dmc.reg + REG_DMC_EMR3) & BITM_DMC_EMR3_MPR) != 0) |
| ; |
| |
| t_CTL = (dmc.dmc_ctl_value & BITM_DMC_CTL_RL_DQS) >> BITP_DMC_CTL_RL_DQS; |
| dmcdelay(600u); |
| if (t_CTL != 0u) |
| while ((readl(dmc.reg + REG_DMC_CTL) & BITM_DMC_CTL_RL_DQS) != 0) |
| ; |
| #endif |
| |
| /* check if DMC initialization finished*/ |
| while ((readl(dmc.reg + REG_DMC_STAT) & BITM_DMC_STAT_INITDONE) == 0) |
| ; |
| |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| /* toggle DCYCLE */ |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| temp |= BITM_DMC_DDR_LANE0_CTL1_COMP_DCYCLE; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| temp |= BITM_DMC_DDR_LANE1_CTL1_COMP_DCYCLE; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| |
| dmcdelay(10u); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| temp &= (~BITM_DMC_DDR_LANE0_CTL1_COMP_DCYCLE); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| temp &= (~BITM_DMC_DDR_LANE1_CTL1_COMP_DCYCLE); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| |
| /* toggle RSTDAT */ |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL0); |
| temp |= BITM_DMC_DDR_LANE0_CTL0_CB_RSTDAT; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL0); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL0); |
| temp &= (~BITM_DMC_DDR_LANE0_CTL0_CB_RSTDAT); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL0); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL0); |
| temp |= BITM_DMC_DDR_LANE1_CTL0_CB_RSTDAT; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL0); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL0); |
| temp &= (~BITM_DMC_DDR_LANE1_CTL0_CB_RSTDAT); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL0); |
| |
| dmcdelay(2500u); |
| |
| /* Program phyphase*/ |
| phyphase = (readl(dmc.reg + REG_DMC_STAT) & |
| BITM_DMC_STAT_PHYRDPHASE) >> BITP_DMC_STAT_PHYRDPHASE; |
| data_cyc = (phyphase << BITP_DMC_DLLCTL_DATACYC) & |
| BITM_DMC_DLLCTL_DATACYC; |
| rd_cnt = dmc.dmc_dllctl_value; |
| rd_cnt <<= BITP_DMC_DLLCTL_DLLCALRDCNT; |
| rd_cnt &= BITM_DMC_DLLCTL_DLLCALRDCNT; |
| writel(rd_cnt | data_cyc, dmc.reg + REG_DMC_DLLCTL); |
| writel((dmc.dmc_ctl_value & (~BITM_DMC_CTL_INIT) & |
| (~BITM_DMC_CTL_RL_DQS)), dmc.reg + REG_DMC_CTL); |
| |
| #if DELAYTRIM |
| /* DQS delay trim*/ |
| u32 stat_value, WL_code_LDQS, WL_code_UDQS; |
| |
| /* For LDQS */ |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1) | (0x000000D0); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| dmcdelay(2500u); |
| writel(0x00400000, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| writel(0x0, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| stat_value = (readl(dmc.reg + REG_DMC_DDR_SCRATCH_STAT0) & |
| (0xFFFF0000)) >> 16; |
| WL_code_LDQS = (stat_value) & (0x0000001F); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| temp &= ~(BITM_DMC_DDR_LANE0_CTL1_BYPCODE | |
| BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| |
| /* If write leveling is enabled */ |
| if ((dmc.dmc_mr1_value & BITM_DMC_MR1_WL) >> BITP_DMC_MR1_WL) { |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| temp |= (((WL_code_LDQS + LANE0_DQS_DELAY) << |
| BITP_DMC_DDR_LANE0_CTL1_BYPCODE) & |
| BITM_DMC_DDR_LANE0_CTL1_BYPCODE) | |
| BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| } else { |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| temp |= (((DQS_DEFAULT_DELAY + LANE0_DQS_DELAY) << |
| BITP_DMC_DDR_LANE0_CTL1_BYPCODE) & |
| BITM_DMC_DDR_LANE0_CTL1_BYPCODE) | |
| BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1); |
| } |
| dmcdelay(2500u); |
| |
| /* For UDQS */ |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1) | (0x000000D0); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| dmcdelay(2500u); |
| writel(0x00800000, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| dmcdelay(2500u); |
| writel(0x0, dmc.reg + REG_DMC_DDR_ROOT_CTL); |
| stat_value = (readl(dmc.reg + REG_DMC_DDR_SCRATCH_STAT1) & |
| (0xFFFF0000)) >> 16; |
| WL_code_UDQS = (stat_value) & (0x0000001F); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| temp &= ~(BITM_DMC_DDR_LANE0_CTL1_BYPCODE | |
| BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| |
| /* If write leveling is enabled */ |
| if ((dmc.dmc_mr1_value & BITM_DMC_MR1_WL) >> BITP_DMC_MR1_WL) { |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| temp |= (((WL_code_UDQS + LANE1_DQS_DELAY) << |
| BITP_DMC_DDR_LANE0_CTL1_BYPCODE) & |
| BITM_DMC_DDR_LANE0_CTL1_BYPCODE) | |
| BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| } else { |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| temp |= (((DQS_DEFAULT_DELAY + LANE1_DQS_DELAY) << |
| BITP_DMC_DDR_LANE0_CTL1_BYPCODE) & |
| BITM_DMC_DDR_LANE0_CTL1_BYPCODE) | |
| BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN; |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1); |
| } |
| dmcdelay(2500u); |
| #endif |
| |
| #else |
| /* 5. Program the DMCx_CTL.DLLCTL register with 0x948 value |
| * (DATACYC=9, DLLCALRDCNT=72). |
| */ |
| writel(0x00000948, dmc.reg + REG_DMC_DLLCTL); |
| #endif |
| |
| /* 6. Workaround for anomaly#20000037 */ |
| if (dmc.anomaly_20000037_applicable) { |
| /* Perform dummy read to any DMC location */ |
| readl(0x80000000); |
| |
| writel(readl(dmc.reg + REG_DMC_PHY_CTL0) | 0x1000, |
| dmc.reg + REG_DMC_PHY_CTL0); |
| /* Clear DMCx_PHY_CTL0.RESETDAT bit */ |
| writel(readl(dmc.reg + REG_DMC_PHY_CTL0) & (~0x1000), |
| dmc.reg + REG_DMC_PHY_CTL0); |
| } |
| } |
| |
| static inline void dmc_init(void) |
| { |
| /* PHY Calibration+Initialization */ |
| if (!dmc.phy_init_required) |
| goto out; |
| |
| switch (dmc.calib_mode) { |
| case CALIBRATION_LEGACY: |
| calibration_legacy(); |
| break; |
| case CALIBRATION_METHOD1: |
| calibration_method1(); |
| break; |
| case CALIBRATION_METHOD2: |
| calibration_method2(); |
| break; |
| } |
| |
| #if DQSTRIM |
| /* DQS duty trim */ |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL0); |
| temp |= ((DQSCODE) << BITP_DMC_DDR_LANE0_CTL0_BYPENB) & |
| (BITM_DMC_DDR_LANE1_CTL0_BYPENB | |
| BITM_DMC_DDR_LANE0_CTL0_BYPSELP | |
| BITM_DMC_DDR_LANE0_CTL0_BYPCODE); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL0); |
| |
| temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL0); |
| temp |= ((DQSCODE) << BITP_DMC_DDR_LANE1_CTL0_BYPENB) & |
| (BITM_DMC_DDR_LANE1_CTL1_BYPCODE | |
| BITM_DMC_DDR_LANE1_CTL0_BYPSELP | |
| BITM_DMC_DDR_LANE1_CTL0_BYPCODE); |
| writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL0); |
| #endif |
| |
| #if CLKTRIM |
| /* Clock duty trim */ |
| temp = readl(dmc.reg + REG_DMC_DDR_CA_CTL); |
| temp |= (((CLKCODE << BITP_DMC_DDR_CA_CTL_BYPCODE1) & |
| BITM_DMC_DDR_CA_CTL_BYPCODE1) | |
| BITM_DMC_DDR_CA_CTL_BYPENB | |
| ((CLKDIR << BITP_DMC_DDR_CA_CTL_BYPSELP) & |
| BITM_DMC_DDR_CA_CTL_BYPSELP)); |
| writel(temp, dmc.reg + REG_DMC_DDR_CA_CTL); |
| #endif |
| |
| out: |
| /* Controller Initialization */ |
| dmc_controller_init(); |
| } |
| |
| static inline void __dmc_config(uint32_t dmc_no) |
| { |
| if (dmc_no == 0) { |
| dmc.reg = REG_DMC0_BASE; |
| dmc.dmc_data_calib_add_value = DMC0_DATA_CALIB_ADD; |
| } else if (dmc_no == 1) { |
| dmc.reg = REG_DMC1_BASE; |
| dmc.dmc_data_calib_add_value = DMC1_DATA_CALIB_ADD; |
| } else { |
| return; |
| } |
| |
| if (IS_ENABLED(CONFIG_ADI_USE_DDR2)) |
| dmc.ddr_mode = DDR2_MODE; |
| else |
| dmc.ddr_mode = DDR3_MODE; |
| |
| dmc.phy_init_required = true; |
| |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| dmc.anomaly_20000037_applicable = false; |
| dmc.dmc_dllctl_value = DMC_DLLCTL_VALUE; |
| dmc.calib_mode = CALIBRATION_METHOD2; |
| #else |
| dmc.anomaly_20000037_applicable = true; |
| dmc.calib_mode = CALIBRATION_LEGACY; |
| #endif |
| |
| dmc.dmc_ctl_value = DMC_CTL_VALUE; |
| dmc.dmc_cfg_value = DMC_CFG_VALUE; |
| dmc.dmc_tr0_value = DMC_TR0_VALUE; |
| dmc.dmc_tr1_value = DMC_TR1_VALUE; |
| dmc.dmc_tr2_value = DMC_TR2_VALUE; |
| dmc.dmc_mr0_value = DMC_MR0_VALUE; |
| dmc.dmc_mr1_value = DMC_MR1_VALUE; |
| dmc.dmc_mr2_value = DMC_MR2_VALUE; |
| |
| #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| dmc.dmc_mr3_value = DMC_MR3_VALUE; |
| dmc.dmc_zqctl0_value = DMC_ZQCTL0_VALUE; |
| dmc.dmc_zqctl1_value = DMC_ZQCTL1_VALUE; |
| dmc.dmc_zqctl2_value = DMC_ZQCTL2_VALUE; |
| #endif |
| |
| dmc.padctl2_value = DMC_PADCTL2_VALUE; |
| dmc.dmc_cphyctl_value = DMC_CPHYCTL_VALUE; |
| |
| /* Initialize DMC now */ |
| dmc_init(); |
| } |
| |
| void DMC_Config(void) |
| { |
| if (IS_ENABLED(CONFIG_ADI_USE_DMC0)) |
| __dmc_config(0); |
| |
| if (IS_ENABLED(CONFIG_ADI_USE_DMC1)) |
| __dmc_config(1); |
| } |