• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/mips/brcm-boards/bcm947xx/
1/*
2 * Low-Level PCI and SB support for BCM47xx (Linux support code)
3 *
4 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: pcibios.c,v 1.11 2011-01-10 23:25:05 $
19 */
20
21#include <linux/version.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/sched.h>
25#include <linux/pci.h>
26#include <linux/init.h>
27#include <linux/delay.h>
28#include <asm/io.h>
29#include <asm/irq.h>
30#include <asm/paccess.h>
31#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
32#include <linux/config.h>
33#endif
34
35#include <typedefs.h>
36#include <bcmutils.h>
37#include <hndsoc.h>
38#include <siutils.h>
39#include <hndcpu.h>
40#include <hndpci.h>
41#include <pcicfg.h>
42#include <bcmdevs.h>
43#include <bcmnvram.h>
44
45/* Global SB handle */
46extern si_t *bcm947xx_sih;
47extern spinlock_t bcm947xx_sih_lock;
48
49/* Global USB capability */
50int usb_hsic_cap = 0;
51int usb_hsic_cap_port = 0;
52EXPORT_SYMBOL(usb_hsic_cap);
53EXPORT_SYMBOL(usb_hsic_cap_port);
54
55/* Convenience */
56#define sih bcm947xx_sih
57#define sih_lock bcm947xx_sih_lock
58
59static int
60sbpci_read_config_reg(struct pci_bus *bus, unsigned int devfn, int where,
61                      int size, u32 *value)
62{
63	unsigned long flags;
64	int ret;
65
66	spin_lock_irqsave(&sih_lock, flags);
67	ret = hndpci_read_config(sih, bus->number, PCI_SLOT(devfn),
68	                        PCI_FUNC(devfn), where, value, size);
69	spin_unlock_irqrestore(&sih_lock, flags);
70	return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
71}
72
73static int
74sbpci_write_config_reg(struct pci_bus *bus, unsigned int devfn, int where,
75                       int size, u32 value)
76{
77	unsigned long flags;
78	int ret;
79
80	spin_lock_irqsave(&sih_lock, flags);
81	ret = hndpci_write_config(sih, bus->number, PCI_SLOT(devfn),
82	                         PCI_FUNC(devfn), where, &value, size);
83	spin_unlock_irqrestore(&sih_lock, flags);
84	return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
85}
86
87static struct pci_ops pcibios_ops = {
88	sbpci_read_config_reg,
89	sbpci_write_config_reg
90};
91
92static u32 pci_iobase = 0x100;
93static u32 pci_membase = SI_PCI_DMA;
94
95#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
96static struct resource bcm_pci_mem_resource = {
97        .name   = "bcm947xx PCI memory space",
98        .start  = SI_PCI_MEM  /* BCM_PCI_MEM_BASE_PA */,
99        .end    = SI_PCI_MEM + SI_PCI_MEM_SZ /* BCM_PCI_MEM_END_PA */,
100        .flags  = IORESOURCE_MEM
101};
102
103static struct resource bcm_pci_io_resource = {
104        .name   = "bcm947xx PCI IO space",
105        .start  = 0xc0000000 /* BCM_PCI_IO_BASE_PA */,
106        .end    = 0xc0001000 /* BCM_PCI_IO_END_PA */,
107        .flags  = IORESOURCE_IO
108};
109
110struct pci_controller bcm947xxcontroller = {
111        .pci_ops        = &pcibios_ops,
112        .io_resource    = &bcm_pci_io_resource,
113        .mem_resource   = &bcm_pci_mem_resource,
114};
115#endif
116
117void __init
118pcibios_init(void)
119{
120	ulong flags;
121
122	/* For 4716, use sbtopcie0 to access the device. We
123	 * can't use address match 2 (1 GB window) region as MIPS
124	 * can not generate 64-bit address on the backplane.
125	 */
126	if (sih->chip == BCM4716_CHIP_ID) {
127		printk(KERN_INFO "PCI: Using membase %x\n", SI_PCI_MEM);
128		pci_membase = SI_PCI_MEM;
129	}
130
131	if (!(sih = si_kattach(SI_OSH)))
132		panic("si_kattach failed");
133	spin_lock_init(&sih_lock);
134
135	spin_lock_irqsave(&sih_lock, flags);
136	hndpci_init(sih);
137	spin_unlock_irqrestore(&sih_lock, flags);
138
139	set_io_port_base((unsigned long) ioremap_nocache(SI_PCI_MEM, 0x04000000));
140
141	/* Scan the SB bus */
142	printk(KERN_INFO "PCI: scanning bus %x\n", 0);
143#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
144	register_pci_controller( &bcm947xxcontroller );
145	pci_scan_bus(0, &pcibios_ops, &bcm947xxcontroller);
146#else
147	pci_scan_bus(0, &pcibios_ops, NULL);
148#endif
149}
150
151char * __init
152pcibios_setup(char *str)
153{
154	if (!strncmp(str, "ban=", 4)) {
155		hndpci_ban(simple_strtoul(str + 4, NULL, 0));
156		return NULL;
157	}
158
159	return (str);
160}
161
162void __devinit
163pcibios_fixup_bus(struct pci_bus *b)
164{
165	struct list_head *ln;
166	struct pci_dev *d, *dev;
167	struct resource *res;
168	int pos, size;
169	u32 *base;
170	u8 irq;
171
172	printk("PCI: Fixing up bus %d\n", b->number);
173
174	/* Fix up SB */
175	if (b->number == 0) {
176		for (ln = b->devices.next; ln != &b->devices; ln = ln->next) {
177			d = pci_dev_b(ln);
178			/* Fix up interrupt lines */
179			pci_read_config_byte(d, PCI_INTERRUPT_LINE, &irq);
180			d->irq = irq + 2;
181			pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
182		}
183	} else {
184		irq = 0;
185		/* Find the corresponding IRQ of the PCI/PCIe core per bus number */
186		/* All devices on the bus use the same IRQ as the core */
187		list_for_each_entry(dev, &((pci_find_bus(0, 0))->devices), bus_list) {
188			if ((dev != NULL) &&
189			    ((dev->device == PCI_CORE_ID) ||
190			    (dev->device == PCIE_CORE_ID))) {
191				if (dev->subordinate && dev->subordinate->number == b->number) {
192					irq = dev->irq;
193					break;
194				}
195			}
196		}
197
198		pci_membase = hndpci_get_membase(b->number);
199		/* Fix up external PCI */
200		for (ln = b->devices.next; ln != &b->devices; ln = ln->next) {
201			bool is_hostbridge;
202
203			d = pci_dev_b(ln);
204			is_hostbridge = hndpci_is_hostbridge(b->number, PCI_SLOT(d->devfn));
205			/* Fix up resource bases */
206			for (pos = 0; pos < 6; pos++) {
207				res = &d->resource[pos];
208				base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase;
209				if (res->end) {
210					size = res->end - res->start + 1;
211					if (*base & (size - 1))
212						*base = (*base + size) & ~(size - 1);
213					res->start = *base;
214					res->end = res->start + size - 1;
215					*base += size;
216					pci_write_config_dword(d,
217						PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
218				}
219				/* Fix up PCI bridge BAR0 only */
220				if (is_hostbridge)
221					break;
222			}
223			/* Fix up interrupt lines */
224			d->irq = irq;
225			pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
226		}
227		hndpci_arb_park(sih, PCI_PARK_NVRAM);
228	}
229}
230
231int
232pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
233{
234	return (dev->irq);
235}
236
237int
238pcibios_enable_resources(struct pci_dev *dev)
239{
240	u16 cmd, old_cmd;
241	int idx;
242	struct resource *r;
243
244	/* External PCI only */
245	if (dev->bus->number == 0)
246		return 0;
247
248	pci_read_config_word(dev, PCI_COMMAND, &cmd);
249	old_cmd = cmd;
250	for (idx = 0; idx < 6; idx++) {
251		r = &dev->resource[idx];
252		if (r->flags & IORESOURCE_IO)
253			cmd |= PCI_COMMAND_IO;
254		if (r->flags & IORESOURCE_MEM)
255			cmd |= PCI_COMMAND_MEMORY;
256	}
257	if (dev->resource[PCI_ROM_RESOURCE].start)
258		cmd |= PCI_COMMAND_MEMORY;
259	if (cmd != old_cmd) {
260		printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
261		pci_write_config_word(dev, PCI_COMMAND, cmd);
262	}
263	return 0;
264}
265
266int
267pcibios_enable_device(struct pci_dev *dev, int mask)
268{
269	ulong flags;
270	uint coreidx, coreid;
271	void *regs;
272	int rc = -1;
273
274	/* External PCI device enable */
275	if (dev->bus->number != 0)
276		return pcibios_enable_resources(dev);
277
278	/* These cores come out of reset enabled */
279	if (dev->device == MIPS_CORE_ID ||
280	    dev->device == MIPS33_CORE_ID ||
281	    dev->device == CC_CORE_ID)
282		return 0;
283
284	spin_lock_irqsave(&sih_lock, flags);
285
286	regs = si_setcoreidx(sih, PCI_SLOT(dev->devfn));
287	coreidx = si_coreidx(sih);
288	coreid = si_coreid(sih);
289
290	if (!regs) {
291		printk(KERN_ERR "WARNING! PCIBIOS_DEVICE_NOT_FOUND\n");
292		goto out;
293	}
294
295	/*
296	 * The USB core requires a special bit to be set during core
297	 * reset to enable host (OHCI) mode. Resetting the SB core in
298	 * pcibios_enable_device() is a hack for compatibility with
299	 * vanilla usb-ohci so that it does not have to know about
300	 * SB. A driver that wants to use the USB core in device mode
301	 * should know about SB and should reset the bit back to 0
302	 * after calling pcibios_enable_device().
303	 */
304	if (coreid == USB_CORE_ID) {
305		si_core_disable(sih, si_core_cflags(sih, 0, 0));
306		si_core_reset(sih, 1 << 29, 0);
307	}
308	/*
309	 * USB 2.0 special considerations:
310	 *
311	 * 1. Since the core supports both OHCI and EHCI functions, it must
312	 *    only be reset once.
313	 *
314	 * 2. In addition to the standard SB reset sequence, the Host Control
315	 *    Register must be programmed to bring the USB core and various
316	 *    phy components out of reset.
317	 */
318	else if (coreid == USB20H_CORE_ID) {
319		if (!si_iscoreup(sih)) {
320			si_core_reset(sih, 0, 0);
321			mdelay(10);
322			if (si_corerev(sih) >= 5) {
323				uint32 tmp;
324				/* Enable Misc PLL */
325				tmp = readl(regs + 0x1e0);
326				tmp |= 0x100;
327				writel(tmp, regs + 0x1e0);
328				SPINWAIT((((tmp = readl(regs + 0x1e0)) & (1 << 24))
329					== 0), 1000);
330				/* Take out of resets */
331				writel(0x4ff, regs + 0x200);
332				udelay(25);
333				writel(0x6ff, regs + 0x200);
334				udelay(25);
335
336				/* Make sure digital and AFE are locked in USB PHY */
337				writel(0x6b, regs + 0x524);
338				udelay(50);
339				tmp = readl(regs + 0x524);
340				udelay(50);
341				writel(0xab, regs + 0x524);
342				udelay(50);
343				tmp = readl(regs + 0x524);
344				udelay(50);
345				writel(0x2b, regs + 0x524);
346				udelay(50);
347				tmp = readl(regs + 0x524);
348				udelay(50);
349				writel(0x10ab, regs + 0x524);
350				udelay(50);
351				tmp = readl(regs + 0x524);
352				SPINWAIT((((tmp = readl(regs + 0x528)) & 0xc000) !=
353					0xc000), 100000);
354				if ((tmp & 0xc000) != 0xc000) {
355					printk(KERN_WARNING "WARNING! USB20H mdio_rddata 0x%08x\n", tmp);
356					goto out;
357				}
358				writel(0x80000000, regs + 0x528);
359				tmp = readl(regs + 0x314);
360				udelay(265);
361				writel(0x7ff, regs + 0x200);
362				udelay(10);
363
364				/* Take USB and HSIC out of non-driving modes */
365				writel(0, regs + 0x510);
366			} else {
367				writel(0x7ff, regs + 0x200);
368				udelay(1);
369			}
370		}
371		/* PRxxxx: War for 5354 failures. */
372		if (si_corerev(sih) == 1) {
373			uint32 tmp;
374
375			/* Change Flush control reg */
376			tmp = readl(regs + 0x400);
377			tmp &= ~8;
378			writel(tmp, regs + 0x400);
379			tmp = readl(regs + 0x400);
380			printk(KERN_DEBUG "USB20H fcr: 0x%x\n", tmp);
381
382			/* Change Shim control reg */
383			tmp = readl(regs + 0x304);
384			tmp &= ~0x100;
385			writel(tmp, regs + 0x304);
386			tmp = readl(regs + 0x304);
387			printk(KERN_DEBUG "USB20H shim cr: 0x%x\n", tmp);
388		}
389		if (si_corerev(sih) == 5) {
390			usb_hsic_cap = 1;
391			usb_hsic_cap_port = 2;
392		}
393	} else {
394		si_core_reset(sih, 0, 0);
395	}
396
397	/* Initialize USBHC core OK */
398	rc = 0;
399out:
400	si_setcoreidx(sih, coreidx);
401	spin_unlock_irqrestore(&sih_lock, flags);
402
403	/* Reset the device */
404	if (coreid == USB20H_CORE_ID || coreid == USB_CORE_ID)	{
405		int wombo_reset = GPIO_PIN_NOTDEFINED;
406
407		if ((wombo_reset = getgpiopin(NULL, "wombo_reset", GPIO_PIN_NOTDEFINED)) !=
408	    GPIO_PIN_NOTDEFINED) {
409			int reset = 1 << wombo_reset;
410
411			printk("wombo_reset set to gpio %d\n", wombo_reset);
412
413			si_gpioout(sih, reset, 0, GPIO_DRV_PRIORITY);
414			si_gpioouten(sih, reset, reset, GPIO_DRV_PRIORITY);
415			mdelay(50);
416
417			si_gpioout(sih, reset, reset, GPIO_DRV_PRIORITY);
418			mdelay(20);
419		}
420	}
421
422	return rc;
423}
424
425void
426pcibios_update_resource(struct pci_dev *dev, struct resource *root,
427	struct resource *res, int resource)
428{
429	unsigned long where, size;
430	u32 reg;
431
432	/* External PCI only */
433	if (dev->bus->number == 0)
434		return;
435
436	where = PCI_BASE_ADDRESS_0 + (resource * 4);
437	size = res->end - res->start;
438	pci_read_config_dword(dev, where, &reg);
439	reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
440	pci_write_config_dword(dev, where, reg);
441}
442
443static void __init
444quirk_sbpci_bridge(struct pci_dev *dev)
445{
446	if (dev->bus->number == 0 ||
447		!hndpci_is_hostbridge(dev->bus->number, PCI_SLOT(dev->devfn)))
448		return;
449
450	printk("PCI: Fixing up bridge\n");
451
452	/* Enable PCI bridge bus mastering and memory space */
453	pci_set_master(dev);
454	pcibios_enable_resources(dev);
455
456	/* Enable PCI bridge BAR1 prefetch and burst */
457	pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3);
458}
459
460DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_sbpci_bridge);
461