📄 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
*
* 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 20
#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 locking functions
*--------------------------------------------------------------*/
int isp1362_hw_lock = 0;
int isp1362_hw_isr = 0;
void isp1362_disable_interrupt(int irq) {
/* DUMMY functions
* Not used */
disable_irq(irq);
return;
}
void isp1362_enable_interrupt(int irq) {
/* DUMMY functions
* Not used */
enable_irq(irq);
return;
}
/*--------------------------------------------------------------*
* 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))
isp1362_hw_isr = 1;
/* 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);
isp1362_hw_isr = 0;
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 __devinit
isp1362_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??
*/
memcpy(loc_dev->name, isp1362_driver_name, sizeof(isp1362_driver_name));
loc_dev->name[sizeof(isp1362_driver_name)] = 0;
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;
}
memcpy(loc_dev->name, isp1362_driver_name, sizeof(isp1362_driver_name));
loc_dev->name[sizeof(isp1362_driver_name)] = 0;
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]);
memcpy(loc_dev->name, isp1362_driver_name, sizeof(isp1362_driver_name));
loc_dev->name[sizeof(isp1362_driver_name)] = 0;
loc_dev->active = 1;
return 0;
} /* End of isp1362_pci_probe */
/* PCI cleanup function of ISP1362
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -