static unsigned int pdc20621_dimm_init()

in sata_sx4.c [1212:1354]


static unsigned int pdc20621_dimm_init(struct ata_host *host)
{
	int speed, size, length;
	u32 addr, spd0, pci_status;
	u32 time_period = 0;
	u32 tcount = 0;
	u32 ticks = 0;
	u32 clock = 0;
	u32 fparam = 0;
	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];

	/* hard-code chip #0 */
	mmio += PDC_CHIP0_OFS;

	/* Initialize PLL based upon PCI Bus Frequency */

	/* Initialize Time Period Register */
	writel(0xffffffff, mmio + PDC_TIME_PERIOD);
	time_period = readl(mmio + PDC_TIME_PERIOD);
	dev_dbg(host->dev, "Time Period Register (0x40): 0x%x\n", time_period);

	/* Enable timer */
	writel(PDC_TIMER_DEFAULT, mmio + PDC_TIME_CONTROL);
	readl(mmio + PDC_TIME_CONTROL);

	/* Wait 3 seconds */
	msleep(3000);

	/*
	   When timer is enabled, counter is decreased every internal
	   clock cycle.
	*/

	tcount = readl(mmio + PDC_TIME_COUNTER);
	dev_dbg(host->dev, "Time Counter Register (0x44): 0x%x\n", tcount);

	/*
	   If SX4 is on PCI-X bus, after 3 seconds, the timer counter
	   register should be >= (0xffffffff - 3x10^8).
	*/
	if (tcount >= PCI_X_TCOUNT) {
		ticks = (time_period - tcount);
		dev_dbg(host->dev, "Num counters 0x%x (%d)\n", ticks, ticks);

		clock = (ticks / 300000);
		dev_dbg(host->dev, "10 * Internal clk = 0x%x (%d)\n",
			clock, clock);

		clock = (clock * 33);
		dev_dbg(host->dev, "10 * Internal clk * 33 = 0x%x (%d)\n",
			clock, clock);

		/* PLL F Param (bit 22:16) */
		fparam = (1400000 / clock) - 2;
		dev_dbg(host->dev, "PLL F Param: 0x%x (%d)\n", fparam, fparam);

		/* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
		pci_status = (0x8a001824 | (fparam << 16));
	} else
		pci_status = PCI_PLL_INIT;

	/* Initialize PLL. */
	dev_dbg(host->dev, "pci_status: 0x%x\n", pci_status);
	writel(pci_status, mmio + PDC_CTL_STATUS);
	readl(mmio + PDC_CTL_STATUS);

	/*
	   Read SPD of DIMM by I2C interface,
	   and program the DIMM Module Controller.
	*/
	if (!(speed = pdc20621_detect_dimm(host))) {
		dev_err(host->dev, "Detect Local DIMM Fail\n");
		return 1;	/* DIMM error */
	}
	dev_dbg(host->dev, "Local DIMM Speed = %d\n", speed);

	/* Programming DIMM0 Module Control Register (index_CID0:80h) */
	size = pdc20621_prog_dimm0(host);
	dev_dbg(host->dev, "Local DIMM Size = %dMB\n", size);

	/* Programming DIMM Module Global Control Register (index_CID0:88h) */
	if (pdc20621_prog_dimm_global(host)) {
		dev_err(host->dev,
			"Programming DIMM Module Global Control Register Fail\n");
		return 1;
	}

	if (dimm_test) {
		u8 test_parttern1[40] =
			{0x55,0xAA,'P','r','o','m','i','s','e',' ',
			'N','o','t',' ','Y','e','t',' ',
			'D','e','f','i','n','e','d',' ',
			'1','.','1','0',
			'9','8','0','3','1','6','1','2',0,0};
		u8 test_parttern2[40] = {0};

		pdc20621_put_to_dimm(host, test_parttern2, 0x10040, 40);
		pdc20621_put_to_dimm(host, test_parttern2, 0x40, 40);

		pdc20621_put_to_dimm(host, test_parttern1, 0x10040, 40);
		pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
		dev_info(host->dev, "DIMM test pattern 1: %x, %x, %s\n", test_parttern2[0],
		       test_parttern2[1], &(test_parttern2[2]));
		pdc20621_get_from_dimm(host, test_parttern2, 0x10040,
				       40);
		dev_info(host->dev, "DIMM test pattern 2: %x, %x, %s\n",
			 test_parttern2[0],
			 test_parttern2[1], &(test_parttern2[2]));

		pdc20621_put_to_dimm(host, test_parttern1, 0x40, 40);
		pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
		dev_info(host->dev, "DIMM test pattern 3: %x, %x, %s\n",
			 test_parttern2[0],
			 test_parttern2[1], &(test_parttern2[2]));
	}

	/* ECC initiliazation. */

	if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
			       PDC_DIMM_SPD_TYPE, &spd0)) {
		dev_err(host->dev,
			"Failed in i2c read: device=%#x, subaddr=%#x\n",
		       PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE);
		return 1;
	}
	if (spd0 == 0x02) {
		void *buf;
		dev_dbg(host->dev, "Start ECC initialization\n");
		addr = 0;
		length = size * 1024 * 1024;
		buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
		if (!buf)
			return 1;
		while (addr < length) {
			pdc20621_put_to_dimm(host, buf, addr,
					     ECC_ERASE_BUF_SZ);
			addr += ECC_ERASE_BUF_SZ;
		}
		kfree(buf);
		dev_dbg(host->dev, "Finish ECC initialization\n");
	}
	return 0;
}