LPC IO地址映射配置及运用

LPC IO地址映射配置及运用

LPC概念
LPC全称为Low Pin Count,是Intel用来替换ISA(Industry Standard Architecture)总线的,用来减少总线引脚数的。在x86芯片上,LPC是以PCI桥模式存在的,其设备功能号一般为PCI D31:F0。同时该LPC桥下还挂有其它的子设备,以Xeon D-1500 CPU为例,该PCI桥下还挂有DMA、Timer、RTC、GPIO、电源管理、中断控制器等子设备。

标准的LPC接口设备连接图:
LPC IO地址映射配置及运用_第1张图片
假如我们这里的LPC Device为一个普通的CPLD设备,我们想在Linux内核通过LPC控制器来读写CPLD设备的地址空间,比如该CPLD地址空间为256字节。那对应的驱动代码该如何编写呢?
首先,我们先了解下x86上的IO地址空间的知识。比如上面的CPLD地址空间就是属于IO地址空间。x86的IO地址空间为16位,大小为64KB,地址范围为0x0:0xFFFF。一般划分为固定IO地址空间和可配IO地址空间。固定IO地址空间是属于CPU固定使用或保留的空间,可配IO地址空间一般不要和固定IO地址空间冲突,否则不利于产品兼容和出现未知异常问题。固定IO地址空间如下图所示,在CPU芯片手册上会有描述:
LPC IO地址映射配置及运用_第2张图片
其次,LPC桥配置空间寄存器有提供4个LPC接口通用IO地址空间映射寄存器(LPC I/F Generic Decode Range 1 Register),如下图所示,我们可以选择任意的一个寄存器用来映射CPLD设备。
LPC IO地址映射配置及运用_第3张图片
注:这4个寄存器需要在BIOS下开启使能才可以,这样在内核下该解码功能才可以正常工作。

该寄存器有3个域值,比特0为使能位,比特15:2为映射的IO基址,比特23:18为映射大小的掩码位,基址和掩码位均为忽略最低2比特位,比如该值配置为0x00fc0901,则表示,该窗口使能,基址为0x900,大小为256字节。
内核shell下可以通过lspci -xxx -s 00:1f.0命令来查看LPC桥配置空间寄存器值,如下图:
LPC IO地址映射配置及运用_第4张图片
驱动示例
我们找到0x0900-0x09FF这段无人使用的IO地址空间给CPLD设备使用,大小为256字节。使用LPC I/F Generic Decode Range 4 Register来进行映射。驱动初始化配置及使用代码如下:

static u16 lpc_cpld_base1 = 0x900;

u8 lpc_cpld_read_reg(int index, u16 address)
{
    u8 reg_val;
    u16 cpld_base;
    
    cpld_base = lpc_cpld_base1;
    
    reg_val = inb(cpld_base + (address & 0xff));
    
    LPC_LOG_DBG(LOG_DEBUG, "cpld_base:0x%x, address:0x%x, value:0x%02x\n", 
        cpld_base, address, reg_val);

    return reg_val;
}

void lpc_cpld_write_reg(int index, u16 address, u8 reg_val)
{
    u16 cpld_base;
    
    cpld_base = lpc_cpld_base1;
    
    outb((reg_val & 0xff), cpld_base + (address & 0xff));
    
    LPC_LOG_DBG(LOG_DEBUG, "cpld_base:0x%x, address:0x%x, value:0x%02x\n", 
        cpld_base, address, reg_val);
    return;
}

static int __init lpc_dbg_init(void)
{
    struct pci_dev *pdev = NULL;
    
    printk("lpc_dbg_init\n");

    pdev = pci_get_device(0x8086, 0x8c54, pdev);
    if (!pdev) {
        printk("pci_get_device(0x8086, 0x8c54) failed!\n");
    }

    lpc_pdev = pdev;

    /* 
     * LPC I/F Generic Decode Range 4 Register for cpld1 0x0900-0x09FF
     */
    pci_write_config_dword(pdev, 0x90, 0xfc0901);
    if (!request_region(lpc_cpld_base1, 0x100, "lpc_cpld1")) {
        printk("request_region 0x%x failed!\n", lpc_cpld_base1);
		return -EBUSY;
	}
	
    return 0;
}

运行结果
下图即为上述代码运行后的LPC桥配置空间寄存器值及dump出来的CPLD IO地址空间内容。
LPC IO地址映射配置及运用_第5张图片

你可能感兴趣的:(X86)