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, ®val, 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, ®val, 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, ®val, 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, ®val, 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, ®val, 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