in sun8i-a33-mbus.c [260:313]
static int sun8i_a33_mbus_hw_init(struct device *dev,
struct sun8i_a33_mbus *priv,
unsigned long ddr_freq)
{
u32 i, mbus_cr, mbus_freq_mhz;
/* Choose tREFI and tRFC to match the configured DRAM type. */
mbus_cr = readl_relaxed(priv->reg_mbus + MBUS_CR);
switch (MBUS_CR_GET_DRAM_TYPE(mbus_cr)) {
case MBUS_CR_DRAM_TYPE_DDR2:
case MBUS_CR_DRAM_TYPE_DDR3:
case MBUS_CR_DRAM_TYPE_DDR4:
priv->tREFI_ns = 7800;
priv->tRFC_ns = 350;
break;
case MBUS_CR_DRAM_TYPE_LPDDR2:
case MBUS_CR_DRAM_TYPE_LPDDR3:
priv->tREFI_ns = 3900;
priv->tRFC_ns = 210;
break;
default:
return -EINVAL;
}
/* Save ODTMAP so it can be restored when raising the frequency. */
priv->odtmap = readl_relaxed(priv->reg_dram + DRAM_ODTMAP);
/* Compute the DRAM data bus width by counting enabled DATx8 blocks. */
for (i = 0; i < DRAM_DX_MAX; ++i) {
void __iomem *reg = priv->reg_dram + DRAM_DXnGCR0(i);
if (!(readl_relaxed(reg) & DRAM_DXnGCR0_DXEN))
break;
}
priv->data_width = i;
dev_dbg(dev, "Detected %u-bit %sDDRx with%s ODT\n",
priv->data_width * 8,
MBUS_CR_GET_DRAM_TYPE(mbus_cr) > 4 ? "LP" : "",
priv->odtmap ? "" : "out");
/* Program MBUS_TMR such that the PMU period unit is microseconds. */
mbus_freq_mhz = clk_get_rate(priv->clk_mbus) / USEC_PER_SEC;
writel_relaxed(MBUS_TMR_PERIOD(mbus_freq_mhz),
priv->reg_mbus + MBUS_TMR);
/* "Master Ready Mask Register" bits must be set or MDFS will block. */
writel_relaxed(0xffffffff, priv->reg_mbus + MBUS_MDFSMRMR);
sun8i_a33_mbus_restart_pmu_counters(priv);
sun8i_a33_mbus_update_nominal_bw(priv, ddr_freq / USEC_PER_SEC);
return 0;
}