1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Faraday FTPCI100 PCI Bridge Controller Device Driver Implementation
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2011 Andes Technology Corporation
5*4882a593Smuzhiyun * Gavin Guo, Andes Technology Corporation <gavinguo@andestech.com>
6*4882a593Smuzhiyun * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <malloc.h>
12*4882a593Smuzhiyun #include <pci.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <faraday/ftpci100.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <asm/io.h>
17*4882a593Smuzhiyun #include <asm/types.h> /* u32, u16.... used by pci.h */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun struct ftpci100_data {
20*4882a593Smuzhiyun unsigned int reg_base;
21*4882a593Smuzhiyun unsigned int io_base;
22*4882a593Smuzhiyun unsigned int mem_base;
23*4882a593Smuzhiyun unsigned int mmio_base;
24*4882a593Smuzhiyun unsigned int ndevs;
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun static struct pci_config devs[FTPCI100_MAX_FUNCTIONS];
28*4882a593Smuzhiyun static struct pci_controller local_hose;
29*4882a593Smuzhiyun
setup_pci_bar(unsigned int bus,unsigned int dev,unsigned func,unsigned char header,struct ftpci100_data * priv)30*4882a593Smuzhiyun static void setup_pci_bar(unsigned int bus, unsigned int dev, unsigned func,
31*4882a593Smuzhiyun unsigned char header, struct ftpci100_data *priv)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun struct pci_controller *hose = (struct pci_controller *)&local_hose;
34*4882a593Smuzhiyun unsigned int i, tmp32, bar_no, iovsmem = 1;
35*4882a593Smuzhiyun pci_dev_t dev_nu;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* A device is present, add an entry to the array */
38*4882a593Smuzhiyun devs[priv->ndevs].bus = bus;
39*4882a593Smuzhiyun devs[priv->ndevs].dev = dev;
40*4882a593Smuzhiyun devs[priv->ndevs].func = func;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun dev_nu = PCI_BDF(bus, dev, func);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun if ((header & 0x7f) == 0x01)
45*4882a593Smuzhiyun /* PCI-PCI Bridge */
46*4882a593Smuzhiyun bar_no = 2;
47*4882a593Smuzhiyun else
48*4882a593Smuzhiyun bar_no = 6;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* Allocate address spaces by configuring BARs */
51*4882a593Smuzhiyun for (i = 0; i < bar_no; i++) {
52*4882a593Smuzhiyun pci_hose_write_config_dword(hose, dev_nu,
53*4882a593Smuzhiyun PCI_BASE_ADDRESS_0 + i * 4, 0xffffffff);
54*4882a593Smuzhiyun pci_hose_read_config_dword(hose, dev_nu,
55*4882a593Smuzhiyun PCI_BASE_ADDRESS_0 + i * 4, &tmp32);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun if (tmp32 == 0x0)
58*4882a593Smuzhiyun continue;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* IO space */
61*4882a593Smuzhiyun if (tmp32 & 0x1) {
62*4882a593Smuzhiyun iovsmem = 0;
63*4882a593Smuzhiyun unsigned int size_mask = ~(tmp32 & 0xfffffffc);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (priv->io_base & size_mask)
66*4882a593Smuzhiyun priv->io_base = (priv->io_base & ~size_mask) + \
67*4882a593Smuzhiyun size_mask + 1;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun devs[priv->ndevs].bar[i].addr = priv->io_base;
70*4882a593Smuzhiyun devs[priv->ndevs].bar[i].size = size_mask + 1;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun pci_hose_write_config_dword(hose, dev_nu,
73*4882a593Smuzhiyun PCI_BASE_ADDRESS_0 + i * 4,
74*4882a593Smuzhiyun priv->io_base);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun debug("Allocated IO address 0x%X-" \
77*4882a593Smuzhiyun "0x%X for Bus %d, Device %d, Function %d\n",
78*4882a593Smuzhiyun priv->io_base,
79*4882a593Smuzhiyun priv->io_base + size_mask, bus, dev, func);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun priv->io_base += size_mask + 1;
82*4882a593Smuzhiyun } else {
83*4882a593Smuzhiyun /* Memory space */
84*4882a593Smuzhiyun unsigned int is_64bit = ((tmp32 & 0x6) == 0x4);
85*4882a593Smuzhiyun unsigned int is_pref = tmp32 & 0x8;
86*4882a593Smuzhiyun unsigned int size_mask = ~(tmp32 & 0xfffffff0);
87*4882a593Smuzhiyun unsigned int alloc_base;
88*4882a593Smuzhiyun unsigned int *addr_mem_base;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (is_pref)
91*4882a593Smuzhiyun addr_mem_base = &priv->mem_base;
92*4882a593Smuzhiyun else
93*4882a593Smuzhiyun addr_mem_base = &priv->mmio_base;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun alloc_base = *addr_mem_base;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if (alloc_base & size_mask)
98*4882a593Smuzhiyun alloc_base = (alloc_base & ~size_mask) \
99*4882a593Smuzhiyun + size_mask + 1;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun pci_hose_write_config_dword(hose, dev_nu,
102*4882a593Smuzhiyun PCI_BASE_ADDRESS_0 + i * 4, alloc_base);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun debug("Allocated %s address 0x%X-" \
105*4882a593Smuzhiyun "0x%X for Bus %d, Device %d, Function %d\n",
106*4882a593Smuzhiyun is_pref ? "MEM" : "MMIO", alloc_base,
107*4882a593Smuzhiyun alloc_base + size_mask, bus, dev, func);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun devs[priv->ndevs].bar[i].addr = alloc_base;
110*4882a593Smuzhiyun devs[priv->ndevs].bar[i].size = size_mask + 1;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun debug("BAR address BAR size\n");
113*4882a593Smuzhiyun debug("%010x %08d\n",
114*4882a593Smuzhiyun devs[priv->ndevs].bar[0].addr,
115*4882a593Smuzhiyun devs[priv->ndevs].bar[0].size);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun alloc_base += size_mask + 1;
118*4882a593Smuzhiyun *addr_mem_base = alloc_base;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (is_64bit) {
121*4882a593Smuzhiyun i++;
122*4882a593Smuzhiyun pci_hose_write_config_dword(hose, dev_nu,
123*4882a593Smuzhiyun PCI_BASE_ADDRESS_0 + i * 4, 0x0);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* Enable Bus Master, Memory Space, and IO Space */
129*4882a593Smuzhiyun pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32);
130*4882a593Smuzhiyun pci_hose_write_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, 0x08);
131*4882a593Smuzhiyun pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun pci_hose_read_config_dword(hose, dev_nu, PCI_COMMAND, &tmp32);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun tmp32 &= 0xffff;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (iovsmem == 0)
138*4882a593Smuzhiyun tmp32 |= 0x5;
139*4882a593Smuzhiyun else
140*4882a593Smuzhiyun tmp32 |= 0x6;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun pci_hose_write_config_dword(hose, dev_nu, PCI_COMMAND, tmp32);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
pci_bus_scan(struct ftpci100_data * priv)145*4882a593Smuzhiyun static void pci_bus_scan(struct ftpci100_data *priv)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun struct pci_controller *hose = (struct pci_controller *)&local_hose;
148*4882a593Smuzhiyun unsigned int bus, dev, func;
149*4882a593Smuzhiyun pci_dev_t dev_nu;
150*4882a593Smuzhiyun unsigned int data32;
151*4882a593Smuzhiyun unsigned int tmp;
152*4882a593Smuzhiyun unsigned char header;
153*4882a593Smuzhiyun unsigned char int_pin;
154*4882a593Smuzhiyun unsigned int niobars;
155*4882a593Smuzhiyun unsigned int nmbars;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun priv->ndevs = 1;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun nmbars = 0;
160*4882a593Smuzhiyun niobars = 0;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun for (bus = 0; bus < MAX_BUS_NUM; bus++)
163*4882a593Smuzhiyun for (dev = 0; dev < MAX_DEV_NUM; dev++)
164*4882a593Smuzhiyun for (func = 0; func < MAX_FUN_NUM; func++) {
165*4882a593Smuzhiyun dev_nu = PCI_BDF(bus, dev, func);
166*4882a593Smuzhiyun pci_hose_read_config_dword(hose, dev_nu,
167*4882a593Smuzhiyun PCI_VENDOR_ID, &data32);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /*
170*4882a593Smuzhiyun * some broken boards return 0 or ~0,
171*4882a593Smuzhiyun * if a slot is empty.
172*4882a593Smuzhiyun */
173*4882a593Smuzhiyun if (data32 == 0xffffffff ||
174*4882a593Smuzhiyun data32 == 0x00000000 ||
175*4882a593Smuzhiyun data32 == 0x0000ffff ||
176*4882a593Smuzhiyun data32 == 0xffff0000)
177*4882a593Smuzhiyun continue;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun pci_hose_read_config_dword(hose, dev_nu,
180*4882a593Smuzhiyun PCI_HEADER_TYPE, &tmp);
181*4882a593Smuzhiyun header = (unsigned char)tmp;
182*4882a593Smuzhiyun setup_pci_bar(bus, dev, func, header, priv);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun devs[priv->ndevs].v_id = (u16)(data32 & \
185*4882a593Smuzhiyun 0x0000ffff);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun devs[priv->ndevs].d_id = (u16)((data32 & \
188*4882a593Smuzhiyun 0xffff0000) >> 16);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /* Figure out what INTX# line the card uses */
191*4882a593Smuzhiyun pci_hose_read_config_byte(hose, dev_nu,
192*4882a593Smuzhiyun PCI_INTERRUPT_PIN, &int_pin);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* assign the appropriate irq line */
195*4882a593Smuzhiyun if (int_pin > PCI_IRQ_LINES) {
196*4882a593Smuzhiyun printf("more irq lines than expect\n");
197*4882a593Smuzhiyun } else if (int_pin != 0) {
198*4882a593Smuzhiyun /* This device uses an interrupt line */
199*4882a593Smuzhiyun devs[priv->ndevs].pin = int_pin;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun pci_hose_read_config_dword(hose, dev_nu,
203*4882a593Smuzhiyun PCI_CLASS_DEVICE, &data32);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun debug("%06d %03d %03d " \
206*4882a593Smuzhiyun "%04d %08x %08x " \
207*4882a593Smuzhiyun "%03d %08x %06d %08x\n",
208*4882a593Smuzhiyun priv->ndevs, devs[priv->ndevs].bus,
209*4882a593Smuzhiyun devs[priv->ndevs].dev,
210*4882a593Smuzhiyun devs[priv->ndevs].func,
211*4882a593Smuzhiyun devs[priv->ndevs].d_id,
212*4882a593Smuzhiyun devs[priv->ndevs].v_id,
213*4882a593Smuzhiyun devs[priv->ndevs].pin,
214*4882a593Smuzhiyun devs[priv->ndevs].bar[0].addr,
215*4882a593Smuzhiyun devs[priv->ndevs].bar[0].size,
216*4882a593Smuzhiyun data32 >> 8);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun priv->ndevs++;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
ftpci_preinit(struct ftpci100_data * priv)222*4882a593Smuzhiyun static void ftpci_preinit(struct ftpci100_data *priv)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun struct ftpci100_ahbc *ftpci100;
225*4882a593Smuzhiyun struct pci_controller *hose = (struct pci_controller *)&local_hose;
226*4882a593Smuzhiyun u32 pci_config_addr;
227*4882a593Smuzhiyun u32 pci_config_data;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun priv->reg_base = CONFIG_FTPCI100_BASE;
230*4882a593Smuzhiyun priv->io_base = CONFIG_FTPCI100_BASE + CONFIG_FTPCI100_IO_SIZE;
231*4882a593Smuzhiyun priv->mmio_base = CONFIG_FTPCI100_MEM_BASE;
232*4882a593Smuzhiyun priv->mem_base = CONFIG_FTPCI100_MEM_BASE + CONFIG_FTPCI100_MEM_SIZE;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun ftpci100 = (struct ftpci100_ahbc *)priv->reg_base;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun pci_config_addr = (u32) &ftpci100->conf;
237*4882a593Smuzhiyun pci_config_data = (u32) &ftpci100->data;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* print device name */
240*4882a593Smuzhiyun printf("FTPCI100\n");
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* dump basic configuration */
243*4882a593Smuzhiyun debug("%s: Config addr is %08X, data port is %08X\n",
244*4882a593Smuzhiyun __func__, pci_config_addr, pci_config_data);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* PCI memory space */
247*4882a593Smuzhiyun pci_set_region(hose->regions + 0,
248*4882a593Smuzhiyun CONFIG_PCI_MEM_BUS,
249*4882a593Smuzhiyun CONFIG_PCI_MEM_PHYS,
250*4882a593Smuzhiyun CONFIG_PCI_MEM_SIZE,
251*4882a593Smuzhiyun PCI_REGION_MEM);
252*4882a593Smuzhiyun hose->region_count++;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* PCI IO space */
255*4882a593Smuzhiyun pci_set_region(hose->regions + 1,
256*4882a593Smuzhiyun CONFIG_PCI_IO_BUS,
257*4882a593Smuzhiyun CONFIG_PCI_IO_PHYS,
258*4882a593Smuzhiyun CONFIG_PCI_IO_SIZE,
259*4882a593Smuzhiyun PCI_REGION_IO);
260*4882a593Smuzhiyun hose->region_count++;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun #if defined(CONFIG_PCI_SYS_BUS)
263*4882a593Smuzhiyun /* PCI System Memory space */
264*4882a593Smuzhiyun pci_set_region(hose->regions + 2,
265*4882a593Smuzhiyun CONFIG_PCI_SYS_BUS,
266*4882a593Smuzhiyun CONFIG_PCI_SYS_PHYS,
267*4882a593Smuzhiyun CONFIG_PCI_SYS_SIZE,
268*4882a593Smuzhiyun PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
269*4882a593Smuzhiyun hose->region_count++;
270*4882a593Smuzhiyun #endif
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* setup indirect read/write function */
273*4882a593Smuzhiyun pci_setup_indirect(hose, pci_config_addr, pci_config_data);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /* register hose */
276*4882a593Smuzhiyun pci_register_hose(hose);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
pci_ftpci_init(void)279*4882a593Smuzhiyun void pci_ftpci_init(void)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun struct ftpci100_data *priv = NULL;
282*4882a593Smuzhiyun struct pci_controller *hose = (struct pci_controller *)&local_hose;
283*4882a593Smuzhiyun pci_dev_t bridge_num;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun struct pci_device_id bridge_ids[] = {
286*4882a593Smuzhiyun {FTPCI100_BRIDGE_VENDORID, FTPCI100_BRIDGE_DEVICEID},
287*4882a593Smuzhiyun {0, 0}
288*4882a593Smuzhiyun };
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun priv = malloc(sizeof(struct ftpci100_data));
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun if (!priv) {
293*4882a593Smuzhiyun printf("%s(): failed to malloc priv\n", __func__);
294*4882a593Smuzhiyun return;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun memset(priv, 0, sizeof(struct ftpci100_data));
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun ftpci_preinit(priv);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun debug("Device bus dev func deviceID vendorID pin address" \
302*4882a593Smuzhiyun " size class\n");
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun pci_bus_scan(priv);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /*
307*4882a593Smuzhiyun * Setup the PCI Bridge Window to 1GB,
308*4882a593Smuzhiyun * it will cause USB OHCI Host controller Unrecoverable Error
309*4882a593Smuzhiyun * if it is not set.
310*4882a593Smuzhiyun */
311*4882a593Smuzhiyun bridge_num = pci_find_devices(bridge_ids, 0);
312*4882a593Smuzhiyun if (bridge_num == -1) {
313*4882a593Smuzhiyun printf("PCI Bridge not found\n");
314*4882a593Smuzhiyun return;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun pci_hose_write_config_dword(hose, bridge_num, PCI_MEM_BASE_SIZE1,
317*4882a593Smuzhiyun FTPCI100_BASE_ADR_SIZE(1024));
318*4882a593Smuzhiyun }
319