⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m82xx_pci.c

📁 linux-2.6.15.6
💻 C
字号:
/* * * (C) Copyright 2003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * (C) Copyright 2004 Red Hat, Inc. * * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug <vbordug@ru.mvista.com> * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */#include <linux/kernel.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/machdep.h>#include <asm/pci-bridge.h>#include <asm/immap_cpm2.h>#include <asm/mpc8260.h>#include <asm/cpm2.h>#include "m82xx_pci.h"/* * Interrupt routing */static inline intpq2pci_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin){	static char pci_irq_table[][4] =	/*	 *	PCI IDSEL/INTPIN->INTLINE	 * 	  A      B      C      D	 */	{		{ PIRQA, PIRQB, PIRQC, PIRQD },	/* IDSEL 22 - PCI slot 0 */		{ PIRQD, PIRQA, PIRQB, PIRQC },	/* IDSEL 23 - PCI slot 1 */		{ PIRQC, PIRQD, PIRQA, PIRQB },	/* IDSEL 24 - PCI slot 2 */	};	const long min_idsel = 22, max_idsel = 24, irqs_per_slot = 4;	return PCI_IRQ_TABLE_LOOKUP;}static voidpq2pci_mask_irq(unsigned int irq){	int bit = irq - NR_CPM_INTS;	*(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit));	return;}static voidpq2pci_unmask_irq(unsigned int irq){	int bit = irq - NR_CPM_INTS;	*(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit));	return;}static voidpq2pci_mask_and_ack(unsigned int irq){	int bit = irq - NR_CPM_INTS;	*(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit));	return;}static voidpq2pci_end_irq(unsigned int irq){	int bit = irq - NR_CPM_INTS;	*(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit));	return;}struct hw_interrupt_type pq2pci_ic = {	"PQ2 PCI",	NULL,	NULL,	pq2pci_unmask_irq,	pq2pci_mask_irq,	pq2pci_mask_and_ack,	pq2pci_end_irq,	0};static irqreturn_tpq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs){	unsigned long stat, mask, pend;	int bit;	for(;;) {		stat = *(volatile unsigned long *) PCI_INT_STAT_REG;		mask = *(volatile unsigned long *) PCI_INT_MASK_REG;		pend = stat & ~mask & 0xf0000000;		if (!pend)			break;		for (bit = 0; pend != 0; ++bit, pend <<= 1) {			if (pend & 0x80000000)				__do_IRQ(NR_CPM_INTS + bit, regs);		}	}	return IRQ_HANDLED;}static struct irqaction pq2pci_irqaction = {	.handler = pq2pci_irq_demux,	.flags 	 = SA_INTERRUPT,	.mask	 = CPU_MASK_NONE,	.name	 = "PQ2 PCI cascade",};voidpq2pci_init_irq(void){	int irq;	volatile cpm2_map_t *immap = cpm2_immr;#if defined CONFIG_ADS8272	/* configure chip select for PCI interrupt controller */	immap->im_memctl.memc_br3 = PCI_INT_STAT_REG | 0x00001801;	immap->im_memctl.memc_or3 = 0xffff8010;#elif defined CONFIG_PQ2FADS	immap->im_memctl.memc_br8 = PCI_INT_STAT_REG | 0x00001801;	immap->im_memctl.memc_or8 = 0xffff8010;#endif	for (irq = NR_CPM_INTS; irq < NR_CPM_INTS + 4; irq++)		irq_desc[irq].handler = &pq2pci_ic;	/* make PCI IRQ level sensitive */	immap->im_intctl.ic_siexr &=		~(1 << (14 - (PCI_INT_TO_SIU - SIU_INT_IRQ1)));	/* mask all PCI interrupts */	*(volatile unsigned long *) PCI_INT_MASK_REG |= 0xfff00000;	/* install the demultiplexer for the PCI cascade interrupt */	setup_irq(PCI_INT_TO_SIU, &pq2pci_irqaction);	return;}static intpq2pci_exclude_device(u_char bus, u_char devfn){	return PCIBIOS_SUCCESSFUL;}/* PCI bus configuration registers. */static voidpq2ads_setup_pci(struct pci_controller *hose){	__u32 val;	volatile cpm2_map_t *immap = cpm2_immr;	bd_t* binfo = (bd_t*) __res;	u32 sccr = immap->im_clkrst.car_sccr;	uint pci_div,freq,time;		/* PCI int lowest prio */	/* Each 4 bits is a device bus request	and the MS 4bits	 is highest priority */	/* Bus                4bit value	   ---                ----------	   CPM high      	0b0000	   CPM middle           0b0001	   CPM low       	0b0010	   PCI reguest          0b0011	   Reserved      	0b0100	   Reserved      	0b0101	   Internal Core     	0b0110	   External Master 1 	0b0111	   External Master 2 	0b1000	   External Master 3 	0b1001	   The rest are reserved	 */	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893;	/* park bus on core */	immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_CORE;	/*	 * Set up master windows that allow the CPU to access PCI space. These	 * windows are set up using the two SIU PCIBR registers.	 */	immap->im_memctl.memc_pcimsk0 = M82xx_PCI_PRIM_WND_SIZE;	immap->im_memctl.memc_pcibr0  = M82xx_PCI_PRIM_WND_BASE | PCIBR_ENABLE;#ifdef M82xx_PCI_SEC_WND_SIZE	immap->im_memctl.memc_pcimsk1 = M82xx_PCI_SEC_WND_SIZE;	immap->im_memctl.memc_pcibr1  = M82xx_PCI_SEC_WND_BASE | PCIBR_ENABLE;#endif#if defined CONFIG_ADS8272	immap->im_siu_conf.siu_82xx.sc_siumcr =		(immap->im_siu_conf.siu_82xx.sc_siumcr &		~(SIUMCR_BBD | SIUMCR_ESE | SIUMCR_PBSE |		SIUMCR_CDIS | SIUMCR_DPPC11 | SIUMCR_L2CPC11 |		SIUMCR_LBPC11 | SIUMCR_APPC11 |		SIUMCR_CS10PC11 | SIUMCR_BCTLC11 | SIUMCR_MMR11)) |		SIUMCR_DPPC11 | SIUMCR_L2CPC01 | SIUMCR_LBPC00 |		SIUMCR_APPC10 | SIUMCR_CS10PC00 |		SIUMCR_BCTLC00 | SIUMCR_MMR11 ;#elif defined CONFIG_PQ2FADS	/*	 * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),	 * and local bus for PCI (SIUMCR [LBPC]).	 */	immap->im_siu_conf.siu_82xx.sc_siumcr = (immap->im_siu_conf.siu_82xx.sc_siumcr &				~(SIUMCR_L2CPC11 | SIUMCR_LBPC11 | SIUMCR_CS10PC11 | SIUMCR_APPC11) |				SIUMCR_BBD | SIUMCR_LBPC01 | SIUMCR_DPPC11 | SIUMCR_APPC10);#endif	/* Enable PCI  */	immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);	pci_div = ( (sccr & SCCR_PCI_MODCK) ? 2 : 1) *			( ( (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT) + 1);	freq = (uint)((2*binfo->bi_cpmfreq)/(pci_div));	time = (int)66666666/freq;	/* due to PCI Local Bus spec, some devices needs to wait such a long	time after RST 	deassertion. More specifically, 0.508s for 66MHz & twice more for 33 */	printk("%s: The PCI bus is %d Mhz.\nWaiting %s after deasserting RST...\n",__FILE__,freq,	(time==1) ? "0.5 seconds":"1 second" );	{		int i;		for(i=0;i<(500*time);i++)			udelay(1000);	}	/* setup ATU registers */	immap->im_pci.pci_pocmr0 = cpu_to_le32(POCMR_ENABLE | POCMR_PCI_IO |				((~(M82xx_PCI_IO_SIZE - 1U)) >> POTA_ADDR_SHIFT));	immap->im_pci.pci_potar0 = cpu_to_le32(M82xx_PCI_LOWER_IO >> POTA_ADDR_SHIFT);	immap->im_pci.pci_pobar0 = cpu_to_le32(M82xx_PCI_IO_BASE >> POTA_ADDR_SHIFT);	/* Set-up non-prefetchable window */	immap->im_pci.pci_pocmr1 = cpu_to_le32(POCMR_ENABLE | ((~(M82xx_PCI_MMIO_SIZE-1U)) >> POTA_ADDR_SHIFT));	immap->im_pci.pci_potar1 = cpu_to_le32(M82xx_PCI_LOWER_MMIO >> POTA_ADDR_SHIFT);	immap->im_pci.pci_pobar1 = cpu_to_le32((M82xx_PCI_LOWER_MMIO - M82xx_PCI_MMIO_OFFSET) >> POTA_ADDR_SHIFT);	/* Set-up prefetchable window */	immap->im_pci.pci_pocmr2 = cpu_to_le32(POCMR_ENABLE |POCMR_PREFETCH_EN |		(~(M82xx_PCI_MEM_SIZE-1U) >> POTA_ADDR_SHIFT));	immap->im_pci.pci_potar2 = cpu_to_le32(M82xx_PCI_LOWER_MEM >> POTA_ADDR_SHIFT);	immap->im_pci.pci_pobar2 = cpu_to_le32((M82xx_PCI_LOWER_MEM - M82xx_PCI_MEM_OFFSET) >> POTA_ADDR_SHIFT); 	/* Inbound transactions from PCI memory space */	immap->im_pci.pci_picmr0 = cpu_to_le32(PICMR_ENABLE | PICMR_PREFETCH_EN |					((~(M82xx_PCI_SLAVE_MEM_SIZE-1U)) >> PITA_ADDR_SHIFT));	immap->im_pci.pci_pibar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_BUS  >> PITA_ADDR_SHIFT);	immap->im_pci.pci_pitar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_LOCAL>> PITA_ADDR_SHIFT);#if defined CONFIG_ADS8272	/* PCI int highest prio */	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x01236745;#elif defined CONFIG_PQ2FADS	immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;#endif	/* park bus on PCI */	immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;	/* Enable bus mastering and inbound memory transactions */	early_read_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, &val);	val &= 0xffff0000;	val |= PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER;	early_write_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, val);}void __init pq2_find_bridges(void){	extern int pci_assign_all_buses;	struct pci_controller * hose;	int host_bridge;	pci_assign_all_buses = 1;	hose = pcibios_alloc_controller();	if (!hose)		return;	ppc_md.pci_swizzle = common_swizzle;	hose->first_busno = 0;	hose->bus_offset = 0;	hose->last_busno = 0xff;#ifdef CONFIG_ADS8272	hose->set_cfg_type = 1;#endif	setup_m8260_indirect_pci(hose,				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_data);	/* Make sure it is a supported bridge */	early_read_config_dword(hose,				0,				PCI_DEVFN(0,0),				PCI_VENDOR_ID,				&host_bridge);	switch (host_bridge) {		case PCI_DEVICE_ID_MPC8265:			break;		case PCI_DEVICE_ID_MPC8272:			break;		default:			printk("Attempting to use unrecognized host bridge ID"				" 0x%08x.\n", host_bridge);			break;	}	pq2ads_setup_pci(hose);	hose->io_space.start =	M82xx_PCI_LOWER_IO;	hose->io_space.end = M82xx_PCI_UPPER_IO;	hose->mem_space.start = M82xx_PCI_LOWER_MEM;	hose->mem_space.end = M82xx_PCI_UPPER_MMIO;	hose->pci_mem_offset = M82xx_PCI_MEM_OFFSET;	isa_io_base =	(unsigned long) ioremap(M82xx_PCI_IO_BASE,					M82xx_PCI_IO_SIZE);	hose->io_base_virt = (void *) isa_io_base;	/* setup resources */	pci_init_resource(&hose->mem_resources[0],			M82xx_PCI_LOWER_MEM,			M82xx_PCI_UPPER_MEM,			IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory");	pci_init_resource(&hose->mem_resources[1],			M82xx_PCI_LOWER_MMIO,			M82xx_PCI_UPPER_MMIO,			IORESOURCE_MEM, "PCI memory");	pci_init_resource(&hose->io_resource,			M82xx_PCI_LOWER_IO,			M82xx_PCI_UPPER_IO,			IORESOURCE_IO | 1, "PCI I/O");	ppc_md.pci_exclude_device = pq2pci_exclude_device;	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);	ppc_md.pci_map_irq = pq2pci_map_irq;	ppc_md.pcibios_fixup = NULL;	ppc_md.pcibios_fixup_bus = NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -