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