]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/keymile/km_arm/fpga_config.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / board / keymile / km_arm / fpga_config.c
1 /*
2  * (C) Copyright 2012
3  * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <i2c.h>
10 #include <asm/errno.h>
11
12 /* GPIO Pin from kirkwood connected to PROGRAM_B pin of the xilinx FPGA */
13 #define KM_XLX_PROGRAM_B_PIN    39
14
15 #define BOCO_ADDR       0x10
16
17 #define ID_REG          0x00
18 #define BOCO2_ID        0x5b
19
20 static int check_boco2(void)
21 {
22         int ret;
23         u8 id;
24
25         ret = i2c_read(BOCO_ADDR, ID_REG, 1, &id, 1);
26         if (ret) {
27                 printf("%s: error reading the BOCO id !!\n", __func__);
28                 return ret;
29         }
30
31         return (id == BOCO2_ID);
32 }
33
34 static int boco_clear_bits(u8 reg, u8 flags)
35 {
36         int ret;
37         u8 regval;
38
39         /* give access to the EEPROM from FPGA */
40         ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
41         if (ret) {
42                 printf("%s: error reading the BOCO @%#x !!\n",
43                         __func__, reg);
44                 return ret;
45         }
46         regval &= ~flags;
47         ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
48         if (ret) {
49                 printf("%s: error writing the BOCO @%#x !!\n",
50                         __func__, reg);
51                 return ret;
52         }
53
54         return 0;
55 }
56
57 static int boco_set_bits(u8 reg, u8 flags)
58 {
59         int ret;
60         u8 regval;
61
62         /* give access to the EEPROM from FPGA */
63         ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
64         if (ret) {
65                 printf("%s: error reading the BOCO @%#x !!\n",
66                         __func__, reg);
67                 return ret;
68         }
69         regval |= flags;
70         ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
71         if (ret) {
72                 printf("%s: error writing the BOCO @%#x !!\n",
73                         __func__, reg);
74                 return ret;
75         }
76
77         return 0;
78 }
79
80 #define SPI_REG         0x06
81 #define CFG_EEPROM      0x02
82 #define FPGA_PROG       0x04
83 #define FPGA_INIT_B     0x10
84 #define FPGA_DONE       0x20
85
86 static int fpga_done(void)
87 {
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 }
104
105 int skip;
106
107 int trigger_fpga_config(void)
108 {
109         int ret = 0;
110
111         /* if the FPGA is already configured, we do not want to
112          * reconfigure it */
113         skip = 0;
114         if (fpga_done()) {
115                 printf("PCIe FPGA config: skipped\n");
116                 skip = 1;
117                 return 0;
118         }
119
120         if (check_boco2()) {
121                 /* we have a BOCO2, this has to be triggered here */
122
123                 /* make sure the FPGA_can access the EEPROM */
124                 ret = boco_clear_bits(SPI_REG, CFG_EEPROM);
125                 if (ret)
126                         return ret;
127
128                 /* trigger the config start */
129                 ret = boco_clear_bits(SPI_REG, FPGA_PROG | FPGA_INIT_B);
130                 if (ret)
131                         return ret;
132
133                 /* small delay for the pulse */
134                 udelay(10);
135
136                 /* up signal for pulse end */
137                 ret = boco_set_bits(SPI_REG, FPGA_PROG);
138                 if (ret)
139                         return ret;
140
141                 /* finally, raise INIT_B to remove the config delay */
142                 ret = boco_set_bits(SPI_REG, FPGA_INIT_B);
143                 if (ret)
144                         return ret;
145
146         } else {
147                 /* we do it the old way, with the gpio pin */
148                 kw_gpio_set_valid(KM_XLX_PROGRAM_B_PIN, 1);
149                 kw_gpio_direction_output(KM_XLX_PROGRAM_B_PIN, 0);
150                 /* small delay for the pulse */
151                 udelay(10);
152                 kw_gpio_direction_input(KM_XLX_PROGRAM_B_PIN);
153         }
154
155         return 0;
156 }
157
158 int wait_for_fpga_config(void)
159 {
160         int ret = 0;
161         u8 spictrl;
162         u32 timeout = 20000;
163
164         if (skip)
165                 return 0;
166
167         if (!check_boco2()) {
168                 /* we do not have BOCO2, this is not really used */
169                 return 0;
170         }
171
172         printf("PCIe FPGA config:");
173         do {
174                 ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &spictrl, 1);
175                 if (ret) {
176                         printf("%s: error reading the BOCO spictrl !!\n",
177                                 __func__);
178                         return ret;
179                 }
180                 if (timeout-- == 0) {
181                         printf(" FPGA_DONE timeout\n");
182                         return -EFAULT;
183                 }
184                 udelay(10);
185         } while (!(spictrl & FPGA_DONE));
186
187         printf(" done\n");
188
189         return 0;
190 }
191
192 #if defined(KM_PCIE_RESET_MPP7)
193
194 #define KM_PEX_RST_GPIO_PIN     7
195 int fpga_reset(void)
196 {
197         if (!check_boco2()) {
198                 /* we do not have BOCO2, this is not really used */
199                 return 0;
200         }
201
202         printf("PCIe reset through GPIO7: ");
203         /* apply PCIe reset via GPIO */
204         kw_gpio_set_valid(KM_PEX_RST_GPIO_PIN, 1);
205         kw_gpio_direction_output(KM_PEX_RST_GPIO_PIN, 1);
206         kw_gpio_set_value(KM_PEX_RST_GPIO_PIN, 0);
207         udelay(1000*10);
208         kw_gpio_set_value(KM_PEX_RST_GPIO_PIN, 1);
209
210         printf(" done\n");
211
212         return 0;
213 }
214
215 #else
216
217 #define PRST1           0x4
218 #define PCIE_RST        0x10
219 #define TRAFFIC_RST     0x04
220
221 int fpga_reset(void)
222 {
223         int ret = 0;
224         u8 resets;
225
226         if (!check_boco2()) {
227                 /* we do not have BOCO2, this is not really used */
228                 return 0;
229         }
230
231         /* if we have skipped, we only want to reset the PCIe part */
232         resets = skip ? PCIE_RST : PCIE_RST | TRAFFIC_RST;
233
234         ret = boco_clear_bits(PRST1, resets);
235         if (ret)
236                 return ret;
237
238         /* small delay for the pulse */
239         udelay(10);
240
241         ret = boco_set_bits(PRST1, resets);
242         if (ret)
243                 return ret;
244
245         return 0;
246 }
247 #endif
248
249 /* the FPGA was configured, we configure the BOCO2 so that the EEPROM
250  * is available from the Bobcat SPI bus */
251 int toggle_eeprom_spi_bus(void)
252 {
253         int ret = 0;
254
255         if (!check_boco2()) {
256                 /* we do not have BOCO2, this is not really used */
257                 return 0;
258         }
259
260         ret = boco_set_bits(SPI_REG, CFG_EEPROM);
261         if (ret)
262                 return ret;
263
264         return 0;
265 }