xref: /OK3568_Linux_fs/u-boot/drivers/pci/pci_ftpci100.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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