📄 hal_pci.c
字号:
/************************************************************************ * Philips ISP1362 hardware access layer driver for * Intel X86 PCI platform * * (c) 2002 Koninklijke Philips Electronics N.V., All rights reserved * * This source code and any compilation or derivative thereof is the * proprietary information of Koninklijke Philips Electronics N.V. * and is confidential in nature. * Under no circumstances is this software to be exposed to or placed * under an Open Source License of any type without the expressed * written permission of Koninklijke Philips Electronics N.V. * * File Name: hal_pci.c * * History: * * Version Date Author Comments * ------------------------------------------------- * 1.0 09/23/02 SYARRA Initial Creation * 1.1 05/12/03 SYARRA PLX9054-AC (PCI BRIDGE) Chip support * * Note: use tab space 4 ************************************************************************/#include <linux/config.h>#define MODULE#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h> /* for in_interrupt() */#undef DEBUG#include <linux/usb.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/unaligned.h>#include <asm/dma.h>#include "hal_intf.h"/*--------------------------------------------------------------* * Local variable Definitions *--------------------------------------------------------------*/struct isp1362_dev isp1362_loc_dev[ISP1362_LAST_DEV];static struct isp1362_hal hal_data;static __u16 pci_io_base = 0;static int isp1362_pci_latency;/*--------------------------------------------------------------* * Local # Definitions *--------------------------------------------------------------*/#define PCI_ACCESS_RETRY_COUNT 6#define PLX_INT_CSR_REG 0x68#define PLX_LBRD0_REG 0x18#define PLX_LBRD0_WAIT_STATE_MASK 0x000000C3#define PLX_LBRD0_WAIT_STATES 0x00000003#define isp1362_driver_name "1362-pci"#define DRIVER_AUTHOR "Philips Semiconductors"#define DRIVER_DESC "ISP1362 bus driver"/*--------------------------------------------------------------* * Local Function Declerations *--------------------------------------------------------------*/static void __devexit isp1362_pci_remove (struct pci_dev *dev);static int __devinit isp1362_pci_probe (struct pci_dev *dev, const struct pci_device_id *id);static int isp1362_pci_suspend (struct pci_dev *dev, __u32 state);static int isp1362_pci_resume (struct pci_dev *dev);static void isp1362_pci_isr (int irq, void *__data, struct pt_regs *r);/*--------------------------------------------------------------* * ISP1362 Interrupt Service Routine *--------------------------------------------------------------*//* Interrupt Service Routine of isp1362 * Reads the source of interrupt and calls the corresponding driver's ISR. * Before calling the driver's ISR clears the source of interrupt. * The drivers can get the source of interrupt from the dev->int_reg field */void isp1362_pci_isr(int irq, void *__data, struct pt_regs *r) { __u32 irq_mask; __u32 hc_int_reg; __u32 intrenable; struct isp1362_dev *dev; func_debug(("isp1362_pci_isr(irq = %d,__data=%p,r=%p)\n",irq,__data,r)) /* Process the Host Controller Driver */ dev = &isp1362_loc_dev[ISP1362_HC]; /* Get the source of interrupts for Host Controller */ isp1362_reg_read16(dev, HC_MP_INT_REG,(dev->int_reg)); isp1362_reg_read16(dev, HC_MP_INT_EN_REG,irq_mask); isp1362_reg_read32(dev, HC_INT_STS_REG,(dev->alt_int_reg) ); isp1362_reg_read32(dev, HC_INT_EN_REG,intrenable ); /* Clear the source of interrupts for Host Controller */ isp1362_reg_write16(dev,(HC_MP_INT_REG|0x80), (dev->int_reg)); isp1362_reg_write32(dev,(HC_INT_STS_REG|0x80), (dev->alt_int_reg)); dev->int_reg &= irq_mask; hc_int_reg = dev->int_reg; dev->alt_int_reg &= intrenable; /* call the Host Isr if any valid interrupt is present */ if(dev->int_reg) dev->handler(dev,dev->isr_data); /* Process OTG controller Driver * Since OTG is part of HC interrupt register, the interrupt source * will be HC interrupt Register */ dev = &isp1362_loc_dev[ISP1362_OTG]; if(hc_int_reg & HC_OTG_INT) { /* Read the source of OTG_INT and clear the * interrupt source */ isp1362_reg_read16(dev, OTG_INT_REG,(dev->int_reg)); isp1362_reg_write16(dev, (OTG_INT_REG|0x80),OTG_INT_MASK); if(dev->int_reg) dev->handler(dev, dev->isr_data); } /* Process the Device Controller */ dev = &isp1362_loc_dev[ISP1362_DC]; /* Get the source of interrupts for Device Controller * Device Controller interrupts are cleared by the driver * during processing */ isp1362_reg_read32(dev, DC_INT_REG,(dev->int_reg)); isp1362_reg_read32(dev, DC_INT_EN_REG,irq_mask); dev->int_reg &= irq_mask; if(dev->int_reg) dev->handler(dev, dev->isr_data); return;} /* End of isp1362_pci_isr *//*--------------------------------------------------------------* * PCI Driver Interface Functions *--------------------------------------------------------------*/static const struct pci_device_id __devinitdata isp1362_pci_ids [] = { { /* handle PCI BRIDE manufactured by PLX */ class: ((PCI_CLASS_BRIDGE_OTHER << 8) | 0x00), class_mask: ~0, /* no matter who makes it */ vendor: PCI_VENDOR_ID_PLX, device: PCI_ANY_ID, subvendor: PCI_ANY_ID, subdevice: PCI_ANY_ID, }, { /* end: all zeroes */ }};MODULE_DEVICE_TABLE (pci, isp1362_pci_ids);/* Pci driver interface functions */static struct pci_driver isp1362_pci_driver = { name: "isp1362-hal", id_table: &isp1362_pci_ids [0], probe: isp1362_pci_probe, remove: isp1362_pci_remove,#ifdef CONFIG_PM suspend: isp1362_pci_suspend, resume: isp1362_pci_resume,#endif /* PM */};/* PCI probe function of ISP1362 * This function is called from PCI Driver as an initialization function * when it founds the PCI device. This functions initializes the information * for the 3 Controllers with the assigned resources and tests the register * access to these controllers and do a software reset and makes them ready * for the drivers to play with them. */static int __devinitisp1362_pci_probe (struct pci_dev *dev, const struct pci_device_id *id){ u8 latency, limit; __u32 reg_data = 0; int retry_count; struct isp1362_dev *loc_dev; __u8 plx_lbrd0; func_debug(("isp1362_pci_probe(dev=%p)\n",dev)) if (pci_enable_device(dev) < 0) return -ENODEV; if (!dev->irq) { detail_debug(("found ISP1362 device with no IRQ assigned. check BIOS settings!")) return -ENODEV; } /* Grab the PLX PCI IO port start address */ pci_io_base = pci_resource_start(dev, 1); detail_debug(("isp1362 pci IO Base= %x\n", pci_io_base)) /* Get the Host Controller IO and INT resources */ loc_dev = &(isp1362_loc_dev[ISP1362_HC]); loc_dev->irq = dev->irq; reg_data = pci_resource_start(dev, 2); loc_dev->io_base = reg_data; loc_dev->io_data = loc_dev->io_base; loc_dev->io_cmd = loc_dev->io_base + 2; loc_dev->io_len = 4; loc_dev->index = ISP1362_HC; detail_debug(("isp1362 HC IO Base= %x irq = %x\n", loc_dev->io_base,loc_dev->irq)) /* Get the Device Controller IO and INT resources * Device controller also uses the same INT channel for PCI * but the IO is different */ loc_dev = &(isp1362_loc_dev[ISP1362_DC]); loc_dev->irq = dev->irq; loc_dev->io_base = reg_data + 4; loc_dev->io_data = loc_dev->io_base; loc_dev->io_cmd = loc_dev->io_base + 2; loc_dev->io_len = 4; loc_dev->index = ISP1362_DC; detail_debug(("isp1362 DC IO Base= %x irq = %x\n", loc_dev->io_base,loc_dev->irq)) /* Get the OTG Controller IO and INT resources * OTG controller resources are same as Host Controller resources */ loc_dev = &(isp1362_loc_dev[ISP1362_OTG]); loc_dev->irq = dev->irq; loc_dev->io_base = reg_data; loc_dev->io_data = loc_dev->io_base; loc_dev->io_cmd = loc_dev->io_base + 2; loc_dev->io_len = 4; loc_dev->index = ISP1362_OTG; detail_debug(("isp1362 OTG IO Base= %x irq = %x\n", loc_dev->io_base,loc_dev->irq)) /* bad pci latencies can contribute to overruns */ pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); if (latency) { pci_read_config_byte (dev, PCI_MAX_LAT, &limit); if (limit && limit < latency) { dbg ("PCI latency reduced to max %d", limit); pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); isp1362_pci_latency = limit; } else { /* it might already have been reduced */ isp1362_pci_latency = latency; } } /* Configure the Wait States for the PLX chip (needed for 9054-AC package) */ /* This is specific to ISP1362, PXL9054 bridge setting */ plx_lbrd0 = inb(PLX_LBRD0_REG + pci_io_base); plx_lbrd0 &= PLX_LBRD0_WAIT_STATE_MASK; /* Mask bits 5-2 Memory space 0 internal waut states */ plx_lbrd0 |= (PLX_LBRD0_WAIT_STATES << 2); /* Set wait states to 3 */ outb(plx_lbrd0, (PLX_LBRD0_REG + pci_io_base)); /* Intialize Host Controller * Check IO resource availability, Check registers accebility * Read the Chip ID, Reset the chip and make it ready for use * by the Host Controller Driver */ loc_dev = &(isp1362_loc_dev[ISP1362_HC]); if( check_region(loc_dev->io_base, loc_dev->io_len) < 0) { detail_debug(("Host Controller IO region (0x%x-0x%x) busy\n",loc_dev->io_base,loc_dev->io_len)) return -EBUSY; } request_region(loc_dev->io_base, loc_dev->io_len,isp1362_driver_name); /* Try to check whether we can access Scratch Register of * Host Controller or not. The initial PCI access is retried until * local init for the PCI bridge is completed */ retry_count = PCI_ACCESS_RETRY_COUNT; while((reg_data != 0xFACE) && retry_count) { isp1362_reg_write16(loc_dev, (HC_SCRATCH_REG|0x80), 0xFACE); isp1362_reg_read16(loc_dev, HC_SCRATCH_REG,reg_data); retry_count--; } /* Host Controller presence is detected by writing to scratch register * and reading back and checking the contents are same or not */ if(reg_data != 0xFACE) { detail_debug(("%s unable to access HC Scratch Register",isp1362_driver_name)) release_region(loc_dev->io_base, loc_dev->io_len); return -ENODEV; } /* Reset the Host controller (reset requires some time ..... * is 100 msec ok?? */ loc_dev->active = 1; isp1362_reg_write16(loc_dev, (HC_SW_RESET_REG|0x80), 0x00F6); isp1362_mdelay(100); isp1362_reg_read16(loc_dev, HC_CHIP_ID_REG,(loc_dev->chip_id)); detail_debug(("%s: found HC Chip Id = %x\n",isp1362_driver_name, loc_dev->chip_id)) release_region(loc_dev->io_base, loc_dev->io_len);/* release IO space */ /* Update the local and store the PCI data */ hal_data.io_usage = 0; hal_data.irq_usage = 0; pci_set_drvdata (dev, isp1362_loc_dev); /* Now Process the Device Controller */ loc_dev = &(isp1362_loc_dev[ISP1362_DC]); request_region(loc_dev->io_base, loc_dev->io_len,isp1362_driver_name); reg_data = 0; isp1362_reg_write16(loc_dev, (DC_SCRATCH_REG&0xFE), 0xFACE); isp1362_reg_read16(loc_dev, DC_SCRATCH_REG,reg_data); if(reg_data != 0xFACE) { detail_debug(("%s unable to access DC Scratch Register",isp1362_driver_name)) release_region(loc_dev->io_base, loc_dev->io_len); return -ENODEV; } loc_dev->active = 1; isp1362_reg_read16(loc_dev, DC_CHIP_ID_REG,(loc_dev->chip_id)); detail_debug(("%s: found DC Chip Id = %x\n",isp1362_driver_name, loc_dev->chip_id)) /* Rest the DC. Assume 10 msec are fairly enough for DC to reset */ isp1362_command(DC_SW_RESET_REG,loc_dev); isp1362_mdelay(10); release_region(loc_dev->io_base, loc_dev->io_len);/* release IO space */ /* Now Process the OTG Controller * OTG resources are same as HC resource nothing to be done here */ loc_dev = &(isp1362_loc_dev[ISP1362_OTG]); loc_dev->active = 1; return 0;} /* End of isp1362_pci_probe */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -