aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-mvebu/alleycat5/soc.c
blob: 98e66735eb9eb546bbb3bbe20c54489589293e89 (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
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
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2018 Marvell International Ltd.
 */

#include <asm/arch-armada8k/cache_llc.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <dm/device.h>

#define DEVICE_ID_REG			0x7F90004C
#define DEVICE_ID_MASK			0xffff0
#define REV_ID_MASK			0xf
#define DEVICE_ID_OFFSET		4
#define REV_ID_OFFSET			0

#define DEVICE_SAR_REG			0x944F8204

#define DEVICE_ID_SUB_REV		(MVEBU_REGISTER(0x2400230))
#define DEVICE_ID_SUB_REV_OFFSET	7
#define DEVICE_ID_SUB_REV_MASK		(0xffff << DEVICE_ID_SUB_REV_OFFSET)

#define AC5X_DEV_ID			0x9800

struct soc_info {
	u32 dev_id;
	u32 rev_id;
	char *soc_name;
};

static struct soc_info soc_info_table[] = {
	/* Two reserved entries for unidentified devices - don't change */
	{ 0xB4FF, 0x0, "Unidentified Alleycat5"},
	{ 0x98FF, 0x0, "Unidentified Alleycat5x"},

	{ 0xB400, 0x2, "Alleycat5-plus  98DX2538-A2"},
	{ 0xB401, 0x2, "Alleycat5-plus  98DX2535-A2"},
	{ 0xB402, 0x2, "Alleycat5-plus  98DX2532-A2"},
	{ 0xB403, 0x2, "Alleycat5-plus  98DX2531-A2"},
	{ 0xB408, 0x2, "Alleycat5  98DX2528-A2"},
	{ 0xB409, 0x2, "Alleycat5  98DX2525-A2"},
	{ 0xB40A, 0x2, "Alleycat5  98DX2522-A2"},
	{ 0xB40B, 0x2, "Alleycat5  98DX2521-A2"},
	{ 0xB410, 0x2, "Alleycat5-lite  98DX2518-A2"},
	{ 0xB411, 0x2, "Alleycat5-lite  98DX2515-A2"},
	{ 0xB412, 0x2, "Alleycat5-lite  98DX2512-A2"},
	{ 0xB413, 0x2, "Alleycat5-lite  98DX2511-A2"},

	{ 0xB400, 0x1, "Alleycat5-plus  98DX2538-A1"},
	{ 0xB401, 0x1, "Alleycat5-plus  98DX2535-A1"},
	{ 0xB402, 0x1, "Alleycat5-plus  98DX2532-A1"},
	{ 0xB403, 0x1, "Alleycat5-plus  98DX2531-A1"},
	{ 0xB408, 0x1, "Alleycat5  98DX2528-A1"},
	{ 0xB409, 0x1, "Alleycat5  98DX2525-A1"},
	{ 0xB40A, 0x1, "Alleycat5  98DX2522-A1"},
	{ 0xB40B, 0x1, "Alleycat5  98DX2521-A1"},
	{ 0xB410, 0x1, "Alleycat5-lite  98DX2518-A1"},
	{ 0xB411, 0x1, "Alleycat5-lite  98DX2515-A1"},
	{ 0xB412, 0x1, "Alleycat5-lite  98DX2512-A1"},
	{ 0xB413, 0x1, "Alleycat5-lite  98DX2511-A1"},
	{ 0x9800, 0x1, "Alleycat5X 98DX3500M-A1"},
	{ 0x9806, 0x1, "Alleycat5X 98DX3501M-A1"},
	{ 0x9801, 0x1, "Alleycat5X 98DX3510M-A1"},
	{ 0x9802, 0x1, "Alleycat5X 98DX3520M-A1"},
	{ 0x9803, 0x1, "Alleycat5X 98DX3530M-A1"},
	{ 0x9804, 0x1, "Alleycat5X 98DX3540M-A1"},
	{ 0x9805, 0x1, "Alleycat5X 98DX3550M-A1"},
	{ 0x9820, 0x1, "Alleycat5X 98DX3500-A1"},
	{ 0x9826, 0x1, "Alleycat5X 98DX3501-A1"},
	{ 0x9821, 0x1, "Alleycat5X 98DX3510-A1"},
	{ 0x9861, 0x1, "Alleycat5X 98DX3510H-A1"},
	{ 0x9841, 0x1, "Alleycat5X 98DX3510MH-A1"},
	{ 0x9822, 0x1, "Alleycat5X 98DX3520-A1"},
	{ 0x9823, 0x1, "Alleycat5X 98DX3530-A1"},
	{ 0x9863, 0x1, "Alleycat5X 98DX3530H-A1"},
	{ 0x9824, 0x1, "Alleycat5X 98DX3540-A1"},
	{ 0x9825, 0x1, "Alleycat5X 98DX3550-A1"},

	{ 0xB400, 0x0, "Alleycat5-plus  98DX2538-A0"},
	{ 0xB401, 0x0, "Alleycat5-plus  98DX2535-A0"},
	{ 0xB402, 0x0, "Alleycat5-plus  98DX2532-A0"},
	{ 0xB403, 0x0, "Alleycat5-plus  98DX2531-A0"},
	{ 0xB408, 0x0, "Alleycat5  98DX2528-A0"},
	{ 0xB409, 0x0, "Alleycat5  98DX2525-A0"},
	{ 0xB40A, 0x0, "Alleycat5  98DX2522-A0"},
	{ 0xB40B, 0x0, "Alleycat5  98DX2521-A0"},
	{ 0xB410, 0x0, "Alleycat5-lite  98DX2518-A0"},
	{ 0xB411, 0x0, "Alleycat5-lite  98DX2515-A0"},
	{ 0xB412, 0x0, "Alleycat5-lite  98DX2512-A0"},
	{ 0xB413, 0x0, "Alleycat5-lite  98DX2511-A0"},
	{ 0x9800, 0x0, "Alleycat5X 98DX3500M-A0"},
	{ 0x9806, 0x0, "Alleycat5X 98DX3501M-A0"},
	{ 0x9801, 0x0, "Alleycat5X 98DX3510M-A0"},
	{ 0x9802, 0x0, "Alleycat5X 98DX3520M-A0"},
	{ 0x9803, 0x0, "Alleycat5X 98DX3530M-A0"},
	{ 0x9804, 0x0, "Alleycat5X 98DX3540M-A0"},
	{ 0x9805, 0x0, "Alleycat5X 98DX3550M-A0"},
	{ 0x9820, 0x0, "Alleycat5X 98DX3500-A0"},
	{ 0x9826, 0x0, "Alleycat5X 98DX3501-A0"},
	{ 0x9821, 0x0, "Alleycat5X 98DX3510-A0"},
	{ 0x9861, 0x0, "Alleycat5X 98DX3510H-A0"},
	{ 0x9841, 0x0, "Alleycat5X 98DX3510MH-A0"},
	{ 0x9822, 0x0, "Alleycat5X 98DX3520-A0"},
	{ 0x9823, 0x0, "Alleycat5X 98DX3530-A0"},
	{ 0x9863, 0x0, "Alleycat5X 98DX3530H-A0"},
	{ 0x9824, 0x0, "Alleycat5X 98DX3540-A0"},
	{ 0x9825, 0x0, "Alleycat5X 98DX3550-A0"},
};

#define BIT_VAL(b)          ((1ULL << ((b) + 1)) - 1)
#define BIT_RANGE(bl, bh)   (BIT_VAL(bh) - BIT_VAL((bl) - 1))

#define PLL_MAX_CHOICE	4

#define CPU_TYPE_AC5    0
#define CPU_TYPE_AC5x   1
#define CPU_TYPE_LAST   2

enum mvebu_sar_opts {
	SAR_CPU_FREQ = 0,
	SAR_DDR_FREQ,
	SAR_AP_FABRIC_FREQ,
	SAR_CP_FABRIC_FREQ,
	SAR_CP0_PCIE0_CLK,
	SAR_CP0_PCIE1_CLK,
	SAR_CP1_PCIE0_CLK,
	SAR_CP1_PCIE1_CLK,
	SAR_BOOT_SRC,
	SAR_MAX_IDX
};

static const u32 pll_freq_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1][PLL_MAX_CHOICE] = {
	[CPU_TYPE_AC5] = {
		[SAR_CPU_FREQ] = {
			800, 1200, 1400, 1000
		},
		[SAR_DDR_FREQ] = {
			1200, 800, 0, 0
		},
		[SAR_AP_FABRIC_FREQ] = {
			396, 290, 197, 0
		},
	},
	[CPU_TYPE_AC5x] = {
		[SAR_CPU_FREQ] = {
			800, 1200, 1500, 1600
		},
		[SAR_DDR_FREQ] = {
			1200, 800, 0, 0
		},
		[SAR_AP_FABRIC_FREQ] = {
			0, 0, 0, 0
		}
	}
};

static const u32 soc_sar_masks_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1] = {
	[CPU_TYPE_AC5] = {
		[SAR_CPU_FREQ] = BIT_RANGE(18, 20),
		[SAR_DDR_FREQ] = BIT_RANGE(16, 17),
		[SAR_AP_FABRIC_FREQ] = BIT_RANGE(22, 23),
	},
	[CPU_TYPE_AC5x] = {
		[SAR_CPU_FREQ] = BIT_RANGE(8, 10),
		[SAR_DDR_FREQ] = BIT_RANGE(6, 7),
		[SAR_AP_FABRIC_FREQ] = 1,
	},
};

static int get_soc_type_rev(u32 *type, u32 *rev)
{
	*type = (readl(DEVICE_ID_REG) & DEVICE_ID_MASK) >> DEVICE_ID_OFFSET;
	*rev =  (readl(DEVICE_ID_REG) & REV_ID_MASK)    >> REV_ID_OFFSET;

	return 0;
}

static void get_one_sar_freq(int cpu_type, u32 sar_reg_val, enum mvebu_sar_opts sar_opt, u32 *freq)
{
	u32 mask;
	unsigned char choice;

	mask = soc_sar_masks_tbl[cpu_type][sar_opt];
	choice = (sar_reg_val & mask) >> (__builtin_ffs(mask) - 1);
	*freq = pll_freq_tbl[cpu_type][sar_opt][choice];
}

void get_sar_freq(struct sar_freq_modes *sar_freq)
{
	int cpu_type;
	u32 soc_type, rev;
	u32 sar_reg_val = readl(DEVICE_SAR_REG);

	get_soc_type_rev(&soc_type, &rev);
	cpu_type = (soc_type & 0xFF00) == AC5X_DEV_ID ? CPU_TYPE_AC5x : CPU_TYPE_AC5;

	get_one_sar_freq(cpu_type, sar_reg_val, SAR_CPU_FREQ, &sar_freq->p_clk);
	get_one_sar_freq(cpu_type, sar_reg_val, SAR_AP_FABRIC_FREQ, &sar_freq->nb_clk);
	get_one_sar_freq(cpu_type, sar_reg_val, SAR_DDR_FREQ, &sar_freq->d_clk);
}

static int get_soc_table_index(u32 *index)
{
	u32 soc_type;
	u32 rev, i, ret = 1;

	*index = 0;
	get_soc_type_rev(&soc_type, &rev);

	for (i = 0; i < ARRAY_SIZE(soc_info_table) && ret != 0; i++) {
		if (soc_type != soc_info_table[i].dev_id ||
		    rev != soc_info_table[i].rev_id)
			continue;

		*index = i;
		ret = 0;
	}

	if (ret && ((soc_type & 0xFF00) == AC5X_DEV_ID))
		*index = 1;

	return ret;
}

static int get_soc_name(char **soc_name)
{
	u32 index;

	get_soc_table_index(&index);
	*soc_name = soc_info_table[index].soc_name;

	return 0;
}

/* Print device's SoC name and AP & CP information */
void soc_print_device_info(void)
{
	char *soc_name = NULL;

	get_soc_name(&soc_name);

	printf("SoC: %s\n", soc_name);
}

void soc_print_clock_info(void)
{
	struct sar_freq_modes sar_freq;

	get_sar_freq(&sar_freq);
	printf("Clock:  CPU     %4d MHz\n", sar_freq.p_clk);
	printf("\tDDR     %4d MHz\n", sar_freq.d_clk);
	printf("\tFABRIC  %4d MHz\n", sar_freq.nb_clk);
	printf("\tMSS     %4d MHz\n", 200);
}

/* Return NAND clock in Hz */
u32 mvebu_get_nand_clock(void)
{
	return 400 * 1000000;
}

/*
 * Override of __weak int mach_cpu_init(void) :
 * SoC/machine dependent CPU setup
 */
int mach_cpu_init(void)
{
	u32 phy_i;
	u64 new_val, phy_base = 0x7F080800;

	/* Init USB PHY */
#define USB_STEPPING	0x20000
#define WRITE_MASK(addr, mask, val)		\
	{ new_val = (readl(addr) & (~(mask))) | (val);\
	writel(new_val, addr); }

	for (phy_i = 0; phy_i < 2; phy_i++, phy_base += USB_STEPPING) {
		WRITE_MASK(phy_base + 0x4,     0x3,	   0x2);
		WRITE_MASK(phy_base + 0xC,     0x3000000,   0x2000000);
		WRITE_MASK(phy_base + 0x1C,    0x3,         0x2);
		WRITE_MASK(phy_base + 0x0,     0x1FF007F,   0x600005);
		WRITE_MASK(phy_base + 0xC,     0x000F000,   0x0002000);
		/* Calibration Threshold Setting = 4*/
		WRITE_MASK(phy_base + 0x8,     0x700,	   0x400)
		WRITE_MASK(phy_base + 0x14,    0x000000F,   0x000000a);
		/* Change AMP to 4*/
		WRITE_MASK(phy_base + 0xC,     0x3700000,   0x3400000);
		WRITE_MASK(phy_base + 0x4,     0x3,	   0x3);
		/* Impedance calibration triggering is performed by USB probe */
	}

	return 0;
}