pinmux.c

Here is pinmux.c. work in progress. hope it’s useful to someone. wrote it learning about the Beaglebone Black.

typical pinmux output
GPIO | Pin Name | Address | Offset | Value | Mode | PCR
gpio0:0 | GPMC_AD0 P8.25 | 0x44e10800 | 0x0800 | 0x31 | 1 | FRXPULLUP
gpio0:1 | GPMC_AD1 P8.24 | 0x44e10804 | 0x0804 | 0x31 | 1 | FRXPULLUP
gpio0:2 | GPMC_AD2 P8.5 | 0x44e10808 | 0x0808 | 0x31 | 1 | FRXPULLUP
gpio0:3 | GPMC_AD3 P8.6 | 0x44e1080c | 0x080c | 0x31 | 1 | FRXPULLUP
gpio0:4 | GPMC_AD4 P8.23 | 0x44e10810 | 0x0810 | 0x31 | 1 | FRXPULLUP
gpio0:5 | GPMC_AD5 P8.22 | 0x44e10814 | 0x0814 | 0x31 | 1 | FRXPULLUP
gpio0:6 | GPMC_AD6 P8.3 | 0x44e10818 | 0x0818 | 0x31 | 1 | FRXPULLUP
gpio0:7 | GPMC_AD7 P8.4 | 0x44e1081c | 0x081c | 0x31 | 1 | FRXPULLUP
gpio3:22 | GPMC_AD8 P8.19 | 0x44e10820 | 0x0820 | 0x27 | 7 | FRXPULLDN
gpio3:23 | GPMC_AD9 P8.13 | 0x44e10824 | 0x0824 | 0x27 | 7 | FRXPULLDN
gpio3:26 | GPMC_AD10 P8.14 | 0x44e10828 | 0x0828 | 0x27 | 7 | FRXPULLDN
gpio3:27 | GPMC_AD11 P8.17 | 0x44e1082c | 0x082c | 0x27 | 7 | FRXPULLDN
gpio0:12 | GPMC_AD12 P8.12 | 0x44e10830 | 0x0830 | 0x27 | 7 | FRXPULLDN
gpio0:13 | GPMC_AD13 P8.11 | 0x44e10834 | 0x0834 | 0x27 | 7 | FRXPULLDN
gpio0:14 | GPMC_AD14 P8.16 | 0x44e10838 | 0x0838 | 0x27 | 7 | FRXPULLDN
gpio0:15 | GPMC_AD15 P8.15 | 0x44e1083c | 0x083c | 0x27 | 7 | FRXPULLDN
gpio0:16 | GPMC_A0 P9.15 | 0x44e10840 | 0x0840 | 0x27 | 7 | FRXPULLDN
gpio0:17 | GPMC_A1 P9.23 | 0x44e10844 | 0x0844 | 0x27 | 7 | FRXPULLDN
gpio0:18 | GPMC_A2 P9.14 | 0x44e10848 | 0x0848 | 0x27 | 7 | FRXPULLDN
gpio0:19 | GPMC_A3 P9.16 | 0x44e1084c | 0x084c | 0x27 | 7 | FRXPULLDN

hmmm seemed to line up in the shell, :slight_smile:

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "am33xx.h" // get the header file from the source code

// Structure to map offset to pin name
typedef struct {
    const char *name;
    uint32_t offset;
} pin_map_t;


pin_map_t am33xx_pins[] = {
    {"GPMC_AD0 P8.25", AM335X_PIN_GPMC_AD0},
    {"GPMC_AD1 P8.24", AM335X_PIN_GPMC_AD1},
    {"GPMC_AD2 P8.5", AM335X_PIN_GPMC_AD2},
    {"GPMC_AD3 P8.6", AM335X_PIN_GPMC_AD3},
    {"GPMC_AD4 P8.23", AM335X_PIN_GPMC_AD4},
    {"GPMC_AD5 P8.22", AM335X_PIN_GPMC_AD5},
    {"GPMC_AD6 P8.3", AM335X_PIN_GPMC_AD6},
    {"GPMC_AD7 P8.4", AM335X_PIN_GPMC_AD7},
    {"GPMC_AD8 P8.19", AM335X_PIN_GPMC_AD8},
    {"GPMC_AD9 P8.13", AM335X_PIN_GPMC_AD9},
    {"GPMC_AD10 P8.14", AM335X_PIN_GPMC_AD10},
    {"GPMC_AD11 P8.17", AM335X_PIN_GPMC_AD11},
    {"GPMC_AD12 P8.12", AM335X_PIN_GPMC_AD12},
    {"GPMC_AD13 P8.11", AM335X_PIN_GPMC_AD13},
    {"GPMC_AD14 P8.16", AM335X_PIN_GPMC_AD14},
    {"GPMC_AD15 P8.15", AM335X_PIN_GPMC_AD15},
    {"GPMC_A0 P9.15", AM335X_PIN_GPMC_A0},
    {"GPMC_A1 P9.23", AM335X_PIN_GPMC_A1},
    {"GPMC_A2 P9.14", AM335X_PIN_GPMC_A2},
    {"GPMC_A3 P9.16", AM335X_PIN_GPMC_A3},
    {"GPMC_A4 ", AM335X_PIN_GPMC_A4},
    {"GPMC_A5 ", AM335X_PIN_GPMC_A5},
    {"GPMC_A6 ", AM335X_PIN_GPMC_A6},
    {"GPMC_A7 ", AM335X_PIN_GPMC_A7},
    {"GPMC_A8 ", AM335X_PIN_GPMC_A8},
    {"GPMC_A9 ", AM335X_PIN_GPMC_A9},
    {"GPMC_A10 ", AM335X_PIN_GPMC_A10},
    {"GPMC_A11 ", AM335X_PIN_GPMC_A11},
    {"GPMC_WAIT0 P9.11", AM335X_PIN_GPMC_WAIT0},
    {"GPMC_WPN P9.13", AM335X_PIN_GPMC_WPN},
    {"GPMC_BEN1 P9.12", AM335X_PIN_GPMC_BEN1},
    {"GPMC_CSN0 P8.26", AM335X_PIN_GPMC_CSN0},
    {"GPMC_CSN1 P8.21", AM335X_PIN_GPMC_CSN1},
    {"GPMC_CSN2 P8.20", AM335X_PIN_GPMC_CSN2},
    {"GPMC_CSN3 ", AM335X_PIN_GPMC_CSN3},
    {"GPMC_CLK P8.18", AM335X_PIN_GPMC_CLK},
    {"GPMC_ADVN_ALE P8.7", AM335X_PIN_GPMC_ADVN_ALE},
    {"GPMC_OEN_REN P8.8", AM335X_PIN_GPMC_OEN_REN},
    {"GPMC_WEN P8.10", AM335X_PIN_GPMC_WEN},
    {"GPMC_BEN0_CLE P8.9", AM335X_PIN_GPMC_BEN0_CLE},
    {"LCD_DATA0 ", AM335X_PIN_LCD_DATA0},
    {"LCD_DATA1 P8.46", AM335X_PIN_LCD_DATA1},
    {"LCD_DATA2 P8.43", AM335X_PIN_LCD_DATA2},
    {"LCD_DATA3 P8.44", AM335X_PIN_LCD_DATA3},
    {"LCD_DATA4 P8.41", AM335X_PIN_LCD_DATA4},
    {"LCD_DATA5 P8.42", AM335X_PIN_LCD_DATA5},
    {"LCD_DATA6 P8.39", AM335X_PIN_LCD_DATA6},
    {"LCD_DATA7 P8.40", AM335X_PIN_LCD_DATA7},
    {"LCD_DATA8 P8.37", AM335X_PIN_LCD_DATA8},
    {"LCD_DATA9 P8.38", AM335X_PIN_LCD_DATA9},
    {"LCD_DATA10 P8.36", AM335X_PIN_LCD_DATA10},
    {"LCD_DATA11 P8.34", AM335X_PIN_LCD_DATA11},
    {"LCD_DATA12 P8.35", AM335X_PIN_LCD_DATA12},
    {"LCD_DATA13 P8.33", AM335X_PIN_LCD_DATA13},
    {"LCD_DATA14 P8.31", AM335X_PIN_LCD_DATA14},
    {"LCD_DATA15 P8.32", AM335X_PIN_LCD_DATA15},
    {"LCD_VSYNC P8.27", AM335X_PIN_LCD_VSYNC},
    {"LCD_HSYNC P8.29", AM335X_PIN_LCD_HSYNC},
    {"LCD_PCLK P8.28", AM335X_PIN_LCD_PCLK},
    {"LCD_AC_BIAS_EN P8.30", AM335X_PIN_LCD_AC_BIAS_EN},
    {"MMC0_DAT3 ", AM335X_PIN_MMC0_DAT3},
    {"MMC0_DAT2 ", AM335X_PIN_MMC0_DAT2},
    {"MMC0_DAT1 ", AM335X_PIN_MMC0_DAT1},
    {"MMC0_DAT0 ", AM335X_PIN_MMC0_DAT0},
    {"MMC0_CLK ", AM335X_PIN_MMC0_CLK},
    {"MMC0_CMD ", AM335X_PIN_MMC0_CMD},
    {"MII1_COL ", AM335X_PIN_MII1_COL},
    {"MII1_CRS ", AM335X_PIN_MII1_CRS},
    {"MII1_RX_ER ", AM335X_PIN_MII1_RX_ER},
    {"MII1_TX_EN ", AM335X_PIN_MII1_TX_EN},
    {"MII1_RX_DV ", AM335X_PIN_MII1_RX_DV},
    {"MII1_TXD3 ", AM335X_PIN_MII1_TXD3},
    {"MII1_TXD2 ", AM335X_PIN_MII1_TXD2},
    {"MII1_TXD1 ", AM335X_PIN_MII1_TXD1},
    {"MII1_TXD0 ", AM335X_PIN_MII1_TXD0},
    {"MII1_TX_CLK ", AM335X_PIN_MII1_TX_CLK},
    {"MII1_RX_CLK ", AM335X_PIN_MII1_RX_CLK},
    {"MII1_RXD3 ", AM335X_PIN_MII1_RXD3},
    {"MII1_RXD2 ", AM335X_PIN_MII1_RXD2},
    {"MII1_RXD1 ", AM335X_PIN_MII1_RXD1},
    {"MII1_RXD0 ", AM335X_PIN_MII1_RXD0},
    {"RMII1_REF_CLK ", AM335X_PIN_RMII1_REF_CLK},
    {"MDIO ", AM335X_PIN_MDIO},
    {"MDC ", AM335X_PIN_MDC},
    {"SPI0_SCLK P9.22", AM335X_PIN_SPI0_SCLK},
    {"SPI0_D0 P9.21", AM335X_PIN_SPI0_D0},
    {"SPI0_D1 P9.18", AM335X_PIN_SPI0_D1},
    {"SPI0_CS0 P9.17", AM335X_PIN_SPI0_CS0},
    {"SPI0_CS1 ", AM335X_PIN_SPI0_CS1},
    {"ECAP0_IN_PWM0_OUT P9.42", AM335X_PIN_ECAP0_IN_PWM0_OUT},
    {"UART0_CTSN ", AM335X_PIN_UART0_CTSN},
    {"UART0_RTSN ", AM335X_PIN_UART0_RTSN},
    {"UART0_RXD ", AM335X_PIN_UART0_RXD},
    {"UART0_TXD ", AM335X_PIN_UART0_TXD},
    {"UART1_CTSN P9.20", AM335X_PIN_UART1_CTSN},
    {"UART1_RTSN P9.19", AM335X_PIN_UART1_RTSN},
    {"UART1_RXD P9.26", AM335X_PIN_UART1_RXD},
    {"UART1_TXD P9.24", AM335X_PIN_UART1_TXD},
    {"I2C0_SDA ", AM335X_PIN_I2C0_SDA},
    {"I2C0_SCL ", AM335X_PIN_I2C0_SCL},
    {"MCASP0_ACLKX P9.31", AM335X_PIN_MCASP0_ACLKX},
    {"MCASP0_FSX ", AM335X_PIN_MCASP0_FSX},
    {"MCASP0_AXR0 P9.30", AM335X_PIN_MCASP0_AXR0},
    {"MCASP0_AHCLKR P9.25", AM335X_PIN_MCASP0_AHCLKR},
    {"MCASP0_ACLKR P9.42", AM335X_PIN_MCASP0_ACLKR},
    {"MCASP0_FSR P9.27", AM335X_PIN_MCASP0_FSR},
    {"MCASP0_AXR1 P9.41", AM335X_PIN_MCASP0_AXR1},
    {"MCASP0_AHCLKX ", AM335X_PIN_MCASP0_AHCLKX},
    {"XDMA_EVENT_INTR0 ", AM335X_PIN_XDMA_EVENT_INTR0},
    {"XDMA_EVENT_INTR1 P9.41", AM335X_PIN_XDMA_EVENT_INTR1},
    {"WARMRSTN ", AM335X_PIN_WARMRSTN},
    {"NNMI ", AM335X_PIN_NNMI},
    {"TMS ", AM335X_PIN_TMS},
    {"TDI ", AM335X_PIN_TDI},
    {"TDO ", AM335X_PIN_TDO},
    {"TCK ", AM335X_PIN_TCK},
    {"TRSTN ", AM335X_PIN_TRSTN},
    {"EMU0 ", AM335X_PIN_EMU0},
    {"EMU1 ", AM335X_PIN_EMU1},
    {"RTC_PWRONRSTN ", AM335X_PIN_RTC_PWRONRSTN},
    {"PMIC_PMIC_POWER_EN ", AM335X_PIN_PMIC_POWER_EN},
    {"EXT_WAKEUP ", AM335X_PIN_EXT_WAKEUP},
    {"USB0_DRVVBUS ", AM335X_PIN_USB0_DRVVBUS},
    {"USB1_DRVVBUS ", AM335X_PIN_USB1_DRVVBUS},
    {NULL, 0}
};


// Decode mux register bits
void decode_mux(uint32_t val) {
//    printf("    Decode: ");
    
    uint32_t mode = val & 0x7;
    printf(" | %4u ", mode);

    uint32_t slow = val & 0b01000000;
    uint32_t rx = val & 0b00100000;
    uint32_t pullup = val & 0b00010000;
    uint32_t pulldisabled = val & 0b00001000;

    if(slow) {printf(" | S");} else{printf(" | F");}
    if(rx) {printf("RX");} else{printf("TX");}
    if(!pulldisabled) {
	printf("PULL");
    	if(pullup) {printf("UP");} else{printf("DN");}
    }

    printf("\n");
}

// Search for a pin name by offset
const char* find_pin_by_offset(uint32_t offset) {
    for (int i = 0; am33xx_pins[i].name != NULL; i++) {
        if (am33xx_pins[i].offset == offset) {
            return am33xx_pins[i].name;
        }
    }
    return "UNKNOWN";
}

int main() {
    FILE *fp = fopen("/sys/kernel/debug/pinctrl/44e10800.pinmux-pinctrl-single/pins", "r");
    if (!fp) {
        perror("Failed to open pinctrl pins file");
        return 1;
    }

    char line[256];

    //printf("GPIO | Pin Name | Address | Offset | Value | Mode | Pull | Direction | Rate \n");
    printf("%-8s | %-23s | %-10s | %-6s | %-5s | %-5s | %-9s\n", "GPIO", "Pin Name", "Address", "Offset","Value","Mode","PCR");


    while (fgets(line, sizeof(line), fp)) {
        char gpio[32];
        char addr_str[16];
        char val_str[16];
	int cline;

        if (sscanf(line, "pin %*d (%*[^)]) %d:%31s %15s %15s", &cline, gpio, addr_str, val_str) == 4) {
            uint32_t addr = strtoul(addr_str, NULL, 16);
            uint32_t val = strtoul(val_str, NULL, 16);
            uint32_t offset = addr - 0x44e10000;

            const char *pin_name = find_pin_by_offset(offset);

	int caseFound=0;
	if(strstr(gpio, "0-31")!=NULL) {
            printf("gpio0:%-2d | %-23s | 0x%x | 0x%04x | 0x%02x ",
                   cline, pin_name, addr, offset, val);
		caseFound=1;
	}

	if(strstr(gpio, "32-63")!=NULL) {
            printf("gpio1:%-2d | %-23s | 0x%x | 0x%04x | 0x%02x ",
                   cline, pin_name, addr, offset, val);
		caseFound=1;
	}

	if(strstr(gpio, "64-95")!=NULL) {
            printf("gpio2:%-2d | %-23s | 0x%x | 0x%04x | 0x%02x ",
                   cline, pin_name, addr, offset, val);
		caseFound=1;
	}

	if(strstr(gpio, "96-127")!=NULL) {
            printf("gpio3:%-2d | %-23s | 0x%x | 0x%04x | 0x%02x ",
                   cline, pin_name, addr, offset, val);
		caseFound=1;
	}

	if(!caseFound) {
            printf("DIO  :%-2d | %-23s | 0x%x | 0x%04x | 0x%02x ",
                   cline, pin_name, addr, offset, val);

	}

            decode_mux(val);
        }
    }

    fclose(fp);
    return 0;
}

You can always use tripple-backticks to enclose code (monospaced) like so:

Hello

I like it, please add a mit,x11, or gpl copywrite spdx banner to your code so I can ship it!

2 Likes

Reading is easy…. I will be deeply (but pleasantly) surprised if you can get it to SET a pinmux. I tried for quite a while to get setting pinmux from userspace to work and couldn’t get it to on the BBB. (works perfectly on the PB2)

And just to follow up, the code we ended up with is at:

On the PB2, it can use the stock kernel. For the BBB/PB1, we have a custom kernel that puts the bone-pinmux-helper back into the kernel. We then have device tree’s setup to define the possible pinmuxes that the pinctrl can then activate.

2 Likes

Seems like a lot of work to get a couple of pins to pull up.

Well, depends on what you are trying to do. With FPP, we need to dynamically change pins from one mode to another at runtime. For example, we need to be able to change the pins that are used as i2c over to gpio and then back. Or we need to change a pin from gpio mode over to PWM mode. In some cases, it has to be done dynamically at runtime and thus cannot be done via device trees.

Again, very easy to do on the PB2 as you can just write the mux mode to the appropriate register. On the am335x, the register memory is completely protected and cannot be written to except in kernel space.

True.

In your particular use-case, it totally makes sense to provide access to dynamic
reconfiguration, through a kernel module.

That being said, I’m willing to bet a small bag of Haribo’s on the fact that
most people will be quite well served with a static configuration through device-tree. :wink:

Do you know why the bone-pinmux-helper was removed? Seems this is an essential function for the hardware. Is your custom kernel image available for download and use?

the internal libgpio core of linux has had a ton of changes in v6.x era.. This driver only supported the am335x line.. After lots of fun breakage and the sake of long term maintablity, we are trying to just deal with mainline linux as is..

Many users of bone-pinmux-helper used it without the actual need of it..

Regards,

Our kernel sources are at:

And we have debs at:

That said, our Kernel config disables a bunch of things (like power management) that cause issues for us so the exact kernel images may not be good for you. Also, our one patch to the kernel only adds the bone-minmux-helper back to the kernel. It does NOT add the entries to the device tree or the gpio-of-helper that CapeUniversal used. For our use case, just the pinmux helper was needed.

The device tree overlay we use is at:

which contains all the pin definitions and such. As long as the kernel has the bone-pinmux-helper, they should work. You could pair that down to just the pins you really need/want to manipulate.

First Robert, I’m new here so I see you are helping out the open source community, so thanks for that. Second, just a comment, if i wanted a bare bones linux single board computer, without control of gpio, i would just buy a fanless x86 PC. In my opinion, the sole purpose of the BBB line is to merge the linux single board computer with the basic microcontroller with hardware control of gpio. The BBB is a step up from the Raspberry PI, especially with the industrial temperature spec’s. And one more thought, having functions inside libgpiod that set the pull-up resistor that do nothing, is a little bit of a wild goose chase wasting people’s time. Anyway that said, thanks again for all your hard work. I understand d the time it takes to pull all this together.

PS, and thank you for your initial pinmux application, please add a license to it (MIT/GPL2/X11), I like your layout and would like to extend it to other devices (and ship it by default)… I’ll add a repo on BeagleBoard.org · GitHub and give you access too..

Regards,

Okay, I’ll add the GPL2, give me a few minutes, I got a bunch of work going on here.

pinmux.c (9.1 KB)

1 Like

Awesome importing into: GitHub - beagleboard/pinmux · GitHub (let me know your github handle and i’ll add access)