]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/keymile/km_arm/fpga_config.c
Merge branch 'master' of git://git.denx.de/u-boot-microblaze
[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  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301 USA
22  */
23
24 #include <common.h>
25 #include <i2c.h>
26 #include <asm/errno.h>
27
28 /* GPIO Pin from kirkwood connected to PROGRAM_B pin of the xilinx FPGA */
29 #define KM_XLX_PROGRAM_B_PIN    39
30
31 #define BOCO_ADDR       0x10
32
33 #define ID_REG          0x00
34 #define BOCO2_ID        0x5b
35
36 static int check_boco2(void)
37 {
38         int ret;
39         u8 id;
40
41         ret = i2c_read(BOCO_ADDR, ID_REG, 1, &id, 1);
42         if (ret) {
43                 printf("%s: error reading the BOCO id !!\n", __func__);
44                 return ret;
45         }
46
47         return (id == BOCO2_ID);
48 }
49
50 static int boco_clear_bits(u8 reg, u8 flags)
51 {
52         int ret;
53         u8 regval;
54
55         /* give access to the EEPROM from FPGA */
56         ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
57         if (ret) {
58                 printf("%s: error reading the BOCO @%#x !!\n",
59                         __func__, reg);
60                 return ret;
61         }
62         regval &= ~flags;
63         ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
64         if (ret) {
65                 printf("%s: error writing the BOCO @%#x !!\n",
66                         __func__, reg);
67                 return ret;
68         }
69
70         return 0;
71 }
72
73 static int boco_set_bits(u8 reg, u8 flags)
74 {
75         int ret;
76         u8 regval;
77
78         /* give access to the EEPROM from FPGA */
79         ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
80         if (ret) {
81                 printf("%s: error reading the BOCO @%#x !!\n",
82                         __func__, reg);
83                 return ret;
84         }
85         regval |= flags;
86         ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
87         if (ret) {
88                 printf("%s: error writing the BOCO @%#x !!\n",
89                         __func__, reg);
90                 return ret;
91         }
92
93         return 0;
94 }
95
96 #define SPI_REG         0x06
97 #define CFG_EEPROM      0x02
98 #define FPGA_PROG       0x04
99 #define FPGA_INIT_B     0x10
100 #define FPGA_DONE       0x20
101
102 static int fpga_done(void)
103 {
104         int ret = 0;
105         u8 regval;
106
107         /* this is only supported with the boco2 design */
108         if (!check_boco2())
109                 return 0;
110
111         ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &regval, 1);
112         if (ret) {
113                 printf("%s: error reading the BOCO @%#x !!\n",
114                         __func__, SPI_REG);
115                 return 0;
116         }
117
118         return regval & FPGA_DONE ? 1 : 0;
119 }
120
121 int skip;
122
123 int trigger_fpga_config(void)
124 {
125         int ret = 0;
126
127         /* if the FPGA is already configured, we do not want to
128          * reconfigure it */
129         skip = 0;
130         if (fpga_done()) {
131                 printf("PCIe FPGA config: skipped\n");
132                 skip = 1;
133                 return 0;
134         }
135
136         if (check_boco2()) {
137                 /* we have a BOCO2, this has to be triggered here */
138
139                 /* make sure the FPGA_can access the EEPROM */
140                 ret = boco_clear_bits(SPI_REG, CFG_EEPROM);
141                 if (ret)
142                         return ret;
143
144                 /* trigger the config start */
145                 ret = boco_clear_bits(SPI_REG, FPGA_PROG | FPGA_INIT_B);
146                 if (ret)
147                         return ret;
148
149                 /* small delay for the pulse */
150                 udelay(10);
151
152                 /* up signal for pulse end */
153                 ret = boco_set_bits(SPI_REG, FPGA_PROG);
154                 if (ret)
155                         return ret;
156
157                 /* finally, raise INIT_B to remove the config delay */
158                 ret = boco_set_bits(SPI_REG, FPGA_INIT_B);
159                 if (ret)
160                         return ret;
161
162         } else {
163                 /* we do it the old way, with the gpio pin */
164                 kw_gpio_set_valid(KM_XLX_PROGRAM_B_PIN, 1);
165                 kw_gpio_direction_output(KM_XLX_PROGRAM_B_PIN, 0);
166                 /* small delay for the pulse */
167                 udelay(10);
168                 kw_gpio_direction_input(KM_XLX_PROGRAM_B_PIN);
169         }
170
171         return 0;
172 }
173
174 int wait_for_fpga_config(void)
175 {
176         int ret = 0;
177         u8 spictrl;
178         u32 timeout = 20000;
179
180         if (skip)
181                 return 0;
182
183         if (!check_boco2()) {
184                 /* we do not have BOCO2, this is not really used */
185                 return 0;
186         }
187
188         printf("PCIe FPGA config:");
189         do {
190                 ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &spictrl, 1);
191                 if (ret) {
192                         printf("%s: error reading the BOCO spictrl !!\n",
193                                 __func__);
194                         return ret;
195                 }
196                 if (timeout-- == 0) {
197                         printf(" FPGA_DONE timeout\n");
198                         return -EFAULT;
199                 }
200                 udelay(10);
201         } while (!(spictrl & FPGA_DONE));
202
203         printf(" done\n");
204
205         return 0;
206 }
207
208 #define PRST1           0x4
209 #define PCIE_RST        0x10
210 #define TRAFFIC_RST     0x04
211
212 int fpga_reset(void)
213 {
214         int ret = 0;
215         u8 resets;
216
217         if (!check_boco2()) {
218                 /* we do not have BOCO2, this is not really used */
219                 return 0;
220         }
221
222         /* if we have skipped, we only want to reset the PCIe part */
223         resets = skip ? PCIE_RST : PCIE_RST | TRAFFIC_RST;
224
225         ret = boco_clear_bits(PRST1, resets);
226         if (ret)
227                 return ret;
228
229         /* small delay for the pulse */
230         udelay(10);
231
232         ret = boco_set_bits(PRST1, resets);
233         if (ret)
234                 return ret;
235
236         return 0;
237 }
238
239 /* the FPGA was configured, we configure the BOCO2 so that the EEPROM
240  * is available from the Bobcat SPI bus */
241 int toggle_eeprom_spi_bus(void)
242 {
243         int ret = 0;
244
245         if (!check_boco2()) {
246                 /* we do not have BOCO2, this is not really used */
247                 return 0;
248         }
249
250         ret = boco_set_bits(SPI_REG, CFG_EEPROM);
251         if (ret)
252                 return ret;
253
254         return 0;
255 }