JTAG0引脚复用GPIO问题

1.问题描述

在通过GPIO模拟I2C时序的问题,要用到PG11这个引脚,而这个引脚默认是JTAG0的TDO,所在在加载ko模块时,会现现

# echo 203 > export 
[***liuyouhua-debug***] offset: 203 group: 6 numl: 11 num: 3 value: 0x7
Please Check GPIOG11's multi-function = 0x7 

注:203是PG11对应的CPU引脚封装号,定义在$(KERN-DIR)/arch/arm/mach-nuc980/include/mach/gpio.h中:

#define	NUC980_PG11	(0xC0 + 11)
#define	NUC980_PG12	(0xC0 + 12)
#define	NUC980_PG13	(0xC0 + 13)
#define	NUC980_PG14	(0xC0 + 14)
#define	NUC980_PG15	(0xC0 + 15)

2. 问题分析

通过跟踪内核代码发现,PG11没有得到$(KERN-DIR)/drivers/pinctrl-nuc980.c里nuc980_set_mux函数的处理:

/*
 * selector = data.nux.func, which is entry number in nuc980_functions,
 * and group = data.mux.group, which is entry number in nuc980_pmx_func
 * group is not used since some function use different setting between
 * different ports. for example UART....
 */
int nuc980_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
                  unsigned group)
{
	unsigned int i, j;
	unsigned int reg, offset;

	for(i = 0; i < nuc980_pinctrl_groups[group].num_pins; i++) {
		j = nuc980_pinctrl_groups[group].pins[i];
		offset = (j >> 4) * 8 + ((j & 0x8) ? 4 : 0); //计算j在REG_MFP_GPX定义中的偏移

		reg = __raw_readl(REG_MFP_GPA_L + offset);
		reg = (reg & ~(0xF << ((j & 0x7) * 4))) | (nuc980_pinctrl_groups[group].func << ((j & 0x7) * 4));

		__raw_writel(reg, REG_MFP_GPA_L + offset);
	}

	
	return 0;
}
  • reg是获取对应的REG_MFP_GPx_x配置参数,如获取PG11是0x77777000
  • nuc980_pinctrl_groups[group].func对应nuc980_pinctrl_groups[]中的func
  • nuc980_pinctrl_groups数组在$(KERN-DIR)/drivers/pinctrl/pinctrl-nuc980.c定义,其中0x6B对应的PG11的定义:
const struct pinctrl_pin_desc nuc980_pins[] = {
    //......
	PINCTRL_PIN(0x6B, "PG11"),
	PINCTRL_PIN(0x6C, "PG12"),
	PINCTRL_PIN(0x6D, "PG13"),
	PINCTRL_PIN(0x6E, "PG14"),
	PINCTRL_PIN(0x6F, "PG15"),
};

static const unsigned jtag0_pins[] = {0x6B, 0x6C, 0x6D, 0x6E, 0x6F};

static const struct nuc980_pinctrl_group nuc980_pinctrl_groups[] = {
    //......
	{
		.name = "jtag0_grp",
		.pins = jtag0_pins,
		.num_pins = ARRAY_SIZE(jtag0_pins),
		.func = 0x7,
	},
   //......
};
  • group参数对应nuc980_pinctrl_groups数据下标,由于我在$(KERN-DIR)/arch/arm/mach-nuc980/dev.c中关闭了所有引脚PG11的设备注册,所以PG11的nuc980_set_mux并没有得到调用。
  • offset = (j >> 4) * 8 + ((j & 0x8) ? 4 : 0);根据j参数出对应的REG_MFP_GPx_L/H,REG_MFP_GPx定义在$(KERN-DIR)/arch/arm/mach-nuc980/include/mach/regs-gcc.h中:
#define REG_MFP_GPA_L	(GCR_BA+0x070)	/* GPIOA Low Byte Multiple Function Control Register */
#define REG_MFP_GPA_H	(GCR_BA+0x074)	/* GPIOA High Byte Multiple Function Control Register */
#define REG_MFP_GPB_L	(GCR_BA+0x078)	/* GPIOB Low Byte Multiple Function Control Register */
#define REG_MFP_GPB_H	(GCR_BA+0x07C)	/* GPIOB High Byte Multiple Function Control Register */
#define REG_MFP_GPC_L	(GCR_BA+0x080)	/* GPIOC Low Byte Multiple Function Control Register */
#define REG_MFP_GPC_H	(GCR_BA+0x084)	/* GPIOC High Byte Multiple Function Control Register */
#define REG_MFP_GPD_L	(GCR_BA+0x088)	/* GPIOD Low Byte Multiple Function Control Register */
#define REG_MFP_GPD_H	(GCR_BA+0x08C)	/* GPIOD High Byte Multiple Function Control Register */
#define REG_MFP_GPE_L	(GCR_BA+0x090)	/* GPIOE Low Byte Multiple Function Control Register */
#define REG_MFP_GPE_H	(GCR_BA+0x094)	/* GPIOE High Byte Multiple Function Control Register */
#define REG_MFP_GPF_L	(GCR_BA+0x098)	/* GPIOF Low Byte Multiple Function Control Register */
#define REG_MFP_GPF_H	(GCR_BA+0x09C)	/* GPIOF High Byte Multiple Function Control Register */
#define REG_MFP_GPG_L	(GCR_BA+0x0A0)	/* GPIOG Low Byte Multiple Function Control Register */
#define REG_MFP_GPG_H	(GCR_BA+0x0A4)	/* GPIOG High Byte Multiple Function Control Register */
#define REG_MFP_GPH_L	(GCR_BA+0x0A8)	/* GPIOH Low Byte Multiple Function Control Register */
#define REG_MFP_GPH_H	(GCR_BA+0x0AC)	/* GPIOH High Byte Multiple Function Control Register */
#define REG_MFP_GPI_L	(GCR_BA+0x0B0)	/* GPIOI Low Byte Multiple Function Control Register */
#define REG_MFP_GPI_H	(GCR_BA+0x0B4)	/* GPIOI High Byte Multiple Function Control Register */
#define REG_MFP_GPJ_L	(GCR_BA+0x0B8)	/* GPIOJ Low Byte Multiple Function Control Register */
#define REG_DDR_DS_CR	(GCR_BA+0x0E0)	/* DDR I/O Driving Strength Control Register */
#define REG_PORDISCR    (GCR_BA+0x100)	/* Power-On-Reset Disable Control Register */
#define REG_ICEDBGCR    (GCR_BA+0x104)	/* ICE Debug Interface Control Register */
#define REG_WRPRTR		(GCR_BA+0x1FC)	/* Register Write-Protection Control Register */

实例解析PG11:

  • jtag0_pins[]中定义PG11的是0x6B,因此offset = (j >> 4) * 8 + ((j & 0x8) ? 4 : 0)中j的值是0x6B;
  • j>>4计算出0x6B所属GPIO组(0x6B对应REG_MFP_GPG组);
  • (j >> 4) * 8的8代表8个字节,具体查看《NUC980_Technical_Rev》中System Manager的Register Description段(如下图);
  • ((j & 0x8) ? 4 : 0)计算是REG_MFP_GPx_L还是REG_MFP_GPx_H。

JTAG0引脚复用GPIO问题_第1张图片

JTAG0引脚复用GPIO问题_第2张图片

 

 

3.解决方法

在驱动模块内,自己封装GPIO的set_mux,如:

int nuc980_gpio_set_mux(unsigned int gpio_num)
{
	unsigned int reg, offset;

    offset = (gpio_num >> 4) * 8 + ((gpio_num & 0x8) ? 4 : 0); //计算j在REG_MFP_GPX定义中的偏移

    reg = __raw_readl(REG_MFP_GPA_L + offset);
    reg = (reg & ~(0xF << ((gpio_num & 0x7) * 4))) | (0x0 << ((gpio_num & 0x7) * 4));

    __raw_writel(reg, REG_MFP_GPA_L + offset);

	return 0;
}
  • gpio_num参数在$(KERN-DIR)/drivers/pinctrl/pinctrl-nuc980.c中定义:

    PINCTRL_PIN(0x6B, "PG11"),
    PINCTRL_PIN(0x6C, "PG12"),
    PINCTRL_PIN(0x6D, "PG13"),
    PINCTRL_PIN(0x6E, "PG14"),
    PINCTRL_PIN(0x6F, "PG15"),

  • 调用方法:

nuc980_gpio_set_mux(0x6B);

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Nuvoton,机器学习)