Newer
Older
barebox / arch / arm / mach-mxs / imx.c
@Juergen Beisert Juergen Beisert on 23 May 2013 4 KB MXS: fix SoC detecting
/*
 * (C) Copyright 2010 Juergen Beisert - Pengutronix
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <common.h>
#include <bootsource.h>
#include <command.h>
#include <complete.h>
#include <init.h>
#include <io.h>

#include <mach/generic.h>
#include <mach/imx-regs.h>
#include <mach/revision.h>

#define HW_RTC_PERSISTENT1     0x070

static int imx_reset_usb_bootstrap(void)
{
	/*
	 * Clear USB boot mode.
	 *
	 * When the i.MX28 boots from USB, the ROM code sets this bit. When
	 * after a reset the ROM code detects that this bit is set it will
	 * boot from USB again. This means that if we boot once from USB the
	 * chip will continue to boot from USB until the next power cycle.
	 *
	 * To prevent this (and boot from the configured bootsource instead)
	 * clear this bit here.
	 */
	writel(0x2, IMX_WDT_BASE + HW_RTC_PERSISTENT1 + BIT_CLR);

	return 0;
}
device_initcall(imx_reset_usb_bootstrap);

extern void imx_dump_clocks(void);

static int do_clocks(int argc, char *argv[])
{
	imx_dump_clocks();

	return 0;
}

BAREBOX_CMD_START(dump_clocks)
	.cmd		= do_clocks,
	.usage		= "show clock frequencies",
	BAREBOX_CMD_COMPLETE(empty_complete)
BAREBOX_CMD_END


static int __silicon_revision = SILICON_REVISION_UNKNOWN;

int silicon_revision_get(void)
{
	return __silicon_revision;
}

void silicon_revision_set(const char *soc, int revision)
{
	__silicon_revision = revision;

	printf("detected %s revision %d.%d\n", soc,
	       (revision >> 4) & 0xf, revision & 0xf);
}

#define HW_DIGCTL_CHIPID	(0x8001c310)
#define HW_DIGCTL_CHIPID_MASK	(0xffff << 16)
#define HW_DIGCTL_CHIPID_MX23	(0x3780 << 16)
#define HW_DIGCTL_CHIPID_MX28	(0x2800 << 16)

static void mxs_silicon_revision(void)
{
	enum silicon_revision revision = SILICON_REVISION_UNKNOWN;
	const char *product = "unknown";
	uint32_t reg;
	uint8_t rev;

	reg = readl((void __iomem *)HW_DIGCTL_CHIPID);
	rev = reg & 0xff;

	switch (reg & HW_DIGCTL_CHIPID_MASK) {
	case HW_DIGCTL_CHIPID_MX23:
		product = "i.MX23";
		switch (rev) {
		case 0x0: revision = SILICON_REVISION_1_0; break;
		case 0x1: revision = SILICON_REVISION_1_1; break;
		case 0x2: revision = SILICON_REVISION_1_2; break;
		case 0x3: revision = SILICON_REVISION_1_3; break;
		case 0x4: revision = SILICON_REVISION_1_4; break;
		}
		break;
	case HW_DIGCTL_CHIPID_MX28:
		product = "i.MX28";
		switch (rev) {
		case 0x1: revision = SILICON_REVISION_1_2; break;
		}
	}

	silicon_revision_set(product, revision);
}

#define MX28_REV_1_0_MODE	(0x0001a7f0)
#define MX28_REV_1_2_MODE	(0x00019bf0)

static void mxs_boot_save_loc(void)
{
	enum bootsource src = BOOTSOURCE_UNKNOWN;
	int instance = 0;
	uint32_t mode = 0xff;

	if (cpu_is_mx23()) {
		/* not implemented yet */
	} else if (cpu_is_mx28()) {
		enum silicon_revision rev = silicon_revision_get();

		if (rev == SILICON_REVISION_1_2)
			mode = *(uint32_t *)MX28_REV_1_2_MODE;
		else
			mode = *(uint32_t *)MX28_REV_1_0_MODE;
	}

	switch (mode & 0xf) {
	case 0x0: src = BOOTSOURCE_USB; break;		/* "USB" */
	case 0x1: src = BOOTSOURCE_I2C_EEPROM; break;	/* "I2C, master" */
	case 0x3: instance = 1;	/* fallthrough */	/* "SSP SPI #2, master, NOR" */
	case 0x2: src = BOOTSOURCE_SPI_NOR; break;	/* "SSP SPI #1, master, NOR" */
	case 0x4: src = BOOTSOURCE_NAND; break;		/* "NAND" */
	case 0x8: src = BOOTSOURCE_SPI_EEPROM; break;	/* "SSP SPI #3, master, EEPROM" */
	case 0xa: instance = 1;	/* fallthrough */	/* "SSP SD/MMC #1" */
	case 0x9: src = BOOTSOURCE_MMC; break;		/* "SSP SD/MMC #0" */
	}

	bootsource_set(src);
	bootsource_set_instance(instance);
}

static int mxs_init(void)
{
	mxs_silicon_revision();
	mxs_boot_save_loc();

	return 0;
}
postcore_initcall(mxs_init);