Import upstream u-boot 1.1.4
[u-boot.git] / board / esd / common / pci.c
1 /*
2  * (C) Copyright 2001
3  * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.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., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <ppc4xx.h>
26 #include <asm/processor.h>
27 #include <pci.h>
28
29
30 u_long pci9054_iobase;
31
32
33 #define PCI_PRIMARY_CAR (0x500000dc) /* PCI config address reg */
34 #define PCI_PRIMARY_CDR (0x80000000) /* PCI config data    reg */
35
36
37 /*-----------------------------------------------------------------------------+
38 |  Subroutine:  pci9054_read_config_dword
39 |  Description: Read a PCI configuration register
40 |  Inputs:
41 |               hose            PCI Controller
42 |               dev             PCI Bus+Device+Function number
43 |               offset          Configuration register number
44 |               value           Address of the configuration register value
45 |  Return value:
46 |               0               Successful
47 +-----------------------------------------------------------------------------*/
48 int pci9054_read_config_dword(struct pci_controller *hose,
49                               pci_dev_t dev, int offset, u32* value)
50 {
51   unsigned long      conAdrVal;
52   unsigned long      val;
53
54   /* generate coded value for CON_ADR register */
55   conAdrVal = dev | (offset & 0xfc) | 0x80000000;
56
57   /* Load the CON_ADR (CAR) value first, then read from CON_DATA (CDR) */
58   *(unsigned long *)PCI_PRIMARY_CAR = conAdrVal;
59
60   /* Note: *pResult comes back as -1 if machine check happened */
61   val = in32r(PCI_PRIMARY_CDR);
62
63   *value = (unsigned long) val;
64
65   out32r(PCI_PRIMARY_CAR, 0);
66
67   if ((*(unsigned long *)0x50000304) & 0x60000000)
68     {
69       /* clear pci master/target abort bits */
70       *(unsigned long *)0x50000304 = *(unsigned long *)0x50000304;
71     }
72
73   return 0;
74 }
75
76 /*-----------------------------------------------------------------------------+
77 |  Subroutine:  pci9054_write_config_dword
78 |  Description: Write a PCI configuration register.
79 |  Inputs:
80 |               hose            PCI Controller
81 |               dev             PCI Bus+Device+Function number
82 |               offset          Configuration register number
83 |               Value           Configuration register value
84 |  Return value:
85 |               0               Successful
86 | Updated for pass2 errata #6. Need to disable interrupts and clear the
87 | PCICFGADR reg after writing the PCICFGDATA reg.
88 +-----------------------------------------------------------------------------*/
89 int pci9054_write_config_dword(struct pci_controller *hose,
90                                pci_dev_t dev, int offset, u32 value)
91 {
92   unsigned long      conAdrVal;
93
94   conAdrVal = dev | (offset & 0xfc) | 0x80000000;
95
96   *(unsigned long *)PCI_PRIMARY_CAR = conAdrVal;
97
98   out32r(PCI_PRIMARY_CDR, value);
99
100   out32r(PCI_PRIMARY_CAR, 0);
101
102   /* clear pci master/target abort bits */
103   *(unsigned long *)0x50000304 = *(unsigned long *)0x50000304;
104
105   return (0);
106 }
107
108 /*-----------------------------------------------------------------------
109  */
110
111 #ifdef CONFIG_DASA_SIM
112 static void pci_dasa_sim_config_pci9054(struct pci_controller *hose, pci_dev_t dev,
113                                         struct pci_config_table *_)
114 {
115   unsigned int iobase;
116   unsigned short status = 0;
117   unsigned char timer;
118
119   /*
120    * Configure PLX PCI9054
121    */
122   pci_read_config_word(CFG_PCI9054_DEV_FN, PCI_COMMAND, &status);
123   status |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
124   pci_write_config_word(CFG_PCI9054_DEV_FN, PCI_COMMAND, status);
125
126   /* Check the latency timer for values >= 0x60.
127    */
128   pci_read_config_byte(CFG_PCI9054_DEV_FN, PCI_LATENCY_TIMER, &timer);
129   if (timer < 0x60)
130     {
131       pci_write_config_byte(CFG_PCI9054_DEV_FN, PCI_LATENCY_TIMER, 0x60);
132     }
133
134   /* Set I/O base register.
135    */
136   pci_write_config_dword(CFG_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, CFG_PCI9054_IOBASE);
137   pci_read_config_dword(CFG_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, &iobase);
138
139   pci9054_iobase = pci_mem_to_phys(CFG_PCI9054_DEV_FN, iobase & PCI_BASE_ADDRESS_MEM_MASK);
140
141   if (pci9054_iobase == 0xffffffff)
142     {
143       printf("Error: Can not set I/O base register.\n");
144       return;
145     }
146 }
147 #endif
148
149 static struct pci_config_table pci9054_config_table[] = {
150 #ifndef CONFIG_PCI_PNP
151   { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
152     PCI_BUS(CFG_ETH_DEV_FN), PCI_DEV(CFG_ETH_DEV_FN), PCI_FUNC(CFG_ETH_DEV_FN),
153     pci_cfgfunc_config_device, { CFG_ETH_IOBASE,
154                                  CFG_ETH_IOBASE,
155                                  PCI_COMMAND_IO | PCI_COMMAND_MASTER }},
156 #ifdef CONFIG_DASA_SIM
157   { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
158     PCI_BUS(CFG_PCI9054_DEV_FN), PCI_DEV(CFG_PCI9054_DEV_FN), PCI_FUNC(CFG_PCI9054_DEV_FN),
159     pci_dasa_sim_config_pci9054 },
160 #endif
161 #endif
162   { }
163 };
164
165 static struct pci_controller pci9054_hose = {
166   config_table: pci9054_config_table,
167 };
168
169 void pci_init_board(void)
170 {
171   struct pci_controller *hose = &pci9054_hose;
172
173   /*
174    * Register the hose
175    */
176   hose->first_busno = 0;
177   hose->last_busno = 0xff;
178
179   /* System memory space */
180   pci_set_region(hose->regions + 0,
181                  0x00000000, 0x00000000, 0x01000000,
182                  PCI_REGION_MEM | PCI_REGION_MEMORY);
183
184   /* PCI Memory space */
185   pci_set_region(hose->regions + 1,
186                  0x00000000, 0xc0000000, 0x10000000,
187                  PCI_REGION_MEM);
188
189   pci_set_ops(hose,
190               pci_hose_read_config_byte_via_dword,
191               pci_hose_read_config_word_via_dword,
192               pci9054_read_config_dword,
193               pci_hose_write_config_byte_via_dword,
194               pci_hose_write_config_word_via_dword,
195               pci9054_write_config_dword);
196
197   hose->region_count = 2;
198
199   pci_register_hose(hose);
200
201   hose->last_busno = pci_hose_scan(hose);
202 }