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