blob: d71fda28464a92c56d90f89e041c3e77253af370 [file] [log] [blame]
wdenk26c58432005-01-09 17:12:27 +00001/*
2 * IXP PCI Init
Michael Schwingenb9de2fa2011-05-23 00:00:12 +02003 *
4 * (C) Copyright 2011
5 * Michael Schwingen, michael@schwingen.org
wdenk26c58432005-01-09 17:12:27 +00006 * (C) Copyright 2004 eslab.whut.edu.cn
7 * Yue Hu(huyue_whut@yahoo.com.cn), Ligong Xue(lgxue@hotmail.com)
8 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02009 * SPDX-License-Identifier: GPL-2.0+
wdenk26c58432005-01-09 17:12:27 +000010 */
11
wdenk26c58432005-01-09 17:12:27 +000012#include <common.h>
wdenk26c58432005-01-09 17:12:27 +000013#include <asm/processor.h>
14#include <asm/io.h>
15#include <pci.h>
16#include <asm/arch/ixp425.h>
17#include <asm/arch/ixp425pci.h>
18
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020019DECLARE_GLOBAL_DATA_PTR;
20
21static void non_prefetch_read(unsigned int addr, unsigned int cmd,
22 unsigned int *data);
23static void non_prefetch_write(unsigned int addr, unsigned int cmd,
24 unsigned int data);
25
26/*define the sub vendor and subsystem to be used */
27#define IXP425_PCI_SUB_VENDOR_SYSTEM 0x00000000
wdenk26c58432005-01-09 17:12:27 +000028
29#define PCI_MEMORY_BUS 0x00000000
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020030#define PCI_MEMORY_PHY 0x00000000
wdenk26c58432005-01-09 17:12:27 +000031#define PCI_MEMORY_SIZE 0x04000000
32
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020033#define PCI_MEM_BUS 0x48000000
wdenk26c58432005-01-09 17:12:27 +000034#define PCI_MEM_PHY 0x00000000
35#define PCI_MEM_SIZE 0x04000000
36
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020037#define PCI_IO_BUS 0x00000000
38#define PCI_IO_PHY 0x00000000
39#define PCI_IO_SIZE 0x00010000
40
41/* build address value for config sycle */
42static unsigned int pci_config_addr(pci_dev_t bdf, unsigned int reg)
43{
44 unsigned int bus = PCI_BUS(bdf);
45 unsigned int dev = PCI_DEV(bdf);
46 unsigned int func = PCI_FUNC(bdf);
47 unsigned int addr;
48
49 if (bus) { /* secondary bus, use type 1 config cycle */
50 addr = bdf | (reg & ~3) | 1;
51 } else {
52 /*
53 primary bus, type 0 config cycle. address bits 31:28
54 specify the device 10:8 specify the function
55 */
56 addr = BIT((31 - dev)) | (func << 8) | (reg & ~3);
57 }
58
59 return addr;
60}
wdenk26c58432005-01-09 17:12:27 +000061
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020062static int pci_config_status(void)
63{
64 unsigned int regval;
wdenk26c58432005-01-09 17:12:27 +000065
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020066 regval = readl(PCI_CSR_BASE + PCI_ISR_OFFSET);
67 if ((regval & PCI_ISR_PFE) == 0)
68 return OK;
wdenk26c58432005-01-09 17:12:27 +000069
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020070 /* no device present, make sure that the master abort bit is reset */
71 writel(PCI_ISR_PFE, PCI_CSR_BASE + PCI_ISR_OFFSET);
72 return ERROR;
73}
74
75static int pci_ixp_hose_read_config_dword(struct pci_controller *hose,
76 pci_dev_t bdf, int where, unsigned int *val)
wdenk26c58432005-01-09 17:12:27 +000077{
78 unsigned int retval;
79 unsigned int addr;
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020080 int stat;
wdenk26c58432005-01-09 17:12:27 +000081
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020082 debug("pci_ixp_hose_read_config_dword: bdf %x, reg %x", bdf, where);
wdenk26c58432005-01-09 17:12:27 +000083 /*Set the address to be read */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020084 addr = pci_config_addr(bdf, where);
85 non_prefetch_read(addr, NP_CMD_CONFIGREAD, &retval);
wdenk26c58432005-01-09 17:12:27 +000086 *val = retval;
87
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020088 stat = pci_config_status();
89 if (stat < 0)
90 *val = -1;
91 debug("-> val %x, status %x\n", *val, stat);
92 return stat;
wdenk26c58432005-01-09 17:12:27 +000093}
94
Michael Schwingenb9de2fa2011-05-23 00:00:12 +020095static int pci_ixp_hose_read_config_word(struct pci_controller *hose,
96 pci_dev_t bdf, int where, unsigned short *val)
wdenk26c58432005-01-09 17:12:27 +000097{
98 unsigned int n;
99 unsigned int retval;
100 unsigned int addr;
101 unsigned int byteEnables;
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200102 int stat;
wdenk26c58432005-01-09 17:12:27 +0000103
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200104 debug("pci_ixp_hose_read_config_word: bdf %x, reg %x", bdf, where);
wdenk26c58432005-01-09 17:12:27 +0000105 n = where % 4;
106 /*byte enables are 4 bits active low, the position of each
107 bit maps to the byte that it enables */
108 byteEnables =
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200109 (~(BIT(n) | BIT((n + 1)))) &
wdenk26c58432005-01-09 17:12:27 +0000110 IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
111 byteEnables = byteEnables << PCI_NP_CBE_BESL;
wdenk26c58432005-01-09 17:12:27 +0000112 /*Set the address to be read */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200113 addr = pci_config_addr(bdf, where);
114 non_prefetch_read(addr, byteEnables | NP_CMD_CONFIGREAD, &retval);
wdenk26c58432005-01-09 17:12:27 +0000115
116 /*Pick out the word we are interested in */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200117 *val = retval >> (8 * n);
wdenk26c58432005-01-09 17:12:27 +0000118
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200119 stat = pci_config_status();
120 if (stat < 0)
121 *val = -1;
122 debug("-> val %x, status %x\n", *val, stat);
123 return stat;
wdenk26c58432005-01-09 17:12:27 +0000124}
125
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200126static int pci_ixp_hose_read_config_byte(struct pci_controller *hose,
127 pci_dev_t bdf, int where, unsigned char *val)
wdenk26c58432005-01-09 17:12:27 +0000128{
129 unsigned int retval;
130 unsigned int n;
131 unsigned int byteEnables;
132 unsigned int addr;
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200133 int stat;
wdenk26c58432005-01-09 17:12:27 +0000134
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200135 debug("pci_ixp_hose_read_config_byte: bdf %x, reg %x", bdf, where);
wdenk26c58432005-01-09 17:12:27 +0000136 n = where % 4;
137 /*byte enables are 4 bits, active low, the position of each
138 bit maps to the byte that it enables */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200139 byteEnables = (~BIT(n)) & IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
wdenk26c58432005-01-09 17:12:27 +0000140 byteEnables = byteEnables << PCI_NP_CBE_BESL;
141
wdenk26c58432005-01-09 17:12:27 +0000142 /*Set the address to be read */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200143 addr = pci_config_addr(bdf, where);
144 non_prefetch_read(addr, byteEnables | NP_CMD_CONFIGREAD, &retval);
wdenk26c58432005-01-09 17:12:27 +0000145 /*Pick out the byte we are interested in */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200146 *val = retval >> (8 * n);
wdenk26c58432005-01-09 17:12:27 +0000147
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200148 stat = pci_config_status();
149 if (stat < 0)
150 *val = -1;
151 debug("-> val %x, status %x\n", *val, stat);
152 return stat;
wdenk26c58432005-01-09 17:12:27 +0000153}
154
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200155static int pci_ixp_hose_write_config_byte(struct pci_controller *hose,
156 pci_dev_t bdf, int where, unsigned char val)
wdenk26c58432005-01-09 17:12:27 +0000157{
158 unsigned int addr;
159 unsigned int byteEnables;
160 unsigned int n;
161 unsigned int ldata;
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200162 int stat;
wdenk26c58432005-01-09 17:12:27 +0000163
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200164 debug("pci_ixp_hose_write_config_byte: bdf %x, reg %x, val %x",
165 bdf, where, val);
wdenk26c58432005-01-09 17:12:27 +0000166 n = where % 4;
167 /*byte enables are 4 bits active low, the position of each
168 bit maps to the byte that it enables */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200169 byteEnables = (~BIT(n)) & IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
wdenk26c58432005-01-09 17:12:27 +0000170 byteEnables = byteEnables << PCI_NP_CBE_BESL;
171 ldata = val << (8 * n);
wdenk26c58432005-01-09 17:12:27 +0000172 /*Set the address to be written */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200173 addr = pci_config_addr(bdf, where);
174 non_prefetch_write(addr, byteEnables | NP_CMD_CONFIGWRITE, ldata);
wdenk26c58432005-01-09 17:12:27 +0000175
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200176 stat = pci_config_status();
177 debug("-> status %x\n", stat);
178 return stat;
wdenk26c58432005-01-09 17:12:27 +0000179}
180
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200181static int pci_ixp_hose_write_config_word(struct pci_controller *hose,
182 pci_dev_t bdf, int where, unsigned short val)
wdenk26c58432005-01-09 17:12:27 +0000183{
184 unsigned int addr;
185 unsigned int byteEnables;
186 unsigned int n;
187 unsigned int ldata;
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200188 int stat;
wdenk26c58432005-01-09 17:12:27 +0000189
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200190 debug("pci_ixp_hose_write_config_word: bdf %x, reg %x, val %x",
191 bdf, where, val);
wdenk26c58432005-01-09 17:12:27 +0000192 n = where % 4;
193 /*byte enables are 4 bits active low, the position of each
194 bit maps to the byte that it enables */
195 byteEnables =
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200196 (~(BIT(n) | BIT((n + 1)))) &
wdenk26c58432005-01-09 17:12:27 +0000197 IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
198 byteEnables = byteEnables << PCI_NP_CBE_BESL;
199 ldata = val << (8 * n);
wdenk26c58432005-01-09 17:12:27 +0000200 /*Set the address to be written */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200201 addr = pci_config_addr(bdf, where);
202 non_prefetch_write(addr, byteEnables | NP_CMD_CONFIGWRITE, ldata);
wdenk26c58432005-01-09 17:12:27 +0000203
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200204 stat = pci_config_status();
205 debug("-> status %x\n", stat);
206 return stat;
wdenk26c58432005-01-09 17:12:27 +0000207}
208
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200209static int pci_ixp_hose_write_config_dword(struct pci_controller *hose,
210 pci_dev_t bdf, int where, unsigned int val)
wdenk26c58432005-01-09 17:12:27 +0000211{
212 unsigned int addr;
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200213 int stat;
wdenk26c58432005-01-09 17:12:27 +0000214
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200215 debug("pci_ixp_hose_write_config_dword: bdf %x, reg %x, val %x",
216 bdf, where, val);
wdenk26c58432005-01-09 17:12:27 +0000217 /*Set the address to be written */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200218 addr = pci_config_addr(bdf, where);
219 non_prefetch_write(addr, NP_CMD_CONFIGWRITE, val);
wdenk26c58432005-01-09 17:12:27 +0000220
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200221 stat = pci_config_status();
222 debug("-> status %x\n", stat);
223 return stat;
wdenk26c58432005-01-09 17:12:27 +0000224}
225
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200226static void non_prefetch_read(unsigned int addr,
227 unsigned int cmd, unsigned int *data)
wdenk26c58432005-01-09 17:12:27 +0000228{
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200229 writel(addr, PCI_CSR_BASE + PCI_NP_AD_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000230
231 /*set up and execute the read */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200232 writel(cmd, PCI_CSR_BASE + PCI_NP_CBE_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000233
234 /*The result of the read is now in np_rdata */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200235 *data = readl(PCI_CSR_BASE + PCI_NP_RDATA_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000236
237 return;
238}
239
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200240static void non_prefetch_write(unsigned int addr,
241 unsigned int cmd, unsigned int data)
wdenk26c58432005-01-09 17:12:27 +0000242{
243
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200244 writel(addr, PCI_CSR_BASE + PCI_NP_AD_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000245 /*set up the write */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200246 writel(cmd, PCI_CSR_BASE + PCI_NP_CBE_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000247 /*Execute the write by writing to NP_WDATA */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200248 writel(data, PCI_CSR_BASE + PCI_NP_WDATA_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000249
250 return;
251}
252
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200253static void crp_write(unsigned int offset, unsigned int data)
wdenk26c58432005-01-09 17:12:27 +0000254{
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200255 /*
256 * The CRP address register bit 16 indicates that we want to do a
257 * write
258 */
259 writel(PCI_CRP_WRITE | offset, PCI_CSR_BASE + PCI_CRP_AD_CBE_OFFSET);
260 writel(data, PCI_CSR_BASE + PCI_CRP_WDATA_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000261}
262
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200263void pci_ixp_init(struct pci_controller *hose)
wdenk26c58432005-01-09 17:12:27 +0000264{
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200265 unsigned int csr;
wdenk26c58432005-01-09 17:12:27 +0000266
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200267 /*
268 * Specify that the AHB bus is operating in big endian mode. Set up
269 * byte lane swapping between little-endian PCI and the big-endian
270 * AHB bus
271 */
272#ifdef __ARMEB__
273 csr = PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS;
274#else
275 csr = PCI_CSR_ABE;
wdenk26c58432005-01-09 17:12:27 +0000276#endif
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200277 writel(csr, PCI_CSR_BASE + PCI_CSR_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000278
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200279 writel(0, PCI_CSR_BASE + PCI_INTEN_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000280
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200281 /*
282 * We configure the PCI inbound memory windows to be
283 * 1:1 mapped to SDRAM
284 */
285 crp_write(PCI_CFG_BASE_ADDRESS_0, 0x00000000);
286 crp_write(PCI_CFG_BASE_ADDRESS_1, 0x01000000);
287 crp_write(PCI_CFG_BASE_ADDRESS_2, 0x02000000);
288 crp_write(PCI_CFG_BASE_ADDRESS_3, 0x03000000);
wdenk26c58432005-01-09 17:12:27 +0000289
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200290 /*
291 * Enable CSR window at 64 MiB to allow PCI masters
292 * to continue prefetching past 64 MiB boundary.
293 */
294 crp_write(PCI_CFG_BASE_ADDRESS_4, 0x04000000);
295 /*
296 * Enable the IO window to be way up high, at 0xfffffc00
297 */
298 crp_write(PCI_CFG_BASE_ADDRESS_5, 0xfffffc01);
wdenk26c58432005-01-09 17:12:27 +0000299
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200300 /*Setup PCI-AHB and AHB-PCI address mappings */
301 writel(0x00010203, PCI_CSR_BASE + PCI_AHBMEMBASE_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000302
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200303 writel(0x00000000, PCI_CSR_BASE + PCI_AHBIOBASE_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000304
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200305 writel(0x48494a4b, PCI_CSR_BASE + PCI_PCIMEMBASE_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000306
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200307 crp_write(PCI_CFG_SUB_VENDOR_ID, IXP425_PCI_SUB_VENDOR_SYSTEM);
wdenk26c58432005-01-09 17:12:27 +0000308
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200309 crp_write(PCI_CFG_COMMAND, PCI_CFG_CMD_MAE | PCI_CFG_CMD_BME);
310 udelay(1000);
wdenk26c58432005-01-09 17:12:27 +0000311
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200312 /* clear error bits in status register */
313 writel(PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE,
314 PCI_CSR_BASE + PCI_ISR_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000315
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200316 /*
317 * Set Initialize Complete in PCI Control Register: allow IXP4XX to
318 * respond to PCI configuration cycles.
wdenk26c58432005-01-09 17:12:27 +0000319 */
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200320 csr |= PCI_CSR_IC;
321 writel(csr, PCI_CSR_BASE + PCI_CSR_OFFSET);
wdenk26c58432005-01-09 17:12:27 +0000322
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200323 hose->first_busno = 0;
324 hose->last_busno = 0;
wdenk26c58432005-01-09 17:12:27 +0000325
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200326 /* System memory space */
327 pci_set_region(hose->regions + 0,
328 PCI_MEMORY_BUS,
329 PCI_MEMORY_PHY, PCI_MEMORY_SIZE, PCI_REGION_SYS_MEMORY);
wdenk26c58432005-01-09 17:12:27 +0000330
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200331 /* PCI memory space */
332 pci_set_region(hose->regions + 1,
333 PCI_MEM_BUS,
334 PCI_MEM_PHY, PCI_MEM_SIZE, PCI_REGION_MEM);
335 /* PCI I/O space */
336 pci_set_region(hose->regions + 2,
337 PCI_IO_BUS, PCI_IO_PHY, PCI_IO_SIZE, PCI_REGION_IO);
wdenk26c58432005-01-09 17:12:27 +0000338
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200339 hose->region_count = 3;
wdenk26c58432005-01-09 17:12:27 +0000340
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200341 pci_set_ops(hose,
342 pci_ixp_hose_read_config_byte,
343 pci_ixp_hose_read_config_word,
344 pci_ixp_hose_read_config_dword,
345 pci_ixp_hose_write_config_byte,
346 pci_ixp_hose_write_config_word,
347 pci_ixp_hose_write_config_dword);
wdenk26c58432005-01-09 17:12:27 +0000348
Michael Schwingenb9de2fa2011-05-23 00:00:12 +0200349 pci_register_hose(hose);
350 hose->last_busno = pci_hose_scan(hose);
wdenk26c58432005-01-09 17:12:27 +0000351}