summaryrefslogtreecommitdiff
path: root/board/hisilicon/hikey/hikey.c
blob: 8c1271b4a4f04f4b792a12a857eb020bc95896d7 (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
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
/*
 * (C) Copyright 2015 Linaro
 * Peter Griffin <peter.griffin@linaro.org>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <netdev.h>
#include <asm/io.h>
#include <usb.h>
#include <power/hi6553_pmic.h>
#include <asm-generic/gpio.h>
#include <asm/arch/dwmmc.h>
#include <asm/arch/gpio.h>
#include <asm/arch/periph.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/hi6220.h>

/*TODO drop this table in favour of device tree */
static const struct hikey_gpio_platdata hi6220_gpio[] = {
	{ 0, HI6220_GPIO_BASE(0)},
	{ 1, HI6220_GPIO_BASE(1)},
	{ 2, HI6220_GPIO_BASE(2)},
	{ 3, HI6220_GPIO_BASE(3)},
	{ 4, HI6220_GPIO_BASE(4)},
	{ 5, HI6220_GPIO_BASE(5)},
	{ 6, HI6220_GPIO_BASE(6)},
	{ 7, HI6220_GPIO_BASE(7)},
	{ 8, HI6220_GPIO_BASE(8)},
	{ 9, HI6220_GPIO_BASE(9)},
	{ 10, HI6220_GPIO_BASE(10)},
	{ 11, HI6220_GPIO_BASE(11)},
	{ 12, HI6220_GPIO_BASE(12)},
	{ 13, HI6220_GPIO_BASE(13)},
	{ 14, HI6220_GPIO_BASE(14)},
	{ 15, HI6220_GPIO_BASE(15)},
	{ 16, HI6220_GPIO_BASE(16)},
	{ 17, HI6220_GPIO_BASE(17)},
	{ 18, HI6220_GPIO_BASE(18)},
	{ 19, HI6220_GPIO_BASE(19)},

};

U_BOOT_DEVICES(hi6220_gpios) = {
	{ "gpio_hi6220", &hi6220_gpio[0] },
	{ "gpio_hi6220", &hi6220_gpio[1] },
	{ "gpio_hi6220", &hi6220_gpio[2] },
	{ "gpio_hi6220", &hi6220_gpio[3] },
	{ "gpio_hi6220", &hi6220_gpio[4] },
	{ "gpio_hi6220", &hi6220_gpio[5] },
	{ "gpio_hi6220", &hi6220_gpio[6] },
	{ "gpio_hi6220", &hi6220_gpio[7] },
	{ "gpio_hi6220", &hi6220_gpio[8] },
	{ "gpio_hi6220", &hi6220_gpio[9] },
	{ "gpio_hi6220", &hi6220_gpio[10] },
	{ "gpio_hi6220", &hi6220_gpio[11] },
	{ "gpio_hi6220", &hi6220_gpio[12] },
	{ "gpio_hi6220", &hi6220_gpio[13] },
	{ "gpio_hi6220", &hi6220_gpio[14] },
	{ "gpio_hi6220", &hi6220_gpio[15] },
	{ "gpio_hi6220", &hi6220_gpio[16] },
	{ "gpio_hi6220", &hi6220_gpio[17] },
	{ "gpio_hi6220", &hi6220_gpio[18] },
	{ "gpio_hi6220", &hi6220_gpio[19] },
};

DECLARE_GLOBAL_DATA_PTR;

struct peri_sc_periph_regs *peri_sc =
	(struct peri_sc_periph_regs *)HI6220_PERI_BASE;

struct alwayson_sc_regs *ao_sc =
	(struct alwayson_sc_regs *)ALWAYSON_CTRL_BASE;

/* status offset from enable reg */
#define STAT_EN_OFF 0x2

void hi6220_clk_enable(u32 bitfield, unsigned int *clk_base)
{
	uint32_t data;

	data = readl(clk_base);
	data |= bitfield;

	writel(bitfield, clk_base);
	do {
		data = readl(clk_base + STAT_EN_OFF);
	} while ((data & bitfield) == 0);
}

/* status offset from disable reg */
#define STAT_DIS_OFF 0x1

void hi6220_clk_disable(u32 bitfield, unsigned int *clk_base)
{
	uint32_t data;

	data = readl(clk_base);
	data |= bitfield;

	writel(data, clk_base);
	do {
		data = readl(clk_base + STAT_DIS_OFF);
	} while (data & bitfield);
}

#define EYE_PATTERN	0x70533483

int board_usb_init(int index, enum usb_init_type init)
{
	unsigned int data;

	/* enable USB clock */
	hi6220_clk_enable(PERI_CLK0_USBOTG, &peri_sc->clk0_en);

	/* take usb IPs out of reset */
	writel(PERI_RST0_USBOTG_BUS | PERI_RST0_POR_PICOPHY |
		PERI_RST0_USBOTG | PERI_RST0_USBOTG_32K,
		&peri_sc->rst0_dis);
	do {
		data = readl(&peri_sc->rst0_stat);
		data &= PERI_RST0_USBOTG_BUS | PERI_RST0_POR_PICOPHY |
			PERI_RST0_USBOTG | PERI_RST0_USBOTG_32K;
	} while (data);

	/*CTRL 5*/
	data = readl(&peri_sc->ctrl5);
	data &= ~PERI_CTRL5_PICOPHY_BC_MODE;
	data |= PERI_CTRL5_USBOTG_RES_SEL | PERI_CTRL5_PICOPHY_ACAENB;
	data |= 0x300;
	writel(data, &peri_sc->ctrl5);

	/*CTRL 4*/

	/* configure USB PHY */
	data = readl(&peri_sc->ctrl4);

	/* make PHY out of low power mode */
	data &= ~PERI_CTRL4_PICO_SIDDQ;
	data &= ~PERI_CTRL4_PICO_OGDISABLE;
	data |= PERI_CTRL4_PICO_VBUSVLDEXTSEL | PERI_CTRL4_PICO_VBUSVLDEXT;
	writel(data, &peri_sc->ctrl4);

	writel(EYE_PATTERN, &peri_sc->ctrl8);

	mdelay(5);
	return 0;
}

static int config_sd_carddetect(void)
{
	int ret;

	/* configure GPIO8 as nopull */
	writel(0, 0xf8001830);

	gpio_request(8, "SD CD");

	gpio_direction_input(8);
	ret = gpio_get_value(8);

	if (!ret) {
		printf("%s: SD card present\n", __func__);
		return 1;
	}

	printf("%s: SD card not present\n", __func__);
	return 0;
}


static void mmc1_init_pll(void)
{
	uint32_t data;

	/* select SYSPLL as the source of MMC1 */
	/* select SYSPLL as the source of MUX1 (SC_CLK_SEL0) */
	writel(1 << 11 | 1 << 27, &peri_sc->clk0_sel);
	do {
		data = readl(&peri_sc->clk0_sel);
	} while (!(data & (1 << 11)));

	/* select MUX1 as the source of MUX2 (SC_CLK_SEL0) */
	writel(1 << 30, &peri_sc->clk0_sel);
	do {
		data = readl(&peri_sc->clk0_sel);
	} while (data & (1 << 14));

	hi6220_clk_enable(PERI_CLK0_MMC1, &peri_sc->clk0_en);

	hi6220_clk_enable(PERI_CLK12_MMC1_SRC, &peri_sc->clk12_en);

	do {
		/* 1.2GHz / 50 = 24MHz */
		writel(0x31 | (1 << 7), &peri_sc->clkcfg8bit2);
		data = readl(&peri_sc->clkcfg8bit2);
	} while ((data & 0x31) != 0x31);
}

static void mmc1_reset_clk(void)
{
	unsigned int data;

	/* disable mmc1 bus clock */
	hi6220_clk_disable(PERI_CLK0_MMC1, &peri_sc->clk0_dis);

	/* enable mmc1 bus clock */
	hi6220_clk_enable(PERI_CLK0_MMC1, &peri_sc->clk0_en);

	/* reset mmc1 clock domain */
	writel(PERI_RST0_MMC1, &peri_sc->rst0_en);

	/* bypass mmc1 clock phase */
	data = readl(&peri_sc->ctrl2);
	data |= 3 << 2;
	writel(data, &peri_sc->ctrl2);

	/* disable low power */
	data = readl(&peri_sc->ctrl13);
	data |= 1 << 4;
	writel(data, &peri_sc->ctrl13);
	do {
		data = readl(&peri_sc->rst0_stat);
	} while (!(data & PERI_RST0_MMC1));

	/* unreset mmc0 clock domain */
	writel(PERI_RST0_MMC1, &peri_sc->rst0_dis);
	do {
		data = readl(&peri_sc->rst0_stat);
	} while (data & PERI_RST0_MMC1);
}

/* PMU SSI is the IP that maps the external PMU hi6553 registers as IO */
static void hi6220_pmussi_init(void)
{
	uint32_t data;

	/* Take PMUSSI out of reset */
	writel(ALWAYSON_SC_PERIPH_RST4_DIS_PRESET_PMUSSI_N,
	       &ao_sc->rst4_dis);
	do {
		data = readl(&ao_sc->rst4_stat);
	} while (data & ALWAYSON_SC_PERIPH_RST4_DIS_PRESET_PMUSSI_N);

	/* set PMU SSI clock latency for read operation */
	data = readl(&ao_sc->mcu_subsys_ctrl3);
	data &= ~ALWAYSON_SC_MCU_SUBSYS_CTRL3_RCLK_MASK;
	data |= ALWAYSON_SC_MCU_SUBSYS_CTRL3_RCLK_3;
	writel(data, &ao_sc->mcu_subsys_ctrl3);

	/* enable PMUSSI clock */
	data = ALWAYSON_SC_PERIPH_CLK5_EN_PCLK_PMUSSI_CCPU |
	       ALWAYSON_SC_PERIPH_CLK5_EN_PCLK_PMUSSI_MCU;

	hi6220_clk_enable(data, &ao_sc->clk5_en);

	/* Output high to PMIC on PWR_HOLD_GPIO0_0 */
	gpio_request(0, "PWR_HOLD_GPIO0_0");
	gpio_direction_output(0, 1);
}

int misc_init_r(void)
{
	return 0;
}

int board_init(void)
{
	gd->flags = 0;

	return 0;
}

#ifdef CONFIG_GENERIC_MMC

static int init_dwmmc(void)
{
	int ret;

#ifdef CONFIG_DWMMC

	/* mmc0 clocks are already configured by ATF */
	ret = hi6220_pinmux_config(PERIPH_ID_SDMMC0);
	if (ret)
		printf("%s: Error configuring pinmux for eMMC (%d)\n"
			, __func__, ret);

	ret |= hi6220_dwmci_add_port(0, HI6220_MMC0_BASE, 8);
	if (ret)
		printf("%s: Error adding eMMC port (%d)\n", __func__, ret);


	/* take mmc1 (sd slot) out of reset, configure clocks and pinmuxing */
	mmc1_init_pll();
	mmc1_reset_clk();

	ret |= hi6220_pinmux_config(PERIPH_ID_SDMMC1);
	if (ret)
		printf("%s: Error configuring pinmux for eMMC (%d)\n"
			, __func__, ret);

	config_sd_carddetect();

	ret |= hi6220_dwmci_add_port(1, HI6220_MMC1_BASE, 4);
	if (ret)
		printf("%s: Error adding SD port (%d)\n", __func__, ret);

#endif
	return ret;
}

/* setup board specific PMIC */
int power_init_board(void)
{
	/* init the hi6220 pmussi ip */
	hi6220_pmussi_init();

	power_hi6553_init((u8 *)HI6220_PMUSSI_BASE);

	return 0;
}

int board_mmc_init(bd_t *bis)
{
	int ret;

	/* add the eMMC and sd ports */
	ret = init_dwmmc();

	if (ret)
		debug("init_dwmmc failed\n");

	return ret;
}
#endif

int dram_init(void)
{
	gd->ram_size = PHYS_SDRAM_1_SIZE;
	return 0;
}

void dram_init_banksize(void)
{
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
}

/* Use the Watchdog to cause reset */
void reset_cpu(ulong addr)
{
	/* TODO program the watchdog */
}