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

📄 hal_pci.c

📁 philips公司ISP1362 USB OTG控制芯片的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/************************************************************************
 * 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 + -