PADMUX USER GUIDE


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/18/2023
    1.1
  • Add Chapter VIII DEBUG&FAQ
  • 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