blob: 71bc8ac096a1fad72da18d4fae1a835f436c6276 [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 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenk12f34242003-09-02 22:48:03 +00006 */
7
8#include <common.h>
Stefan Roeseb36df562010-09-09 19:18:00 +02009#include <asm/ppc4xx.h>
wdenk12f34242003-09-02 22:48:03 +000010#include <asm/processor.h>
11#include <pci.h>
12
13
14u_long pci9054_iobase;
15
16
17#define PCI_PRIMARY_CAR (0x500000dc) /* PCI config address reg */
18#define PCI_PRIMARY_CDR (0x80000000) /* PCI config data reg */
19
20
21/*-----------------------------------------------------------------------------+
22| Subroutine: pci9054_read_config_dword
23| Description: Read a PCI configuration register
24| Inputs:
25| hose PCI Controller
26| dev PCI Bus+Device+Function number
27| offset Configuration register number
28| value Address of the configuration register value
29| Return value:
30| 0 Successful
31+-----------------------------------------------------------------------------*/
32int pci9054_read_config_dword(struct pci_controller *hose,
33 pci_dev_t dev, int offset, u32* value)
34{
35 unsigned long conAdrVal;
36 unsigned long val;
37
38 /* generate coded value for CON_ADR register */
39 conAdrVal = dev | (offset & 0xfc) | 0x80000000;
40
41 /* Load the CON_ADR (CAR) value first, then read from CON_DATA (CDR) */
42 *(unsigned long *)PCI_PRIMARY_CAR = conAdrVal;
43
44 /* Note: *pResult comes back as -1 if machine check happened */
45 val = in32r(PCI_PRIMARY_CDR);
46
47 *value = (unsigned long) val;
48
49 out32r(PCI_PRIMARY_CAR, 0);
50
51 if ((*(unsigned long *)0x50000304) & 0x60000000)
52 {
53 /* clear pci master/target abort bits */
54 *(unsigned long *)0x50000304 = *(unsigned long *)0x50000304;
55 }
56
57 return 0;
58}
59
60/*-----------------------------------------------------------------------------+
61| Subroutine: pci9054_write_config_dword
62| Description: Write a PCI configuration register.
63| Inputs:
64| hose PCI Controller
65| dev PCI Bus+Device+Function number
66| offset Configuration register number
67| Value Configuration register value
68| Return value:
69| 0 Successful
70| Updated for pass2 errata #6. Need to disable interrupts and clear the
71| PCICFGADR reg after writing the PCICFGDATA reg.
72+-----------------------------------------------------------------------------*/
73int pci9054_write_config_dword(struct pci_controller *hose,
74 pci_dev_t dev, int offset, u32 value)
75{
76 unsigned long conAdrVal;
77
78 conAdrVal = dev | (offset & 0xfc) | 0x80000000;
79
80 *(unsigned long *)PCI_PRIMARY_CAR = conAdrVal;
81
82 out32r(PCI_PRIMARY_CDR, value);
83
84 out32r(PCI_PRIMARY_CAR, 0);
85
86 /* clear pci master/target abort bits */
87 *(unsigned long *)0x50000304 = *(unsigned long *)0x50000304;
88
89 return (0);
90}
91
92/*-----------------------------------------------------------------------
93 */
94
95#ifdef CONFIG_DASA_SIM
96static void pci_dasa_sim_config_pci9054(struct pci_controller *hose, pci_dev_t dev,
97 struct pci_config_table *_)
98{
99 unsigned int iobase;
100 unsigned short status = 0;
101 unsigned char timer;
102
103 /*
104 * Configure PLX PCI9054
105 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200106 pci_read_config_word(CONFIG_SYS_PCI9054_DEV_FN, PCI_COMMAND, &status);
wdenk12f34242003-09-02 22:48:03 +0000107 status |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200108 pci_write_config_word(CONFIG_SYS_PCI9054_DEV_FN, PCI_COMMAND, status);
wdenk12f34242003-09-02 22:48:03 +0000109
110 /* Check the latency timer for values >= 0x60.
111 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200112 pci_read_config_byte(CONFIG_SYS_PCI9054_DEV_FN, PCI_LATENCY_TIMER, &timer);
wdenk12f34242003-09-02 22:48:03 +0000113 if (timer < 0x60)
114 {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200115 pci_write_config_byte(CONFIG_SYS_PCI9054_DEV_FN, PCI_LATENCY_TIMER, 0x60);
wdenk12f34242003-09-02 22:48:03 +0000116 }
117
118 /* Set I/O base register.
119 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200120 pci_write_config_dword(CONFIG_SYS_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, CONFIG_SYS_PCI9054_IOBASE);
121 pci_read_config_dword(CONFIG_SYS_PCI9054_DEV_FN, PCI_BASE_ADDRESS_0, &iobase);
wdenk12f34242003-09-02 22:48:03 +0000122
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200123 pci9054_iobase = pci_mem_to_phys(CONFIG_SYS_PCI9054_DEV_FN, iobase & PCI_BASE_ADDRESS_MEM_MASK);
wdenk12f34242003-09-02 22:48:03 +0000124
125 if (pci9054_iobase == 0xffffffff)
126 {
127 printf("Error: Can not set I/O base register.\n");
128 return;
129 }
130}
131#endif
132
133static struct pci_config_table pci9054_config_table[] = {
134#ifndef CONFIG_PCI_PNP
135 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200136 PCI_BUS(CONFIG_SYS_ETH_DEV_FN), PCI_DEV(CONFIG_SYS_ETH_DEV_FN), PCI_FUNC(CONFIG_SYS_ETH_DEV_FN),
137 pci_cfgfunc_config_device, { CONFIG_SYS_ETH_IOBASE,
138 CONFIG_SYS_ETH_IOBASE,
wdenk12f34242003-09-02 22:48:03 +0000139 PCI_COMMAND_IO | PCI_COMMAND_MASTER }},
140#ifdef CONFIG_DASA_SIM
141 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200142 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 +0000143 pci_dasa_sim_config_pci9054 },
144#endif
145#endif
146 { }
147};
148
149static struct pci_controller pci9054_hose = {
150 config_table: pci9054_config_table,
151};
152
153void pci_init(void)
154{
155 struct pci_controller *hose = &pci9054_hose;
156
157 /*
158 * Register the hose
159 */
160 hose->first_busno = 0;
161 hose->last_busno = 0xff;
162
163 /* System memory space */
164 pci_set_region(hose->regions + 0,
165 0x00000000, 0x00000000, 0x01000000,
Kumar Galaff4e66e2009-02-06 09:49:31 -0600166 PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
wdenk12f34242003-09-02 22:48:03 +0000167
168 /* PCI Memory space */
169 pci_set_region(hose->regions + 1,
170 0x00000000, 0xc0000000, 0x10000000,
171 PCI_REGION_MEM);
172
173 pci_set_ops(hose,
174 pci_hose_read_config_byte_via_dword,
175 pci_hose_read_config_word_via_dword,
176 pci9054_read_config_dword,
177 pci_hose_write_config_byte_via_dword,
178 pci_hose_write_config_word_via_dword,
179 pci9054_write_config_dword);
180
181 hose->region_count = 2;
182
183 pci_register_hose(hose);
184
185 hose->last_busno = pci_hose_scan(hose);
186}