xref: /rk3399_rockchip-uboot/board/keymile/km_arm/fpga_config.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
1b37f7724SValentin Longchamp /*
2b37f7724SValentin Longchamp  * (C) Copyright 2012
3b37f7724SValentin Longchamp  * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
4b37f7724SValentin Longchamp  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6b37f7724SValentin Longchamp  */
7b37f7724SValentin Longchamp 
8b37f7724SValentin Longchamp #include <common.h>
9b37f7724SValentin Longchamp #include <i2c.h>
10*1221ce45SMasahiro Yamada #include <linux/errno.h>
11b37f7724SValentin Longchamp 
12b37f7724SValentin Longchamp /* GPIO Pin from kirkwood connected to PROGRAM_B pin of the xilinx FPGA */
13b37f7724SValentin Longchamp #define KM_XLX_PROGRAM_B_PIN    39
14b37f7724SValentin Longchamp 
15b37f7724SValentin Longchamp #define BOCO_ADDR	0x10
16b37f7724SValentin Longchamp 
17b37f7724SValentin Longchamp #define ID_REG		0x00
18b37f7724SValentin Longchamp #define BOCO2_ID	0x5b
19b37f7724SValentin Longchamp 
check_boco2(void)20b37f7724SValentin Longchamp static int check_boco2(void)
21b37f7724SValentin Longchamp {
22b37f7724SValentin Longchamp 	int ret;
23b37f7724SValentin Longchamp 	u8 id;
24b37f7724SValentin Longchamp 
25b37f7724SValentin Longchamp 	ret = i2c_read(BOCO_ADDR, ID_REG, 1, &id, 1);
26b37f7724SValentin Longchamp 	if (ret) {
27b37f7724SValentin Longchamp 		printf("%s: error reading the BOCO id !!\n", __func__);
28b37f7724SValentin Longchamp 		return ret;
29b37f7724SValentin Longchamp 	}
30b37f7724SValentin Longchamp 
31b37f7724SValentin Longchamp 	return (id == BOCO2_ID);
32b37f7724SValentin Longchamp }
33b37f7724SValentin Longchamp 
boco_clear_bits(u8 reg,u8 flags)34b37f7724SValentin Longchamp static int boco_clear_bits(u8 reg, u8 flags)
35b37f7724SValentin Longchamp {
36b37f7724SValentin Longchamp 	int ret;
37b37f7724SValentin Longchamp 	u8 regval;
38b37f7724SValentin Longchamp 
39b37f7724SValentin Longchamp 	/* give access to the EEPROM from FPGA */
40b37f7724SValentin Longchamp 	ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
41b37f7724SValentin Longchamp 	if (ret) {
42b37f7724SValentin Longchamp 		printf("%s: error reading the BOCO @%#x !!\n",
43b37f7724SValentin Longchamp 			__func__, reg);
44b37f7724SValentin Longchamp 		return ret;
45b37f7724SValentin Longchamp 	}
46b37f7724SValentin Longchamp 	regval &= ~flags;
47b37f7724SValentin Longchamp 	ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
48b37f7724SValentin Longchamp 	if (ret) {
49b37f7724SValentin Longchamp 		printf("%s: error writing the BOCO @%#x !!\n",
50b37f7724SValentin Longchamp 			__func__, reg);
51b37f7724SValentin Longchamp 		return ret;
52b37f7724SValentin Longchamp 	}
53b37f7724SValentin Longchamp 
54b37f7724SValentin Longchamp 	return 0;
55b37f7724SValentin Longchamp }
56b37f7724SValentin Longchamp 
boco_set_bits(u8 reg,u8 flags)57b37f7724SValentin Longchamp static int boco_set_bits(u8 reg, u8 flags)
58b37f7724SValentin Longchamp {
59b37f7724SValentin Longchamp 	int ret;
60b37f7724SValentin Longchamp 	u8 regval;
61b37f7724SValentin Longchamp 
62b37f7724SValentin Longchamp 	/* give access to the EEPROM from FPGA */
63b37f7724SValentin Longchamp 	ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
64b37f7724SValentin Longchamp 	if (ret) {
65b37f7724SValentin Longchamp 		printf("%s: error reading the BOCO @%#x !!\n",
66b37f7724SValentin Longchamp 			__func__, reg);
67b37f7724SValentin Longchamp 		return ret;
68b37f7724SValentin Longchamp 	}
69b37f7724SValentin Longchamp 	regval |= flags;
70b37f7724SValentin Longchamp 	ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
71b37f7724SValentin Longchamp 	if (ret) {
72b37f7724SValentin Longchamp 		printf("%s: error writing the BOCO @%#x !!\n",
73b37f7724SValentin Longchamp 			__func__, reg);
74b37f7724SValentin Longchamp 		return ret;
75b37f7724SValentin Longchamp 	}
76b37f7724SValentin Longchamp 
77b37f7724SValentin Longchamp 	return 0;
78b37f7724SValentin Longchamp }
79b37f7724SValentin Longchamp 
80b37f7724SValentin Longchamp #define SPI_REG		0x06
81b37f7724SValentin Longchamp #define CFG_EEPROM	0x02
82b37f7724SValentin Longchamp #define FPGA_PROG	0x04
83bcac5b1bSValentin Longchamp #define FPGA_INIT_B	0x10
84b37f7724SValentin Longchamp #define FPGA_DONE	0x20
85b37f7724SValentin Longchamp 
fpga_done(void)86dbdee4caSValentin Longchamp static int fpga_done(void)
87bcac5b1bSValentin Longchamp {
88bcac5b1bSValentin Longchamp 	int ret = 0;
89bcac5b1bSValentin Longchamp 	u8 regval;
90bcac5b1bSValentin Longchamp 
91bcac5b1bSValentin Longchamp 	/* this is only supported with the boco2 design */
92bcac5b1bSValentin Longchamp 	if (!check_boco2())
93bcac5b1bSValentin Longchamp 		return 0;
94bcac5b1bSValentin Longchamp 
95bcac5b1bSValentin Longchamp 	ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &regval, 1);
96bcac5b1bSValentin Longchamp 	if (ret) {
97bcac5b1bSValentin Longchamp 		printf("%s: error reading the BOCO @%#x !!\n",
98bcac5b1bSValentin Longchamp 			__func__, SPI_REG);
99bcac5b1bSValentin Longchamp 		return 0;
100bcac5b1bSValentin Longchamp 	}
101bcac5b1bSValentin Longchamp 
102bcac5b1bSValentin Longchamp 	return regval & FPGA_DONE ? 1 : 0;
103bcac5b1bSValentin Longchamp }
104bcac5b1bSValentin Longchamp 
105bcac5b1bSValentin Longchamp int skip;
106bcac5b1bSValentin Longchamp 
trigger_fpga_config(void)107b37f7724SValentin Longchamp int trigger_fpga_config(void)
108b37f7724SValentin Longchamp {
109b37f7724SValentin Longchamp 	int ret = 0;
110b37f7724SValentin Longchamp 
111bcac5b1bSValentin Longchamp 	/* if the FPGA is already configured, we do not want to
112bcac5b1bSValentin Longchamp 	 * reconfigure it */
113bcac5b1bSValentin Longchamp 	skip = 0;
114bcac5b1bSValentin Longchamp 	if (fpga_done()) {
115bcac5b1bSValentin Longchamp 		printf("PCIe FPGA config: skipped\n");
116bcac5b1bSValentin Longchamp 		skip = 1;
117bcac5b1bSValentin Longchamp 		return 0;
118bcac5b1bSValentin Longchamp 	}
119bcac5b1bSValentin Longchamp 
120b37f7724SValentin Longchamp 	if (check_boco2()) {
121b37f7724SValentin Longchamp 		/* we have a BOCO2, this has to be triggered here */
122b37f7724SValentin Longchamp 
123b37f7724SValentin Longchamp 		/* make sure the FPGA_can access the EEPROM */
124b37f7724SValentin Longchamp 		ret = boco_clear_bits(SPI_REG, CFG_EEPROM);
125b37f7724SValentin Longchamp 		if (ret)
126b37f7724SValentin Longchamp 			return ret;
127b37f7724SValentin Longchamp 
128b37f7724SValentin Longchamp 		/* trigger the config start */
129bcac5b1bSValentin Longchamp 		ret = boco_clear_bits(SPI_REG, FPGA_PROG | FPGA_INIT_B);
130b37f7724SValentin Longchamp 		if (ret)
131b37f7724SValentin Longchamp 			return ret;
132b37f7724SValentin Longchamp 
133b37f7724SValentin Longchamp 		/* small delay for the pulse */
134b37f7724SValentin Longchamp 		udelay(10);
135b37f7724SValentin Longchamp 
136b37f7724SValentin Longchamp 		/* up signal for pulse end */
137b37f7724SValentin Longchamp 		ret = boco_set_bits(SPI_REG, FPGA_PROG);
138b37f7724SValentin Longchamp 		if (ret)
139b37f7724SValentin Longchamp 			return ret;
140b37f7724SValentin Longchamp 
141bcac5b1bSValentin Longchamp 		/* finally, raise INIT_B to remove the config delay */
142bcac5b1bSValentin Longchamp 		ret = boco_set_bits(SPI_REG, FPGA_INIT_B);
143bcac5b1bSValentin Longchamp 		if (ret)
144bcac5b1bSValentin Longchamp 			return ret;
145bcac5b1bSValentin Longchamp 
146b37f7724SValentin Longchamp 	} else {
147b37f7724SValentin Longchamp 		/* we do it the old way, with the gpio pin */
148b37f7724SValentin Longchamp 		kw_gpio_set_valid(KM_XLX_PROGRAM_B_PIN, 1);
149b37f7724SValentin Longchamp 		kw_gpio_direction_output(KM_XLX_PROGRAM_B_PIN, 0);
150b37f7724SValentin Longchamp 		/* small delay for the pulse */
151b37f7724SValentin Longchamp 		udelay(10);
152b37f7724SValentin Longchamp 		kw_gpio_direction_input(KM_XLX_PROGRAM_B_PIN);
153b37f7724SValentin Longchamp 	}
154b37f7724SValentin Longchamp 
155b37f7724SValentin Longchamp 	return 0;
156b37f7724SValentin Longchamp }
157b37f7724SValentin Longchamp 
wait_for_fpga_config(void)158b37f7724SValentin Longchamp int wait_for_fpga_config(void)
159b37f7724SValentin Longchamp {
160b37f7724SValentin Longchamp 	int ret = 0;
161b37f7724SValentin Longchamp 	u8 spictrl;
162b37f7724SValentin Longchamp 	u32 timeout = 20000;
163b37f7724SValentin Longchamp 
164bcac5b1bSValentin Longchamp 	if (skip)
165bcac5b1bSValentin Longchamp 		return 0;
166bcac5b1bSValentin Longchamp 
167b37f7724SValentin Longchamp 	if (!check_boco2()) {
168b37f7724SValentin Longchamp 		/* we do not have BOCO2, this is not really used */
169b37f7724SValentin Longchamp 		return 0;
170b37f7724SValentin Longchamp 	}
171b37f7724SValentin Longchamp 
172b37f7724SValentin Longchamp 	printf("PCIe FPGA config:");
173b37f7724SValentin Longchamp 	do {
174b37f7724SValentin Longchamp 		ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &spictrl, 1);
175b37f7724SValentin Longchamp 		if (ret) {
176b37f7724SValentin Longchamp 			printf("%s: error reading the BOCO spictrl !!\n",
177b37f7724SValentin Longchamp 				__func__);
178b37f7724SValentin Longchamp 			return ret;
179b37f7724SValentin Longchamp 		}
180b37f7724SValentin Longchamp 		if (timeout-- == 0) {
181b37f7724SValentin Longchamp 			printf(" FPGA_DONE timeout\n");
182b37f7724SValentin Longchamp 			return -EFAULT;
183b37f7724SValentin Longchamp 		}
184b37f7724SValentin Longchamp 		udelay(10);
185b37f7724SValentin Longchamp 	} while (!(spictrl & FPGA_DONE));
186b37f7724SValentin Longchamp 
187b37f7724SValentin Longchamp 	printf(" done\n");
188b37f7724SValentin Longchamp 
189b37f7724SValentin Longchamp 	return 0;
190b37f7724SValentin Longchamp }
191b37f7724SValentin Longchamp 
1929c134e18SGerlando Falauto #if defined(KM_PCIE_RESET_MPP7)
1939c134e18SGerlando Falauto 
1949c134e18SGerlando Falauto #define KM_PEX_RST_GPIO_PIN	7
fpga_reset(void)1959c134e18SGerlando Falauto int fpga_reset(void)
1969c134e18SGerlando Falauto {
1979c134e18SGerlando Falauto 	if (!check_boco2()) {
1989c134e18SGerlando Falauto 		/* we do not have BOCO2, this is not really used */
1999c134e18SGerlando Falauto 		return 0;
2009c134e18SGerlando Falauto 	}
2019c134e18SGerlando Falauto 
2029c134e18SGerlando Falauto 	printf("PCIe reset through GPIO7: ");
2039c134e18SGerlando Falauto 	/* apply PCIe reset via GPIO */
2049c134e18SGerlando Falauto 	kw_gpio_set_valid(KM_PEX_RST_GPIO_PIN, 1);
2059c134e18SGerlando Falauto 	kw_gpio_direction_output(KM_PEX_RST_GPIO_PIN, 1);
2069c134e18SGerlando Falauto 	kw_gpio_set_value(KM_PEX_RST_GPIO_PIN, 0);
2079c134e18SGerlando Falauto 	udelay(1000*10);
2089c134e18SGerlando Falauto 	kw_gpio_set_value(KM_PEX_RST_GPIO_PIN, 1);
2099c134e18SGerlando Falauto 
2109c134e18SGerlando Falauto 	printf(" done\n");
2119c134e18SGerlando Falauto 
2129c134e18SGerlando Falauto 	return 0;
2139c134e18SGerlando Falauto }
2149c134e18SGerlando Falauto 
2159c134e18SGerlando Falauto #else
2169c134e18SGerlando Falauto 
217b37f7724SValentin Longchamp #define PRST1		0x4
218dbdee4caSValentin Longchamp #define PCIE_RST	0x10
219dbdee4caSValentin Longchamp #define TRAFFIC_RST	0x04
220b37f7724SValentin Longchamp 
fpga_reset(void)221b37f7724SValentin Longchamp int fpga_reset(void)
222b37f7724SValentin Longchamp {
223b37f7724SValentin Longchamp 	int ret = 0;
224dbdee4caSValentin Longchamp 	u8 resets;
225b37f7724SValentin Longchamp 
226b37f7724SValentin Longchamp 	if (!check_boco2()) {
227b37f7724SValentin Longchamp 		/* we do not have BOCO2, this is not really used */
228b37f7724SValentin Longchamp 		return 0;
229b37f7724SValentin Longchamp 	}
230b37f7724SValentin Longchamp 
231dbdee4caSValentin Longchamp 	/* if we have skipped, we only want to reset the PCIe part */
232dbdee4caSValentin Longchamp 	resets = skip ? PCIE_RST : PCIE_RST | TRAFFIC_RST;
233dbdee4caSValentin Longchamp 
234dbdee4caSValentin Longchamp 	ret = boco_clear_bits(PRST1, resets);
235b37f7724SValentin Longchamp 	if (ret)
236b37f7724SValentin Longchamp 		return ret;
237b37f7724SValentin Longchamp 
238b37f7724SValentin Longchamp 	/* small delay for the pulse */
239b37f7724SValentin Longchamp 	udelay(10);
240b37f7724SValentin Longchamp 
241dbdee4caSValentin Longchamp 	ret = boco_set_bits(PRST1, resets);
242b37f7724SValentin Longchamp 	if (ret)
243b37f7724SValentin Longchamp 		return ret;
244b37f7724SValentin Longchamp 
245b37f7724SValentin Longchamp 	return 0;
246b37f7724SValentin Longchamp }
2479c134e18SGerlando Falauto #endif
248b37f7724SValentin Longchamp 
249b37f7724SValentin Longchamp /* the FPGA was configured, we configure the BOCO2 so that the EEPROM
250b37f7724SValentin Longchamp  * is available from the Bobcat SPI bus */
toggle_eeprom_spi_bus(void)251b37f7724SValentin Longchamp int toggle_eeprom_spi_bus(void)
252b37f7724SValentin Longchamp {
253b37f7724SValentin Longchamp 	int ret = 0;
254b37f7724SValentin Longchamp 
255b37f7724SValentin Longchamp 	if (!check_boco2()) {
256b37f7724SValentin Longchamp 		/* we do not have BOCO2, this is not really used */
257b37f7724SValentin Longchamp 		return 0;
258b37f7724SValentin Longchamp 	}
259b37f7724SValentin Longchamp 
260b37f7724SValentin Longchamp 	ret = boco_set_bits(SPI_REG, CFG_EEPROM);
261b37f7724SValentin Longchamp 	if (ret)
262b37f7724SValentin Longchamp 		return ret;
263b37f7724SValentin Longchamp 
264b37f7724SValentin Longchamp 	return 0;
265b37f7724SValentin Longchamp }
266