1/*-
2 * Copyright (c) 2011
3 *	Ben Gray <ben.r.gray@gmail.com>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/module.h>
35#include <sys/bus.h>
36#include <sys/resource.h>
37#include <sys/rman.h>
38#include <sys/lock.h>
39#include <sys/mutex.h>
40
41#include <machine/bus.h>
42#include <machine/fdt.h>
43#include <machine/cpu.h>
44#include <machine/cpufunc.h>
45#include <machine/frame.h>
46#include <machine/resource.h>
47#include <machine/intr.h>
48
49#include <arm/ti/tivar.h>
50#include <arm/ti/ti_cpuid.h>
51
52#include <arm/ti/omap4/omap4_reg.h>
53#include <arm/ti/omap3/omap3_reg.h>
54#include <arm/ti/am335x/am335x_reg.h>
55
56#define OMAP4_STD_FUSE_DIE_ID_0    0x2200
57#define OMAP4_ID_CODE              0x2204
58#define OMAP4_STD_FUSE_DIE_ID_1    0x2208
59#define OMAP4_STD_FUSE_DIE_ID_2    0x220C
60#define OMAP4_STD_FUSE_DIE_ID_3    0x2210
61#define OMAP4_STD_FUSE_PROD_ID_0   0x2214
62#define OMAP4_STD_FUSE_PROD_ID_1   0x2218
63
64#define OMAP3_ID_CODE              0xA204
65
66static uint32_t chip_revision = 0xffffffff;
67
68/**
69 *	ti_revision - Returns the revision number of the device
70 *
71 *	Simply returns an identifier for the revision of the chip we are running
72 *	on.
73 *
74 *	RETURNS
75 *	A 32-bit identifier for the current chip
76 */
77uint32_t
78ti_revision(void)
79{
80	return chip_revision;
81}
82
83/**
84 *	omap4_get_revision - determines omap4 revision
85 *
86 *	Reads the registers to determine the revision of the chip we are currently
87 *	running on.  Stores the information in global variables.
88 *
89 *
90 */
91static void
92omap4_get_revision(void)
93{
94	uint32_t id_code;
95	uint32_t revision;
96	uint32_t hawkeye;
97	bus_space_handle_t bsh;
98
99	/* The chip revsion is read from the device identification registers and
100	 * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to
101	 * 0x4A00_2218.  This is part of the L4_CORE memory range and should have
102	 * been mapped in by the machdep.c code.
103	 *
104	 *   STD_FUSE_DIE_ID_0    0x4A00 2200
105	 *   ID_CODE              0x4A00 2204   (this is the only one we need)
106	 *   STD_FUSE_DIE_ID_1    0x4A00 2208
107	 *   STD_FUSE_DIE_ID_2    0x4A00 220C
108	 *   STD_FUSE_DIE_ID_3    0x4A00 2210
109	 *   STD_FUSE_PROD_ID_0   0x4A00 2214
110	 *   STD_FUSE_PROD_ID_1   0x4A00 2218
111	 */
112	/* FIXME Should we map somewhere else? */
113	bus_space_map(fdtbus_bs_tag,OMAP44XX_L4_CORE_HWBASE, 0x4000, 0, &bsh);
114	id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP4_ID_CODE);
115	bus_space_unmap(fdtbus_bs_tag, bsh, 0x4000);
116
117	hawkeye = ((id_code >> 12) & 0xffff);
118	revision = ((id_code >> 28) & 0xf);
119
120	/* Apparently according to the linux code there were some ES2.0 samples that
121	 * have the wrong id code and report themselves as ES1.0 silicon.  So used
122	 * the ARM cpuid to get the correct revision.
123	 */
124	if (revision == 0) {
125		id_code = cpufunc_id();
126		revision = (id_code & 0xf) - 1;
127	}
128
129	switch (hawkeye) {
130	case 0xB852:
131		switch (revision) {
132		case 0:
133			chip_revision = OMAP4430_REV_ES1_0;
134			break;
135		case 1:
136			chip_revision = OMAP4430_REV_ES2_1;
137			break;
138		default:
139			chip_revision = OMAP4430_REV_UNKNOWN;
140			break;
141		}
142		break;
143
144	case 0xB95C:
145		switch (revision) {
146		case 3:
147			chip_revision = OMAP4430_REV_ES2_1;
148			break;
149		case 4:
150			chip_revision = OMAP4430_REV_ES2_2;
151			break;
152		case 6:
153			chip_revision = OMAP4430_REV_ES2_3;
154			break;
155		default:
156			chip_revision = OMAP4430_REV_UNKNOWN;
157			break;
158		}
159		break;
160
161	case 0xB94E:
162		switch (revision) {
163		case 0:
164			chip_revision = OMAP4460_REV_ES1_0;
165			break;
166		case 2:
167			chip_revision = OMAP4460_REV_ES1_1;
168			break;
169		default:
170			chip_revision = OMAP4460_REV_UNKNOWN;
171			break;
172		}
173		break;
174
175	case 0xB975:
176		switch (revision) {
177		case 0:
178			chip_revision = OMAP4470_REV_ES1_0;
179			break;
180		default:
181			chip_revision = OMAP4470_REV_UNKNOWN;
182			break;
183		}
184		break;
185
186	default:
187		/* Default to the latest revision if we can't determine type */
188		chip_revision = OMAP_UNKNOWN_DEV;
189		break;
190	}
191	if (chip_revision != OMAP_UNKNOWN_DEV) {
192		printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n",
193		    OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision),
194		    OMAP_REV_MINOR(chip_revision));
195	}
196	else {
197		printf("Texas Instruments unknown OMAP chip: %04x, rev %d\n",
198		    hawkeye, revision);
199	}
200}
201
202/**
203 *	omap3_get_revision - determines omap3 revision
204 *
205 *	Reads the registers to determine the revision of the chip we are currently
206 *	running on.  Stores the information in global variables.
207 *
208 *	WARNING: This function currently only really works for OMAP3530 devices.
209 *
210 *
211 *
212 */
213static void
214omap3_get_revision(void)
215{
216	uint32_t id_code;
217	uint32_t revision;
218	uint32_t hawkeye;
219	bus_space_handle_t bsh;
220
221	/* The chip revsion is read from the device identification registers and
222	 * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to
223	 * 0x4A00_2218.  This is part of the L4_CORE memory range and should have
224	 * been mapped in by the machdep.c code.
225	 *
226	 *   CONTROL_IDCODE       0x4830 A204   (this is the only one we need)
227	 *
228	 *
229	 */
230	bus_space_map(fdtbus_bs_tag, OMAP35XX_L4_WAKEUP_HWBASE, 0x10000, 0, &bsh);
231	id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP3_ID_CODE);
232	bus_space_unmap(fdtbus_bs_tag, bsh, 0x10000);
233
234	hawkeye = ((id_code >> 12) & 0xffff);
235	revision = ((id_code >> 28) & 0xf);
236
237	switch (hawkeye) {
238	case 0xB6D6:
239		chip_revision = OMAP3350_REV_ES1_0;
240		break;
241	case 0xB7AE:
242		if (revision == 1)
243			chip_revision = OMAP3530_REV_ES2_0;
244		else if (revision == 2)
245			chip_revision = OMAP3530_REV_ES2_1;
246		else if (revision == 3)
247			chip_revision = OMAP3530_REV_ES3_0;
248		else if (revision == 4)
249			chip_revision = OMAP3530_REV_ES3_1;
250		else if (revision == 7)
251			chip_revision = OMAP3530_REV_ES3_1_2;
252		break;
253	default:
254		/* Default to the latest revision if we can't determine type */
255		chip_revision = OMAP3530_REV_ES3_1_2;
256		break;
257	}
258	printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n",
259		OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision),
260		OMAP_REV_MINOR(chip_revision));
261}
262
263static void
264am335x_get_revision(void)
265{
266	uint32_t dev_feature;
267	uint8_t cpu_last_char;
268	bus_space_handle_t bsh;
269
270	bus_space_map(fdtbus_bs_tag, AM335X_CONTROL_BASE, AM335X_CONTROL_SIZE, 0, &bsh);
271	chip_revision = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEVICE_ID);
272	dev_feature = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEV_FEATURE);
273	bus_space_unmap(fdtbus_bs_tag, bsh, AM335X_CONTROL_SIZE);
274
275	switch (dev_feature) {
276		case 0x00FF0382:
277			cpu_last_char='2';
278			break;
279		case 0x20FF0382:
280			cpu_last_char='4';
281			break;
282		case 0x00FF0383:
283			cpu_last_char='6';
284			break;
285		case 0x00FE0383:
286			cpu_last_char='7';
287			break;
288		case 0x20FF0383:
289			cpu_last_char='8';
290			break;
291		case 0x20FE0383:
292			cpu_last_char='9';
293			break;
294		default:
295			cpu_last_char='x';
296	}
297
298	printf("Texas Instruments AM335%c Processor, Revision ES1.%u\n",
299		cpu_last_char, AM335X_DEVREV(chip_revision));
300}
301
302/**
303 *	ti_cpu_ident - attempts to identify the chip we are running on
304 *	@dummy: ignored
305 *
306 *	This function is called before any of the driver are initialised, however
307 *	the basic virt to phys maps have been setup in machdep.c so we can still
308 *	access the required registers, we just have to use direct register reads
309 *	and writes rather than going through the bus stuff.
310 *
311 *
312 */
313static void
314ti_cpu_ident(void *dummy)
315{
316	switch(ti_chip()) {
317	case CHIP_OMAP_3:
318		omap3_get_revision();
319		break;
320	case CHIP_OMAP_4:
321		omap4_get_revision();
322		break;
323	case CHIP_AM335X:
324		am335x_get_revision();
325		break;
326	default:
327		panic("Unknown chip type, fixme!\n");
328	}
329}
330
331SYSINIT(ti_cpu_ident, SI_SUB_CPU, SI_ORDER_SECOND, ti_cpu_ident, NULL);
332