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 + -
显示快捷键?