PADMUX USER GUIDE
REVISION HISTORY¶
| Revision No. | Description |
Date |
|---|---|---|
| 1.0 | 04/18/2023 | |
| 1.1 | 03/31/2025 |
1. Overview¶
Padmux is a linux platform driver located in kernel\drivers\sstar\padmux. Because of the multiplexing of gpio pins, usually the same gpio can be used for different functions, so we use the padmux driver to uniformly configure the gpio pin functions to be used when booting.
2. Keyword¶
Please refer to GPIO keyword
3. Function Description¶
- Reuse the specified pad to the specified mode
- Manage the disciplinary reuse of chips
4. Hardware Connection¶
Padmux is a software behavior with no hardware connection.
5. Uboot USE PADMUX¶
The same as Kernel
6. Kernel USE PADMUX¶
Padmux driver definition as follows:
static struct platform_driver sstar_padmux_driver = {
.driver =
{
.name = "padmux",
.owner = THIS_MODULE,
.of_match_table = sstar_padmux_of_match,
.pm = &sstar_padmux_pm_ops,
},
.probe = sstar_padmux_probe,
};
The members who need attention are as follows, and they will be introduced below.
sstar_padmux_of_match sstar_padmux_pm_ops sstar_padmux_probe
6.1. sstar_padmux_of_match¶
Used to match the gpio table device that needs to be configured for startup:
static const struct of_device_id sstar_padmux_of_match[] = {
{.compatible = "sstar,padmux"},
{},
};
Match the device in dts (for example: kernel\arch\arm64\boot\dts\sstar\pcupid-ssm001a-s01a-padmux.dtsi) through sstar-padmux:
padmux {
compatible = "sstar,padmux";
schematic =
//I2C0 Mode1,sensorif_mipi_grp0_i2c
<PAD_I2C0_SDA PINMUX_FOR_I2C0_MODE_1 MDRV_PUSE_I2C0_SDA>,
<PAD_I2C0_SCL PINMUX_FOR_I2C0_MODE_1 MDRV_PUSE_I2C0_SCL>,
//I2C1 Mode1,sensorif_mipi_grp1_i2c
<PAD_I2C1_SCL PINMUX_FOR_I2C1_MODE_1 MDRV_PUSE_I2C1_SCL>,
<PAD_I2C1_SDA PINMUX_FOR_I2C1_MODE_1 MDRV_PUSE_I2C1_SDA>,
//ToucheScreen goodix
<PAD_I2C5_SCL PINMUX_FOR_I2C5_MODE_1 MDRV_PUSE_I2C5_SCL>,
<PAD_I2C5_SDA PINMUX_FOR_I2C5_MODE_1 MDRV_PUSE_I2C5_SDA>,
<GPIO_NR PINMUX_FOR_UNKNOWN_MODE MDRV_PUSE_NA>;
status = "ok"; // ok or disable
};
6.2. sstar_padmux_pm_ops¶
Implement the resume and suspend functions corresponding to str standby:
static const struct dev_pm_ops sstar_padmux_pm_ops = {
.suspend_late = sstar_padmux_suspend,
.resume_early = sstar_padmux_resume,
};
6.3. Sstar_padmux_probe¶
After matching the padmux device, the system will call sstar_padmux_probe to configure the gpio function:
static int sstar_padmux_probe(struct platform_device *pdev)
{
_mdrv_padmux_dts(pdev->dev.of_node);
return 0;
}
static int _mdrv_padmux_dts(struct device_node *np)
{
int nPad;
if (0 >= (nPad = of_property_count_elems_of_size(np, PADINFO_NAME, sizeof(pad_info_t))))
{
PAD_PRINT("[%s][%d] invalid dts of padmux.schematic\n", __FUNCTION__, __LINE__);
return -1;
}
if (NULL == (_pPadInfo = kmalloc(nPad * sizeof(pad_info_t), GFP_KERNEL)))
{
PAD_PRINT("[%s][%d] kmalloc fail\n", __FUNCTION__, __LINE__);
return -1;
}
if (of_property_read_u32_array(np, PADINFO_NAME, (u32 *)_pPadInfo, nPad * sizeof(pad_info_t) / sizeof(U32)))
{
PAD_PRINT("[%s][%d] of_property_read_u32_array fail\n", __FUNCTION__, __LINE__);
kfree(_pPadInfo);
_pPadInfo = NULL;
return -1;
}
_nPad = nPad;
{
int i;
PAD_PRINT("[%s][%d] *******************************\n", __FUNCTION__, __LINE__);
for (i = 0; i < _nPad; i++)
{
PAD_PRINT("[%s][%d] (PadId, Mode, Puse) = (%d, 0x%02x, 0x%08x)\n", __FUNCTION__, __LINE__,
_pPadInfo[i].u32PadId, _pPadInfo[i].u32Mode, _pPadInfo[i].u32Puse);
sstar_gpio_pad_val_set((U8)_pPadInfo[i].u32PadId & 0xFF, _pPadInfo[i].u32Mode);
}
PAD_PRINT("[%s][%d] *******************************\n", __FUNCTION__, __LINE__);
}
return 0;
}
Finally, sstar_gpio_pad_val_set is used to configure gpio to the corresponding function:
kernel\drivers\sstar\gpio\drv_gpio.c
u8 sstar_gpio_pad_val_set(u8 gpio_index, u32 pad_mode)
{
return hal_gpio_pad_val_set(gpio_index, pad_mode);
}
kernel\drivers\sstar\gpio\pcupid\hal_gpio.c
u8 hal_gpio_pad_val_set(u8 gpio_index, u32 pad_mode)
{
return hal_gpio_pad_set_val((u32)gpio_index, pad_mode);
}
kernel\drivers\sstar\gpio\pcupid\hal_pinmux.c
s32 hal_gpio_pad_set_val(u32 pad_id, u32 mode)
{
if (FALSE == hal_gpio_check_pin(pad_id))
{
return 1;
}
else
{
return hal_gpio_pad_set_mode_general(pad_id, mode);
}
}
static s32 hal_gpio_pad_set_mode_general(u32 pad_id, u32 mode)
{
u64 reg_addr = 0;
u16 reg_val = 0;
u8 mode_is_find = 0;
u16 i, ext_item_id = 0;
for (i = 0; i < m_hal_gpio_st_padmux_entry[pad_id].size; i++)
{
reg_addr = _RIUA_16BIT(m_hal_gpio_st_padmux_entry[pad_id].padmux[i].base,
m_hal_gpio_st_padmux_entry[pad_id].padmux[i].offset);
if (mode == m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mode)
{
reg_val = _GPIO_R_WORD_MASK(reg_addr, 0xFFFF);
reg_val &= ~(m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mask);
reg_val |= m_hal_gpio_st_padmux_entry[pad_id].padmux[i].val; // CHECK Multi-Pad Mode
_GPIO_W_WORD_MASK(reg_addr, reg_val, 0xFFFF);
mode_is_find = 1;
pad_mode_recoder[pad_id] = mode;
#if (ENABLE_CHECK_ALL_PAD_CONFLICT == 0)
break;
#endif
}
/*else if ((m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mode >= PINMUX_FOR_PM_PAD_EXT_MODE0_1)
&& (m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mode <= PINMUX_FOR_PM_PAD_EXT_MODE51_1))
{
ext_item_id = i;
}*/
/*else if ((m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mode >= PINMUX_FOR_SPI_EXT_EN_MODE0_1)
&& (m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mode <= PINMUX_FOR_SPI_EXT_EN_MODE5_1))
{
ext_item_id = i;
}*/
else
{
if ((mode == PINMUX_FOR_GPIO_MODE)
&& (m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mode > PRIORITY_GREATER_GPIO))
continue;
reg_val = _GPIO_R_WORD_MASK(reg_addr, m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mask);
if (reg_val == m_hal_gpio_st_padmux_entry[pad_id].padmux[i].val)
{
hal_pinmux_info(
"[Padmux]reset PAD%d(reg 0x%x:%x; mask0x%x) t0 %s (org: %s)\n", pad_id,
m_hal_gpio_st_padmux_entry[pad_id].padmux[i].base,
m_hal_gpio_st_padmux_entry[pad_id].padmux[i].offset,
m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mask, m_hal_gpio_st_padmode_info_tbl[mode].pad_name,
m_hal_gpio_st_padmode_info_tbl[m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mode].pad_name);
if (m_hal_gpio_st_padmux_entry[pad_id].padmux[i].val != 0)
{
_GPIO_W_WORD_MASK(reg_addr, 0, m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mask);
}
else
{
_GPIO_W_WORD_MASK(reg_addr, m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mask,
m_hal_gpio_st_padmux_entry[pad_id].padmux[i].mask);
}
}
}
}
if ((mode_is_find) && (ext_item_id))
{
// set external data mode
reg_addr = _RIUA_16BIT(m_hal_gpio_st_padmux_entry[pad_id].padmux[ext_item_id].base,
m_hal_gpio_st_padmux_entry[pad_id].padmux[ext_item_id].offset);
reg_val = _GPIO_R_WORD_MASK(reg_addr, 0xFFFF);
reg_val &= ~(m_hal_gpio_st_padmux_entry[pad_id].padmux[ext_item_id].mask);
reg_val |= m_hal_gpio_st_padmux_entry[pad_id].padmux[ext_item_id].val; // CHECK Multi-Pad Mode
_GPIO_W_WORD_MASK(reg_addr, reg_val, 0xFFFF);
}
return (mode_is_find) ? 0 : 1;
}
Find the reg corresponding to the gpio and mode settings that need to be configured in the corresponding subtable in m_hal_gpio_st_padmux_entry.
Take PAD_GPIOB_00 configured as PINMUX_FOR_I2C0_MODE_4 as an example:
When configured in dts padmux:
<PAD_GPIOB_00 PINMUX_FOR_I2C0_MODE_4 MDRV_PUSE_I2C0_SCL>, <PAD_GPIOB_01 PINMUX_FOR_I2C0_MODE_4 MDRV_PUSE_I2C0_SDA>,
When probing, the register bank 0x103c offset 0x6f bit2 is set to 1 according to the register setting of gpiob_00_tbl in m_hal_gpio_st_padmux_entry, and the mask value of bit0~bit2 is 4, so it is configured as i2c mode4:
#define PADTOP_BANK 0x103C00
#define REG_I2C0_MODE 0x6f
#define REG_I2C0_MODE_MASK BIT0 | BIT1 | BIT2
{PAD_GPIOB_00, PADTOP_BANK, REG_I2Cf0_MODE, REG_I2C0_MODE_MASK, BIT2, PINMUX_FOR_I2C0_MODE_4}, you can confirm whether the setting is effective by reading reg on the board
6.4. How to Use Padmux DTS File¶
Through the introduction of padmux driver above, we know that as long as we confirm that padmux driver is enabled and write the pin and corresponding mode to be configured in dts, the corresponding gpio function will be configured when padmux probe is turned on. It should be noted that pamdux driver depends on gpio driver, so both drivers must be built into kernel. At present, the default configuration of gpio and padmux on the public board has buildin which is turned on by default:
CONFIG_SSTAR_PADMUX CONFIG_SSTAR_GPIO
The following describes how to configure the corresponding gpio function in padmux of dts.
6.5. Which Padmux DTS File to Use¶
The kernel config file determines which padmux dts file to use according to the flow below.
kernel\arch\arm64\configs\pcupid_ssm001a_s01a_emmc_defconfig:
CONFIG_SSTAR_DTB_NAME="pcupid-ssm001a-s01a"
kernel\arch\arm64\boot\dts\sstar\pcupid-ssm001a-s01a.dts:
#include "pcupid.dtsi" #include "pcupid-ssm001a-s01a-padmux.dtsi"
kernel\arch\arm64\boot\dts\sstar\pcupid-ssm001a-s01a-padmux.dtsi
6.6. Configure GPIO Mode¶
According to the hardware release document 'HW Checklist' of the SDK release (refer to the file name of the SDK release package for the specific version), find the padmux column;
Take configuring PAD_GPIOB_00 to I2C0 as an example, you can see that PAD_GPIOB_00 can only be configured to I2C0 mode 4 to be configured to I2C0, so configure it in padmux dts as follows:
<PAD_GPIOB_00 PINMUX_FOR_I2C0_MODE_4 MDRV_PUSE_I2C0_SCL>, <PAD_GPIOB_01 PINMUX_FOR_I2C0_MODE_4 MDRV_PUSE_I2C0_SDA>,
MDRV_PUSE_I2C0_SCL is generally only used for explanation and comment and has no special use, unless the corresponding function driver has special settings. For other i2c, spi, uart, ttl, mipi settings, you can also refer to the hw checklist in the padmux dts configuration.
6.7. NOTE¶
The same gpio pin can only be reused as one function and cannot be configured as two functions in padmux at the same time. If the function configured in padmux does not take effect, you need to confirm in dts whether it is configured as other functions.
7. API Reference¶
Please refer to GPIO API Reference
8. FAQ¶
Please refer to GPIO FAQ