gt64260_common.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,667 行 · 第 1/3 页

C
1,667
字号
/* * arch/ppc/kernel/gt64260_common.c *  * Common routines for the Marvell/Galileo GT64260 (Discovery) host bridge, * interrupt controller, memory controller, serial controller, enet controller, * etc. * * Author: Mark A. Greer <mgreer@mvista.com> * * Copyright 2001 MontaVista Software Inc. * * 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. *//* * The GT64260 port is the result of hard work from many people from * many companies.  In particular, employees of Marvell/Galileo, Mission * Critical Linux, Xyterra, and MontaVista Software were heavily involved. *//* * At last count, the 64260-B-0 has 65 errata and 24 restrictions.  The odds of * you getting it to work well, under stress, for a long period of time are * low.  If nothing else, you will likely run into an interrupt controller * bug. * * The newer 64260A-B-0 is much improved but has its own problems. * Dave Wilhardt <dwilhardt@zyterra.com> has discovered that you must set * up your PCI snoop regions to be prefetchable with 4-word bursts AND set the * "Memory Write and Invalidate bit" (bit 4) in the cmd reg of each PCI device * before coherency works between PCI and other devices.  Many thanks to Dave. * * So far this code has been tested on Marvell/Galileo EV-64260-BP and * an EV-64260A-BP uni-processor boards with 750 and 7400 processors. * It has not yet been tested with a 7410 or 7450, or on an smp system. * * Note: I have not had any luck moving the base register address of the bridge * 	 with the gt64260_set_base() routine.  I move it in the bootloader * 	 before starting the kernel.  I haven't really looked into it so it * 	 may be an easy fix. -- MAG */#include <linux/kernel.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/slab.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/gt64260.h>#include <asm/delay.h>u32	gt64260_base; /* Virtual base address of 64260's regs */u32	gt64260_revision; /* Revision of the chip */u8	gt64260_pci_exclude_bridge = TRUE;/* ***************************************************************************** * *	Bridge Initialization Routines * ***************************************************************************** */static void gt64260_check_errata(struct pci_controller *hose_a,				 struct pci_controller *hose_b);/* * Typical '_find_bridges()' routine for boards with a GT64260 bridge. */int __initgt64260_find_bridges(u32 phys_base_addr, gt64260_bridge_info_t *info,	int ((*map_irq)(struct pci_dev *, unsigned char, unsigned char))){	struct pci_controller		*hose_a, *hose_b;	u32				io_base_a, io_base_b;	int				rc;	gt64260_base = (u32)ioremap(phys_base_addr,GT64260_INTERNAL_SPACE_SIZE);	hose_a = pcibios_alloc_controller();	if (!hose_a)		return -1;	hose_b = pcibios_alloc_controller();	if (!hose_b)		return -1;	info->hose_a = hose_a;	info->hose_b = hose_b;	/* Ends up mapping PCI Config addr/data pairs twice */	setup_indirect_pci(hose_a,			   phys_base_addr + GT64260_PCI_0_CONFIG_ADDR,			   phys_base_addr + GT64260_PCI_0_CONFIG_DATA);	setup_indirect_pci(hose_b,			   phys_base_addr + GT64260_PCI_1_CONFIG_ADDR,			   phys_base_addr + GT64260_PCI_1_CONFIG_DATA);	if ((rc = gt64260_bridge_init(info)) != 0) {		iounmap((void *)hose_a->cfg_addr);		iounmap((void *)hose_a->cfg_data);		iounmap((void *)hose_b->cfg_addr);		iounmap((void *)hose_b->cfg_data);		iounmap((void *)gt64260_base);		return rc;	}	/* ioremap PCI I/O regions */	io_base_b = (u32)ioremap(info->pci_1_io_start_proc,info->pci_1_io_size);	io_base_a = (u32)ioremap(info->pci_0_io_start_proc,info->pci_0_io_size);	isa_io_base = io_base_a;	hose_a->first_busno = 0;	hose_a->last_busno  = 0xff;	pci_init_resource(&hose_a->io_resource,			  0,	/* really: io_base_a - isa_io_base */			  info->pci_0_io_size - 1,			  IORESOURCE_IO,			  "host bridge PCI bus 0");	hose_a->io_space.start = info->pci_0_io_start_pci;	hose_a->io_space.end   = info->pci_0_io_start_pci +					info->pci_0_io_size - 1;	hose_a->io_base_virt = (void *)isa_io_base;	pci_init_resource(&hose_a->mem_resources[0],			  info->pci_0_mem_start_proc,			  info->pci_0_mem_start_proc + info->pci_0_mem_size - 1,			  IORESOURCE_MEM,			  "host bridge PCI bus 0");	hose_a->mem_space.start = info->pci_0_mem_start_pci_lo;	hose_a->mem_space.end   = info->pci_0_mem_start_pci_lo +					info->pci_0_mem_size - 1;	hose_a->pci_mem_offset = (info->pci_0_mem_start_proc -					info->pci_0_mem_start_pci_lo);	hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);	hose_b->first_busno = hose_a->last_busno + 1;	hose_b->bus_offset  = hose_b->first_busno;	hose_b->last_busno  = 0xff;	pci_init_resource(&hose_b->io_resource,			  io_base_b - isa_io_base,			  io_base_b - isa_io_base + info->pci_1_io_size - 1,			  IORESOURCE_IO,			  "host bridge PCI bus 1");	hose_b->io_space.start = info->pci_1_io_start_pci;	hose_b->io_space.end   = info->pci_1_io_start_pci +					info->pci_1_io_size - 1;	hose_b->io_base_virt = (void *)isa_io_base;	pci_init_resource(&hose_b->mem_resources[0],			  info->pci_1_mem_start_proc,			  info->pci_1_mem_start_proc + info->pci_1_mem_size - 1,			  IORESOURCE_MEM,			  "host bridge PCI bus 1");	hose_b->mem_space.start = info->pci_1_mem_start_pci_lo;	hose_b->mem_space.end   = info->pci_1_mem_start_pci_lo +					info->pci_1_mem_size - 1;	hose_b->pci_mem_offset = (info->pci_1_mem_start_proc -					info->pci_1_mem_start_pci_lo);	hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno);	ppc_md.pci_exclude_device = gt64260_pci_exclude_device;	ppc_md.pci_swizzle        = common_swizzle;	ppc_md.pci_map_irq        = map_irq;	return 0;} /* gt64260_find_bridges() *//* * gt64260_bridge_init() * * Perform bridge initialization for a "typical" setup for a PPC system. */int __initgt64260_bridge_init(gt64260_bridge_info_t *info){	int	window;	u16	u16_val;	u32	u32_val;	int	rc = 0;	u8	save_exclude;	/*	 * Count on firmware to set/clear other bits in this register.	 *	 * Set CPU CONFIG Reg bit:	 *	bit 13 - Pipeline	 *	bit 16 - RdOOO	 *	 * Clear CPU Config Reg bit:	 * 	bit 12 - endianess	 *	bit 27 - RemapWrDis	 */	u32_val = gt_read(GT64260_CPU_CONFIG);	u32_val |= ((1<<13) | (1<<16));	u32_val &= ~((1<<8) | (1<<12) | (1<<27));	gt_write(GT64260_CPU_CONFIG, u32_val);	/* PCI 0/1 Timeout and Retry limits */	u32_val = gt_read(GT64260_PCI_0_TO_RETRY);	u32_val |= 0x0000ffff;	gt_write(GT64260_PCI_0_TO_RETRY, u32_val);	u32_val = gt_read(GT64260_PCI_1_TO_RETRY);	u32_val |= 0x0000ffff;	gt_write(GT64260_PCI_1_TO_RETRY, u32_val);	save_exclude = gt64260_pci_exclude_bridge;	gt64260_pci_exclude_bridge = FALSE;	/* Set class code to indicate host bridge */	early_read_config_dword(info->hose_a,			        info->hose_a->first_busno,			        PCI_DEVFN(0,0),			        PCI_CLASS_REVISION,			        &u32_val);	u32_val &= 0x000000ff;	gt64260_revision = u32_val;	/* a 64260 or 64260A? */	u32_val |= (PCI_CLASS_BRIDGE_HOST << 16);	early_write_config_dword(info->hose_a,				 info->hose_a->first_busno,				 PCI_DEVFN(0,0),				 PCI_CLASS_REVISION,				 u32_val);	early_read_config_dword(info->hose_b,			        info->hose_b->first_busno,			        PCI_DEVFN(0,0),			        PCI_CLASS_REVISION,			        &u32_val);	u32_val &= 0x000000ff;	u32_val |= (PCI_CLASS_BRIDGE_HOST << 16);	early_write_config_dword(info->hose_b,				 info->hose_b->first_busno,				 PCI_DEVFN(0,0),				 PCI_CLASS_REVISION,				 u32_val);	/* Enable 64260 to be PCI master & respond to PCI MEM cycles */	early_read_config_word(info->hose_a,			       info->hose_a->first_busno,			       PCI_DEVFN(0,0),			       PCI_COMMAND,			       &u16_val);	u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);	early_write_config_word(info->hose_a,				info->hose_a->first_busno,				PCI_DEVFN(0,0),				PCI_COMMAND,				u16_val);	early_read_config_word(info->hose_b,			       info->hose_b->first_busno,			       PCI_DEVFN(0,0),			       PCI_COMMAND,			       &u16_val);	u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);	early_write_config_word(info->hose_b,				info->hose_b->first_busno,				PCI_DEVFN(0,0),				PCI_COMMAND,				u16_val);	gt64260_pci_exclude_bridge = save_exclude;	/*	 * Disable all CPU windows on the bridge except for SCS 0 which	 * is covering all of system memory.:	 */	gt64260_cpu_disable_all_windows();	/*	 * Set CPU snoop window to indicate all of system memory	 * is covered with wirte-back cache.	 */	gt64260_cpu_snoop_set_window(0,				     0x00000000,				     info->mem_size,				     GT64260_CPU_SNOOP_WB);	/*	 * Set up CPU->PCI mappings (so CPU can get at PCI dev regs/mem).	 * Will only use one of the four CPU->PCI MEM windows on each bus.	 */	gt64260_cpu_set_pci_io_window(0,				      info->pci_0_io_start_proc,				      info->pci_0_io_start_pci,				      info->pci_0_io_size,				      info->pci_0_io_swap);	gt64260_cpu_set_pci_mem_window(0,				       0,				       info->pci_0_mem_start_proc,				       info->pci_0_mem_start_pci_hi,				       info->pci_0_mem_start_pci_lo,				       info->pci_0_mem_size,				       info->pci_0_mem_swap);	gt64260_cpu_set_pci_io_window(1,				      info->pci_1_io_start_proc,				      info->pci_1_io_start_pci,				      info->pci_1_io_size,				      info->pci_1_io_swap);	gt64260_cpu_set_pci_mem_window(1,				       0,				       info->pci_1_mem_start_proc,				       info->pci_1_mem_start_pci_hi,				       info->pci_1_mem_start_pci_lo,				       info->pci_1_mem_size,				       info->pci_1_mem_swap);	/*	 * Set up PCI MEM->system memory mapping (bridge slave PCI window).	 *	 * Set BAR enables to allow only the SCS0 slave window to respond	 * to PCI read/write cycles.	 */	gt64260_pci_bar_enable(0, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0);	gt64260_pci_bar_enable(1, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0);	/*	 * For virt_to_bus & bus_to_virt to work correctly, this mapping	 * must be the same on both PCI buses.	 */	gt64260_pci_slave_scs_set_window(info->hose_a,					 0,					 0x00000000,					 0x00000000,					 info->mem_size);	gt64260_pci_slave_scs_set_window(info->hose_b,					 0,					 0x00000000,					 0x00000000,					 info->mem_size);	pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */	/* Disable all the access control windows */	for (window=0; window<GT64260_PCI_ACC_CNTL_WINDOWS; window++) {		gt64260_pci_acc_cntl_set_window(0, window, 0, 0, 0, 0); 		gt64260_pci_acc_cntl_set_window(1, window, 0, 0, 0, 0); 	}	/* Disable all the PCI snoop regions */	for (window=0; window<GT64260_PCI_SNOOP_WINDOWS; window++) {		gt64260_pci_snoop_set_window(0, window, 0, 0, 0, 0); 		gt64260_pci_snoop_set_window(1, window, 0, 0, 0, 0); 	}	gt64260_pci_acc_cntl_set_window(0,					0,					0x00000000,					0x00000000,					info->mem_size,					(GT64260_PCI_ACC_CNTL_PREFETCHEN |					 GT64260_PCI_ACC_CNTL_MBURST_4_WORDS |					 GT64260_PCI_ACC_CNTL_SWAP_BYTE));	gt64260_pci_acc_cntl_set_window(1,					0,					0x00000000,					0x00000000,					info->mem_size,					(GT64260_PCI_ACC_CNTL_PREFETCHEN |					 GT64260_PCI_ACC_CNTL_MBURST_4_WORDS |					 GT64260_PCI_ACC_CNTL_SWAP_BYTE));	gt64260_pci_snoop_set_window(0,				     0,				     0x00000000,				     0x00000000,				     info->mem_size,				     GT64260_PCI_SNOOP_WB);						gt64260_pci_snoop_set_window(1,				     0,				     0x00000000,				     0x00000000,				     info->mem_size,				     GT64260_PCI_SNOOP_WB);	gt64260_check_errata(info->hose_a, info->hose_b);	/* Set latency timer (to 64) & cacheline size; clear BIST */	gt64260_pci_exclude_bridge = FALSE;	u32_val = ((0x04 << 8) | (L1_CACHE_LINE_SIZE / 4));	early_write_config_dword(info->hose_a,				 info->hose_a->first_busno,				 PCI_DEVFN(0,0),				 PCI_CACHE_LINE_SIZE,				 u32_val);	early_write_config_dword(info->hose_b,				 info->hose_b->first_busno,				 PCI_DEVFN(0,0),				 PCI_CACHE_LINE_SIZE,				 u32_val);	gt64260_pci_exclude_bridge = TRUE;	return rc;} /* gt64260_bridge_init() *//* * gt64260_check_errata() * * Apply applicable errata and restrictions from 0.5 of the * Errata and Restrictions document from Marvell/Galileo. */static void __initgt64260_check_errata(struct pci_controller *hose_a,		     struct pci_controller *hose_b){	u32	val;	u8	save_exclude;	/* Currently 2 versions, 64260 and 64260A */	if (gt64260_revision == GT64260) {		save_exclude = gt64260_pci_exclude_bridge;		gt64260_pci_exclude_bridge = FALSE;		/* FEr#5, FEr#12 */		early_read_config_dword(hose_a,					hose_a->first_busno,					PCI_DEVFN(0,0),					PCI_COMMAND,					&val);		val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);		early_write_config_dword(hose_a,					 hose_a->first_busno,					 PCI_DEVFN(0,0),					 PCI_COMMAND,					 val);		early_read_config_dword(hose_b,					hose_b->first_busno,					PCI_DEVFN(0,0),					PCI_COMMAND,					&val);		val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);		early_write_config_dword(hose_b,					 hose_b->first_busno,					 PCI_DEVFN(0,0),					 PCI_COMMAND,					 val);		gt64260_pci_exclude_bridge = save_exclude;		/* FEr#12, FEr#13 */		gt_clr_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9)));		gt_clr_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9)));		/* FEr#54 */		gt_clr_bits(GT64260_CPU_SNOOP_BASE_0, 0xfffcf000);		gt_clr_bits(GT64260_CPU_SNOOP_BASE_1, 0xfffcf000);		gt_clr_bits(GT64260_CPU_SNOOP_BASE_2, 0xfffcf000);		gt_clr_bits(GT64260_CPU_SNOOP_BASE_3, 0xfffcf000);		/* R#18 */		gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26));	} else if (gt64260_revision == GT64260A) {		/* R#18 */		gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26));		/* No longer errata so turn on */		gt_set_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9)));		gt_set_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9)));	}} /* gt64260_check_errata() *//* ***************************************************************************** * *	General Window Setting Routines * ***************************************************************************** */static intgt64260_set_32bit_window(u32 base_addr,			 u32 size,			 u32 other_bits,			 u32 bot_reg,			 u32 top_reg){	u32	val;	if (size > 0) {		/* Set up the window on the CPU side */		gt_write(bot_reg, (base_addr >> 20) | other_bits);		gt_write(top_reg, (base_addr + size - 1) >> 20);	} else { /* Disable window */		gt_write(top_reg, 0x00000000);		gt_write(bot_reg, 0x00000fff | other_bits);	}	val = gt_read(bot_reg); /* Flush FIFO */	return 0;} /* gt64260_set_32bit_window() */static intgt64260_set_64bit_window(u32 base_addr_hi,			 u32 base_addr_lo,			 u32 size,			 u32 other_bits,			 u32 bot_reg_hi,			 u32 bot_reg_lo,			 u32 top_reg){	int	rc;	if ((rc = gt64260_set_32bit_window(base_addr_lo,					   size,					   other_bits,					   bot_reg_lo,					   top_reg)) == 0) {		gt_write(bot_reg_hi, base_addr_hi);		base_addr_hi = gt_read(bot_reg_hi); /* Flush FIFO */	}	return rc;} /* gt64260_set_64bit_window() *//* ***************************************************************************** * *	CPU Configuration Routines * ***************************************************************************** */intgt64260_cpu_scs_set_window(u32 window,			   u32 base_addr,			   u32 size){

⌨️ 快捷键说明

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