diff options
-rw-r--r-- | arch/arm/dts/k3-j721e-main.dtsi | 19 | ||||
-rw-r--r-- | arch/sandbox/dts/test.dts | 72 | ||||
-rw-r--r-- | configs/omap35_logic_somlv_defconfig | 1 | ||||
-rw-r--r-- | configs/sandbox_defconfig | 1 | ||||
-rw-r--r-- | configs/sandbox_flattree_defconfig | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 474 | ||||
-rw-r--r-- | test/dm/pinmux.c | 91 |
7 files changed, 590 insertions, 69 deletions
diff --git a/arch/arm/dts/k3-j721e-main.dtsi b/arch/arm/dts/k3-j721e-main.dtsi index e47b6c0eb70..07b489679ed 100644 --- a/arch/arm/dts/k3-j721e-main.dtsi +++ b/arch/arm/dts/k3-j721e-main.dtsi @@ -1078,13 +1078,12 @@ assigned-clocks = <&k3_clks 91 1>; assigned-clock-parents = <&k3_clks 91 2>; bus-width = <8>; - mmc-hs400-1_8v; + mmc-hs200-1_8v; mmc-ddr-1_8v; ti,otap-del-sel-legacy = <0xf>; ti,otap-del-sel-mmc-hs = <0xf>; ti,otap-del-sel-ddr52 = <0x5>; ti,otap-del-sel-hs200 = <0x6>; - ti,otap-del-sel-hs400 = <0x0>; ti,itap-del-sel-legacy = <0x10>; ti,itap-del-sel-mmc-hs = <0xa>; ti,itap-del-sel-ddr52 = <0x3>; @@ -1102,14 +1101,20 @@ assigned-clocks = <&k3_clks 92 0>; assigned-clock-parents = <&k3_clks 92 1>; ti,otap-del-sel-legacy = <0x0>; - ti,otap-del-sel-sd-hs = <0xf>; + ti,otap-del-sel-sd-hs = <0x0>; ti,otap-del-sel-sdr12 = <0xf>; ti,otap-del-sel-sdr25 = <0xf>; ti,otap-del-sel-sdr50 = <0xc>; ti,otap-del-sel-ddr50 = <0xc>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; + ti,itap-del-sel-ddr50 = <0x2>; ti,trm-icp = <0x8>; ti,clkbuf-sel = <0x7>; dma-coherent; + sdhci-caps-mask = <0x2 0x0>; }; main_sdhci2: sdhci@4f98000 { @@ -1122,14 +1127,20 @@ assigned-clocks = <&k3_clks 93 0>; assigned-clock-parents = <&k3_clks 93 1>; ti,otap-del-sel-legacy = <0x0>; - ti,otap-del-sel-sd-hs = <0xf>; + ti,otap-del-sel-sd-hs = <0x0>; ti,otap-del-sel-sdr12 = <0xf>; ti,otap-del-sel-sdr25 = <0xf>; ti,otap-del-sel-sdr50 = <0xc>; ti,otap-del-sel-ddr50 = <0xc>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; + ti,itap-del-sel-ddr50 = <0x2>; ti,trm-icp = <0x8>; ti,clkbuf-sel = <0x7>; dma-coherent; + sdhci-caps-mask = <0x2 0x0>; }; usbss0: cdns-usb@4104000 { diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index dde4efb9334..48240aa26f6 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -634,6 +634,9 @@ reg = <0 1>; compatible = "sandbox,i2c"; clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinmux_i2c0_pins>; + eeprom@2c { reg = <0x2c>; compatible = "i2c-eeprom"; @@ -714,6 +717,8 @@ lcd { u-boot,dm-pre-reloc; compatible = "sandbox,lcd-sdl"; + pinctrl-names = "default"; + pinctrl-0 = <&pinmux_lcd_pins>; xres = <1366>; yres = <768>; }; @@ -964,6 +969,8 @@ pwm: pwm { compatible = "sandbox,pwm"; #pwm-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pinmux_pwm_pins>; }; pwm2 { @@ -1035,6 +1042,9 @@ reg = <0 1>; compatible = "sandbox,spi"; cs-gpios = <0>, <0>, <&gpio_a 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinmux_spi0_pins>; + spi.bin@0 { reg = <0>; compatible = "spansion,m25p16", "jedec,spi-nor"; @@ -1124,6 +1134,8 @@ uart0: serial { compatible = "sandbox,serial"; u-boot,dm-pre-reloc; + pinctrl-names = "default"; + pinctrl-0 = <&pinmux_uart0_pins>; }; usb_0: usb@0 { @@ -1392,6 +1404,66 @@ }; }; + pinctrl-single-no-width { + compatible = "pinctrl-single"; + reg = <0x0000 0x238>; + #pinctrl-cells = <1>; + pinctrl-single,function-mask = <0x7f>; + }; + + pinctrl-single-pins { + compatible = "pinctrl-single"; + reg = <0x0000 0x238>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x7f>; + + pinmux_pwm_pins: pinmux_pwm_pins { + pinctrl-single,pins = < 0x48 0x06 >; + }; + + pinmux_spi0_pins: pinmux_spi0_pins { + pinctrl-single,pins = < + 0x190 0x0c + 0x194 0x0c + 0x198 0x23 + 0x19c 0x0c + >; + }; + + pinmux_uart0_pins: pinmux_uart0_pins { + pinctrl-single,pins = < + 0x70 0x30 + 0x74 0x00 + >; + }; + }; + + pinctrl-single-bits { + compatible = "pinctrl-single"; + reg = <0x0000 0x50>; + #pinctrl-cells = <2>; + pinctrl-single,bit-per-mux; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xf>; + + pinmux_i2c0_pins: pinmux_i2c0_pins { + pinctrl-single,bits = < + 0x10 0x00002200 0x0000ff00 + >; + }; + + pinmux_lcd_pins: pinmux_lcd_pins { + pinctrl-single,bits = < + 0x40 0x22222200 0xffffff00 + 0x44 0x22222222 0xffffffff + 0x48 0x00000022 0x000000ff + 0x48 0x02000000 0x0f000000 + 0x4c 0x02000022 0x0f0000ff + >; + }; + }; + hwspinlock@0 { compatible = "sandbox,hwspinlock"; }; diff --git a/configs/omap35_logic_somlv_defconfig b/configs/omap35_logic_somlv_defconfig index e6655c7828d..a8eab408f6e 100644 --- a/configs/omap35_logic_somlv_defconfig +++ b/configs/omap35_logic_somlv_defconfig @@ -4,6 +4,7 @@ CONFIG_ARM=y CONFIG_ARCH_OMAP2PLUS=y CONFIG_SYS_TEXT_BASE=0x80100000 CONFIG_TI_COMMON_CMD_OPTIONS=y +# CONFIG_SPL_GPIO_SUPPORT is not set CONFIG_SYS_MALLOC_F_LEN=0x4000 CONFIG_NR_DRAM_BANKS=2 CONFIG_SPL_TEXT_BASE=0x40200000 diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index c9318d4af56..6038dcba95c 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -198,6 +198,7 @@ CONFIG_PHY_SANDBOX=y CONFIG_PINCTRL=y CONFIG_PINCONF=y CONFIG_PINCTRL_SANDBOX=y +CONFIG_PINCTRL_SINGLE=y CONFIG_POWER_DOMAIN=y CONFIG_SANDBOX_POWER_DOMAIN=y CONFIG_DM_PMIC=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index b68f938cb37..689b3a9e202 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -142,6 +142,7 @@ CONFIG_PHY_SANDBOX=y CONFIG_PINCTRL=y CONFIG_PINCONF=y CONFIG_PINCTRL_SANDBOX=y +CONFIG_PINCTRL_SINGLE=y CONFIG_POWER_DOMAIN=y CONFIG_SANDBOX_POWER_DOMAIN=y CONFIG_DM_PMIC=y diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 20c3c82aa98..48bdd0f6f5b 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1,34 +1,262 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch> + * Copyright (C) 2021 Dario Binacchi <dariobin@libero.it> */ #include <common.h> #include <dm.h> #include <dm/device_compat.h> +#include <dm/devres.h> #include <dm/pinctrl.h> #include <linux/libfdt.h> +#include <linux/list.h> #include <asm/io.h> +#include <sort.h> +/** + * struct single_pdata - platform data + * @base: first configuration register + * @offset: index of last configuration register + * @mask: configuration-value mask bits + * @width: configuration register bit width + * @bits_per_mux: true if one register controls more than one pin + */ struct single_pdata { - fdt_addr_t base; /* first configuration register */ - int offset; /* index of last configuration register */ - u32 mask; /* configuration-value mask bits */ - int width; /* configuration register bit width */ + fdt_addr_t base; + int offset; + u32 mask; + u32 width; bool bits_per_mux; }; +/** + * struct single_func - pinctrl function + * @node: list node + * @name: pinctrl function name + * @npins: number of entries in pins array + * @pins: pins array + */ +struct single_func { + struct list_head node; + const char *name; + unsigned int npins; + unsigned int *pins; +}; + +/** + * struct single_priv - private data + * @bits_per_pin: number of bits per pin + * @npins: number of selectable pins + * @pin_name: temporary buffer to store the pin name + */ +struct single_priv { +#if (IS_ENABLED(CONFIG_SANDBOX)) + u32 *sandbox_regs; +#endif + unsigned int bits_per_pin; + unsigned int npins; + char pin_name[PINNAME_SIZE]; + struct list_head functions; +}; + +/** + * struct single_fdt_pin_cfg - pin configuration + * + * This structure is used for the pin configuration parameters in case + * the register controls only one pin. + * + * @reg: configuration register offset + * @val: configuration register value + */ struct single_fdt_pin_cfg { - fdt32_t reg; /* configuration register offset */ - fdt32_t val; /* configuration register value */ + fdt32_t reg; + fdt32_t val; }; +/** + * struct single_fdt_bits_cfg - pin configuration + * + * This structure is used for the pin configuration parameters in case + * the register controls more than one pin. + * + * @reg: configuration register offset + * @val: configuration register value + * @mask: configuration register mask + */ struct single_fdt_bits_cfg { - fdt32_t reg; /* configuration register offset */ - fdt32_t val; /* configuration register value */ - fdt32_t mask; /* configuration register mask */ + fdt32_t reg; + fdt32_t val; + fdt32_t mask; }; +#if (!IS_ENABLED(CONFIG_SANDBOX)) + +static unsigned int single_read(struct udevice *dev, fdt_addr_t reg) +{ + struct single_pdata *pdata = dev_get_plat(dev); + + switch (pdata->width) { + case 8: + return readb(reg); + case 16: + return readw(reg); + default: /* 32 bits */ + return readl(reg); + } + + return readb(reg); +} + +static void single_write(struct udevice *dev, unsigned int val, fdt_addr_t reg) +{ + struct single_pdata *pdata = dev_get_plat(dev); + + switch (pdata->width) { + case 8: + writeb(val, reg); + break; + case 16: + writew(val, reg); + break; + default: /* 32 bits */ + writel(val, reg); + } +} + +#else /* CONFIG_SANDBOX */ + +static unsigned int single_read(struct udevice *dev, fdt_addr_t reg) +{ + struct single_priv *priv = dev_get_priv(dev); + + return priv->sandbox_regs[reg]; +} + +static void single_write(struct udevice *dev, unsigned int val, fdt_addr_t reg) +{ + struct single_priv *priv = dev_get_priv(dev); + + priv->sandbox_regs[reg] = val; +} + +#endif /* CONFIG_SANDBOX */ + +/** + * single_get_pin_by_offset() - get a pin based on the register offset + * @dev: single driver instance + * @offset: register offset from the base + */ +static int single_get_pin_by_offset(struct udevice *dev, unsigned int offset) +{ + struct single_pdata *pdata = dev_get_plat(dev); + struct single_priv *priv = dev_get_priv(dev); + + if (offset > pdata->offset) { + dev_err(dev, "mux offset out of range: 0x%x (0x%x)\n", + offset, pdata->offset); + return -EINVAL; + } + + if (pdata->bits_per_mux) + return (offset * BITS_PER_BYTE) / priv->bits_per_pin; + + return offset / (pdata->width / BITS_PER_BYTE); +} + +static int single_get_offset_by_pin(struct udevice *dev, unsigned int pin) +{ + struct single_pdata *pdata = dev_get_plat(dev); + struct single_priv *priv = dev_get_priv(dev); + unsigned int mux_bytes; + + if (pin >= priv->npins) + return -EINVAL; + + mux_bytes = pdata->width / BITS_PER_BYTE; + if (pdata->bits_per_mux) { + int byte_num; + + byte_num = (priv->bits_per_pin * pin) / BITS_PER_BYTE; + return (byte_num / mux_bytes) * mux_bytes; + } + + return pin * mux_bytes; +} + +static const char *single_get_pin_function(struct udevice *dev, + unsigned int pin) +{ + struct single_priv *priv = dev_get_priv(dev); + struct single_func *func; + int i; + + list_for_each_entry(func, &priv->functions, node) { + for (i = 0; i < func->npins; i++) { + if (pin == func->pins[i]) + return func->name; + + if (pin < func->pins[i]) + break; + } + } + + return NULL; +} + +static int single_get_pin_muxing(struct udevice *dev, unsigned int pin, + char *buf, int size) +{ + struct single_pdata *pdata = dev_get_plat(dev); + struct single_priv *priv = dev_get_priv(dev); + fdt_addr_t reg; + const char *fname; + unsigned int val; + int offset, pin_shift = 0; + + offset = single_get_offset_by_pin(dev, pin); + if (offset < 0) + return offset; + + reg = pdata->base + offset; + val = single_read(dev, reg); + + if (pdata->bits_per_mux) + pin_shift = pin % (pdata->width / priv->bits_per_pin) * + priv->bits_per_pin; + + val &= (pdata->mask << pin_shift); + fname = single_get_pin_function(dev, pin); + snprintf(buf, size, "%pa 0x%08x %s", ®, val, + fname ? fname : "UNCLAIMED"); + return 0; +} + +static struct single_func *single_allocate_function(struct udevice *dev, + unsigned int group_pins) +{ + struct single_func *func; + + func = devm_kmalloc(dev, sizeof(*func), GFP_KERNEL); + if (!func) + return ERR_PTR(-ENOMEM); + + func->pins = devm_kmalloc(dev, sizeof(unsigned int) * group_pins, + GFP_KERNEL); + if (!func->pins) + return ERR_PTR(-ENOMEM); + + return func; +} + +static int single_pin_compare(const void *s1, const void *s2) +{ + int pin1 = *(const unsigned int *)s1; + int pin2 = *(const unsigned int *)s2; + + return pin1 - pin2; +} + /** * single_configure_pins() - Configure pins based on FDT data * @@ -42,75 +270,129 @@ struct single_fdt_bits_cfg { * @size: Size of the 'pins' array in bytes. * The number of register/value pairs in the 'pins' array therefore * equals to 'size / sizeof(struct single_fdt_pin_cfg)'. + * @fname: Function name. */ static int single_configure_pins(struct udevice *dev, const struct single_fdt_pin_cfg *pins, - int size) + int size, const char *fname) { struct single_pdata *pdata = dev_get_plat(dev); - int count = size / sizeof(struct single_fdt_pin_cfg); - phys_addr_t n, reg; - u32 val; + struct single_priv *priv = dev_get_priv(dev); + int n, pin, count = size / sizeof(struct single_fdt_pin_cfg); + struct single_func *func; + phys_addr_t reg; + u32 offset, val; + /* If function mask is null, needn't enable it. */ + if (!pdata->mask) + return 0; + + func = single_allocate_function(dev, count); + if (IS_ERR(func)) + return PTR_ERR(func); + + func->name = fname; + func->npins = 0; for (n = 0; n < count; n++, pins++) { - reg = fdt32_to_cpu(pins->reg); - if ((reg < 0) || (reg > pdata->offset)) { - dev_dbg(dev, " invalid register offset 0x%pa\n", ®); + offset = fdt32_to_cpu(pins->reg); + if (offset < 0 || offset > pdata->offset) { + dev_err(dev, " invalid register offset 0x%x\n", + offset); continue; } - reg += pdata->base; + + reg = pdata->base + offset; val = fdt32_to_cpu(pins->val) & pdata->mask; - switch (pdata->width) { - case 16: - writew((readw(reg) & ~pdata->mask) | val, reg); - break; - case 32: - writel((readl(reg) & ~pdata->mask) | val, reg); - break; - default: - dev_warn(dev, "unsupported register width %i\n", - pdata->width); + pin = single_get_pin_by_offset(dev, offset); + if (pin < 0) { + dev_err(dev, " failed to get pin by offset %x\n", + offset); continue; } - dev_dbg(dev, " reg/val 0x%pa/0x%08x\n", ®, val); + + single_write(dev, (single_read(dev, reg) & ~pdata->mask) | val, + reg); + dev_dbg(dev, " reg/val %pa/0x%08x\n", ®, val); + func->pins[func->npins] = pin; + func->npins++; } + + qsort(func->pins, func->npins, sizeof(func->pins[0]), + single_pin_compare); + list_add(&func->node, &priv->functions); return 0; } static int single_configure_bits(struct udevice *dev, const struct single_fdt_bits_cfg *pins, - int size) + int size, const char *fname) { struct single_pdata *pdata = dev_get_plat(dev); - int count = size / sizeof(struct single_fdt_bits_cfg); - phys_addr_t n, reg; - u32 val, mask; + struct single_priv *priv = dev_get_priv(dev); + int n, pin, count = size / sizeof(struct single_fdt_bits_cfg); + int npins_in_reg, pin_num_from_lsb; + struct single_func *func; + phys_addr_t reg; + u32 offset, val, mask, bit_pos, val_pos, mask_pos, submask; + npins_in_reg = pdata->width / priv->bits_per_pin; + func = single_allocate_function(dev, count * npins_in_reg); + if (IS_ERR(func)) + return PTR_ERR(func); + + func->name = fname; + func->npins = 0; for (n = 0; n < count; n++, pins++) { - reg = fdt32_to_cpu(pins->reg); - if ((reg < 0) || (reg > pdata->offset)) { - dev_dbg(dev, " invalid register offset 0x%pa\n", ®); + offset = fdt32_to_cpu(pins->reg); + if (offset < 0 || offset > pdata->offset) { + dev_dbg(dev, " invalid register offset 0x%x\n", + offset); + continue; + } + + reg = pdata->base + offset; + + pin = single_get_pin_by_offset(dev, offset); + if (pin < 0) { + dev_err(dev, " failed to get pin by offset 0x%pa\n", + ®); continue; } - reg += pdata->base; mask = fdt32_to_cpu(pins->mask); val = fdt32_to_cpu(pins->val) & mask; + single_write(dev, (single_read(dev, reg) & ~mask) | val, reg); + dev_dbg(dev, " reg/val %pa/0x%08x\n", ®, val); - switch (pdata->width) { - case 16: - writew((readw(reg) & ~mask) | val, reg); - break; - case 32: - writel((readl(reg) & ~mask) | val, reg); - break; - default: - dev_warn(dev, "unsupported register width %i\n", - pdata->width); - continue; + while (mask) { + bit_pos = __ffs(mask); + pin_num_from_lsb = bit_pos / priv->bits_per_pin; + mask_pos = pdata->mask << bit_pos; + val_pos = val & mask_pos; + submask = mask & mask_pos; + + if ((mask & mask_pos) == 0) { + dev_err(dev, "Invalid mask at 0x%x\n", offset); + break; + } + + mask &= ~mask_pos; + + if (submask != mask_pos) { + dev_warn(dev, + "Invalid submask 0x%x at 0x%x\n", + submask, offset); + continue; + } + + func->pins[func->npins] = pin + pin_num_from_lsb; + func->npins++; } - dev_dbg(dev, " reg/val 0x%pa/0x%08x\n", ®, val); } + + qsort(func->pins, func->npins, sizeof(func->pins[0]), + single_pin_compare); + list_add(&func->node, &priv->functions); return 0; } static int single_set_state(struct udevice *dev, @@ -128,7 +410,7 @@ static int single_set_state(struct udevice *dev, dev_dbg(dev, " invalid pin configuration in fdt\n"); return -FDT_ERR_BADSTRUCTURE; } - single_configure_pins(dev, prop, len); + single_configure_pins(dev, prop, len, config->name); return 0; } @@ -140,7 +422,7 @@ static int single_set_state(struct udevice *dev, dev_dbg(dev, " invalid bits configuration in fdt\n"); return -FDT_ERR_BADSTRUCTURE; } - single_configure_bits(dev, prop_bits, len); + single_configure_bits(dev, prop_bits, len, config->name); return 0; } @@ -148,20 +430,83 @@ static int single_set_state(struct udevice *dev, return len; } +static const char *single_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct single_priv *priv = dev_get_priv(dev); + + if (selector >= priv->npins) + snprintf(priv->pin_name, PINNAME_SIZE, "Error"); + else + snprintf(priv->pin_name, PINNAME_SIZE, "PIN%u", selector); + + return priv->pin_name; +} + +static int single_get_pins_count(struct udevice *dev) +{ + struct single_priv *priv = dev_get_priv(dev); + + return priv->npins; +} + +static int single_probe(struct udevice *dev) +{ + struct single_pdata *pdata = dev_get_plat(dev); + struct single_priv *priv = dev_get_priv(dev); + u32 size; + + INIT_LIST_HEAD(&priv->functions); + + size = pdata->offset + pdata->width / BITS_PER_BYTE; + #if (CONFIG_IS_ENABLED(SANDBOX)) + priv->sandbox_regs = + devm_kzalloc(dev, size * sizeof(*priv->sandbox_regs), + GFP_KERNEL); + if (!priv->sandbox_regs) + return -ENOMEM; + #endif + + priv->npins = size / (pdata->width / BITS_PER_BYTE); + if (pdata->bits_per_mux) { + priv->bits_per_pin = fls(pdata->mask); + priv->npins *= (pdata->width / priv->bits_per_pin); + } + + dev_dbg(dev, "%d pins\n", priv->npins); + return 0; +} + static int single_of_to_plat(struct udevice *dev) { fdt_addr_t addr; - u32 of_reg[2]; - int res; + fdt_size_t size; struct single_pdata *pdata = dev_get_plat(dev); + int ret; - pdata->width = - dev_read_u32_default(dev, "pinctrl-single,register-width", 0); + ret = dev_read_u32(dev, "pinctrl-single,register-width", &pdata->width); + if (ret) { + dev_err(dev, "missing register width\n"); + return ret; + } - res = dev_read_u32_array(dev, "reg", of_reg, 2); - if (res) - return res; - pdata->offset = of_reg[1] - pdata->width / 8; + switch (pdata->width) { + case 8: + case 16: + case 32: + break; + default: + dev_err(dev, "wrong register width\n"); + return -EINVAL; + } + + addr = dev_read_addr_size(dev, "reg", &size); + if (addr == FDT_ADDR_T_NONE) { + dev_err(dev, "failed to get base register size\n"); + return -EINVAL; + } + + pdata->offset = size - pdata->width / BITS_PER_BYTE; addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) { @@ -170,15 +515,22 @@ static int single_of_to_plat(struct udevice *dev) } pdata->base = addr; - pdata->mask = dev_read_u32_default(dev, "pinctrl-single,function-mask", - 0xffffffff); + ret = dev_read_u32(dev, "pinctrl-single,function-mask", &pdata->mask); + if (ret) { + pdata->mask = 0; + dev_warn(dev, "missing function register mask\n"); + } + pdata->bits_per_mux = dev_read_bool(dev, "pinctrl-single,bit-per-mux"); return 0; } const struct pinctrl_ops single_pinctrl_ops = { + .get_pins_count = single_get_pins_count, + .get_pin_name = single_get_pin_name, .set_state = single_set_state, + .get_pin_muxing = single_get_pin_muxing, }; static const struct udevice_id single_pinctrl_match[] = { @@ -192,5 +544,7 @@ U_BOOT_DRIVER(single_pinctrl) = { .of_match = single_pinctrl_match, .ops = &single_pinctrl_ops, .plat_auto = sizeof(struct single_pdata), + .priv_auto = sizeof(struct single_priv), .of_to_plat = single_of_to_plat, + .probe = single_probe, }; diff --git a/test/dm/pinmux.c b/test/dm/pinmux.c index 047184d4bcb..265df4ccb97 100644 --- a/test/dm/pinmux.c +++ b/test/dm/pinmux.c @@ -9,16 +9,21 @@ #include <dm/test.h> #include <test/ut.h> -static int dm_test_pinmux(struct unit_test_state *uts) -{ - char buf[64]; - struct udevice *dev; - +static char buf[64]; #define test_muxing(selector, expected) do { \ ut_assertok(pinctrl_get_pin_muxing(dev, selector, buf, sizeof(buf))); \ ut_asserteq_str(expected, (char *)&buf); \ } while (0) +#define test_name(selector, expected) do { \ + ut_assertok(pinctrl_get_pin_name(dev, selector, buf, sizeof(buf))); \ + ut_asserteq_str(expected, (char *)&buf); \ +} while (0) + +static int dm_test_pinmux(struct unit_test_state *uts) +{ + struct udevice *dev; + ut_assertok(uclass_get_device_by_name(UCLASS_PINCTRL, "pinctrl", &dev)); test_muxing(0, "UART TX."); test_muxing(1, "UART RX."); @@ -54,4 +59,80 @@ static int dm_test_pinmux(struct unit_test_state *uts) return 0; } + DM_TEST(dm_test_pinmux, UT_TESTF_SCAN_FDT); + +static int dm_test_pinctrl_single(struct unit_test_state *uts) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_name(UCLASS_PINCTRL, + "pinctrl-single-no-width", &dev); + ut_asserteq(-EINVAL, ret); + ut_assertok(uclass_get_device_by_name(UCLASS_PWM, "pwm", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_SERIAL, "serial", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_SPI, "spi@0", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_PINCTRL, + "pinctrl-single-pins", &dev)); + ut_asserteq(142, pinctrl_get_pins_count(dev)); + test_name(0, "PIN0"); + test_name(141, "PIN141"); + test_name(142, "Error"); + test_muxing(0, "0x00000000 0x00000000 UNCLAIMED"); + test_muxing(18, "0x00000048 0x00000006 pinmux_pwm_pins"); + test_muxing(28, "0x00000070 0x00000030 pinmux_uart0_pins"); + test_muxing(29, "0x00000074 0x00000000 pinmux_uart0_pins"); + test_muxing(100, "0x00000190 0x0000000c pinmux_spi0_pins"); + test_muxing(101, "0x00000194 0x0000000c pinmux_spi0_pins"); + test_muxing(102, "0x00000198 0x00000023 pinmux_spi0_pins"); + test_muxing(103, "0x0000019c 0x0000000c pinmux_spi0_pins"); + ret = pinctrl_get_pin_muxing(dev, 142, buf, sizeof(buf)); + ut_asserteq(-EINVAL, ret); + ut_assertok(uclass_get_device_by_name(UCLASS_I2C, "i2c@0", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_VIDEO, "lcd", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_PINCTRL, + "pinctrl-single-bits", &dev)); + ut_asserteq(160, pinctrl_get_pins_count(dev)); + test_name(0, "PIN0"); + test_name(159, "PIN159"); + test_name(160, "Error"); + test_muxing(0, "0x00000000 0x00000000 UNCLAIMED"); + test_muxing(34, "0x00000010 0x00000200 pinmux_i2c0_pins"); + test_muxing(35, "0x00000010 0x00002000 pinmux_i2c0_pins"); + test_muxing(130, "0x00000040 0x00000200 pinmux_lcd_pins"); + test_muxing(131, "0x00000040 0x00002000 pinmux_lcd_pins"); + test_muxing(132, "0x00000040 0x00020000 pinmux_lcd_pins"); + test_muxing(133, "0x00000040 0x00200000 pinmux_lcd_pins"); + test_muxing(134, "0x00000040 0x02000000 pinmux_lcd_pins"); + test_muxing(135, "0x00000040 0x20000000 pinmux_lcd_pins"); + test_muxing(136, "0x00000044 0x00000002 pinmux_lcd_pins"); + test_muxing(137, "0x00000044 0x00000020 pinmux_lcd_pins"); + test_muxing(138, "0x00000044 0x00000200 pinmux_lcd_pins"); + test_muxing(139, "0x00000044 0x00002000 pinmux_lcd_pins"); + test_muxing(140, "0x00000044 0x00020000 pinmux_lcd_pins"); + test_muxing(141, "0x00000044 0x00200000 pinmux_lcd_pins"); + test_muxing(142, "0x00000044 0x02000000 pinmux_lcd_pins"); + test_muxing(143, "0x00000044 0x20000000 pinmux_lcd_pins"); + test_muxing(144, "0x00000048 0x00000002 pinmux_lcd_pins"); + test_muxing(145, "0x00000048 0x00000020 pinmux_lcd_pins"); + test_muxing(146, "0x00000048 0x00000000 UNCLAIMED"); + test_muxing(147, "0x00000048 0x00000000 UNCLAIMED"); + test_muxing(148, "0x00000048 0x00000000 UNCLAIMED"); + test_muxing(149, "0x00000048 0x00000000 UNCLAIMED"); + test_muxing(150, "0x00000048 0x02000000 pinmux_lcd_pins"); + test_muxing(151, "0x00000048 0x00000000 UNCLAIMED"); + test_muxing(152, "0x0000004c 0x00000002 pinmux_lcd_pins"); + test_muxing(153, "0x0000004c 0x00000020 pinmux_lcd_pins"); + test_muxing(154, "0x0000004c 0x00000000 UNCLAIMED"); + test_muxing(155, "0x0000004c 0x00000000 UNCLAIMED"); + test_muxing(156, "0x0000004c 0x00000000 UNCLAIMED"); + test_muxing(157, "0x0000004c 0x00000000 UNCLAIMED"); + test_muxing(158, "0x0000004c 0x02000000 pinmux_lcd_pins"); + test_muxing(159, "0x0000004c 0x00000000 UNCLAIMED"); + ret = pinctrl_get_pin_muxing(dev, 160, buf, sizeof(buf)); + ut_asserteq(-EINVAL, ret); + return 0; +} + +DM_TEST(dm_test_pinctrl_single, UT_TESTF_SCAN_FDT); |