blob: ddfbea9a08c89f654f352eaf5cfabee7ca242e46 [file] [log] [blame]
wdenk12f34242003-09-02 22:48:03 +00001/*
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
30u_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+-----------------------------------------------------------------------------*/
48int 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+-----------------------------------------------------------------------------*/
89int 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
112static 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 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200122 pci_read_config_word(CONFIG_SYS_PCI9054_DEV_FN, PCI_COMMAND, &status);
wdenk12f34242003-09-02 22:48:03 +0000123 status |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200124 pci_write_config_word(CONFIG_SYS_PCI9054_DEV_FN, PCI_COMMAND, status);
wdenk12f34242003-09-02 22:48:03 +0000125
126 /* Check the latency timer for values >= 0x60.
127 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200128 pci_read_config_byte(CONFIG_SYS_PCI9054_DEV_FN, PCI_LATENCY_TIMER, &timer);
wdenk12f34242003-09-02 22:48:03 +0000129 if (timer < 0x60)
130 {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200131 pci_write_config_byte(CONFIG_SYS_PCI9054_DEV_FN, PCI_LATENCY_TIMER, 0x60);
wdenk12f34242003-09-02 22:48:03 +0000132 }
133
134 /* Set I/O base register.
135 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200136 pci_write_config_dword(CONFIG_SYS_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, CONFIG_SYS_PCI9054_IOBASE);
137 pci_read_config_dword(CONFIG_SYS_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, &iobase);
wdenk12f34242003-09-02 22:48:03 +0000138
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200139 pci9054_iobase = pci_mem_to_phys(CONFIG_SYS_PCI9054_DEV_FN, iobase & PCI_BASE_ADDRESS_MEM_MASK);
wdenk12f34242003-09-02 22:48:03 +0000140
141 if (pci9054_iobase == 0xffffffff)
142 {
143 printf("Error: Can not set I/O base register.\n");
144 return;
145 }
146}
147#endif
148
149static struct pci_config_table pci9054_config_table[] = {
150#ifndef CONFIG_PCI_PNP
151 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200152 PCI_BUS(CONFIG_SYS_ETH_DEV_FN), PCI_DEV(CONFIG_SYS_ETH_DEV_FN), PCI_FUNC(CONFIG_SYS_ETH_DEV_FN),
153 pci_cfgfunc_config_device, { CONFIG_SYS_ETH_IOBASE,
154 CONFIG_SYS_ETH_IOBASE,
wdenk12f34242003-09-02 22:48:03 +0000155 PCI_COMMAND_IO | PCI_COMMAND_MASTER }},
156#ifdef CONFIG_DASA_SIM
157 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200158 PCI_BUS(CONFIG_SYS_PCI9054_DEV_FN), PCI_DEV(CONFIG_SYS_PCI9054_DEV_FN), PCI_FUNC(CONFIG_SYS_PCI9054_DEV_FN),
wdenk12f34242003-09-02 22:48:03 +0000159 pci_dasa_sim_config_pci9054 },
160#endif
161#endif
162 { }
163};
164
165static struct pci_controller pci9054_hose = {
166 config_table: pci9054_config_table,
167};
168
169void pci_init(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,
Kumar Galaff4e66e2009-02-06 09:49:31 -0600182 PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
wdenk12f34242003-09-02 22:48:03 +0000183
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}