static int sun8i_a33_mbus_hw_init()

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;
}