summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mxs/imx.c
blob: fcb26f73b3793370cc9d9abb23b51d16938ed08e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * (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);