blob: 8bb0470bc3073aee35992c1b5fde8c819ae2fa0b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Valentin Longchamp6633fed2012-07-05 05:05:05 +00002/*
3 * (C) Copyright 2012
4 * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
Valentin Longchamp6633fed2012-07-05 05:05:05 +00005 */
6
7#include <common.h>
8#include <i2c.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +09009#include <linux/errno.h>
Valentin Longchamp6633fed2012-07-05 05:05:05 +000010
11/* GPIO Pin from kirkwood connected to PROGRAM_B pin of the xilinx FPGA */
12#define KM_XLX_PROGRAM_B_PIN 39
13
14#define BOCO_ADDR 0x10
15
16#define ID_REG 0x00
17#define BOCO2_ID 0x5b
18
19static int check_boco2(void)
20{
21 int ret;
22 u8 id;
23
24 ret = i2c_read(BOCO_ADDR, ID_REG, 1, &id, 1);
25 if (ret) {
26 printf("%s: error reading the BOCO id !!\n", __func__);
27 return ret;
28 }
29
30 return (id == BOCO2_ID);
31}
32
33static int boco_clear_bits(u8 reg, u8 flags)
34{
35 int ret;
36 u8 regval;
37
38 /* give access to the EEPROM from FPGA */
39 ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
40 if (ret) {
41 printf("%s: error reading the BOCO @%#x !!\n",
42 __func__, reg);
43 return ret;
44 }
45 regval &= ~flags;
46 ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
47 if (ret) {
48 printf("%s: error writing the BOCO @%#x !!\n",
49 __func__, reg);
50 return ret;
51 }
52
53 return 0;
54}
55
56static int boco_set_bits(u8 reg, u8 flags)
57{
58 int ret;
59 u8 regval;
60
61 /* give access to the EEPROM from FPGA */
62 ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
63 if (ret) {
64 printf("%s: error reading the BOCO @%#x !!\n",
65 __func__, reg);
66 return ret;
67 }
68 regval |= flags;
69 ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
70 if (ret) {
71 printf("%s: error writing the BOCO @%#x !!\n",
72 __func__, reg);
73 return ret;
74 }
75
76 return 0;
77}
78
79#define SPI_REG 0x06
80#define CFG_EEPROM 0x02
81#define FPGA_PROG 0x04
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +000082#define FPGA_INIT_B 0x10
Valentin Longchamp6633fed2012-07-05 05:05:05 +000083#define FPGA_DONE 0x20
84
Holger Brunck55b3c6c2020-01-13 15:34:01 +010085#ifndef CONFIG_KM_FPGA_FORCE_CONFIG
Valentin Longchamp4e80d1c2012-07-05 05:05:09 +000086static int fpga_done(void)
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +000087{
88 int ret = 0;
89 u8 regval;
90
91 /* this is only supported with the boco2 design */
92 if (!check_boco2())
93 return 0;
94
95 ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &regval, 1);
96 if (ret) {
97 printf("%s: error reading the BOCO @%#x !!\n",
98 __func__, SPI_REG);
99 return 0;
100 }
101
102 return regval & FPGA_DONE ? 1 : 0;
103}
Holger Brunck55b3c6c2020-01-13 15:34:01 +0100104#endif /* CONFIG_KM_FPGA_FORCE_CONFIG */
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +0000105
Holger Brunck55b3c6c2020-01-13 15:34:01 +0100106static int skip;
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +0000107
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000108int trigger_fpga_config(void)
109{
110 int ret = 0;
111
Holger Brunck55b3c6c2020-01-13 15:34:01 +0100112 skip = 0;
113#ifndef CONFIG_KM_FPGA_FORCE_CONFIG
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +0000114 /* if the FPGA is already configured, we do not want to
115 * reconfigure it */
116 skip = 0;
117 if (fpga_done()) {
118 printf("PCIe FPGA config: skipped\n");
119 skip = 1;
120 return 0;
121 }
Holger Brunck55b3c6c2020-01-13 15:34:01 +0100122#endif /* CONFIG_KM_FPGA_FORCE_CONFIG */
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +0000123
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000124 if (check_boco2()) {
125 /* we have a BOCO2, this has to be triggered here */
126
127 /* make sure the FPGA_can access the EEPROM */
128 ret = boco_clear_bits(SPI_REG, CFG_EEPROM);
129 if (ret)
130 return ret;
131
132 /* trigger the config start */
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +0000133 ret = boco_clear_bits(SPI_REG, FPGA_PROG | FPGA_INIT_B);
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000134 if (ret)
135 return ret;
136
137 /* small delay for the pulse */
138 udelay(10);
139
140 /* up signal for pulse end */
141 ret = boco_set_bits(SPI_REG, FPGA_PROG);
142 if (ret)
143 return ret;
144
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +0000145 /* finally, raise INIT_B to remove the config delay */
146 ret = boco_set_bits(SPI_REG, FPGA_INIT_B);
147 if (ret)
148 return ret;
149
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000150 } else {
151 /* we do it the old way, with the gpio pin */
152 kw_gpio_set_valid(KM_XLX_PROGRAM_B_PIN, 1);
153 kw_gpio_direction_output(KM_XLX_PROGRAM_B_PIN, 0);
154 /* small delay for the pulse */
155 udelay(10);
156 kw_gpio_direction_input(KM_XLX_PROGRAM_B_PIN);
157 }
158
159 return 0;
160}
161
162int wait_for_fpga_config(void)
163{
164 int ret = 0;
165 u8 spictrl;
166 u32 timeout = 20000;
167
Valentin Longchampa5dcdbb2012-07-05 05:05:08 +0000168 if (skip)
169 return 0;
170
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000171 if (!check_boco2()) {
172 /* we do not have BOCO2, this is not really used */
173 return 0;
174 }
175
176 printf("PCIe FPGA config:");
177 do {
178 ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &spictrl, 1);
179 if (ret) {
180 printf("%s: error reading the BOCO spictrl !!\n",
181 __func__);
182 return ret;
183 }
184 if (timeout-- == 0) {
185 printf(" FPGA_DONE timeout\n");
186 return -EFAULT;
187 }
188 udelay(10);
189 } while (!(spictrl & FPGA_DONE));
190
191 printf(" done\n");
192
193 return 0;
194}
195
Holger Brunck55b3c6c2020-01-13 15:34:01 +0100196#if defined(CONFIG_KM_FPGA_NO_RESET)
197int fpga_reset(void)
198{
199 /* no dedicated reset pin for FPGA */
200 return 0;
201}
Gerlando Falauto29ff59a2014-02-13 16:43:00 +0100202#else
203
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000204#define PRST1 0x4
Valentin Longchamp4e80d1c2012-07-05 05:05:09 +0000205#define PCIE_RST 0x10
206#define TRAFFIC_RST 0x04
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000207
208int fpga_reset(void)
209{
210 int ret = 0;
Valentin Longchamp4e80d1c2012-07-05 05:05:09 +0000211 u8 resets;
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000212
213 if (!check_boco2()) {
214 /* we do not have BOCO2, this is not really used */
215 return 0;
216 }
217
Valentin Longchamp4e80d1c2012-07-05 05:05:09 +0000218 /* if we have skipped, we only want to reset the PCIe part */
219 resets = skip ? PCIE_RST : PCIE_RST | TRAFFIC_RST;
220
221 ret = boco_clear_bits(PRST1, resets);
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000222 if (ret)
223 return ret;
224
225 /* small delay for the pulse */
226 udelay(10);
227
Valentin Longchamp4e80d1c2012-07-05 05:05:09 +0000228 ret = boco_set_bits(PRST1, resets);
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000229 if (ret)
230 return ret;
231
232 return 0;
233}
Gerlando Falauto29ff59a2014-02-13 16:43:00 +0100234#endif
Valentin Longchamp6633fed2012-07-05 05:05:05 +0000235
236/* the FPGA was configured, we configure the BOCO2 so that the EEPROM
237 * is available from the Bobcat SPI bus */
238int toggle_eeprom_spi_bus(void)
239{
240 int ret = 0;
241
242 if (!check_boco2()) {
243 /* we do not have BOCO2, this is not really used */
244 return 0;
245 }
246
247 ret = boco_set_bits(SPI_REG, CFG_EEPROM);
248 if (ret)
249 return ret;
250
251 return 0;
252}