i.MX8MP平台开发分享(IOMUX篇)- uboot驱动

专栏目录:专栏目录传送门

平台内核
i.MX8MP5.15.71

1. pinfunc.h

pinfunc.h中定义了所有的引脚,命名方式是MX8MP_IOMUXC___,例如下面的MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00定义了MUX寄存器偏移,PAD配置寄存器偏移,输入选择寄存器偏移,MUX模式,输入寄存器的值。如果是输出引脚,那么输入选择寄存器偏移就为0。

image-20221227135218724

我们在dts中设置的0x184值是设置PAD的电气属性。

pinctrl_gpio1: gpio1grp {
		fsl,pins = <
			MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00	0x184		/* SODIMM 206 */
		>;
};

2.iomux驱动

uboot中的pinctl驱动通过imx_pinctrl_probe来注册iomux功能,主要是IOMUX基地址。

int imx_pinctrl_probe(struct udevice *dev,
		      struct imx_pinctrl_soc_info *info)
{
	struct imx_pinctrl_priv *priv = dev_get_priv(dev);
	int node = dev_of_offset(dev), ret;
	fdt_addr_t addr;
	fdt_size_t size;

	priv->dev = dev;
	priv->info = info;

	addr = devfdt_get_addr_size_index(dev, 0, &size);

	info->base = map_sysmem(addr, size);

	priv->info = info;

	return 0;
}

驱动在device_probe的时候通过pinctrl_select_state来读取dtb中的pinctl信息,并配置gpio。

device_probe
->pinctrl_select_state
	->pinctrl_select_state_full
		->pinctrl_config_one
			->ops->set_state
				->imx_pinctrl_set_state

最后会调用各vendor定义的set_state函数,在这里是imx_pinctrl_set_state。下面我们就来看看pinctrl_select_state_full是如何一步步配置gpio的。

3.pinctrl_select_state_full

在了解软件流程之前,我们先以LED为例看看dts中的定义:

gpio-leds {
		compatible = "gpio-leds";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_gpio_led>;

		status {
			label = "yellow:status";
			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
			default-state = "on";
		};
	};

&iomuxc {
	pinctrl-names = "default";
    ....
        
    pinctrl_gpio_led: gpioledgrp {
		fsl,pins = <
			MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x19
		>;
	};
    
    ....
}

pinctrl-0使用的iomux配置是pinctrl_gpio_led,这个pinctrl_gpio_led定义在iomuxc节点内,fsl,pins定义了需要MUX的引脚列表。PAD电气特性设置为了0x19。

dev_read_stringlist_search会在这个设备的dts节点下搜索名为statename的"pinctrl-names",一般这个statename为“default”。如果是“default”,这里的dev_read_prop使用的propname就是“pinctrl-0”。根据这个name找到pinctrl_gpio_led,然后uclass_get_device_by_phandle_id找到iomuxc节点下的pinctrl_gpio_led

最后pinctrl_config_one中的set_state根据pinctrl_gpio_led中的配置内容,配置IOMUX寄存器。

static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
{

	state = dev_read_stringlist_search(dev, "pinctrl-names", statename);

	snprintf(propname, sizeof(propname), "pinctrl-%d", state);
	list = dev_read_prop(dev, propname, &size);
	
	size /= sizeof(*list);
	for (i = 0; i < size; i++) {
		phandle = fdt32_to_cpu(*list++);
		ret = uclass_get_device_by_phandle_id(UCLASS_PINCONFIG, phandle,
						      &config);
		ret = pinctrl_config_one(config);
	}

	return 0;
}

4.imx_pinctrl_set_state

上一节最后提到set_state会配置IOMUX寄存器。对于i.MX平台这里的set_state函数是imx_pinctrl_set_state。这一节我们重点分析寄存器设置过程。

pinctrl_gpio_led定义展开,我们可以看出,实际上fsl,pins等于<0x014 0x274 0x000 0x0 0x0 0x184>

pinctrl_gpio1: gpio1grp {
		fsl,pins = <
			//MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00	0x184
			<mux_reg conf_reg input_reg mux_mode input_val pad_conf_val>
			  0x014  0x274    0x000     0x0       0x0      0x184
		>;
};

一起来看看下面的imx_pinctrl_set_state是如何解析这些定义并设置寄存器的。

  1. 设置一个gpio配置占用的大小,如果是SCU,那么pin_size为12,如果是共享MUX和配置寄存器的话,一个gpio占用的pin_size为20,正常的gpio占用pin_size为24。这里的占用大小是指fsl,pins中一个gpio配置占用的大小,一个数值占用4比特。

    if (info->flags & IMX8_USE_SCU)
    		pin_size = SHARE_IMX8_PIN_SIZE;
    	else if (info->flags & SHARE_MUX_CONF_REG)
    		pin_size = SHARE_FSL_PIN_SIZE;
    	else
    		pin_size = FSL_PIN_SIZE;//一个gpio占用的大小24
    
  2. 获取"fsl,pins"占用的总大小,存储到size。

    prop = fdt_getprop(gd->fdt_blob, node, "fsl,pins", &size);
    
  3. 获取"fsl,pins"中的内容,存储到pin_data中,

    fdtdec_get_int_array(gd->fdt_blob, node, "fsl,pins",
    				 pin_data, size >> 2)
    
  4. 获取"fsl,pins"中引脚的个数

    npins = size / pin_size;
    
  5. 遍历引脚,配置寄存器。pin_data中依次存储 <mux_reg conf_reg input_reg mux_mode input_val pad_conf_val>

    • 依次获取mux_reg conf_reg input_reg mux_mode input_val pad_conf_val的数值,存储到对应名字的变量中。

    • 对于输出引脚,只需要设置mux和pad即可。但是有些i.MX芯片MUX和PAD寄存器是做进了一个寄存器,这种情况有一些特殊,我们使用clrsetbits_le32来设置一个寄存器中相应的位来写入MUX和PAD。

      writel(mux_mode, info->base + mux_reg);
      writel(config_val,info->base + conf_reg);
      
    • 对于输入引脚,需要配置输入选择寄存器。这里又细分为两种情况。①如果选择输入值以0xff开头,它是一个古怪的选择输入,其值应该被解释为如下。

      31      23     15      7       0
      | 0xff | shift | width | select |
      

      它是用来解决某些引脚的选择输入没有在选择输入寄存器中实现,而是在一些通用寄存器中实现的问题。我们将选择输入值、宽度和位域的移位编码到设备树中引脚功能ID的input_val单元中,然后在这里对它们进行解码,以便在通用寄存器中设置选择输入位。

      正常情况下,是直接写入寄存器。

      writel(input_val,info->base + input_reg);
      

以上我们就梳理完了IOMUX的核心功能~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漫游嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值