summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap/omap3_generic.c
blob: 4ab265a9ba022dc7603a4780dd438379e41faaeb (plain) (blame)
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
/**
 * @file
 * @brief Provide Generic implementations for OMAP3 architecture
 *
 * FileName: arch/arm/mach-omap/omap3_generic.c
 *
 * This file contains the generic implementations of various OMAP3
 * relevant functions
 * For more info on OMAP34XX, see http://focus.ti.com/pdfs/wtbu/swpu114g.pdf
 *
 * Important one is @ref a_init which is architecture init code.
 * The implemented functions are present in sys_info.h
 *
 * Originally from http://linux.omap.com/pub/bootloader/3430sdp/u-boot-v1.tar.gz
 */
/*
 * (C) Copyright 2006-2008
 * Texas Instruments, <www.ti.com>
 * Richard Woodruff <r-woodruff2@ti.com>
 * Nishanth Menon <x0nishan@ti.com>
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */
#include <common.h>
#include <init.h>
#include <io.h>
#include <mach/silicon.h>
#include <mach/gpmc.h>
#include <mach/sdrc.h>
#include <mach/control.h>
#include <mach/omap3-smx.h>
#include <mach/clocks.h>
#include <mach/wdt.h>
#include <mach/sys_info.h>
#include <mach/syslib.h>
#include <mach/xload.h>

/**
 * @brief Reset the CPU
 *
 * In case of crashes, reset the CPU
 *
 * @param addr Cause of crash
 *
 * @return void
 */
void __noreturn reset_cpu(unsigned long addr)
{
	writel(PRM_RSTCTRL_RESET, PRM_REG(RSTCTRL));

	while (1);
}
EXPORT_SYMBOL(reset_cpu);

/**
 * @brief Low level CPU type
 *
 * @return Detected CPU type
 */
u32 get_cpu_type(void)
{
	u32 idcode_val;
	u16 hawkeye;

	idcode_val = readl(IDCODE_REG);

	hawkeye = get_hawkeye(idcode_val);

	if (hawkeye == OMAP_HAWKEYE_34XX)
		return CPU_3430;

	if (hawkeye == OMAP_HAWKEYE_36XX)
		return CPU_3630;

	/*
	 * Fallback to OMAP3430 as default.
	 */
	return CPU_3430;
}

/**
 * @brief Extract the OMAP ES revision
 *
 * The significance of the CPU revision depends upon the cpu type.
 * Latest known revision is considered default.
 *
 * @return silicon version
 */
u32 get_cpu_rev(void)
{
	u32 idcode_val;
	u32 version, retval;

	idcode_val = readl(IDCODE_REG);

	version = get_version(idcode_val);

	switch (get_cpu_type()) {
	case CPU_3630:
		switch (version) {
		case 0:
			retval = OMAP36XX_ES1;
			break;
		case 1:
			retval = OMAP36XX_ES1_1;
			break;
		case 2:
			/*
			 * Fall through the default case.
			 */
		default:
			retval = OMAP36XX_ES1_2;
		}
		break;
	case CPU_3430:
		/*
		 * Same as default case
		 */
	default:
		/*
		 * On OMAP3430 ES1.0 the IDCODE register is not exposed on L4.
		 * Use CPU ID to check for the same.
		 */
		__asm__ __volatile__("mrc p15, 0, %0, c0, c0, 0":"=r"(retval));
		if ((retval & 0xf) == 0x0) {
			retval = OMAP34XX_ES1;
		} else {
			switch (version) {
			case 0: /* This field was not set in early samples */
			case 1:
				retval = OMAP34XX_ES2;
				break;
			case 2:
				retval = OMAP34XX_ES2_1;
				break;
			case 3:
				retval = OMAP34XX_ES3;
				break;
			case 4:
				/*
				 * Same as default case
				 */
			default:
				retval = OMAP34XX_ES3_1;
			}
		}
	}

	return retval;
}

/**
 * @brief Get size of chip select 0/1
 *
 * @param[in] offset  give the offset if we need CS1
 *
 * @return return the sdram size.
 */
u32 get_sdr_cs_size(u32 offset)
{
	u32 size;
	/* get ram size field */
	size = readl(SDRC_REG(MCFG_0) + offset) >> 8;
	size &= 0x3FF;		/* remove unwanted bits */
	size *= 2 * (1024 * 1024);	/* find size in MB */
	return size;
}
EXPORT_SYMBOL(get_sdr_cs_size);
/**
 * @brief base address of chip select 1 (cs0 is defined at 0x80000000)
 *
 * @return return the CS1 base address.
 */
u32 get_sdr_cs1_base(void)
{
	u32 base;
	u32 cs_cfg;

	cs_cfg = readl(SDRC_REG(CS_CFG));
	/* get ram size field */
	base = (cs_cfg & 0x0000000F) << 2; /* get CS1STARTHIGH */
	base = base | ((cs_cfg & 0x00000300) >> 8); /* get CS1STARTLOW */
	base = base << 25;
	base += 0x80000000;
	return base;
}
EXPORT_SYMBOL(get_sdr_cs1_base);
/**
 * @brief Get the initial SYSBOOT value
 *
 * SYSBOOT is useful to know which state OMAP booted from.
 *
 * @return - Return the value of SYSBOOT.
 */
inline u32 get_sysboot_value(void)
{
	return (0x0000003F & readl(CONTROL_REG(STATUS)));
}

/**
 * @brief Return the current CS0 base address
 *
 * Return current address hardware will be
 * fetching from. The below effectively gives what is correct, its a bit
 * mis-leading compared to the TRM.  For the most general case the mask
 * needs to be also taken into account this does work in practice.
 *
 * @return  base address
 */
u32 get_gpmc0_base(void)
{
	u32 b;
	b = readl(GPMC_REG(CONFIG7_0));
	b &= 0x1F;		/* keep base [5:0] */
	b = b << 24;		/* ret 0x0b000000 */
	return b;
}

/**
 * @brief Get the upper address of current execution
 *
 * we can use this to figure out if we are running in SRAM /
 * XIP Flash or in SDRAM
 *
 * @return base address
 */
u32 get_base(void)
{
	u32 val;
	__asm__ __volatile__("mov %0, pc \n":"=r"(val)::"memory");
	val &= 0xF0000000;
	val >>= 28;
	return val;
}

/**
 * @brief Are we running in Flash XIP?
 *
 * If the base is in GPMC address space, we probably are!
 *
 * @return 1 if we are running in XIP mode, else return 0
 */
u32 running_in_flash(void)
{
	if (get_base() < 4)
		return 1;	/* in flash */
	return 0;		/* running in SRAM or SDRAM */
}

/**
 * @brief Are we running in OMAP internal SRAM?
 *
 * If in SRAM address, then yes!
 *
 * @return  1 if we are running in SRAM, else return 0
 */
u32 running_in_sram(void)
{
	if (get_base() == 4)
		return 1;	/* in SRAM */
	return 0;		/* running in FLASH or SDRAM */
}

/**
 * @brief Are we running in SDRAM?
 *
 * if we are not in GPMC nor in SRAM address space,
 * we are in SDRAM execution area
 *
 * @return 1 if we are running from SDRAM, else return 0
 */
u32 running_in_sdram(void)
{
	if (get_base() > 4)
		return 1;	/* in sdram */
	return 0;		/* running in SRAM or FLASH */
}
EXPORT_SYMBOL(running_in_sdram);

/**
 * @brief Is this an XIP type device or a stream one
 *
 * Sysboot bits 4-0 specify type.  Bit 5, sys mem/perif
 *
 * @return Boot type
 */
u32 get_boot_type(void)
{
	u32 v;
	v = get_sysboot_value() & ((0x1 << 4) | (0x1 << 3) | (0x1 << 2) |
				   (0x1 << 1) | (0x1 << 0));
	return v;
}

/**
 * @brief What type of device are we?
 *
 * are we on a GP/HS/EMU/TEST device?
 *
 * @return  device type
 */
u32 get_device_type(void)
{
	int mode;
	mode = readl(CONTROL_REG(STATUS)) & (DEVICE_MASK);
	return (mode >>= 8);
}

/**
 * @brief Setup security registers for access
 *
 * This can be done for GP Device only. for HS/EMU devices, read TRM.
 *
 * @return void
 */
static void secure_unlock_mem(void)
{
	/* Permission values for registers -Full fledged permissions to all */
#define UNLOCK_1 0xFFFFFFFF
#define UNLOCK_2 0x00000000
#define UNLOCK_3 0x0000FFFF
	/* Protection Module Register Target APE (PM_RT) */
	writel(UNLOCK_1, RT_REQ_INFO_PERMISSION_1);
	writel(UNLOCK_1, RT_READ_PERMISSION_0);
	writel(UNLOCK_1, RT_WRITE_PERMISSION_0);
	writel(UNLOCK_2, RT_ADDR_MATCH_1);

	writel(UNLOCK_3, GPMC_REQ_INFO_PERMISSION_0);
	writel(UNLOCK_3, GPMC_READ_PERMISSION_0);
	writel(UNLOCK_3, GPMC_WRITE_PERMISSION_0);

	writel(UNLOCK_3, OCM_REQ_INFO_PERMISSION_0);
	writel(UNLOCK_3, OCM_READ_PERMISSION_0);
	writel(UNLOCK_3, OCM_WRITE_PERMISSION_0);
	writel(UNLOCK_2, OCM_ADDR_MATCH_2);

	/* IVA Changes */
	writel(UNLOCK_3, IVA2_REQ_INFO_PERMISSION_0);
	writel(UNLOCK_3, IVA2_READ_PERMISSION_0);
	writel(UNLOCK_3, IVA2_WRITE_PERMISSION_0);

	writel(UNLOCK_1, SMS_RG_ATT0);	/* SDRC region 0 public */
}

/**
 * @brief Come out of secure mode
 * If chip is EMU and boot type is external configure
 * secure registers and exit secure world general use.
 *
 * @return void
 */
static void secureworld_exit(void)
{
	unsigned long i;

	/* configrue non-secure access control register */
	__asm__ __volatile__("mrc p15, 0, %0, c1, c1, 2":"=r"(i));
	/* enabling co-processor CP10 and CP11 accesses in NS world */
	__asm__ __volatile__("orr %0, %0, #0xC00":"=r"(i));
	/* allow allocation of locked TLBs and L2 lines in NS world */
	/* allow use of PLE registers in NS world also */
	__asm__ __volatile__("orr %0, %0, #0x70000":"=r"(i));
	__asm__ __volatile__("mcr p15, 0, %0, c1, c1, 2":"=r"(i));

	/* Enable ASA in ACR register */
	__asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1":"=r"(i));
	__asm__ __volatile__("orr %0, %0, #0x10":"=r"(i));
	__asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1":"=r"(i));

	/* Exiting secure world */
	__asm__ __volatile__("mrc p15, 0, %0, c1, c1, 0":"=r"(i));
	__asm__ __volatile__("orr %0, %0, #0x31":"=r"(i));
	__asm__ __volatile__("mcr p15, 0, %0, c1, c1, 0":"=r"(i));
}

/**
 * @brief Shut down the watchdogs
 *
 * There are 3 watch dogs WD1=Secure, WD2=MPU, WD3=IVA. WD1 is
 * either taken care of by ROM (HS/EMU) or not accessible (GP).
 * We need to take care of WD2-MPU or take a PRCM reset.  WD3
 * should not be running and does not generate a PRCM reset.
 *
 * @return void
 */
static void watchdog_init(void)
{
	int pending = 1;

	sr32(CM_REG(FCLKEN_WKUP), 5, 1, 1);
	sr32(CM_REG(ICLKEN_WKUP), 5, 1, 1);
	wait_on_value((0x1 << 5), 0x20, CM_REG(IDLEST_WKUP), 5);

	writel(WDT_DISABLE_CODE1, WDT_REG(WSPR));

	do {
		pending = readl(WDT_REG(WWPS));
	} while (pending);

	writel(WDT_DISABLE_CODE2, WDT_REG(WSPR));
}

/**
 * @brief Write to AuxCR desired value using SMI.
 *  general use.
 *
 * @return void
 */
void setup_auxcr(void);

/**
 * @brief Try to unlock the SRAM for general use
 *
 * If chip is GP/EMU(special) type, unlock the SRAM for
 * general use.
 *
 * @return void
 */
static void try_unlock_memory(void)
{
	int mode;
	int in_sdram = running_in_sdram();

	/* if GP device unlock device SRAM for general use */
	/* secure code breaks for Secure/Emulation device - HS/E/T */
	mode = get_device_type();
	if (mode == GP_DEVICE)
		secure_unlock_mem();
	/* If device is EMU and boot is XIP external booting
	 * Unlock firewalls and disable L2 and put chip
	 * out of secure world
	 */
	/* Assuming memories are unlocked by the demon who put us in SDRAM */
	if ((mode <= EMU_DEVICE) && (get_boot_type() == 0x1F)
	    && (!in_sdram)) {
		secure_unlock_mem();
		secureworld_exit();
	}

	return;
}

/**
 * @brief OMAP3 Architecture specific Initialization
 *
 * Does early system init of disabling the watchdog, enable
 * memory and configuring the clocks.
 *
 * prcm_init is called only if CONFIG_OMAP3_CLOCK_CONFIG is defined.
 * We depend on link time clean up to remove a_init if no caller exists.
 *
 * @warning Called path is with SRAM stack
 *
 * @return void
 */
void omap3_core_init(void)
{
	watchdog_init();

	try_unlock_memory();

	/* Writing to AuxCR in barebox using SMI for GP DEV */
	/* Currently SMI in Kernel on ES2 devices seems to have an isse
	 * Once that is resolved, we can postpone this config to kernel
	 */
	if (get_device_type() == GP_DEVICE)
		setup_auxcr();

	sdelay(100);

#ifdef CONFIG_OMAP3_CLOCK_CONFIG
	prcm_init();
#endif

}

#define OMAP3_TRACING_VECTOR1 0x4020ffb4

enum omap_boot_src omap3_bootsrc(void)
{
	u32 bootsrc = readl(OMAP3_TRACING_VECTOR1);

	if (bootsrc & (1 << 2))
		return OMAP_BOOTSRC_NAND;
	if (bootsrc & (1 << 6))
		return OMAP_BOOTSRC_MMC1;
	return OMAP_BOOTSRC_UNKNOWN;
}

/* GPMC timing for OMAP3 nand device */
const struct gpmc_config omap3_nand_cfg = {
	.cfg = {
		0x00000000,	/* CONF1 */
		0x00141400,	/* CONF2 */
		0x00141400,	/* CONF3 */
		0x0F010F01,	/* CONF4 */
		0x010C1414,	/* CONF5 */
		0x1F040000 |
		0x00000A80,	/* CONF6 */
	},
	/* GPMC address map as small as possible */
	.base = 0x28000000,
	.size = GPMC_SIZE_16M,
};