这里用的devm_ioremap与ioremap很相似,唯一的区别引用一下这个网页上的回复http://www.spinics.net/lists/devicetree/msg07744.html的:In the PCIv3 driver, use devm_ioremap() instead of just ioremap(). when remapping the system controller in the PCIv3 driver, so the mapping will be automatically released on probe failure.
而这里dbi_base经过对platform-imx-pcie.c中的分析,访问的是[ PCIE_ARB_END_ADDR - SZ_16K, PCIE_ARB_END_ADDR]这一段
/* FIXME the field name should be aligned to RM */
imx_pcie_clrset(IOMUXC_GPR12_APP_LTSSM_ENABLE, 0 << 10, IOMUXC_GPR12);
/* configure constant input signal to the pcie ctrl and phy */
if (pdata->type_ep & 1)
/* EP */
imx_pcie_clrset(IOMUXC_GPR12_DEVICE_TYPE,
PCI_EXP_TYPE_ENDPOINT << 12, IOMUXC_GPR12);
else
/* RC */
imx_pcie_clrset(IOMUXC_GPR12_DEVICE_TYPE,
PCI_EXP_TYPE_ROOT_PORT << 12, IOMUXC_GPR12);
imx_pcie_clrset(IOMUXC_GPR12_LOS_LEVEL, 9 << 4, IOMUXC_GPR12);
imx_pcie_clrset(IOMUXC_GPR8_TX_DEEMPH_GEN1, 0 << 0, IOMUXC_GPR8);
imx_pcie_clrset(IOMUXC_GPR8_TX_DEEMPH_GEN2_3P5DB, 0 << 6, IOMUXC_GPR8);
imx_pcie_clrset(IOMUXC_GPR8_TX_DEEMPH_GEN2_6DB, 20 << 12, IOMUXC_GPR8);
imx_pcie_clrset(IOMUXC_GPR8_TX_SWING_FULL, 127 << 18, IOMUXC_GPR8);
imx_pcie_clrset(IOMUXC_GPR8_TX_SWING_LOW, 127 << 25, IOMUXC_GPR8);
寄存器配置,其中对于PCIE的link成功与否比较关键的就是IOMUXC_GPR8和IOMUXC_GPR12,不过在reference manual中IOMUXC_GPR12的值已经被定死了,所以只能调节IOMUXC_GPR8了。
这里imx_pcie_clrset是一个内联函数,定义如下:
/* IMX PCIE GPR configure routines */
static inline void imx_pcie_clrset(u32 mask, u32 val, void __iomem *addr)
{
writel(((readl(addr) & ~mask) | (val & mask)), addr);
}
鉴于这里已经可以直接对地址进行直接读写,那么这块内存区域就已经被映射过了。找到IOMUXC_GPR8的定义,在arch/arm/mach-mx6/crm_regs.h文件中:
/* IOMUXC */
#define MXC_IOMUXC_BASE
MX6_IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR)
…………
#define IOMUXC_GPR8
(MXC_IOMUXC_BASE + 0x20)
这里MX6Q_IOMUXC_BASE_ADDR被定义在arch/arm/plat-mxc/include/mach/mx6.h中:
#define AIPS1_ARB_BASE_ADDR
0x02000000
………………
#define ATZ1_BASE_ADDR
AIPS1_ARB_BASE_ADDR
…………
#define AIPS1_OFF_BASE_ADDR
(ATZ1_BASE_ADDR + 0x80000)
…………
#define MX6Q_IOMUXC_BASE_ADDR
(AIPS1_OFF_BASE_ADDR + 0x60000)
最终的值也就是0x0200_0000+0x8_0000+0x6_0000 = 0x020E_0000,参考i.MX6Q reference manual可以找到IOMUXC寄存器范围:[020E_0000, 020E_3FFF] 这里和驱动相对应。
而MX6_IO_ADDRESS的定义在arch/arm/plat-mxc/include/mach/mx6.h中,定义如下的:
#define PERIPBASE_VIRT
0xF2000000
…………
#define MX6_IO_ADDRESS(x) (void __force __iomem *)((x) + PERIPBASE_VIRT)
基本上就是对基地址的一个偏移量。
注意:直接这样访问是无效的,首先必须要在MMU中建立页表映射到这段地址,即ioremap以后才可以从内核空间访问(这里能访问是因为这块地址之前肯定已经映射过了),只不过映射之后的关系是物理地址增加一个偏移量而已。
/* Enable the pwr, clks and so on */
imx_pcie_enable_controller(dev);
如注释所言,使能pcie的电源和时钟等,由于i.mx是由fuse100来供电的,因此需要通过GPIO的某个引脚来控制供电开关。这个函数很关键,下面简单介绍一下, 本身也不长。
/* Enable PCIE power */
gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN");
/* activate PCIE_PWR_EN */
gpio_direction_output(pdata->pcie_pwr_en, 1);
imx_pcie_clrset(IOMUXC_GPR1_TEST_POWERDOWN, 0 << 18, IOMUXC_GPR1);