summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/armv7/u8500/cpu.c
blob: d8634bebbdf759286137b2bc17390cf92229c3cf (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
 * Copyright (C) 2012 Linaro Limited
 * Mathieu Poirier <mathieu.poirier@linaro.org>
 *
 * Based on original code from Joakim Axelsson at ST-Ericsson
 * (C) Copyright 2010 ST-Ericsson
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <asm/io.h>
#include <asm/arch/prcmu.h>
#include <asm/arch/clock.h>
#include <asm/arch/hardware.h>

#include <asm/arch/hardware.h>

#define CPUID_DB8500V1		0x411fc091
#define CPUID_DB8500V2		0x412fc091
#define ASICID_DB8500V11	0x008500A1

#define CACHE_CONTR_BASE	0xA0412000
/* Cache controller register offsets
 * as found in ARM's technical reference manual
 */
#define CACHE_INVAL_BY_WAY	(CACHE_CONTR_BASE + 0x77C)
#define CACHE_LOCKDOWN_BY_D	(CACHE_CONTR_BASE + 0X900)
#define CACHE_LOCKDOWN_BY_I	(CACHE_CONTR_BASE + 0X904)

static unsigned int read_asicid(void);

static inline unsigned int read_cpuid(void)
{
	unsigned int val;

	/* Main ID register (MIDR) */
	asm("mrc        p15, 0, %0, c0, c0, 0"
	   : "=r" (val)
	   :
	   : "cc");

	return val;
}

static int cpu_is_u8500v11(void)
{
	return read_asicid() == ASICID_DB8500V11;
}

static int cpu_is_u8500v2(void)
{
	return read_cpuid() == CPUID_DB8500V2;
}

static unsigned int read_asicid(void)
{
	unsigned int *address;

	if (cpu_is_u8500v2())
		address = (void *) U8500_ASIC_ID_LOC_V2;
	else
		address = (void *) U8500_ASIC_ID_LOC_ED_V1;

	return readl(address);
}

void cpu_cache_initialization(void)
{
	unsigned int value;
	/* invalidate all cache entries */
	writel(0xFFFF, CACHE_INVAL_BY_WAY);

	/* ways are set to '0' when they are totally
	 * cleaned and invalidated
	 */
	do {
		value = readl(CACHE_INVAL_BY_WAY);
	} while (value & 0xFF);

	/* Invalidate register 9 D and I lockdown */
	writel(0xFF, CACHE_LOCKDOWN_BY_D);
	writel(0xFF, CACHE_LOCKDOWN_BY_I);
}

#ifdef CONFIG_ARCH_CPU_INIT
/*
 * SOC specific cpu init
 */
int arch_cpu_init(void)
{
	db8500_prcmu_init();
	db8500_clocks_init();

	return 0;
}
#endif /* CONFIG_ARCH_CPU_INIT */

#ifdef CONFIG_MMC

int u8500_mmc_power_init(void)
{
	int ret;
	int enable, voltage;
	int ab8500_revision;

	if (!cpu_is_u8500v11() && !cpu_is_u8500v2())
		return 0;

	/* Get AB8500 revision */
	ret = ab8500_read(AB8500_MISC, AB8500_REV_REG);
	if (ret < 0)
		goto out;

	ab8500_revision = ret;

	/*
	 * On v1.1 HREF boards (HREF+), Vaux3 needs to be enabled for the SD
	 * card to work.  This is done by enabling the regulators in the AB8500
	 * via PRCMU I2C transactions.
	 *
	 * This code is derived from the handling of AB8500_LDO_VAUX3 in
	 * ab8500_ldo_enable() and ab8500_ldo_disable() in Linux.
	 *
	 * Turn off and delay is required to have it work across soft reboots.
	 */

	/* Turn off (read-modify-write) */
	ret = ab8500_read(AB8500_REGU_CTRL2,
				AB8500_REGU_VRF1VAUX3_REGU_REG);
	if (ret < 0)
		goto out;

	enable = ret;

	/* Turn off */
	ret = ab8500_write(AB8500_REGU_CTRL2,
			AB8500_REGU_VRF1VAUX3_REGU_REG,
			enable & ~LDO_VAUX3_ENABLE_MASK);
	if (ret < 0)
		goto out;

	udelay(10 * 1000);

	/* Set the voltage to 2.91 V or 2.9 V without overriding VRF1 value */
	ret = ab8500_read(AB8500_REGU_CTRL2,
			AB8500_REGU_VRF1VAUX3_SEL_REG);
	if (ret < 0)
		goto out;

	voltage = ret;

	if (ab8500_revision < 0x20) {
		voltage &= ~LDO_VAUX3_SEL_MASK;
		voltage |= LDO_VAUX3_SEL_2V9;
	} else {
		voltage &= ~LDO_VAUX3_V2_SEL_MASK;
		voltage |= LDO_VAUX3_V2_SEL_2V91;
	}

	ret = ab8500_write(AB8500_REGU_CTRL2,
			AB8500_REGU_VRF1VAUX3_SEL_REG, voltage);
	if (ret < 0)
		goto out;

	/* Turn on the supply */
	enable &= ~LDO_VAUX3_ENABLE_MASK;
	enable |= LDO_VAUX3_ENABLE_VAL;

	ret = ab8500_write(AB8500_REGU_CTRL2,
			AB8500_REGU_VRF1VAUX3_REGU_REG, enable);

out:
	return ret;
}
#endif /* CONFIG_MMC */