I've got an issue where I'm trying to implement write levelling for DDR3 on an RK3288. From what I can tell by reading the TRM, DDR3 write leveling is supported. For some reason I can’t seem to get the write leveling routine to run and compensate for the individual byte lane skews. According to the DDR_PCTL_DFITRSTAT0 register, the PHY is configured for PHY Independent mode (reading 0x30303). According to the DFI 2.1 spec: "In PHY Independent mode, the PHY is responsible for executing data eye training, gate training or write leveling independent of the Memory Controller. In this mode, the associated training interface is not used other than the mode signal to the MC. The Memory Controller should be capable of generating the required MRS commands to enter or exit the test modes of the memory devices. These operations are not automatically generated. All training sequences, regardless of mode, are expected to be executed after memory initialization. For PHY Independent mode, the update interface may be used to suspend memory commands while the training sequences are executed." The current driver (sdram_rk3288.c) makes no reference to DDR3 write leveling. Here is what I’ve tried without luck: 1. Configure the DRAMs for write leveling using the appropriate MRS commands. // Issue a mode register set (MRS) command to MR1 to enable write leveling (MR1[7] = '1') and disable the output of the SDRAM (MR1[12] = '1'). This command is issued simultaneously to all ranks. send_command_op_corrected(pctl, 3, MRS_CMD, 1, (sdram_params->phy_timing.mr[1] | (1 << 7) | (1 << 12))); // Enable the output of the rank being write-leveled. This is done by issuing a MRS command to the selected rank with bit MR1[12] set to '0'. MR1[7] is kept set when issuing this command to make sure write leveling remains enabled for the rank. Wait tMOD to satisfy SDRAM MRS to other commands timing. send_command_op_corrected(pctl, 1, MRS_CMD, 1, ((sdram_params->phy_timing.mr[1] | (1 << 7)) & 0x0fff)); 2. Configure the DRAMs for write leveling using the appropriate MRS commands and set the dfi_wrlvl_en bit in register DDR_PCTL_DFITRWRLVLEN: // Issue a mode register set (MRS) command to MR1 to enable write leveling (MR1[7] = '1') and disable the output of the SDRAM (MR1[12] = '1'). This command is issued simultaneously to all ranks. send_command_op_corrected(pctl, 3, MRS_CMD, 1, (sdram_params->phy_timing.mr[1] | (1 << 7) | (1 << 12))); // Enable the output of the rank being write-leveled. This is done by issuing a MRS command to the selected rank with bit MR1[12] set to '0'. MR1[7] is kept set when issuing this command to make sure write leveling remains enabled for the rank. Wait tMOD to satisfy SDRAM MRS to other commands timing. send_command_op_corrected(pctl, 1, MRS_CMD, 1, ((sdram_params->phy_timing.mr[1] | (1 << 7)) & 0x0fff)); // Set dfitrwrlvlen high writel(0x1ff, &pctl->dfitrwrlvlen); 3. Configure the DRAMs for write leveling using the appropriate MRS commands, set the dfi_wrlvl_en bit in register DDR_PCTL_DFITRWRLVLEN, and rerun memory_init(). // Issue a mode register set (MRS) command to MR1 to enable write leveling (MR1[7] = '1') and disable the output of the SDRAM (MR1[12] = '1'). This command is issued simultaneously to all ranks. send_command_op_corrected(pctl, 3, MRS_CMD, 1, (sdram_params->phy_timing.mr[1] | (1 << 7) | (1 << 12))); // Enable the output of the rank being write-leveled. This is done by issuing a MRS command to the selected rank with bit MR1[12] set to '0'. MR1[7] is kept set when issuing this command to make sure write leveling remains enabled for the rank. Wait tMOD to satisfy SDRAM MRS to other commands timing. send_command_op_corrected(pctl, 1, MRS_CMD, 1, ((sdram_params->phy_timing.mr[1] | (1 << 7)) & 0x0fff)); // Set dfitrwrlvlen high writel(0x1ff, &pctl->dfitrwrlvlen); memory_init(publ, sdram_params->base.dramtype); 4. Manually control the dfi_wrlvl_en, dfi_wrlvl_strobe, dfi_wrlvl_load, and dfi_wrlvl_delay bits while monitoring the dfi_wrlvl_resp bits as described in Figure 50 of version 2.1 of the DDR PHY Interface (DFI) Specification: // Issue a mode register set (MRS) command to MR1 to enable write leveling (MR1[7] = '1') and disable the output of the SDRAM (MR1[12] = '1'). This command is issued simultaneously to all ranks. send_command_op_corrected(pctl, 3, MRS_CMD, 1, (sdram_params->phy_timing.mr[1] | (1 << 7) | (1 << 12))); // Enable the output of the rank being write-leveled. This is done by issuing a MRS command to the selected rank with bit MR1[12] set to '0'. MR1[7] is kept set when issuing this command to make sure write leveling remains enabled for the rank. Wait tMOD to satisfy SDRAM MRS to other commands timing. send_command_op_corrected(pctl, 1, MRS_CMD, 1, ((sdram_params->phy_timing.mr[1] | (1 << 7)) & 0x0fff)); // Set dfitrwrlvlen high writel(0x1ff, &pctl->dfitrwrlvlen); int index0; for (index0 = 0; index0 < 10000; index0++) { // Set the delay writel(index0, &pctl->dfitrwrlvldelay0); udelay(1); // Set dfi_wrlvl_load writel(0x80001ff0, &pctl->dfitrcmd); udelay(1); // Set dfi_wrlvl_strobe writel(0x80001ff1, &pctl->dfitrcmd); udelay(1); // Read dfi_wrlvl_resp0 if (readl(&pctl->dfitrwrlvlresp0) & 0x1) { break; } } Here is the send_command_op_corrected function definition. static inline void send_command_op_corrected(struct rk3288_ddr_pctl *pctl, u32 rank, u32 cmd, u32 ma, u32 op) { send_command(pctl, rank, cmd, (ma & 0x3) << 17 | (op & 0x1fff) << 4); } None of these generate any activity on the DDR bus, besides the MRS commands. Does anyone know what I need to do to trigger a write leveling routine? It seems like after the DRAMs are configured, I would need to set something on the RK3288 to trigger it. The TRM is pretty sparse when it comes to discussing write leveling, does anyone know if the PHY actually supports this? Thanks! _______________________________________________ Linux-rockchip mailing list Linux-rockchip@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/linux-rockchip