GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,279 @@
#
# PINCTRL infrastructure and drivers
#
menu "Pin controllers"
config PINCTRL
bool "Support pin controllers"
depends on DM
help
This enables the basic support for pinctrl framework. You may want
to enable some more options depending on what you want to do.
config PINCTRL_FULL
bool "Support full pin controllers"
depends on PINCTRL && OF_CONTROL
default y
help
This provides Linux-compatible device tree interface for the pinctrl
subsystem. This feature depends on device tree configuration because
it parses a device tree to look for the pinctrl device which the
peripheral device is associated with.
If this option is disabled (it is the only possible choice for non-DT
boards), the pinctrl core provides no systematic mechanism for
identifying peripheral devices, applying needed pinctrl settings.
It is totally up to the implementation of each low-level driver.
You can save memory footprint in return for some limitations.
config PINCTRL_GENERIC
bool "Support generic pin controllers"
depends on PINCTRL_FULL
default y
help
Say Y here if you want to use the pinctrl subsystem through the
generic DT interface. If enabled, some functions become available
to parse common properties such as "pins", "groups", "functions" and
some pin configuration parameters. It would be easier if you only
need the generic DT interface for pin muxing and pin configuration.
If you need to handle vendor-specific DT properties, you can disable
this option and implement your own set_state callback in the pinctrl
operations.
config PINMUX
bool "Support pin multiplexing controllers"
depends on PINCTRL_GENERIC
default y
help
This option enables pin multiplexing through the generic pinctrl
framework. Most SoCs have their own multiplexing arrangement where
a single pin can be used for several functions. An SoC pinctrl driver
allows the required function to be selected for each pin.
The driver is typically controlled by the device tree.
config PINCONF
bool "Support pin configuration controllers"
depends on PINCTRL_GENERIC
help
This option enables pin configuration through the generic pinctrl
framework.
config PINCONF_RECURSIVE
bool "Support recursive binding for pin configuration nodes"
depends on PINCTRL_FULL
default n if ARCH_STM32MP
default y
help
In the Linux pinctrl binding, the pin configuration nodes need not be
direct children of the pin controller device (may be grandchildren for
example). It is define is each individual pin controller device.
Say Y here if you want to keep this behavior with the pinconfig
u-class: all sub are recursivelly bounded.
If the option is disabled, this behavior is deactivated and only
the direct children of pin controller will be assumed as pin
configuration; you can save memory footprint when this feature is
no needed.
config SPL_PINCTRL
bool "Support pin controllers in SPL"
depends on SPL && SPL_DM
help
This option is an SPL-variant of the PINCTRL option.
See the help of PINCTRL for details.
config SPL_PINCTRL_FULL
bool "Support full pin controllers in SPL"
depends on SPL_PINCTRL && SPL_OF_CONTROL
default n if TARGET_STM32F746_DISCO
default y
help
This option is an SPL-variant of the PINCTRL_FULL option.
See the help of PINCTRL_FULL for details.
config SPL_PINCTRL_GENERIC
bool "Support generic pin controllers in SPL"
depends on SPL_PINCTRL_FULL
default y
help
This option is an SPL-variant of the PINCTRL_GENERIC option.
See the help of PINCTRL_GENERIC for details.
config SPL_PINMUX
bool "Support pin multiplexing controllers in SPL"
depends on SPL_PINCTRL_GENERIC
default y
help
This option is an SPL-variant of the PINMUX option.
See the help of PINMUX for details.
The pinctrl subsystem can add a substantial overhead to the SPL
image since it typically requires quite a few tables either in the
driver or in the device tree. If this is acceptable and you need
to adjust pin multiplexing in SPL in order to boot into U-Boot,
enable this option. You will need to enable device tree in SPL
for this to work.
config SPL_PINCONF
bool "Support pin configuration controllers in SPL"
depends on SPL_PINCTRL_GENERIC
help
This option is an SPL-variant of the PINCONF option.
See the help of PINCONF for details.
config SPL_PINCONF_RECURSIVE
bool "Support recursive binding for pin configuration nodes in SPL"
depends on SPL_PINCTRL_FULL
default n if ARCH_STM32MP
default y
help
This option is an SPL-variant of the PINCONF_RECURSIVE option.
See the help of PINCONF_RECURSIVE for details.
if PINCTRL || SPL_PINCTRL
config PINCTRL_AR933X
bool "QCA/Athores ar933x pin control driver"
depends on DM && SOC_AR933X
help
Support pin multiplexing control on QCA/Athores ar933x SoCs.
The driver is controlled by a device tree node which contains
both the GPIO definitions and pin control functions for each
available multiplex function.
config PINCTRL_AT91
bool "AT91 pinctrl driver"
depends on DM
help
This option is to enable the AT91 pinctrl driver for AT91 PIO
controller.
AT91 PIO controller is a combined gpio-controller, pin-mux and
pin-config module. Each I/O pin may be dedicated as a general-purpose
I/O or be assigned to a function of an embedded peripheral. Each I/O
pin has a glitch filter providing rejection of glitches lower than
one-half of peripheral clock cycle and a debouncing filter providing
rejection of unwanted pulses from key or push button operations. You
can also control the multi-driver capability, pull-up and pull-down
feature on each I/O pin.
config PINCTRL_AT91PIO4
bool "AT91 PIO4 pinctrl driver"
depends on DM
help
This option is to enable the AT91 pinctrl driver for AT91 PIO4
controller which is available on SAMA5D2 SoC.
config PINCTRL_PIC32
bool "Microchip PIC32 pin-control and pin-mux driver"
depends on DM && MACH_PIC32
default y
help
Supports individual pin selection and configuration for each
remappable peripheral available on Microchip PIC32
SoCs. This driver is controlled by a device tree node which
contains both GPIO definition and pin control functions.
config PINCTRL_QCA953X
bool "QCA/Athores qca953x pin control driver"
depends on DM && SOC_QCA953X
help
Support pin multiplexing control on QCA/Athores qca953x SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_ROCKCHIP_RV1108
bool "Rockchip rv1108 pin control driver"
depends on DM
help
Support pin multiplexing control on Rockchip rv1108 SoC.
The driver is controlled by a device tree node which contains
both the GPIO definitions and pin control functions for each
available multiplex function.
config PINCTRL_SANDBOX
bool "Sandbox pinctrl driver"
depends on SANDBOX
help
This enables pinctrl driver for sandbox.
Currently, this driver actually does nothing but print debug
messages when pinctrl operations are invoked.
config PINCTRL_SINGLE
bool "Single register pin-control and pin-multiplex driver"
depends on DM
help
This enables pinctrl driver for systems using a single register for
pin configuration and multiplexing. TI's AM335X SoCs are examples of
such systems.
Depending on the platform make sure to also enable OF_TRANSLATE and
eventually SPL_OF_TRANSLATE to get correct address translations.
config PINCTRL_STI
bool "STMicroelectronics STi pin-control and pin-mux driver"
depends on DM && ARCH_STI
default y
help
Support pin multiplexing control on STMicrolectronics STi SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_STM32
bool "ST STM32 pin control driver"
depends on DM
help
Supports pin multiplexing control on stm32 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_STMFX
bool "STMicroelectronics STMFX I2C GPIO expander pinctrl driver"
depends on DM && PINCTRL_FULL
help
I2C driver for STMicroelectronics Multi-Function eXpander (STMFX)
GPIO expander.
Supports pin multiplexing control on stm32 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config SPL_PINCTRL_STMFX
bool "STMicroelectronics STMFX I2C GPIO expander pinctrl driver in SPL"
depends on SPL_PINCTRL_FULL
help
This option is an SPL-variant of the SPL_PINCTRL_STMFX option.
See the help of PINCTRL_STMFX for details.
config ASPEED_AST2500_PINCTRL
bool "Aspeed AST2500 pin control driver"
depends on DM && PINCTRL_GENERIC && ASPEED_AST2500
default y
help
Support pin multiplexing control on Aspeed ast2500 SoC. The driver uses
Generic Pinctrl framework and is compatible with the Linux driver,
i.e. it uses the same device tree configuration.
endif
source "drivers/pinctrl/broadcom/Kconfig"
source "drivers/pinctrl/exynos/Kconfig"
source "drivers/pinctrl/mediatek/Kconfig"
source "drivers/pinctrl/meson/Kconfig"
source "drivers/pinctrl/mscc/Kconfig"
source "drivers/pinctrl/mtmips/Kconfig"
source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/nxp/Kconfig"
source "drivers/pinctrl/renesas/Kconfig"
source "drivers/pinctrl/rockchip/Kconfig"
source "drivers/pinctrl/uniphier/Kconfig"
endmenu
@@ -0,0 +1,27 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += pinctrl-uclass.o
obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o
obj-y += nxp/
obj-$(CONFIG_$(SPL_)PINCTRL_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-$(CONFIG_ARCH_ATH79) += ath79/
obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
obj-$(CONFIG_ARCH_RMOBILE) += renesas/
obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o
obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/
obj-$(CONFIG_PINCTRL_MESON) += meson/
obj-$(CONFIG_PINCTRL_MTK) += mediatek/
obj-$(CONFIG_PINCTRL_MSCC) += mscc/
obj-$(CONFIG_ARCH_MVEBU) += mvebu/
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o
obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o
obj-$(CONFIG_$(SPL_)PINCTRL_STMFX) += pinctrl-stmfx.o
obj-y += broadcom/
@@ -0,0 +1 @@
obj-$(CONFIG_ASPEED_AST2500_PINCTRL) += pinctrl_ast2500.o
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2017 Google, Inc
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/pinctrl.h>
#include <asm/arch/scu_ast2500.h>
#include <dm/pinctrl.h>
/*
* This driver works with very simple configuration that has the same name
* for group and function. This way it is compatible with the Linux Kernel
* driver.
*/
struct ast2500_pinctrl_priv {
struct ast2500_scu *scu;
};
static int ast2500_pinctrl_probe(struct udevice *dev)
{
struct ast2500_pinctrl_priv *priv = dev_get_priv(dev);
priv->scu = ast_get_scu();
return 0;
}
struct ast2500_group_config {
char *group_name;
/* Control register number (1-10) */
unsigned reg_num;
/* The mask of control bits in the register */
u32 ctrl_bit_mask;
};
static const struct ast2500_group_config ast2500_groups[] = {
{ "I2C1", 8, (1 << 13) | (1 << 12) },
{ "I2C2", 8, (1 << 15) | (1 << 14) },
{ "I2C3", 8, (1 << 16) },
{ "I2C4", 5, (1 << 17) },
{ "I2C4", 5, (1 << 17) },
{ "I2C5", 5, (1 << 18) },
{ "I2C6", 5, (1 << 19) },
{ "I2C7", 5, (1 << 20) },
{ "I2C8", 5, (1 << 21) },
{ "I2C9", 5, (1 << 22) },
{ "I2C10", 5, (1 << 23) },
{ "I2C11", 5, (1 << 24) },
{ "I2C12", 5, (1 << 25) },
{ "I2C13", 5, (1 << 26) },
{ "I2C14", 5, (1 << 27) },
{ "MAC1LINK", 1, (1 << 0) },
{ "MDIO1", 3, (1 << 31) | (1 << 30) },
{ "MAC2LINK", 1, (1 << 1) },
{ "MDIO2", 5, (1 << 2) },
{ "SD1", 5, (1 << 0) },
{ "SD2", 5, (1 << 1) },
};
static int ast2500_pinctrl_get_groups_count(struct udevice *dev)
{
debug("PINCTRL: get_(functions/groups)_count\n");
return ARRAY_SIZE(ast2500_groups);
}
static const char *ast2500_pinctrl_get_group_name(struct udevice *dev,
unsigned selector)
{
debug("PINCTRL: get_(function/group)_name %u\n", selector);
return ast2500_groups[selector].group_name;
}
static int ast2500_pinctrl_group_set(struct udevice *dev, unsigned selector,
unsigned func_selector)
{
struct ast2500_pinctrl_priv *priv = dev_get_priv(dev);
const struct ast2500_group_config *config;
u32 *ctrl_reg;
debug("PINCTRL: group_set <%u, %u>\n", selector, func_selector);
if (selector >= ARRAY_SIZE(ast2500_groups))
return -EINVAL;
config = &ast2500_groups[selector];
if (config->reg_num > 6)
ctrl_reg = &priv->scu->pinmux_ctrl1[config->reg_num - 7];
else
ctrl_reg = &priv->scu->pinmux_ctrl[config->reg_num - 1];
ast_scu_unlock(priv->scu);
setbits_le32(ctrl_reg, config->ctrl_bit_mask);
ast_scu_lock(priv->scu);
return 0;
}
static struct pinctrl_ops ast2500_pinctrl_ops = {
.set_state = pinctrl_generic_set_state,
.get_groups_count = ast2500_pinctrl_get_groups_count,
.get_group_name = ast2500_pinctrl_get_group_name,
.get_functions_count = ast2500_pinctrl_get_groups_count,
.get_function_name = ast2500_pinctrl_get_group_name,
.pinmux_group_set = ast2500_pinctrl_group_set,
};
static const struct udevice_id ast2500_pinctrl_ids[] = {
{ .compatible = "aspeed,ast2500-pinctrl" },
{ .compatible = "aspeed,g5-pinctrl" },
{ }
};
U_BOOT_DRIVER(pinctrl_ast2500) = {
.name = "aspeed_ast2500_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = ast2500_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct ast2500_pinctrl_priv),
.ops = &ast2500_pinctrl_ops,
.probe = ast2500_pinctrl_probe,
};
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_PINCTRL_AR933X) += pinctrl_ar933x.o
obj-$(CONFIG_PINCTRL_QCA953X) += pinctrl_qca953x.o
@@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <dm/pinctrl.h>
#include <mach/ar71xx_regs.h>
DECLARE_GLOBAL_DATA_PTR;
enum periph_id {
PERIPH_ID_UART0,
PERIPH_ID_SPI0,
PERIPH_ID_NONE = -1,
};
struct ar933x_pinctrl_priv {
void __iomem *regs;
};
static void pinctrl_ar933x_spi_config(struct ar933x_pinctrl_priv *priv, int cs)
{
switch (cs) {
case 0:
clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
AR933X_GPIO(4), AR933X_GPIO(3) |
AR933X_GPIO(5) | AR933X_GPIO(2));
setbits_be32(priv->regs + AR71XX_GPIO_REG_FUNC,
AR933X_GPIO_FUNC_SPI_EN |
AR933X_GPIO_FUNC_RES_TRUE);
break;
}
}
static void pinctrl_ar933x_uart_config(struct ar933x_pinctrl_priv *priv, int uart_id)
{
switch (uart_id) {
case PERIPH_ID_UART0:
clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
AR933X_GPIO(9), AR933X_GPIO(10));
setbits_be32(priv->regs + AR71XX_GPIO_REG_FUNC,
AR933X_GPIO_FUNC_UART_EN |
AR933X_GPIO_FUNC_RES_TRUE);
break;
}
}
static int ar933x_pinctrl_request(struct udevice *dev, int func, int flags)
{
struct ar933x_pinctrl_priv *priv = dev_get_priv(dev);
debug("%s: func=%x, flags=%x\n", __func__, func, flags);
switch (func) {
case PERIPH_ID_SPI0:
pinctrl_ar933x_spi_config(priv, flags);
break;
case PERIPH_ID_UART0:
pinctrl_ar933x_uart_config(priv, func);
break;
default:
return -EINVAL;
}
return 0;
}
static int ar933x_pinctrl_get_periph_id(struct udevice *dev,
struct udevice *periph)
{
u32 cell[2];
int ret;
ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(periph),
"interrupts", cell, ARRAY_SIZE(cell));
if (ret < 0)
return -EINVAL;
switch (cell[0]) {
case 128:
return PERIPH_ID_UART0;
case 129:
return PERIPH_ID_SPI0;
}
return -ENOENT;
}
static int ar933x_pinctrl_set_state_simple(struct udevice *dev,
struct udevice *periph)
{
int func;
func = ar933x_pinctrl_get_periph_id(dev, periph);
if (func < 0)
return func;
return ar933x_pinctrl_request(dev, func, 0);
}
static struct pinctrl_ops ar933x_pinctrl_ops = {
.set_state_simple = ar933x_pinctrl_set_state_simple,
.request = ar933x_pinctrl_request,
.get_periph_id = ar933x_pinctrl_get_periph_id,
};
static int ar933x_pinctrl_probe(struct udevice *dev)
{
struct ar933x_pinctrl_priv *priv = dev_get_priv(dev);
fdt_addr_t addr;
addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = map_physmem(addr,
AR71XX_GPIO_SIZE,
MAP_NOCACHE);
return 0;
}
static const struct udevice_id ar933x_pinctrl_ids[] = {
{ .compatible = "qca,ar933x-pinctrl" },
{ }
};
U_BOOT_DRIVER(pinctrl_ar933x) = {
.name = "pinctrl_ar933x",
.id = UCLASS_PINCTRL,
.of_match = ar933x_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct ar933x_pinctrl_priv),
.ops = &ar933x_pinctrl_ops,
.probe = ar933x_pinctrl_probe,
};
@@ -0,0 +1,155 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <dm/pinctrl.h>
#include <mach/ar71xx_regs.h>
DECLARE_GLOBAL_DATA_PTR;
enum periph_id {
PERIPH_ID_UART0,
PERIPH_ID_SPI0,
PERIPH_ID_NONE = -1,
};
struct qca953x_pinctrl_priv {
void __iomem *regs;
};
static void pinctrl_qca953x_spi_config(struct qca953x_pinctrl_priv *priv, int cs)
{
switch (cs) {
case 0:
clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
QCA953X_GPIO(5) | QCA953X_GPIO(6) |
QCA953X_GPIO(7), QCA953X_GPIO(8));
clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC1,
QCA953X_GPIO_MUX_MASK(8) |
QCA953X_GPIO_MUX_MASK(16) |
QCA953X_GPIO_MUX_MASK(24),
(QCA953X_GPIO_OUT_MUX_SPI_CS0 << 8) |
(QCA953X_GPIO_OUT_MUX_SPI_CLK << 16) |
(QCA953X_GPIO_OUT_MUX_SPI_MOSI << 24));
clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
QCA953X_GPIO_MUX_MASK(0),
QCA953X_GPIO_IN_MUX_SPI_DATA_IN);
setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
QCA953X_GPIO(8));
break;
}
}
static void pinctrl_qca953x_uart_config(struct qca953x_pinctrl_priv *priv, int uart_id)
{
switch (uart_id) {
case PERIPH_ID_UART0:
clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
QCA953X_GPIO(9), QCA953X_GPIO(10));
clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC2,
QCA953X_GPIO_MUX_MASK(16),
QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16);
clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
QCA953X_GPIO_MUX_MASK(8),
QCA953X_GPIO_IN_MUX_UART0_SIN << 8);
setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
QCA953X_GPIO(10));
break;
}
}
static int qca953x_pinctrl_request(struct udevice *dev, int func, int flags)
{
struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
debug("%s: func=%x, flags=%x\n", __func__, func, flags);
switch (func) {
case PERIPH_ID_SPI0:
pinctrl_qca953x_spi_config(priv, flags);
break;
case PERIPH_ID_UART0:
pinctrl_qca953x_uart_config(priv, func);
break;
default:
return -EINVAL;
}
return 0;
}
static int qca953x_pinctrl_get_periph_id(struct udevice *dev,
struct udevice *periph)
{
u32 cell[2];
int ret;
ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(periph),
"interrupts", cell, ARRAY_SIZE(cell));
if (ret < 0)
return -EINVAL;
switch (cell[0]) {
case 128:
return PERIPH_ID_UART0;
case 129:
return PERIPH_ID_SPI0;
}
return -ENOENT;
}
static int qca953x_pinctrl_set_state_simple(struct udevice *dev,
struct udevice *periph)
{
int func;
func = qca953x_pinctrl_get_periph_id(dev, periph);
if (func < 0)
return func;
return qca953x_pinctrl_request(dev, func, 0);
}
static struct pinctrl_ops qca953x_pinctrl_ops = {
.set_state_simple = qca953x_pinctrl_set_state_simple,
.request = qca953x_pinctrl_request,
.get_periph_id = qca953x_pinctrl_get_periph_id,
};
static int qca953x_pinctrl_probe(struct udevice *dev)
{
struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
fdt_addr_t addr;
addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = map_physmem(addr,
AR71XX_GPIO_SIZE,
MAP_NOCACHE);
return 0;
}
static const struct udevice_id qca953x_pinctrl_ids[] = {
{ .compatible = "qca,qca953x-pinctrl" },
{ }
};
U_BOOT_DRIVER(pinctrl_qca953x) = {
.name = "pinctrl_qca953x",
.id = UCLASS_PINCTRL,
.of_match = qca953x_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct qca953x_pinctrl_priv),
.ops = &qca953x_pinctrl_ops,
.probe = qca953x_pinctrl_probe,
};
@@ -0,0 +1,15 @@
config PINCTRL_BCM283X
depends on ARCH_BCM283X && PINCTRL_FULL && OF_CONTROL
default y
bool "Broadcom 283x family pin control driver"
help
Support pin multiplexing and pin configuration control on
Broadcom's 283x family of SoCs.
config PINCTRL_BCM6838
depends on ARCH_BMIPS && PINCTRL_FULL && OF_CONTROL
default y
bool "Broadcom 6838 family pin control driver"
help
Support pin multiplexing and pin configuration control on
Broadcom's 6838 family of SoCs.
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2018 Alexander Graf <agraf@suse.de>
#
# https://spdx.org/licenses
obj-$(CONFIG_PINCTRL_BCM283X) += pinctrl-bcm283x.o
obj-$(CONFIG_PINCTRL_BCM6838) += pinctrl-bcm6838.o
@@ -0,0 +1,155 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Alexander Graf <agraf@suse.de>
*
* Based on drivers/pinctrl/mvebu/pinctrl-mvebu.c and
* drivers/gpio/bcm2835_gpio.c
*
* This driver gets instantiated by the GPIO driver, because both devices
* share the same device node.
* https://spdx.org/licenses
*/
#include <common.h>
#include <config.h>
#include <errno.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/gpio.h>
struct bcm283x_pinctrl_priv {
u32 *base_reg;
};
#define MAX_PINS_PER_BANK 16
static void bcm2835_gpio_set_func_id(struct udevice *dev, unsigned int gpio,
int func)
{
struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev);
int reg_offset;
int field_offset;
reg_offset = BCM2835_GPIO_FSEL_BANK(gpio);
field_offset = BCM2835_GPIO_FSEL_SHIFT(gpio);
clrsetbits_le32(&priv->base_reg[reg_offset],
BCM2835_GPIO_FSEL_MASK << field_offset,
(func & BCM2835_GPIO_FSEL_MASK) << field_offset);
}
static int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned int gpio)
{
struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev);
u32 val;
val = readl(&priv->base_reg[BCM2835_GPIO_FSEL_BANK(gpio)]);
return (val >> BCM2835_GPIO_FSEL_SHIFT(gpio) & BCM2835_GPIO_FSEL_MASK);
}
/*
* bcm283x_pinctrl_set_state: configure pin functions.
* @dev: the pinctrl device to be configured.
* @config: the state to be configured.
* @return: 0 in success
*/
int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
u32 pin_arr[MAX_PINS_PER_BANK];
u32 function;
int i, len, pin_count = 0;
if (!dev_read_prop(config, "brcm,pins", &len) || !len ||
len & 0x3 || dev_read_u32_array(config, "brcm,pins", pin_arr,
len / sizeof(u32))) {
debug("Failed reading pins array for pinconfig %s (%d)\n",
config->name, len);
return -EINVAL;
}
pin_count = len / sizeof(u32);
function = dev_read_u32_default(config, "brcm,function", -1);
if (function < 0) {
debug("Failed reading function for pinconfig %s (%d)\n",
config->name, function);
return -EINVAL;
}
for (i = 0; i < pin_count; i++)
bcm2835_gpio_set_func_id(dev, pin_arr[i], function);
return 0;
}
static int bcm283x_pinctrl_get_gpio_mux(struct udevice *dev, int banknum,
int index)
{
if (banknum != 0)
return -EINVAL;
return bcm2835_gpio_get_func_id(dev, index);
}
static const struct udevice_id bcm2835_pinctrl_id[] = {
{.compatible = "brcm,bcm2835-gpio"},
{.compatible = "brcm,bcm2711-gpio"},
{}
};
int bcm283x_pinctl_probe(struct udevice *dev)
{
struct bcm283x_pinctrl_priv *priv;
int ret;
struct udevice *pdev;
priv = dev_get_priv(dev);
if (!priv) {
debug("%s: Failed to get private\n", __func__);
return -EINVAL;
}
priv->base_reg = dev_read_addr_ptr(dev);
if (priv->base_reg == (void *)FDT_ADDR_T_NONE) {
debug("%s: Failed to get base address\n", __func__);
return -EINVAL;
}
/* Create GPIO device as well */
ret = device_bind(dev, lists_driver_lookup_name("gpio_bcm2835"),
"gpio_bcm2835", NULL, dev_of_offset(dev), &pdev);
if (ret) {
/*
* While we really want the pinctrl driver to work to make
* devices go where they should go, the GPIO controller is
* not quite as crucial as it's only rarely used, so don't
* fail here.
*/
printf("Failed to bind GPIO driver\n");
}
return 0;
}
static struct pinctrl_ops bcm283x_pinctrl_ops = {
.set_state = bcm283x_pinctrl_set_state,
.get_gpio_mux = bcm283x_pinctrl_get_gpio_mux,
};
U_BOOT_DRIVER(pinctrl_bcm283x) = {
.name = "bcm283x_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(bcm2835_pinctrl_id),
.priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv),
.ops = &bcm283x_pinctrl_ops,
.probe = bcm283x_pinctl_probe,
#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_BOARD)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
@@ -0,0 +1,161 @@
// SPDX-License-Identifier: GPL-2.0
#include <common.h>
#include <dm.h>
#include <regmap.h>
#include <syscon.h>
#include <dm/pinctrl.h>
#define BCM6838_CMD_LOAD_MUX 0x21
#define BCM6838_FUNC_OFFS 12
#define BCM6838_FUNC_MASK (0x37 << BCM6838_FUNC_OFFS)
#define BCM6838_PIN_OFFS 0
#define BCM6838_PIN_MASK (0xfff << BCM6838_PIN_OFFS)
#define BCM6838_MAX_PIN_NAME_LEN 8
static char bcm6838_pin_name[BCM6838_MAX_PIN_NAME_LEN];
#define BCM6838_MAX_FUNC_NAME_LEN 8
static char bcm6838_func_name[BCM6838_MAX_FUNC_NAME_LEN];
struct bcm6838_test_port_hw {
unsigned long port_blk_data1;
unsigned long port_blk_data2;
unsigned long port_command;
};
static const struct bcm6838_test_port_hw bcm6838_hw = {
.port_blk_data1 = 0x10,
.port_blk_data2 = 0x14,
.port_command = 0x18
};
struct bcm6838_pinctrl_priv {
const struct bcm6838_test_port_hw *hw;
struct regmap *regmap;
u32 pins_count;
u32 functions_count;
};
int bcm6838_pinctrl_get_pins_count(struct udevice *dev)
{
struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
return priv->pins_count;
}
const char *bcm6838_pinctrl_get_pin_name(struct udevice *dev,
unsigned int selector)
{
snprintf(bcm6838_pin_name, BCM6838_MAX_PIN_NAME_LEN, "%u", selector);
return bcm6838_pin_name;
}
int bcm6838_pinctrl_get_functions_count(struct udevice *dev)
{
struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
return priv->functions_count;
}
const char *bcm6838_pinctrl_get_function_name(struct udevice *dev,
unsigned int selector)
{
snprintf(bcm6838_func_name, BCM6838_MAX_FUNC_NAME_LEN, "%u", selector);
return bcm6838_func_name;
}
int bcm6838_pinctrl_pinmux_set(struct udevice *dev,
unsigned int pin_selector,
unsigned int func_selector)
{
struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
const struct bcm6838_test_port_hw *hw = priv->hw;
unsigned int data;
regmap_write(priv->regmap, hw->port_blk_data1, 0);
data = (func_selector << BCM6838_FUNC_OFFS) & BCM6838_FUNC_MASK;
data |= (pin_selector << BCM6838_PIN_OFFS) & BCM6838_PIN_MASK;
regmap_write(priv->regmap, hw->port_blk_data2, data);
regmap_write(priv->regmap, hw->port_command, BCM6838_CMD_LOAD_MUX);
return 0;
}
int bcm6838_pinctrl_probe(struct udevice *dev)
{
struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
const struct bcm6838_test_port_hw *hw =
(const struct bcm6838_test_port_hw *)dev_get_driver_data(dev);
int err;
u32 phandle;
ofnode node;
err = ofnode_read_u32(dev_ofnode(dev), "regmap", &phandle);
if (err) {
dev_err(dev, "%s: unable to read regmap\n", __func__);
goto out;
}
node = ofnode_get_by_phandle(phandle);
if (!ofnode_valid(node)) {
dev_err(dev, "%s: unable to find node\n", __func__);
err = -EINVAL;
goto out;
}
priv->regmap = syscon_node_to_regmap(node);
if (!priv->regmap) {
dev_err(dev, "%s: unable to find regmap\n", __func__);
err = -ENODEV;
goto out;
}
err = ofnode_read_u32(dev_ofnode(dev), "brcm,pins-count",
&priv->pins_count);
if (err) {
dev_err(dev, "%s: unable to read brcm,pins-count\n",
__func__);
goto out;
}
err = ofnode_read_u32(dev_ofnode(dev), "brcm,functions-count",
&priv->functions_count);
if (err) {
dev_err(dev, "%s: unable to read brcm,functions-count\n",
__func__);
goto out;
}
priv->hw = hw;
out:
return err;
}
const struct pinctrl_ops bcm6838_pinctrl_ops = {
.set_state = pinctrl_generic_set_state,
.get_pins_count = bcm6838_pinctrl_get_pins_count,
.get_pin_name = bcm6838_pinctrl_get_pin_name,
.get_functions_count = bcm6838_pinctrl_get_functions_count,
.get_function_name = bcm6838_pinctrl_get_function_name,
.pinmux_set = bcm6838_pinctrl_pinmux_set,
};
static const struct udevice_id bcm6838_pinctrl_match[] = {
{
.compatible = "brcm,bcm6838-pinctrl",
.data = (ulong)&bcm6838_hw,
},
{ /* sentinel */ }
};
U_BOOT_DRIVER(bcm6838_pinctrl) = {
.name = "bcm6838_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = bcm6838_pinctrl_match,
.ops = &bcm6838_pinctrl_ops,
.priv_auto_alloc_size = sizeof(struct bcm6838_pinctrl_priv),
.probe = bcm6838_pinctrl_probe,
};
@@ -0,0 +1,10 @@
config PINCTRL_EXYNOS
bool
config PINCTRL_EXYNOS7420
bool "Samsung Exynos7420 pinctrl driver"
depends on ARCH_EXYNOS && PINCTRL_FULL
select PINCTRL_EXYNOS
help
Support pin multiplexing and pin configuration control on
Samsung's Exynos7420 SoC.
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2016 Samsung Electronics
# Thomas Abraham <thomas.ab@samsung.com>
obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o
obj-$(CONFIG_PINCTRL_EXYNOS7420) += pinctrl-exynos7420.o
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Exynos pinctrl driver common code.
* Copyright (C) 2016 Samsung Electronics
* Thomas Abraham <thomas.ab@samsung.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include "pinctrl-exynos.h"
DECLARE_GLOBAL_DATA_PTR;
/**
* exynos_pinctrl_setup_peri: setup pinctrl for a peripheral.
* conf: soc specific pin configuration data array
* num_conf: number of configurations in the conf array.
* base: base address of the pin controller.
*/
void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
unsigned int num_conf, unsigned long base)
{
unsigned int idx, val;
for (idx = 0; idx < num_conf; idx++) {
val = readl(base + conf[idx].offset);
val &= ~(conf[idx].mask);
val |= conf[idx].value;
writel(val, base + conf[idx].offset);
}
}
/* given a pin-name, return the address of pin config registers */
static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
u32 *pin)
{
struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl;
const struct samsung_pin_bank_data *bank_data = pin_ctrl->pin_banks;
u32 nr_banks = pin_ctrl->nr_banks, idx = 0;
char bank[10];
/*
* The format of the pin name is <bank name>-<pin_number>.
* Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number.
*/
while (pin_name[idx] != '-') {
bank[idx] = pin_name[idx];
idx++;
}
bank[idx] = '\0';
*pin = pin_name[++idx] - '0';
/* lookup the pin bank data using the pin bank name */
for (idx = 0; idx < nr_banks; idx++)
if (!strcmp(bank, bank_data[idx].name))
break;
return priv->base + bank_data[idx].offset;
}
/**
* exynos_pinctrl_set_state: configure a pin state.
* dev: the pinctrl device to be configured.
* config: the state to be configured.
*/
int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(config);
unsigned int count, idx, pin_num;
unsigned int pinfunc, pinpud, pindrv;
unsigned long reg, value;
const char *name;
/*
* refer to the following document for the pinctrl bindings
* linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
*/
count = fdt_stringlist_count(fdt, node, "samsung,pins");
if (count <= 0)
return -EINVAL;
pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1);
pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1);
pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1);
for (idx = 0; idx < count; idx++) {
name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
if (!name)
continue;
reg = pin_to_bank_base(dev, name, &pin_num);
if (pinfunc != -1) {
value = readl(reg + PIN_CON);
value &= ~(0xf << (pin_num << 2));
value |= (pinfunc << (pin_num << 2));
writel(value, reg + PIN_CON);
}
if (pinpud != -1) {
value = readl(reg + PIN_PUD);
value &= ~(0x3 << (pin_num << 1));
value |= (pinpud << (pin_num << 1));
writel(value, reg + PIN_PUD);
}
if (pindrv != -1) {
value = readl(reg + PIN_DRV);
value &= ~(0x3 << (pin_num << 1));
value |= (pindrv << (pin_num << 1));
writel(value, reg + PIN_DRV);
}
}
return 0;
}
int exynos_pinctrl_probe(struct udevice *dev)
{
struct exynos_pinctrl_priv *priv;
fdt_addr_t base;
priv = dev_get_priv(dev);
if (!priv)
return -EINVAL;
base = devfdt_get_addr(dev);
if (base == FDT_ADDR_T_NONE)
return -EINVAL;
priv->base = base;
priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
dev->req_seq;
return 0;
}
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Exynos pinctrl driver header.
* Copyright (C) 2016 Samsung Electronics
* Thomas Abraham <thomas.ab@samsung.com>
*/
#ifndef __PINCTRL_EXYNOS_H_
#define __PINCTRL_EXYNOS__H_
#define PIN_CON 0x00 /* Offset of pin function register */
#define PIN_DAT 0x04 /* Offset of pin data register */
#define PIN_PUD 0x08 /* Offset of pin pull up/down config register */
#define PIN_DRV 0x0C /* Offset of pin drive strength register */
/**
* struct samsung_pin_bank_data: represent a controller pin-bank data.
* @offset: starting offset of the pin-bank registers.
* @nr_pins: number of pins included in this bank.
* @name: name to be prefixed for each pin in this pin bank.
*/
struct samsung_pin_bank_data {
u32 offset;
u8 nr_pins;
const char *name;
};
#define EXYNOS_PIN_BANK(pins, reg, id) \
{ \
.offset = reg, \
.nr_pins = pins, \
.name = id \
}
/**
* struct samsung_pin_ctrl: represent a pin controller.
* @pin_banks: list of pin banks included in this controller.
* @nr_banks: number of pin banks.
*/
struct samsung_pin_ctrl {
const struct samsung_pin_bank_data *pin_banks;
u32 nr_banks;
};
/**
* struct exynos_pinctrl_priv: exynos pin controller driver private data
* @pin_ctrl: pin controller bank information.
* @base: base address of the pin controller instance.
* @num_banks: number of pin banks included in the pin controller.
*/
struct exynos_pinctrl_priv {
const struct samsung_pin_ctrl *pin_ctrl;
unsigned long base;
int num_banks;
};
/**
* struct exynos_pinctrl_config_data: configuration for a peripheral.
* @offset: offset of the config registers in the controller.
* @mask: value of the register to be masked with.
* @value: new value to be programmed.
*/
struct exynos_pinctrl_config_data {
const unsigned int offset;
const unsigned int mask;
const unsigned int value;
};
void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
unsigned int num_conf, unsigned long base);
int exynos_pinctrl_set_state(struct udevice *dev,
struct udevice *config);
int exynos_pinctrl_probe(struct udevice *dev);
#endif /* __PINCTRL_EXYNOS_H_ */
@@ -0,0 +1,116 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Exynos7420 pinctrl driver.
* Copyright (C) 2016 Samsung Electronics
* Thomas Abraham <thomas.ab@samsung.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <fdtdec.h>
#include <asm/arch/pinmux.h>
#include "pinctrl-exynos.h"
#define GPD1_OFFSET 0xc0
static struct exynos_pinctrl_config_data serial2_conf[] = {
{
.offset = GPD1_OFFSET + PIN_CON,
.mask = 0x00ff0000,
.value = 0x00220000,
}, {
.offset = GPD1_OFFSET + PIN_PUD,
.mask = 0x00000f00,
.value = 0x00000f00,
},
};
static int exynos7420_pinctrl_request(struct udevice *dev, int peripheral,
int flags)
{
struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
unsigned long base = priv->base;
switch (PERIPH_ID_UART2) {
case PERIPH_ID_UART2:
exynos_pinctrl_setup_peri(serial2_conf,
ARRAY_SIZE(serial2_conf), base);
break;
default:
return -ENODEV;
}
return 0;
}
static struct pinctrl_ops exynos7420_pinctrl_ops = {
.set_state = exynos_pinctrl_set_state,
.request = exynos7420_pinctrl_request,
};
/* pin banks of Exynos7420 pin-controller - BUS0 */
static const struct samsung_pin_bank_data exynos7420_pin_banks0[] = {
EXYNOS_PIN_BANK(5, 0x000, "gpb0"),
EXYNOS_PIN_BANK(8, 0x020, "gpc0"),
EXYNOS_PIN_BANK(2, 0x040, "gpc1"),
EXYNOS_PIN_BANK(6, 0x060, "gpc2"),
EXYNOS_PIN_BANK(8, 0x080, "gpc3"),
EXYNOS_PIN_BANK(4, 0x0a0, "gpd0"),
EXYNOS_PIN_BANK(6, 0x0c0, "gpd1"),
EXYNOS_PIN_BANK(8, 0x0e0, "gpd2"),
EXYNOS_PIN_BANK(5, 0x100, "gpd4"),
EXYNOS_PIN_BANK(4, 0x120, "gpd5"),
EXYNOS_PIN_BANK(6, 0x140, "gpd6"),
EXYNOS_PIN_BANK(3, 0x160, "gpd7"),
EXYNOS_PIN_BANK(2, 0x180, "gpd8"),
EXYNOS_PIN_BANK(2, 0x1a0, "gpg0"),
EXYNOS_PIN_BANK(4, 0x1c0, "gpg3"),
};
/* pin banks of Exynos7420 pin-controller - FSYS0 */
static const struct samsung_pin_bank_data exynos7420_pin_banks1[] = {
EXYNOS_PIN_BANK(7, 0x000, "gpr4"),
};
/* pin banks of Exynos7420 pin-controller - FSYS1 */
static const struct samsung_pin_bank_data exynos7420_pin_banks2[] = {
EXYNOS_PIN_BANK(4, 0x000, "gpr0"),
EXYNOS_PIN_BANK(8, 0x020, "gpr1"),
EXYNOS_PIN_BANK(5, 0x040, "gpr2"),
EXYNOS_PIN_BANK(8, 0x060, "gpr3"),
};
const struct samsung_pin_ctrl exynos7420_pin_ctrl[] = {
{
/* pin-controller instance BUS0 data */
.pin_banks = exynos7420_pin_banks0,
.nr_banks = ARRAY_SIZE(exynos7420_pin_banks0),
}, {
/* pin-controller instance FSYS0 data */
.pin_banks = exynos7420_pin_banks1,
.nr_banks = ARRAY_SIZE(exynos7420_pin_banks1),
}, {
/* pin-controller instance FSYS1 data */
.pin_banks = exynos7420_pin_banks2,
.nr_banks = ARRAY_SIZE(exynos7420_pin_banks2),
},
};
static const struct udevice_id exynos7420_pinctrl_ids[] = {
{ .compatible = "samsung,exynos7420-pinctrl",
.data = (ulong)exynos7420_pin_ctrl },
{ }
};
U_BOOT_DRIVER(pinctrl_exynos7420) = {
.name = "pinctrl_exynos7420",
.id = UCLASS_PINCTRL,
.of_match = exynos7420_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct exynos_pinctrl_priv),
.ops = &exynos7420_pinctrl_ops,
.probe = exynos_pinctrl_probe,
};
@@ -0,0 +1,23 @@
if ARCH_MEDIATEK
config PINCTRL_MTK
depends on PINCTRL_GENERIC
bool
config PINCTRL_MT7623
bool "MT7623 SoC pinctrl driver"
select PINCTRL_MTK
config PINCTRL_MT7629
bool "MT7629 SoC pinctrl driver"
select PINCTRL_MTK
config PINCTRL_MT8516
bool "MT8516 SoC pinctrl driver"
select PINCTRL_MTK
config PINCTRL_MT8518
bool "MT8518 SoC pinctrl driver"
select PINCTRL_MTK
endif
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
# Core
obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o
# SoC Drivers
obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o
obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
obj-$(CONFIG_PINCTRL_MT8516) += pinctrl-mt8516.o
obj-$(CONFIG_PINCTRL_MT8518) += pinctrl-mt8518.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,409 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 MediaTek Inc.
* Author: Ryder Lee <ryder.lee@mediatek.com>
*/
#include <dm.h>
#include "pinctrl-mtk-common.h"
#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \
_x_bits, 32, false)
#define MT7629_PIN(_number, _name) MTK_PIN(_number, _name, DRV_GRP1)
static const struct mtk_pin_field_calc mt7629_pin_mode_range[] = {
PIN_FIELD(0, 78, 0x300, 0x10, 0, 4),
};
static const struct mtk_pin_field_calc mt7629_pin_dir_range[] = {
PIN_FIELD(0, 78, 0x0, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7629_pin_di_range[] = {
PIN_FIELD(0, 78, 0x200, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7629_pin_do_range[] = {
PIN_FIELD(0, 78, 0x100, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7629_pin_ies_range[] = {
PIN_FIELD(0, 10, 0x1000, 0x10, 0, 1),
PIN_FIELD(11, 18, 0x2000, 0x10, 0, 1),
PIN_FIELD(19, 32, 0x3000, 0x10, 0, 1),
PIN_FIELD(33, 48, 0x4000, 0x10, 0, 1),
PIN_FIELD(49, 50, 0x5000, 0x10, 0, 1),
PIN_FIELD(51, 69, 0x6000, 0x10, 0, 1),
PIN_FIELD(70, 78, 0x7000, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7629_pin_smt_range[] = {
PIN_FIELD(0, 10, 0x1100, 0x10, 0, 1),
PIN_FIELD(11, 18, 0x2100, 0x10, 0, 1),
PIN_FIELD(19, 32, 0x3100, 0x10, 0, 1),
PIN_FIELD(33, 48, 0x4100, 0x10, 0, 1),
PIN_FIELD(49, 50, 0x5100, 0x10, 0, 1),
PIN_FIELD(51, 69, 0x6100, 0x10, 0, 1),
PIN_FIELD(70, 78, 0x7100, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7629_pin_pullen_range[] = {
PIN_FIELD(0, 10, 0x1400, 0x10, 0, 1),
PIN_FIELD(11, 18, 0x2400, 0x10, 0, 1),
PIN_FIELD(19, 32, 0x3400, 0x10, 0, 1),
PIN_FIELD(33, 48, 0x4400, 0x10, 0, 1),
PIN_FIELD(49, 50, 0x5400, 0x10, 0, 1),
PIN_FIELD(51, 69, 0x6400, 0x10, 0, 1),
PIN_FIELD(70, 78, 0x7400, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7629_pin_pullsel_range[] = {
PIN_FIELD(0, 10, 0x1500, 0x10, 0, 1),
PIN_FIELD(11, 18, 0x2500, 0x10, 0, 1),
PIN_FIELD(19, 32, 0x3500, 0x10, 0, 1),
PIN_FIELD(33, 48, 0x4500, 0x10, 0, 1),
PIN_FIELD(49, 50, 0x5500, 0x10, 0, 1),
PIN_FIELD(51, 69, 0x6500, 0x10, 0, 1),
PIN_FIELD(70, 78, 0x7500, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7629_pin_drv_range[] = {
PIN_FIELD(0, 10, 0x1600, 0x10, 0, 4),
PIN_FIELD(11, 18, 0x2600, 0x10, 0, 4),
PIN_FIELD(19, 32, 0x3600, 0x10, 0, 4),
PIN_FIELD(33, 48, 0x4600, 0x10, 0, 4),
PIN_FIELD(49, 50, 0x5600, 0x10, 0, 4),
PIN_FIELD(51, 69, 0x6600, 0x10, 0, 4),
PIN_FIELD(70, 78, 0x7600, 0x10, 0, 4),
};
static const struct mtk_pin_reg_calc mt7629_reg_cals[] = {
[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7629_pin_mode_range),
[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7629_pin_dir_range),
[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7629_pin_di_range),
[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7629_pin_do_range),
[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7629_pin_ies_range),
[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7629_pin_smt_range),
[PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7629_pin_pullsel_range),
[PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7629_pin_pullen_range),
[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7629_pin_drv_range),
};
static const struct mtk_pin_desc mt7629_pins[] = {
MT7629_PIN(0, "TOP_5G_CLK"),
MT7629_PIN(1, "TOP_5G_DATA"),
MT7629_PIN(2, "WF0_5G_HB0"),
MT7629_PIN(3, "WF0_5G_HB1"),
MT7629_PIN(4, "WF0_5G_HB2"),
MT7629_PIN(5, "WF0_5G_HB3"),
MT7629_PIN(6, "WF0_5G_HB4"),
MT7629_PIN(7, "WF0_5G_HB5"),
MT7629_PIN(8, "WF0_5G_HB6"),
MT7629_PIN(9, "XO_REQ"),
MT7629_PIN(10, "TOP_RST_N"),
MT7629_PIN(11, "SYS_WATCHDOG"),
MT7629_PIN(12, "EPHY_LED0_N_JTDO"),
MT7629_PIN(13, "EPHY_LED1_N_JTDI"),
MT7629_PIN(14, "EPHY_LED2_N_JTMS"),
MT7629_PIN(15, "EPHY_LED3_N_JTCLK"),
MT7629_PIN(16, "EPHY_LED4_N_JTRST_N"),
MT7629_PIN(17, "WF2G_LED_N"),
MT7629_PIN(18, "WF5G_LED_N"),
MT7629_PIN(19, "I2C_SDA"),
MT7629_PIN(20, "I2C_SCL"),
MT7629_PIN(21, "GPIO_9"),
MT7629_PIN(22, "GPIO_10"),
MT7629_PIN(23, "GPIO_11"),
MT7629_PIN(24, "GPIO_12"),
MT7629_PIN(25, "UART1_TXD"),
MT7629_PIN(26, "UART1_RXD"),
MT7629_PIN(27, "UART1_CTS"),
MT7629_PIN(28, "UART1_RTS"),
MT7629_PIN(29, "UART2_TXD"),
MT7629_PIN(30, "UART2_RXD"),
MT7629_PIN(31, "UART2_CTS"),
MT7629_PIN(32, "UART2_RTS"),
MT7629_PIN(33, "MDI_TP_P1"),
MT7629_PIN(34, "MDI_TN_P1"),
MT7629_PIN(35, "MDI_RP_P1"),
MT7629_PIN(36, "MDI_RN_P1"),
MT7629_PIN(37, "MDI_RP_P2"),
MT7629_PIN(38, "MDI_RN_P2"),
MT7629_PIN(39, "MDI_TP_P2"),
MT7629_PIN(40, "MDI_TN_P2"),
MT7629_PIN(41, "MDI_TP_P3"),
MT7629_PIN(42, "MDI_TN_P3"),
MT7629_PIN(43, "MDI_RP_P3"),
MT7629_PIN(44, "MDI_RN_P3"),
MT7629_PIN(45, "MDI_RP_P4"),
MT7629_PIN(46, "MDI_RN_P4"),
MT7629_PIN(47, "MDI_TP_P4"),
MT7629_PIN(48, "MDI_TN_P4"),
MT7629_PIN(49, "SMI_MDC"),
MT7629_PIN(50, "SMI_MDIO"),
MT7629_PIN(51, "PCIE_PERESET_N"),
MT7629_PIN(52, "PWM_0"),
MT7629_PIN(53, "GPIO_0"),
MT7629_PIN(54, "GPIO_1"),
MT7629_PIN(55, "GPIO_2"),
MT7629_PIN(56, "GPIO_3"),
MT7629_PIN(57, "GPIO_4"),
MT7629_PIN(58, "GPIO_5"),
MT7629_PIN(59, "GPIO_6"),
MT7629_PIN(60, "GPIO_7"),
MT7629_PIN(61, "GPIO_8"),
MT7629_PIN(62, "SPI_CLK"),
MT7629_PIN(63, "SPI_CS"),
MT7629_PIN(64, "SPI_MOSI"),
MT7629_PIN(65, "SPI_MISO"),
MT7629_PIN(66, "SPI_WP"),
MT7629_PIN(67, "SPI_HOLD"),
MT7629_PIN(68, "UART0_TXD"),
MT7629_PIN(69, "UART0_RXD"),
MT7629_PIN(70, "TOP_2G_CLK"),
MT7629_PIN(71, "TOP_2G_DATA"),
MT7629_PIN(72, "WF0_2G_HB0"),
MT7629_PIN(73, "WF0_2G_HB1"),
MT7629_PIN(74, "WF0_2G_HB2"),
MT7629_PIN(75, "WF0_2G_HB3"),
MT7629_PIN(76, "WF0_2G_HB4"),
MT7629_PIN(77, "WF0_2G_HB5"),
MT7629_PIN(78, "WF0_2G_HB6"),
};
/* List all groups consisting of these pins dedicated to the enablement of
* certain hardware block and the corresponding mode for all of the pins.
* The hardware probably has multiple combinations of these pinouts.
*/
/* WF 5G */
static int mt7629_wf0_5g_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, };
static int mt7629_wf0_5g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
/* LED for EPHY */
static int mt7629_ephy_leds_pins[] = { 12, 13, 14, 15, 16, 17, 18, };
static int mt7629_ephy_leds_funcs[] = { 1, 1, 1, 1, 1, 1, 1, };
static int mt7629_ephy_led0_pins[] = { 12, };
static int mt7629_ephy_led0_funcs[] = { 1, };
static int mt7629_ephy_led1_pins[] = { 13, };
static int mt7629_ephy_led1_funcs[] = { 1, };
static int mt7629_ephy_led2_pins[] = { 14, };
static int mt7629_ephy_led2_funcs[] = { 1, };
static int mt7629_ephy_led3_pins[] = { 15, };
static int mt7629_ephy_led3_funcs[] = { 1, };
static int mt7629_ephy_led4_pins[] = { 16, };
static int mt7629_ephy_led4_funcs[] = { 1, };
static int mt7629_wf2g_led_pins[] = { 17, };
static int mt7629_wf2g_led_funcs[] = { 1, };
static int mt7629_wf5g_led_pins[] = { 18, };
static int mt7629_wf5g_led_funcs[] = { 1, };
/* Watchdog */
static int mt7629_watchdog_pins[] = { 11, };
static int mt7629_watchdog_funcs[] = { 1, };
/* LED for GPHY */
static int mt7629_gphy_leds_0_pins[] = { 21, 22, 23, };
static int mt7629_gphy_leds_0_funcs[] = { 2, 2, 2, };
static int mt7629_gphy_led1_0_pins[] = { 21, };
static int mt7629_gphy_led1_0_funcs[] = { 2, };
static int mt7629_gphy_led2_0_pins[] = { 22, };
static int mt7629_gphy_led2_0_funcs[] = { 2, };
static int mt7629_gphy_led3_0_pins[] = { 23, };
static int mt7629_gphy_led3_0_funcs[] = { 2, };
static int mt7629_gphy_leds_1_pins[] = { 57, 58, 59, };
static int mt7629_gphy_leds_1_funcs[] = { 1, 1, 1, };
static int mt7629_gphy_led1_1_pins[] = { 57, };
static int mt7629_gphy_led1_1_funcs[] = { 1, };
static int mt7629_gphy_led2_1_pins[] = { 58, };
static int mt7629_gphy_led2_1_funcs[] = { 1, };
static int mt7629_gphy_led3_1_pins[] = { 59, };
static int mt7629_gphy_led3_1_funcs[] = { 1, };
/* I2C */
static int mt7629_i2c_0_pins[] = { 19, 20, };
static int mt7629_i2c_0_funcs[] = { 1, 1, };
static int mt7629_i2c_1_pins[] = { 53, 54, };
static int mt7629_i2c_1_funcs[] = { 1, 1, };
/* SPI */
static int mt7629_spi_0_pins[] = { 21, 22, 23, 24, };
static int mt7629_spi_0_funcs[] = { 1, 1, 1, 1, };
static int mt7629_spi_1_pins[] = { 62, 63, 64, 65, };
static int mt7629_spi_1_funcs[] = { 1, 1, 1, 1, };
static int mt7629_spi_wp_pins[] = { 66, };
static int mt7629_spi_wp_funcs[] = { 1, };
static int mt7629_spi_hold_pins[] = { 67, };
static int mt7629_spi_hold_funcs[] = { 1, };
/* UART */
static int mt7629_uart1_0_txd_rxd_pins[] = { 25, 26, };
static int mt7629_uart1_0_txd_rxd_funcs[] = { 1, 1, };
static int mt7629_uart1_1_txd_rxd_pins[] = { 53, 54, };
static int mt7629_uart1_1_txd_rxd_funcs[] = { 2, 2, };
static int mt7629_uart2_0_txd_rxd_pins[] = { 29, 30, };
static int mt7629_uart2_0_txd_rxd_funcs[] = { 1, 1, };
static int mt7629_uart2_1_txd_rxd_pins[] = { 57, 58, };
static int mt7629_uart2_1_txd_rxd_funcs[] = { 2, 2, };
static int mt7629_uart1_0_cts_rts_pins[] = { 27, 28, };
static int mt7629_uart1_0_cts_rts_funcs[] = { 1, 1, };
static int mt7629_uart1_1_cts_rts_pins[] = { 55, 56, };
static int mt7629_uart1_1_cts_rts_funcs[] = { 2, 2, };
static int mt7629_uart2_0_cts_rts_pins[] = { 31, 32, };
static int mt7629_uart2_0_cts_rts_funcs[] = { 1, 1, };
static int mt7629_uart2_1_cts_rts_pins[] = { 59, 60, };
static int mt7629_uart2_1_cts_rts_funcs[] = { 2, 2, };
static int mt7629_uart0_txd_rxd_pins[] = { 68, 69, };
static int mt7629_uart0_txd_rxd_funcs[] = { 1, 1, };
/* MDC/MDIO */
static int mt7629_mdc_mdio_pins[] = { 49, 50, };
static int mt7629_mdc_mdio_funcs[] = { 1, 1, };
/* PCIE */
static int mt7629_pcie_pereset_pins[] = { 51, };
static int mt7629_pcie_pereset_funcs[] = { 1, };
static int mt7629_pcie_wake_pins[] = { 55, };
static int mt7629_pcie_wake_funcs[] = { 1, };
static int mt7629_pcie_clkreq_pins[] = { 56, };
static int mt7629_pcie_clkreq_funcs[] = { 1, };
/* PWM */
static int mt7629_pwm_0_pins[] = { 52, };
static int mt7629_pwm_0_funcs[] = { 1, };
static int mt7629_pwm_1_pins[] = { 61, };
static int mt7629_pwm_1_funcs[] = { 2, };
/* WF 2G */
static int mt7629_wf0_2g_pins[] = { 70, 71, 72, 73, 74, 75, 76, 77, 78, };
static int mt7629_wf0_2g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, };
/* SNFI */
static int mt7629_snfi_pins[] = { 62, 63, 64, 65, 66, 67 };
static int mt7629_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 };
/* SPI NOR */
static int mt7629_snor_pins[] = { 62, 63, 64, 65, 66, 67 };
static int mt7629_snor_funcs[] = { 1, 1, 1, 1, 1, 1 };
static const struct mtk_group_desc mt7629_groups[] = {
PINCTRL_PIN_GROUP("wf0_5g", mt7629_wf0_5g),
PINCTRL_PIN_GROUP("ephy_leds", mt7629_ephy_leds),
PINCTRL_PIN_GROUP("ephy_led0", mt7629_ephy_led0),
PINCTRL_PIN_GROUP("ephy_led1", mt7629_ephy_led1),
PINCTRL_PIN_GROUP("ephy_led2", mt7629_ephy_led2),
PINCTRL_PIN_GROUP("ephy_led3", mt7629_ephy_led3),
PINCTRL_PIN_GROUP("ephy_led4", mt7629_ephy_led4),
PINCTRL_PIN_GROUP("wf2g_led", mt7629_wf2g_led),
PINCTRL_PIN_GROUP("wf5g_led", mt7629_wf5g_led),
PINCTRL_PIN_GROUP("watchdog", mt7629_watchdog),
PINCTRL_PIN_GROUP("gphy_leds_0", mt7629_gphy_leds_0),
PINCTRL_PIN_GROUP("gphy_led1_0", mt7629_gphy_led1_0),
PINCTRL_PIN_GROUP("gphy_led2_0", mt7629_gphy_led2_0),
PINCTRL_PIN_GROUP("gphy_led3_0", mt7629_gphy_led3_0),
PINCTRL_PIN_GROUP("gphy_leds_1", mt7629_gphy_leds_1),
PINCTRL_PIN_GROUP("gphy_led1_1", mt7629_gphy_led1_1),
PINCTRL_PIN_GROUP("gphy_led2_1", mt7629_gphy_led2_1),
PINCTRL_PIN_GROUP("gphy_led3_1", mt7629_gphy_led3_1),
PINCTRL_PIN_GROUP("i2c_0", mt7629_i2c_0),
PINCTRL_PIN_GROUP("i2c_1", mt7629_i2c_1),
PINCTRL_PIN_GROUP("spi_0", mt7629_spi_0),
PINCTRL_PIN_GROUP("spi_1", mt7629_spi_1),
PINCTRL_PIN_GROUP("spi_wp", mt7629_spi_wp),
PINCTRL_PIN_GROUP("spi_hold", mt7629_spi_hold),
PINCTRL_PIN_GROUP("uart1_0_txd_rxd", mt7629_uart1_0_txd_rxd),
PINCTRL_PIN_GROUP("uart1_1_txd_rxd", mt7629_uart1_1_txd_rxd),
PINCTRL_PIN_GROUP("uart2_0_txd_rxd", mt7629_uart2_0_txd_rxd),
PINCTRL_PIN_GROUP("uart2_1_txd_rxd", mt7629_uart2_1_txd_rxd),
PINCTRL_PIN_GROUP("uart1_0_cts_rts", mt7629_uart1_0_cts_rts),
PINCTRL_PIN_GROUP("uart1_1_cts_rts", mt7629_uart1_1_cts_rts),
PINCTRL_PIN_GROUP("uart2_0_cts_rts", mt7629_uart2_0_cts_rts),
PINCTRL_PIN_GROUP("uart2_1_cts_rts", mt7629_uart2_1_cts_rts),
PINCTRL_PIN_GROUP("uart0_txd_rxd", mt7629_uart0_txd_rxd),
PINCTRL_PIN_GROUP("mdc_mdio", mt7629_mdc_mdio),
PINCTRL_PIN_GROUP("pcie_pereset", mt7629_pcie_pereset),
PINCTRL_PIN_GROUP("pcie_wake", mt7629_pcie_wake),
PINCTRL_PIN_GROUP("pcie_clkreq", mt7629_pcie_clkreq),
PINCTRL_PIN_GROUP("pwm_0", mt7629_pwm_0),
PINCTRL_PIN_GROUP("pwm_1", mt7629_pwm_1),
PINCTRL_PIN_GROUP("wf0_2g", mt7629_wf0_2g),
PINCTRL_PIN_GROUP("snfi", mt7629_snfi),
PINCTRL_PIN_GROUP("spi_nor", mt7629_snor),
};
/* Joint those groups owning the same capability in user point of view which
* allows that people tend to use through the device tree.
*/
static const char *const mt7629_ethernet_groups[] = { "mdc_mdio", };
static const char *const mt7629_i2c_groups[] = { "i2c_0", "i2c_1", };
static const char *const mt7629_led_groups[] = { "ephy_leds", "ephy_led0",
"ephy_led1", "ephy_led2",
"ephy_led3", "ephy_led4",
"wf2g_led", "wf5g_led",
"gphy_leds_0", "gphy_led1_0",
"gphy_led2_0", "gphy_led3_0",
"gphy_leds_1", "gphy_led1_1",
"gphy_led2_1", "gphy_led3_1",};
static const char *const mt7629_pcie_groups[] = { "pcie_pereset", "pcie_wake",
"pcie_clkreq", };
static const char *const mt7629_pwm_groups[] = { "pwm_0", "pwm_1", };
static const char *const mt7629_spi_groups[] = { "spi_0", "spi_1", "spi_wp",
"spi_hold", };
static const char *const mt7629_uart_groups[] = { "uart1_0_txd_rxd",
"uart1_1_txd_rxd",
"uart2_0_txd_rxd",
"uart2_1_txd_rxd",
"uart1_0_cts_rts",
"uart1_1_cts_rts",
"uart2_0_cts_rts",
"uart2_1_cts_rts",
"uart0_txd_rxd", };
static const char *const mt7629_wdt_groups[] = { "watchdog", };
static const char *const mt7629_wifi_groups[] = { "wf0_5g", "wf0_2g", };
static const char *const mt7629_flash_groups[] = { "snfi", "spi_nor" };
static const struct mtk_function_desc mt7629_functions[] = {
{"eth", mt7629_ethernet_groups, ARRAY_SIZE(mt7629_ethernet_groups)},
{"i2c", mt7629_i2c_groups, ARRAY_SIZE(mt7629_i2c_groups)},
{"led", mt7629_led_groups, ARRAY_SIZE(mt7629_led_groups)},
{"pcie", mt7629_pcie_groups, ARRAY_SIZE(mt7629_pcie_groups)},
{"pwm", mt7629_pwm_groups, ARRAY_SIZE(mt7629_pwm_groups)},
{"spi", mt7629_spi_groups, ARRAY_SIZE(mt7629_spi_groups)},
{"uart", mt7629_uart_groups, ARRAY_SIZE(mt7629_uart_groups)},
{"watchdog", mt7629_wdt_groups, ARRAY_SIZE(mt7629_wdt_groups)},
{"wifi", mt7629_wifi_groups, ARRAY_SIZE(mt7629_wifi_groups)},
{"flash", mt7629_flash_groups, ARRAY_SIZE(mt7629_flash_groups)},
};
static struct mtk_pinctrl_soc mt7629_data = {
.name = "mt7629_pinctrl",
.reg_cal = mt7629_reg_cals,
.pins = mt7629_pins,
.npins = ARRAY_SIZE(mt7629_pins),
.grps = mt7629_groups,
.ngrps = ARRAY_SIZE(mt7629_groups),
.funcs = mt7629_functions,
.nfuncs = ARRAY_SIZE(mt7629_functions),
};
static int mtk_pinctrl_mt7629_probe(struct udevice *dev)
{
return mtk_pinctrl_common_probe(dev, &mt7629_data);
}
static const struct udevice_id mt7629_pctrl_match[] = {
{ .compatible = "mediatek,mt7629-pinctrl" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(mt7629_pinctrl) = {
.name = "mt7629_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = mt7629_pctrl_match,
.ops = &mtk_pinctrl_ops,
.probe = mtk_pinctrl_mt7629_probe,
.priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv),
};
@@ -0,0 +1,391 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 BayLibre, SAS
* Author: Fabien Parent <fparent@baylibre.com>
*/
#include <dm.h>
#include "pinctrl-mtk-common.h"
#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \
_x_bits, 16, false)
static const struct mtk_pin_field_calc mt8516_pin_mode_range[] = {
PIN_FIELD_CALC(0, 124, 0x300, 0x10, 0, 3, 15, false),
};
static const struct mtk_pin_field_calc mt8516_pin_dir_range[] = {
PIN_FIELD(0, 124, 0x0, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8516_pin_di_range[] = {
PIN_FIELD(0, 124, 0x200, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8516_pin_do_range[] = {
PIN_FIELD(0, 124, 0x100, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8516_pin_ies_range[] = {
PIN_FIELD(0, 6, 0x900, 0x10, 2, 1),
PIN_FIELD(7, 10, 0x900, 0x10, 3, 1),
PIN_FIELD(11, 13, 0x900, 0x10, 12, 1),
PIN_FIELD(14, 17, 0x900, 0x10, 13, 1),
PIN_FIELD(18, 20, 0x910, 0x10, 10, 1),
PIN_FIELD(21, 23, 0x900, 0x10, 13, 1),
PIN_FIELD(24, 25, 0x900, 0x10, 12, 1),
PIN_FIELD(26, 30, 0x900, 0x10, 0, 1),
PIN_FIELD(31, 33, 0x900, 0x10, 1, 1),
PIN_FIELD(34, 39, 0x900, 0x10, 2, 1),
PIN_FIELD(40, 40, 0x910, 0x10, 11, 1),
PIN_FIELD(41, 43, 0x900, 0x10, 10, 1),
PIN_FIELD(44, 47, 0x900, 0x10, 11, 1),
PIN_FIELD(48, 51, 0x900, 0x10, 14, 1),
PIN_FIELD(52, 53, 0x910, 0x10, 0, 1),
PIN_FIELD(54, 54, 0x910, 0x10, 2, 1),
PIN_FIELD(55, 57, 0x910, 0x10, 4, 1),
PIN_FIELD(58, 59, 0x900, 0x10, 15, 1),
PIN_FIELD(60, 61, 0x910, 0x10, 1, 1),
PIN_FIELD(62, 65, 0x910, 0x10, 5, 1),
PIN_FIELD(66, 67, 0x910, 0x10, 6, 1),
PIN_FIELD(68, 68, 0x930, 0x10, 2, 1),
PIN_FIELD(69, 69, 0x930, 0x10, 1, 1),
PIN_FIELD(70, 70, 0x930, 0x10, 6, 1),
PIN_FIELD(71, 71, 0x930, 0x10, 5, 1),
PIN_FIELD(72, 72, 0x930, 0x10, 4, 1),
PIN_FIELD(73, 73, 0x930, 0x10, 3, 1),
PIN_FIELD(100, 103, 0x910, 0x10, 7, 1),
PIN_FIELD(104, 104, 0x920, 0x10, 12, 1),
PIN_FIELD(105, 105, 0x920, 0x10, 11, 1),
PIN_FIELD(106, 106, 0x930, 0x10, 0, 1),
PIN_FIELD(107, 107, 0x920, 0x10, 15, 1),
PIN_FIELD(108, 108, 0x920, 0x10, 14, 1),
PIN_FIELD(109, 109, 0x920, 0x10, 13, 1),
PIN_FIELD(110, 110, 0x920, 0x10, 9, 1),
PIN_FIELD(111, 111, 0x920, 0x10, 8, 1),
PIN_FIELD(112, 112, 0x920, 0x10, 7, 1),
PIN_FIELD(113, 113, 0x920, 0x10, 6, 1),
PIN_FIELD(114, 114, 0x920, 0x10, 10, 1),
PIN_FIELD(115, 115, 0x920, 0x10, 1, 1),
PIN_FIELD(116, 116, 0x920, 0x10, 0, 1),
PIN_FIELD(117, 117, 0x920, 0x10, 5, 1),
PIN_FIELD(118, 118, 0x920, 0x10, 4, 1),
PIN_FIELD(119, 119, 0x920, 0x10, 3, 1),
PIN_FIELD(120, 120, 0x920, 0x10, 2, 1),
PIN_FIELD(121, 124, 0x910, 0x10, 9, 1),
};
static const struct mtk_pin_field_calc mt8516_pin_smt_range[] = {
PIN_FIELD(0, 6, 0xA00, 0x10, 2, 1),
PIN_FIELD(7, 10, 0xA00, 0x10, 3, 1),
PIN_FIELD(11, 13, 0xA00, 0x10, 12, 1),
PIN_FIELD(14, 17, 0xA00, 0x10, 13, 1),
PIN_FIELD(18, 20, 0xA10, 0x10, 10, 1),
PIN_FIELD(21, 23, 0xA00, 0x10, 13, 1),
PIN_FIELD(24, 25, 0xA00, 0x10, 12, 1),
PIN_FIELD(26, 30, 0xA00, 0x10, 0, 1),
PIN_FIELD(31, 33, 0xA00, 0x10, 1, 1),
PIN_FIELD(40, 40, 0xA10, 0x10, 11, 1),
PIN_FIELD(41, 43, 0xA00, 0x10, 10, 1),
PIN_FIELD(44, 47, 0xA00, 0x10, 11, 1),
PIN_FIELD(48, 51, 0xA00, 0x10, 14, 1),
PIN_FIELD(52, 53, 0xA10, 0x10, 0, 1),
PIN_FIELD(54, 54, 0xA10, 0x10, 2, 1),
PIN_FIELD(55, 57, 0xA10, 0x10, 4, 1),
PIN_FIELD(58, 59, 0xA00, 0x10, 15, 1),
PIN_FIELD(60, 61, 0xA10, 0x10, 1, 1),
PIN_FIELD(62, 65, 0xA10, 0x10, 5, 1),
PIN_FIELD(66, 67, 0xA10, 0x10, 6, 1),
PIN_FIELD(68, 68, 0xA30, 0x10, 2, 1),
PIN_FIELD(69, 69, 0xA30, 0x10, 1, 1),
PIN_FIELD(70, 70, 0xA30, 0x10, 3, 1),
PIN_FIELD(71, 71, 0xA30, 0x10, 4, 1),
PIN_FIELD(72, 72, 0xA30, 0x10, 5, 1),
PIN_FIELD(73, 73, 0xA30, 0x10, 6, 1),
PIN_FIELD(100, 103, 0xA10, 0x10, 7, 1),
PIN_FIELD(104, 104, 0xA20, 0x10, 12, 1),
PIN_FIELD(105, 105, 0xA20, 0x10, 11, 1),
PIN_FIELD(106, 106, 0xA30, 0x10, 13, 1),
PIN_FIELD(107, 107, 0xA20, 0x10, 14, 1),
PIN_FIELD(108, 108, 0xA20, 0x10, 15, 1),
PIN_FIELD(109, 109, 0xA30, 0x10, 0, 1),
PIN_FIELD(110, 110, 0xA20, 0x10, 9, 1),
PIN_FIELD(111, 111, 0xA20, 0x10, 8, 1),
PIN_FIELD(112, 112, 0xA20, 0x10, 7, 1),
PIN_FIELD(113, 113, 0xA20, 0x10, 6, 1),
PIN_FIELD(114, 114, 0xA20, 0x10, 10, 1),
PIN_FIELD(115, 115, 0xA20, 0x10, 1, 1),
PIN_FIELD(116, 116, 0xA20, 0x10, 0, 1),
PIN_FIELD(117, 117, 0xA20, 0x10, 5, 1),
PIN_FIELD(118, 118, 0xA20, 0x10, 4, 1),
PIN_FIELD(119, 119, 0xA20, 0x10, 3, 1),
PIN_FIELD(120, 120, 0xA20, 0x10, 2, 1),
PIN_FIELD(121, 124, 0xA10, 0x10, 9, 1),
};
static const struct mtk_pin_field_calc mt8516_pin_pullen_range[] = {
PIN_FIELD(0, 13, 0x500, 0x10, 0, 1),
PIN_FIELD(18, 20, 0x510, 0x10, 2, 1),
PIN_FIELD(24, 31, 0x510, 0x10, 8, 1),
PIN_FIELD(32, 39, 0x520, 0x10, 0, 1),
PIN_FIELD(44, 47, 0x520, 0x10, 12, 1),
PIN_FIELD(48, 63, 0x530, 0x10, 0, 1),
PIN_FIELD(64, 67, 0x540, 0x10, 0, 1),
PIN_FIELD(100, 103, 0x560, 0x10, 4, 1),
PIN_FIELD(121, 124, 0x570, 0x10, 9, 1),
};
static const struct mtk_pin_field_calc mt8516_pin_pullsel_range[] = {
PIN_FIELD(0, 13, 0x600, 0x10, 0, 1),
PIN_FIELD(18, 20, 0x610, 0x10, 2, 1),
PIN_FIELD(24, 31, 0x610, 0x10, 8, 1),
PIN_FIELD(32, 39, 0x620, 0x10, 0, 1),
PIN_FIELD(44, 47, 0x620, 0x10, 12, 1),
PIN_FIELD(48, 63, 0x630, 0x10, 0, 1),
PIN_FIELD(64, 67, 0x640, 0x10, 0, 1),
PIN_FIELD(100, 103, 0x660, 0x10, 4, 1),
PIN_FIELD(121, 124, 0x670, 0x10, 9, 1),
};
static const struct mtk_pin_field_calc mt8516_pin_drv_range[] = {
PIN_FIELD(0, 4, 0xd00, 0x10, 0, 4),
PIN_FIELD(5, 10, 0xd00, 0x10, 4, 4),
PIN_FIELD(11, 13, 0xd00, 0x10, 8, 4),
PIN_FIELD(14, 17, 0xd00, 0x10, 12, 4),
PIN_FIELD(18, 20, 0xd10, 0x10, 0, 4),
PIN_FIELD(21, 23, 0xd00, 0x10, 12, 4),
PIN_FIELD(24, 25, 0xd00, 0x10, 8, 4),
PIN_FIELD(26, 30, 0xd10, 0x10, 4, 4),
PIN_FIELD(31, 33, 0xd10, 0x10, 8, 4),
PIN_FIELD(34, 35, 0xd10, 0x10, 12, 4),
PIN_FIELD(36, 39, 0xd20, 0x10, 0, 4),
PIN_FIELD(40, 40, 0xd20, 0x10, 4, 4),
PIN_FIELD(41, 43, 0xd20, 0x10, 8, 4),
PIN_FIELD(44, 47, 0xd20, 0x10, 12, 4),
PIN_FIELD(48, 51, 0xd30, 0x10, 0, 4),
PIN_FIELD(54, 54, 0xd30, 0x10, 8, 4),
PIN_FIELD(55, 57, 0xd30, 0x10, 12, 4),
PIN_FIELD(62, 67, 0xd40, 0x10, 8, 4),
PIN_FIELD(68, 68, 0xd40, 0x10, 12, 4),
PIN_FIELD(69, 69, 0xd50, 0x10, 0, 4),
PIN_FIELD(70, 73, 0xd50, 0x10, 4, 4),
PIN_FIELD(100, 103, 0xd50, 0x10, 8, 4),
PIN_FIELD(104, 104, 0xd50, 0x10, 12, 4),
PIN_FIELD(105, 105, 0xd60, 0x10, 0, 4),
PIN_FIELD(106, 109, 0xd60, 0x10, 4, 4),
PIN_FIELD(110, 113, 0xd70, 0x10, 0, 4),
PIN_FIELD(114, 114, 0xd70, 0x10, 4, 4),
PIN_FIELD(115, 115, 0xd60, 0x10, 12, 4),
PIN_FIELD(116, 116, 0xd60, 0x10, 8, 4),
PIN_FIELD(117, 120, 0xd70, 0x10, 0, 4),
};
static const struct mtk_pin_reg_calc mt8516_reg_cals[] = {
[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt8516_pin_mode_range),
[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8516_pin_dir_range),
[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8516_pin_di_range),
[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8516_pin_do_range),
[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8516_pin_ies_range),
[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8516_pin_smt_range),
[PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt8516_pin_pullsel_range),
[PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt8516_pin_pullen_range),
[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt8516_pin_drv_range),
};
static const struct mtk_pin_desc mt8516_pins[] = {
MTK_PIN(0, "EINT0", DRV_GRP0),
MTK_PIN(1, "EINT1", DRV_GRP0),
MTK_PIN(2, "EINT2", DRV_GRP0),
MTK_PIN(3, "EINT3", DRV_GRP0),
MTK_PIN(4, "EINT4", DRV_GRP0),
MTK_PIN(5, "EINT5", DRV_GRP0),
MTK_PIN(6, "EINT6", DRV_GRP0),
MTK_PIN(7, "EINT7", DRV_GRP0),
MTK_PIN(8, "EINT8", DRV_GRP0),
MTK_PIN(9, "EINT9", DRV_GRP0),
MTK_PIN(10, "EINT10", DRV_GRP0),
MTK_PIN(11, "EINT11", DRV_GRP0),
MTK_PIN(12, "EINT12", DRV_GRP0),
MTK_PIN(13, "EINT13", DRV_GRP0),
MTK_PIN(14, "EINT14", DRV_GRP2),
MTK_PIN(15, "EINT15", DRV_GRP2),
MTK_PIN(16, "EINT16", DRV_GRP2),
MTK_PIN(17, "EINT17", DRV_GRP2),
MTK_PIN(18, "EINT18", DRV_GRP0),
MTK_PIN(19, "EINT19", DRV_GRP0),
MTK_PIN(20, "EINT20", DRV_GRP0),
MTK_PIN(21, "EINT21", DRV_GRP2),
MTK_PIN(22, "EINT22", DRV_GRP2),
MTK_PIN(23, "EINT23", DRV_GRP2),
MTK_PIN(24, "EINT24", DRV_GRP0),
MTK_PIN(25, "EINT25", DRV_GRP0),
MTK_PIN(26, "PWRAP_SPI0_MI", DRV_GRP4),
MTK_PIN(27, "PWRAP_SPI0_MO", DRV_GRP4),
MTK_PIN(28, "PWRAP_INT", DRV_GRP4),
MTK_PIN(29, "PWRAP_SPIO0_CK", DRV_GRP4),
MTK_PIN(30, "PWARP_SPI0_CSN", DRV_GRP4),
MTK_PIN(31, "RTC32K_CK", DRV_GRP4),
MTK_PIN(32, "WATCHDOG", DRV_GRP4),
MTK_PIN(33, "SRCLKENA0", DRV_GRP4),
MTK_PIN(34, "URXD2", DRV_GRP0),
MTK_PIN(35, "UTXD2", DRV_GRP0),
MTK_PIN(36, "MRG_CLK", DRV_GRP0),
MTK_PIN(37, "MRG_SYNC", DRV_GRP0),
MTK_PIN(38, "MRG_DI", DRV_GRP0),
MTK_PIN(39, "MRG_DO", DRV_GRP0),
MTK_PIN(40, "KPROW0", DRV_GRP2),
MTK_PIN(41, "KPROW1", DRV_GRP2),
MTK_PIN(42, "KPCOL0", DRV_GRP2),
MTK_PIN(43, "KPCOL1", DRV_GRP2),
MTK_PIN(44, "JMTS", DRV_GRP2),
MTK_PIN(45, "JTCK", DRV_GRP2),
MTK_PIN(46, "JTDI", DRV_GRP2),
MTK_PIN(47, "JTDO", DRV_GRP2),
MTK_PIN(48, "SPI_CS", DRV_GRP2),
MTK_PIN(49, "SPI_CK", DRV_GRP2),
MTK_PIN(50, "SPI_MI", DRV_GRP2),
MTK_PIN(51, "SPI_MO", DRV_GRP2),
MTK_PIN(52, "SDA1", DRV_GRP2),
MTK_PIN(53, "SCL1", DRV_GRP2),
MTK_PIN(54, "DISP_PWM", DRV_GRP2),
MTK_PIN(55, "I2S_DATA_IN", DRV_GRP2),
MTK_PIN(56, "I2S_LRCK", DRV_GRP2),
MTK_PIN(57, "I2S_BCK", DRV_GRP2),
MTK_PIN(58, "SDA0", DRV_GRP2),
MTK_PIN(59, "SCL0", DRV_GRP2),
MTK_PIN(60, "SDA2", DRV_GRP2),
MTK_PIN(61, "SCL2", DRV_GRP2),
MTK_PIN(62, "URXD0", DRV_GRP2),
MTK_PIN(63, "UTXD0", DRV_GRP2),
MTK_PIN(64, "URXD1", DRV_GRP2),
MTK_PIN(65, "UTXD1", DRV_GRP2),
MTK_PIN(66, "LCM_RST", DRV_GRP2),
MTK_PIN(67, "DSI_TE", DRV_GRP2),
MTK_PIN(68, "MSDC2_CMD", DRV_GRP4),
MTK_PIN(69, "MSDC2_CLK", DRV_GRP4),
MTK_PIN(70, "MSDC2_DAT0", DRV_GRP4),
MTK_PIN(71, "MSDC2_DAT1", DRV_GRP4),
MTK_PIN(72, "MSDC2_DAT2", DRV_GRP4),
MTK_PIN(73, "MSDC2_DAT3", DRV_GRP4),
MTK_PIN(74, "TDN3", DRV_GRP0),
MTK_PIN(75, "TDP3", DRV_GRP0),
MTK_PIN(76, "TDN2", DRV_GRP0),
MTK_PIN(77, "TDP2", DRV_GRP0),
MTK_PIN(78, "TCN", DRV_GRP0),
MTK_PIN(79, "TCP", DRV_GRP0),
MTK_PIN(80, "TDN1", DRV_GRP0),
MTK_PIN(81, "TDP1", DRV_GRP0),
MTK_PIN(82, "TDN0", DRV_GRP0),
MTK_PIN(83, "TDP0", DRV_GRP0),
MTK_PIN(84, "RDN0", DRV_GRP0),
MTK_PIN(85, "RDP0", DRV_GRP0),
MTK_PIN(86, "RDN1", DRV_GRP0),
MTK_PIN(87, "RDP1", DRV_GRP0),
MTK_PIN(88, "RCN", DRV_GRP0),
MTK_PIN(89, "RCP", DRV_GRP0),
MTK_PIN(90, "RDN2", DRV_GRP0),
MTK_PIN(91, "RDP2", DRV_GRP0),
MTK_PIN(92, "RDN3", DRV_GRP0),
MTK_PIN(93, "RDP3", DRV_GRP0),
MTK_PIN(94, "RCN_A", DRV_GRP0),
MTK_PIN(95, "RCP_A", DRV_GRP0),
MTK_PIN(96, "RDN1_A", DRV_GRP0),
MTK_PIN(97, "RDP1_A", DRV_GRP0),
MTK_PIN(98, "RDN0_A", DRV_GRP0),
MTK_PIN(99, "RDP0_A", DRV_GRP0),
MTK_PIN(100, "CMDDAT0", DRV_GRP2),
MTK_PIN(101, "CMDDAT1", DRV_GRP2),
MTK_PIN(102, "CMMCLK", DRV_GRP2),
MTK_PIN(103, "CMPCLK", DRV_GRP2),
MTK_PIN(104, "MSDC1_CMD", DRV_GRP4),
MTK_PIN(105, "MSDC1_CLK", DRV_GRP4),
MTK_PIN(106, "MSDC1_DAT0", DRV_GRP4),
MTK_PIN(107, "MSDC1_DAT1", DRV_GRP4),
MTK_PIN(108, "MSDC1_DAT2", DRV_GRP4),
MTK_PIN(109, "MSDC1_DAT3", DRV_GRP4),
MTK_PIN(110, "MSDC0_DAT7", DRV_GRP4),
MTK_PIN(111, "MSDC0_DAT6", DRV_GRP4),
MTK_PIN(112, "MSDC0_DAT5", DRV_GRP4),
MTK_PIN(113, "MSDC0_DAT4", DRV_GRP4),
MTK_PIN(114, "MSDC0_RSTB", DRV_GRP4),
MTK_PIN(115, "MSDC0_CMD", DRV_GRP4),
MTK_PIN(116, "MSDC0_CLK", DRV_GRP4),
MTK_PIN(117, "MSDC0_DAT3", DRV_GRP4),
MTK_PIN(118, "MSDC0_DAT2", DRV_GRP4),
MTK_PIN(119, "MSDC0_DAT1", DRV_GRP4),
MTK_PIN(120, "MSDC0_DAT0", DRV_GRP4),
};
/* List all groups consisting of these pins dedicated to the enablement of
* certain hardware block and the corresponding mode for all of the pins.
* The hardware probably has multiple combinations of these pinouts.
*/
/* UART */
static int mt8516_uart0_0_rxd_txd_pins[] = { 62, 63, };
static int mt8516_uart0_0_rxd_txd_funcs[] = { 1, 1, };
static int mt8516_uart1_0_rxd_txd_pins[] = { 64, 65, };
static int mt8516_uart1_0_rxd_txd_funcs[] = { 1, 1, };
static int mt8516_uart2_0_rxd_txd_pins[] = { 34, 35, };
static int mt8516_uart2_0_rxd_txd_funcs[] = { 1, 1, };
/* Joint those groups owning the same capability in user point of view which
* allows that people tend to use through the device tree.
*/
static const char *const mt8516_uart_groups[] = { "uart0_0_rxd_txd",
"uart1_0_rxd_txd",
"uart2_0_rxd_txd", };
/* MMC0 */
static int mt8516_msdc0_pins[] = { 110, 111, 112, 113, 114, 115, 116, 117, 118,
119, 120, };
static int mt8516_msdc0_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
static const struct mtk_group_desc mt8516_groups[] = {
PINCTRL_PIN_GROUP("uart0_0_rxd_txd", mt8516_uart0_0_rxd_txd),
PINCTRL_PIN_GROUP("uart1_0_rxd_txd", mt8516_uart1_0_rxd_txd),
PINCTRL_PIN_GROUP("uart2_0_rxd_txd", mt8516_uart2_0_rxd_txd),
PINCTRL_PIN_GROUP("msdc0", mt8516_msdc0),
};
static const char *const mt8516_msdc_groups[] = { "msdc0" };
static const struct mtk_function_desc mt8516_functions[] = {
{"uart", mt8516_uart_groups, ARRAY_SIZE(mt8516_uart_groups)},
{"msdc", mt8516_msdc_groups, ARRAY_SIZE(mt8516_msdc_groups)},
};
static struct mtk_pinctrl_soc mt8516_data = {
.name = "mt8516_pinctrl",
.reg_cal = mt8516_reg_cals,
.pins = mt8516_pins,
.npins = ARRAY_SIZE(mt8516_pins),
.grps = mt8516_groups,
.ngrps = ARRAY_SIZE(mt8516_groups),
.funcs = mt8516_functions,
.nfuncs = ARRAY_SIZE(mt8516_functions),
};
static int mtk_pinctrl_mt8516_probe(struct udevice *dev)
{
return mtk_pinctrl_common_probe(dev, &mt8516_data);
}
static const struct udevice_id mt8516_pctrl_match[] = {
{ .compatible = "mediatek,mt8516-pinctrl" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(mt8516_pinctrl) = {
.name = "mt8516_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = mt8516_pctrl_match,
.ops = &mtk_pinctrl_ops,
.probe = mtk_pinctrl_mt8516_probe,
.priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv),
};
@@ -0,0 +1,411 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 MediaTek Inc.
* Author: Mingming Lee <mingming.lee@mediatek.com>
*/
#include <dm.h>
#include "pinctrl-mtk-common.h"
#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \
_x_bits, 16, false)
static const struct mtk_pin_field_calc mt8518_pin_mode_range[] = {
PIN_FIELD_CALC(0, 119, 0x300, 0x10, 0, 3, 15, false),
};
static const struct mtk_pin_field_calc mt8518_pin_dir_range[] = {
PIN_FIELD(0, 119, 0x0, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8518_pin_di_range[] = {
PIN_FIELD(0, 119, 0x200, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8518_pin_do_range[] = {
PIN_FIELD(0, 119, 0x100, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8518_pin_ies_range[] = {
PIN_FIELD(0, 2, 0x900, 0x10, 0, 1),
PIN_FIELD(3, 3, 0x920, 0x10, 9, 1),
PIN_FIELD(4, 4, 0x920, 0x10, 8, 1),
PIN_FIELD(5, 5, 0x920, 0x10, 7, 1),
PIN_FIELD(6, 6, 0x920, 0x10, 6, 1),
PIN_FIELD(7, 7, 0x920, 0x10, 10, 1),
PIN_FIELD(8, 8, 0x920, 0x10, 1, 1),
PIN_FIELD(9, 9, 0x920, 0x10, 0, 1),
PIN_FIELD(10, 10, 0x920, 0x10, 5, 1),
PIN_FIELD(11, 11, 0x920, 0x10, 4, 1),
PIN_FIELD(12, 12, 0x920, 0x10, 3, 1),
PIN_FIELD(13, 13, 0x920, 0x10, 2, 1),
PIN_FIELD(14, 14, 0x900, 0x10, 1, 1),
PIN_FIELD(15, 15, 0x900, 0x10, 2, 1),
PIN_FIELD(16, 16, 0x900, 0x10, 3, 1),
PIN_FIELD(17, 20, 0x900, 0x10, 4, 1),
PIN_FIELD(21, 22, 0x900, 0x10, 5, 1),
PIN_FIELD(23, 27, 0x910, 0x10, 15, 1),
PIN_FIELD(28, 28, 0x900, 0x10, 6, 1),
PIN_FIELD(29, 29, 0x930, 0x10, 2, 1),
PIN_FIELD(30, 30, 0x930, 0x10, 1, 1),
PIN_FIELD(31, 31, 0x930, 0x10, 6, 1),
PIN_FIELD(32, 32, 0x930, 0x10, 5, 1),
PIN_FIELD(33, 33, 0x930, 0x10, 4, 1),
PIN_FIELD(34, 35, 0x930, 0x10, 3, 1),
PIN_FIELD(36, 39, 0x900, 0x10, 7, 1),
PIN_FIELD(40, 41, 0x900, 0x10, 8, 1),
PIN_FIELD(42, 44, 0x900, 0x10, 9, 1),
PIN_FIELD(45, 47, 0x900, 0x10, 10, 1),
PIN_FIELD(48, 51, 0x900, 0x10, 11, 1),
PIN_FIELD(52, 55, 0x900, 0x10, 12, 1),
PIN_FIELD(56, 56, 0x900, 0x10, 13, 1),
PIN_FIELD(57, 57, 0x900, 0x10, 14, 1),
PIN_FIELD(58, 58, 0x900, 0x10, 15, 1),
PIN_FIELD(59, 60, 0x910, 0x10, 0, 1),
PIN_FIELD(61, 61, 0x910, 0x10, 1, 1),
PIN_FIELD(62, 62, 0x910, 0x10, 2, 1),
PIN_FIELD(63, 69, 0x910, 0x10, 3, 1),
PIN_FIELD(70, 70, 0x910, 0x10, 4, 1),
PIN_FIELD(71, 76, 0x910, 0x10, 5, 1),
PIN_FIELD(77, 80, 0x910, 0x10, 6, 1),
PIN_FIELD(81, 87, 0x910, 0x10, 7, 1),
PIN_FIELD(88, 97, 0x910, 0x10, 8, 1),
PIN_FIELD(98, 103, 0x910, 0x10, 9, 1),
PIN_FIELD(104, 107, 0x910, 0x10, 10, 1),
PIN_FIELD(108, 109, 0x910, 0x10, 11, 1),
PIN_FIELD(110, 111, 0x910, 0x10, 12, 1),
PIN_FIELD(112, 113, 0x910, 0x10, 13, 1),
PIN_FIELD(114, 114, 0x920, 0x10, 12, 1),
PIN_FIELD(115, 115, 0x920, 0x10, 11, 1),
PIN_FIELD(116, 116, 0x930, 0x10, 0, 1),
PIN_FIELD(117, 117, 0x920, 0x10, 15, 1),
PIN_FIELD(118, 118, 0x920, 0x10, 14, 1),
PIN_FIELD(119, 119, 0x920, 0x10, 13, 1),
};
static const struct mtk_pin_field_calc mt8518_pin_smt_range[] = {
PIN_FIELD(0, 2, 0xA00, 0x10, 0, 1),
PIN_FIELD(3, 3, 0xA20, 0x10, 9, 1),
PIN_FIELD(4, 4, 0xA20, 0x10, 8, 1),
PIN_FIELD(5, 5, 0xA20, 0x10, 7, 1),
PIN_FIELD(6, 6, 0xA20, 0x10, 6, 1),
PIN_FIELD(7, 7, 0xA20, 0x10, 10, 1),
PIN_FIELD(8, 8, 0xA20, 0x10, 1, 1),
PIN_FIELD(9, 9, 0xA20, 0x10, 0, 1),
PIN_FIELD(10, 10, 0xA20, 0x10, 5, 1),
PIN_FIELD(11, 11, 0xA20, 0x10, 4, 1),
PIN_FIELD(12, 12, 0xA20, 0x10, 3, 1),
PIN_FIELD(13, 13, 0xA20, 0x10, 2, 1),
PIN_FIELD(14, 14, 0xA00, 0x10, 1, 1),
PIN_FIELD(15, 15, 0xA00, 0x10, 2, 1),
PIN_FIELD(16, 16, 0xA00, 0x10, 3, 1),
PIN_FIELD(17, 20, 0xA00, 0x10, 4, 1),
PIN_FIELD(21, 22, 0xA00, 0x10, 5, 1),
PIN_FIELD(23, 27, 0xA10, 0x10, 15, 1),
PIN_FIELD(28, 28, 0xA00, 0x10, 6, 1),
PIN_FIELD(29, 29, 0xA30, 0x10, 2, 1),
PIN_FIELD(30, 30, 0xA30, 0x10, 1, 1),
PIN_FIELD(31, 31, 0xA30, 0x10, 6, 1),
PIN_FIELD(32, 32, 0xA30, 0x10, 5, 1),
PIN_FIELD(33, 33, 0xA30, 0x10, 4, 1),
PIN_FIELD(34, 35, 0xA30, 0x10, 3, 1),
PIN_FIELD(36, 39, 0xA00, 0x10, 7, 1),
PIN_FIELD(40, 41, 0xA00, 0x10, 8, 1),
PIN_FIELD(42, 44, 0xA00, 0x10, 9, 1),
PIN_FIELD(45, 47, 0xA00, 0x10, 10, 1),
PIN_FIELD(48, 51, 0xA00, 0x10, 11, 1),
PIN_FIELD(52, 55, 0xA00, 0x10, 12, 1),
PIN_FIELD(56, 56, 0xA00, 0x10, 13, 1),
PIN_FIELD(57, 57, 0xA00, 0x10, 14, 1),
PIN_FIELD(58, 58, 0xA00, 0x10, 15, 1),
PIN_FIELD(59, 60, 0xA10, 0x10, 0, 1),
PIN_FIELD(61, 61, 0xA10, 0x10, 1, 1),
PIN_FIELD(62, 62, 0xA10, 0x10, 2, 1),
PIN_FIELD(63, 69, 0xA10, 0x10, 3, 1),
PIN_FIELD(70, 70, 0xA10, 0x10, 4, 1),
PIN_FIELD(71, 76, 0xA10, 0x10, 5, 1),
PIN_FIELD(77, 80, 0xA10, 0x10, 6, 1),
PIN_FIELD(81, 87, 0xA10, 0x10, 7, 1),
PIN_FIELD(88, 97, 0xA10, 0x10, 8, 1),
PIN_FIELD(98, 103, 0xA10, 0x10, 9, 1),
PIN_FIELD(104, 107, 0xA10, 0x10, 10, 1),
PIN_FIELD(108, 109, 0xA10, 0x10, 11, 1),
PIN_FIELD(110, 111, 0xA10, 0x10, 12, 1),
PIN_FIELD(112, 113, 0xA10, 0x10, 13, 1),
PIN_FIELD(114, 114, 0xA20, 0x10, 12, 1),
PIN_FIELD(115, 115, 0xA20, 0x10, 11, 1),
PIN_FIELD(116, 116, 0xA30, 0x10, 0, 1),
PIN_FIELD(117, 117, 0xA20, 0x10, 15, 1),
PIN_FIELD(118, 118, 0xA20, 0x10, 14, 1),
PIN_FIELD(119, 119, 0xA20, 0x10, 13, 1),
};
static const struct mtk_pin_field_calc mt8518_pin_pullen_range[] = {
PIN_FIELD(14, 15, 0x500, 0x10, 14, 1),
PIN_FIELD(16, 28, 0x510, 0x10, 0, 1),
PIN_FIELD(36, 47, 0x520, 0x10, 4, 1),
PIN_FIELD(48, 63, 0x530, 0x10, 0, 1),
PIN_FIELD(64, 79, 0x540, 0x10, 0, 1),
PIN_FIELD(80, 95, 0x550, 0x10, 0, 1),
PIN_FIELD(96, 111, 0x560, 0x10, 0, 1),
PIN_FIELD(112, 113, 0x570, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8518_pin_pullsel_range[] = {
PIN_FIELD(14, 15, 0x600, 0x10, 14, 1),
PIN_FIELD(16, 28, 0x610, 0x10, 0, 1),
PIN_FIELD(36, 47, 0x620, 0x10, 4, 1),
PIN_FIELD(48, 63, 0x630, 0x10, 0, 1),
PIN_FIELD(64, 79, 0x640, 0x10, 0, 1),
PIN_FIELD(80, 95, 0x650, 0x10, 0, 1),
PIN_FIELD(96, 111, 0x660, 0x10, 0, 1),
PIN_FIELD(112, 113, 0x670, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt8518_pin_drv_range[] = {
PIN_FIELD(0, 2, 0xd70, 0x10, 8, 4),
PIN_FIELD(3, 6, 0xd70, 0x10, 0, 4),
PIN_FIELD(7, 7, 0xd70, 0x10, 4, 4),
PIN_FIELD(8, 8, 0xd60, 0x10, 8, 4),
PIN_FIELD(9, 9, 0xd60, 0x10, 12, 4),
PIN_FIELD(10, 13, 0xd70, 0x10, 0, 4),
PIN_FIELD(14, 14, 0xd50, 0x10, 8, 4),
PIN_FIELD(15, 15, 0xd20, 0x10, 4, 4),
PIN_FIELD(16, 16, 0xd50, 0x10, 8, 4),
PIN_FIELD(17, 20, 0xd20, 0x10, 12, 4),
PIN_FIELD(23, 27, 0xd30, 0x10, 8, 4),
PIN_FIELD(28, 28, 0xd10, 0x10, 0, 4),
PIN_FIELD(29, 29, 0xd40, 0x10, 12, 4),
PIN_FIELD(30, 30, 0xd50, 0x10, 0, 4),
PIN_FIELD(31, 35, 0xd50, 0x10, 4, 4),
PIN_FIELD(36, 41, 0xd00, 0x10, 0, 4),
PIN_FIELD(42, 47, 0xd00, 0x10, 4, 4),
PIN_FIELD(48, 51, 0xd00, 0x10, 8, 4),
PIN_FIELD(52, 55, 0xd10, 0x10, 12, 4),
PIN_FIELD(56, 56, 0xdb0, 0x10, 4, 4),
PIN_FIELD(57, 58, 0xd00, 0x10, 8, 4),
PIN_FIELD(59, 62, 0xd00, 0x10, 12, 4),
PIN_FIELD(63, 68, 0xd90, 0x10, 12, 4),
PIN_FIELD(69, 69, 0xda0, 0x10, 0, 4),
PIN_FIELD(70, 70, 0xda0, 0x10, 12, 4),
PIN_FIELD(71, 73, 0xd80, 0x10, 12, 4),
PIN_FIELD(74, 76, 0xd90, 0x10, 0, 4),
PIN_FIELD(77, 80, 0xd20, 0x10, 0, 4),
PIN_FIELD(81, 87, 0xd80, 0x10, 8, 4),
PIN_FIELD(88, 97, 0xd30, 0x10, 0, 4),
PIN_FIELD(98, 103, 0xd10, 0x10, 4, 4),
PIN_FIELD(104, 105, 0xd40, 0x10, 8, 4),
PIN_FIELD(106, 107, 0xd10, 0x10, 8, 4),
PIN_FIELD(114, 114, 0xd50, 0x10, 12, 4),
PIN_FIELD(115, 115, 0xd60, 0x10, 0, 4),
PIN_FIELD(116, 119, 0xd60, 0x10, 4, 4),
};
static const struct mtk_pin_reg_calc mt8518_reg_cals[] = {
[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt8518_pin_mode_range),
[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8518_pin_dir_range),
[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8518_pin_di_range),
[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8518_pin_do_range),
[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8518_pin_ies_range),
[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8518_pin_smt_range),
[PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt8518_pin_pullsel_range),
[PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt8518_pin_pullen_range),
[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt8518_pin_drv_range),
};
static const struct mtk_pin_desc mt8518_pins[] = {
MTK_PIN(0, "NFI_NCEB0", DRV_GRP4),
MTK_PIN(1, "NFI_NREB", DRV_GRP4),
MTK_PIN(2, "NFI_NRNB", DRV_GRP4),
MTK_PIN(3, "MSDC0_DAT7", DRV_GRP4),
MTK_PIN(4, "MSDC0_DAT6", DRV_GRP4),
MTK_PIN(5, "MSDC0_DAT5", DRV_GRP4),
MTK_PIN(6, "MSDC0_DAT4", DRV_GRP4),
MTK_PIN(7, "MSDC0_RSTB", DRV_GRP4),
MTK_PIN(8, "MSDC0_CMD", DRV_GRP4),
MTK_PIN(9, "MSDC0_CLK", DRV_GRP4),
MTK_PIN(10, "MSDC0_DAT3", DRV_GRP4),
MTK_PIN(11, "MSDC0_DAT2", DRV_GRP4),
MTK_PIN(12, "MSDC0_DAT1", DRV_GRP4),
MTK_PIN(13, "MSDC0_DAT0", DRV_GRP4),
MTK_PIN(14, "RTC32K_CK", DRV_GRP2),
MTK_PIN(15, "WATCHDOG", DRV_GRP2),
MTK_PIN(16, "SUSPEND", DRV_GRP2),
MTK_PIN(17, "JTMS", DRV_GRP2),
MTK_PIN(18, "JTCK", DRV_GRP2),
MTK_PIN(19, "JTDI", DRV_GRP2),
MTK_PIN(20, "JTDO", DRV_GRP2),
MTK_PIN(21, "SDA3", DRV_GRP2),
MTK_PIN(22, "SCL3", DRV_GRP2),
MTK_PIN(23, "PWRAP_SPI_CLK", DRV_GRP2),
MTK_PIN(24, "PWRAP_SPI_CSN", DRV_GRP2),
MTK_PIN(25, "PWRAP_SPI_MOSI", DRV_GRP2),
MTK_PIN(26, "PWRAP_SPI_MISO", DRV_GRP2),
MTK_PIN(27, "PWRAP_INT", DRV_GRP2),
MTK_PIN(28, "EINT22", DRV_GRP2),
MTK_PIN(29, "MSDC2_CMD", DRV_GRP4),
MTK_PIN(30, "MSDC2_CLK", DRV_GRP4),
MTK_PIN(31, "MSDC2_DAT0", DRV_GRP4),
MTK_PIN(32, "MSDC2_DAT1", DRV_GRP4),
MTK_PIN(33, "MSDC2_DAT2", DRV_GRP4),
MTK_PIN(34, "MSDC2_DAT3", DRV_GRP4),
MTK_PIN(35, "MSDC2_DS", DRV_GRP4),
MTK_PIN(36, "EINT0", DRV_GRP0),
MTK_PIN(37, "EINT1", DRV_GRP0),
MTK_PIN(38, "EINT2", DRV_GRP0),
MTK_PIN(39, "EINT3", DRV_GRP0),
MTK_PIN(40, "EINT4", DRV_GRP0),
MTK_PIN(41, "EINT5", DRV_GRP0),
MTK_PIN(42, "EINT6", DRV_GRP0),
MTK_PIN(43, "EINT7", DRV_GRP0),
MTK_PIN(44, "EINT8", DRV_GRP0),
MTK_PIN(45, "EINT9", DRV_GRP0),
MTK_PIN(46, "EINT10", DRV_GRP0),
MTK_PIN(47, "EINT11", DRV_GRP0),
MTK_PIN(48, "EINT12", DRV_GRP0),
MTK_PIN(49, "EINT13", DRV_GRP0),
MTK_PIN(50, "EINT14", DRV_GRP0),
MTK_PIN(51, "EINT15", DRV_GRP0),
MTK_PIN(52, "URXD1", DRV_GRP0),
MTK_PIN(53, "UTXD1", DRV_GRP0),
MTK_PIN(54, "URTS1", DRV_GRP0),
MTK_PIN(55, "UCTS1", DRV_GRP0),
MTK_PIN(56, "IR", DRV_GRP0),
MTK_PIN(57, "EINT16", DRV_GRP0),
MTK_PIN(58, "EINT17", DRV_GRP0),
MTK_PIN(59, "EINT18", DRV_GRP0),
MTK_PIN(60, "EINT19", DRV_GRP0),
MTK_PIN(61, "EINT20", DRV_GRP0),
MTK_PIN(62, "EINT21", DRV_GRP0),
MTK_PIN(63, "I2SO_MCLK", DRV_GRP0),
MTK_PIN(64, "I2SO_BCK", DRV_GRP0),
MTK_PIN(65, "I2SO_LRCK", DRV_GRP0),
MTK_PIN(66, "I2SO_D0", DRV_GRP0),
MTK_PIN(67, "I2SO_D1", DRV_GRP0),
MTK_PIN(68, "I2SO_D2", DRV_GRP0),
MTK_PIN(69, "I2SO_D3", DRV_GRP0),
MTK_PIN(70, "SPDIF_IN0", DRV_GRP0),
MTK_PIN(71, "DMIC_CLK0", DRV_GRP0),
MTK_PIN(72, "DMIC_CLK1", DRV_GRP0),
MTK_PIN(73, "DMIC_DAT0", DRV_GRP0),
MTK_PIN(74, "DMIC_DAT1", DRV_GRP0),
MTK_PIN(75, "DMIC_DAT2", DRV_GRP0),
MTK_PIN(76, "DMIC_DAT3", DRV_GRP0),
MTK_PIN(77, "TDM_MCLK", DRV_GRP0),
MTK_PIN(78, "TDM_BCK", DRV_GRP0),
MTK_PIN(79, "TDM_LRCK", DRV_GRP0),
MTK_PIN(80, "TDM_DI", DRV_GRP0),
MTK_PIN(81, "I2SIN_D0", DRV_GRP0),
MTK_PIN(82, "I2SIN_D1", DRV_GRP0),
MTK_PIN(83, "I2SIN_D2", DRV_GRP0),
MTK_PIN(84, "I2SIN_D3", DRV_GRP0),
MTK_PIN(85, "I2SIN_MCLK", DRV_GRP0),
MTK_PIN(86, "I2SIN_BCK", DRV_GRP0),
MTK_PIN(87, "I2SIN_LRCK", DRV_GRP0),
MTK_PIN(88, "SPI1_CS", DRV_GRP0),
MTK_PIN(89, "SPI1_CK", DRV_GRP0),
MTK_PIN(90, "SPI1_MI", DRV_GRP0),
MTK_PIN(91, "SPI1_MO", DRV_GRP0),
MTK_PIN(92, "SPI2_CS", DRV_GRP0),
MTK_PIN(93, "SPI2_CK", DRV_GRP0),
MTK_PIN(94, "SPI2_MI0", DRV_GRP0),
MTK_PIN(95, "SPI2_MI1", DRV_GRP0),
MTK_PIN(96, "SPI2_MI2", DRV_GRP0),
MTK_PIN(97, "SPI2_MI3", DRV_GRP0),
MTK_PIN(98, "SW_RESET_DSP", DRV_GRP0),
MTK_PIN(99, "GPIO1", DRV_GRP0),
MTK_PIN(100, "GPIO2", DRV_GRP0),
MTK_PIN(101, "GPIO3", DRV_GRP0),
MTK_PIN(102, "GPIO4", DRV_GRP0),
MTK_PIN(103, "RTC32K_DSP", DRV_GRP0),
MTK_PIN(104, "URXD0", DRV_GRP2),
MTK_PIN(105, "UTXD0", DRV_GRP2),
MTK_PIN(106, "URXD2", DRV_GRP2),
MTK_PIN(107, "UTXD2", DRV_GRP2),
MTK_PIN(108, "SDA1", DRV_GRP4),
MTK_PIN(109, "SCL1", DRV_GRP4),
MTK_PIN(110, "SDA0", DRV_GRP4),
MTK_PIN(111, "SCL0", DRV_GRP4),
MTK_PIN(112, "SDA2", DRV_GRP4),
MTK_PIN(113, "SCL2", DRV_GRP4),
MTK_PIN(114, "MSDC1_CMD", DRV_GRP4),
MTK_PIN(115, "MSDC1_CLK", DRV_GRP4),
MTK_PIN(116, "MSDC1_DAT0", DRV_GRP4),
MTK_PIN(117, "MSDC1_DAT1", DRV_GRP4),
MTK_PIN(118, "MSDC1_DAT2", DRV_GRP4),
MTK_PIN(119, "MSDC1_DAT3", DRV_GRP4),
};
/* List all groups consisting of these pins dedicated to the enablement of
* certain hardware block and the corresponding mode for all of the pins.
* The hardware probably has multiple combinations of these pinouts.
*/
/* UART */
static int mt8518_uart0_0_rxd_txd_pins[] = { 104, 105, };
static int mt8518_uart0_0_rxd_txd_funcs[] = { 1, 1, };
static int mt8518_uart1_0_rxd_txd_pins[] = { 52, 53, };
static int mt8518_uart1_0_rxd_txd_funcs[] = { 1, 1, };
static int mt8518_uart2_0_rxd_txd_pins[] = { 106, 107, };
static int mt8518_uart2_0_rxd_txd_funcs[] = { 1, 1, };
/* Joint those groups owning the same capability in user point of view which
* allows that people tend to use through the device tree.
*/
static const char *const mt8518_uart_groups[] = { "uart0_0_rxd_txd",
"uart1_0_rxd_txd",
"uart2_0_rxd_txd", };
/* MMC0 */
static int mt8518_msdc0_pins[] = { 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, };
static int mt8518_msdc0_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
static const struct mtk_group_desc mt8518_groups[] = {
PINCTRL_PIN_GROUP("uart0_0_rxd_txd", mt8518_uart0_0_rxd_txd),
PINCTRL_PIN_GROUP("uart1_0_rxd_txd", mt8518_uart1_0_rxd_txd),
PINCTRL_PIN_GROUP("uart2_0_rxd_txd", mt8518_uart2_0_rxd_txd),
PINCTRL_PIN_GROUP("msdc0", mt8518_msdc0),
};
static const char *const mt8518_msdc_groups[] = { "msdc0" };
static const struct mtk_function_desc mt8518_functions[] = {
{"uart", mt8518_uart_groups, ARRAY_SIZE(mt8518_uart_groups)},
{"msdc", mt8518_msdc_groups, ARRAY_SIZE(mt8518_msdc_groups)},
};
static struct mtk_pinctrl_soc mt8518_data = {
.name = "mt8518_pinctrl",
.reg_cal = mt8518_reg_cals,
.pins = mt8518_pins,
.npins = ARRAY_SIZE(mt8518_pins),
.grps = mt8518_groups,
.ngrps = ARRAY_SIZE(mt8518_groups),
.funcs = mt8518_functions,
.nfuncs = ARRAY_SIZE(mt8518_functions),
};
static int mtk_pinctrl_mt8518_probe(struct udevice *dev)
{
return mtk_pinctrl_common_probe(dev, &mt8518_data);
}
static const struct udevice_id mt8518_pctrl_match[] = {
{ .compatible = "mediatek,mt8518-pinctrl" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(mt8518_pinctrl) = {
.name = "mt8518_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = mt8518_pctrl_match,
.ops = &mtk_pinctrl_ops,
.probe = mtk_pinctrl_mt8518_probe,
.priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv),
};
@@ -0,0 +1,555 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 MediaTek Inc.
* Author: Ryder Lee <ryder.lee@mediatek.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <asm/io.h>
#include <asm-generic/gpio.h>
#include "pinctrl-mtk-common.h"
#if CONFIG_IS_ENABLED(PINCONF)
/**
* struct mtk_drive_desc - the structure that holds the information
* of the driving current
* @min: the minimum current of this group
* @max: the maximum current of this group
* @step: the step current of this group
* @scal: the weight factor
*
* formula: output = ((input) / step - 1) * scal
*/
struct mtk_drive_desc {
u8 min;
u8 max;
u8 step;
u8 scal;
};
/* The groups of drive strength */
static const struct mtk_drive_desc mtk_drive[] = {
[DRV_GRP0] = { 4, 16, 4, 1 },
[DRV_GRP1] = { 4, 16, 4, 2 },
[DRV_GRP2] = { 2, 8, 2, 1 },
[DRV_GRP3] = { 2, 8, 2, 2 },
[DRV_GRP4] = { 2, 16, 2, 1 },
};
#endif
static const char *mtk_pinctrl_dummy_name = "_dummy";
static void mtk_w32(struct udevice *dev, u32 reg, u32 val)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
__raw_writel(val, priv->base + reg);
}
static u32 mtk_r32(struct udevice *dev, u32 reg)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
return __raw_readl(priv->base + reg);
}
static inline int get_count_order(unsigned int count)
{
int order;
order = fls(count) - 1;
if (count & (count - 1))
order++;
return order;
}
void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set)
{
u32 val;
val = mtk_r32(dev, reg);
val &= ~mask;
val |= set;
mtk_w32(dev, reg, val);
}
static int mtk_hw_pin_field_lookup(struct udevice *dev, int pin,
const struct mtk_pin_reg_calc *rc,
struct mtk_pin_field *pfd)
{
const struct mtk_pin_field_calc *c, *e;
u32 bits;
c = rc->range;
e = c + rc->nranges;
while (c < e) {
if (pin >= c->s_pin && pin <= c->e_pin)
break;
c++;
}
if (c >= e)
return -EINVAL;
/* Calculated bits as the overall offset the pin is located at,
* if c->fixed is held, that determines the all the pins in the
* range use the same field with the s_pin.
*/
bits = c->fixed ? c->s_bit : c->s_bit + (pin - c->s_pin) * (c->x_bits);
/* Fill pfd from bits. For example 32-bit register applied is assumed
* when c->sz_reg is equal to 32.
*/
pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg);
pfd->bitpos = bits % c->sz_reg;
pfd->mask = (1 << c->x_bits) - 1;
/* pfd->next is used for indicating that bit wrapping-around happens
* which requires the manipulation for bit 0 starting in the next
* register to form the complete field read/write.
*/
pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0;
return 0;
}
static int mtk_hw_pin_field_get(struct udevice *dev, int pin,
int field, struct mtk_pin_field *pfd)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
const struct mtk_pin_reg_calc *rc;
if (field < 0 || field >= PINCTRL_PIN_REG_MAX)
return -EINVAL;
if (priv->soc->reg_cal && priv->soc->reg_cal[field].range)
rc = &priv->soc->reg_cal[field];
else
return -EINVAL;
return mtk_hw_pin_field_lookup(dev, pin, rc, pfd);
}
static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l)
{
*l = 32 - pf->bitpos;
*h = get_count_order(pf->mask) - *l;
}
static void mtk_hw_write_cross_field(struct udevice *dev,
struct mtk_pin_field *pf, int value)
{
int nbits_l, nbits_h;
mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
mtk_rmw(dev, pf->offset, pf->mask << pf->bitpos,
(value & pf->mask) << pf->bitpos);
mtk_rmw(dev, pf->offset + pf->next, BIT(nbits_h) - 1,
(value & pf->mask) >> nbits_l);
}
static void mtk_hw_read_cross_field(struct udevice *dev,
struct mtk_pin_field *pf, int *value)
{
int nbits_l, nbits_h, h, l;
mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
l = (mtk_r32(dev, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1);
h = (mtk_r32(dev, pf->offset + pf->next)) & (BIT(nbits_h) - 1);
*value = (h << nbits_l) | l;
}
static int mtk_hw_set_value(struct udevice *dev, int pin, int field,
int value)
{
struct mtk_pin_field pf;
int err;
err = mtk_hw_pin_field_get(dev, pin, field, &pf);
if (err)
return err;
if (!pf.next)
mtk_rmw(dev, pf.offset, pf.mask << pf.bitpos,
(value & pf.mask) << pf.bitpos);
else
mtk_hw_write_cross_field(dev, &pf, value);
return 0;
}
static int mtk_hw_get_value(struct udevice *dev, int pin, int field,
int *value)
{
struct mtk_pin_field pf;
int err;
err = mtk_hw_pin_field_get(dev, pin, field, &pf);
if (err)
return err;
if (!pf.next)
*value = (mtk_r32(dev, pf.offset) >> pf.bitpos) & pf.mask;
else
mtk_hw_read_cross_field(dev, &pf, value);
return 0;
}
static int mtk_get_groups_count(struct udevice *dev)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
return priv->soc->ngrps;
}
static const char *mtk_get_pin_name(struct udevice *dev,
unsigned int selector)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
if (!priv->soc->grps[selector].name)
return mtk_pinctrl_dummy_name;
return priv->soc->pins[selector].name;
}
static int mtk_get_pins_count(struct udevice *dev)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
return priv->soc->npins;
}
static const char *mtk_get_group_name(struct udevice *dev,
unsigned int selector)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
if (!priv->soc->grps[selector].name)
return mtk_pinctrl_dummy_name;
return priv->soc->grps[selector].name;
}
static int mtk_get_functions_count(struct udevice *dev)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
return priv->soc->nfuncs;
}
static const char *mtk_get_function_name(struct udevice *dev,
unsigned int selector)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
if (!priv->soc->funcs[selector].name)
return mtk_pinctrl_dummy_name;
return priv->soc->funcs[selector].name;
}
static int mtk_pinmux_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int func_selector)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
const struct mtk_group_desc *grp =
&priv->soc->grps[group_selector];
int i;
for (i = 0; i < grp->num_pins; i++) {
int *pin_modes = grp->data;
mtk_hw_set_value(dev, grp->pins[i], PINCTRL_PIN_REG_MODE,
pin_modes[i]);
}
return 0;
}
#if CONFIG_IS_ENABLED(PINCONF)
static const struct pinconf_param mtk_conf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
{ "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
{ "output-high", PIN_CONFIG_OUTPUT, 1, },
{ "output-low", PIN_CONFIG_OUTPUT, 0, },
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
};
int mtk_pinconf_drive_set(struct udevice *dev, u32 pin, u32 arg)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
const struct mtk_pin_desc *desc = &priv->soc->pins[pin];
const struct mtk_drive_desc *tb;
int err = -ENOTSUPP;
tb = &mtk_drive[desc->drv_n];
/* 4mA when (e8, e4) = (0, 0)
* 8mA when (e8, e4) = (0, 1)
* 12mA when (e8, e4) = (1, 0)
* 16mA when (e8, e4) = (1, 1)
*/
if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {
arg = (arg / tb->step - 1) * tb->scal;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DRV, arg);
if (err)
return err;
}
return 0;
}
static int mtk_pinconf_set(struct udevice *dev, unsigned int pin,
unsigned int param, unsigned int arg)
{
int err = 0;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
(param == PIN_CONFIG_BIAS_PULL_UP) ? 3 : 2;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLSEL,
arg & 1);
if (err)
goto err;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLEN,
!!(arg & 2));
if (err)
goto err;
break;
case PIN_CONFIG_OUTPUT_ENABLE:
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT, 0);
if (err)
goto err;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1);
if (err)
goto err;
break;
case PIN_CONFIG_INPUT_ENABLE:
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_IES, 1);
if (err)
goto err;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 0);
if (err)
goto err;
break;
case PIN_CONFIG_OUTPUT:
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1);
if (err)
goto err;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DO, arg);
if (err)
goto err;
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
/* arg = 1: Input mode & SMT enable ;
* arg = 0: Output mode & SMT disable
*/
arg = arg ? 2 : 1;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR,
arg & 1);
if (err)
goto err;
err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT,
!!(arg & 2));
if (err)
goto err;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
err = mtk_pinconf_drive_set(dev, pin, arg);
if (err)
goto err;
break;
default:
err = -ENOTSUPP;
}
err:
return err;
}
static int mtk_pinconf_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int param, unsigned int arg)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
const struct mtk_group_desc *grp =
&priv->soc->grps[group_selector];
int i, ret;
for (i = 0; i < grp->num_pins; i++) {
ret = mtk_pinconf_set(dev, grp->pins[i], param, arg);
if (ret)
return ret;
}
return 0;
}
#endif
const struct pinctrl_ops mtk_pinctrl_ops = {
.get_pins_count = mtk_get_pins_count,
.get_pin_name = mtk_get_pin_name,
.get_groups_count = mtk_get_groups_count,
.get_group_name = mtk_get_group_name,
.get_functions_count = mtk_get_functions_count,
.get_function_name = mtk_get_function_name,
.pinmux_group_set = mtk_pinmux_group_set,
#if CONFIG_IS_ENABLED(PINCONF)
.pinconf_num_params = ARRAY_SIZE(mtk_conf_params),
.pinconf_params = mtk_conf_params,
.pinconf_set = mtk_pinconf_set,
.pinconf_group_set = mtk_pinconf_group_set,
#endif
.set_state = pinctrl_generic_set_state,
};
static int mtk_gpio_get(struct udevice *dev, unsigned int off)
{
int val, err;
err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DI, &val);
if (err)
return err;
return !!val;
}
static int mtk_gpio_set(struct udevice *dev, unsigned int off, int val)
{
return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DO, !!val);
}
static int mtk_gpio_get_direction(struct udevice *dev, unsigned int off)
{
int val, err;
err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DIR, &val);
if (err)
return err;
return val ? GPIOF_OUTPUT : GPIOF_INPUT;
}
static int mtk_gpio_direction_input(struct udevice *dev, unsigned int off)
{
return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 0);
}
static int mtk_gpio_direction_output(struct udevice *dev,
unsigned int off, int val)
{
mtk_gpio_set(dev, off, val);
/* And set the requested value */
return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 1);
}
static int mtk_gpio_request(struct udevice *dev, unsigned int off,
const char *label)
{
return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_MODE, 0);
}
static int mtk_gpio_probe(struct udevice *dev)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev->parent);
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = priv->soc->name;
uc_priv->gpio_count = priv->soc->npins;
return 0;
}
static const struct dm_gpio_ops mtk_gpio_ops = {
.request = mtk_gpio_request,
.set_value = mtk_gpio_set,
.get_value = mtk_gpio_get,
.get_function = mtk_gpio_get_direction,
.direction_input = mtk_gpio_direction_input,
.direction_output = mtk_gpio_direction_output,
};
static struct driver mtk_gpio_driver = {
.name = "mediatek_gpio",
.id = UCLASS_GPIO,
.probe = mtk_gpio_probe,
.ops = &mtk_gpio_ops,
};
static int mtk_gpiochip_register(struct udevice *parent)
{
struct uclass_driver *drv;
struct udevice *dev;
int ret;
ofnode node;
drv = lists_uclass_lookup(UCLASS_GPIO);
if (!drv)
return -ENOENT;
dev_for_each_subnode(node, parent)
if (ofnode_read_bool(node, "gpio-controller")) {
ret = 0;
break;
}
if (ret)
return ret;
ret = device_bind_with_driver_data(parent, &mtk_gpio_driver,
"mediatek_gpio", 0, node,
&dev);
if (ret)
return ret;
return 0;
}
int mtk_pinctrl_common_probe(struct udevice *dev,
struct mtk_pinctrl_soc *soc)
{
struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
int ret;
priv->base = dev_read_addr_ptr(dev);
if (priv->base == (void *)FDT_ADDR_T_NONE)
return -EINVAL;
priv->soc = soc;
ret = mtk_gpiochip_register(dev);
if (ret)
return ret;
return 0;
}
@@ -0,0 +1,184 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018 MediaTek Inc.
* Author: Ryder Lee <ryder.lee@mediatek.com>
*/
#ifndef __PINCTRL_MEDIATEK_H__
#define __PINCTRL_MEDIATEK_H__
#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
#define MTK_PIN(_number, _name, _drv_n) { \
.number = _number, \
.name = _name, \
.drv_n = _drv_n, \
}
#define PINCTRL_PIN_GROUP(name, id) \
{ \
name, \
id##_pins, \
ARRAY_SIZE(id##_pins), \
id##_funcs, \
}
#define PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \
_x_bits, _sz_reg, _fixed) { \
.s_pin = _s_pin, \
.e_pin = _e_pin, \
.s_addr = _s_addr, \
.x_addrs = _x_addrs, \
.s_bit = _s_bit, \
.x_bits = _x_bits, \
.sz_reg = _sz_reg, \
.fixed = _fixed, \
}
/* List these attributes which could be modified for the pin */
enum {
PINCTRL_PIN_REG_MODE,
PINCTRL_PIN_REG_DIR,
PINCTRL_PIN_REG_DI,
PINCTRL_PIN_REG_DO,
PINCTRL_PIN_REG_IES,
PINCTRL_PIN_REG_SMT,
PINCTRL_PIN_REG_PULLEN,
PINCTRL_PIN_REG_PULLSEL,
PINCTRL_PIN_REG_DRV,
PINCTRL_PIN_REG_MAX,
};
/* Group the pins by the driving current */
enum {
DRV_FIXED,
DRV_GRP0,
DRV_GRP1,
DRV_GRP2,
DRV_GRP3,
DRV_GRP4,
};
/**
* struct mtk_pin_field - the structure that holds the information of the field
* used to describe the attribute for the pin
* @offset: the register offset relative to the base address
* @mask: the mask used to filter out the field from the register
* @bitpos: the start bit relative to the register
* @next: the indication that the field would be extended to the
next register
*/
struct mtk_pin_field {
u32 offset;
u32 mask;
u8 bitpos;
u8 next;
};
/**
* struct mtk_pin_field_calc - the structure that holds the range providing
* the guide used to look up the relevant field
* @s_pin: the start pin within the range
* @e_pin: the end pin within the range
* @s_addr: the start address for the range
* @x_addrs: the address distance between two consecutive registers
* within the range
* @s_bit: the start bit for the first register within the range
* @x_bits: the bit distance between two consecutive pins within
* the range
* @sz_reg: the size of bits in a register
* @fixed: the consecutive pins share the same bits with the 1st
* pin
*/
struct mtk_pin_field_calc {
u16 s_pin;
u16 e_pin;
u32 s_addr;
u8 x_addrs;
u8 s_bit;
u8 x_bits;
u8 sz_reg;
u8 fixed;
};
/**
* struct mtk_pin_reg_calc - the structure that holds all ranges used to
* determine which register the pin would make use of
* for certain pin attribute.
* @range: the start address for the range
* @nranges: the number of items in the range
*/
struct mtk_pin_reg_calc {
const struct mtk_pin_field_calc *range;
unsigned int nranges;
};
/**
* struct mtk_pin_desc - the structure that providing information
* for each pin of chips
* @number: unique pin number from the global pin number space
* @name: name for this pin
* @drv_n: the index with the driving group
*/
struct mtk_pin_desc {
unsigned int number;
const char *name;
u8 drv_n;
};
/**
* struct mtk_group_desc - generic pin group descriptor
* @name: name of the pin group
* @pins: array of pins that belong to the group
* @num_pins: number of pins in the group
* @data: pin controller driver specific data
*/
struct mtk_group_desc {
const char *name;
int *pins;
int num_pins;
void *data;
};
/**
* struct mtk_function_desc - generic function descriptor
* @name: name of the function
* @group_names: array of pin group names
* @num_group_names: number of pin group names
*/
struct mtk_function_desc {
const char *name;
const char * const *group_names;
int num_group_names;
};
/* struct mtk_pin_soc - the structure that holds SoC-specific data */
struct mtk_pinctrl_soc {
const char *name;
const struct mtk_pin_reg_calc *reg_cal;
const struct mtk_pin_desc *pins;
int npins;
const struct mtk_group_desc *grps;
int ngrps;
const struct mtk_function_desc *funcs;
int nfuncs;
};
/**
* struct mtk_pinctrl_priv - private data for MTK pinctrl driver
*
* @base: base address of the pinctrl device
* @soc: SoC specific data
*/
struct mtk_pinctrl_priv {
void __iomem *base;
struct mtk_pinctrl_soc *soc;
};
extern const struct pinctrl_ops mtk_pinctrl_ops;
/* A common read-modify-write helper for MediaTek chips */
void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set);
int mtk_pinctrl_common_probe(struct udevice *dev,
struct mtk_pinctrl_soc *soc);
#endif /* __PINCTRL_MEDIATEK_H__ */
@@ -0,0 +1,32 @@
if ARCH_MESON
config PINCTRL_MESON
select PINCTRL_GENERIC
select PINCONF
bool
config PINCTRL_MESON_GX_PMX
select PINCTRL_MESON
bool
config PINCTRL_MESON_AXG_PMX
select PINCTRL_MESON
bool
config PINCTRL_MESON_GXBB
bool "Amlogic Meson GXBB SoC pinctrl driver"
select PINCTRL_MESON_GX_PMX
config PINCTRL_MESON_GXL
bool "Amlogic Meson GXL SoC pinctrl driver"
select PINCTRL_MESON_GX_PMX
config PINCTRL_MESON_AXG
bool "Amlogic Meson AXG SoC pinctrl driver"
select PINCTRL_MESON_AXG_PMX
config PINCTRL_MESON_G12A
bool "Amlogic Meson G12a SoC pinctrl driver"
select PINCTRL_MESON_AXG_PMX
endif
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += pinctrl-meson.o
obj-$(CONFIG_PINCTRL_MESON_GX_PMX) += pinctrl-meson-gx-pmx.o
obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o
obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o
obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o
obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o
obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Jerome Brunet <jbrunet@baylibre.com>
* Copyright (C) 2017 Xingyu Chen <xingyu.chen@amlogic.com>
*/
#include <asm/gpio.h>
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <linux/io.h>
#include "pinctrl-meson-axg.h"
static int meson_axg_pmx_get_bank(struct udevice *dev, unsigned int pin,
struct meson_pmx_bank **bank)
{
int i;
struct meson_pinctrl *priv = dev_get_priv(dev);
struct meson_axg_pmx_data *pmx = priv->data->pmx_data;
for (i = 0; i < pmx->num_pmx_banks; i++)
if (pin >= pmx->pmx_banks[i].first &&
pin <= pmx->pmx_banks[i].last) {
*bank = &pmx->pmx_banks[i];
return 0;
}
return -EINVAL;
}
static int meson_axg_pmx_calc_reg_and_offset(struct meson_pmx_bank *bank,
unsigned int pin,
unsigned int *reg,
unsigned int *offset)
{
int shift;
shift = pin - bank->first;
*reg = bank->reg + (bank->offset + (shift << 2)) / 32;
*offset = (bank->offset + (shift << 2)) % 32;
return 0;
}
static int meson_axg_pmx_update_function(struct udevice *dev,
unsigned int pin, unsigned int func)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
struct meson_pmx_bank *bank;
unsigned int offset;
unsigned int reg;
unsigned int tmp;
int ret;
ret = meson_axg_pmx_get_bank(dev, pin, &bank);
if (ret)
return ret;
meson_axg_pmx_calc_reg_and_offset(bank, pin, &reg, &offset);
tmp = readl(priv->reg_mux + (reg << 2));
tmp &= ~(0xf << offset);
tmp |= (func & 0xf) << offset;
writel(tmp, priv->reg_mux + (reg << 2));
return ret;
}
static int meson_axg_pinmux_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int func_selector)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
const struct meson_pmx_group *group;
const struct meson_pmx_func *func;
struct meson_pmx_axg_data *pmx_data;
int i, ret;
group = &priv->data->groups[group_selector];
pmx_data = (struct meson_pmx_axg_data *)group->data;
func = &priv->data->funcs[func_selector];
debug("pinmux: set group %s func %s\n", group->name, func->name);
for (i = 0; i < group->num_pins; i++) {
ret = meson_axg_pmx_update_function(dev, group->pins[i],
pmx_data->func);
if (ret)
return ret;
}
return 0;
}
static int meson_axg_pinmux_get(struct udevice *dev, unsigned int selector,
char *buf, int size)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
struct meson_pmx_axg_data *pmx_data;
struct meson_pmx_group *group;
struct meson_pmx_bank *bank;
unsigned int offset;
unsigned int func;
unsigned int reg;
int ret, i, j;
selector += priv->data->pin_base;
ret = meson_axg_pmx_get_bank(dev, selector, &bank);
if (ret) {
snprintf(buf, size, "Unhandled");
return 0;
}
meson_axg_pmx_calc_reg_and_offset(bank, selector, &reg, &offset);
func = (readl(priv->reg_mux + (reg << 2)) >> offset) & 0xf;
for (i = 0; i < priv->data->num_groups; i++) {
group = &priv->data->groups[i];
pmx_data = (struct meson_pmx_axg_data *)group->data;
if (pmx_data->func != func)
continue;
for (j = 0; j < group->num_pins; j++) {
if (group->pins[j] == selector) {
snprintf(buf, size, "%s (%x)",
group->name, func);
return 0;
}
}
}
snprintf(buf, size, "Unknown (%x)", func);
return 0;
}
const struct pinconf_param meson_axg_pinconf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
};
const struct pinctrl_ops meson_axg_pinctrl_ops = {
.get_groups_count = meson_pinctrl_get_groups_count,
.get_group_name = meson_pinctrl_get_group_name,
.get_functions_count = meson_pinmux_get_functions_count,
.get_function_name = meson_pinmux_get_function_name,
.pinmux_group_set = meson_axg_pinmux_group_set,
.set_state = pinctrl_generic_set_state,
.pinconf_params = meson_axg_pinconf_params,
.pinconf_num_params = ARRAY_SIZE(meson_axg_pinconf_params),
.pinconf_set = meson_pinconf_set,
.pinconf_group_set = meson_pinconf_group_set,
.get_pin_name = meson_pinctrl_get_pin_name,
.get_pins_count = meson_pinctrl_get_pins_count,
.get_pin_muxing = meson_axg_pinmux_get,
};
static int meson_axg_gpio_request(struct udevice *dev,
unsigned int offset, const char *label)
{
return meson_axg_pmx_update_function(dev->parent, offset, 0);
}
static const struct dm_gpio_ops meson_axg_gpio_ops = {
.request = meson_axg_gpio_request,
.set_value = meson_gpio_set,
.get_value = meson_gpio_get,
.get_function = meson_gpio_get_direction,
.direction_input = meson_gpio_direction_input,
.direction_output = meson_gpio_direction_output,
};
const struct driver meson_axg_gpio_driver = {
.name = "meson-axg-gpio",
.id = UCLASS_GPIO,
.probe = meson_gpio_probe,
.ops = &meson_axg_gpio_ops,
};
@@ -0,0 +1,979 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright (C) 2018 Neil Armstrong <narmstrong@baylibre.com>
*
* Based on code from Linux kernel:
* Copyright (c) 2017 Amlogic, Inc. All rights reserved.
* Author: Xingyu Chen <xingyu.chen@amlogic.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <dt-bindings/gpio/meson-axg-gpio.h>
#include "pinctrl-meson-axg.h"
#define EE_OFF 15
/* emmc */
static const unsigned int emmc_nand_d0_pins[] = { PIN(BOOT_0, EE_OFF) };
static const unsigned int emmc_nand_d1_pins[] = { PIN(BOOT_1, EE_OFF) };
static const unsigned int emmc_nand_d2_pins[] = { PIN(BOOT_2, EE_OFF) };
static const unsigned int emmc_nand_d3_pins[] = { PIN(BOOT_3, EE_OFF) };
static const unsigned int emmc_nand_d4_pins[] = { PIN(BOOT_4, EE_OFF) };
static const unsigned int emmc_nand_d5_pins[] = { PIN(BOOT_5, EE_OFF) };
static const unsigned int emmc_nand_d6_pins[] = { PIN(BOOT_6, EE_OFF) };
static const unsigned int emmc_nand_d7_pins[] = { PIN(BOOT_7, EE_OFF) };
static const unsigned int emmc_clk_pins[] = { PIN(BOOT_8, EE_OFF) };
static const unsigned int emmc_cmd_pins[] = { PIN(BOOT_10, EE_OFF) };
static const unsigned int emmc_ds_pins[] = { PIN(BOOT_13, EE_OFF) };
/* nand */
static const unsigned int nand_ce0_pins[] = { PIN(BOOT_8, EE_OFF) };
static const unsigned int nand_ale_pins[] = { PIN(BOOT_9, EE_OFF) };
static const unsigned int nand_cle_pins[] = { PIN(BOOT_10, EE_OFF) };
static const unsigned int nand_wen_clk_pins[] = { PIN(BOOT_11, EE_OFF) };
static const unsigned int nand_ren_wr_pins[] = { PIN(BOOT_12, EE_OFF) };
static const unsigned int nand_rb0_pins[] = { PIN(BOOT_13, EE_OFF) };
/* nor */
static const unsigned int nor_hold_pins[] = { PIN(BOOT_3, EE_OFF) };
static const unsigned int nor_d_pins[] = { PIN(BOOT_4, EE_OFF) };
static const unsigned int nor_q_pins[] = { PIN(BOOT_5, EE_OFF) };
static const unsigned int nor_c_pins[] = { PIN(BOOT_6, EE_OFF) };
static const unsigned int nor_wp_pins[] = { PIN(BOOT_9, EE_OFF) };
static const unsigned int nor_cs_pins[] = { PIN(BOOT_14, EE_OFF) };
/* sdio */
static const unsigned int sdio_d0_pins[] = { PIN(GPIOX_0, EE_OFF) };
static const unsigned int sdio_d1_pins[] = { PIN(GPIOX_1, EE_OFF) };
static const unsigned int sdio_d2_pins[] = { PIN(GPIOX_2, EE_OFF) };
static const unsigned int sdio_d3_pins[] = { PIN(GPIOX_3, EE_OFF) };
static const unsigned int sdio_clk_pins[] = { PIN(GPIOX_4, EE_OFF) };
static const unsigned int sdio_cmd_pins[] = { PIN(GPIOX_5, EE_OFF) };
/* spi0 */
static const unsigned int spi0_clk_pins[] = { PIN(GPIOZ_0, EE_OFF) };
static const unsigned int spi0_mosi_pins[] = { PIN(GPIOZ_1, EE_OFF) };
static const unsigned int spi0_miso_pins[] = { PIN(GPIOZ_2, EE_OFF) };
static const unsigned int spi0_ss0_pins[] = { PIN(GPIOZ_3, EE_OFF) };
static const unsigned int spi0_ss1_pins[] = { PIN(GPIOZ_4, EE_OFF) };
static const unsigned int spi0_ss2_pins[] = { PIN(GPIOZ_5, EE_OFF) };
/* spi1 */
static const unsigned int spi1_clk_x_pins[] = { PIN(GPIOX_19, EE_OFF) };
static const unsigned int spi1_mosi_x_pins[] = { PIN(GPIOX_17, EE_OFF) };
static const unsigned int spi1_miso_x_pins[] = { PIN(GPIOX_18, EE_OFF) };
static const unsigned int spi1_ss0_x_pins[] = { PIN(GPIOX_16, EE_OFF) };
static const unsigned int spi1_clk_a_pins[] = { PIN(GPIOA_4, EE_OFF) };
static const unsigned int spi1_mosi_a_pins[] = { PIN(GPIOA_2, EE_OFF) };
static const unsigned int spi1_miso_a_pins[] = { PIN(GPIOA_3, EE_OFF) };
static const unsigned int spi1_ss0_a_pins[] = { PIN(GPIOA_5, EE_OFF) };
static const unsigned int spi1_ss1_pins[] = { PIN(GPIOA_6, EE_OFF) };
/* i2c0 */
static const unsigned int i2c0_sck_pins[] = { PIN(GPIOZ_6, EE_OFF) };
static const unsigned int i2c0_sda_pins[] = { PIN(GPIOZ_7, EE_OFF) };
/* i2c1 */
static const unsigned int i2c1_sck_z_pins[] = { PIN(GPIOZ_8, EE_OFF) };
static const unsigned int i2c1_sda_z_pins[] = { PIN(GPIOZ_9, EE_OFF) };
static const unsigned int i2c1_sck_x_pins[] = { PIN(GPIOX_16, EE_OFF) };
static const unsigned int i2c1_sda_x_pins[] = { PIN(GPIOX_17, EE_OFF) };
/* i2c2 */
static const unsigned int i2c2_sck_x_pins[] = { PIN(GPIOX_18, EE_OFF) };
static const unsigned int i2c2_sda_x_pins[] = { PIN(GPIOX_19, EE_OFF) };
static const unsigned int i2c2_sda_a_pins[] = { PIN(GPIOA_17, EE_OFF) };
static const unsigned int i2c2_sck_a_pins[] = { PIN(GPIOA_18, EE_OFF) };
/* i2c3 */
static const unsigned int i2c3_sda_a6_pins[] = { PIN(GPIOA_6, EE_OFF) };
static const unsigned int i2c3_sck_a7_pins[] = { PIN(GPIOA_7, EE_OFF) };
static const unsigned int i2c3_sda_a12_pins[] = { PIN(GPIOA_12, EE_OFF) };
static const unsigned int i2c3_sck_a13_pins[] = { PIN(GPIOA_13, EE_OFF) };
static const unsigned int i2c3_sda_a19_pins[] = { PIN(GPIOA_19, EE_OFF) };
static const unsigned int i2c3_sck_a20_pins[] = { PIN(GPIOA_20, EE_OFF) };
/* uart_a */
static const unsigned int uart_rts_a_pins[] = { PIN(GPIOX_11, EE_OFF) };
static const unsigned int uart_cts_a_pins[] = { PIN(GPIOX_10, EE_OFF) };
static const unsigned int uart_tx_a_pins[] = { PIN(GPIOX_8, EE_OFF) };
static const unsigned int uart_rx_a_pins[] = { PIN(GPIOX_9, EE_OFF) };
/* uart_b */
static const unsigned int uart_rts_b_z_pins[] = { PIN(GPIOZ_0, EE_OFF) };
static const unsigned int uart_cts_b_z_pins[] = { PIN(GPIOZ_1, EE_OFF) };
static const unsigned int uart_tx_b_z_pins[] = { PIN(GPIOZ_2, EE_OFF) };
static const unsigned int uart_rx_b_z_pins[] = { PIN(GPIOZ_3, EE_OFF) };
static const unsigned int uart_rts_b_x_pins[] = { PIN(GPIOX_18, EE_OFF) };
static const unsigned int uart_cts_b_x_pins[] = { PIN(GPIOX_19, EE_OFF) };
static const unsigned int uart_tx_b_x_pins[] = { PIN(GPIOX_16, EE_OFF) };
static const unsigned int uart_rx_b_x_pins[] = { PIN(GPIOX_17, EE_OFF) };
/* uart_ao_b */
static const unsigned int uart_ao_tx_b_z_pins[] = { PIN(GPIOZ_8, EE_OFF) };
static const unsigned int uart_ao_rx_b_z_pins[] = { PIN(GPIOZ_9, EE_OFF) };
static const unsigned int uart_ao_cts_b_z_pins[] = { PIN(GPIOZ_6, EE_OFF) };
static const unsigned int uart_ao_rts_b_z_pins[] = { PIN(GPIOZ_7, EE_OFF) };
/* pwm_a */
static const unsigned int pwm_a_z_pins[] = { PIN(GPIOZ_5, EE_OFF) };
static const unsigned int pwm_a_x18_pins[] = { PIN(GPIOX_18, EE_OFF) };
static const unsigned int pwm_a_x20_pins[] = { PIN(GPIOX_20, EE_OFF) };
static const unsigned int pwm_a_a_pins[] = { PIN(GPIOA_14, EE_OFF) };
/* pwm_b */
static const unsigned int pwm_b_z_pins[] = { PIN(GPIOZ_4, EE_OFF) };
static const unsigned int pwm_b_x_pins[] = { PIN(GPIOX_19, EE_OFF) };
static const unsigned int pwm_b_a_pins[] = { PIN(GPIOA_15, EE_OFF) };
/* pwm_c */
static const unsigned int pwm_c_x10_pins[] = { PIN(GPIOX_10, EE_OFF) };
static const unsigned int pwm_c_x17_pins[] = { PIN(GPIOX_17, EE_OFF) };
static const unsigned int pwm_c_a_pins[] = { PIN(GPIOA_16, EE_OFF) };
/* pwm_d */
static const unsigned int pwm_d_x11_pins[] = { PIN(GPIOX_11, EE_OFF) };
static const unsigned int pwm_d_x16_pins[] = { PIN(GPIOX_16, EE_OFF) };
/* pwm_vs */
static const unsigned int pwm_vs_pins[] = { PIN(GPIOA_0, EE_OFF) };
/* spdif_in */
static const unsigned int spdif_in_z_pins[] = { PIN(GPIOZ_4, EE_OFF) };
static const unsigned int spdif_in_a1_pins[] = { PIN(GPIOA_1, EE_OFF) };
static const unsigned int spdif_in_a7_pins[] = { PIN(GPIOA_7, EE_OFF) };
static const unsigned int spdif_in_a19_pins[] = { PIN(GPIOA_19, EE_OFF) };
static const unsigned int spdif_in_a20_pins[] = { PIN(GPIOA_20, EE_OFF) };
/* spdif_out */
static const unsigned int spdif_out_z_pins[] = { PIN(GPIOZ_5, EE_OFF) };
static const unsigned int spdif_out_a1_pins[] = { PIN(GPIOA_1, EE_OFF) };
static const unsigned int spdif_out_a11_pins[] = { PIN(GPIOA_11, EE_OFF) };
static const unsigned int spdif_out_a19_pins[] = { PIN(GPIOA_19, EE_OFF) };
static const unsigned int spdif_out_a20_pins[] = { PIN(GPIOA_20, EE_OFF) };
/* jtag_ee */
static const unsigned int jtag_tdo_x_pins[] = { PIN(GPIOX_0, EE_OFF) };
static const unsigned int jtag_tdi_x_pins[] = { PIN(GPIOX_1, EE_OFF) };
static const unsigned int jtag_clk_x_pins[] = { PIN(GPIOX_4, EE_OFF) };
static const unsigned int jtag_tms_x_pins[] = { PIN(GPIOX_5, EE_OFF) };
/* eth */
static const unsigned int eth_txd0_x_pins[] = { PIN(GPIOX_8, EE_OFF) };
static const unsigned int eth_txd1_x_pins[] = { PIN(GPIOX_9, EE_OFF) };
static const unsigned int eth_txen_x_pins[] = { PIN(GPIOX_10, EE_OFF) };
static const unsigned int eth_rgmii_rx_clk_x_pins[] = { PIN(GPIOX_12, EE_OFF) };
static const unsigned int eth_rxd0_x_pins[] = { PIN(GPIOX_13, EE_OFF) };
static const unsigned int eth_rxd1_x_pins[] = { PIN(GPIOX_14, EE_OFF) };
static const unsigned int eth_rx_dv_x_pins[] = { PIN(GPIOX_15, EE_OFF) };
static const unsigned int eth_mdio_x_pins[] = { PIN(GPIOX_21, EE_OFF) };
static const unsigned int eth_mdc_x_pins[] = { PIN(GPIOX_22, EE_OFF) };
static const unsigned int eth_txd0_y_pins[] = { PIN(GPIOY_10, EE_OFF) };
static const unsigned int eth_txd1_y_pins[] = { PIN(GPIOY_11, EE_OFF) };
static const unsigned int eth_txen_y_pins[] = { PIN(GPIOY_9, EE_OFF) };
static const unsigned int eth_rgmii_rx_clk_y_pins[] = { PIN(GPIOY_2, EE_OFF) };
static const unsigned int eth_rxd0_y_pins[] = { PIN(GPIOY_4, EE_OFF) };
static const unsigned int eth_rxd1_y_pins[] = { PIN(GPIOY_5, EE_OFF) };
static const unsigned int eth_rx_dv_y_pins[] = { PIN(GPIOY_3, EE_OFF) };
static const unsigned int eth_mdio_y_pins[] = { PIN(GPIOY_0, EE_OFF) };
static const unsigned int eth_mdc_y_pins[] = { PIN(GPIOY_1, EE_OFF) };
static const unsigned int eth_rxd2_rgmii_pins[] = { PIN(GPIOY_6, EE_OFF) };
static const unsigned int eth_rxd3_rgmii_pins[] = { PIN(GPIOY_7, EE_OFF) };
static const unsigned int eth_rgmii_tx_clk_pins[] = { PIN(GPIOY_8, EE_OFF) };
static const unsigned int eth_txd2_rgmii_pins[] = { PIN(GPIOY_12, EE_OFF) };
static const unsigned int eth_txd3_rgmii_pins[] = { PIN(GPIOY_13, EE_OFF) };
/* pdm */
static const unsigned int pdm_dclk_a14_pins[] = { PIN(GPIOA_14, EE_OFF) };
static const unsigned int pdm_dclk_a19_pins[] = { PIN(GPIOA_19, EE_OFF) };
static const unsigned int pdm_din0_pins[] = { PIN(GPIOA_15, EE_OFF) };
static const unsigned int pdm_din1_pins[] = { PIN(GPIOA_16, EE_OFF) };
static const unsigned int pdm_din2_pins[] = { PIN(GPIOA_17, EE_OFF) };
static const unsigned int pdm_din3_pins[] = { PIN(GPIOA_18, EE_OFF) };
/* mclk */
static const unsigned int mclk_c_pins[] = { PIN(GPIOA_0, EE_OFF) };
static const unsigned int mclk_b_pins[] = { PIN(GPIOA_1, EE_OFF) };
/* tdm */
static const unsigned int tdma_sclk_pins[] = { PIN(GPIOX_12, EE_OFF) };
static const unsigned int tdma_sclk_slv_pins[] = { PIN(GPIOX_12, EE_OFF) };
static const unsigned int tdma_fs_pins[] = { PIN(GPIOX_13, EE_OFF) };
static const unsigned int tdma_fs_slv_pins[] = { PIN(GPIOX_13, EE_OFF) };
static const unsigned int tdma_din0_pins[] = { PIN(GPIOX_14, EE_OFF) };
static const unsigned int tdma_dout0_x14_pins[] = { PIN(GPIOX_14, EE_OFF) };
static const unsigned int tdma_dout0_x15_pins[] = { PIN(GPIOX_15, EE_OFF) };
static const unsigned int tdma_dout1_pins[] = { PIN(GPIOX_15, EE_OFF) };
static const unsigned int tdma_din1_pins[] = { PIN(GPIOX_15, EE_OFF) };
static const unsigned int tdmc_sclk_pins[] = { PIN(GPIOA_2, EE_OFF) };
static const unsigned int tdmc_sclk_slv_pins[] = { PIN(GPIOA_2, EE_OFF) };
static const unsigned int tdmc_fs_pins[] = { PIN(GPIOA_3, EE_OFF) };
static const unsigned int tdmc_fs_slv_pins[] = { PIN(GPIOA_3, EE_OFF) };
static const unsigned int tdmc_din0_pins[] = { PIN(GPIOA_4, EE_OFF) };
static const unsigned int tdmc_dout0_pins[] = { PIN(GPIOA_4, EE_OFF) };
static const unsigned int tdmc_din1_pins[] = { PIN(GPIOA_5, EE_OFF) };
static const unsigned int tdmc_dout1_pins[] = { PIN(GPIOA_5, EE_OFF) };
static const unsigned int tdmc_din2_pins[] = { PIN(GPIOA_6, EE_OFF) };
static const unsigned int tdmc_dout2_pins[] = { PIN(GPIOA_6, EE_OFF) };
static const unsigned int tdmc_din3_pins[] = { PIN(GPIOA_7, EE_OFF) };
static const unsigned int tdmc_dout3_pins[] = { PIN(GPIOA_7, EE_OFF) };
static const unsigned int tdmb_sclk_pins[] = { PIN(GPIOA_8, EE_OFF) };
static const unsigned int tdmb_sclk_slv_pins[] = { PIN(GPIOA_8, EE_OFF) };
static const unsigned int tdmb_fs_pins[] = { PIN(GPIOA_9, EE_OFF) };
static const unsigned int tdmb_fs_slv_pins[] = { PIN(GPIOA_9, EE_OFF) };
static const unsigned int tdmb_din0_pins[] = { PIN(GPIOA_10, EE_OFF) };
static const unsigned int tdmb_dout0_pins[] = { PIN(GPIOA_10, EE_OFF) };
static const unsigned int tdmb_din1_pins[] = { PIN(GPIOA_11, EE_OFF) };
static const unsigned int tdmb_dout1_pins[] = { PIN(GPIOA_11, EE_OFF) };
static const unsigned int tdmb_din2_pins[] = { PIN(GPIOA_12, EE_OFF) };
static const unsigned int tdmb_dout2_pins[] = { PIN(GPIOA_12, EE_OFF) };
static const unsigned int tdmb_din3_pins[] = { PIN(GPIOA_13, EE_OFF) };
static const unsigned int tdmb_dout3_pins[] = { PIN(GPIOA_13, EE_OFF) };
static struct meson_pmx_group meson_axg_periphs_groups[] = {
GPIO_GROUP(GPIOZ_0, EE_OFF),
GPIO_GROUP(GPIOZ_1, EE_OFF),
GPIO_GROUP(GPIOZ_2, EE_OFF),
GPIO_GROUP(GPIOZ_3, EE_OFF),
GPIO_GROUP(GPIOZ_4, EE_OFF),
GPIO_GROUP(GPIOZ_5, EE_OFF),
GPIO_GROUP(GPIOZ_6, EE_OFF),
GPIO_GROUP(GPIOZ_7, EE_OFF),
GPIO_GROUP(GPIOZ_8, EE_OFF),
GPIO_GROUP(GPIOZ_9, EE_OFF),
GPIO_GROUP(GPIOZ_10, EE_OFF),
GPIO_GROUP(BOOT_0, EE_OFF),
GPIO_GROUP(BOOT_1, EE_OFF),
GPIO_GROUP(BOOT_2, EE_OFF),
GPIO_GROUP(BOOT_3, EE_OFF),
GPIO_GROUP(BOOT_4, EE_OFF),
GPIO_GROUP(BOOT_5, EE_OFF),
GPIO_GROUP(BOOT_6, EE_OFF),
GPIO_GROUP(BOOT_7, EE_OFF),
GPIO_GROUP(BOOT_8, EE_OFF),
GPIO_GROUP(BOOT_9, EE_OFF),
GPIO_GROUP(BOOT_10, EE_OFF),
GPIO_GROUP(BOOT_11, EE_OFF),
GPIO_GROUP(BOOT_12, EE_OFF),
GPIO_GROUP(BOOT_13, EE_OFF),
GPIO_GROUP(BOOT_14, EE_OFF),
GPIO_GROUP(GPIOA_0, EE_OFF),
GPIO_GROUP(GPIOA_1, EE_OFF),
GPIO_GROUP(GPIOA_2, EE_OFF),
GPIO_GROUP(GPIOA_3, EE_OFF),
GPIO_GROUP(GPIOA_4, EE_OFF),
GPIO_GROUP(GPIOA_5, EE_OFF),
GPIO_GROUP(GPIOA_6, EE_OFF),
GPIO_GROUP(GPIOA_7, EE_OFF),
GPIO_GROUP(GPIOA_8, EE_OFF),
GPIO_GROUP(GPIOA_9, EE_OFF),
GPIO_GROUP(GPIOA_10, EE_OFF),
GPIO_GROUP(GPIOA_11, EE_OFF),
GPIO_GROUP(GPIOA_12, EE_OFF),
GPIO_GROUP(GPIOA_13, EE_OFF),
GPIO_GROUP(GPIOA_14, EE_OFF),
GPIO_GROUP(GPIOA_15, EE_OFF),
GPIO_GROUP(GPIOA_16, EE_OFF),
GPIO_GROUP(GPIOA_17, EE_OFF),
GPIO_GROUP(GPIOA_19, EE_OFF),
GPIO_GROUP(GPIOA_20, EE_OFF),
GPIO_GROUP(GPIOX_0, EE_OFF),
GPIO_GROUP(GPIOX_1, EE_OFF),
GPIO_GROUP(GPIOX_2, EE_OFF),
GPIO_GROUP(GPIOX_3, EE_OFF),
GPIO_GROUP(GPIOX_4, EE_OFF),
GPIO_GROUP(GPIOX_5, EE_OFF),
GPIO_GROUP(GPIOX_6, EE_OFF),
GPIO_GROUP(GPIOX_7, EE_OFF),
GPIO_GROUP(GPIOX_8, EE_OFF),
GPIO_GROUP(GPIOX_9, EE_OFF),
GPIO_GROUP(GPIOX_10, EE_OFF),
GPIO_GROUP(GPIOX_11, EE_OFF),
GPIO_GROUP(GPIOX_12, EE_OFF),
GPIO_GROUP(GPIOX_13, EE_OFF),
GPIO_GROUP(GPIOX_14, EE_OFF),
GPIO_GROUP(GPIOX_15, EE_OFF),
GPIO_GROUP(GPIOX_16, EE_OFF),
GPIO_GROUP(GPIOX_17, EE_OFF),
GPIO_GROUP(GPIOX_18, EE_OFF),
GPIO_GROUP(GPIOX_19, EE_OFF),
GPIO_GROUP(GPIOX_20, EE_OFF),
GPIO_GROUP(GPIOX_21, EE_OFF),
GPIO_GROUP(GPIOX_22, EE_OFF),
GPIO_GROUP(GPIOY_0, EE_OFF),
GPIO_GROUP(GPIOY_1, EE_OFF),
GPIO_GROUP(GPIOY_2, EE_OFF),
GPIO_GROUP(GPIOY_3, EE_OFF),
GPIO_GROUP(GPIOY_4, EE_OFF),
GPIO_GROUP(GPIOY_5, EE_OFF),
GPIO_GROUP(GPIOY_6, EE_OFF),
GPIO_GROUP(GPIOY_7, EE_OFF),
GPIO_GROUP(GPIOY_8, EE_OFF),
GPIO_GROUP(GPIOY_9, EE_OFF),
GPIO_GROUP(GPIOY_10, EE_OFF),
GPIO_GROUP(GPIOY_11, EE_OFF),
GPIO_GROUP(GPIOY_12, EE_OFF),
GPIO_GROUP(GPIOY_13, EE_OFF),
GPIO_GROUP(GPIOY_14, EE_OFF),
GPIO_GROUP(GPIOY_15, EE_OFF),
/* bank BOOT */
GROUP(emmc_nand_d0, 1),
GROUP(emmc_nand_d1, 1),
GROUP(emmc_nand_d2, 1),
GROUP(emmc_nand_d3, 1),
GROUP(emmc_nand_d4, 1),
GROUP(emmc_nand_d5, 1),
GROUP(emmc_nand_d6, 1),
GROUP(emmc_nand_d7, 1),
GROUP(emmc_clk, 1),
GROUP(emmc_cmd, 1),
GROUP(emmc_ds, 1),
GROUP(nand_ce0, 2),
GROUP(nand_ale, 2),
GROUP(nand_cle, 2),
GROUP(nand_wen_clk, 2),
GROUP(nand_ren_wr, 2),
GROUP(nand_rb0, 2),
GROUP(nor_hold, 3),
GROUP(nor_d, 3),
GROUP(nor_q, 3),
GROUP(nor_c, 3),
GROUP(nor_wp, 3),
GROUP(nor_cs, 3),
/* bank GPIOZ */
GROUP(spi0_clk, 1),
GROUP(spi0_mosi, 1),
GROUP(spi0_miso, 1),
GROUP(spi0_ss0, 1),
GROUP(spi0_ss1, 1),
GROUP(spi0_ss2, 1),
GROUP(i2c0_sck, 1),
GROUP(i2c0_sda, 1),
GROUP(i2c1_sck_z, 1),
GROUP(i2c1_sda_z, 1),
GROUP(uart_rts_b_z, 2),
GROUP(uart_cts_b_z, 2),
GROUP(uart_tx_b_z, 2),
GROUP(uart_rx_b_z, 2),
GROUP(pwm_a_z, 2),
GROUP(pwm_b_z, 2),
GROUP(spdif_in_z, 3),
GROUP(spdif_out_z, 3),
GROUP(uart_ao_tx_b_z, 2),
GROUP(uart_ao_rx_b_z, 2),
GROUP(uart_ao_cts_b_z, 2),
GROUP(uart_ao_rts_b_z, 2),
/* bank GPIOX */
GROUP(sdio_d0, 1),
GROUP(sdio_d1, 1),
GROUP(sdio_d2, 1),
GROUP(sdio_d3, 1),
GROUP(sdio_clk, 1),
GROUP(sdio_cmd, 1),
GROUP(i2c1_sck_x, 1),
GROUP(i2c1_sda_x, 1),
GROUP(i2c2_sck_x, 1),
GROUP(i2c2_sda_x, 1),
GROUP(uart_rts_a, 1),
GROUP(uart_cts_a, 1),
GROUP(uart_tx_a, 1),
GROUP(uart_rx_a, 1),
GROUP(uart_rts_b_x, 2),
GROUP(uart_cts_b_x, 2),
GROUP(uart_tx_b_x, 2),
GROUP(uart_rx_b_x, 2),
GROUP(jtag_tdo_x, 2),
GROUP(jtag_tdi_x, 2),
GROUP(jtag_clk_x, 2),
GROUP(jtag_tms_x, 2),
GROUP(spi1_clk_x, 4),
GROUP(spi1_mosi_x, 4),
GROUP(spi1_miso_x, 4),
GROUP(spi1_ss0_x, 4),
GROUP(pwm_a_x18, 3),
GROUP(pwm_a_x20, 1),
GROUP(pwm_b_x, 3),
GROUP(pwm_c_x10, 3),
GROUP(pwm_c_x17, 3),
GROUP(pwm_d_x11, 3),
GROUP(pwm_d_x16, 3),
GROUP(eth_txd0_x, 4),
GROUP(eth_txd1_x, 4),
GROUP(eth_txen_x, 4),
GROUP(eth_rgmii_rx_clk_x, 4),
GROUP(eth_rxd0_x, 4),
GROUP(eth_rxd1_x, 4),
GROUP(eth_rx_dv_x, 4),
GROUP(eth_mdio_x, 4),
GROUP(eth_mdc_x, 4),
GROUP(tdma_sclk, 1),
GROUP(tdma_sclk_slv, 2),
GROUP(tdma_fs, 1),
GROUP(tdma_fs_slv, 2),
GROUP(tdma_din0, 1),
GROUP(tdma_dout0_x14, 2),
GROUP(tdma_dout0_x15, 1),
GROUP(tdma_dout1, 2),
GROUP(tdma_din1, 3),
/* bank GPIOY */
GROUP(eth_txd0_y, 1),
GROUP(eth_txd1_y, 1),
GROUP(eth_txen_y, 1),
GROUP(eth_rgmii_rx_clk_y, 1),
GROUP(eth_rxd0_y, 1),
GROUP(eth_rxd1_y, 1),
GROUP(eth_rx_dv_y, 1),
GROUP(eth_mdio_y, 1),
GROUP(eth_mdc_y, 1),
GROUP(eth_rxd2_rgmii, 1),
GROUP(eth_rxd3_rgmii, 1),
GROUP(eth_rgmii_tx_clk, 1),
GROUP(eth_txd2_rgmii, 1),
GROUP(eth_txd3_rgmii, 1),
/* bank GPIOA */
GROUP(spdif_out_a1, 4),
GROUP(spdif_out_a11, 3),
GROUP(spdif_out_a19, 2),
GROUP(spdif_out_a20, 1),
GROUP(spdif_in_a1, 3),
GROUP(spdif_in_a7, 3),
GROUP(spdif_in_a19, 1),
GROUP(spdif_in_a20, 2),
GROUP(spi1_clk_a, 3),
GROUP(spi1_mosi_a, 3),
GROUP(spi1_miso_a, 3),
GROUP(spi1_ss0_a, 3),
GROUP(spi1_ss1, 3),
GROUP(pwm_a_a, 3),
GROUP(pwm_b_a, 3),
GROUP(pwm_c_a, 3),
GROUP(pwm_vs, 2),
GROUP(i2c2_sda_a, 3),
GROUP(i2c2_sck_a, 3),
GROUP(i2c3_sda_a6, 4),
GROUP(i2c3_sck_a7, 4),
GROUP(i2c3_sda_a12, 4),
GROUP(i2c3_sck_a13, 4),
GROUP(i2c3_sda_a19, 4),
GROUP(i2c3_sck_a20, 4),
GROUP(pdm_dclk_a14, 1),
GROUP(pdm_dclk_a19, 3),
GROUP(pdm_din0, 1),
GROUP(pdm_din1, 1),
GROUP(pdm_din2, 1),
GROUP(pdm_din3, 1),
GROUP(mclk_c, 1),
GROUP(mclk_b, 1),
GROUP(tdmc_sclk, 1),
GROUP(tdmc_sclk_slv, 2),
GROUP(tdmc_fs, 1),
GROUP(tdmc_fs_slv, 2),
GROUP(tdmc_din0, 2),
GROUP(tdmc_dout0, 1),
GROUP(tdmc_din1, 2),
GROUP(tdmc_dout1, 1),
GROUP(tdmc_din2, 2),
GROUP(tdmc_dout2, 1),
GROUP(tdmc_din3, 2),
GROUP(tdmc_dout3, 1),
GROUP(tdmb_sclk, 1),
GROUP(tdmb_sclk_slv, 2),
GROUP(tdmb_fs, 1),
GROUP(tdmb_fs_slv, 2),
GROUP(tdmb_din0, 2),
GROUP(tdmb_dout0, 1),
GROUP(tdmb_din1, 2),
GROUP(tdmb_dout1, 1),
GROUP(tdmb_din2, 2),
GROUP(tdmb_dout2, 1),
GROUP(tdmb_din3, 2),
GROUP(tdmb_dout3, 1),
};
/* uart_ao_a */
static const unsigned int uart_ao_tx_a_pins[] = {GPIOAO_0};
static const unsigned int uart_ao_rx_a_pins[] = {GPIOAO_1};
static const unsigned int uart_ao_cts_a_pins[] = {GPIOAO_2};
static const unsigned int uart_ao_rts_a_pins[] = {GPIOAO_3};
/* uart_ao_b */
static const unsigned int uart_ao_tx_b_pins[] = {GPIOAO_4};
static const unsigned int uart_ao_rx_b_pins[] = {GPIOAO_5};
static const unsigned int uart_ao_cts_b_pins[] = {GPIOAO_2};
static const unsigned int uart_ao_rts_b_pins[] = {GPIOAO_3};
/* i2c_ao */
static const unsigned int i2c_ao_sck_4_pins[] = {GPIOAO_4};
static const unsigned int i2c_ao_sda_5_pins[] = {GPIOAO_5};
static const unsigned int i2c_ao_sck_8_pins[] = {GPIOAO_8};
static const unsigned int i2c_ao_sda_9_pins[] = {GPIOAO_9};
static const unsigned int i2c_ao_sck_10_pins[] = {GPIOAO_10};
static const unsigned int i2c_ao_sda_11_pins[] = {GPIOAO_11};
/* i2c_ao_slave */
static const unsigned int i2c_ao_slave_sck_pins[] = {GPIOAO_10};
static const unsigned int i2c_ao_slave_sda_pins[] = {GPIOAO_11};
/* ir_in */
static const unsigned int remote_input_ao_pins[] = {GPIOAO_6};
/* ir_out */
static const unsigned int remote_out_ao_pins[] = {GPIOAO_7};
/* pwm_ao_a */
static const unsigned int pwm_ao_a_pins[] = {GPIOAO_3};
/* pwm_ao_b */
static const unsigned int pwm_ao_b_ao2_pins[] = {GPIOAO_2};
static const unsigned int pwm_ao_b_ao12_pins[] = {GPIOAO_12};
/* pwm_ao_c */
static const unsigned int pwm_ao_c_ao8_pins[] = {GPIOAO_8};
static const unsigned int pwm_ao_c_ao13_pins[] = {GPIOAO_13};
/* pwm_ao_d */
static const unsigned int pwm_ao_d_pins[] = {GPIOAO_9};
/* jtag_ao */
static const unsigned int jtag_ao_tdi_pins[] = {GPIOAO_3};
static const unsigned int jtag_ao_tdo_pins[] = {GPIOAO_4};
static const unsigned int jtag_ao_clk_pins[] = {GPIOAO_5};
static const unsigned int jtag_ao_tms_pins[] = {GPIOAO_7};
static struct meson_pmx_group meson_axg_aobus_groups[] = {
GPIO_GROUP(GPIOAO_0, 0),
GPIO_GROUP(GPIOAO_1, 0),
GPIO_GROUP(GPIOAO_2, 0),
GPIO_GROUP(GPIOAO_3, 0),
GPIO_GROUP(GPIOAO_4, 0),
GPIO_GROUP(GPIOAO_5, 0),
GPIO_GROUP(GPIOAO_6, 0),
GPIO_GROUP(GPIOAO_7, 0),
GPIO_GROUP(GPIOAO_8, 0),
GPIO_GROUP(GPIOAO_9, 0),
GPIO_GROUP(GPIOAO_10, 0),
GPIO_GROUP(GPIOAO_11, 0),
GPIO_GROUP(GPIOAO_12, 0),
GPIO_GROUP(GPIOAO_13, 0),
GPIO_GROUP(GPIO_TEST_N, 0),
/* bank AO */
GROUP(uart_ao_tx_a, 1),
GROUP(uart_ao_rx_a, 1),
GROUP(uart_ao_cts_a, 2),
GROUP(uart_ao_rts_a, 2),
GROUP(uart_ao_tx_b, 1),
GROUP(uart_ao_rx_b, 1),
GROUP(uart_ao_cts_b, 1),
GROUP(uart_ao_rts_b, 1),
GROUP(i2c_ao_sck_4, 2),
GROUP(i2c_ao_sda_5, 2),
GROUP(i2c_ao_sck_8, 2),
GROUP(i2c_ao_sda_9, 2),
GROUP(i2c_ao_sck_10, 2),
GROUP(i2c_ao_sda_11, 2),
GROUP(i2c_ao_slave_sck, 1),
GROUP(i2c_ao_slave_sda, 1),
GROUP(remote_input_ao, 1),
GROUP(remote_out_ao, 1),
GROUP(pwm_ao_a, 3),
GROUP(pwm_ao_b_ao2, 3),
GROUP(pwm_ao_b_ao12, 3),
GROUP(pwm_ao_c_ao8, 3),
GROUP(pwm_ao_c_ao13, 3),
GROUP(pwm_ao_d, 3),
GROUP(jtag_ao_tdi, 4),
GROUP(jtag_ao_tdo, 4),
GROUP(jtag_ao_clk, 4),
GROUP(jtag_ao_tms, 4),
};
static const char * const gpio_periphs_groups[] = {
"GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4",
"GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9",
"GPIOZ_10",
"BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4",
"BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9",
"BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
"GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4",
"GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9",
"GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14",
"GPIOA_15", "GPIOA_16", "GPIOA_17", "GPIOA_18", "GPIOA_19",
"GPIOA_20",
"GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
"GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
"GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
"GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19",
"GPIOX_20", "GPIOX_21", "GPIOX_22",
"GPIOY_0", "GPIOY_1", "GPIOY_2", "GPIOY_3", "GPIOY_4",
"GPIOY_5", "GPIOY_6", "GPIOY_7", "GPIOY_8", "GPIOY_9",
"GPIOY_10", "GPIOY_11", "GPIOY_12", "GPIOY_13", "GPIOY_14",
"GPIOY_15",
};
static const char * const emmc_groups[] = {
"emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2",
"emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5",
"emmc_nand_d6", "emmc_nand_d7",
"emmc_clk", "emmc_cmd", "emmc_ds",
};
static const char * const nand_groups[] = {
"emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2",
"emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5",
"emmc_nand_d6", "emmc_nand_d7",
"nand_ce0", "nand_ale", "nand_cle",
"nand_wen_clk", "nand_ren_wr", "nand_rb0",
};
static const char * const nor_groups[] = {
"nor_d", "nor_q", "nor_c", "nor_cs",
"nor_hold", "nor_wp",
};
static const char * const sdio_groups[] = {
"sdio_d0", "sdio_d1", "sdio_d2", "sdio_d3",
"sdio_cmd", "sdio_clk",
};
static const char * const spi0_groups[] = {
"spi0_clk", "spi0_mosi", "spi0_miso", "spi0_ss0",
"spi0_ss1", "spi0_ss2"
};
static const char * const spi1_groups[] = {
"spi1_clk_x", "spi1_mosi_x", "spi1_miso_x", "spi1_ss0_x",
"spi1_clk_a", "spi1_mosi_a", "spi1_miso_a", "spi1_ss0_a",
"spi1_ss1"
};
static const char * const uart_a_groups[] = {
"uart_tx_a", "uart_rx_a", "uart_cts_a", "uart_rts_a",
};
static const char * const uart_b_groups[] = {
"uart_tx_b_z", "uart_rx_b_z", "uart_cts_b_z", "uart_rts_b_z",
"uart_tx_b_x", "uart_rx_b_x", "uart_cts_b_x", "uart_rts_b_x",
};
static const char * const uart_ao_b_z_groups[] = {
"uart_ao_tx_b_z", "uart_ao_rx_b_z",
"uart_ao_cts_b_z", "uart_ao_rts_b_z",
};
static const char * const i2c0_groups[] = {
"i2c0_sck", "i2c0_sda",
};
static const char * const i2c1_groups[] = {
"i2c1_sck_z", "i2c1_sda_z",
"i2c1_sck_x", "i2c1_sda_x",
};
static const char * const i2c2_groups[] = {
"i2c2_sck_x", "i2c2_sda_x",
"i2c2_sda_a", "i2c2_sck_a",
};
static const char * const i2c3_groups[] = {
"i2c3_sda_a6", "i2c3_sck_a7",
"i2c3_sda_a12", "i2c3_sck_a13",
"i2c3_sda_a19", "i2c3_sck_a20",
};
static const char * const eth_groups[] = {
"eth_rxd2_rgmii", "eth_rxd3_rgmii", "eth_rgmii_tx_clk",
"eth_txd2_rgmii", "eth_txd3_rgmii",
"eth_txd0_x", "eth_txd1_x", "eth_txen_x", "eth_rgmii_rx_clk_x",
"eth_rxd0_x", "eth_rxd1_x", "eth_rx_dv_x", "eth_mdio_x",
"eth_mdc_x",
"eth_txd0_y", "eth_txd1_y", "eth_txen_y", "eth_rgmii_rx_clk_y",
"eth_rxd0_y", "eth_rxd1_y", "eth_rx_dv_y", "eth_mdio_y",
"eth_mdc_y",
};
static const char * const pwm_a_groups[] = {
"pwm_a_z", "pwm_a_x18", "pwm_a_x20", "pwm_a_a",
};
static const char * const pwm_b_groups[] = {
"pwm_b_z", "pwm_b_x", "pwm_b_a",
};
static const char * const pwm_c_groups[] = {
"pwm_c_x10", "pwm_c_x17", "pwm_c_a",
};
static const char * const pwm_d_groups[] = {
"pwm_d_x11", "pwm_d_x16",
};
static const char * const pwm_vs_groups[] = {
"pwm_vs",
};
static const char * const spdif_out_groups[] = {
"spdif_out_z", "spdif_out_a1", "spdif_out_a11",
"spdif_out_a19", "spdif_out_a20",
};
static const char * const spdif_in_groups[] = {
"spdif_in_z", "spdif_in_a1", "spdif_in_a7",
"spdif_in_a19", "spdif_in_a20",
};
static const char * const jtag_ee_groups[] = {
"jtag_tdo_x", "jtag_tdi_x", "jtag_clk_x",
"jtag_tms_x",
};
static const char * const pdm_groups[] = {
"pdm_din0", "pdm_din1", "pdm_din2", "pdm_din3",
"pdm_dclk_a14", "pdm_dclk_a19",
};
static const char * const gpio_aobus_groups[] = {
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
"GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
"GPIOAO_10", "GPIOAO_11", "GPIOAO_12", "GPIOAO_13",
"GPIO_TEST_N",
};
static const char * const uart_ao_a_groups[] = {
"uart_ao_tx_a", "uart_ao_rx_a", "uart_ao_cts_a", "uart_ao_rts_a",
};
static const char * const uart_ao_b_groups[] = {
"uart_ao_tx_b", "uart_ao_rx_b", "uart_ao_cts_b", "uart_ao_rts_b",
};
static const char * const i2c_ao_groups[] = {
"i2c_ao_sck_4", "i2c_ao_sda_5",
"i2c_ao_sck_8", "i2c_ao_sda_9",
"i2c_ao_sck_10", "i2c_ao_sda_11",
};
static const char * const i2c_ao_slave_groups[] = {
"i2c_ao_slave_sck", "i2c_ao_slave_sda",
};
static const char * const remote_input_ao_groups[] = {
"remote_input_ao",
};
static const char * const remote_out_ao_groups[] = {
"remote_out_ao",
};
static const char * const pwm_ao_a_groups[] = {
"pwm_ao_a",
};
static const char * const pwm_ao_b_groups[] = {
"pwm_ao_b_ao2", "pwm_ao_b_ao12",
};
static const char * const pwm_ao_c_groups[] = {
"pwm_ao_c_ao8", "pwm_ao_c_ao13",
};
static const char * const pwm_ao_d_groups[] = {
"pwm_ao_d",
};
static const char * const jtag_ao_groups[] = {
"jtag_ao_tdi", "jtag_ao_tdo", "jtag_ao_clk", "jtag_ao_tms",
};
static const char * const mclk_c_groups[] = {
"mclk_c",
};
static const char * const mclk_b_groups[] = {
"mclk_b",
};
static const char * const tdma_groups[] = {
"tdma_sclk", "tdma_sclk_slv", "tdma_fs", "tdma_fs_slv",
"tdma_din0", "tdma_dout0_x14", "tdma_dout0_x15", "tdma_dout1",
"tdma_din1",
};
static const char * const tdmc_groups[] = {
"tdmc_sclk", "tdmc_sclk_slv", "tdmc_fs", "tdmc_fs_slv",
"tdmc_din0", "tdmc_dout0", "tdmc_din1", "tdmc_dout1",
"tdmc_din2", "tdmc_dout2", "tdmc_din3", "tdmc_dout3",
};
static const char * const tdmb_groups[] = {
"tdmb_sclk", "tdmb_sclk_slv", "tdmb_fs", "tdmb_fs_slv",
"tdmb_din0", "tdmb_dout0", "tdmb_din1", "tdmb_dout1",
"tdmb_din2", "tdmb_dout2", "tdmb_din3", "tdmb_dout3",
};
static struct meson_pmx_func meson_axg_periphs_functions[] = {
FUNCTION(gpio_periphs),
FUNCTION(emmc),
FUNCTION(nor),
FUNCTION(spi0),
FUNCTION(spi1),
FUNCTION(sdio),
FUNCTION(nand),
FUNCTION(uart_a),
FUNCTION(uart_b),
FUNCTION(uart_ao_b_z),
FUNCTION(i2c0),
FUNCTION(i2c1),
FUNCTION(i2c2),
FUNCTION(i2c3),
FUNCTION(eth),
FUNCTION(pwm_a),
FUNCTION(pwm_b),
FUNCTION(pwm_c),
FUNCTION(pwm_d),
FUNCTION(pwm_vs),
FUNCTION(spdif_out),
FUNCTION(spdif_in),
FUNCTION(jtag_ee),
FUNCTION(pdm),
FUNCTION(mclk_b),
FUNCTION(mclk_c),
FUNCTION(tdma),
FUNCTION(tdmb),
FUNCTION(tdmc),
};
static struct meson_pmx_func meson_axg_aobus_functions[] = {
FUNCTION(gpio_aobus),
FUNCTION(uart_ao_a),
FUNCTION(uart_ao_b),
FUNCTION(i2c_ao),
FUNCTION(i2c_ao_slave),
FUNCTION(remote_input_ao),
FUNCTION(remote_out_ao),
FUNCTION(pwm_ao_a),
FUNCTION(pwm_ao_b),
FUNCTION(pwm_ao_c),
FUNCTION(pwm_ao_d),
FUNCTION(jtag_ao),
};
static struct meson_bank meson_axg_periphs_banks[] = {
/* name first last pullen pull dir out in */
BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_10, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_14, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
BANK("A", PIN(GPIOA_0, EE_OFF), PIN(GPIOA_20, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_15, EE_OFF), 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
};
static struct meson_bank meson_axg_aobus_banks[] = {
/* name first last pullen pull dir out in */
BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 16, 0, 0, 0, 0, 0, 16, 1, 0),
};
static struct meson_pmx_bank meson_axg_periphs_pmx_banks[] = {
/* name first last reg offset */
BANK_PMX("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_10, EE_OFF), 0x2, 0),
BANK_PMX("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_14, EE_OFF), 0x0, 0),
BANK_PMX("A", PIN(GPIOA_0, EE_OFF), PIN(GPIOA_20, EE_OFF), 0xb, 0),
BANK_PMX("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 0x4, 0),
BANK_PMX("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_15, EE_OFF), 0x8, 0),
};
static struct meson_axg_pmx_data meson_axg_periphs_pmx_banks_data = {
.pmx_banks = meson_axg_periphs_pmx_banks,
.num_pmx_banks = ARRAY_SIZE(meson_axg_periphs_pmx_banks),
};
static struct meson_pmx_bank meson_axg_aobus_pmx_banks[] = {
BANK_PMX("AO", GPIOAO_0, GPIOAO_13, 0x0, 0),
};
static struct meson_axg_pmx_data meson_axg_aobus_pmx_banks_data = {
.pmx_banks = meson_axg_aobus_pmx_banks,
.num_pmx_banks = ARRAY_SIZE(meson_axg_aobus_pmx_banks),
};
struct meson_pinctrl_data meson_axg_periphs_pinctrl_data = {
.name = "periphs-banks",
.pin_base = EE_OFF,
.groups = meson_axg_periphs_groups,
.funcs = meson_axg_periphs_functions,
.banks = meson_axg_periphs_banks,
.num_pins = 86,
.num_groups = ARRAY_SIZE(meson_axg_periphs_groups),
.num_funcs = ARRAY_SIZE(meson_axg_periphs_functions),
.num_banks = ARRAY_SIZE(meson_axg_periphs_banks),
.gpio_driver = &meson_axg_gpio_driver,
.pmx_data = &meson_axg_periphs_pmx_banks_data,
};
struct meson_pinctrl_data meson_axg_aobus_pinctrl_data = {
.name = "aobus-banks",
.pin_base = 0,
.groups = meson_axg_aobus_groups,
.funcs = meson_axg_aobus_functions,
.banks = meson_axg_aobus_banks,
.num_pins = 14,
.num_groups = ARRAY_SIZE(meson_axg_aobus_groups),
.num_funcs = ARRAY_SIZE(meson_axg_aobus_functions),
.num_banks = ARRAY_SIZE(meson_axg_aobus_banks),
.gpio_driver = &meson_axg_gpio_driver,
.pmx_data = &meson_axg_aobus_pmx_banks_data,
};
static const struct udevice_id meson_axg_pinctrl_match[] = {
{
.compatible = "amlogic,meson-axg-periphs-pinctrl",
.data = (ulong)&meson_axg_periphs_pinctrl_data,
},
{
.compatible = "amlogic,meson-axg-aobus-pinctrl",
.data = (ulong)&meson_axg_aobus_pinctrl_data,
},
{ /* sentinel */ }
};
U_BOOT_DRIVER(meson_axg_pinctrl) = {
.name = "meson-axg-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(meson_axg_pinctrl_match),
.probe = meson_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct meson_pinctrl),
.ops = &meson_axg_pinctrl_ops,
};
@@ -0,0 +1,66 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2017 Jerome Brunet <jbrunet@baylibre.com>
* Copyright (C) 2017 Xingyu Chen <xingyu.chen@amlogic.com>
*/
#ifndef __PINCTRL_MESON_AXG_H__
#define __PINCTRL_MESON_AXG_H__
#include "pinctrl-meson.h"
struct meson_pmx_bank {
const char *name;
unsigned int first;
unsigned int last;
unsigned int reg;
unsigned int offset;
};
struct meson_axg_pmx_data {
struct meson_pmx_bank *pmx_banks;
unsigned int num_pmx_banks;
};
#define BANK_PMX(n, f, l, r, o) \
{ \
.name = n, \
.first = f, \
.last = l, \
.reg = r, \
.offset = o, \
}
struct meson_pmx_axg_data {
unsigned int func;
};
#define PMX_DATA(f) \
{ \
.func = f, \
}
#define GROUP(grp, f) \
{ \
.name = #grp, \
.pins = grp ## _pins, \
.num_pins = ARRAY_SIZE(grp ## _pins), \
.data = (const struct meson_pmx_axg_data[]){ \
PMX_DATA(f), \
}, \
}
#define GPIO_GROUP(gpio, b) \
{ \
.name = #gpio, \
.pins = (const unsigned int[]){ PIN(gpio, b) }, \
.num_pins = 1, \
.data = (const struct meson_pmx_axg_data[]){ \
PMX_DATA(0), \
}, \
}
extern const struct pinctrl_ops meson_axg_pinctrl_ops;
extern const struct driver meson_axg_gpio_driver;
#endif /* __PINCTRL_MESON_AXG_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,151 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
*/
#include <asm/gpio.h>
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <linux/io.h>
#include "pinctrl-meson-gx.h"
static void meson_gx_pinmux_disable_other_groups(struct meson_pinctrl *priv,
unsigned int pin,
int sel_group)
{
struct meson_pmx_group *group;
struct meson_gx_pmx_data *pmx_data;
void __iomem *addr;
int i, j;
for (i = 0; i < priv->data->num_groups; i++) {
group = &priv->data->groups[i];
pmx_data = (struct meson_gx_pmx_data *)group->data;
if (pmx_data->is_gpio || i == sel_group)
continue;
for (j = 0; j < group->num_pins; j++) {
if (group->pins[j] == pin) {
/* We have found a group using the pin */
debug("pinmux: disabling %s\n", group->name);
addr = priv->reg_mux + pmx_data->reg * 4;
writel(readl(addr) & ~BIT(pmx_data->bit), addr);
}
}
}
}
static int meson_gx_pinmux_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int func_selector)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
const struct meson_pmx_group *group;
const struct meson_pmx_func *func;
struct meson_gx_pmx_data *pmx_data;
void __iomem *addr;
int i;
group = &priv->data->groups[group_selector];
pmx_data = (struct meson_gx_pmx_data *)group->data;
func = &priv->data->funcs[func_selector];
debug("pinmux: set group %s func %s\n", group->name, func->name);
/*
* Disable groups using the same pins.
* The selected group is not disabled to avoid glitches.
*/
for (i = 0; i < group->num_pins; i++) {
meson_gx_pinmux_disable_other_groups(priv,
group->pins[i],
group_selector);
}
/* Function 0 (GPIO) doesn't need any additional setting */
if (func_selector) {
addr = priv->reg_mux + pmx_data->reg * 4;
writel(readl(addr) | BIT(pmx_data->bit), addr);
}
return 0;
}
static int meson_gx_pinmux_get(struct udevice *dev,
unsigned int selector,
char *buf, int size)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
struct meson_pmx_group *group;
struct meson_gx_pmx_data *pmx_data;
void __iomem *addr;
int i, j, pos = 0;
unsigned int pin;
u32 reg;
pin = selector + priv->data->pin_base;
for (i = 0; i < priv->data->num_groups; i++) {
group = &priv->data->groups[i];
pmx_data = (struct meson_gx_pmx_data *)group->data;
if (pmx_data->is_gpio)
continue;
for (j = 0; j < group->num_pins; j++) {
if (group->pins[j] == pin) {
/* We have found a group using the pin */
addr = priv->reg_mux + pmx_data->reg * 4;
reg = readl(addr) & BIT(pmx_data->bit);
if (reg) {
pos += snprintf(buf + pos, size - pos,
"%s ", group->name) - 1;
return 0;
}
}
}
}
/* Fallback, must be used as GPIO */
snprintf(buf, size, "%s or Unknown",
priv->data->groups[selector].name);
return 0;
}
const struct pinconf_param meson_gx_pinconf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
};
const struct pinctrl_ops meson_gx_pinctrl_ops = {
.get_groups_count = meson_pinctrl_get_groups_count,
.get_group_name = meson_pinctrl_get_group_name,
.get_functions_count = meson_pinmux_get_functions_count,
.get_function_name = meson_pinmux_get_function_name,
.pinmux_group_set = meson_gx_pinmux_group_set,
.set_state = pinctrl_generic_set_state,
.pinconf_params = meson_gx_pinconf_params,
.pinconf_num_params = ARRAY_SIZE(meson_gx_pinconf_params),
.pinconf_set = meson_pinconf_set,
.pinconf_group_set = meson_pinconf_group_set,
.get_pin_name = meson_pinctrl_get_pin_name,
.get_pins_count = meson_pinctrl_get_pins_count,
.get_pin_muxing = meson_gx_pinmux_get,
};
static const struct dm_gpio_ops meson_gx_gpio_ops = {
.set_value = meson_gpio_set,
.get_value = meson_gpio_get,
.get_function = meson_gpio_get_direction,
.direction_input = meson_gpio_direction_input,
.direction_output = meson_gpio_direction_output,
};
const struct driver meson_gx_gpio_driver = {
.name = "meson-gx-gpio",
.id = UCLASS_GPIO,
.probe = meson_gpio_probe,
.ops = &meson_gx_gpio_ops,
};
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
* Copyright (C) 2017 Jerome Brunet <jbrunet@baylibre.com>
*/
#ifndef __PINCTRL_MESON_GX_H__
#define __PINCTRL_MESON_GX_H__
#include "pinctrl-meson.h"
struct meson_gx_pmx_data {
bool is_gpio;
unsigned int reg;
unsigned int bit;
};
#define PMX_DATA(r, b, g) \
{ \
.reg = r, \
.bit = b, \
.is_gpio = g, \
}
#define GROUP(grp, r, b) \
{ \
.name = #grp, \
.pins = grp ## _pins, \
.num_pins = ARRAY_SIZE(grp ## _pins), \
.data = (const struct meson_gx_pmx_data[]){ \
PMX_DATA(r, b, false), \
}, \
}
#define GPIO_GROUP(gpio, b) \
{ \
.name = #gpio, \
.pins = (const unsigned int[]){ PIN(gpio, b) }, \
.num_pins = 1, \
.data = (const struct meson_gx_pmx_data[]){ \
PMX_DATA(0, 0, true), \
}, \
}
extern const struct pinctrl_ops meson_gx_pinctrl_ops;
extern const struct driver meson_gx_gpio_driver;
#endif /* __PINCTRL_MESON_GX_H__ */
@@ -0,0 +1,477 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
*
* Based on code from Linux kernel:
* Copyright (C) 2016 Endless Mobile, Inc.
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <dt-bindings/gpio/meson-gxbb-gpio.h>
#include "pinctrl-meson-gx.h"
#define EE_OFF 15
static const unsigned int emmc_nand_d07_pins[] = {
PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF),
PIN(BOOT_3, EE_OFF), PIN(BOOT_4, EE_OFF), PIN(BOOT_5, EE_OFF),
PIN(BOOT_6, EE_OFF), PIN(BOOT_7, EE_OFF),
};
static const unsigned int emmc_clk_pins[] = { PIN(BOOT_8, EE_OFF) };
static const unsigned int emmc_cmd_pins[] = { PIN(BOOT_10, EE_OFF) };
static const unsigned int emmc_ds_pins[] = { PIN(BOOT_15, EE_OFF) };
static const unsigned int sdcard_d0_pins[] = { PIN(CARD_1, EE_OFF) };
static const unsigned int sdcard_d1_pins[] = { PIN(CARD_0, EE_OFF) };
static const unsigned int sdcard_d2_pins[] = { PIN(CARD_5, EE_OFF) };
static const unsigned int sdcard_d3_pins[] = { PIN(CARD_4, EE_OFF) };
static const unsigned int sdcard_cmd_pins[] = { PIN(CARD_3, EE_OFF) };
static const unsigned int sdcard_clk_pins[] = { PIN(CARD_2, EE_OFF) };
static const unsigned int uart_tx_a_pins[] = { PIN(GPIOX_12, EE_OFF) };
static const unsigned int uart_rx_a_pins[] = { PIN(GPIOX_13, EE_OFF) };
static const unsigned int uart_cts_a_pins[] = { PIN(GPIOX_14, EE_OFF) };
static const unsigned int uart_rts_a_pins[] = { PIN(GPIOX_15, EE_OFF) };
static const unsigned int uart_tx_b_pins[] = { PIN(GPIODV_24, EE_OFF) };
static const unsigned int uart_rx_b_pins[] = { PIN(GPIODV_25, EE_OFF) };
static const unsigned int uart_cts_b_pins[] = { PIN(GPIODV_26, EE_OFF) };
static const unsigned int uart_rts_b_pins[] = { PIN(GPIODV_27, EE_OFF) };
static const unsigned int uart_tx_c_pins[] = { PIN(GPIOY_13, EE_OFF) };
static const unsigned int uart_rx_c_pins[] = { PIN(GPIOY_14, EE_OFF) };
static const unsigned int uart_cts_c_pins[] = { PIN(GPIOX_11, EE_OFF) };
static const unsigned int uart_rts_c_pins[] = { PIN(GPIOX_12, EE_OFF) };
static const unsigned int eth_mdio_pins[] = { PIN(GPIOZ_0, EE_OFF) };
static const unsigned int eth_mdc_pins[] = { PIN(GPIOZ_1, EE_OFF) };
static const unsigned int eth_clk_rx_clk_pins[] = { PIN(GPIOZ_2, EE_OFF) };
static const unsigned int eth_rx_dv_pins[] = { PIN(GPIOZ_3, EE_OFF) };
static const unsigned int eth_rxd0_pins[] = { PIN(GPIOZ_4, EE_OFF) };
static const unsigned int eth_rxd1_pins[] = { PIN(GPIOZ_5, EE_OFF) };
static const unsigned int eth_rxd2_pins[] = { PIN(GPIOZ_6, EE_OFF) };
static const unsigned int eth_rxd3_pins[] = { PIN(GPIOZ_7, EE_OFF) };
static const unsigned int eth_rgmii_tx_clk_pins[] = { PIN(GPIOZ_8, EE_OFF) };
static const unsigned int eth_tx_en_pins[] = { PIN(GPIOZ_9, EE_OFF) };
static const unsigned int eth_txd0_pins[] = { PIN(GPIOZ_10, EE_OFF) };
static const unsigned int eth_txd1_pins[] = { PIN(GPIOZ_11, EE_OFF) };
static const unsigned int eth_txd2_pins[] = { PIN(GPIOZ_12, EE_OFF) };
static const unsigned int eth_txd3_pins[] = { PIN(GPIOZ_13, EE_OFF) };
static const unsigned int hdmi_hpd_pins[] = { PIN(GPIOH_0, EE_OFF) };
static const unsigned int hdmi_sda_pins[] = { PIN(GPIOH_1, EE_OFF) };
static const unsigned int hdmi_scl_pins[] = { PIN(GPIOH_2, EE_OFF) };
static const unsigned int uart_tx_ao_a_pins[] = { PIN(GPIOAO_0, 0) };
static const unsigned int uart_rx_ao_a_pins[] = { PIN(GPIOAO_1, 0) };
static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) };
static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_0, 0) };
static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_1, 0),
PIN(GPIOAO_5, 0) };
static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) };
static const unsigned int i2c_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
static const unsigned int i2c_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
static const unsigned int i2c_slave_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
static const unsigned int i2c_slave_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
GPIO_GROUP(GPIOZ_0, EE_OFF),
GPIO_GROUP(GPIOZ_1, EE_OFF),
GPIO_GROUP(GPIOZ_2, EE_OFF),
GPIO_GROUP(GPIOZ_3, EE_OFF),
GPIO_GROUP(GPIOZ_4, EE_OFF),
GPIO_GROUP(GPIOZ_5, EE_OFF),
GPIO_GROUP(GPIOZ_6, EE_OFF),
GPIO_GROUP(GPIOZ_7, EE_OFF),
GPIO_GROUP(GPIOZ_8, EE_OFF),
GPIO_GROUP(GPIOZ_9, EE_OFF),
GPIO_GROUP(GPIOZ_10, EE_OFF),
GPIO_GROUP(GPIOZ_11, EE_OFF),
GPIO_GROUP(GPIOZ_12, EE_OFF),
GPIO_GROUP(GPIOZ_13, EE_OFF),
GPIO_GROUP(GPIOZ_14, EE_OFF),
GPIO_GROUP(GPIOZ_15, EE_OFF),
GPIO_GROUP(GPIOH_0, EE_OFF),
GPIO_GROUP(GPIOH_1, EE_OFF),
GPIO_GROUP(GPIOH_2, EE_OFF),
GPIO_GROUP(GPIOH_3, EE_OFF),
GPIO_GROUP(BOOT_0, EE_OFF),
GPIO_GROUP(BOOT_1, EE_OFF),
GPIO_GROUP(BOOT_2, EE_OFF),
GPIO_GROUP(BOOT_3, EE_OFF),
GPIO_GROUP(BOOT_4, EE_OFF),
GPIO_GROUP(BOOT_5, EE_OFF),
GPIO_GROUP(BOOT_6, EE_OFF),
GPIO_GROUP(BOOT_7, EE_OFF),
GPIO_GROUP(BOOT_8, EE_OFF),
GPIO_GROUP(BOOT_9, EE_OFF),
GPIO_GROUP(BOOT_10, EE_OFF),
GPIO_GROUP(BOOT_11, EE_OFF),
GPIO_GROUP(BOOT_12, EE_OFF),
GPIO_GROUP(BOOT_13, EE_OFF),
GPIO_GROUP(BOOT_14, EE_OFF),
GPIO_GROUP(BOOT_15, EE_OFF),
GPIO_GROUP(BOOT_16, EE_OFF),
GPIO_GROUP(BOOT_17, EE_OFF),
GPIO_GROUP(CARD_0, EE_OFF),
GPIO_GROUP(CARD_1, EE_OFF),
GPIO_GROUP(CARD_2, EE_OFF),
GPIO_GROUP(CARD_3, EE_OFF),
GPIO_GROUP(CARD_4, EE_OFF),
GPIO_GROUP(CARD_5, EE_OFF),
GPIO_GROUP(CARD_6, EE_OFF),
GPIO_GROUP(GPIODV_0, EE_OFF),
GPIO_GROUP(GPIODV_1, EE_OFF),
GPIO_GROUP(GPIODV_2, EE_OFF),
GPIO_GROUP(GPIODV_3, EE_OFF),
GPIO_GROUP(GPIODV_4, EE_OFF),
GPIO_GROUP(GPIODV_5, EE_OFF),
GPIO_GROUP(GPIODV_6, EE_OFF),
GPIO_GROUP(GPIODV_7, EE_OFF),
GPIO_GROUP(GPIODV_8, EE_OFF),
GPIO_GROUP(GPIODV_9, EE_OFF),
GPIO_GROUP(GPIODV_10, EE_OFF),
GPIO_GROUP(GPIODV_11, EE_OFF),
GPIO_GROUP(GPIODV_12, EE_OFF),
GPIO_GROUP(GPIODV_13, EE_OFF),
GPIO_GROUP(GPIODV_14, EE_OFF),
GPIO_GROUP(GPIODV_15, EE_OFF),
GPIO_GROUP(GPIODV_16, EE_OFF),
GPIO_GROUP(GPIODV_17, EE_OFF),
GPIO_GROUP(GPIODV_18, EE_OFF),
GPIO_GROUP(GPIODV_19, EE_OFF),
GPIO_GROUP(GPIODV_20, EE_OFF),
GPIO_GROUP(GPIODV_21, EE_OFF),
GPIO_GROUP(GPIODV_22, EE_OFF),
GPIO_GROUP(GPIODV_23, EE_OFF),
GPIO_GROUP(GPIODV_24, EE_OFF),
GPIO_GROUP(GPIODV_25, EE_OFF),
GPIO_GROUP(GPIODV_26, EE_OFF),
GPIO_GROUP(GPIODV_27, EE_OFF),
GPIO_GROUP(GPIODV_28, EE_OFF),
GPIO_GROUP(GPIODV_29, EE_OFF),
GPIO_GROUP(GPIOY_0, EE_OFF),
GPIO_GROUP(GPIOY_1, EE_OFF),
GPIO_GROUP(GPIOY_2, EE_OFF),
GPIO_GROUP(GPIOY_3, EE_OFF),
GPIO_GROUP(GPIOY_4, EE_OFF),
GPIO_GROUP(GPIOY_5, EE_OFF),
GPIO_GROUP(GPIOY_6, EE_OFF),
GPIO_GROUP(GPIOY_7, EE_OFF),
GPIO_GROUP(GPIOY_8, EE_OFF),
GPIO_GROUP(GPIOY_9, EE_OFF),
GPIO_GROUP(GPIOY_10, EE_OFF),
GPIO_GROUP(GPIOY_11, EE_OFF),
GPIO_GROUP(GPIOY_12, EE_OFF),
GPIO_GROUP(GPIOY_13, EE_OFF),
GPIO_GROUP(GPIOY_14, EE_OFF),
GPIO_GROUP(GPIOY_15, EE_OFF),
GPIO_GROUP(GPIOY_16, EE_OFF),
GPIO_GROUP(GPIOX_0, EE_OFF),
GPIO_GROUP(GPIOX_1, EE_OFF),
GPIO_GROUP(GPIOX_2, EE_OFF),
GPIO_GROUP(GPIOX_3, EE_OFF),
GPIO_GROUP(GPIOX_4, EE_OFF),
GPIO_GROUP(GPIOX_5, EE_OFF),
GPIO_GROUP(GPIOX_6, EE_OFF),
GPIO_GROUP(GPIOX_7, EE_OFF),
GPIO_GROUP(GPIOX_8, EE_OFF),
GPIO_GROUP(GPIOX_9, EE_OFF),
GPIO_GROUP(GPIOX_10, EE_OFF),
GPIO_GROUP(GPIOX_11, EE_OFF),
GPIO_GROUP(GPIOX_12, EE_OFF),
GPIO_GROUP(GPIOX_13, EE_OFF),
GPIO_GROUP(GPIOX_14, EE_OFF),
GPIO_GROUP(GPIOX_15, EE_OFF),
GPIO_GROUP(GPIOX_16, EE_OFF),
GPIO_GROUP(GPIOX_17, EE_OFF),
GPIO_GROUP(GPIOX_18, EE_OFF),
GPIO_GROUP(GPIOX_19, EE_OFF),
GPIO_GROUP(GPIOX_20, EE_OFF),
GPIO_GROUP(GPIOX_21, EE_OFF),
GPIO_GROUP(GPIOX_22, EE_OFF),
GPIO_GROUP(GPIOCLK_0, EE_OFF),
GPIO_GROUP(GPIOCLK_1, EE_OFF),
GPIO_GROUP(GPIOCLK_2, EE_OFF),
GPIO_GROUP(GPIOCLK_3, EE_OFF),
/* Bank X */
GROUP(uart_tx_a, 4, 13),
GROUP(uart_rx_a, 4, 12),
GROUP(uart_cts_a, 4, 11),
GROUP(uart_rts_a, 4, 10),
/* Bank Y */
GROUP(uart_cts_c, 1, 19),
GROUP(uart_rts_c, 1, 18),
GROUP(uart_tx_c, 1, 17),
GROUP(uart_rx_c, 1, 16),
/* Bank Z */
GROUP(eth_mdio, 6, 1),
GROUP(eth_mdc, 6, 0),
GROUP(eth_clk_rx_clk, 6, 13),
GROUP(eth_rx_dv, 6, 12),
GROUP(eth_rxd0, 6, 11),
GROUP(eth_rxd1, 6, 10),
GROUP(eth_rxd2, 6, 9),
GROUP(eth_rxd3, 6, 8),
GROUP(eth_rgmii_tx_clk, 6, 7),
GROUP(eth_tx_en, 6, 6),
GROUP(eth_txd0, 6, 5),
GROUP(eth_txd1, 6, 4),
GROUP(eth_txd2, 6, 3),
GROUP(eth_txd3, 6, 2),
/* Bank H */
GROUP(hdmi_hpd, 1, 26),
GROUP(hdmi_sda, 1, 25),
GROUP(hdmi_scl, 1, 24),
/* Bank DV */
GROUP(uart_tx_b, 2, 29),
GROUP(uart_rx_b, 2, 28),
GROUP(uart_cts_b, 2, 27),
GROUP(uart_rts_b, 2, 26),
/* Bank BOOT */
GROUP(emmc_nand_d07, 4, 30),
GROUP(emmc_clk, 4, 18),
GROUP(emmc_cmd, 4, 19),
GROUP(emmc_ds, 4, 31),
/* Bank CARD */
GROUP(sdcard_d1, 2, 14),
GROUP(sdcard_d0, 2, 15),
GROUP(sdcard_d3, 2, 12),
GROUP(sdcard_d2, 2, 13),
GROUP(sdcard_cmd, 2, 10),
GROUP(sdcard_clk, 2, 11),
};
static struct meson_pmx_group meson_gxbb_aobus_groups[] = {
GPIO_GROUP(GPIOAO_0, 0),
GPIO_GROUP(GPIOAO_1, 0),
GPIO_GROUP(GPIOAO_2, 0),
GPIO_GROUP(GPIOAO_3, 0),
GPIO_GROUP(GPIOAO_4, 0),
GPIO_GROUP(GPIOAO_5, 0),
GPIO_GROUP(GPIOAO_6, 0),
GPIO_GROUP(GPIOAO_7, 0),
GPIO_GROUP(GPIOAO_8, 0),
GPIO_GROUP(GPIOAO_9, 0),
GPIO_GROUP(GPIOAO_10, 0),
GPIO_GROUP(GPIOAO_11, 0),
GPIO_GROUP(GPIOAO_12, 0),
GPIO_GROUP(GPIOAO_13, 0),
GPIO_GROUP(GPIO_TEST_N, 0),
/* bank AO */
GROUP(uart_tx_ao_b, 0, 26),
GROUP(uart_rx_ao_b, 0, 25),
GROUP(uart_tx_ao_a, 0, 12),
GROUP(uart_rx_ao_a, 0, 11),
GROUP(uart_cts_ao_a, 0, 10),
GROUP(uart_rts_ao_a, 0, 9),
GROUP(uart_cts_ao_b, 0, 8),
GROUP(uart_rts_ao_b, 0, 7),
GROUP(i2c_sck_ao, 0, 6),
GROUP(i2c_sda_ao, 0, 5),
GROUP(i2c_slave_sck_ao, 0, 2),
GROUP(i2c_slave_sda_ao, 0, 1),
};
static const char * const gpio_periphs_groups[] = {
"GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4",
"GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9",
"GPIOZ_10", "GPIOZ_11", "GPIOZ_12", "GPIOZ_13", "GPIOZ_14",
"GPIOZ_15",
"GPIOH_0", "GPIOH_1", "GPIOH_2", "GPIOH_3",
"BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4",
"BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9",
"BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
"BOOT_15", "BOOT_16", "BOOT_17",
"CARD_0", "CARD_1", "CARD_2", "CARD_3", "CARD_4",
"CARD_5", "CARD_6",
"GPIODV_0", "GPIODV_1", "GPIODV_2", "GPIODV_3", "GPIODV_4",
"GPIODV_5", "GPIODV_6", "GPIODV_7", "GPIODV_8", "GPIODV_9",
"GPIODV_10", "GPIODV_11", "GPIODV_12", "GPIODV_13", "GPIODV_14",
"GPIODV_15", "GPIODV_16", "GPIODV_17", "GPIODV_18", "GPIODV_19",
"GPIODV_20", "GPIODV_21", "GPIODV_22", "GPIODV_23", "GPIODV_24",
"GPIODV_25", "GPIODV_26", "GPIODV_27", "GPIODV_28", "GPIODV_29",
"GPIOY_0", "GPIOY_1", "GPIOY_2", "GPIOY_3", "GPIOY_4",
"GPIOY_5", "GPIOY_6", "GPIOY_7", "GPIOY_8", "GPIOY_9",
"GPIOY_10", "GPIOY_11", "GPIOY_12", "GPIOY_13", "GPIOY_14",
"GPIOY_15", "GPIOY_16",
"GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
"GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
"GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
"GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19",
"GPIOX_20", "GPIOX_21", "GPIOX_22",
"GPIOCLK_0", "GPIOCLK_1", "GPIOCLK_2", "GPIOCLK_3",
};
static const char * const emmc_groups[] = {
"emmc_nand_d07", "emmc_clk", "emmc_cmd", "emmc_ds",
};
static const char * const sdcard_groups[] = {
"sdcard_d0", "sdcard_d1", "sdcard_d2", "sdcard_d3",
"sdcard_cmd", "sdcard_clk",
};
static const char * const uart_a_groups[] = {
"uart_tx_a", "uart_rx_a", "uart_cts_a", "uart_rts_a",
};
static const char * const uart_b_groups[] = {
"uart_tx_b", "uart_rx_b", "uart_cts_b", "uart_rts_b",
};
static const char * const uart_c_groups[] = {
"uart_tx_c", "uart_rx_c", "uart_cts_c", "uart_rts_c",
};
static const char * const eth_groups[] = {
"eth_mdio", "eth_mdc", "eth_clk_rx_clk", "eth_rx_dv",
"eth_rxd0", "eth_rxd1", "eth_rxd2", "eth_rxd3",
"eth_rgmii_tx_clk", "eth_tx_en",
"eth_txd0", "eth_txd1", "eth_txd2", "eth_txd3",
};
static const char * const hdmi_hpd_groups[] = {
"hdmi_hpd",
};
static const char * const hdmi_i2c_groups[] = {
"hdmi_sda", "hdmi_scl",
};
static const char * const gpio_aobus_groups[] = {
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
"GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
"GPIOAO_10", "GPIOAO_11", "GPIOAO_12", "GPIOAO_13",
"GPIO_TEST_N",
};
static const char * const uart_ao_groups[] = {
"uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a",
};
static const char * const uart_ao_b_groups[] = {
"uart_tx_ao_b", "uart_rx_ao_b", "uart_cts_ao_b", "uart_rts_ao_b",
};
static const char * const i2c_ao_groups[] = {
"i2c_sdk_ao", "i2c_sda_ao",
};
static const char * const i2c_slave_ao_groups[] = {
"i2c_slave_sdk_ao", "i2c_slave_sda_ao",
};
static struct meson_pmx_func meson_gxbb_periphs_functions[] = {
FUNCTION(gpio_periphs),
FUNCTION(emmc),
FUNCTION(sdcard),
FUNCTION(uart_a),
FUNCTION(uart_b),
FUNCTION(uart_c),
FUNCTION(eth),
FUNCTION(hdmi_hpd),
FUNCTION(hdmi_i2c),
};
static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
FUNCTION(gpio_aobus),
FUNCTION(uart_ao),
FUNCTION(uart_ao_b),
FUNCTION(i2c_ao),
FUNCTION(i2c_slave_ao),
};
static struct meson_bank meson_gxbb_periphs_banks[] = {
/* name first last pullen pull dir out in */
BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
};
static struct meson_bank meson_gxbb_aobus_banks[] = {
/* name first last pullen pull dir out in */
BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
.name = "periphs-banks",
.pin_base = 15,
.groups = meson_gxbb_periphs_groups,
.funcs = meson_gxbb_periphs_functions,
.banks = meson_gxbb_periphs_banks,
.num_pins = 119,
.num_groups = ARRAY_SIZE(meson_gxbb_periphs_groups),
.num_funcs = ARRAY_SIZE(meson_gxbb_periphs_functions),
.num_banks = ARRAY_SIZE(meson_gxbb_periphs_banks),
.gpio_driver = &meson_gx_gpio_driver,
};
struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = {
.name = "aobus-banks",
.pin_base = 0,
.groups = meson_gxbb_aobus_groups,
.funcs = meson_gxbb_aobus_functions,
.banks = meson_gxbb_aobus_banks,
.num_pins = 15,
.num_groups = ARRAY_SIZE(meson_gxbb_aobus_groups),
.num_funcs = ARRAY_SIZE(meson_gxbb_aobus_functions),
.num_banks = ARRAY_SIZE(meson_gxbb_aobus_banks),
.gpio_driver = &meson_gx_gpio_driver,
};
static const struct udevice_id meson_gxbb_pinctrl_match[] = {
{
.compatible = "amlogic,meson-gxbb-periphs-pinctrl",
.data = (ulong)&meson_gxbb_periphs_pinctrl_data,
},
{
.compatible = "amlogic,meson-gxbb-aobus-pinctrl",
.data = (ulong)&meson_gxbb_aobus_pinctrl_data,
},
{ /* sentinel */ }
};
U_BOOT_DRIVER(meson_gxbb_pinctrl) = {
.name = "meson-gxbb-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(meson_gxbb_pinctrl_match),
.probe = meson_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct meson_pinctrl),
.ops = &meson_gx_pinctrl_ops,
};
@@ -0,0 +1,739 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
*
* Based on code from Linux kernel:
* Copyright (C) 2016 Endless Mobile, Inc.
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <dt-bindings/gpio/meson-gxl-gpio.h>
#include "pinctrl-meson-gx.h"
#define EE_OFF 11
static const unsigned int emmc_nand_d07_pins[] = {
PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF),
PIN(BOOT_3, EE_OFF), PIN(BOOT_4, EE_OFF), PIN(BOOT_5, EE_OFF),
PIN(BOOT_6, EE_OFF), PIN(BOOT_7, EE_OFF),
};
static const unsigned int emmc_clk_pins[] = { PIN(BOOT_8, EE_OFF) };
static const unsigned int emmc_cmd_pins[] = { PIN(BOOT_10, EE_OFF) };
static const unsigned int emmc_ds_pins[] = { PIN(BOOT_15, EE_OFF) };
static const unsigned int nor_d_pins[] = { PIN(BOOT_11, EE_OFF) };
static const unsigned int nor_q_pins[] = { PIN(BOOT_12, EE_OFF) };
static const unsigned int nor_c_pins[] = { PIN(BOOT_13, EE_OFF) };
static const unsigned int nor_cs_pins[] = { PIN(BOOT_15, EE_OFF) };
static const unsigned int spi_mosi_pins[] = { PIN(GPIOX_8, EE_OFF) };
static const unsigned int spi_miso_pins[] = { PIN(GPIOX_9, EE_OFF) };
static const unsigned int spi_ss0_pins[] = { PIN(GPIOX_10, EE_OFF) };
static const unsigned int spi_sclk_pins[] = { PIN(GPIOX_11, EE_OFF) };
static const unsigned int sdcard_d0_pins[] = { PIN(CARD_1, EE_OFF) };
static const unsigned int sdcard_d1_pins[] = { PIN(CARD_0, EE_OFF) };
static const unsigned int sdcard_d2_pins[] = { PIN(CARD_5, EE_OFF) };
static const unsigned int sdcard_d3_pins[] = { PIN(CARD_4, EE_OFF) };
static const unsigned int sdcard_cmd_pins[] = { PIN(CARD_3, EE_OFF) };
static const unsigned int sdcard_clk_pins[] = { PIN(CARD_2, EE_OFF) };
static const unsigned int sdio_d0_pins[] = { PIN(GPIOX_0, EE_OFF) };
static const unsigned int sdio_d1_pins[] = { PIN(GPIOX_1, EE_OFF) };
static const unsigned int sdio_d2_pins[] = { PIN(GPIOX_2, EE_OFF) };
static const unsigned int sdio_d3_pins[] = { PIN(GPIOX_3, EE_OFF) };
static const unsigned int sdio_cmd_pins[] = { PIN(GPIOX_4, EE_OFF) };
static const unsigned int sdio_clk_pins[] = { PIN(GPIOX_5, EE_OFF) };
static const unsigned int sdio_irq_pins[] = { PIN(GPIOX_7, EE_OFF) };
static const unsigned int nand_ce0_pins[] = { PIN(BOOT_8, EE_OFF) };
static const unsigned int nand_ce1_pins[] = { PIN(BOOT_9, EE_OFF) };
static const unsigned int nand_rb0_pins[] = { PIN(BOOT_10, EE_OFF) };
static const unsigned int nand_ale_pins[] = { PIN(BOOT_11, EE_OFF) };
static const unsigned int nand_cle_pins[] = { PIN(BOOT_12, EE_OFF) };
static const unsigned int nand_wen_clk_pins[] = { PIN(BOOT_13, EE_OFF) };
static const unsigned int nand_ren_wr_pins[] = { PIN(BOOT_14, EE_OFF) };
static const unsigned int nand_dqs_pins[] = { PIN(BOOT_15, EE_OFF) };
static const unsigned int uart_tx_a_pins[] = { PIN(GPIOX_12, EE_OFF) };
static const unsigned int uart_rx_a_pins[] = { PIN(GPIOX_13, EE_OFF) };
static const unsigned int uart_cts_a_pins[] = { PIN(GPIOX_14, EE_OFF) };
static const unsigned int uart_rts_a_pins[] = { PIN(GPIOX_15, EE_OFF) };
static const unsigned int uart_tx_b_pins[] = { PIN(GPIODV_24, EE_OFF) };
static const unsigned int uart_rx_b_pins[] = { PIN(GPIODV_25, EE_OFF) };
static const unsigned int uart_cts_b_pins[] = { PIN(GPIODV_26, EE_OFF) };
static const unsigned int uart_rts_b_pins[] = { PIN(GPIODV_27, EE_OFF) };
static const unsigned int uart_tx_c_pins[] = { PIN(GPIOX_8, EE_OFF) };
static const unsigned int uart_rx_c_pins[] = { PIN(GPIOX_9, EE_OFF) };
static const unsigned int uart_cts_c_pins[] = { PIN(GPIOX_10, EE_OFF) };
static const unsigned int uart_rts_c_pins[] = { PIN(GPIOX_11, EE_OFF) };
static const unsigned int i2c_sck_a_pins[] = { PIN(GPIODV_25, EE_OFF) };
static const unsigned int i2c_sda_a_pins[] = { PIN(GPIODV_24, EE_OFF) };
static const unsigned int i2c_sck_b_pins[] = { PIN(GPIODV_27, EE_OFF) };
static const unsigned int i2c_sda_b_pins[] = { PIN(GPIODV_26, EE_OFF) };
static const unsigned int i2c_sck_c_pins[] = { PIN(GPIODV_29, EE_OFF) };
static const unsigned int i2c_sda_c_pins[] = { PIN(GPIODV_28, EE_OFF) };
static const unsigned int i2c_sck_c_dv19_pins[] = { PIN(GPIODV_19, EE_OFF) };
static const unsigned int i2c_sda_c_dv18_pins[] = { PIN(GPIODV_18, EE_OFF) };
static const unsigned int eth_mdio_pins[] = { PIN(GPIOZ_0, EE_OFF) };
static const unsigned int eth_mdc_pins[] = { PIN(GPIOZ_1, EE_OFF) };
static const unsigned int eth_clk_rx_clk_pins[] = { PIN(GPIOZ_2, EE_OFF) };
static const unsigned int eth_rx_dv_pins[] = { PIN(GPIOZ_3, EE_OFF) };
static const unsigned int eth_rxd0_pins[] = { PIN(GPIOZ_4, EE_OFF) };
static const unsigned int eth_rxd1_pins[] = { PIN(GPIOZ_5, EE_OFF) };
static const unsigned int eth_rxd2_pins[] = { PIN(GPIOZ_6, EE_OFF) };
static const unsigned int eth_rxd3_pins[] = { PIN(GPIOZ_7, EE_OFF) };
static const unsigned int eth_rgmii_tx_clk_pins[] = { PIN(GPIOZ_8, EE_OFF) };
static const unsigned int eth_tx_en_pins[] = { PIN(GPIOZ_9, EE_OFF) };
static const unsigned int eth_txd0_pins[] = { PIN(GPIOZ_10, EE_OFF) };
static const unsigned int eth_txd1_pins[] = { PIN(GPIOZ_11, EE_OFF) };
static const unsigned int eth_txd2_pins[] = { PIN(GPIOZ_12, EE_OFF) };
static const unsigned int eth_txd3_pins[] = { PIN(GPIOZ_13, EE_OFF) };
static const unsigned int pwm_a_pins[] = { PIN(GPIOX_6, EE_OFF) };
static const unsigned int pwm_b_pins[] = { PIN(GPIODV_29, EE_OFF) };
static const unsigned int pwm_c_pins[] = { PIN(GPIOZ_15, EE_OFF) };
static const unsigned int pwm_d_pins[] = { PIN(GPIODV_28, EE_OFF) };
static const unsigned int pwm_e_pins[] = { PIN(GPIOX_16, EE_OFF) };
static const unsigned int pwm_f_clk_pins[] = { PIN(GPIOCLK_1, EE_OFF) };
static const unsigned int pwm_f_x_pins[] = { PIN(GPIOX_7, EE_OFF) };
static const unsigned int hdmi_hpd_pins[] = { PIN(GPIOH_0, EE_OFF) };
static const unsigned int hdmi_sda_pins[] = { PIN(GPIOH_1, EE_OFF) };
static const unsigned int hdmi_scl_pins[] = { PIN(GPIOH_2, EE_OFF) };
static const unsigned int i2s_am_clk_pins[] = { PIN(GPIOH_6, EE_OFF) };
static const unsigned int i2s_out_ao_clk_pins[] = { PIN(GPIOH_7, EE_OFF) };
static const unsigned int i2s_out_lr_clk_pins[] = { PIN(GPIOH_8, EE_OFF) };
static const unsigned int i2s_out_ch01_pins[] = { PIN(GPIOH_9, EE_OFF) };
static const unsigned int i2s_out_ch23_z_pins[] = { PIN(GPIOZ_5, EE_OFF) };
static const unsigned int i2s_out_ch45_z_pins[] = { PIN(GPIOZ_6, EE_OFF) };
static const unsigned int i2s_out_ch67_z_pins[] = { PIN(GPIOZ_7, EE_OFF) };
static const unsigned int spdif_out_h_pins[] = { PIN(GPIOH_4, EE_OFF) };
static const unsigned int eth_link_led_pins[] = { PIN(GPIOZ_14, EE_OFF) };
static const unsigned int eth_act_led_pins[] = { PIN(GPIOZ_15, EE_OFF) };
static const unsigned int tsin_a_d0_pins[] = { PIN(GPIODV_0, EE_OFF) };
static const unsigned int tsin_a_d0_x_pins[] = { PIN(GPIOX_10, EE_OFF) };
static const unsigned int tsin_a_clk_pins[] = { PIN(GPIODV_8, EE_OFF) };
static const unsigned int tsin_a_clk_x_pins[] = { PIN(GPIOX_11, EE_OFF) };
static const unsigned int tsin_a_sop_pins[] = { PIN(GPIODV_9, EE_OFF) };
static const unsigned int tsin_a_sop_x_pins[] = { PIN(GPIOX_8, EE_OFF) };
static const unsigned int tsin_a_d_valid_pins[] = { PIN(GPIODV_10, EE_OFF) };
static const unsigned int tsin_a_d_valid_x_pins[] = { PIN(GPIOX_9, EE_OFF) };
static const unsigned int tsin_a_fail_pins[] = { PIN(GPIODV_11, EE_OFF) };
static const unsigned int tsin_a_dp_pins[] = {
PIN(GPIODV_1, EE_OFF),
PIN(GPIODV_2, EE_OFF),
PIN(GPIODV_3, EE_OFF),
PIN(GPIODV_4, EE_OFF),
PIN(GPIODV_5, EE_OFF),
PIN(GPIODV_6, EE_OFF),
PIN(GPIODV_7, EE_OFF),
};
static const unsigned int uart_tx_ao_a_pins[] = { PIN(GPIOAO_0, 0) };
static const unsigned int uart_rx_ao_a_pins[] = { PIN(GPIOAO_1, 0) };
static const unsigned int uart_tx_ao_b_0_pins[] = { PIN(GPIOAO_0, 0) };
static const unsigned int uart_rx_ao_b_1_pins[] = { PIN(GPIOAO_1, 0) };
static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) };
static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_4, 0) };
static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_5, 0) };
static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) };
static const unsigned int i2c_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
static const unsigned int i2c_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
static const unsigned int i2c_slave_sck_ao_pins[] = {PIN(GPIOAO_4, 0) };
static const unsigned int i2c_slave_sda_ao_pins[] = {PIN(GPIOAO_5, 0) };
static const unsigned int remote_input_ao_pins[] = {PIN(GPIOAO_7, 0) };
static const unsigned int pwm_ao_a_3_pins[] = { PIN(GPIOAO_3, 0) };
static const unsigned int pwm_ao_a_8_pins[] = { PIN(GPIOAO_8, 0) };
static const unsigned int pwm_ao_b_pins[] = { PIN(GPIOAO_9, 0) };
static const unsigned int pwm_ao_b_6_pins[] = { PIN(GPIOAO_6, 0) };
static const unsigned int i2s_out_ch23_ao_pins[] = { PIN(GPIOAO_8, 0) };
static const unsigned int i2s_out_ch45_ao_pins[] = { PIN(GPIOAO_9, 0) };
static const unsigned int spdif_out_ao_6_pins[] = { PIN(GPIOAO_6, 0) };
static const unsigned int spdif_out_ao_9_pins[] = { PIN(GPIOAO_9, 0) };
static const unsigned int ao_cec_pins[] = { PIN(GPIOAO_8, 0) };
static const unsigned int ee_cec_pins[] = { PIN(GPIOAO_8, 0) };
static struct meson_pmx_group meson_gxl_periphs_groups[] = {
GPIO_GROUP(GPIOZ_0, EE_OFF),
GPIO_GROUP(GPIOZ_1, EE_OFF),
GPIO_GROUP(GPIOZ_2, EE_OFF),
GPIO_GROUP(GPIOZ_3, EE_OFF),
GPIO_GROUP(GPIOZ_4, EE_OFF),
GPIO_GROUP(GPIOZ_5, EE_OFF),
GPIO_GROUP(GPIOZ_6, EE_OFF),
GPIO_GROUP(GPIOZ_7, EE_OFF),
GPIO_GROUP(GPIOZ_8, EE_OFF),
GPIO_GROUP(GPIOZ_9, EE_OFF),
GPIO_GROUP(GPIOZ_10, EE_OFF),
GPIO_GROUP(GPIOZ_11, EE_OFF),
GPIO_GROUP(GPIOZ_12, EE_OFF),
GPIO_GROUP(GPIOZ_13, EE_OFF),
GPIO_GROUP(GPIOZ_14, EE_OFF),
GPIO_GROUP(GPIOZ_15, EE_OFF),
GPIO_GROUP(GPIOH_0, EE_OFF),
GPIO_GROUP(GPIOH_1, EE_OFF),
GPIO_GROUP(GPIOH_2, EE_OFF),
GPIO_GROUP(GPIOH_3, EE_OFF),
GPIO_GROUP(GPIOH_4, EE_OFF),
GPIO_GROUP(GPIOH_5, EE_OFF),
GPIO_GROUP(GPIOH_6, EE_OFF),
GPIO_GROUP(GPIOH_7, EE_OFF),
GPIO_GROUP(GPIOH_8, EE_OFF),
GPIO_GROUP(GPIOH_9, EE_OFF),
GPIO_GROUP(BOOT_0, EE_OFF),
GPIO_GROUP(BOOT_1, EE_OFF),
GPIO_GROUP(BOOT_2, EE_OFF),
GPIO_GROUP(BOOT_3, EE_OFF),
GPIO_GROUP(BOOT_4, EE_OFF),
GPIO_GROUP(BOOT_5, EE_OFF),
GPIO_GROUP(BOOT_6, EE_OFF),
GPIO_GROUP(BOOT_7, EE_OFF),
GPIO_GROUP(BOOT_8, EE_OFF),
GPIO_GROUP(BOOT_9, EE_OFF),
GPIO_GROUP(BOOT_10, EE_OFF),
GPIO_GROUP(BOOT_11, EE_OFF),
GPIO_GROUP(BOOT_12, EE_OFF),
GPIO_GROUP(BOOT_13, EE_OFF),
GPIO_GROUP(BOOT_14, EE_OFF),
GPIO_GROUP(BOOT_15, EE_OFF),
GPIO_GROUP(CARD_0, EE_OFF),
GPIO_GROUP(CARD_1, EE_OFF),
GPIO_GROUP(CARD_2, EE_OFF),
GPIO_GROUP(CARD_3, EE_OFF),
GPIO_GROUP(CARD_4, EE_OFF),
GPIO_GROUP(CARD_5, EE_OFF),
GPIO_GROUP(CARD_6, EE_OFF),
GPIO_GROUP(GPIODV_0, EE_OFF),
GPIO_GROUP(GPIODV_1, EE_OFF),
GPIO_GROUP(GPIODV_2, EE_OFF),
GPIO_GROUP(GPIODV_3, EE_OFF),
GPIO_GROUP(GPIODV_4, EE_OFF),
GPIO_GROUP(GPIODV_5, EE_OFF),
GPIO_GROUP(GPIODV_6, EE_OFF),
GPIO_GROUP(GPIODV_7, EE_OFF),
GPIO_GROUP(GPIODV_8, EE_OFF),
GPIO_GROUP(GPIODV_9, EE_OFF),
GPIO_GROUP(GPIODV_10, EE_OFF),
GPIO_GROUP(GPIODV_11, EE_OFF),
GPIO_GROUP(GPIODV_12, EE_OFF),
GPIO_GROUP(GPIODV_13, EE_OFF),
GPIO_GROUP(GPIODV_14, EE_OFF),
GPIO_GROUP(GPIODV_15, EE_OFF),
GPIO_GROUP(GPIODV_16, EE_OFF),
GPIO_GROUP(GPIODV_17, EE_OFF),
GPIO_GROUP(GPIODV_18, EE_OFF),
GPIO_GROUP(GPIODV_19, EE_OFF),
GPIO_GROUP(GPIODV_20, EE_OFF),
GPIO_GROUP(GPIODV_21, EE_OFF),
GPIO_GROUP(GPIODV_22, EE_OFF),
GPIO_GROUP(GPIODV_23, EE_OFF),
GPIO_GROUP(GPIODV_24, EE_OFF),
GPIO_GROUP(GPIODV_25, EE_OFF),
GPIO_GROUP(GPIODV_26, EE_OFF),
GPIO_GROUP(GPIODV_27, EE_OFF),
GPIO_GROUP(GPIODV_28, EE_OFF),
GPIO_GROUP(GPIODV_29, EE_OFF),
GPIO_GROUP(GPIOX_0, EE_OFF),
GPIO_GROUP(GPIOX_1, EE_OFF),
GPIO_GROUP(GPIOX_2, EE_OFF),
GPIO_GROUP(GPIOX_3, EE_OFF),
GPIO_GROUP(GPIOX_4, EE_OFF),
GPIO_GROUP(GPIOX_5, EE_OFF),
GPIO_GROUP(GPIOX_6, EE_OFF),
GPIO_GROUP(GPIOX_7, EE_OFF),
GPIO_GROUP(GPIOX_8, EE_OFF),
GPIO_GROUP(GPIOX_9, EE_OFF),
GPIO_GROUP(GPIOX_10, EE_OFF),
GPIO_GROUP(GPIOX_11, EE_OFF),
GPIO_GROUP(GPIOX_12, EE_OFF),
GPIO_GROUP(GPIOX_13, EE_OFF),
GPIO_GROUP(GPIOX_14, EE_OFF),
GPIO_GROUP(GPIOX_15, EE_OFF),
GPIO_GROUP(GPIOX_16, EE_OFF),
GPIO_GROUP(GPIOX_17, EE_OFF),
GPIO_GROUP(GPIOX_18, EE_OFF),
GPIO_GROUP(GPIOCLK_0, EE_OFF),
GPIO_GROUP(GPIOCLK_1, EE_OFF),
/* Bank X */
GROUP(sdio_d0, 5, 31),
GROUP(sdio_d1, 5, 30),
GROUP(sdio_d2, 5, 29),
GROUP(sdio_d3, 5, 28),
GROUP(sdio_clk, 5, 27),
GROUP(sdio_cmd, 5, 26),
GROUP(sdio_irq, 5, 24),
GROUP(uart_tx_a, 5, 19),
GROUP(uart_rx_a, 5, 18),
GROUP(uart_cts_a, 5, 17),
GROUP(uart_rts_a, 5, 16),
GROUP(uart_tx_c, 5, 13),
GROUP(uart_rx_c, 5, 12),
GROUP(uart_cts_c, 5, 11),
GROUP(uart_rts_c, 5, 10),
GROUP(pwm_a, 5, 25),
GROUP(pwm_e, 5, 15),
GROUP(pwm_f_x, 5, 14),
GROUP(spi_mosi, 5, 3),
GROUP(spi_miso, 5, 2),
GROUP(spi_ss0, 5, 1),
GROUP(spi_sclk, 5, 0),
GROUP(tsin_a_sop_x, 6, 3),
GROUP(tsin_a_d_valid_x, 6, 2),
GROUP(tsin_a_d0_x, 6, 1),
GROUP(tsin_a_clk_x, 6, 0),
/* Bank Z */
GROUP(eth_mdio, 4, 23),
GROUP(eth_mdc, 4, 22),
GROUP(eth_clk_rx_clk, 4, 21),
GROUP(eth_rx_dv, 4, 20),
GROUP(eth_rxd0, 4, 19),
GROUP(eth_rxd1, 4, 18),
GROUP(eth_rxd2, 4, 17),
GROUP(eth_rxd3, 4, 16),
GROUP(eth_rgmii_tx_clk, 4, 15),
GROUP(eth_tx_en, 4, 14),
GROUP(eth_txd0, 4, 13),
GROUP(eth_txd1, 4, 12),
GROUP(eth_txd2, 4, 11),
GROUP(eth_txd3, 4, 10),
GROUP(pwm_c, 3, 20),
GROUP(i2s_out_ch23_z, 3, 26),
GROUP(i2s_out_ch45_z, 3, 25),
GROUP(i2s_out_ch67_z, 3, 24),
GROUP(eth_link_led, 4, 25),
GROUP(eth_act_led, 4, 24),
/* Bank H */
GROUP(hdmi_hpd, 6, 31),
GROUP(hdmi_sda, 6, 30),
GROUP(hdmi_scl, 6, 29),
GROUP(i2s_am_clk, 6, 26),
GROUP(i2s_out_ao_clk, 6, 25),
GROUP(i2s_out_lr_clk, 6, 24),
GROUP(i2s_out_ch01, 6, 23),
GROUP(spdif_out_h, 6, 28),
/* Bank DV */
GROUP(uart_tx_b, 2, 16),
GROUP(uart_rx_b, 2, 15),
GROUP(uart_cts_b, 2, 14),
GROUP(uart_rts_b, 2, 13),
GROUP(i2c_sda_c_dv18, 1, 17),
GROUP(i2c_sck_c_dv19, 1, 16),
GROUP(i2c_sda_a, 1, 15),
GROUP(i2c_sck_a, 1, 14),
GROUP(i2c_sda_b, 1, 13),
GROUP(i2c_sck_b, 1, 12),
GROUP(i2c_sda_c, 1, 11),
GROUP(i2c_sck_c, 1, 10),
GROUP(pwm_b, 2, 11),
GROUP(pwm_d, 2, 12),
GROUP(tsin_a_d0, 2, 4),
GROUP(tsin_a_dp, 2, 3),
GROUP(tsin_a_clk, 2, 2),
GROUP(tsin_a_sop, 2, 1),
GROUP(tsin_a_d_valid, 2, 0),
GROUP(tsin_a_fail, 1, 31),
/* Bank BOOT */
GROUP(emmc_nand_d07, 7, 31),
GROUP(emmc_clk, 7, 30),
GROUP(emmc_cmd, 7, 29),
GROUP(emmc_ds, 7, 28),
GROUP(nor_d, 7, 13),
GROUP(nor_q, 7, 12),
GROUP(nor_c, 7, 11),
GROUP(nor_cs, 7, 10),
GROUP(nand_ce0, 7, 7),
GROUP(nand_ce1, 7, 6),
GROUP(nand_rb0, 7, 5),
GROUP(nand_ale, 7, 4),
GROUP(nand_cle, 7, 3),
GROUP(nand_wen_clk, 7, 2),
GROUP(nand_ren_wr, 7, 1),
GROUP(nand_dqs, 7, 0),
/* Bank CARD */
GROUP(sdcard_d1, 6, 5),
GROUP(sdcard_d0, 6, 4),
GROUP(sdcard_d3, 6, 1),
GROUP(sdcard_d2, 6, 0),
GROUP(sdcard_cmd, 6, 2),
GROUP(sdcard_clk, 6, 3),
/* Bank CLK */
GROUP(pwm_f_clk, 8, 30),
};
static struct meson_pmx_group meson_gxl_aobus_groups[] = {
GPIO_GROUP(GPIOAO_0, 0),
GPIO_GROUP(GPIOAO_1, 0),
GPIO_GROUP(GPIOAO_2, 0),
GPIO_GROUP(GPIOAO_3, 0),
GPIO_GROUP(GPIOAO_4, 0),
GPIO_GROUP(GPIOAO_5, 0),
GPIO_GROUP(GPIOAO_6, 0),
GPIO_GROUP(GPIOAO_7, 0),
GPIO_GROUP(GPIOAO_8, 0),
GPIO_GROUP(GPIOAO_9, 0),
GPIO_GROUP(GPIO_TEST_N, 0),
/* bank AO */
GROUP(uart_tx_ao_b_0, 0, 26),
GROUP(uart_rx_ao_b_1, 0, 25),
GROUP(uart_tx_ao_b, 0, 24),
GROUP(uart_rx_ao_b, 0, 23),
GROUP(uart_tx_ao_a, 0, 12),
GROUP(uart_rx_ao_a, 0, 11),
GROUP(uart_cts_ao_a, 0, 10),
GROUP(uart_rts_ao_a, 0, 9),
GROUP(uart_cts_ao_b, 0, 8),
GROUP(uart_rts_ao_b, 0, 7),
GROUP(i2c_sck_ao, 0, 6),
GROUP(i2c_sda_ao, 0, 5),
GROUP(i2c_slave_sck_ao, 0, 2),
GROUP(i2c_slave_sda_ao, 0, 1),
GROUP(remote_input_ao, 0, 0),
GROUP(pwm_ao_a_3, 0, 22),
GROUP(pwm_ao_b_6, 0, 18),
GROUP(pwm_ao_a_8, 0, 17),
GROUP(pwm_ao_b, 0, 3),
GROUP(i2s_out_ch23_ao, 1, 0),
GROUP(i2s_out_ch45_ao, 1, 1),
GROUP(spdif_out_ao_6, 0, 16),
GROUP(spdif_out_ao_9, 0, 4),
GROUP(ao_cec, 0, 15),
GROUP(ee_cec, 0, 14),
};
static const char * const gpio_periphs_groups[] = {
"GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4",
"GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9",
"GPIOZ_10", "GPIOZ_11", "GPIOZ_12", "GPIOZ_13", "GPIOZ_14",
"GPIOZ_15",
"GPIOH_0", "GPIOH_1", "GPIOH_2", "GPIOH_3", "GPIOH_4",
"GPIOH_5", "GPIOH_6", "GPIOH_7", "GPIOH_8", "GPIOH_9",
"BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4",
"BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9",
"BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
"BOOT_15",
"CARD_0", "CARD_1", "CARD_2", "CARD_3", "CARD_4",
"CARD_5", "CARD_6",
"GPIODV_0", "GPIODV_1", "GPIODV_2", "GPIODV_3", "GPIODV_4",
"GPIODV_5", "GPIODV_6", "GPIODV_7", "GPIODV_8", "GPIODV_9",
"GPIODV_10", "GPIODV_11", "GPIODV_12", "GPIODV_13", "GPIODV_14",
"GPIODV_15", "GPIODV_16", "GPIODV_17", "GPIODV_18", "GPIODV_19",
"GPIODV_20", "GPIODV_21", "GPIODV_22", "GPIODV_23", "GPIODV_24",
"GPIODV_25", "GPIODV_26", "GPIODV_27", "GPIODV_28", "GPIODV_29",
"GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
"GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
"GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
"GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18",
"GPIOCLK_0", "GPIOCLK_1",
};
static const char * const emmc_groups[] = {
"emmc_nand_d07", "emmc_clk", "emmc_cmd", "emmc_ds",
};
static const char * const nor_groups[] = {
"nor_d", "nor_q", "nor_c", "nor_cs",
};
static const char * const spi_groups[] = {
"spi_mosi", "spi_miso", "spi_ss0", "spi_sclk",
};
static const char * const sdcard_groups[] = {
"sdcard_d0", "sdcard_d1", "sdcard_d2", "sdcard_d3",
"sdcard_cmd", "sdcard_clk",
};
static const char * const sdio_groups[] = {
"sdio_d0", "sdio_d1", "sdio_d2", "sdio_d3",
"sdio_cmd", "sdio_clk", "sdio_irq",
};
static const char * const nand_groups[] = {
"nand_ce0", "nand_ce1", "nand_rb0", "nand_ale", "nand_cle",
"nand_wen_clk", "nand_ren_wr", "nand_dqs",
};
static const char * const uart_a_groups[] = {
"uart_tx_a", "uart_rx_a", "uart_cts_a", "uart_rts_a",
};
static const char * const uart_b_groups[] = {
"uart_tx_b", "uart_rx_b", "uart_cts_b", "uart_rts_b",
};
static const char * const uart_c_groups[] = {
"uart_tx_c", "uart_rx_c", "uart_cts_c", "uart_rts_c",
};
static const char * const i2c_a_groups[] = {
"i2c_sck_a", "i2c_sda_a",
};
static const char * const i2c_b_groups[] = {
"i2c_sck_b", "i2c_sda_b",
};
static const char * const i2c_c_groups[] = {
"i2c_sck_c", "i2c_sda_c", "i2c_sda_c_dv18", "i2c_sck_c_dv19",
};
static const char * const eth_groups[] = {
"eth_mdio", "eth_mdc", "eth_clk_rx_clk", "eth_rx_dv",
"eth_rxd0", "eth_rxd1", "eth_rxd2", "eth_rxd3",
"eth_rgmii_tx_clk", "eth_tx_en",
"eth_txd0", "eth_txd1", "eth_txd2", "eth_txd3",
};
static const char * const pwm_a_groups[] = {
"pwm_a",
};
static const char * const pwm_b_groups[] = {
"pwm_b",
};
static const char * const pwm_c_groups[] = {
"pwm_c",
};
static const char * const pwm_d_groups[] = {
"pwm_d",
};
static const char * const pwm_e_groups[] = {
"pwm_e",
};
static const char * const pwm_f_groups[] = {
"pwm_f_clk", "pwm_f_x",
};
static const char * const hdmi_hpd_groups[] = {
"hdmi_hpd",
};
static const char * const hdmi_i2c_groups[] = {
"hdmi_sda", "hdmi_scl",
};
static const char * const i2s_out_groups[] = {
"i2s_am_clk", "i2s_out_ao_clk", "i2s_out_lr_clk",
"i2s_out_ch01", "i2s_out_ch23_z", "i2s_out_ch45_z", "i2s_out_ch67_z",
};
static const char * const spdif_out_groups[] = {
"spdif_out_h",
};
static const char * const eth_led_groups[] = {
"eth_link_led", "eth_act_led",
};
static const char * const tsin_a_groups[] = {
"tsin_a_clk", "tsin_a_clk_x", "tsin_a_sop", "tsin_a_sop_x",
"tsin_a_d_valid", "tsin_a_d_valid_x", "tsin_a_d0", "tsin_a_d0_x",
"tsin_a_dp", "tsin_a_fail",
};
static const char * const gpio_aobus_groups[] = {
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
"GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
"GPIO_TEST_N",
};
static const char * const uart_ao_groups[] = {
"uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a",
};
static const char * const uart_ao_b_groups[] = {
"uart_tx_ao_b", "uart_rx_ao_b", "uart_cts_ao_b", "uart_rts_ao_b",
"uart_tx_ao_b_0", "uart_rx_ao_b_1",
};
static const char * const i2c_ao_groups[] = {
"i2c_sck_ao", "i2c_sda_ao",
};
static const char * const i2c_slave_ao_groups[] = {
"i2c_slave_sck_ao", "i2c_slave_sda_ao",
};
static const char * const remote_input_ao_groups[] = {
"remote_input_ao",
};
static const char * const pwm_ao_a_groups[] = {
"pwm_ao_a_3", "pwm_ao_a_8",
};
static const char * const pwm_ao_b_groups[] = {
"pwm_ao_b", "pwm_ao_b_6",
};
static const char * const i2s_out_ao_groups[] = {
"i2s_out_ch23_ao", "i2s_out_ch45_ao",
};
static const char * const spdif_out_ao_groups[] = {
"spdif_out_ao_6", "spdif_out_ao_9",
};
static const char * const cec_ao_groups[] = {
"ao_cec", "ee_cec",
};
static struct meson_pmx_func meson_gxl_periphs_functions[] = {
FUNCTION(gpio_periphs),
FUNCTION(emmc),
FUNCTION(nor),
FUNCTION(spi),
FUNCTION(sdcard),
FUNCTION(sdio),
FUNCTION(nand),
FUNCTION(uart_a),
FUNCTION(uart_b),
FUNCTION(uart_c),
FUNCTION(i2c_a),
FUNCTION(i2c_b),
FUNCTION(i2c_c),
FUNCTION(eth),
FUNCTION(pwm_a),
FUNCTION(pwm_b),
FUNCTION(pwm_c),
FUNCTION(pwm_d),
FUNCTION(pwm_e),
FUNCTION(pwm_f),
FUNCTION(hdmi_hpd),
FUNCTION(hdmi_i2c),
FUNCTION(i2s_out),
FUNCTION(spdif_out),
FUNCTION(eth_led),
FUNCTION(tsin_a),
};
static struct meson_pmx_func meson_gxl_aobus_functions[] = {
FUNCTION(gpio_aobus),
FUNCTION(uart_ao),
FUNCTION(uart_ao_b),
FUNCTION(i2c_ao),
FUNCTION(i2c_slave_ao),
FUNCTION(remote_input_ao),
FUNCTION(pwm_ao_a),
FUNCTION(pwm_ao_b),
FUNCTION(i2s_out_ao),
FUNCTION(spdif_out_ao),
FUNCTION(cec_ao),
};
static struct meson_bank meson_gxl_periphs_banks[] = {
/* name first last pullen pull dir out in */
BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_18, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_9, EE_OFF), 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_15, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_1, EE_OFF), 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
};
static struct meson_bank meson_gxl_aobus_banks[] = {
/* name first last pullen pull dir out in */
BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_9, 0), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data = {
.name = "periphs-banks",
.pin_base = 11,
.groups = meson_gxl_periphs_groups,
.funcs = meson_gxl_periphs_functions,
.banks = meson_gxl_periphs_banks,
.num_pins = 100,
.num_groups = ARRAY_SIZE(meson_gxl_periphs_groups),
.num_funcs = ARRAY_SIZE(meson_gxl_periphs_functions),
.num_banks = ARRAY_SIZE(meson_gxl_periphs_banks),
.gpio_driver = &meson_gx_gpio_driver,
};
struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data = {
.name = "aobus-banks",
.pin_base = 0,
.groups = meson_gxl_aobus_groups,
.funcs = meson_gxl_aobus_functions,
.banks = meson_gxl_aobus_banks,
.num_pins = 11,
.num_groups = ARRAY_SIZE(meson_gxl_aobus_groups),
.num_funcs = ARRAY_SIZE(meson_gxl_aobus_functions),
.num_banks = ARRAY_SIZE(meson_gxl_aobus_banks),
.gpio_driver = &meson_gx_gpio_driver,
};
static const struct udevice_id meson_gxl_pinctrl_match[] = {
{
.compatible = "amlogic,meson-gxl-periphs-pinctrl",
.data = (ulong)&meson_gxl_periphs_pinctrl_data,
},
{
.compatible = "amlogic,meson-gxl-aobus-pinctrl",
.data = (ulong)&meson_gxl_aobus_pinctrl_data,
},
{ /* sentinel */ }
};
U_BOOT_DRIVER(meson_gxl_pinctrl) = {
.name = "meson-gxl-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(meson_gxl_pinctrl_match),
.probe = meson_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct meson_pinctrl),
.ops = &meson_gx_pinctrl_ops,
};
@@ -0,0 +1,421 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <fdt_support.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include <asm/gpio.h>
#include "pinctrl-meson.h"
DECLARE_GLOBAL_DATA_PTR;
static const char *meson_pinctrl_dummy_name = "_dummy";
static char pin_name[PINNAME_SIZE];
int meson_pinctrl_get_groups_count(struct udevice *dev)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
return priv->data->num_groups;
}
const char *meson_pinctrl_get_group_name(struct udevice *dev,
unsigned int selector)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
if (!priv->data->groups[selector].name)
return meson_pinctrl_dummy_name;
return priv->data->groups[selector].name;
}
int meson_pinctrl_get_pins_count(struct udevice *dev)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
return priv->data->num_pins;
}
const char *meson_pinctrl_get_pin_name(struct udevice *dev,
unsigned int selector)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
if (selector > priv->data->num_pins ||
selector > priv->data->funcs[0].num_groups)
snprintf(pin_name, PINNAME_SIZE, "Error");
else
snprintf(pin_name, PINNAME_SIZE, "%s",
priv->data->funcs[0].groups[selector]);
return pin_name;
}
int meson_pinmux_get_functions_count(struct udevice *dev)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
return priv->data->num_funcs;
}
const char *meson_pinmux_get_function_name(struct udevice *dev,
unsigned int selector)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
return priv->data->funcs[selector].name;
}
static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset,
enum meson_reg_type reg_type,
unsigned int *reg, unsigned int *bit)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
struct meson_bank *bank = NULL;
struct meson_reg_desc *desc;
unsigned int pin;
int i;
pin = priv->data->pin_base + offset;
for (i = 0; i < priv->data->num_banks; i++) {
if (pin >= priv->data->banks[i].first &&
pin <= priv->data->banks[i].last) {
bank = &priv->data->banks[i];
break;
}
}
if (!bank)
return -EINVAL;
desc = &bank->regs[reg_type];
*reg = desc->reg * 4;
*bit = desc->bit + pin - bank->first;
return 0;
}
int meson_gpio_get(struct udevice *dev, unsigned int offset)
{
struct meson_pinctrl *priv = dev_get_priv(dev->parent);
unsigned int reg, bit;
int ret;
ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, &reg,
&bit);
if (ret)
return ret;
return !!(readl(priv->reg_gpio + reg) & BIT(bit));
}
int meson_gpio_set(struct udevice *dev, unsigned int offset, int value)
{
struct meson_pinctrl *priv = dev_get_priv(dev->parent);
unsigned int reg, bit;
int ret;
ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
&bit);
if (ret)
return ret;
clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
return 0;
}
int meson_gpio_get_direction(struct udevice *dev, unsigned int offset)
{
struct meson_pinctrl *priv = dev_get_priv(dev->parent);
unsigned int reg, bit, val;
int ret;
ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
&bit);
if (ret)
return ret;
val = readl(priv->reg_gpio + reg);
return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT;
}
int meson_gpio_direction_input(struct udevice *dev, unsigned int offset)
{
struct meson_pinctrl *priv = dev_get_priv(dev->parent);
unsigned int reg, bit;
int ret;
ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
&bit);
if (ret)
return ret;
setbits_le32(priv->reg_gpio + reg, BIT(bit));
return 0;
}
int meson_gpio_direction_output(struct udevice *dev,
unsigned int offset, int value)
{
struct meson_pinctrl *priv = dev_get_priv(dev->parent);
unsigned int reg, bit;
int ret;
ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
&bit);
if (ret)
return ret;
clrbits_le32(priv->reg_gpio + reg, BIT(bit));
ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
&bit);
if (ret)
return ret;
clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
return 0;
}
static int meson_pinconf_bias_set(struct udevice *dev, unsigned int pin,
unsigned int param)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
unsigned int offset = pin - priv->data->pin_base;
unsigned int reg, bit;
int ret;
ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULLEN, &reg, &bit);
if (ret)
return ret;
if (param == PIN_CONFIG_BIAS_DISABLE) {
clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 0);
return 0;
}
/* othewise, enable the bias and select level */
clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 1);
ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULL, &reg, &bit);
if (ret)
return ret;
clrsetbits_le32(priv->reg_pull + reg, BIT(bit),
param == PIN_CONFIG_BIAS_PULL_UP);
return 0;
}
static int meson_pinconf_drive_strength_set(struct udevice *dev,
unsigned int pin,
unsigned int drive_strength_ua)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
unsigned int offset = pin - priv->data->pin_base;
unsigned int reg, bit;
unsigned int ds_val;
int ret;
if (!priv->reg_ds) {
dev_err(dev, "drive-strength-microamp not supported\n");
return -ENOTSUPP;
}
ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DS, &reg, &bit);
if (ret)
return ret;
bit = bit << 1;
if (drive_strength_ua <= 500) {
ds_val = MESON_PINCONF_DRV_500UA;
} else if (drive_strength_ua <= 2500) {
ds_val = MESON_PINCONF_DRV_2500UA;
} else if (drive_strength_ua <= 3000) {
ds_val = MESON_PINCONF_DRV_3000UA;
} else if (drive_strength_ua <= 4000) {
ds_val = MESON_PINCONF_DRV_4000UA;
} else {
dev_warn(dev,
"pin %u: invalid drive-strength-microamp : %d , default to 4mA\n",
pin, drive_strength_ua);
ds_val = MESON_PINCONF_DRV_4000UA;
}
clrsetbits_le32(priv->reg_ds + reg, 0x3 << bit, ds_val << bit);
return 0;
}
int meson_pinconf_set(struct udevice *dev, unsigned int pin,
unsigned int param, unsigned int arg)
{
int ret;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
ret = meson_pinconf_bias_set(dev, pin, param);
break;
case PIN_CONFIG_DRIVE_STRENGTH_UA:
ret = meson_pinconf_drive_strength_set(dev, pin, arg);
break;
default:
dev_err(dev, "unsupported configuration parameter %u\n", param);
return -EINVAL;
}
return ret;
}
int meson_pinconf_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int param, unsigned int arg)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
struct meson_pmx_group *grp = &priv->data->groups[group_selector];
int i, ret;
for (i = 0; i < grp->num_pins; i++) {
ret = meson_pinconf_set(dev, grp->pins[i], param, arg);
if (ret)
return ret;
}
return 0;
}
int meson_gpio_probe(struct udevice *dev)
{
struct meson_pinctrl *priv = dev_get_priv(dev->parent);
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = priv->data->name;
uc_priv->gpio_count = priv->data->num_pins;
return 0;
}
static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
{
int index, len = 0;
const fdt32_t *reg;
index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name);
if (index < 0)
return FDT_ADDR_T_NONE;
reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
return FDT_ADDR_T_NONE;
reg += index * (na + ns);
return fdt_translate_address((void *)gd->fdt_blob, offset, reg);
}
int meson_pinctrl_probe(struct udevice *dev)
{
struct meson_pinctrl *priv = dev_get_priv(dev);
struct uclass_driver *drv;
struct udevice *gpio_dev;
fdt_addr_t addr;
int node, gpio = -1, len;
int na, ns;
char *name;
na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent));
if (na < 1) {
debug("bad #address-cells\n");
return -EINVAL;
}
ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
if (ns < 1) {
debug("bad #size-cells\n");
return -EINVAL;
}
fdt_for_each_subnode(node, gd->fdt_blob, dev_of_offset(dev)) {
if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) {
gpio = node;
break;
}
}
if (!gpio) {
debug("gpio node not found\n");
return -EINVAL;
}
addr = parse_address(gpio, "mux", na, ns);
if (addr == FDT_ADDR_T_NONE) {
debug("mux address not found\n");
return -EINVAL;
}
priv->reg_mux = (void __iomem *)addr;
addr = parse_address(gpio, "gpio", na, ns);
if (addr == FDT_ADDR_T_NONE) {
debug("gpio address not found\n");
return -EINVAL;
}
priv->reg_gpio = (void __iomem *)addr;
addr = parse_address(gpio, "pull", na, ns);
/* Use gpio region if pull one is not present */
if (addr == FDT_ADDR_T_NONE)
priv->reg_pull = priv->reg_gpio;
else
priv->reg_pull = (void __iomem *)addr;
addr = parse_address(gpio, "pull-enable", na, ns);
/* Use pull region if pull-enable one is not present */
if (addr == FDT_ADDR_T_NONE)
priv->reg_pullen = priv->reg_pull;
else
priv->reg_pullen = (void __iomem *)addr;
addr = parse_address(gpio, "ds", na, ns);
/* Drive strength region is optional */
if (addr == FDT_ADDR_T_NONE)
priv->reg_ds = NULL;
else
priv->reg_ds = (void __iomem *)addr;
priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev);
/* Lookup GPIO driver */
drv = lists_uclass_lookup(UCLASS_GPIO);
if (!drv) {
puts("Cannot find GPIO driver\n");
return -ENOENT;
}
name = calloc(1, 32);
sprintf(name, "meson-gpio");
/* Create child device UCLASS_GPIO and bind it */
device_bind(dev, priv->data->gpio_driver, name, NULL, gpio, &gpio_dev);
dev_set_of_offset(gpio_dev, gpio);
return 0;
}
@@ -0,0 +1,161 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
*/
#ifndef __PINCTRL_MESON_H__
#define __PINCTRL_MESON_H__
#include <linux/types.h>
struct meson_pmx_group {
const char *name;
const unsigned int *pins;
unsigned int num_pins;
const void *data;
};
struct meson_pmx_func {
const char *name;
const char * const *groups;
unsigned int num_groups;
};
struct meson_pinctrl_data {
const char *name;
struct meson_pmx_group *groups;
struct meson_pmx_func *funcs;
struct meson_bank *banks;
unsigned int pin_base;
unsigned int num_pins;
unsigned int num_groups;
unsigned int num_funcs;
unsigned int num_banks;
const struct driver *gpio_driver;
void *pmx_data;
};
struct meson_pinctrl {
struct meson_pinctrl_data *data;
void __iomem *reg_mux;
void __iomem *reg_gpio;
void __iomem *reg_pull;
void __iomem *reg_pullen;
void __iomem *reg_ds;
};
/**
* struct meson_reg_desc - a register descriptor
*
* @reg: register offset in the regmap
* @bit: bit index in register
*
* The structure describes the information needed to control pull,
* pull-enable, direction, etc. for a single pin
*/
struct meson_reg_desc {
unsigned int reg;
unsigned int bit;
};
/**
* enum meson_pinconf_drv - value of drive-strength supported
*/
enum meson_pinconf_drv {
MESON_PINCONF_DRV_500UA,
MESON_PINCONF_DRV_2500UA,
MESON_PINCONF_DRV_3000UA,
MESON_PINCONF_DRV_4000UA,
};
/**
* enum meson_reg_type - type of registers encoded in @meson_reg_desc
*/
enum meson_reg_type {
REG_PULLEN,
REG_PULL,
REG_DIR,
REG_OUT,
REG_IN,
REG_DS,
NUM_REG,
};
/**
* struct meson bank
*
* @name: bank name
* @first: first pin of the bank
* @last: last pin of the bank
* @regs: array of register descriptors
*
* A bank represents a set of pins controlled by a contiguous set of
* bits in the domain registers. The structure specifies which bits in
* the regmap control the different functionalities. Each member of
* the @regs array refers to the first pin of the bank.
*/
struct meson_bank {
const char *name;
unsigned int first;
unsigned int last;
struct meson_reg_desc regs[NUM_REG];
};
#define PIN(x, b) (b + x)
#define FUNCTION(fn) \
{ \
.name = #fn, \
.groups = fn ## _groups, \
.num_groups = ARRAY_SIZE(fn ## _groups), \
}
#define BANK_DS(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib, \
dsr, dsb) \
{ \
.name = n, \
.first = f, \
.last = l, \
.regs = { \
[REG_PULLEN] = {per, peb}, \
[REG_PULL] = {pr, pb}, \
[REG_DIR] = {dr, db}, \
[REG_OUT] = { or, ob}, \
[REG_IN] = {ir, ib}, \
[REG_DS] = {dsr, dsb}, \
}, \
}
#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
BANK_DS(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib, 0, 0)
#define MESON_PIN(x, b) PINCTRL_PIN(PIN(x, b), #x)
extern const struct pinctrl_ops meson_pinctrl_ops;
int meson_pinctrl_get_groups_count(struct udevice *dev);
const char *meson_pinctrl_get_group_name(struct udevice *dev,
unsigned int selector);
int meson_pinctrl_get_pins_count(struct udevice *dev);
const char *meson_pinctrl_get_pin_name(struct udevice *dev,
unsigned int selector);
int meson_pinmux_get_functions_count(struct udevice *dev);
const char *meson_pinmux_get_function_name(struct udevice *dev,
unsigned int selector);
int meson_pinctrl_probe(struct udevice *dev);
int meson_gpio_get(struct udevice *dev, unsigned int offset);
int meson_gpio_set(struct udevice *dev, unsigned int offset, int value);
int meson_gpio_get_direction(struct udevice *dev, unsigned int offset);
int meson_gpio_direction_input(struct udevice *dev, unsigned int offset);
int meson_gpio_direction_output(struct udevice *dev, unsigned int offset,
int value);
int meson_gpio_probe(struct udevice *dev);
int meson_pinconf_set(struct udevice *dev, unsigned int pin,
unsigned int param, unsigned int arg);
int meson_pinconf_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int param, unsigned int arg);
#endif /* __PINCTRL_MESON_H__ */
@@ -0,0 +1,50 @@
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
config PINCTRL_MSCC
bool
config PINCTRL_MSCC_OCELOT
depends on SOC_OCELOT && PINCTRL_FULL && OF_CONTROL
select PINCTRL_MSCC
default y
bool "Microsemi ocelot family pin control driver"
help
Support pin multiplexing and pin configuration control on
Microsemi ocelot SoCs.
config PINCTRL_MSCC_LUTON
depends on SOC_LUTON && PINCTRL_FULL && OF_CONTROL
select PINCTRL_MSCC
default y
bool "Microsemi luton family pin control driver"
help
Support pin multiplexing and pin configuration control on
Microsemi luton SoCs.
config PINCTRL_MSCC_JR2
depends on SOC_JR2 && PINCTRL_FULL && OF_CONTROL
select PINCTRL_MSCC
default y
bool "Microsemi jr2 family pin control driver"
help
Support pin multiplexing and pin configuration control on
Microsemi jr2 SoCs.
config PINCTRL_MSCC_SERVALT
depends on SOC_SERVALT && PINCTRL_FULL && OF_CONTROL
select PINCTRL_MSCC
default y
bool "Microsemi servalt family pin control driver"
help
Support pin multiplexing and pin configuration control on
Microsemi servalt SoCs.
config PINCTRL_MSCC_SERVAL
depends on SOC_SERVAL && PINCTRL_FULL && OF_CONTROL
select PINCTRL_MSCC
default y
bool "Microsemi serval family pin control driver"
help
Support pin multiplexing and pin configuration control on
Microsemi serval SoCs.
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
obj-y += mscc-common.o
obj-$(CONFIG_PINCTRL_MSCC_OCELOT) += pinctrl-ocelot.o
obj-$(CONFIG_PINCTRL_MSCC_LUTON) += pinctrl-luton.o
obj-$(CONFIG_PINCTRL_MSCC_JR2) += pinctrl-jr2.o
obj-$(CONFIG_PINCTRL_MSCC_SERVALT) += pinctrl-servalt.o
obj-$(CONFIG_PINCTRL_MSCC_SERVAL) += pinctrl-serval.o
@@ -0,0 +1,274 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi SoCs pinctrl driver
*
* Author: <alexandre.belloni@free-electrons.com>
* Author: <gregory.clement@bootlin.com>
* License: Dual MIT/GPL
* Copyright (c) 2017 Microsemi Corporation
*/
#include <asm/gpio.h>
#include <asm/system.h>
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <errno.h>
#include <fdtdec.h>
#include <linux/io.h>
#include "mscc-common.h"
static void mscc_writel(unsigned int offset, void *addr)
{
if (offset < 32)
writel(BIT(offset), addr);
else
writel(BIT(offset % 32), addr + 4);
}
static unsigned int mscc_readl(unsigned int offset, void *addr)
{
if (offset < 32)
return readl(addr);
else
return readl(addr + 4);
}
static void mscc_setbits(unsigned int offset, void *addr)
{
if (offset < 32)
writel(readl(addr) | BIT(offset), addr);
else
writel(readl(addr + 4) | BIT(offset % 32), addr + 4);
}
static void mscc_clrbits(unsigned int offset, void *addr)
{
if (offset < 32)
writel(readl(addr) & ~BIT(offset), addr);
else
writel(readl(addr + 4) & ~BIT(offset % 32), addr + 4);
}
static int mscc_get_functions_count(struct udevice *dev)
{
struct mscc_pinctrl *info = dev_get_priv(dev);
return info->num_func;
}
static const char *mscc_get_function_name(struct udevice *dev,
unsigned int function)
{
struct mscc_pinctrl *info = dev_get_priv(dev);
return info->function_names[function];
}
static int mscc_pin_function_idx(unsigned int pin, unsigned int function,
const struct mscc_pin_data *mscc_pins)
{
struct mscc_pin_caps *p = mscc_pins[pin].drv_data;
int i;
for (i = 0; i < MSCC_FUNC_PER_PIN; i++) {
if (function == p->functions[i])
return i;
}
return -1;
}
static int mscc_pinmux_set_mux(struct udevice *dev,
unsigned int pin_selector, unsigned int selector)
{
struct mscc_pinctrl *info = dev_get_priv(dev);
struct mscc_pin_caps *pin = info->mscc_pins[pin_selector].drv_data;
int f, offset, regoff;
f = mscc_pin_function_idx(pin_selector, selector, info->mscc_pins);
if (f < 0)
return -EINVAL;
/*
* f is encoded on two bits.
* bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of
* ALT1
* This is racy because both registers can't be updated at the same time
* but it doesn't matter much for now.
*/
offset = pin->pin;
regoff = info->mscc_gpios[MSCC_GPIO_ALT0];
if (offset >= 32) {
offset = offset % 32;
regoff = info->mscc_gpios[MSCC_GPIO_ALT1];
}
if (f & BIT(0))
mscc_setbits(offset, info->regs + regoff);
else
mscc_clrbits(offset, info->regs + regoff);
if (f & BIT(1))
mscc_setbits(offset, info->regs + regoff + 4);
else
mscc_clrbits(offset, info->regs + regoff + 4);
return 0;
}
static int mscc_pctl_get_groups_count(struct udevice *dev)
{
struct mscc_pinctrl *info = dev_get_priv(dev);
return info->num_pins;
}
static const char *mscc_pctl_get_group_name(struct udevice *dev,
unsigned int group)
{
struct mscc_pinctrl *info = dev_get_priv(dev);
return info->mscc_pins[group].name;
}
static int mscc_create_group_func_map(struct udevice *dev,
struct mscc_pinctrl *info)
{
u16 pins[info->num_pins];
int f, npins, i;
for (f = 0; f < info->num_func; f++) {
for (npins = 0, i = 0; i < info->num_pins; i++) {
if (mscc_pin_function_idx(i, f, info->mscc_pins) >= 0)
pins[npins++] = i;
}
info->func[f].ngroups = npins;
info->func[f].groups = devm_kzalloc(dev, npins * sizeof(char *),
GFP_KERNEL);
if (!info->func[f].groups)
return -ENOMEM;
for (i = 0; i < npins; i++)
info->func[f].groups[i] = info->mscc_pins[pins[i]].name;
}
return 0;
}
static int mscc_pinctrl_register(struct udevice *dev, struct mscc_pinctrl *info)
{
int ret;
ret = mscc_create_group_func_map(dev, info);
if (ret) {
dev_err(dev, "Unable to create group func map.\n");
return ret;
}
return 0;
}
static int mscc_gpio_get(struct udevice *dev, unsigned int offset)
{
struct mscc_pinctrl *info = dev_get_priv(dev->parent);
unsigned int val;
if (mscc_readl(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]) &
BIT(offset % 32))
val = mscc_readl(offset,
info->regs + info->mscc_gpios[MSCC_GPIO_OUT]);
else
val = mscc_readl(offset,
info->regs + info->mscc_gpios[MSCC_GPIO_IN]);
return !!(val & BIT(offset % 32));
}
static int mscc_gpio_set(struct udevice *dev, unsigned int offset, int value)
{
struct mscc_pinctrl *info = dev_get_priv(dev->parent);
if (value)
mscc_writel(offset,
info->regs + info->mscc_gpios[MSCC_GPIO_OUT_SET]);
else
mscc_writel(offset,
info->regs + info->mscc_gpios[MSCC_GPIO_OUT_CLR]);
return 0;
}
static int mscc_gpio_get_direction(struct udevice *dev, unsigned int offset)
{
struct mscc_pinctrl *info = dev_get_priv(dev->parent);
unsigned int val;
val = mscc_readl(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]);
return (val & BIT(offset % 32)) ? GPIOF_OUTPUT : GPIOF_INPUT;
}
static int mscc_gpio_direction_input(struct udevice *dev, unsigned int offset)
{
struct mscc_pinctrl *info = dev_get_priv(dev->parent);
mscc_clrbits(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]);
return 0;
}
static int mscc_gpio_direction_output(struct udevice *dev,
unsigned int offset, int value)
{
struct mscc_pinctrl *info = dev_get_priv(dev->parent);
mscc_setbits(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]);
return mscc_gpio_set(dev, offset, value);
}
const struct dm_gpio_ops mscc_gpio_ops = {
.set_value = mscc_gpio_set,
.get_value = mscc_gpio_get,
.get_function = mscc_gpio_get_direction,
.direction_input = mscc_gpio_direction_input,
.direction_output = mscc_gpio_direction_output,
};
const struct pinctrl_ops mscc_pinctrl_ops = {
.get_pins_count = mscc_pctl_get_groups_count,
.get_pin_name = mscc_pctl_get_group_name,
.get_functions_count = mscc_get_functions_count,
.get_function_name = mscc_get_function_name,
.pinmux_set = mscc_pinmux_set_mux,
.set_state = pinctrl_generic_set_state,
};
int mscc_pinctrl_probe(struct udevice *dev, int num_func,
const struct mscc_pin_data *mscc_pins, int num_pins,
char * const *function_names,
const unsigned long *mscc_gpios)
{
struct mscc_pinctrl *priv = dev_get_priv(dev);
int ret;
priv->regs = dev_remap_addr(dev);
if (!priv->regs)
return -EINVAL;
priv->func = devm_kzalloc(dev, num_func * sizeof(struct mscc_pmx_func),
GFP_KERNEL);
priv->num_func = num_func;
priv->mscc_pins = mscc_pins;
priv->num_pins = num_pins;
priv->function_names = function_names;
priv->mscc_gpios = mscc_gpios;
ret = mscc_pinctrl_register(dev, priv);
return ret;
}
@@ -0,0 +1,66 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Microsemi SoCs pinctrl driver
*
* Author: <alexandre.belloni@free-electrons.com>
* License: Dual MIT/GPL
* Copyright (c) 2017 Microsemi Corporation
*/
#define MSCC_FUNC_PER_PIN 4
enum mscc_regs_gpio {
MSCC_GPIO_OUT_SET,
MSCC_GPIO_OUT_CLR,
MSCC_GPIO_OUT,
MSCC_GPIO_IN,
MSCC_GPIO_OE,
MSCC_GPIO_INTR,
MSCC_GPIO_INTR_ENA,
MSCC_GPIO_INTR_IDENT,
MSCC_GPIO_ALT0,
MSCC_GPIO_ALT1,
};
struct mscc_pin_caps {
unsigned int pin;
unsigned char functions[MSCC_FUNC_PER_PIN];
};
struct mscc_pin_data {
const char *name;
struct mscc_pin_caps *drv_data;
};
#define MSCC_P(p, f0, f1, f2) \
static struct mscc_pin_caps mscc_pin_##p = { \
.pin = p, \
.functions = { \
FUNC_GPIO, FUNC_##f0, FUNC_##f1, FUNC_##f2, \
}, \
}
struct mscc_pmx_func {
const char **groups;
unsigned int ngroups;
};
struct mscc_pinctrl {
struct udevice *dev;
struct pinctrl_dev *pctl;
void __iomem *regs;
struct mscc_pmx_func *func;
int num_func;
const struct mscc_pin_data *mscc_pins;
int num_pins;
char * const *function_names;
const unsigned long *mscc_gpios;
};
int mscc_pinctrl_probe(struct udevice *dev, int num_func,
const struct mscc_pin_data *mscc_pins, int num_pins,
char * const *function_names,
const unsigned long *mscc_gpios);
const struct pinctrl_ops mscc_pinctrl_ops;
const struct dm_gpio_ops mscc_gpio_ops;
@@ -0,0 +1,323 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi SoCs pinctrl driver
*
* Author: <horatiu.vultur@microchip.com>
* Copyright (c) 2018 Microsemi Corporation
*/
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <errno.h>
#include <fdtdec.h>
#include <linux/io.h>
#include <asm/gpio.h>
#include <asm/system.h>
#include "mscc-common.h"
enum {
FUNC_NONE,
FUNC_GPIO,
FUNC_IRQ0_IN,
FUNC_IRQ0_OUT,
FUNC_IRQ1_IN,
FUNC_IRQ1_OUT,
FUNC_MIIM1,
FUNC_MIIM2,
FUNC_PCI_WAKE,
FUNC_PTP0,
FUNC_PTP1,
FUNC_PTP2,
FUNC_PTP3,
FUNC_PWM,
FUNC_RECO_CLK0,
FUNC_RECO_CLK1,
FUNC_SFP0,
FUNC_SFP1,
FUNC_SFP2,
FUNC_SFP3,
FUNC_SFP4,
FUNC_SFP5,
FUNC_SFP6,
FUNC_SFP7,
FUNC_SFP8,
FUNC_SFP9,
FUNC_SFP10,
FUNC_SFP11,
FUNC_SFP12,
FUNC_SFP13,
FUNC_SFP14,
FUNC_SFP15,
FUNC_SG0,
FUNC_SG1,
FUNC_SG2,
FUNC_SI,
FUNC_TACHO,
FUNC_TWI,
FUNC_TWI2,
FUNC_TWI_SCL_M,
FUNC_UART,
FUNC_UART2,
FUNC_MAX
};
static char * const jr2_function_names[] = {
[FUNC_NONE] = "none",
[FUNC_GPIO] = "gpio",
[FUNC_IRQ0_IN] = "irq0_in",
[FUNC_IRQ0_OUT] = "irq0_out",
[FUNC_IRQ1_IN] = "irq1_in",
[FUNC_IRQ1_OUT] = "irq1_out",
[FUNC_MIIM1] = "miim1",
[FUNC_MIIM2] = "miim2",
[FUNC_PCI_WAKE] = "pci_wake",
[FUNC_PTP0] = "ptp0",
[FUNC_PTP1] = "ptp1",
[FUNC_PTP2] = "ptp2",
[FUNC_PTP3] = "ptp3",
[FUNC_PWM] = "pwm",
[FUNC_RECO_CLK0] = "reco_clk0",
[FUNC_RECO_CLK1] = "reco_clk1",
[FUNC_SFP0] = "sfp0",
[FUNC_SFP1] = "sfp1",
[FUNC_SFP2] = "sfp2",
[FUNC_SFP3] = "sfp3",
[FUNC_SFP4] = "sfp4",
[FUNC_SFP5] = "sfp5",
[FUNC_SFP6] = "sfp6",
[FUNC_SFP7] = "sfp7",
[FUNC_SFP8] = "sfp8",
[FUNC_SFP9] = "sfp9",
[FUNC_SFP10] = "sfp10",
[FUNC_SFP11] = "sfp11",
[FUNC_SFP12] = "sfp12",
[FUNC_SFP13] = "sfp13",
[FUNC_SFP14] = "sfp14",
[FUNC_SFP15] = "sfp15",
[FUNC_SG0] = "sg0",
[FUNC_SG1] = "sg1",
[FUNC_SG2] = "sg2",
[FUNC_SI] = "si",
[FUNC_TACHO] = "tacho",
[FUNC_TWI] = "twi",
[FUNC_TWI2] = "twi2",
[FUNC_TWI_SCL_M] = "twi_scl_m",
[FUNC_UART] = "uart",
[FUNC_UART2] = "uart2",
};
#define JR2_P(p, f0, f1) \
static struct mscc_pin_caps jr2_pin_##p = { \
.pin = p, \
.functions = { \
FUNC_GPIO, FUNC_##f0, FUNC_##f1, FUNC_NONE \
}, \
}
JR2_P(0, SG0, NONE);
JR2_P(1, SG0, NONE);
JR2_P(2, SG0, NONE);
JR2_P(3, SG0, NONE);
JR2_P(4, SG1, NONE);
JR2_P(5, SG1, NONE);
JR2_P(6, IRQ0_IN, IRQ0_OUT);
JR2_P(7, IRQ1_IN, IRQ1_OUT);
JR2_P(8, PTP0, NONE);
JR2_P(9, PTP1, NONE);
JR2_P(10, UART, NONE);
JR2_P(11, UART, NONE);
JR2_P(12, SG1, NONE);
JR2_P(13, SG1, NONE);
JR2_P(14, TWI, TWI_SCL_M);
JR2_P(15, TWI, NONE);
JR2_P(16, SI, TWI_SCL_M);
JR2_P(17, SI, TWI_SCL_M);
JR2_P(18, SI, TWI_SCL_M);
JR2_P(19, PCI_WAKE, NONE);
JR2_P(20, IRQ0_OUT, TWI_SCL_M);
JR2_P(21, IRQ1_OUT, TWI_SCL_M);
JR2_P(22, TACHO, NONE);
JR2_P(23, PWM, NONE);
JR2_P(24, UART2, NONE);
JR2_P(25, UART2, SI);
JR2_P(26, PTP2, SI);
JR2_P(27, PTP3, SI);
JR2_P(28, TWI2, SI);
JR2_P(29, TWI, SI);
JR2_P(30, SG2, SI);
JR2_P(31, SG2, SI);
JR2_P(32, SG2, SI);
JR2_P(33, SG2, SI);
JR2_P(34, NONE, TWI_SCL_M);
JR2_P(35, NONE, TWI_SCL_M);
JR2_P(36, NONE, TWI_SCL_M);
JR2_P(37, NONE, TWI_SCL_M);
JR2_P(38, NONE, TWI_SCL_M);
JR2_P(39, NONE, TWI_SCL_M);
JR2_P(40, NONE, TWI_SCL_M);
JR2_P(41, NONE, TWI_SCL_M);
JR2_P(42, NONE, TWI_SCL_M);
JR2_P(43, NONE, TWI_SCL_M);
JR2_P(44, NONE, SFP8);
JR2_P(45, NONE, SFP9);
JR2_P(46, NONE, SFP10);
JR2_P(47, NONE, SFP11);
JR2_P(48, SFP0, NONE);
JR2_P(49, SFP1, SI);
JR2_P(50, SFP2, SI);
JR2_P(51, SFP3, SI);
JR2_P(52, SFP4, NONE);
JR2_P(53, SFP5, NONE);
JR2_P(54, SFP6, NONE);
JR2_P(55, SFP7, NONE);
JR2_P(56, MIIM1, SFP12);
JR2_P(57, MIIM1, SFP13);
JR2_P(58, MIIM2, SFP14);
JR2_P(59, MIIM2, SFP15);
JR2_P(60, NONE, NONE);
JR2_P(61, NONE, NONE);
JR2_P(62, NONE, NONE);
JR2_P(63, NONE, NONE);
#define JR2_PIN(n) { \
.name = "GPIO_"#n, \
.drv_data = &jr2_pin_##n \
}
static const struct mscc_pin_data jr2_pins[] = {
JR2_PIN(0),
JR2_PIN(1),
JR2_PIN(2),
JR2_PIN(3),
JR2_PIN(4),
JR2_PIN(5),
JR2_PIN(6),
JR2_PIN(7),
JR2_PIN(8),
JR2_PIN(9),
JR2_PIN(10),
JR2_PIN(11),
JR2_PIN(12),
JR2_PIN(13),
JR2_PIN(14),
JR2_PIN(15),
JR2_PIN(16),
JR2_PIN(17),
JR2_PIN(18),
JR2_PIN(19),
JR2_PIN(20),
JR2_PIN(21),
JR2_PIN(22),
JR2_PIN(23),
JR2_PIN(24),
JR2_PIN(25),
JR2_PIN(26),
JR2_PIN(27),
JR2_PIN(28),
JR2_PIN(29),
JR2_PIN(30),
JR2_PIN(31),
JR2_PIN(32),
JR2_PIN(33),
JR2_PIN(34),
JR2_PIN(35),
JR2_PIN(36),
JR2_PIN(37),
JR2_PIN(38),
JR2_PIN(39),
JR2_PIN(40),
JR2_PIN(41),
JR2_PIN(42),
JR2_PIN(43),
JR2_PIN(44),
JR2_PIN(45),
JR2_PIN(46),
JR2_PIN(47),
JR2_PIN(48),
JR2_PIN(49),
JR2_PIN(50),
JR2_PIN(51),
JR2_PIN(52),
JR2_PIN(53),
JR2_PIN(54),
JR2_PIN(55),
JR2_PIN(56),
JR2_PIN(57),
JR2_PIN(58),
JR2_PIN(59),
JR2_PIN(60),
JR2_PIN(61),
JR2_PIN(62),
JR2_PIN(63),
};
static const unsigned long jr2_gpios[] = {
[MSCC_GPIO_OUT_SET] = 0x00,
[MSCC_GPIO_OUT_CLR] = 0x08,
[MSCC_GPIO_OUT] = 0x10,
[MSCC_GPIO_IN] = 0x18,
[MSCC_GPIO_OE] = 0x20,
[MSCC_GPIO_INTR] = 0x28,
[MSCC_GPIO_INTR_ENA] = 0x30,
[MSCC_GPIO_INTR_IDENT] = 0x38,
[MSCC_GPIO_ALT0] = 0x40,
[MSCC_GPIO_ALT1] = 0x48,
};
static int jr2_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = "jr2-gpio";
uc_priv->gpio_count = ARRAY_SIZE(jr2_pins);
return 0;
}
static struct driver jr2_gpio_driver = {
.name = "jr2-gpio",
.id = UCLASS_GPIO,
.probe = jr2_gpio_probe,
.ops = &mscc_gpio_ops,
};
static int jr2_pinctrl_probe(struct udevice *dev)
{
int ret;
ret = mscc_pinctrl_probe(dev, FUNC_MAX, jr2_pins,
ARRAY_SIZE(jr2_pins),
jr2_function_names,
jr2_gpios);
if (ret)
return ret;
ret = device_bind(dev, &jr2_gpio_driver, "jr2-gpio", NULL,
dev_of_offset(dev), NULL);
if (ret)
return ret;
return 0;
}
static const struct udevice_id jr2_pinctrl_of_match[] = {
{ .compatible = "mscc,jaguar2-pinctrl" },
{},
};
U_BOOT_DRIVER(jr2_pinctrl) = {
.name = "jr2-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(jr2_pinctrl_of_match),
.probe = jr2_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct mscc_pinctrl),
.ops = &mscc_pinctrl_ops,
};
@@ -0,0 +1,186 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi SoCs pinctrl driver
*
* Author: <gregory.clement@bootlin.com>
* License: Dual MIT/GPL
* Copyright (c) 2018 Microsemi Corporation
*/
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <errno.h>
#include <fdtdec.h>
#include <linux/io.h>
#include <asm/gpio.h>
#include <asm/system.h>
#include "mscc-common.h"
enum {
FUNC_NONE,
FUNC_GPIO,
FUNC_SIO,
FUNC_TACHO,
FUNC_TWI,
FUNC_PHY_LED,
FUNC_EXT_IRQ,
FUNC_SFP,
FUNC_SI,
FUNC_PWM,
FUNC_UART,
FUNC_MAX
};
static char * const luton_function_names[] = {
[FUNC_NONE] = "none",
[FUNC_GPIO] = "gpio",
[FUNC_SIO] = "sio",
[FUNC_TACHO] = "tacho",
[FUNC_TWI] = "twi",
[FUNC_PHY_LED] = "phy_led",
[FUNC_EXT_IRQ] = "ext_irq",
[FUNC_SFP] = "sfp",
[FUNC_SI] = "si",
[FUNC_PWM] = "pwm",
[FUNC_UART] = "uart",
};
MSCC_P(0, SIO, NONE, NONE);
MSCC_P(1, SIO, NONE, NONE);
MSCC_P(2, SIO, NONE, NONE);
MSCC_P(3, SIO, NONE, NONE);
MSCC_P(4, TACHO, NONE, NONE);
MSCC_P(5, TWI, PHY_LED, NONE);
MSCC_P(6, TWI, PHY_LED, NONE);
MSCC_P(7, NONE, PHY_LED, NONE);
MSCC_P(8, EXT_IRQ, PHY_LED, NONE);
MSCC_P(9, EXT_IRQ, PHY_LED, NONE);
MSCC_P(10, SFP, PHY_LED, NONE);
MSCC_P(11, SFP, PHY_LED, NONE);
MSCC_P(12, SFP, PHY_LED, NONE);
MSCC_P(13, SFP, PHY_LED, NONE);
MSCC_P(14, SI, PHY_LED, NONE);
MSCC_P(15, SI, PHY_LED, NONE);
MSCC_P(16, SI, PHY_LED, NONE);
MSCC_P(17, SFP, PHY_LED, NONE);
MSCC_P(18, SFP, PHY_LED, NONE);
MSCC_P(19, SFP, PHY_LED, NONE);
MSCC_P(20, SFP, PHY_LED, NONE);
MSCC_P(21, SFP, PHY_LED, NONE);
MSCC_P(22, SFP, PHY_LED, NONE);
MSCC_P(23, SFP, PHY_LED, NONE);
MSCC_P(24, SFP, PHY_LED, NONE);
MSCC_P(25, SFP, PHY_LED, NONE);
MSCC_P(26, SFP, PHY_LED, NONE);
MSCC_P(27, SFP, PHY_LED, NONE);
MSCC_P(28, SFP, PHY_LED, NONE);
MSCC_P(29, PWM, NONE, NONE);
MSCC_P(30, UART, NONE, NONE);
MSCC_P(31, UART, NONE, NONE);
#define LUTON_PIN(n) { \
.name = "GPIO_"#n, \
.drv_data = &mscc_pin_##n \
}
static const struct mscc_pin_data luton_pins[] = {
LUTON_PIN(0),
LUTON_PIN(1),
LUTON_PIN(2),
LUTON_PIN(3),
LUTON_PIN(4),
LUTON_PIN(5),
LUTON_PIN(6),
LUTON_PIN(7),
LUTON_PIN(8),
LUTON_PIN(9),
LUTON_PIN(10),
LUTON_PIN(11),
LUTON_PIN(12),
LUTON_PIN(13),
LUTON_PIN(14),
LUTON_PIN(15),
LUTON_PIN(16),
LUTON_PIN(17),
LUTON_PIN(18),
LUTON_PIN(19),
LUTON_PIN(20),
LUTON_PIN(21),
LUTON_PIN(22),
LUTON_PIN(23),
LUTON_PIN(24),
LUTON_PIN(25),
LUTON_PIN(26),
LUTON_PIN(27),
LUTON_PIN(28),
LUTON_PIN(29),
LUTON_PIN(30),
LUTON_PIN(31),
};
static const unsigned long luton_gpios[] = {
[MSCC_GPIO_OUT_SET] = 0x00,
[MSCC_GPIO_OUT_CLR] = 0x04,
[MSCC_GPIO_OUT] = 0x08,
[MSCC_GPIO_IN] = 0x0c,
[MSCC_GPIO_OE] = 0x10,
[MSCC_GPIO_INTR] = 0x14,
[MSCC_GPIO_INTR_ENA] = 0x18,
[MSCC_GPIO_INTR_IDENT] = 0x1c,
[MSCC_GPIO_ALT0] = 0x20,
[MSCC_GPIO_ALT1] = 0x24,
};
static int luton_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = "luton-gpio";
uc_priv->gpio_count = ARRAY_SIZE(luton_pins);
return 0;
}
static struct driver luton_gpio_driver = {
.name = "luton-gpio",
.id = UCLASS_GPIO,
.probe = luton_gpio_probe,
.ops = &mscc_gpio_ops,
};
int luton_pinctrl_probe(struct udevice *dev)
{
int ret;
ret = mscc_pinctrl_probe(dev, FUNC_MAX, luton_pins,
ARRAY_SIZE(luton_pins), luton_function_names,
luton_gpios);
if (ret)
return ret;
ret = device_bind(dev, &luton_gpio_driver, "luton-gpio", NULL,
dev_of_offset(dev), NULL);
return 0;
}
static const struct udevice_id luton_pinctrl_of_match[] = {
{.compatible = "mscc,luton-pinctrl"},
{},
};
U_BOOT_DRIVER(luton_pinctrl) = {
.name = "luton-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(luton_pinctrl_of_match),
.probe = luton_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct mscc_pinctrl),
.ops = &mscc_pinctrl_ops,
};
@@ -0,0 +1,202 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi SoCs pinctrl driver
*
* Author: <alexandre.belloni@free-electrons.com>
* Author: <gregory.clement@bootlin.com>
* License: Dual MIT/GPL
* Copyright (c) 2017 Microsemi Corporation
*/
#include <asm/gpio.h>
#include <asm/system.h>
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <errno.h>
#include <fdtdec.h>
#include <linux/io.h>
#include "mscc-common.h"
enum {
FUNC_NONE,
FUNC_GPIO,
FUNC_IRQ0_IN,
FUNC_IRQ0_OUT,
FUNC_IRQ1_IN,
FUNC_IRQ1_OUT,
FUNC_MIIM1,
FUNC_PCI_WAKE,
FUNC_PTP0,
FUNC_PTP1,
FUNC_PTP2,
FUNC_PTP3,
FUNC_PWM,
FUNC_RECO_CLK0,
FUNC_RECO_CLK1,
FUNC_SFP0,
FUNC_SFP1,
FUNC_SFP2,
FUNC_SFP3,
FUNC_SFP4,
FUNC_SFP5,
FUNC_SG0,
FUNC_SI,
FUNC_TACHO,
FUNC_TWI,
FUNC_TWI_SCL_M,
FUNC_UART,
FUNC_UART2,
FUNC_MAX
};
static char * const ocelot_function_names[] = {
[FUNC_NONE] = "none",
[FUNC_GPIO] = "gpio",
[FUNC_IRQ0_IN] = "irq0_in",
[FUNC_IRQ0_OUT] = "irq0_out",
[FUNC_IRQ1_IN] = "irq1_in",
[FUNC_IRQ1_OUT] = "irq1_out",
[FUNC_MIIM1] = "miim1",
[FUNC_PCI_WAKE] = "pci_wake",
[FUNC_PTP0] = "ptp0",
[FUNC_PTP1] = "ptp1",
[FUNC_PTP2] = "ptp2",
[FUNC_PTP3] = "ptp3",
[FUNC_PWM] = "pwm",
[FUNC_RECO_CLK0] = "reco_clk0",
[FUNC_RECO_CLK1] = "reco_clk1",
[FUNC_SFP0] = "sfp0",
[FUNC_SFP1] = "sfp1",
[FUNC_SFP2] = "sfp2",
[FUNC_SFP3] = "sfp3",
[FUNC_SFP4] = "sfp4",
[FUNC_SFP5] = "sfp5",
[FUNC_SG0] = "sg0",
[FUNC_SI] = "si",
[FUNC_TACHO] = "tacho",
[FUNC_TWI] = "twi",
[FUNC_TWI_SCL_M] = "twi_scl_m",
[FUNC_UART] = "uart",
[FUNC_UART2] = "uart2",
};
MSCC_P(0, SG0, NONE, NONE);
MSCC_P(1, SG0, NONE, NONE);
MSCC_P(2, SG0, NONE, NONE);
MSCC_P(3, SG0, NONE, NONE);
MSCC_P(4, IRQ0_IN, IRQ0_OUT, TWI);
MSCC_P(5, IRQ1_IN, IRQ1_OUT, PCI_WAKE);
MSCC_P(6, UART, TWI_SCL_M, NONE);
MSCC_P(7, UART, TWI_SCL_M, NONE);
MSCC_P(8, SI, TWI_SCL_M, IRQ0_OUT);
MSCC_P(9, SI, TWI_SCL_M, IRQ1_OUT);
MSCC_P(10, PTP2, TWI_SCL_M, SFP0);
MSCC_P(11, PTP3, TWI_SCL_M, SFP1);
MSCC_P(12, UART2, TWI_SCL_M, SFP2);
MSCC_P(13, UART2, TWI_SCL_M, SFP3);
MSCC_P(14, MIIM1, TWI_SCL_M, SFP4);
MSCC_P(15, MIIM1, TWI_SCL_M, SFP5);
MSCC_P(16, TWI, NONE, SI);
MSCC_P(17, TWI, TWI_SCL_M, SI);
MSCC_P(18, PTP0, TWI_SCL_M, NONE);
MSCC_P(19, PTP1, TWI_SCL_M, NONE);
MSCC_P(20, RECO_CLK0, TACHO, NONE);
MSCC_P(21, RECO_CLK1, PWM, NONE);
#define OCELOT_PIN(n) { \
.name = "GPIO_"#n, \
.drv_data = &mscc_pin_##n \
}
static const struct mscc_pin_data ocelot_pins[] = {
OCELOT_PIN(0),
OCELOT_PIN(1),
OCELOT_PIN(2),
OCELOT_PIN(3),
OCELOT_PIN(4),
OCELOT_PIN(5),
OCELOT_PIN(6),
OCELOT_PIN(7),
OCELOT_PIN(8),
OCELOT_PIN(9),
OCELOT_PIN(10),
OCELOT_PIN(11),
OCELOT_PIN(12),
OCELOT_PIN(13),
OCELOT_PIN(14),
OCELOT_PIN(15),
OCELOT_PIN(16),
OCELOT_PIN(17),
OCELOT_PIN(18),
OCELOT_PIN(19),
OCELOT_PIN(20),
OCELOT_PIN(21),
};
static const unsigned long ocelot_gpios[] = {
[MSCC_GPIO_OUT_SET] = 0x00,
[MSCC_GPIO_OUT_CLR] = 0x04,
[MSCC_GPIO_OUT] = 0x08,
[MSCC_GPIO_IN] = 0x0c,
[MSCC_GPIO_OE] = 0x10,
[MSCC_GPIO_INTR] = 0x14,
[MSCC_GPIO_INTR_ENA] = 0x18,
[MSCC_GPIO_INTR_IDENT] = 0x1c,
[MSCC_GPIO_ALT0] = 0x20,
[MSCC_GPIO_ALT1] = 0x24,
};
static int ocelot_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = "ocelot-gpio";
uc_priv->gpio_count = ARRAY_SIZE(ocelot_pins);
return 0;
}
static struct driver ocelot_gpio_driver = {
.name = "ocelot-gpio",
.id = UCLASS_GPIO,
.probe = ocelot_gpio_probe,
.ops = &mscc_gpio_ops,
};
int ocelot_pinctrl_probe(struct udevice *dev)
{
int ret;
ret = mscc_pinctrl_probe(dev, FUNC_MAX, ocelot_pins,
ARRAY_SIZE(ocelot_pins),
ocelot_function_names,
ocelot_gpios);
if (ret)
return ret;
ret = device_bind(dev, &ocelot_gpio_driver, "ocelot-gpio", NULL,
dev_of_offset(dev), NULL);
return ret;
}
static const struct udevice_id ocelot_pinctrl_of_match[] = {
{.compatible = "mscc,ocelot-pinctrl"},
{},
};
U_BOOT_DRIVER(ocelot_pinctrl) = {
.name = "ocelot-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(ocelot_pinctrl_of_match),
.probe = ocelot_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct mscc_pinctrl),
.ops = &mscc_pinctrl_ops,
};
@@ -0,0 +1,233 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi SoCs pinctrl driver
*
* Author: <horatiu.vultur@microchip.com>
* Copyright (c) 2019 Microsemi Corporation
*/
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <errno.h>
#include <fdtdec.h>
#include <linux/io.h>
#include <asm/gpio.h>
#include <asm/system.h>
#include "mscc-common.h"
enum {
FUNC_NONE,
FUNC_GPIO,
FUNC_IRQ0,
FUNC_IRQ1,
FUNC_MIIM1,
FUNC_PCI_WAKE,
FUNC_PTP0,
FUNC_PTP1,
FUNC_PTP2,
FUNC_PTP3,
FUNC_PWM,
FUNC_RECO_CLK0,
FUNC_RECO_CLK1,
FUNC_SFP0,
FUNC_SFP1,
FUNC_SFP2,
FUNC_SFP3,
FUNC_SFP4,
FUNC_SFP5,
FUNC_SFP6,
FUNC_SFP7,
FUNC_SFP8,
FUNC_SFP9,
FUNC_SFP10,
FUNC_SIO,
FUNC_SI,
FUNC_TACHO,
FUNC_TWI,
FUNC_TWI_SCL_M,
FUNC_UART,
FUNC_UART2,
FUNC_MD,
FUNC_PTP1588,
FUNC_MAX
};
static char * const serval_function_names[] = {
[FUNC_NONE] = "none",
[FUNC_GPIO] = "gpio",
[FUNC_IRQ0] = "irq0",
[FUNC_IRQ1] = "irq1",
[FUNC_MIIM1] = "miim1",
[FUNC_PCI_WAKE] = "pci_wake",
[FUNC_PTP0] = "ptp0",
[FUNC_PTP1] = "ptp1",
[FUNC_PTP2] = "ptp2",
[FUNC_PTP3] = "ptp3",
[FUNC_PWM] = "pwm",
[FUNC_RECO_CLK0] = "reco_clk0",
[FUNC_RECO_CLK1] = "reco_clk1",
[FUNC_SFP0] = "sfp0",
[FUNC_SFP1] = "sfp1",
[FUNC_SFP2] = "sfp2",
[FUNC_SFP3] = "sfp3",
[FUNC_SFP4] = "sfp4",
[FUNC_SFP5] = "sfp5",
[FUNC_SFP6] = "sfp6",
[FUNC_SFP7] = "sfp7",
[FUNC_SFP8] = "sfp8",
[FUNC_SFP9] = "sfp9",
[FUNC_SFP10] = "sfp10",
[FUNC_SIO] = "sio",
[FUNC_SI] = "si",
[FUNC_TACHO] = "tacho",
[FUNC_TWI] = "twi",
[FUNC_TWI_SCL_M] = "twi_scl_m",
[FUNC_UART] = "uart",
[FUNC_UART2] = "uart2",
[FUNC_MD] = "md",
[FUNC_PTP1588] = "1588",
};
MSCC_P(0, SIO, NONE, NONE);
MSCC_P(1, SIO, NONE, NONE);
MSCC_P(2, SIO, NONE, NONE);
MSCC_P(3, SIO, NONE, NONE);
MSCC_P(4, TACHO, NONE, NONE);
MSCC_P(5, PWM, NONE, NONE);
MSCC_P(6, TWI, NONE, NONE);
MSCC_P(7, TWI, NONE, NONE);
MSCC_P(8, SI, NONE, NONE);
MSCC_P(9, SI, MD, NONE);
MSCC_P(10, SI, MD, NONE);
MSCC_P(11, SFP0, MD, TWI_SCL_M);
MSCC_P(12, SFP1, MD, TWI_SCL_M);
MSCC_P(13, SFP2, UART2, TWI_SCL_M);
MSCC_P(14, SFP3, UART2, TWI_SCL_M);
MSCC_P(15, SFP4, PTP1588, TWI_SCL_M);
MSCC_P(16, SFP5, PTP1588, TWI_SCL_M);
MSCC_P(17, SFP6, PCI_WAKE, TWI_SCL_M);
MSCC_P(18, SFP7, NONE, TWI_SCL_M);
MSCC_P(19, SFP8, NONE, TWI_SCL_M);
MSCC_P(20, SFP9, NONE, TWI_SCL_M);
MSCC_P(21, SFP10, NONE, TWI_SCL_M);
MSCC_P(22, NONE, NONE, NONE);
MSCC_P(23, NONE, NONE, NONE);
MSCC_P(24, NONE, NONE, NONE);
MSCC_P(25, NONE, NONE, NONE);
MSCC_P(26, UART, NONE, NONE);
MSCC_P(27, UART, NONE, NONE);
MSCC_P(28, IRQ0, NONE, NONE);
MSCC_P(29, IRQ1, NONE, NONE);
MSCC_P(30, PTP1588, NONE, NONE);
MSCC_P(31, PTP1588, NONE, NONE);
#define SERVAL_PIN(n) { \
.name = "GPIO_"#n, \
.drv_data = &mscc_pin_##n \
}
static const struct mscc_pin_data serval_pins[] = {
SERVAL_PIN(0),
SERVAL_PIN(1),
SERVAL_PIN(2),
SERVAL_PIN(3),
SERVAL_PIN(4),
SERVAL_PIN(5),
SERVAL_PIN(6),
SERVAL_PIN(7),
SERVAL_PIN(8),
SERVAL_PIN(9),
SERVAL_PIN(10),
SERVAL_PIN(11),
SERVAL_PIN(12),
SERVAL_PIN(13),
SERVAL_PIN(14),
SERVAL_PIN(15),
SERVAL_PIN(16),
SERVAL_PIN(17),
SERVAL_PIN(18),
SERVAL_PIN(19),
SERVAL_PIN(20),
SERVAL_PIN(21),
SERVAL_PIN(22),
SERVAL_PIN(23),
SERVAL_PIN(24),
SERVAL_PIN(25),
SERVAL_PIN(26),
SERVAL_PIN(27),
SERVAL_PIN(28),
SERVAL_PIN(29),
SERVAL_PIN(30),
SERVAL_PIN(31),
};
static const unsigned long serval_gpios[] = {
[MSCC_GPIO_OUT_SET] = 0x00,
[MSCC_GPIO_OUT_CLR] = 0x04,
[MSCC_GPIO_OUT] = 0x08,
[MSCC_GPIO_IN] = 0x0c,
[MSCC_GPIO_OE] = 0x10,
[MSCC_GPIO_INTR] = 0x14,
[MSCC_GPIO_INTR_ENA] = 0x18,
[MSCC_GPIO_INTR_IDENT] = 0x1c,
[MSCC_GPIO_ALT0] = 0x20,
[MSCC_GPIO_ALT1] = 0x24,
};
static int serval_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = "serval-gpio";
uc_priv->gpio_count = ARRAY_SIZE(serval_pins);
return 0;
}
static struct driver serval_gpio_driver = {
.name = "serval-gpio",
.id = UCLASS_GPIO,
.probe = serval_gpio_probe,
.ops = &mscc_gpio_ops,
};
static int serval_pinctrl_probe(struct udevice *dev)
{
int ret;
ret = mscc_pinctrl_probe(dev, FUNC_MAX, serval_pins,
ARRAY_SIZE(serval_pins),
serval_function_names,
serval_gpios);
if (ret)
return ret;
ret = device_bind(dev, &serval_gpio_driver, "serval-gpio", NULL,
dev_of_offset(dev), NULL);
if (ret)
return ret;
return 0;
}
static const struct udevice_id serval_pinctrl_of_match[] = {
{ .compatible = "mscc,serval-pinctrl" },
{},
};
U_BOOT_DRIVER(serval_pinctrl) = {
.name = "serval-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(serval_pinctrl_of_match),
.probe = serval_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct mscc_pinctrl),
.ops = &mscc_pinctrl_ops,
};
@@ -0,0 +1,269 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi SoCs pinctrl driver
*
* Author: <horatiu.vultur@microchip.com>
* Copyright (c) 2019 Microsemi Corporation
*/
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <errno.h>
#include <fdtdec.h>
#include <linux/io.h>
#include <asm/gpio.h>
#include <asm/system.h>
#include "mscc-common.h"
enum {
FUNC_NONE,
FUNC_GPIO,
FUNC_IRQ0_IN,
FUNC_IRQ0_OUT,
FUNC_IRQ1_IN,
FUNC_IRQ1_OUT,
FUNC_MIIM1,
FUNC_MIIM2,
FUNC_PCI_WAKE,
FUNC_PTP0,
FUNC_PTP1,
FUNC_PTP2,
FUNC_PTP3,
FUNC_PWM,
FUNC_RCVRD_CLK0,
FUNC_RCVRD_CLK1,
FUNC_RCVRD_CLK2,
FUNC_RCVRD_CLK3,
FUNC_REF_CLK0,
FUNC_REF_CLK1,
FUNC_REF_CLK2,
FUNC_REF_CLK3,
FUNC_SFP0,
FUNC_SFP1,
FUNC_SFP2,
FUNC_SFP3,
FUNC_SFP4,
FUNC_SFP5,
FUNC_SFP6,
FUNC_SFP7,
FUNC_SFP8,
FUNC_SFP9,
FUNC_SFP10,
FUNC_SFP11,
FUNC_SFP12,
FUNC_SFP13,
FUNC_SFP14,
FUNC_SFP15,
FUNC_SIO,
FUNC_SPI,
FUNC_TACHO,
FUNC_TWI,
FUNC_TWI2,
FUNC_TWI_SCL_M,
FUNC_UART,
FUNC_UART2,
FUNC_MAX
};
static char * const servalt_function_names[] = {
[FUNC_NONE] = "none",
[FUNC_GPIO] = "gpio",
[FUNC_IRQ0_IN] = "irq0_in",
[FUNC_IRQ0_OUT] = "irq0_out",
[FUNC_IRQ1_IN] = "irq1_in",
[FUNC_IRQ1_OUT] = "irq1_out",
[FUNC_MIIM1] = "miim1",
[FUNC_MIIM2] = "miim2",
[FUNC_PCI_WAKE] = "pci_wake",
[FUNC_PTP0] = "ptp0",
[FUNC_PTP1] = "ptp1",
[FUNC_PTP2] = "ptp2",
[FUNC_PTP3] = "ptp3",
[FUNC_PWM] = "pwm",
[FUNC_RCVRD_CLK0] = "rcvrd_clk0",
[FUNC_RCVRD_CLK1] = "rcvrd_clk1",
[FUNC_RCVRD_CLK2] = "rcvrd_clk2",
[FUNC_RCVRD_CLK3] = "rcvrd_clk3",
[FUNC_REF_CLK0] = "ref_clk0",
[FUNC_REF_CLK1] = "ref_clk1",
[FUNC_REF_CLK2] = "ref_clk2",
[FUNC_REF_CLK3] = "ref_clk3",
[FUNC_SFP0] = "sfp0",
[FUNC_SFP1] = "sfp1",
[FUNC_SFP2] = "sfp2",
[FUNC_SFP3] = "sfp3",
[FUNC_SFP4] = "sfp4",
[FUNC_SFP5] = "sfp5",
[FUNC_SFP6] = "sfp6",
[FUNC_SFP7] = "sfp7",
[FUNC_SFP8] = "sfp8",
[FUNC_SFP9] = "sfp9",
[FUNC_SFP10] = "sfp10",
[FUNC_SFP11] = "sfp11",
[FUNC_SFP12] = "sfp12",
[FUNC_SFP13] = "sfp13",
[FUNC_SFP14] = "sfp14",
[FUNC_SFP15] = "sfp15",
[FUNC_SIO] = "sio",
[FUNC_SPI] = "spi",
[FUNC_TACHO] = "tacho",
[FUNC_TWI] = "twi",
[FUNC_TWI2] = "twi2",
[FUNC_TWI_SCL_M] = "twi_scl_m",
[FUNC_UART] = "uart",
[FUNC_UART2] = "uart2",
};
MSCC_P(0, SIO, NONE, NONE);
MSCC_P(1, SIO, NONE, NONE);
MSCC_P(2, SIO, NONE, NONE);
MSCC_P(3, SIO, NONE, NONE);
MSCC_P(4, IRQ0_IN, IRQ0_OUT, TWI_SCL_M);
MSCC_P(5, IRQ1_IN, IRQ1_OUT, TWI_SCL_M);
MSCC_P(6, UART, NONE, NONE);
MSCC_P(7, UART, NONE, NONE);
MSCC_P(8, SPI, SFP0, TWI_SCL_M);
MSCC_P(9, PCI_WAKE, SFP1, SPI);
MSCC_P(10, PTP0, SFP2, TWI_SCL_M);
MSCC_P(11, PTP1, SFP3, TWI_SCL_M);
MSCC_P(12, REF_CLK0, SFP4, TWI_SCL_M);
MSCC_P(13, REF_CLK1, SFP5, TWI_SCL_M);
MSCC_P(14, REF_CLK2, IRQ0_OUT, SPI);
MSCC_P(15, REF_CLK3, IRQ1_OUT, SPI);
MSCC_P(16, TACHO, SFP6, SPI);
MSCC_P(17, PWM, NONE, TWI_SCL_M);
MSCC_P(18, PTP2, SFP7, SPI);
MSCC_P(19, PTP3, SFP8, SPI);
MSCC_P(20, UART2, SFP9, SPI);
MSCC_P(21, UART2, NONE, NONE);
MSCC_P(22, MIIM1, SFP10, TWI2);
MSCC_P(23, MIIM1, SFP11, TWI2);
MSCC_P(24, TWI, NONE, NONE);
MSCC_P(25, TWI, SFP12, TWI_SCL_M);
MSCC_P(26, TWI_SCL_M, SFP13, SPI);
MSCC_P(27, TWI_SCL_M, SFP14, SPI);
MSCC_P(28, TWI_SCL_M, SFP15, SPI);
MSCC_P(29, TWI_SCL_M, NONE, NONE);
MSCC_P(30, TWI_SCL_M, NONE, NONE);
MSCC_P(31, TWI_SCL_M, NONE, NONE);
MSCC_P(32, TWI_SCL_M, NONE, NONE);
MSCC_P(33, RCVRD_CLK0, NONE, NONE);
MSCC_P(34, RCVRD_CLK1, NONE, NONE);
MSCC_P(35, RCVRD_CLK2, NONE, NONE);
MSCC_P(36, RCVRD_CLK3, NONE, NONE);
#define SERVALT_PIN(n) { \
.name = "GPIO_"#n, \
.drv_data = &mscc_pin_##n \
}
static const struct mscc_pin_data servalt_pins[] = {
SERVALT_PIN(0),
SERVALT_PIN(1),
SERVALT_PIN(2),
SERVALT_PIN(3),
SERVALT_PIN(4),
SERVALT_PIN(5),
SERVALT_PIN(6),
SERVALT_PIN(7),
SERVALT_PIN(8),
SERVALT_PIN(9),
SERVALT_PIN(10),
SERVALT_PIN(11),
SERVALT_PIN(12),
SERVALT_PIN(13),
SERVALT_PIN(14),
SERVALT_PIN(15),
SERVALT_PIN(16),
SERVALT_PIN(17),
SERVALT_PIN(18),
SERVALT_PIN(19),
SERVALT_PIN(20),
SERVALT_PIN(21),
SERVALT_PIN(22),
SERVALT_PIN(23),
SERVALT_PIN(24),
SERVALT_PIN(25),
SERVALT_PIN(26),
SERVALT_PIN(27),
SERVALT_PIN(28),
SERVALT_PIN(29),
SERVALT_PIN(30),
SERVALT_PIN(31),
SERVALT_PIN(32),
SERVALT_PIN(33),
SERVALT_PIN(34),
SERVALT_PIN(35),
SERVALT_PIN(36),
};
static const unsigned long servalt_gpios[] = {
[MSCC_GPIO_OUT_SET] = 0x00,
[MSCC_GPIO_OUT_CLR] = 0x08,
[MSCC_GPIO_OUT] = 0x10,
[MSCC_GPIO_IN] = 0x18,
[MSCC_GPIO_OE] = 0x20,
[MSCC_GPIO_INTR] = 0x28,
[MSCC_GPIO_INTR_ENA] = 0x30,
[MSCC_GPIO_INTR_IDENT] = 0x38,
[MSCC_GPIO_ALT0] = 0x40,
[MSCC_GPIO_ALT1] = 0x48,
};
static int servalt_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = "servalt-gpio";
uc_priv->gpio_count = ARRAY_SIZE(servalt_pins);
return 0;
}
static struct driver servalt_gpio_driver = {
.name = "servalt-gpio",
.id = UCLASS_GPIO,
.probe = servalt_gpio_probe,
.ops = &mscc_gpio_ops,
};
static int servalt_pinctrl_probe(struct udevice *dev)
{
int ret;
ret = mscc_pinctrl_probe(dev, FUNC_MAX, servalt_pins,
ARRAY_SIZE(servalt_pins),
servalt_function_names,
servalt_gpios);
if (ret)
return ret;
ret = device_bind(dev, &servalt_gpio_driver, "servalt-gpio", NULL,
dev_of_offset(dev), NULL);
if (ret)
return ret;
return 0;
}
static const struct udevice_id servalt_pinctrl_of_match[] = {
{ .compatible = "mscc,servalt-pinctrl" },
{},
};
U_BOOT_DRIVER(servalt_pinctrl) = {
.name = "servalt-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(servalt_pinctrl_of_match),
.probe = servalt_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct mscc_pinctrl),
.ops = &mscc_pinctrl_ops,
};
@@ -0,0 +1,13 @@
config PINCTRL_MTMIPS
depends on ARCH_MTMIPS
bool
config PINCTRL_MT7628
bool "MediaTek MT7628 pin control driver"
select PINCTRL_MTMIPS
depends on SOC_MT7628 && PINCTRL_GENERIC
help
Support pin multiplexing control on MediaTek MT7628.
The driver is controlled by a device tree node which contains
the pin mux functions for each available pin groups.
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# Core
obj-$(CONFIG_PINCTRL_MTMIPS) += pinctrl-mtmips-common.o
# SoC Drivers
obj-$(CONFIG_PINCTRL_MT7628) += pinctrl-mt7628.o
@@ -0,0 +1,585 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 MediaTek Inc. All Rights Reserved.
*
* Author: Weijie Gao <weijie.gao@mediatek.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include "pinctrl-mtmips-common.h"
DECLARE_GLOBAL_DATA_PTR;
#define AGPIO_OFS 0
#define GPIOMODE1_OFS 0x24
#define GPIOMODE2_OFS 0x28
#define EPHY4_1_PAD_SHIFT 17
#define EPHY4_1_PAD_MASK 0x0f
#define EPHY0_SHIFT 16
#define RF_OLT_MODE_SHIFT 12
#define N9_EINT_SRC_SHIFT 9
#define WLED_OD_SHIFT 8
#define REF_CLKO_PAD_SHIFT 4
#define I2S_CLK_PAD_SHIFT 3
#define I2S_WS_PAD_SHIFT 2
#define I2S_SDO_PAD_SHIFT 1
#define I2S_SDI_PAD_SHIFT 0
#define GM4_MASK 3
#define P4LED_K_SHIFT 26
#define P3LED_K_SHIFT 24
#define P2LED_K_SHIFT 22
#define P1LED_K_SHIFT 20
#define P0LED_K_SHIFT 18
#define WLED_K_SHIFT 16
#define P4LED_A_SHIFT 10
#define P3LED_A_SHIFT 8
#define P2LED_A_SHIFT 6
#define P1LED_A_SHIFT 4
#define P0LED_A_SHIFT 2
#define WLED_A_SHIFT 0
#define PWM1_SHIFT 30
#define PWM0_SHIFT 28
#define UART2_SHIFT 26
#define UART1_SHIFT 24
#define I2C_SHIFT 20
#define REFCLK_SHIFT 18
#define PERST_SHIFT 16
#define ESD_SHIFT 15
#define WDT_SHIFT 14
#define SPI_SHIFT 12
#define SDMODE_SHIFT 10
#define UART0_SHIFT 8
#define I2S_SHIFT 6
#define SPI_CS1_SHIFT 4
#define SPIS_SHIFT 2
#define GPIO0_SHIFT 0
#define PAD_PU_G0_REG 0x00
#define PAD_PU_G1_REG 0x04
#define PAD_PD_G0_REG 0x10
#define PAD_PD_G1_REG 0x14
#define PAD_SR_G0_REG 0x20
#define PAD_SR_G1_REG 0x24
#define PAD_SMT_G0_REG 0x30
#define PAD_SMT_G1_REG 0x34
#define PAD_E2_G0_REG 0x40
#define PAD_E2_G1_REG 0x44
#define PAD_E4_G0_REG 0x50
#define PAD_E4_G1_REG 0x54
#define PAD_E8_G0_REG 0x60
#define PAD_E8_G1_REG 0x64
#define PIN_CONFIG_DRIVE_STRENGTH_28 (PIN_CONFIG_END + 1)
#define PIN_CONFIG_DRIVE_STRENGTH_4G (PIN_CONFIG_END + 2)
struct mt7628_pinctrl_priv {
struct mtmips_pinctrl_priv mp;
void __iomem *pcbase;
};
#if CONFIG_IS_ENABLED(PINMUX)
static const struct mtmips_pmx_func ephy4_1_pad_grp[] = {
FUNC("digital", 0xf),
FUNC("analog", 0),
};
static const struct mtmips_pmx_func ephy0_grp[] = {
FUNC("disable", 1),
FUNC("enable", 0),
};
static const struct mtmips_pmx_func rf_olt_grp[] = {
FUNC("enable", 1),
FUNC("disable", 0),
};
static const struct mtmips_pmx_func n9_eint_src_grp[] = {
FUNC("gpio", 1),
FUNC("utif", 0),
};
static const struct mtmips_pmx_func wlen_od_grp[] = {
FUNC("enable", 1),
FUNC("disable", 0),
};
static const struct mtmips_pmx_func ref_clko_grp[] = {
FUNC("digital", 1),
FUNC("analog", 0),
};
static const struct mtmips_pmx_func i2s_clk_grp[] = {
FUNC("digital", 1),
FUNC("analog", 0),
};
static const struct mtmips_pmx_func i2s_ws_grp[] = {
FUNC("digital", 1),
FUNC("analog", 0),
};
static const struct mtmips_pmx_func i2s_sdo_grp[] = {
FUNC("digital", 1),
FUNC("analog", 0),
};
static const struct mtmips_pmx_func i2s_sdi_grp[] = {
FUNC("digital", 1),
FUNC("analog", 0),
};
static const struct mtmips_pmx_func pwm1_grp[] = {
FUNC("sdxc d6", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("pwm1", 0),
};
static const struct mtmips_pmx_func pwm0_grp[] = {
FUNC("sdxc d7", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("pwm0", 0),
};
static const struct mtmips_pmx_func uart2_grp[] = {
FUNC("sdxc d5 d4", 3),
FUNC("pwm", 2),
FUNC("gpio", 1),
FUNC("uart2", 0),
};
static const struct mtmips_pmx_func uart1_grp[] = {
FUNC("sw_r", 3),
FUNC("pwm", 2),
FUNC("gpio", 1),
FUNC("uart1", 0),
};
static const struct mtmips_pmx_func i2c_grp[] = {
FUNC("-", 3),
FUNC("debug", 2),
FUNC("gpio", 1),
FUNC("i2c", 0),
};
static const struct mtmips_pmx_func refclk_grp[] = {
FUNC("gpio", 1),
FUNC("refclk", 0),
};
static const struct mtmips_pmx_func perst_grp[] = {
FUNC("gpio", 1),
FUNC("perst", 0),
};
static const struct mtmips_pmx_func esd_grp[] = {
FUNC("router", 1),
FUNC("iot", 0),
};
static const struct mtmips_pmx_func wdt_grp[] = {
FUNC("gpio", 1),
FUNC("wdt", 0),
};
static const struct mtmips_pmx_func spi_grp[] = {
FUNC("gpio", 1),
FUNC("spi", 0),
};
static const struct mtmips_pmx_func sd_mode_grp[] = {
FUNC("n9 jtag", 3),
FUNC("utif1", 2),
FUNC("gpio", 1),
FUNC("sdxc", 0),
};
static const struct mtmips_pmx_func uart0_grp[] = {
FUNC("-", 3),
FUNC("-", 2),
FUNC("gpio", 1),
FUNC("uart0", 0),
};
static const struct mtmips_pmx_func i2s_grp[] = {
FUNC("antenna", 3),
FUNC("pcm", 2),
FUNC("gpio", 1),
FUNC("i2s", 0),
};
static const struct mtmips_pmx_func spi_cs1_grp[] = {
FUNC("-", 3),
FUNC("refclk", 2),
FUNC("gpio", 1),
FUNC("spi cs1", 0),
};
static const struct mtmips_pmx_func spis_grp[] = {
FUNC("pwm_uart2", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("spis", 0),
};
static const struct mtmips_pmx_func gpio0_grp[] = {
FUNC("perst", 3),
FUNC("refclk", 2),
FUNC("gpio", 1),
FUNC("gpio0", 0),
};
static const struct mtmips_pmx_func wled_a_grp[] = {
FUNC("-", 3),
FUNC("-", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p0led_a_grp[] = {
FUNC("jtag", 3),
FUNC("rsvd", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p1led_a_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p2led_a_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p3led_a_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p4led_a_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func wled_k_grp[] = {
FUNC("-", 3),
FUNC("-", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p0led_k_grp[] = {
FUNC("jtag", 3),
FUNC("rsvd", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p1led_k_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p2led_k_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p3led_k_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_func p4led_k_grp[] = {
FUNC("jtag", 3),
FUNC("utif", 2),
FUNC("gpio", 1),
FUNC("led", 0),
};
static const struct mtmips_pmx_group mt7628_pinmux_data[] = {
GRP("ephy4_1_pad", ephy4_1_pad_grp, AGPIO_OFS, EPHY4_1_PAD_SHIFT,
EPHY4_1_PAD_MASK),
GRP("ephy0", ephy0_grp, AGPIO_OFS, EPHY0_SHIFT, 1),
GRP("rf_olt", rf_olt_grp, AGPIO_OFS, RF_OLT_MODE_SHIFT, 1),
GRP("n9_eint_src", n9_eint_src_grp, AGPIO_OFS, N9_EINT_SRC_SHIFT, 1),
GRP("wlen_od", wlen_od_grp, AGPIO_OFS, WLED_OD_SHIFT, 1),
GRP("ref_clko_pad", ref_clko_grp, AGPIO_OFS, REF_CLKO_PAD_SHIFT, 1),
GRP("i2s_clk_pad", i2s_clk_grp, AGPIO_OFS, I2S_CLK_PAD_SHIFT, 1),
GRP("i2s_ws_pad", i2s_ws_grp, AGPIO_OFS, I2S_WS_PAD_SHIFT, 1),
GRP("i2s_sdo_pad", i2s_sdo_grp, AGPIO_OFS, I2S_SDO_PAD_SHIFT, 1),
GRP("i2s_sdi_pad", i2s_sdi_grp, AGPIO_OFS, I2S_SDI_PAD_SHIFT, 1),
GRP("pwm1", pwm1_grp, GPIOMODE1_OFS, PWM1_SHIFT, GM4_MASK),
GRP("pwm0", pwm0_grp, GPIOMODE1_OFS, PWM0_SHIFT, GM4_MASK),
GRP("uart2", uart2_grp, GPIOMODE1_OFS, UART2_SHIFT, GM4_MASK),
GRP("uart1", uart1_grp, GPIOMODE1_OFS, UART1_SHIFT, GM4_MASK),
GRP("i2c", i2c_grp, GPIOMODE1_OFS, I2C_SHIFT, GM4_MASK),
GRP("refclk", refclk_grp, GPIOMODE1_OFS, REFCLK_SHIFT, 1),
GRP("perst", perst_grp, GPIOMODE1_OFS, PERST_SHIFT, 1),
GRP("sd router", esd_grp, GPIOMODE1_OFS, ESD_SHIFT, 1),
GRP("wdt", wdt_grp, GPIOMODE1_OFS, WDT_SHIFT, 1),
GRP("spi", spi_grp, GPIOMODE1_OFS, SPI_SHIFT, 1),
GRP("sdmode", sd_mode_grp, GPIOMODE1_OFS, SDMODE_SHIFT, GM4_MASK),
GRP("uart0", uart0_grp, GPIOMODE1_OFS, UART0_SHIFT, GM4_MASK),
GRP("i2s", i2s_grp, GPIOMODE1_OFS, I2S_SHIFT, GM4_MASK),
GRP("spi cs1", spi_cs1_grp, GPIOMODE1_OFS, SPI_CS1_SHIFT, GM4_MASK),
GRP("spis", spis_grp, GPIOMODE1_OFS, SPIS_SHIFT, GM4_MASK),
GRP("gpio0", gpio0_grp, GPIOMODE1_OFS, GPIO0_SHIFT, GM4_MASK),
GRP("wled_a", wled_a_grp, GPIOMODE2_OFS, WLED_A_SHIFT, GM4_MASK),
GRP("p0led_a", p0led_a_grp, GPIOMODE2_OFS, P0LED_A_SHIFT, GM4_MASK),
GRP("p1led_a", p1led_a_grp, GPIOMODE2_OFS, P1LED_A_SHIFT, GM4_MASK),
GRP("p2led_a", p2led_a_grp, GPIOMODE2_OFS, P2LED_A_SHIFT, GM4_MASK),
GRP("p3led_a", p3led_a_grp, GPIOMODE2_OFS, P3LED_A_SHIFT, GM4_MASK),
GRP("p4led_a", p4led_a_grp, GPIOMODE2_OFS, P4LED_A_SHIFT, GM4_MASK),
GRP("wled_k", wled_k_grp, GPIOMODE2_OFS, WLED_K_SHIFT, GM4_MASK),
GRP("p0led_k", p0led_k_grp, GPIOMODE2_OFS, P0LED_K_SHIFT, GM4_MASK),
GRP("p1led_k", p1led_k_grp, GPIOMODE2_OFS, P1LED_K_SHIFT, GM4_MASK),
GRP("p2led_k", p2led_k_grp, GPIOMODE2_OFS, P2LED_K_SHIFT, GM4_MASK),
GRP("p3led_k", p3led_k_grp, GPIOMODE2_OFS, P3LED_K_SHIFT, GM4_MASK),
GRP("p4led_k", p4led_k_grp, GPIOMODE2_OFS, P4LED_K_SHIFT, GM4_MASK),
};
static int mt7628_get_groups_count(struct udevice *dev)
{
return ARRAY_SIZE(mt7628_pinmux_data);
}
static const char *mt7628_get_group_name(struct udevice *dev,
unsigned int selector)
{
return mt7628_pinmux_data[selector].name;
}
#endif /* CONFIG_IS_ENABLED(PINMUX) */
#if CONFIG_IS_ENABLED(PINCONF)
static const struct pinconf_param mt7628_conf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
{ "drive-strength-28", PIN_CONFIG_DRIVE_STRENGTH_28, 0 },
{ "drive-strength-4g", PIN_CONFIG_DRIVE_STRENGTH_4G, 0 },
{ "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
};
static const char *const mt7628_pins[] = {
"i2s_sdi",
"i2s_sdo",
"i2s_ws",
"i2s_clk",
"i2s_sclk",
"i2c_sd",
"spi_cs1",
"spi_clk",
"spi_mosi",
"spi_miso",
"spi_cs0",
"gpio0",
"uart0_txd",
"uart0_rxd",
"spis_cs",
"spis_clk",
"spis_miso",
"spis_mosi",
"pwm_ch0",
"pwm_ch1",
"uart2_txd",
"uart2_rxd",
"sd_wp",
"sd_cd",
"sd_d1",
"sd_d0",
"sd_clk",
"sd_cmd",
"sd_d3",
"sd_d2",
"ephy_led4_k",
"ephy_led3_k",
"ephy_led2_k",
"ephy_led1_k",
"ephy_led0_k",
"wled_k",
"perst_n",
"co_clko",
"wdt",
"ephy_led4_a",
"ephy_led3_a",
"ephy_led2_a",
"ephy_led1_a",
"ephy_led0_a",
"wled_a",
"uart1_txd",
"uart1_rxd",
};
static const u32 mt7628_drv_strength_28_tbl[] = {2, 4, 6, 8};
static const u32 mt7628_drv_strength_4g_tbl[] = {4, 8, 12, 16};
static int mt7628_set_drv_strength(void __iomem *base, u32 val, u32 bit,
const u32 tbl[], u32 reg_lo, u32 reg_hi)
{
int i;
for (i = 0; i < 4; i++)
if (tbl[i] == val)
break;
if (i >= 4)
return -EINVAL;
clrsetbits_32(base + reg_lo, BIT(bit), (i & 1) << bit);
clrsetbits_32(base + reg_hi, BIT(bit), ((i >> 1) & 1) << bit);
return 0;
}
static int mt7628_get_pins_count(struct udevice *dev)
{
return ARRAY_SIZE(mt7628_pins);
}
static const char *mt7628_get_pin_name(struct udevice *dev,
unsigned int selector)
{
return mt7628_pins[selector];
}
static int mt7628_pinconf_set(struct udevice *dev, unsigned int pin_selector,
unsigned int param, unsigned int argument)
{
struct mt7628_pinctrl_priv *priv = dev_get_priv(dev);
u32 offs, bit;
int ret = 0;
offs = (pin_selector / 32) * 4;
bit = pin_selector % 32;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
clrbits_32(priv->pcbase + offs + PAD_PU_G0_REG, BIT(bit));
clrbits_32(priv->pcbase + offs + PAD_PD_G0_REG, BIT(bit));
break;
case PIN_CONFIG_BIAS_PULL_UP:
setbits_32(priv->pcbase + offs + PAD_PU_G0_REG, BIT(bit));
clrbits_32(priv->pcbase + offs + PAD_PD_G0_REG, BIT(bit));
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
clrbits_32(priv->pcbase + offs + PAD_PU_G0_REG, BIT(bit));
setbits_32(priv->pcbase + offs + PAD_PD_G0_REG, BIT(bit));
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
clrsetbits_32(priv->pcbase + offs + PAD_SMT_G0_REG,
BIT(bit), (!!argument) << bit);
break;
case PIN_CONFIG_DRIVE_STRENGTH_28:
ret = mt7628_set_drv_strength(priv->pcbase + offs, argument,
bit, mt7628_drv_strength_28_tbl,
PAD_E2_G0_REG, PAD_E4_G0_REG);
break;
case PIN_CONFIG_DRIVE_STRENGTH_4G:
ret = mt7628_set_drv_strength(priv->pcbase + offs, argument,
bit, mt7628_drv_strength_4g_tbl,
PAD_E4_G0_REG, PAD_E8_G0_REG);
break;
case PIN_CONFIG_SLEW_RATE:
clrsetbits_32(priv->pcbase + offs + PAD_SR_G0_REG,
BIT(bit), (!!argument) << bit);
break;
default:
ret = -EINVAL;
}
return ret;
}
#endif
static int mt7628_pinctrl_probe(struct udevice *dev)
{
struct mt7628_pinctrl_priv *priv = dev_get_priv(dev);
int ret = 0;
#if CONFIG_IS_ENABLED(PINMUX)
ret = mtmips_pinctrl_probe(&priv->mp, ARRAY_SIZE(mt7628_pinmux_data),
mt7628_pinmux_data);
#endif /* CONFIG_IS_ENABLED(PINMUX) */
return ret;
}
static int mt7628_pinctrl_ofdata_to_platdata(struct udevice *dev)
{
struct mt7628_pinctrl_priv *priv = dev_get_priv(dev);
priv->mp.base = (void __iomem *)dev_remap_addr_index(dev, 0);
if (!priv->mp.base)
return -EINVAL;
priv->pcbase = (void __iomem *)dev_remap_addr_index(dev, 1);
if (!priv->pcbase)
return -EINVAL;
return 0;
}
static const struct pinctrl_ops mt7628_pinctrl_ops = {
#if CONFIG_IS_ENABLED(PINMUX)
.get_groups_count = mt7628_get_groups_count,
.get_group_name = mt7628_get_group_name,
.get_functions_count = mtmips_get_functions_count,
.get_function_name = mtmips_get_function_name,
.pinmux_group_set = mtmips_pinmux_group_set,
#endif /* CONFIG_IS_ENABLED(PINMUX) */
#if CONFIG_IS_ENABLED(PINCONF)
.pinconf_num_params = ARRAY_SIZE(mt7628_conf_params),
.pinconf_params = mt7628_conf_params,
.get_pins_count = mt7628_get_pins_count,
.get_pin_name = mt7628_get_pin_name,
.pinconf_set = mt7628_pinconf_set,
#endif /* CONFIG_IS_ENABLED(PINCONF) */
.set_state = pinctrl_generic_set_state,
};
static const struct udevice_id mt7628_pinctrl_ids[] = {
{ .compatible = "mediatek,mt7628-pinctrl" },
{ }
};
U_BOOT_DRIVER(mt7628_pinctrl) = {
.name = "mt7628-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = mt7628_pinctrl_ids,
.ofdata_to_platdata = mt7628_pinctrl_ofdata_to_platdata,
.ops = &mt7628_pinctrl_ops,
.probe = mt7628_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct mt7628_pinctrl_priv),
};
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 MediaTek Inc. All Rights Reserved.
*
* Author: Weijie Gao <weijie.gao@mediatek.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <linux/io.h>
#include "pinctrl-mtmips-common.h"
static void mtmips_pinctrl_reg_set(struct mtmips_pinctrl_priv *priv,
u32 reg, u32 shift, u32 mask, u32 value)
{
u32 val;
val = readl(priv->base + reg);
val &= ~(mask << shift);
val |= value << shift;
writel(val, priv->base + reg);
}
int mtmips_get_functions_count(struct udevice *dev)
{
struct mtmips_pinctrl_priv *priv = dev_get_priv(dev);
return priv->nfuncs;
}
const char *mtmips_get_function_name(struct udevice *dev, unsigned int selector)
{
struct mtmips_pinctrl_priv *priv = dev_get_priv(dev);
return priv->funcs[selector]->name;
}
int mtmips_pinmux_group_set(struct udevice *dev, unsigned int group_selector,
unsigned int func_selector)
{
struct mtmips_pinctrl_priv *priv = dev_get_priv(dev);
const struct mtmips_pmx_group *grp = &priv->groups[group_selector];
const struct mtmips_pmx_func *func = priv->funcs[func_selector];
int i;
if (!grp->nfuncs)
return 0;
for (i = 0; i < grp->nfuncs; i++) {
if (!strcmp(grp->funcs[i].name, func->name)) {
mtmips_pinctrl_reg_set(priv, grp->reg, grp->shift,
grp->mask, grp->funcs[i].value);
return 0;
}
}
return -EINVAL;
}
int mtmips_pinctrl_probe(struct mtmips_pinctrl_priv *priv, u32 ngroups,
const struct mtmips_pmx_group *groups)
{
int i, j, n;
priv->ngroups = ngroups;
priv->groups = groups;
priv->nfuncs = 0;
for (i = 0; i < ngroups; i++)
priv->nfuncs += groups[i].nfuncs;
priv->funcs = malloc(priv->nfuncs * sizeof(*priv->funcs));
if (!priv->funcs)
return -ENOMEM;
n = 0;
for (i = 0; i < ngroups; i++) {
for (j = 0; j < groups[i].nfuncs; j++)
priv->funcs[n++] = &groups[i].funcs[j];
}
return 0;
}
@@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 MediaTek Inc. All Rights Reserved.
*
* Author: Weijie Gao <weijie.gao@mediatek.com>
*/
#ifndef _PINCTRL_MTMIPS_COMMON_H_
#define _PINCTRL_MTMIPS_COMMON_H_
#include <common.h>
struct mtmips_pmx_func {
const char *name;
int value;
};
struct mtmips_pmx_group {
const char *name;
u32 reg;
u32 shift;
char mask;
int nfuncs;
const struct mtmips_pmx_func *funcs;
};
struct mtmips_pinctrl_priv {
void __iomem *base;
u32 ngroups;
const struct mtmips_pmx_group *groups;
u32 nfuncs;
const struct mtmips_pmx_func **funcs;
};
#define FUNC(name, value) { name, value }
#define GRP(_name, _funcs, _reg, _shift, _mask) \
{ .name = (_name), .reg = (_reg), .shift = (_shift), .mask = (_mask), \
.funcs = (_funcs), .nfuncs = ARRAY_SIZE(_funcs) }
int mtmips_get_functions_count(struct udevice *dev);
const char *mtmips_get_function_name(struct udevice *dev,
unsigned int selector);
int mtmips_pinmux_group_set(struct udevice *dev, unsigned int group_selector,
unsigned int func_selector);
int mtmips_pinctrl_probe(struct mtmips_pinctrl_priv *priv, u32 ngroups,
const struct mtmips_pmx_group *groups);
#endif /* _PINCTRL_MTMIPS_COMMON_H_ */
@@ -0,0 +1,17 @@
if ARCH_MVEBU
config PINCTRL_ARMADA_37XX
depends on ARMADA_3700 && PINCTRL_FULL
bool "Armada 37xx pin control driver"
help
Support pin multiplexing and pin configuration control on
Marvell's Armada-37xx SoC.
config PINCTRL_ARMADA_8K
depends on ARMADA_8K && PINCTRL_FULL
bool "Armada 7k/8k pin control driver"
help
Support pin multiplexing and pin configuration control on
Marvell's Armada-8K SoC.
endif
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2016 Marvell International Ltd.
#
# https://spdx.org/licenses
obj-$(CONFIG_PINCTRL_ARMADA_37XX) += pinctrl-armada-37xx.o
obj-$(CONFIG_PINCTRL_ARMADA_8K) += pinctrl-mvebu.o
@@ -0,0 +1,643 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* U-Boot Marvell 37xx SoC pinctrl driver
*
* Copyright (C) 2017 Stefan Roese <sr@denx.de>
*
* This driver is based on the Linux driver version, which is:
* Copyright (C) 2017 Marvell
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* Additionally parts are derived from the Meson U-Boot pinctrl driver,
* which is:
* (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
* Based on code from Linux kernel:
* Copyright (C) 2016 Endless Mobile, Inc.
* https://spdx.org/licenses
*/
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <errno.h>
#include <fdtdec.h>
#include <regmap.h>
#include <asm/gpio.h>
#include <asm/system.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
#define OUTPUT_EN 0x0
#define INPUT_VAL 0x10
#define OUTPUT_VAL 0x18
#define OUTPUT_CTL 0x20
#define SELECTION 0x30
#define IRQ_EN 0x0
#define IRQ_POL 0x08
#define IRQ_STATUS 0x10
#define IRQ_WKUP 0x18
#define NB_FUNCS 3
#define GPIO_PER_REG 32
/**
* struct armada_37xx_pin_group: represents group of pins of a pinmux function.
* The pins of a pinmux groups are composed of one or two groups of contiguous
* pins.
* @name: Name of the pin group, used to lookup the group.
* @start_pins: Index of the first pin of the main range of pins belonging to
* the group
* @npins: Number of pins included in the first range
* @reg_mask: Bit mask matching the group in the selection register
* @extra_pins: Index of the first pin of the optional second range of pins
* belonging to the group
* @npins: Number of pins included in the second optional range
* @funcs: A list of pinmux functions that can be selected for this group.
* @pins: List of the pins included in the group
*/
struct armada_37xx_pin_group {
const char *name;
unsigned int start_pin;
unsigned int npins;
u32 reg_mask;
u32 val[NB_FUNCS];
unsigned int extra_pin;
unsigned int extra_npins;
const char *funcs[NB_FUNCS];
unsigned int *pins;
};
struct armada_37xx_pin_data {
u8 nr_pins;
char *name;
struct armada_37xx_pin_group *groups;
int ngroups;
};
struct armada_37xx_pmx_func {
const char *name;
const char **groups;
unsigned int ngroups;
};
struct armada_37xx_pinctrl {
void __iomem *base;
const struct armada_37xx_pin_data *data;
struct udevice *dev;
struct pinctrl_dev *pctl_dev;
struct armada_37xx_pin_group *groups;
unsigned int ngroups;
struct armada_37xx_pmx_func *funcs;
unsigned int nfuncs;
};
#define PIN_GRP(_name, _start, _nr, _mask, _func1, _func2) \
{ \
.name = _name, \
.start_pin = _start, \
.npins = _nr, \
.reg_mask = _mask, \
.val = {0, _mask}, \
.funcs = {_func1, _func2} \
}
#define PIN_GRP_GPIO(_name, _start, _nr, _mask, _func1) \
{ \
.name = _name, \
.start_pin = _start, \
.npins = _nr, \
.reg_mask = _mask, \
.val = {0, _mask}, \
.funcs = {_func1, "gpio"} \
}
#define PIN_GRP_GPIO_2(_name, _start, _nr, _mask, _val1, _val2, _func1) \
{ \
.name = _name, \
.start_pin = _start, \
.npins = _nr, \
.reg_mask = _mask, \
.val = {_val1, _val2}, \
.funcs = {_func1, "gpio"} \
}
#define PIN_GRP_GPIO_3(_name, _start, _nr, _mask, _v1, _v2, _v3, _f1, _f2) \
{ \
.name = _name, \
.start_pin = _start, \
.npins = _nr, \
.reg_mask = _mask, \
.val = {_v1, _v2, _v3}, \
.funcs = {_f1, _f2, "gpio"} \
}
#define PIN_GRP_EXTRA(_name, _start, _nr, _mask, _v1, _v2, _start2, _nr2, \
_f1, _f2) \
{ \
.name = _name, \
.start_pin = _start, \
.npins = _nr, \
.reg_mask = _mask, \
.val = {_v1, _v2}, \
.extra_pin = _start2, \
.extra_npins = _nr2, \
.funcs = {_f1, _f2} \
}
static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
PIN_GRP_GPIO("jtag", 20, 5, BIT(0), "jtag"),
PIN_GRP_GPIO("sdio0", 8, 3, BIT(1), "sdio"),
PIN_GRP_GPIO("emmc_nb", 27, 9, BIT(2), "emmc"),
PIN_GRP_GPIO("pwm0", 11, 1, BIT(3), "pwm"),
PIN_GRP_GPIO("pwm1", 12, 1, BIT(4), "pwm"),
PIN_GRP_GPIO("pwm2", 13, 1, BIT(5), "pwm"),
PIN_GRP_GPIO("pwm3", 14, 1, BIT(6), "pwm"),
PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"),
PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"),
PIN_GRP_GPIO("i2c2", 2, 2, BIT(9), "i2c"),
PIN_GRP_GPIO("i2c1", 0, 2, BIT(10), "i2c"),
PIN_GRP_GPIO("spi_cs1", 17, 1, BIT(12), "spi"),
PIN_GRP_GPIO_2("spi_cs2", 18, 1, BIT(13) | BIT(19), 0, BIT(13), "spi"),
PIN_GRP_GPIO_2("spi_cs3", 19, 1, BIT(14) | BIT(19), 0, BIT(14), "spi"),
PIN_GRP_GPIO("onewire", 4, 1, BIT(16), "onewire"),
PIN_GRP_GPIO("uart1", 25, 2, BIT(17), "uart"),
PIN_GRP_GPIO("spi_quad", 15, 2, BIT(18), "spi"),
PIN_GRP_EXTRA("uart2", 9, 2, BIT(1) | BIT(13) | BIT(14) | BIT(19),
BIT(1) | BIT(13) | BIT(14), BIT(1) | BIT(19),
18, 2, "gpio", "uart"),
PIN_GRP_GPIO("led0_od", 11, 1, BIT(20), "led"),
PIN_GRP_GPIO("led1_od", 12, 1, BIT(21), "led"),
PIN_GRP_GPIO("led2_od", 13, 1, BIT(22), "led"),
PIN_GRP_GPIO("led3_od", 14, 1, BIT(23), "led"),
};
static struct armada_37xx_pin_group armada_37xx_sb_groups[] = {
PIN_GRP_GPIO("usb32_drvvbus0", 0, 1, BIT(0), "drvbus"),
PIN_GRP_GPIO("usb2_drvvbus1", 1, 1, BIT(1), "drvbus"),
PIN_GRP_GPIO("sdio_sb", 24, 6, BIT(2), "sdio"),
PIN_GRP_GPIO("rgmii", 6, 12, BIT(3), "mii"),
PIN_GRP_GPIO("smi", 18, 2, BIT(4), "smi"),
PIN_GRP_GPIO("pcie1", 3, 3, BIT(5) | BIT(9) | BIT(10), "pcie"),
PIN_GRP_GPIO("ptp", 20, 3, BIT(11) | BIT(12) | BIT(13), "ptp"),
PIN_GRP("ptp_clk", 21, 1, BIT(6), "ptp", "mii"),
PIN_GRP("ptp_trig", 22, 1, BIT(7), "ptp", "mii"),
PIN_GRP_GPIO_3("mii_col", 23, 1, BIT(8) | BIT(14), 0, BIT(8), BIT(14),
"mii", "mii_err"),
};
const struct armada_37xx_pin_data armada_37xx_pin_nb = {
.nr_pins = 36,
.name = "GPIO1",
.groups = armada_37xx_nb_groups,
.ngroups = ARRAY_SIZE(armada_37xx_nb_groups),
};
const struct armada_37xx_pin_data armada_37xx_pin_sb = {
.nr_pins = 30,
.name = "GPIO2",
.groups = armada_37xx_sb_groups,
.ngroups = ARRAY_SIZE(armada_37xx_sb_groups),
};
static inline void armada_37xx_update_reg(unsigned int *reg,
unsigned int *offset)
{
/* We never have more than 2 registers */
if (*offset >= GPIO_PER_REG) {
*offset -= GPIO_PER_REG;
*reg += sizeof(u32);
}
}
static int armada_37xx_get_func_reg(struct armada_37xx_pin_group *grp,
const char *func)
{
int f;
for (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++)
if (!strcmp(grp->funcs[f], func))
return f;
return -ENOTSUPP;
}
static int armada_37xx_pmx_get_groups_count(struct udevice *dev)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
return info->ngroups;
}
static const char *armada_37xx_pmx_dummy_name = "_dummy";
static const char *armada_37xx_pmx_get_group_name(struct udevice *dev,
unsigned selector)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
if (!info->groups[selector].name)
return armada_37xx_pmx_dummy_name;
return info->groups[selector].name;
}
static int armada_37xx_pmx_get_funcs_count(struct udevice *dev)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
return info->nfuncs;
}
static const char *armada_37xx_pmx_get_func_name(struct udevice *dev,
unsigned selector)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
return info->funcs[selector].name;
}
static int armada_37xx_pmx_set_by_name(struct udevice *dev,
const char *name,
struct armada_37xx_pin_group *grp)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
unsigned int reg = SELECTION;
unsigned int mask = grp->reg_mask;
int func, val;
dev_dbg(info->dev, "enable function %s group %s\n",
name, grp->name);
func = armada_37xx_get_func_reg(grp, name);
if (func < 0)
return func;
val = grp->val[func];
clrsetbits_le32(info->base + reg, mask, val);
return 0;
}
static int armada_37xx_pmx_group_set(struct udevice *dev,
unsigned group_selector,
unsigned func_selector)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
struct armada_37xx_pin_group *grp = &info->groups[group_selector];
const char *name = info->funcs[func_selector].name;
return armada_37xx_pmx_set_by_name(dev, name, grp);
}
/**
* armada_37xx_add_function() - Add a new function to the list
* @funcs: array of function to add the new one
* @funcsize: size of the remaining space for the function
* @name: name of the function to add
*
* If it is a new function then create it by adding its name else
* increment the number of group associated to this function.
*/
static int armada_37xx_add_function(struct armada_37xx_pmx_func *funcs,
int *funcsize, const char *name)
{
int i = 0;
if (*funcsize <= 0)
return -EOVERFLOW;
while (funcs->ngroups) {
/* function already there */
if (strcmp(funcs->name, name) == 0) {
funcs->ngroups++;
return -EEXIST;
}
funcs++;
i++;
}
/* append new unique function */
funcs->name = name;
funcs->ngroups = 1;
(*funcsize)--;
return 0;
}
/**
* armada_37xx_fill_group() - complete the group array
* @info: info driver instance
*
* Based on the data available from the armada_37xx_pin_group array
* completes the last member of the struct for each function: the list
* of the groups associated to this function.
*
*/
static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info)
{
int n, num = 0, funcsize = info->data->nr_pins;
for (n = 0; n < info->ngroups; n++) {
struct armada_37xx_pin_group *grp = &info->groups[n];
int i, j, f;
grp->pins = devm_kzalloc(info->dev,
(grp->npins + grp->extra_npins) *
sizeof(*grp->pins), GFP_KERNEL);
if (!grp->pins)
return -ENOMEM;
for (i = 0; i < grp->npins; i++)
grp->pins[i] = grp->start_pin + i;
for (j = 0; j < grp->extra_npins; j++)
grp->pins[i+j] = grp->extra_pin + j;
for (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++) {
int ret;
/* check for unique functions and count groups */
ret = armada_37xx_add_function(info->funcs, &funcsize,
grp->funcs[f]);
if (ret == -EOVERFLOW)
dev_err(info->dev,
"More functions than pins(%d)\n",
info->data->nr_pins);
if (ret < 0)
continue;
num++;
}
}
info->nfuncs = num;
return 0;
}
/**
* armada_37xx_fill_funcs() - complete the funcs array
* @info: info driver instance
*
* Based on the data available from the armada_37xx_pin_group array
* completes the last two member of the struct for each group:
* - the list of the pins included in the group
* - the list of pinmux functions that can be selected for this group
*
*/
static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
{
struct armada_37xx_pmx_func *funcs = info->funcs;
int n;
for (n = 0; n < info->nfuncs; n++) {
const char *name = funcs[n].name;
const char **groups;
int g;
funcs[n].groups = devm_kzalloc(info->dev, funcs[n].ngroups *
sizeof(*(funcs[n].groups)),
GFP_KERNEL);
if (!funcs[n].groups)
return -ENOMEM;
groups = funcs[n].groups;
for (g = 0; g < info->ngroups; g++) {
struct armada_37xx_pin_group *gp = &info->groups[g];
int f;
for (f = 0; (f < NB_FUNCS) && gp->funcs[f]; f++) {
if (strcmp(gp->funcs[f], name) == 0) {
*groups = gp->name;
groups++;
}
}
}
}
return 0;
}
static int armada_37xx_gpio_get(struct udevice *dev, unsigned int offset)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
unsigned int reg = INPUT_VAL;
unsigned int val, mask;
armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
val = readl(info->base + reg);
return (val & mask) != 0;
}
static int armada_37xx_gpio_set(struct udevice *dev, unsigned int offset,
int value)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
unsigned int reg = OUTPUT_VAL;
unsigned int mask, val;
armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
val = value ? mask : 0;
clrsetbits_le32(info->base + reg, mask, val);
return 0;
}
static int armada_37xx_gpio_get_direction(struct udevice *dev,
unsigned int offset)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
unsigned int reg = OUTPUT_EN;
unsigned int val, mask;
armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
val = readl(info->base + reg);
if (val & mask)
return GPIOF_OUTPUT;
else
return GPIOF_INPUT;
}
static int armada_37xx_gpio_direction_input(struct udevice *dev,
unsigned int offset)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
unsigned int reg = OUTPUT_EN;
unsigned int mask;
armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
clrbits_le32(info->base + reg, mask);
return 0;
}
static int armada_37xx_gpio_direction_output(struct udevice *dev,
unsigned int offset, int value)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
unsigned int reg = OUTPUT_EN;
unsigned int mask;
armada_37xx_update_reg(&reg, &offset);
mask = BIT(offset);
setbits_le32(info->base + reg, mask);
/* And set the requested value */
return armada_37xx_gpio_set(dev, offset, value);
}
static int armada_37xx_gpio_probe(struct udevice *dev)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->bank_name = info->data->name;
uc_priv->gpio_count = info->data->nr_pins;
return 0;
}
static const struct dm_gpio_ops armada_37xx_gpio_ops = {
.set_value = armada_37xx_gpio_set,
.get_value = armada_37xx_gpio_get,
.get_function = armada_37xx_gpio_get_direction,
.direction_input = armada_37xx_gpio_direction_input,
.direction_output = armada_37xx_gpio_direction_output,
};
static struct driver armada_37xx_gpio_driver = {
.name = "armada-37xx-gpio",
.id = UCLASS_GPIO,
.probe = armada_37xx_gpio_probe,
.ops = &armada_37xx_gpio_ops,
};
static int armada_37xx_gpiochip_register(struct udevice *parent,
struct armada_37xx_pinctrl *info)
{
const void *blob = gd->fdt_blob;
int node = dev_of_offset(parent);
struct uclass_driver *drv;
struct udevice *dev;
int ret = -ENODEV;
int subnode;
char *name;
/* Lookup GPIO driver */
drv = lists_uclass_lookup(UCLASS_GPIO);
if (!drv) {
puts("Cannot find GPIO driver\n");
return -ENOENT;
}
fdt_for_each_subnode(subnode, blob, node) {
if (fdtdec_get_bool(blob, subnode, "gpio-controller")) {
ret = 0;
break;
}
};
if (ret)
return ret;
name = calloc(1, 32);
sprintf(name, "armada-37xx-gpio");
/* Create child device UCLASS_GPIO and bind it */
device_bind(parent, &armada_37xx_gpio_driver, name, NULL, subnode,
&dev);
dev_set_of_offset(dev, subnode);
return 0;
}
const struct pinctrl_ops armada_37xx_pinctrl_ops = {
.get_groups_count = armada_37xx_pmx_get_groups_count,
.get_group_name = armada_37xx_pmx_get_group_name,
.get_functions_count = armada_37xx_pmx_get_funcs_count,
.get_function_name = armada_37xx_pmx_get_func_name,
.pinmux_group_set = armada_37xx_pmx_group_set,
.set_state = pinctrl_generic_set_state,
};
int armada_37xx_pinctrl_probe(struct udevice *dev)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
const struct armada_37xx_pin_data *pin_data;
int ret;
info->data = (struct armada_37xx_pin_data *)dev_get_driver_data(dev);
pin_data = info->data;
info->base = (void __iomem *)devfdt_get_addr(dev);
if (!info->base) {
pr_err("unable to find regmap\n");
return -ENODEV;
}
info->groups = pin_data->groups;
info->ngroups = pin_data->ngroups;
/*
* we allocate functions for number of pins and hope there are
* fewer unique functions than pins available
*/
info->funcs = devm_kzalloc(info->dev, pin_data->nr_pins *
sizeof(struct armada_37xx_pmx_func), GFP_KERNEL);
if (!info->funcs)
return -ENOMEM;
ret = armada_37xx_fill_group(info);
if (ret)
return ret;
ret = armada_37xx_fill_func(info);
if (ret)
return ret;
ret = armada_37xx_gpiochip_register(dev, info);
if (ret)
return ret;
return 0;
}
static const struct udevice_id armada_37xx_pinctrl_of_match[] = {
{
.compatible = "marvell,armada3710-sb-pinctrl",
.data = (ulong)&armada_37xx_pin_sb,
},
{
.compatible = "marvell,armada3710-nb-pinctrl",
.data = (ulong)&armada_37xx_pin_nb,
},
{ /* sentinel */ }
};
U_BOOT_DRIVER(armada_37xx_pinctrl) = {
.name = "armada-37xx-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(armada_37xx_pinctrl_of_match),
.probe = armada_37xx_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct armada_37xx_pinctrl),
.ops = &armada_37xx_pinctrl_ops,
};
@@ -0,0 +1,233 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 Marvell International Ltd.
* https://spdx.org/licenses
*/
#include <common.h>
#include <config.h>
#include <fdtdec.h>
#include <errno.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <dm/root.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/arch-armada8k/soc-info.h>
#include "pinctrl-mvebu.h"
#define AP_EMMC_PHY_CTRL_REG 0x100
#define CP_EMMC_PHY_CTRL_REG 0x424
#define EMMC_PHY_CTRL_SDPHY_EN BIT(0)
#define AP806_EMMC_CLK_PIN_ID 0
#define AP806_EMMC_CLK_FUNC 0x1
#define CP110_EMMC_CLK_PIN_ID 56
#define CP110_EMMC_CLK_FUNC 0xe
DECLARE_GLOBAL_DATA_PTR;
/* mvebu_pinctl_emmc_set_mux: configure sd/mmc PHY mux
* To enable SDIO/eMMC in Armada-APN806/CP110, need to configure PHY mux.
* eMMC/SD PHY register responsible for muxing between MPPs and SD/eMMC
* controller:
* - Bit0 enabled SDIO/eMMC PHY is used as a MPP muxltiplexer,
* - Bit0 disabled SDIO/eMMC PHY is connected to SDIO/eMMC controller
* If pin function is set to eMMC/SD, then configure the eMMC/SD PHY
* muxltiplexer register to be on SDIO/eMMC controller
*/
void mvebu_pinctl_emmc_set_mux(struct udevice *dev, u32 pin, u32 func)
{
const void *blob = gd->fdt_blob;
int node = dev_of_offset(dev);
struct mvebu_pinctrl_priv *priv = dev_get_priv(dev);
if (!fdt_node_check_compatible(blob, node, "marvell,ap806-pinctrl")) {
if ((pin == AP806_EMMC_CLK_PIN_ID) &&
(func == AP806_EMMC_CLK_FUNC)) {
clrbits_le32(priv->base_reg + AP_EMMC_PHY_CTRL_REG,
EMMC_PHY_CTRL_SDPHY_EN);
}
} else if (!fdt_node_check_compatible(blob, node,
"marvell,armada-8k-cpm-pinctrl")) {
if ((pin == CP110_EMMC_CLK_PIN_ID) &&
(func == CP110_EMMC_CLK_FUNC)) {
clrbits_le32(priv->base_reg + CP_EMMC_PHY_CTRL_REG,
EMMC_PHY_CTRL_SDPHY_EN);
}
}
}
/*
* mvebu_pinctrl_set_state: configure pin functions.
* @dev: the pinctrl device to be configured.
* @config: the state to be configured.
* @return: 0 in success
*/
int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
const void *blob = gd->fdt_blob;
int node = dev_of_offset(config);
struct mvebu_pinctrl_priv *priv;
u32 pin_arr[MVEBU_MAX_PINS_PER_BANK];
u32 function;
int i, pin_count;
priv = dev_get_priv(dev);
pin_count = fdtdec_get_int_array_count(blob, node,
"marvell,pins",
pin_arr,
MVEBU_MAX_PINS_PER_BANK);
if (pin_count <= 0) {
debug("Failed reading pins array for pinconfig %s (%d)\n",
config->name, pin_count);
return -EINVAL;
}
function = fdtdec_get_int(blob, node, "marvell,function", 0xff);
/*
* Check if setup of PHY mux is needed for this pins group.
* Only the first pin id in array is tested, all the rest use the same
* pin function.
*/
mvebu_pinctl_emmc_set_mux(dev, pin_arr[0], function);
for (i = 0; i < pin_count; i++) {
int reg_offset;
int field_offset;
int pin = pin_arr[i];
if (function > priv->max_func) {
debug("Illegal function %d for pinconfig %s\n",
function, config->name);
return -EINVAL;
}
/* Calculate register address and bit in register */
reg_offset = priv->reg_direction * 4 *
(pin >> (PIN_REG_SHIFT));
field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
clrsetbits_le32(priv->base_reg + reg_offset,
PIN_FUNC_MASK << field_offset,
(function & PIN_FUNC_MASK) << field_offset);
}
return 0;
}
/*
* mvebu_pinctrl_set_state_all: configure the entire bank pin functions.
* @dev: the pinctrl device to be configured.
* @config: the state to be configured.
* @return: 0 in success
*/
static int mvebu_pinctrl_set_state_all(struct udevice *dev,
struct udevice *config)
{
const void *blob = gd->fdt_blob;
int node = dev_of_offset(config);
struct mvebu_pinctrl_priv *priv;
u32 func_arr[MVEBU_MAX_PINS_PER_BANK];
int pin, err;
priv = dev_get_priv(dev);
err = fdtdec_get_int_array(blob, node, "pin-func",
func_arr, priv->pin_cnt);
if (err) {
debug("Failed reading pin functions for bank %s\n",
priv->bank_name);
return -EINVAL;
}
/* Check if setup of PHY mux is needed for this pins group. */
if (priv->pin_cnt < CP110_EMMC_CLK_PIN_ID)
mvebu_pinctl_emmc_set_mux(dev, AP806_EMMC_CLK_PIN_ID,
func_arr[AP806_EMMC_CLK_PIN_ID]);
else
mvebu_pinctl_emmc_set_mux(dev, CP110_EMMC_CLK_PIN_ID,
func_arr[CP110_EMMC_CLK_PIN_ID]);
for (pin = 0; pin < priv->pin_cnt; pin++) {
int reg_offset;
int field_offset;
u32 func = func_arr[pin];
/* Bypass pins with function 0xFF */
if (func == 0xff) {
debug("Warning: pin %d value is not modified ", pin);
debug("(kept as default)\n");
continue;
} else if (func > priv->max_func) {
debug("Illegal function %d for pin %d\n", func, pin);
return -EINVAL;
}
/* Calculate register address and bit in register */
reg_offset = priv->reg_direction * 4 *
(pin >> (PIN_REG_SHIFT));
field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
clrsetbits_le32(priv->base_reg + reg_offset,
PIN_FUNC_MASK << field_offset,
(func & PIN_FUNC_MASK) << field_offset);
}
return 0;
}
int mvebu_pinctl_probe(struct udevice *dev)
{
const void *blob = gd->fdt_blob;
int node = dev_of_offset(dev);
struct mvebu_pinctrl_priv *priv;
priv = dev_get_priv(dev);
if (!priv) {
debug("%s: Failed to get private\n", __func__);
return -EINVAL;
}
priv->base_reg = devfdt_get_addr_ptr(dev);
if (priv->base_reg == (void *)FDT_ADDR_T_NONE) {
debug("%s: Failed to get base address\n", __func__);
return -EINVAL;
}
priv->pin_cnt = fdtdec_get_int(blob, node, "pin-count",
MVEBU_MAX_PINS_PER_BANK);
priv->max_func = fdtdec_get_int(blob, node, "max-func",
MVEBU_MAX_FUNC);
priv->bank_name = fdt_getprop(blob, node, "bank-name", NULL);
priv->reg_direction = 1;
if (fdtdec_get_bool(blob, node, "reverse-reg"))
priv->reg_direction = -1;
return mvebu_pinctrl_set_state_all(dev, dev);
}
static struct pinctrl_ops mvebu_pinctrl_ops = {
.set_state = mvebu_pinctrl_set_state
};
static const struct udevice_id mvebu_pinctrl_ids[] = {
{ .compatible = "marvell,mvebu-pinctrl" },
{ .compatible = "marvell,ap806-pinctrl" },
{ .compatible = "marvell,armada-7k-pinctrl" },
{ .compatible = "marvell,armada-8k-cpm-pinctrl" },
{ .compatible = "marvell,armada-8k-cps-pinctrl" },
{ }
};
U_BOOT_DRIVER(pinctrl_mvebu) = {
.name = "mvebu_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = mvebu_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct mvebu_pinctrl_priv),
.ops = &mvebu_pinctrl_ops,
.probe = mvebu_pinctl_probe
};
@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2016 Marvell International Ltd.
* https://spdx.org/licenses
*/
#ifndef __PINCTRL_MVEBU_H_
#define __PINCTRL_MVEBU_H_
#define MVEBU_MAX_PINCTL_BANKS 4
#define MVEBU_MAX_PINS_PER_BANK 100
#define MVEBU_MAX_FUNC 0xF
/*
* struct mvebu_pin_bank_data: mvebu-pinctrl bank data
* @base_reg: controller base address for this bank
* @pin_cnt: number of pins included in this bank
* @max_func: maximum configurable function value for pins in this bank
* @reg_direction:
* @bank_name: the pin's bank name
*/
struct mvebu_pinctrl_priv {
void *base_reg;
uint pin_cnt;
uint max_func;
int reg_direction;
const char *bank_name;
};
#endif /* __PINCTRL_MVEBU_H_ */
@@ -0,0 +1,114 @@
config PINCTRL_IMX
bool
config PINCTRL_IMX_SCU
bool
config PINCTRL_IMX5
bool "IMX5 pinctrl driver"
depends on ARCH_MX5 && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
help
Say Y here to enable the imx5 pinctrl driver
This provides a simple pinctrl driver for i.MX 53SoC familiy,
i.MX53. This feature depends on device tree
configuration. This driver is different from the linux one,
this is a simple implementation, only parses the 'fsl,pins'
property and configure related registers.
config PINCTRL_IMX6
bool "IMX6 pinctrl driver"
depends on ARCH_MX6 && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
help
Say Y here to enable the imx6 pinctrl driver
This provides a simple pinctrl driver for i.MX6 SoC familiy,
i.MX6DQ/SL/SX/UL/DQP. This feature depends on device tree
configuration. This driver is different from the linux one,
this is a simple implementation, only parses the 'fsl,pins'
property and configure related registers.
config PINCTRL_IMX7
bool "IMX7 pinctrl driver"
depends on ARCH_MX7 && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
help
Say Y here to enable the imx7 pinctrl driver
This provides a simple pinctrl driver for i.MX7 SoC familiy,
i.MX7D. This feature depends on device tree
configuration. This driver is different from the linux one,
this is a simple implementation, only parses the 'fsl,pins'
property and configure related registers.
config PINCTRL_IMX7ULP
bool "IMX7ULP pinctrl driver"
depends on ARCH_MX7ULP && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
help
Say Y here to enable the imx7ulp pinctrl driver
This provides a simple pinctrl driver for i.MX7ULP SoC familiy.
This feature depends on device tree configuration. This driver
is different from the linux one, this is a simple implementation,
only parses the 'fsl,pins' property and configure related
registers.
config PINCTRL_IMX8
bool "IMX8 pinctrl driver"
depends on ARCH_IMX8 && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
select PINCTRL_IMX_SCU
help
Say Y here to enable the imx8 pinctrl driver
This provides a simple pinctrl driver for i.MX8 SoC familiy.
This feature depends on device tree configuration. This driver
is different from the linux one, this is a simple implementation,
only parses the 'fsl,pins' property and configures related
registers.
config PINCTRL_IMX8M
bool "IMX8M pinctrl driver"
depends on ARCH_IMX8M && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
help
Say Y here to enable the imx8m pinctrl driver
This provides a simple pinctrl driver for i.MX8M SoC familiy.
This feature depends on device tree configuration. This driver
is different from the linux one, this is a simple implementation,
only parses the 'fsl,pins' property and configure related
registers.
config PINCTRL_MXS
bool "NXP MXS pinctrl driver"
depends on ARCH_MX28 && PINCTRL_FULL
help
Say Y here to enable the i.MX mxs pinctrl driver
This option provides a simple pinctrl driver for i.MX mxs SoC
familiy, e.g. i.MX28. This feature depends on device tree
configuration.
config PINCTRL_VYBRID
bool "Vybrid (vf610) pinctrl driver"
depends on ARCH_VF610 && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
help
Say Y here to enable the Vybrid (vf610) pinctrl driver
This provides a simple pinctrl driver for Vybrid SoC familiy,
vf610. This feature depends on device tree
configuration. This driver is different from the linux one,
this is a simple implementation, only parses the 'fsl,pins'
property and configure related registers.
@@ -0,0 +1,10 @@
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
obj-$(CONFIG_PINCTRL_IMX5) += pinctrl-imx5.o
obj-$(CONFIG_PINCTRL_IMX6) += pinctrl-imx6.o
obj-$(CONFIG_PINCTRL_IMX7) += pinctrl-imx7.o
obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o
obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o
obj-$(CONFIG_PINCTRL_IMX8) += pinctrl-imx8.o
obj-$(CONFIG_PINCTRL_IMX8M) += pinctrl-imx8m.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_VYBRID) += pinctrl-vf610.o
@@ -0,0 +1,269 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
*/
#include <common.h>
#include <mapmem.h>
#include <linux/io.h>
#include <linux/err.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
DECLARE_GLOBAL_DATA_PTR;
static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
struct imx_pinctrl_priv *priv = dev_get_priv(dev);
struct imx_pinctrl_soc_info *info = priv->info;
int node = dev_of_offset(config);
const struct fdt_property *prop;
u32 *pin_data;
int npins, size, pin_size;
int mux_reg, conf_reg, input_reg;
u32 input_val, mux_mode, config_val;
u32 mux_shift = info->mux_mask ? ffs(info->mux_mask) - 1 : 0;
int i, j = 0;
dev_dbg(dev, "%s: %s\n", __func__, config->name);
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;
prop = fdt_getprop(gd->fdt_blob, node, "fsl,pins", &size);
if (!prop) {
dev_err(dev, "No fsl,pins property in node %s\n", config->name);
return -EINVAL;
}
if (!size || size % pin_size) {
dev_err(dev, "Invalid fsl,pins property in node %s\n",
config->name);
return -EINVAL;
}
pin_data = devm_kzalloc(dev, size, 0);
if (!pin_data)
return -ENOMEM;
if (fdtdec_get_int_array(gd->fdt_blob, node, "fsl,pins",
pin_data, size >> 2)) {
dev_err(dev, "Error reading pin data.\n");
devm_kfree(dev, pin_data);
return -EINVAL;
}
npins = size / pin_size;
if (info->flags & IMX8_USE_SCU) {
imx_pinctrl_scu_conf_pins(info, pin_data, npins);
} else {
/*
* Refer to linux documentation for details:
* Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
*/
for (i = 0; i < npins; i++) {
mux_reg = pin_data[j++];
if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
mux_reg = -1;
if (info->flags & SHARE_MUX_CONF_REG) {
conf_reg = mux_reg;
} else {
conf_reg = pin_data[j++];
if (!(info->flags & ZERO_OFFSET_VALID) &&
!conf_reg)
conf_reg = -1;
}
if ((mux_reg == -1) || (conf_reg == -1)) {
dev_err(dev, "Error mux_reg or conf_reg\n");
devm_kfree(dev, pin_data);
return -EINVAL;
}
input_reg = pin_data[j++];
mux_mode = pin_data[j++];
input_val = pin_data[j++];
config_val = pin_data[j++];
dev_dbg(dev, "mux_reg 0x%x, conf_reg 0x%x, "
"input_reg 0x%x, mux_mode 0x%x, "
"input_val 0x%x, config_val 0x%x\n",
mux_reg, conf_reg, input_reg, mux_mode,
input_val, config_val);
if (config_val & IMX_PAD_SION)
mux_mode |= IOMUXC_CONFIG_SION;
config_val &= ~IMX_PAD_SION;
/* Set Mux */
if (info->flags & SHARE_MUX_CONF_REG) {
clrsetbits_le32(info->base + mux_reg,
info->mux_mask,
mux_mode << mux_shift);
} else {
writel(mux_mode, info->base + mux_reg);
}
dev_dbg(dev, "write mux: offset 0x%x val 0x%x\n",
mux_reg, mux_mode);
/*
* Set select input
*
* If the select input value begins with 0xff,
* it's a quirky select input and the value should
* be interpreted as below.
* 31 23 15 7 0
* | 0xff | shift | width | select |
* It's used to work around the problem that the
* select input for some pin is not implemented in
* the select input register but in some general
* purpose register. We encode the select input
* value, width and shift of the bit field into
* input_val cell of pin function ID in device tree,
* and then decode them here for setting up the select
* input bits in general purpose register.
*/
if (input_val >> 24 == 0xff) {
u32 val = input_val;
u8 select = val & 0xff;
u8 width = (val >> 8) & 0xff;
u8 shift = (val >> 16) & 0xff;
u32 mask = ((1 << width) - 1) << shift;
/*
* The input_reg[i] here is actually some
* IOMUXC general purpose register, not
* regular select input register.
*/
val = readl(info->base + input_reg);
val &= ~mask;
val |= select << shift;
writel(val, info->base + input_reg);
} else if (input_reg) {
/*
* Regular select input register can never be
* at offset 0, and we only print register
* value for regular case.
*/
if (info->input_sel_base)
writel(input_val,
info->input_sel_base +
input_reg);
else
writel(input_val,
info->base + input_reg);
dev_dbg(dev, "select_input: offset 0x%x val "
"0x%x\n", input_reg, input_val);
}
/* Set config */
if (!(config_val & IMX_NO_PAD_CTL)) {
if (info->flags & SHARE_MUX_CONF_REG) {
clrsetbits_le32(info->base + conf_reg,
~info->mux_mask,
config_val);
} else {
writel(config_val,
info->base + conf_reg);
}
dev_dbg(dev, "write config: offset 0x%x val "
"0x%x\n", conf_reg, config_val);
}
}
}
devm_kfree(dev, pin_data);
return 0;
}
const struct pinctrl_ops imx_pinctrl_ops = {
.set_state = imx_pinctrl_set_state,
};
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;
struct fdtdec_phandle_args arg;
fdt_addr_t addr;
fdt_size_t size;
if (!info) {
dev_err(dev, "wrong pinctrl info\n");
return -EINVAL;
}
priv->dev = dev;
priv->info = info;
if (info->flags & IMX8_USE_SCU)
return 0;
addr = devfdt_get_addr_size_index(dev, 0, &size);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
info->base = map_sysmem(addr, size);
if (!info->base)
return -ENOMEM;
priv->info = info;
info->mux_mask = fdtdec_get_int(gd->fdt_blob, node, "fsl,mux_mask", 0);
/*
* Refer to linux documentation for details:
* Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt
*/
if (fdtdec_get_bool(gd->fdt_blob, node, "fsl,input-sel")) {
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
node, "fsl,input-sel",
NULL, 0, 0, &arg);
if (ret) {
dev_err(dev, "iomuxc fsl,input-sel property not found\n");
return -EINVAL;
}
addr = fdtdec_get_addr_size(gd->fdt_blob, arg.node, "reg",
&size);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
info->input_sel_base = map_sysmem(addr, size);
if (!info->input_sel_base)
return -ENOMEM;
}
dev_dbg(dev, "initialized IMX pinctrl driver\n");
return 0;
}
int imx_pinctrl_remove(struct udevice *dev)
{
struct imx_pinctrl_priv *priv = dev_get_priv(dev);
struct imx_pinctrl_soc_info *info = priv->info;
if (info->flags & IMX8_USE_SCU)
return 0;
if (info->input_sel_base)
unmap_sysmem(info->input_sel_base);
if (info->base)
unmap_sysmem(info->base);
return 0;
}
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
*/
#ifndef __DRIVERS_PINCTRL_IMX_H
#define __DRIVERS_PINCTRL_IMX_H
/**
* @base: the address to the controller in virtual memory
* @input_sel_base: the address of the select input in virtual memory.
* @flags: flags specific for each soc
* @mux_mask: Used when SHARE_MUX_CONF_REG flag is added
*/
struct imx_pinctrl_soc_info {
void __iomem *base;
void __iomem *input_sel_base;
unsigned int flags;
unsigned int mux_mask;
};
/**
* @dev: a pointer back to containing device
* @info: the soc info
*/
struct imx_pinctrl_priv {
struct udevice *dev;
struct imx_pinctrl_soc_info *info;
};
extern const struct pinctrl_ops imx_pinctrl_ops;
#define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */
#define IMX_PAD_SION 0x40000000 /* set SION */
/*
* Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
* 1 u32 CONFIG, so 24 types in total for each pin.
*/
#define FSL_PIN_SIZE 24
#define SHARE_FSL_PIN_SIZE 20
/* Each pin on imx8qm/qxp consists of 2 u32 PIN_FUNC_ID and 1 u32 CONFIG */
#define SHARE_IMX8_PIN_SIZE 12
#define SHARE_MUX_CONF_REG 0x1
#define ZERO_OFFSET_VALID 0x2
#define CONFIG_IBE_OBE 0x4
#define IMX8_USE_SCU 0x8
#define IOMUXC_CONFIG_SION (0x1 << 4)
int imx_pinctrl_probe(struct udevice *dev, struct imx_pinctrl_soc_info *info);
int imx_pinctrl_remove(struct udevice *dev);
#ifdef CONFIG_PINCTRL_IMX_SCU
int imx_pinctrl_scu_conf_pins(struct imx_pinctrl_soc_info *info,
u32 *pin_data, int npins);
#else
static inline int imx_pinctrl_scu_conf_pins(struct imx_pinctrl_soc_info *info,
u32 *pin_data, int npins)
{
return 0;
}
#endif
#endif /* __DRIVERS_PINCTRL_IMX_H */
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
static struct imx_pinctrl_soc_info imx5_pinctrl_soc_info;
static int imx5_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id imx5_pinctrl_match[] = {
{
.compatible = "fsl,imx53-iomuxc",
.data = (ulong)&imx5_pinctrl_soc_info
},
{
.compatible = "fsl,imx53-iomuxc-gpr",
.data = (ulong)&imx5_pinctrl_soc_info
},
{ /* sentinel */ }
};
U_BOOT_DRIVER(imx5_pinctrl) = {
.name = "imx5-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(imx5_pinctrl_match),
.probe = imx5_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
static struct imx_pinctrl_soc_info imx6_pinctrl_soc_info __section(".data");
/* FIXME Before reloaction, BSS is overlapped with DT area */
static struct imx_pinctrl_soc_info imx6ul_pinctrl_soc_info = {
.flags = ZERO_OFFSET_VALID,
};
static struct imx_pinctrl_soc_info imx6_snvs_pinctrl_soc_info = {
.flags = ZERO_OFFSET_VALID,
};
static int imx6_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id imx6_pinctrl_match[] = {
{ .compatible = "fsl,imx6q-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
{ .compatible = "fsl,imx6dl-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
{ .compatible = "fsl,imx6sl-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
{ .compatible = "fsl,imx6sll-iomuxc-snvs", .data = (ulong)&imx6_snvs_pinctrl_soc_info },
{ .compatible = "fsl,imx6sll-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
{ .compatible = "fsl,imx6sx-iomuxc", .data = (ulong)&imx6_pinctrl_soc_info },
{ .compatible = "fsl,imx6ul-iomuxc", .data = (ulong)&imx6ul_pinctrl_soc_info },
{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = (ulong)&imx6_snvs_pinctrl_soc_info },
{ /* sentinel */ }
};
U_BOOT_DRIVER(imx6_pinctrl) = {
.name = "imx6-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(imx6_pinctrl_match),
.probe = imx6_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
static struct imx_pinctrl_soc_info imx7_pinctrl_soc_info;
static struct imx_pinctrl_soc_info imx7_lpsr_pinctrl_soc_info = {
.flags = ZERO_OFFSET_VALID,
};
static int imx7_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id imx7_pinctrl_match[] = {
{ .compatible = "fsl,imx7d-iomuxc", .data = (ulong)&imx7_pinctrl_soc_info },
{ .compatible = "fsl,imx7d-iomuxc-lpsr", .data = (ulong)&imx7_lpsr_pinctrl_soc_info },
{ /* sentinel */ }
};
U_BOOT_DRIVER(imx7_pinctrl) = {
.name = "imx7-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(imx7_pinctrl_match),
.probe = imx7_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
*
* Peng Fan <peng.fan@nxp.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
static struct imx_pinctrl_soc_info imx7ulp_pinctrl_soc_info0 = {
.flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CONFIG_IBE_OBE,
};
static struct imx_pinctrl_soc_info imx7ulp_pinctrl_soc_info1 = {
.flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CONFIG_IBE_OBE,
};
static int imx7ulp_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id imx7ulp_pinctrl_match[] = {
{ .compatible = "fsl,imx7ulp-iomuxc-0", .data = (ulong)&imx7ulp_pinctrl_soc_info0 },
{ .compatible = "fsl,imx7ulp-iomuxc-1", .data = (ulong)&imx7ulp_pinctrl_soc_info1 },
{ /* sentinel */ }
};
U_BOOT_DRIVER(imx7ulp_pinctrl) = {
.name = "imx7ulp-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(imx7ulp_pinctrl_match),
.probe = imx7ulp_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 NXP
*/
#include <common.h>
#include <dm/device.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
DECLARE_GLOBAL_DATA_PTR;
static struct imx_pinctrl_soc_info imx8_pinctrl_soc_info = {
.flags = IMX8_USE_SCU,
};
static int imx8_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id imx8_pinctrl_match[] = {
{ .compatible = "fsl,imx8qxp-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
{ .compatible = "fsl,imx8qm-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
{ /* sentinel */ }
};
U_BOOT_DRIVER(imx8_pinctrl) = {
.name = "imx8_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(imx8_pinctrl_match),
.probe = imx8_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2019 NXP
*/
#include <dm/device.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
static struct imx_pinctrl_soc_info imx8mq_pinctrl_soc_info;
static int imx8mq_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id imx8m_pinctrl_match[] = {
{ .compatible = "fsl,imx8mq-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info },
{ .compatible = "fsl,imx8mm-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info },
{ .compatible = "fsl,imx8mn-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info },
{ /* sentinel */ }
};
U_BOOT_DRIVER(imx8mq_pinctrl) = {
.name = "imx8mq-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(imx8m_pinctrl_match),
.probe = imx8mq_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
@@ -0,0 +1,190 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 DENX Software Engineering
* Lukasz Majewski, DENX Software Engineering, lukma@denx.de
*/
#include <common.h>
#include <linux/io.h>
#include <linux/err.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <dm/read.h>
#include "pinctrl-mxs.h"
DECLARE_GLOBAL_DATA_PTR;
struct mxs_pinctrl_priv {
void __iomem *base;
const struct mxs_regs *regs;
};
static unsigned long mxs_dt_node_to_map(struct udevice *conf)
{
unsigned long config = 0;
int ret;
u32 val;
ret = dev_read_u32(conf, "fsl,drive-strength", &val);
if (!ret)
config = val | MA_PRESENT;
ret = dev_read_u32(conf, "fsl,voltage", &val);
if (!ret)
config |= val << VOL_SHIFT | VOL_PRESENT;
ret = dev_read_u32(conf, "fsl,pull-up", &val);
if (!ret)
config |= val << PULL_SHIFT | PULL_PRESENT;
return config;
}
static int mxs_pinctrl_set_mux(struct udevice *dev, u32 val, int bank, int pin)
{
struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
int muxsel = MUXID_TO_MUXSEL(val), shift;
void __iomem *reg;
reg = iomux->base + iomux->regs->muxsel;
reg += bank * 0x20 + pin / 16 * 0x10;
shift = pin % 16 * 2;
mxs_pinctrl_rmwl(muxsel, 0x3, shift, reg);
debug(" mux %d,", muxsel);
return 0;
}
static int mxs_pinctrl_set_state(struct udevice *dev, struct udevice *conf)
{
struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
u32 *pin_data, val, ma, vol, pull;
int npins, size, i, ret;
unsigned long config;
debug("\n%s: set state: %s\n", __func__, conf->name);
size = dev_read_size(conf, "fsl,pinmux-ids");
if (size < 0)
return size;
if (!size || size % sizeof(int)) {
dev_err(dev, "Invalid fsl,pinmux-ids property in %s\n",
conf->name);
return -EINVAL;
}
npins = size / sizeof(int);
pin_data = devm_kzalloc(dev, size, 0);
if (!pin_data)
return -ENOMEM;
ret = dev_read_u32_array(conf, "fsl,pinmux-ids", pin_data, npins);
if (ret) {
dev_err(dev, "Error reading pin data.\n");
devm_kfree(dev, pin_data);
return -EINVAL;
}
config = mxs_dt_node_to_map(conf);
ma = CONFIG_TO_MA(config);
vol = CONFIG_TO_VOL(config);
pull = CONFIG_TO_PULL(config);
for (i = 0; i < npins; i++) {
int pinid, bank, pin, shift;
void __iomem *reg;
val = pin_data[i];
pinid = MUXID_TO_PINID(val);
bank = PINID_TO_BANK(pinid);
pin = PINID_TO_PIN(pinid);
debug("(val: 0x%x) pin %d,", val, pinid);
/* Setup pinmux */
mxs_pinctrl_set_mux(dev, val, bank, pin);
debug(" ma: %d, vol: %d, pull: %d\n", ma, vol, pull);
/* drive */
reg = iomux->base + iomux->regs->drive;
reg += bank * 0x40 + pin / 8 * 0x10;
/* mA */
if (config & MA_PRESENT) {
shift = pin % 8 * 4;
mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
}
/* vol */
if (config & VOL_PRESENT) {
shift = pin % 8 * 4 + 2;
if (vol)
writel(1 << shift, reg + SET);
else
writel(1 << shift, reg + CLR);
}
/* pull */
if (config & PULL_PRESENT) {
reg = iomux->base + iomux->regs->pull;
reg += bank * 0x10;
shift = pin;
if (pull)
writel(1 << shift, reg + SET);
else
writel(1 << shift, reg + CLR);
}
}
devm_kfree(dev, pin_data);
return 0;
}
static struct pinctrl_ops mxs_pinctrl_ops = {
.set_state = mxs_pinctrl_set_state,
};
static int mxs_pinctrl_probe(struct udevice *dev)
{
struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
iomux->base = dev_read_addr_ptr(dev);
iomux->regs = (struct mxs_regs *)dev_get_driver_data(dev);
return 0;
}
static const struct mxs_regs imx23_regs = {
.muxsel = 0x100,
.drive = 0x200,
.pull = 0x400,
};
static const struct mxs_regs imx28_regs = {
.muxsel = 0x100,
.drive = 0x300,
.pull = 0x600,
};
static const struct udevice_id mxs_pinctrl_match[] = {
{ .compatible = "fsl,imx23-pinctrl", .data = (ulong)&imx23_regs },
{ .compatible = "fsl,imx28-pinctrl", .data = (ulong)&imx28_regs },
{ /* sentinel */ }
};
U_BOOT_DRIVER(mxs_pinctrl) = {
.name = "mxs-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(mxs_pinctrl_match),
.probe = mxs_pinctrl_probe,
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.bind = dm_scan_fdt_dev,
#endif
.priv_auto_alloc_size = sizeof(struct mxs_pinctrl_priv),
.ops = &mxs_pinctrl_ops,
};
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*/
#ifndef __PINCTRL_MXS_H
#define __PINCTRL_MXS_H
#include <dm/pinctrl.h>
#define SET 0x4
#define CLR 0x8
#define TOG 0xc
#define MXS_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
#define PINID(bank, pin) ((bank) * 32 + (pin))
/*
* pinmux-id bit field definitions
*
* bank: 15..12 (4)
* pin: 11..4 (8)
* muxsel: 3..0 (4)
*/
#define MUXID_TO_PINID(m) PINID((m) >> 12 & 0xf, (m) >> 4 & 0xff)
#define MUXID_TO_MUXSEL(m) ((m) & 0xf)
#define PINID_TO_BANK(p) ((p) >> 5)
#define PINID_TO_PIN(p) ((p) % 32)
/*
* pin config bit field definitions
*
* pull-up: 6..5 (2)
* voltage: 4..3 (2)
* mA: 2..0 (3)
*
* MSB of each field is presence bit for the config.
*/
#define PULL_PRESENT (1 << 6)
#define PULL_SHIFT 5
#define VOL_PRESENT (1 << 4)
#define VOL_SHIFT 3
#define MA_PRESENT (1 << 2)
#define MA_SHIFT 0
#define CONFIG_TO_PULL(c) ((c) >> PULL_SHIFT & 0x1)
#define CONFIG_TO_VOL(c) ((c) >> VOL_SHIFT & 0x1)
#define CONFIG_TO_MA(c) ((c) >> MA_SHIFT & 0x3)
struct mxs_regs {
u16 muxsel;
u16 drive;
u16 pull;
};
static inline void mxs_pinctrl_rmwl(u32 value, u32 mask, u8 shift,
void __iomem *reg)
{
clrsetbits_le32(reg, mask << shift, value << shift);
}
#endif /* __PINCTRL_MXS_H */
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 NXP
*/
#include <common.h>
#include <errno.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/arch/sci/sci.h>
#include <misc.h>
#include "pinctrl-imx.h"
#define PADRING_IFMUX_EN_SHIFT 31
#define PADRING_IFMUX_EN_MASK BIT(31)
#define PADRING_GP_EN_SHIFT 30
#define PADRING_GP_EN_MASK BIT(30)
#define PADRING_IFMUX_SHIFT 27
#define PADRING_IFMUX_MASK GENMASK(29, 27)
static int imx_pinconf_scu_set(struct imx_pinctrl_soc_info *info, u32 pad,
u32 mux, u32 val)
{
int ret;
/*
* Mux should be done in pmx set, but we do not have a good api
* to handle that in scfw, so config it in pad conf func
*/
val |= PADRING_IFMUX_EN_MASK;
val |= PADRING_GP_EN_MASK;
val |= (mux << PADRING_IFMUX_SHIFT) & PADRING_IFMUX_MASK;
ret = sc_pad_set(-1, pad, val);
if (ret)
printf("%s %d\n", __func__, ret);
return 0;
}
int imx_pinctrl_scu_conf_pins(struct imx_pinctrl_soc_info *info, u32 *pin_data,
int npins)
{
int pin_id, mux, config_val;
int i, j = 0;
int ret;
/*
* Refer to linux documentation for details:
* Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
*/
for (i = 0; i < npins; i++) {
pin_id = pin_data[j++];
mux = pin_data[j++];
config_val = pin_data[j++];
ret = imx_pinconf_scu_set(info, pin_id, mux, config_val);
if (ret)
printf("Set pin %d, mux %d, val %d, error\n", pin_id,
mux, config_val);
}
return 0;
}
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 DENX Software Engineering
* Lukasz Majewski, DENX Software Engineering, lukma@denx.de
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
static struct imx_pinctrl_soc_info vf610_pinctrl_soc_info = {
.flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID,
};
static int vf610_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id vf610_pinctrl_match[] = {
{ .compatible = "fsl,vf610-iomuxc",
.data = (ulong)&vf610_pinctrl_soc_info },
{ /* sentinel */ }
};
U_BOOT_DRIVER(vf610_pinctrl) = {
.name = "vf610-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(vf610_pinctrl_match),
.probe = vf610_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
@@ -0,0 +1,181 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Atmel PIO4 pinctrl driver
*
* Copyright (C) 2016 Atmel Corporation
* Wenyou.Yang <wenyou.yang@atmel.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <linux/io.h>
#include <linux/err.h>
#include <mach/atmel_pio4.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* Warning:
* In order to not introduce confusion between Atmel PIO groups and pinctrl
* framework groups, Atmel PIO groups will be called banks.
*/
struct atmel_pio4_platdata {
struct atmel_pio4_port *reg_base;
};
static const struct pinconf_param conf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
{ "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
};
static u32 atmel_pinctrl_get_pinconf(const void *blob, int node)
{
const struct pinconf_param *params;
u32 param, arg, conf = 0;
u32 i;
for (i = 0; i < ARRAY_SIZE(conf_params); i++) {
params = &conf_params[i];
if (!fdt_get_property(blob, node, params->property, NULL))
continue;
param = params->param;
arg = params->default_value;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
conf &= (~ATMEL_PIO_PUEN_MASK);
conf &= (~ATMEL_PIO_PDEN_MASK);
break;
case PIN_CONFIG_BIAS_PULL_UP:
conf |= ATMEL_PIO_PUEN_MASK;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
conf |= ATMEL_PIO_PDEN_MASK;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
if (arg == 0)
conf &= (~ATMEL_PIO_OPD_MASK);
else
conf |= ATMEL_PIO_OPD_MASK;
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
if (arg == 0)
conf |= ATMEL_PIO_SCHMITT_MASK;
else
conf &= (~ATMEL_PIO_SCHMITT_MASK);
break;
case PIN_CONFIG_INPUT_DEBOUNCE:
if (arg == 0) {
conf &= (~ATMEL_PIO_IFEN_MASK);
conf &= (~ATMEL_PIO_IFSCEN_MASK);
} else {
conf |= ATMEL_PIO_IFEN_MASK;
conf |= ATMEL_PIO_IFSCEN_MASK;
}
break;
default:
printf("%s: Unsupported configuration parameter: %u\n",
__func__, param);
break;
}
}
return conf;
}
static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
u32 bank)
{
struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
struct atmel_pio4_port *bank_base =
(struct atmel_pio4_port *)((u32)plat->reg_base +
ATMEL_PIO_BANK_OFFSET * bank);
return bank_base;
}
#define MAX_PINMUX_ENTRIES 40
static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
struct atmel_pio4_port *bank_base;
const void *blob = gd->fdt_blob;
int node = dev_of_offset(config);
u32 offset, func, bank, line;
u32 cells[MAX_PINMUX_ENTRIES];
u32 i, conf;
int count;
conf = atmel_pinctrl_get_pinconf(blob, node);
count = fdtdec_get_int_array_count(blob, node, "pinmux",
cells, ARRAY_SIZE(cells));
if (count < 0) {
printf("%s: bad pinmux array %d\n", __func__, count);
return -EINVAL;
}
if (count > MAX_PINMUX_ENTRIES) {
printf("%s: unsupported pinmux array count %d\n",
__func__, count);
return -EINVAL;
}
for (i = 0 ; i < count; i++) {
offset = ATMEL_GET_PIN_NO(cells[i]);
func = ATMEL_GET_PIN_FUNC(cells[i]);
bank = ATMEL_PIO_BANK(offset);
line = ATMEL_PIO_LINE(offset);
bank_base = atmel_pio4_bank_base(dev, bank);
writel(BIT(line), &bank_base->mskr);
conf &= (~ATMEL_PIO_CFGR_FUNC_MASK);
conf |= (func & ATMEL_PIO_CFGR_FUNC_MASK);
writel(conf, &bank_base->cfgr);
}
return 0;
}
const struct pinctrl_ops atmel_pinctrl_ops = {
.set_state = atmel_pinctrl_set_state,
};
static int atmel_pinctrl_probe(struct udevice *dev)
{
struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
fdt_addr_t addr_base;
dev = dev_get_parent(dev);
addr_base = devfdt_get_addr(dev);
if (addr_base == FDT_ADDR_T_NONE)
return -EINVAL;
plat->reg_base = (struct atmel_pio4_port *)addr_base;
return 0;
}
static const struct udevice_id atmel_pinctrl_match[] = {
{ .compatible = "atmel,sama5d2-pinctrl" },
{}
};
U_BOOT_DRIVER(atmel_pinctrl) = {
.name = "pinctrl_atmel_pio4",
.id = UCLASS_PINCTRL,
.of_match = atmel_pinctrl_match,
.probe = atmel_pinctrl_probe,
.platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata),
.ops = &atmel_pinctrl_ops,
};
@@ -0,0 +1,527 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Atmel PIO pinctrl driver
*
* Copyright (C) 2016 Atmel Corporation
* Wenyou.Yang <wenyou.yang@atmel.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <asm/hardware.h>
#include <linux/io.h>
#include <linux/err.h>
#include <mach/at91_pio.h>
DECLARE_GLOBAL_DATA_PTR;
#define MAX_GPIO_BANKS 5
#define MAX_NB_GPIO_PER_BANK 32
#define MAX_PINMUX_ENTRIES 200
struct at91_pinctrl_priv {
struct at91_port *reg_base[MAX_GPIO_BANKS];
u32 nbanks;
};
#define PULL_UP BIT(0)
#define MULTI_DRIVE BIT(1)
#define DEGLITCH BIT(2)
#define PULL_DOWN BIT(3)
#define DIS_SCHMIT BIT(4)
#define DRIVE_STRENGTH_SHIFT 5
#define DRIVE_STRENGTH_MASK 0x3
#define DRIVE_STRENGTH (DRIVE_STRENGTH_MASK << DRIVE_STRENGTH_SHIFT)
#define OUTPUT BIT(7)
#define OUTPUT_VAL_SHIFT 8
#define OUTPUT_VAL (0x1 << OUTPUT_VAL_SHIFT)
#define SLEWRATE_SHIFT 9
#define SLEWRATE_MASK 0x1
#define SLEWRATE (SLEWRATE_MASK << SLEWRATE_SHIFT)
#define DEBOUNCE BIT(16)
#define DEBOUNCE_VAL_SHIFT 17
#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT)
/**
* These defines will translated the dt binding settings to our internal
* settings. They are not necessarily the same value as the register setting.
* The actual drive strength current of low, medium and high must be looked up
* from the corresponding device datasheet. This value is different for pins
* that are even in the same banks. It is also dependent on VCC.
* DRIVE_STRENGTH_DEFAULT is just a placeholder to avoid changing the drive
* strength when there is no dt config for it.
*/
enum drive_strength_bit {
DRIVE_STRENGTH_BIT_DEF,
DRIVE_STRENGTH_BIT_LOW,
DRIVE_STRENGTH_BIT_MED,
DRIVE_STRENGTH_BIT_HI,
};
#define DRIVE_STRENGTH_BIT_MSK(name) (DRIVE_STRENGTH_BIT_##name << \
DRIVE_STRENGTH_SHIFT)
enum slewrate_bit {
SLEWRATE_BIT_DIS,
SLEWRATE_BIT_ENA,
};
#define SLEWRATE_BIT_MSK(name) (SLEWRATE_BIT_##name << SLEWRATE_SHIFT)
enum at91_mux {
AT91_MUX_GPIO = 0,
AT91_MUX_PERIPH_A = 1,
AT91_MUX_PERIPH_B = 2,
AT91_MUX_PERIPH_C = 3,
AT91_MUX_PERIPH_D = 4,
};
/**
* struct at91_pinctrl_mux_ops - describes an AT91 mux ops group
* on new IP with support for periph C and D the way to mux in
* periph A and B has changed
* So provide the right callbacks
* if not present means the IP does not support it
* @mux_A_periph: assign the corresponding pin to the peripheral A function.
* @mux_B_periph: assign the corresponding pin to the peripheral B function.
* @mux_C_periph: assign the corresponding pin to the peripheral C function.
* @mux_D_periph: assign the corresponding pin to the peripheral D function.
* @set_deglitch: enable/disable the deglitch feature.
* @set_debounce: enable/disable the debounce feature.
* @set_pulldown: enable/disable the pulldown feature.
* @disable_schmitt_trig: disable schmitt trigger
*/
struct at91_pinctrl_mux_ops {
void (*mux_A_periph)(struct at91_port *pio, u32 mask);
void (*mux_B_periph)(struct at91_port *pio, u32 mask);
void (*mux_C_periph)(struct at91_port *pio, u32 mask);
void (*mux_D_periph)(struct at91_port *pio, u32 mask);
void (*set_deglitch)(struct at91_port *pio, u32 mask, bool is_on);
void (*set_debounce)(struct at91_port *pio, u32 mask, bool is_on,
u32 div);
void (*set_pulldown)(struct at91_port *pio, u32 mask, bool is_on);
void (*disable_schmitt_trig)(struct at91_port *pio, u32 mask);
void (*set_drivestrength)(struct at91_port *pio, u32 pin,
u32 strength);
void (*set_slewrate)(struct at91_port *pio, u32 pin, u32 slewrate);
};
static u32 two_bit_pin_value_shift_amount(u32 pin)
{
/* return the shift value for a pin for "two bit" per pin registers,
* i.e. drive strength */
return 2 * ((pin >= MAX_NB_GPIO_PER_BANK/2)
? pin - MAX_NB_GPIO_PER_BANK/2 : pin);
}
static void at91_mux_disable_interrupt(struct at91_port *pio, u32 mask)
{
writel(mask, &pio->idr);
}
static void at91_mux_set_pullup(struct at91_port *pio, u32 mask, bool on)
{
if (on)
writel(mask, &pio->mux.pio3.ppddr);
writel(mask, (on ? &pio->puer : &pio->pudr));
}
static void at91_mux_set_output(struct at91_port *pio, unsigned mask,
bool is_on, bool val)
{
writel(mask, (val ? &pio->sodr : &pio->codr));
writel(mask, (is_on ? &pio->oer : &pio->odr));
}
static void at91_mux_set_multidrive(struct at91_port *pio, u32 mask, bool on)
{
writel(mask, (on ? &pio->mder : &pio->mddr));
}
static void at91_mux_set_A_periph(struct at91_port *pio, u32 mask)
{
writel(mask, &pio->mux.pio2.asr);
}
static void at91_mux_set_B_periph(struct at91_port *pio, u32 mask)
{
writel(mask, &pio->mux.pio2.bsr);
}
static void at91_mux_pio3_set_A_periph(struct at91_port *pio, u32 mask)
{
writel(readl(&pio->mux.pio3.abcdsr1) & ~mask, &pio->mux.pio3.abcdsr1);
writel(readl(&pio->mux.pio3.abcdsr2) & ~mask, &pio->mux.pio3.abcdsr2);
}
static void at91_mux_pio3_set_B_periph(struct at91_port *pio, u32 mask)
{
writel(readl(&pio->mux.pio3.abcdsr1) | mask, &pio->mux.pio3.abcdsr1);
writel(readl(&pio->mux.pio3.abcdsr2) & ~mask, &pio->mux.pio3.abcdsr2);
}
static void at91_mux_pio3_set_C_periph(struct at91_port *pio, u32 mask)
{
writel(readl(&pio->mux.pio3.abcdsr1) & ~mask, &pio->mux.pio3.abcdsr1);
writel(readl(&pio->mux.pio3.abcdsr2) | mask, &pio->mux.pio3.abcdsr2);
}
static void at91_mux_pio3_set_D_periph(struct at91_port *pio, u32 mask)
{
writel(readl(&pio->mux.pio3.abcdsr1) | mask, &pio->mux.pio3.abcdsr1);
writel(readl(&pio->mux.pio3.abcdsr2) | mask, &pio->mux.pio3.abcdsr2);
}
static void at91_mux_set_deglitch(struct at91_port *pio, u32 mask, bool is_on)
{
writel(mask, (is_on ? &pio->ifer : &pio->ifdr));
}
static void at91_mux_pio3_set_deglitch(struct at91_port *pio,
u32 mask, bool is_on)
{
if (is_on)
writel(mask, &pio->mux.pio3.ifscdr);
at91_mux_set_deglitch(pio, mask, is_on);
}
static void at91_mux_pio3_set_debounce(struct at91_port *pio, u32 mask,
bool is_on, u32 div)
{
if (is_on) {
writel(mask, &pio->mux.pio3.ifscer);
writel(div & PIO_SCDR_DIV, &pio->mux.pio3.scdr);
writel(mask, &pio->ifer);
} else {
writel(mask, &pio->mux.pio3.ifscdr);
}
}
static void at91_mux_pio3_set_pulldown(struct at91_port *pio,
u32 mask, bool is_on)
{
if (is_on)
writel(mask, &pio->pudr);
writel(mask, (is_on ? &pio->mux.pio3.ppder : &pio->mux.pio3.ppddr));
}
static void at91_mux_pio3_disable_schmitt_trig(struct at91_port *pio,
u32 mask)
{
writel(readl(&pio->schmitt) | mask, &pio->schmitt);
}
static void set_drive_strength(void *reg, u32 pin, u32 strength)
{
u32 shift = two_bit_pin_value_shift_amount(pin);
clrsetbits_le32(reg, DRIVE_STRENGTH_MASK << shift, strength << shift);
}
static void at91_mux_sama5d3_set_drivestrength(struct at91_port *pio,
u32 pin, u32 setting)
{
void *reg;
reg = &pio->driver12;
if (pin >= MAX_NB_GPIO_PER_BANK / 2)
reg = &pio->driver2;
/* do nothing if setting is zero */
if (!setting)
return;
/* strength is 1 to 1 with setting for SAMA5 */
set_drive_strength(reg, pin, setting);
}
static void at91_mux_sam9x5_set_drivestrength(struct at91_port *pio,
u32 pin, u32 setting)
{
void *reg;
reg = &pio->driver1;
if (pin >= MAX_NB_GPIO_PER_BANK / 2)
reg = &pio->driver12;
/* do nothing if setting is zero */
if (!setting)
return;
/* strength is inverse on SAM9x5s with our defines
* 0 = hi, 1 = med, 2 = low, 3 = rsvd */
setting = DRIVE_STRENGTH_BIT_MSK(HI) - setting;
set_drive_strength(reg, pin, setting);
}
static void at91_mux_sam9x60_set_drivestrength(struct at91_port *pio, u32 pin,
u32 setting)
{
void *reg = &pio->driver12;
u32 tmp;
if (setting <= DRIVE_STRENGTH_BIT_DEF ||
setting == DRIVE_STRENGTH_BIT_MED ||
setting > DRIVE_STRENGTH_BIT_HI)
return;
tmp = readl(reg);
/* Strength is 0: low, 1: hi */
if (setting == DRIVE_STRENGTH_BIT_LOW)
tmp &= ~BIT(pin);
else
tmp |= BIT(pin);
writel(tmp, reg);
}
static void at91_mux_sam9x60_set_slewrate(struct at91_port *pio, u32 pin,
u32 setting)
{
void *reg = &pio->reserved12[3];
u32 tmp;
if (setting < SLEWRATE_BIT_DIS || setting > SLEWRATE_BIT_ENA)
return;
tmp = readl(reg);
if (setting == SLEWRATE_BIT_DIS)
tmp &= ~BIT(pin);
else
tmp |= BIT(pin);
writel(tmp, reg);
}
static struct at91_pinctrl_mux_ops at91rm9200_ops = {
.mux_A_periph = at91_mux_set_A_periph,
.mux_B_periph = at91_mux_set_B_periph,
.set_deglitch = at91_mux_set_deglitch,
};
static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
.mux_A_periph = at91_mux_pio3_set_A_periph,
.mux_B_periph = at91_mux_pio3_set_B_periph,
.mux_C_periph = at91_mux_pio3_set_C_periph,
.mux_D_periph = at91_mux_pio3_set_D_periph,
.set_deglitch = at91_mux_pio3_set_deglitch,
.set_debounce = at91_mux_pio3_set_debounce,
.set_pulldown = at91_mux_pio3_set_pulldown,
.disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
.set_drivestrength = at91_mux_sam9x5_set_drivestrength,
};
static struct at91_pinctrl_mux_ops sama5d3_ops = {
.mux_A_periph = at91_mux_pio3_set_A_periph,
.mux_B_periph = at91_mux_pio3_set_B_periph,
.mux_C_periph = at91_mux_pio3_set_C_periph,
.mux_D_periph = at91_mux_pio3_set_D_periph,
.set_deglitch = at91_mux_pio3_set_deglitch,
.set_debounce = at91_mux_pio3_set_debounce,
.set_pulldown = at91_mux_pio3_set_pulldown,
.disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
.set_drivestrength = at91_mux_sama5d3_set_drivestrength,
};
static struct at91_pinctrl_mux_ops sam9x60_ops = {
.mux_A_periph = at91_mux_pio3_set_A_periph,
.mux_B_periph = at91_mux_pio3_set_B_periph,
.mux_C_periph = at91_mux_pio3_set_C_periph,
.mux_D_periph = at91_mux_pio3_set_D_periph,
.set_deglitch = at91_mux_pio3_set_deglitch,
.set_debounce = at91_mux_pio3_set_debounce,
.set_pulldown = at91_mux_pio3_set_pulldown,
.disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
.set_drivestrength = at91_mux_sam9x60_set_drivestrength,
.set_slewrate = at91_mux_sam9x60_set_slewrate,
};
static void at91_mux_gpio_disable(struct at91_port *pio, u32 mask)
{
writel(mask, &pio->pdr);
}
static void at91_mux_gpio_enable(struct at91_port *pio, u32 mask, bool input)
{
writel(mask, &pio->per);
writel(mask, (input ? &pio->odr : &pio->oer));
}
static int at91_pmx_set(struct at91_pinctrl_mux_ops *ops,
struct at91_port *pio, u32 mask, enum at91_mux mux)
{
at91_mux_disable_interrupt(pio, mask);
switch (mux) {
case AT91_MUX_GPIO:
at91_mux_gpio_enable(pio, mask, 1);
break;
case AT91_MUX_PERIPH_A:
ops->mux_A_periph(pio, mask);
break;
case AT91_MUX_PERIPH_B:
ops->mux_B_periph(pio, mask);
break;
case AT91_MUX_PERIPH_C:
if (!ops->mux_C_periph)
return -EINVAL;
ops->mux_C_periph(pio, mask);
break;
case AT91_MUX_PERIPH_D:
if (!ops->mux_D_periph)
return -EINVAL;
ops->mux_D_periph(pio, mask);
break;
}
if (mux)
at91_mux_gpio_disable(pio, mask);
return 0;
}
static int at91_pinconf_set(struct at91_pinctrl_mux_ops *ops,
struct at91_port *pio, u32 pin, u32 config)
{
u32 mask = BIT(pin);
if ((config & PULL_UP) && (config & PULL_DOWN))
return -EINVAL;
at91_mux_set_output(pio, mask, config & OUTPUT,
(config & OUTPUT_VAL) >> OUTPUT_VAL_SHIFT);
at91_mux_set_pullup(pio, mask, config & PULL_UP);
at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
if (ops->set_deglitch)
ops->set_deglitch(pio, mask, config & DEGLITCH);
if (ops->set_debounce)
ops->set_debounce(pio, mask, config & DEBOUNCE,
(config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT);
if (ops->set_pulldown)
ops->set_pulldown(pio, mask, config & PULL_DOWN);
if (ops->disable_schmitt_trig && config & DIS_SCHMIT)
ops->disable_schmitt_trig(pio, mask);
if (ops->set_drivestrength)
ops->set_drivestrength(pio, pin,
(config & DRIVE_STRENGTH) >> DRIVE_STRENGTH_SHIFT);
if (ops->set_slewrate)
ops->set_slewrate(pio, pin,
(config & SLEWRATE) >> SLEWRATE_SHIFT);
return 0;
}
static int at91_pin_check_config(struct udevice *dev, u32 bank, u32 pin)
{
struct at91_pinctrl_priv *priv = dev_get_priv(dev);
if (bank >= priv->nbanks) {
debug("pin conf bank %d >= nbanks %d\n", bank, priv->nbanks);
return -EINVAL;
}
if (pin >= MAX_NB_GPIO_PER_BANK) {
debug("pin conf pin %d >= %d\n", pin, MAX_NB_GPIO_PER_BANK);
return -EINVAL;
}
return 0;
}
static int at91_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
struct at91_pinctrl_priv *priv = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev_of_offset(config);
u32 cells[MAX_PINMUX_ENTRIES];
const u32 *list = cells;
u32 bank, pin;
u32 conf, mask, count, i;
int size;
int ret;
enum at91_mux mux;
struct at91_port *pio;
struct at91_pinctrl_mux_ops *ops =
(struct at91_pinctrl_mux_ops *)dev_get_driver_data(dev);
/*
* the binding format is atmel,pins = <bank pin mux CONFIG ...>,
* do sanity check and calculate pins number
*/
size = fdtdec_get_int_array_count(blob, node, "atmel,pins",
cells, ARRAY_SIZE(cells));
/* we do not check return since it's safe node passed down */
count = size >> 2;
if (!count)
return -EINVAL;
for (i = 0; i < count; i++) {
bank = *list++;
pin = *list++;
mux = *list++;
conf = *list++;
ret = at91_pin_check_config(dev, bank, pin);
if (ret)
return ret;
pio = priv->reg_base[bank];
mask = BIT(pin);
ret = at91_pmx_set(ops, pio, mask, mux);
if (ret)
return ret;
ret = at91_pinconf_set(ops, pio, pin, conf);
if (ret)
return ret;
}
return 0;
}
const struct pinctrl_ops at91_pinctrl_ops = {
.set_state = at91_pinctrl_set_state,
};
static int at91_pinctrl_probe(struct udevice *dev)
{
struct at91_pinctrl_priv *priv = dev_get_priv(dev);
fdt_addr_t addr_base;
int index;
for (index = 0; index < MAX_GPIO_BANKS; index++) {
addr_base = devfdt_get_addr_index(dev, index);
if (addr_base == FDT_ADDR_T_NONE)
break;
priv->reg_base[index] = (struct at91_port *)addr_base;
}
priv->nbanks = index;
return 0;
}
static const struct udevice_id at91_pinctrl_match[] = {
{ .compatible = "atmel,sama5d3-pinctrl", .data = (ulong)&sama5d3_ops },
{ .compatible = "atmel,at91sam9x5-pinctrl", .data = (ulong)&at91sam9x5_ops },
{ .compatible = "atmel,at91rm9200-pinctrl", .data = (ulong)&at91rm9200_ops },
{ .compatible = "microchip,sam9x60-pinctrl", .data = (ulong)&sam9x60_ops },
{}
};
U_BOOT_DRIVER(at91_pinctrl) = {
.name = "pinctrl_at91",
.id = UCLASS_PINCTRL,
.of_match = at91_pinctrl_match,
.probe = at91_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct at91_pinctrl_priv),
.ops = &at91_pinctrl_ops,
};
@@ -0,0 +1,360 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <dm.h>
#include <linux/compat.h>
#include <dm/pinctrl.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* pinctrl_pin_name_to_selector() - return the pin selector for a pin
*
* @dev: pin controller device
* @pin: the pin name to look up
* @return: pin selector, or negative error code on failure
*/
static int pinctrl_pin_name_to_selector(struct udevice *dev, const char *pin)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
unsigned npins, selector;
if (!ops->get_pins_count || !ops->get_pin_name) {
dev_dbg(dev, "get_pins_count or get_pin_name missing\n");
return -ENOSYS;
}
npins = ops->get_pins_count(dev);
/* See if this pctldev has this pin */
for (selector = 0; selector < npins; selector++) {
const char *pname = ops->get_pin_name(dev, selector);
if (!strcmp(pin, pname))
return selector;
}
return -ENOSYS;
}
/**
* pinctrl_group_name_to_selector() - return the group selector for a group
*
* @dev: pin controller device
* @group: the pin group name to look up
* @return: pin group selector, or negative error code on failure
*/
static int pinctrl_group_name_to_selector(struct udevice *dev,
const char *group)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
unsigned ngroups, selector;
if (!ops->get_groups_count || !ops->get_group_name) {
dev_dbg(dev, "get_groups_count or get_group_name missing\n");
return -ENOSYS;
}
ngroups = ops->get_groups_count(dev);
/* See if this pctldev has this group */
for (selector = 0; selector < ngroups; selector++) {
const char *gname = ops->get_group_name(dev, selector);
if (!strcmp(group, gname))
return selector;
}
return -ENOSYS;
}
#if CONFIG_IS_ENABLED(PINMUX)
/**
* pinmux_func_name_to_selector() - return the function selector for a function
*
* @dev: pin controller device
* @function: the function name to look up
* @return: function selector, or negative error code on failure
*/
static int pinmux_func_name_to_selector(struct udevice *dev,
const char *function)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
unsigned nfuncs, selector = 0;
if (!ops->get_functions_count || !ops->get_function_name) {
dev_dbg(dev,
"get_functions_count or get_function_name missing\n");
return -ENOSYS;
}
nfuncs = ops->get_functions_count(dev);
/* See if this pctldev has this function */
for (selector = 0; selector < nfuncs; selector++) {
const char *fname = ops->get_function_name(dev, selector);
if (!strcmp(function, fname))
return selector;
}
return -ENOSYS;
}
/**
* pinmux_enable_setting() - enable pin-mux setting for a certain pin/group
*
* @dev: pin controller device
* @is_group: target of operation (true: pin group, false: pin)
* @selector: pin selector or group selector, depending on @is_group
* @func_selector: function selector
* @return: 0 on success, or negative error code on failure
*/
static int pinmux_enable_setting(struct udevice *dev, bool is_group,
unsigned selector, unsigned func_selector)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (is_group) {
if (!ops->pinmux_group_set) {
dev_dbg(dev, "pinmux_group_set op missing\n");
return -ENOSYS;
}
return ops->pinmux_group_set(dev, selector, func_selector);
} else {
if (!ops->pinmux_set) {
dev_dbg(dev, "pinmux_set op missing\n");
return -ENOSYS;
}
return ops->pinmux_set(dev, selector, func_selector);
}
}
#else
static int pinmux_func_name_to_selector(struct udevice *dev,
const char *function)
{
return 0;
}
static int pinmux_enable_setting(struct udevice *dev, bool is_group,
unsigned selector, unsigned func_selector)
{
return 0;
}
#endif
#if CONFIG_IS_ENABLED(PINCONF)
/**
* pinconf_prop_name_to_param() - return parameter ID for a property name
*
* @dev: pin controller device
* @property: property name in DTS, such as "bias-pull-up", "slew-rate", etc.
* @default_value: return default value in case no value is specified in DTS
* @return: return pamater ID, or negative error code on failure
*/
static int pinconf_prop_name_to_param(struct udevice *dev,
const char *property, u32 *default_value)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
const struct pinconf_param *p, *end;
if (!ops->pinconf_num_params || !ops->pinconf_params) {
dev_dbg(dev, "pinconf_num_params or pinconf_params missing\n");
return -ENOSYS;
}
p = ops->pinconf_params;
end = p + ops->pinconf_num_params;
/* See if this pctldev supports this parameter */
for (; p < end; p++) {
if (!strcmp(property, p->property)) {
*default_value = p->default_value;
return p->param;
}
}
return -ENOSYS;
}
/**
* pinconf_enable_setting() - apply pin configuration for a certain pin/group
*
* @dev: pin controller device
* @is_group: target of operation (true: pin group, false: pin)
* @selector: pin selector or group selector, depending on @is_group
* @param: configuration paramter
* @argument: argument taken by some configuration parameters
* @return: 0 on success, or negative error code on failure
*/
static int pinconf_enable_setting(struct udevice *dev, bool is_group,
unsigned selector, unsigned param,
u32 argument)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (is_group) {
if (!ops->pinconf_group_set) {
dev_dbg(dev, "pinconf_group_set op missing\n");
return -ENOSYS;
}
return ops->pinconf_group_set(dev, selector, param,
argument);
} else {
if (!ops->pinconf_set) {
dev_dbg(dev, "pinconf_set op missing\n");
return -ENOSYS;
}
return ops->pinconf_set(dev, selector, param, argument);
}
}
#else
static int pinconf_prop_name_to_param(struct udevice *dev,
const char *property, u32 *default_value)
{
return -ENOSYS;
}
static int pinconf_enable_setting(struct udevice *dev, bool is_group,
unsigned selector, unsigned param,
u32 argument)
{
return 0;
}
#endif
/**
* pinctrl_generic_set_state_one() - set state for a certain pin/group
* Apply all pin multiplexing and pin configurations specified by @config
* for a given pin or pin group.
*
* @dev: pin controller device
* @config: pseudo device pointing to config node
* @is_group: target of operation (true: pin group, false: pin)
* @selector: pin selector or group selector, depending on @is_group
* @return: 0 on success, or negative error code on failure
*/
static int pinctrl_generic_set_state_one(struct udevice *dev,
struct udevice *config,
bool is_group, unsigned selector)
{
const void *fdt = gd->fdt_blob;
int node_offset = dev_of_offset(config);
const char *propname;
const void *value;
int prop_offset, len, func_selector, param, ret;
u32 arg, default_val;
for (prop_offset = fdt_first_property_offset(fdt, node_offset);
prop_offset > 0;
prop_offset = fdt_next_property_offset(fdt, prop_offset)) {
value = fdt_getprop_by_offset(fdt, prop_offset,
&propname, &len);
if (!value)
return -EINVAL;
if (!strcmp(propname, "function")) {
func_selector = pinmux_func_name_to_selector(dev,
value);
if (func_selector < 0)
return func_selector;
ret = pinmux_enable_setting(dev, is_group,
selector,
func_selector);
} else {
param = pinconf_prop_name_to_param(dev, propname,
&default_val);
if (param < 0)
continue; /* just skip unknown properties */
if (len >= sizeof(fdt32_t))
arg = fdt32_to_cpu(*(fdt32_t *)value);
else
arg = default_val;
ret = pinconf_enable_setting(dev, is_group,
selector, param, arg);
}
if (ret)
return ret;
}
return 0;
}
/**
* pinctrl_generic_set_state_subnode() - apply all settings in config node
*
* @dev: pin controller device
* @config: pseudo device pointing to config node
* @return: 0 on success, or negative error code on failure
*/
static int pinctrl_generic_set_state_subnode(struct udevice *dev,
struct udevice *config)
{
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(config);
const char *subnode_target_type = "pins";
bool is_group = false;
const char *name;
int strings_count, selector, i, ret;
strings_count = fdt_stringlist_count(fdt, node, subnode_target_type);
if (strings_count < 0) {
subnode_target_type = "groups";
is_group = true;
strings_count = fdt_stringlist_count(fdt, node,
subnode_target_type);
if (strings_count < 0) {
/* skip this node; may contain config child nodes */
return 0;
}
}
for (i = 0; i < strings_count; i++) {
name = fdt_stringlist_get(fdt, node, subnode_target_type, i,
NULL);
if (!name)
return -EINVAL;
if (is_group)
selector = pinctrl_group_name_to_selector(dev, name);
else
selector = pinctrl_pin_name_to_selector(dev, name);
if (selector < 0)
return selector;
ret = pinctrl_generic_set_state_one(dev, config,
is_group, selector);
if (ret)
return ret;
}
return 0;
}
int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
{
struct udevice *child;
int ret;
ret = pinctrl_generic_set_state_subnode(dev, config);
if (ret)
return ret;
for (device_find_first_child(config, &child);
child;
device_find_next_child(&child)) {
ret = pinctrl_generic_set_state_subnode(dev, child);
if (ret)
return ret;
}
return 0;
}
@@ -0,0 +1,167 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
/* #define DEBUG */
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
static const char * const sandbox_pins[] = {
"SCL",
"SDA",
"TX",
"RX",
"W1"
};
static const char * const sandbox_pins_muxing[] = {
"I2C SCL",
"I2C SDA",
"Uart TX",
"Uart RX",
"1-wire gpio",
};
static const char * const sandbox_groups[] = {
"i2c",
"serial_a",
"serial_b",
"spi",
"w1",
};
static const char * const sandbox_functions[] = {
"i2c",
"serial",
"spi",
"w1",
};
static const struct pinconf_param sandbox_conf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
{ "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
{ "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
{ "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
};
static int sandbox_get_pins_count(struct udevice *dev)
{
return ARRAY_SIZE(sandbox_pins);
}
static const char *sandbox_get_pin_name(struct udevice *dev, unsigned selector)
{
return sandbox_pins[selector];
}
static int sandbox_get_pin_muxing(struct udevice *dev,
unsigned int selector,
char *buf, int size)
{
snprintf(buf, size, "%s", sandbox_pins_muxing[selector]);
return 0;
}
static int sandbox_get_groups_count(struct udevice *dev)
{
return ARRAY_SIZE(sandbox_groups);
}
static const char *sandbox_get_group_name(struct udevice *dev,
unsigned selector)
{
return sandbox_groups[selector];
}
static int sandbox_get_functions_count(struct udevice *dev)
{
return ARRAY_SIZE(sandbox_functions);
}
static const char *sandbox_get_function_name(struct udevice *dev,
unsigned selector)
{
return sandbox_functions[selector];
}
static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector,
unsigned func_selector)
{
debug("sandbox pinmux: pin = %d (%s), function = %d (%s)\n",
pin_selector, sandbox_get_pin_name(dev, pin_selector),
func_selector, sandbox_get_function_name(dev, func_selector));
return 0;
}
static int sandbox_pinmux_group_set(struct udevice *dev,
unsigned group_selector,
unsigned func_selector)
{
debug("sandbox pinmux: group = %d (%s), function = %d (%s)\n",
group_selector, sandbox_get_group_name(dev, group_selector),
func_selector, sandbox_get_function_name(dev, func_selector));
return 0;
}
static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector,
unsigned param, unsigned argument)
{
debug("sandbox pinconf: pin = %d (%s), param = %d, arg = %d\n",
pin_selector, sandbox_get_pin_name(dev, pin_selector),
param, argument);
return 0;
}
static int sandbox_pinconf_group_set(struct udevice *dev,
unsigned group_selector,
unsigned param, unsigned argument)
{
debug("sandbox pinconf: group = %d (%s), param = %d, arg = %d\n",
group_selector, sandbox_get_group_name(dev, group_selector),
param, argument);
return 0;
}
const struct pinctrl_ops sandbox_pinctrl_ops = {
.get_pins_count = sandbox_get_pins_count,
.get_pin_name = sandbox_get_pin_name,
.get_pin_muxing = sandbox_get_pin_muxing,
.get_groups_count = sandbox_get_groups_count,
.get_group_name = sandbox_get_group_name,
.get_functions_count = sandbox_get_functions_count,
.get_function_name = sandbox_get_function_name,
.pinmux_set = sandbox_pinmux_set,
.pinmux_group_set = sandbox_pinmux_group_set,
.pinconf_num_params = ARRAY_SIZE(sandbox_conf_params),
.pinconf_params = sandbox_conf_params,
.pinconf_set = sandbox_pinconf_set,
.pinconf_group_set = sandbox_pinconf_group_set,
.set_state = pinctrl_generic_set_state,
};
static const struct udevice_id sandbox_pinctrl_match[] = {
{ .compatible = "sandbox,pinctrl" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(sandbox_pinctrl) = {
.name = "sandbox_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = sandbox_pinctrl_match,
.ops = &sandbox_pinctrl_ops,
};
@@ -0,0 +1,204 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <linux/libfdt.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
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 */
bool bits_per_mux;
};
struct single_fdt_pin_cfg {
fdt32_t reg; /* configuration register offset */
fdt32_t val; /* configuration register value */
};
struct single_fdt_bits_cfg {
fdt32_t reg; /* configuration register offset */
fdt32_t val; /* configuration register value */
fdt32_t mask; /* configuration register mask */
};
/**
* single_configure_pins() - Configure pins based on FDT data
*
* @dev: Pointer to single pin configuration device which is the parent of
* the pins node holding the pin configuration data.
* @pins: Pointer to the first element of an array of register/value pairs
* of type 'struct single_fdt_pin_cfg'. Each such pair describes the
* the pin to be configured and the value to be used for configuration.
* This pointer points to a 'pinctrl-single,pins' property in the
* device-tree.
* @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)'.
*/
static int single_configure_pins(struct udevice *dev,
const struct single_fdt_pin_cfg *pins,
int size)
{
struct single_pdata *pdata = dev->platdata;
int count = size / sizeof(struct single_fdt_pin_cfg);
phys_addr_t n, reg;
u32 val;
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", &reg);
continue;
}
reg += pdata->base;
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);
continue;
}
dev_dbg(dev, " reg/val 0x%pa/0x%08x\n", &reg, val);
}
return 0;
}
static int single_configure_bits(struct udevice *dev,
const struct single_fdt_bits_cfg *pins,
int size)
{
struct single_pdata *pdata = dev->platdata;
int count = size / sizeof(struct single_fdt_bits_cfg);
phys_addr_t n, reg;
u32 val, mask;
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", &reg);
continue;
}
reg += pdata->base;
mask = fdt32_to_cpu(pins->mask);
val = fdt32_to_cpu(pins->val) & mask;
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;
}
dev_dbg(dev, " reg/val 0x%pa/0x%08x\n", &reg, val);
}
return 0;
}
static int single_set_state(struct udevice *dev,
struct udevice *config)
{
const void *fdt = gd->fdt_blob;
const struct single_fdt_pin_cfg *prop;
const struct single_fdt_bits_cfg *prop_bits;
int len;
prop = fdt_getprop(fdt, dev_of_offset(config), "pinctrl-single,pins",
&len);
if (prop) {
dev_dbg(dev, "configuring pins for %s\n", config->name);
if (len % sizeof(struct single_fdt_pin_cfg)) {
dev_dbg(dev, " invalid pin configuration in fdt\n");
return -FDT_ERR_BADSTRUCTURE;
}
single_configure_pins(dev, prop, len);
return 0;
}
/* pinctrl-single,pins not found so check for pinctrl-single,bits */
prop_bits = fdt_getprop(fdt, dev_of_offset(config),
"pinctrl-single,bits",
&len);
if (prop_bits) {
dev_dbg(dev, "configuring pins for %s\n", config->name);
if (len % sizeof(struct single_fdt_bits_cfg)) {
dev_dbg(dev, " invalid bits configuration in fdt\n");
return -FDT_ERR_BADSTRUCTURE;
}
single_configure_bits(dev, prop_bits, len);
return 0;
}
/* Neither 'pinctrl-single,pins' nor 'pinctrl-single,bits' were found */
return len;
}
static int single_ofdata_to_platdata(struct udevice *dev)
{
fdt_addr_t addr;
u32 of_reg[2];
int res;
struct single_pdata *pdata = dev->platdata;
pdata->width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"pinctrl-single,register-width", 0);
res = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
"reg", of_reg, 2);
if (res)
return res;
pdata->offset = of_reg[1] - pdata->width / 8;
addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE) {
dev_dbg(dev, "no valid base register address\n");
return -EINVAL;
}
pdata->base = addr;
pdata->mask = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"pinctrl-single,function-mask",
0xffffffff);
pdata->bits_per_mux = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
"pinctrl-single,bit-per-mux");
return 0;
}
const struct pinctrl_ops single_pinctrl_ops = {
.set_state = single_set_state,
};
static const struct udevice_id single_pinctrl_match[] = {
{ .compatible = "pinctrl-single" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(single_pinctrl) = {
.name = "single-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = single_pinctrl_match,
.ops = &single_pinctrl_ops,
.platdata_auto_alloc_size = sizeof(struct single_pdata),
.ofdata_to_platdata = single_ofdata_to_platdata,
};
@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Pinctrl driver for STMicroelectronics STi SoCs
*
* Copyright (C) 2017, STMicroelectronics - All Rights Reserved
* Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
*/
#include <common.h>
#include <bitfield.h>
#include <dm.h>
#include <errno.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <dm/pinctrl.h>
DECLARE_GLOBAL_DATA_PTR;
#define MAX_STI_PINCONF_ENTRIES 7
/* Output enable */
#define OE (1 << 27)
/* Pull Up */
#define PU (1 << 26)
/* Open Drain */
#define OD (1 << 25)
/* User-frendly defines for Pin Direction */
/* oe = 0, pu = 0, od = 0 */
#define IN (0)
/* oe = 0, pu = 1, od = 0 */
#define IN_PU (PU)
/* oe = 1, pu = 0, od = 0 */
#define OUT (OE)
/* oe = 1, pu = 1, od = 0 */
#define OUT_PU (OE | PU)
/* oe = 1, pu = 0, od = 1 */
#define BIDIR (OE | OD)
/* oe = 1, pu = 1, od = 1 */
#define BIDIR_PU (OE | PU | OD)
struct sti_pinctrl_platdata {
struct regmap *regmap;
};
struct sti_pin_desc {
unsigned char bank;
unsigned char pin;
unsigned char alt;
int dir;
};
/*
* PIO alternative Function selector
*/
void sti_alternate_select(struct udevice *dev, struct sti_pin_desc *pin_desc)
{
struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
unsigned long sysconf, *sysconfreg;
int alt = pin_desc->alt;
int bank = pin_desc->bank;
int pin = pin_desc->pin;
sysconfreg = (unsigned long *)plat->regmap->ranges[0].start;
switch (bank) {
case 0 ... 5: /* in "SBC Bank" */
sysconfreg += bank;
break;
case 10 ... 20: /* in "FRONT Bank" */
sysconfreg += bank - 10;
break;
case 30 ... 35: /* in "REAR Bank" */
sysconfreg += bank - 30;
break;
case 40 ... 42: /* in "FLASH Bank" */
sysconfreg += bank - 40;
break;
default:
BUG();
return;
}
sysconf = readl(sysconfreg);
sysconf = bitfield_replace(sysconf, pin * 4, 3, alt);
writel(sysconf, sysconfreg);
}
/* pin configuration */
void sti_pin_configure(struct udevice *dev, struct sti_pin_desc *pin_desc)
{
struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
int bit;
int oe = 0, pu = 0, od = 0;
unsigned long *sysconfreg;
int bank = pin_desc->bank;
sysconfreg = (unsigned long *)plat->regmap->ranges[0].start + 40;
/*
* NOTE: The PIO configuration for the PIO pins in the
* "FLASH Bank" are different from all the other banks!
* Specifically, the output-enable pin control register
* (SYS_CFG_3040) and the pull-up pin control register
* (SYS_CFG_3050), are both classed as being "reserved".
* Hence, we do not write to these registers to configure
* the OE and PU features for PIOs in this bank. However,
* the open-drain pin control register (SYS_CFG_3060)
* follows the style of the other banks, and so we can
* treat that register normally.
*
* Being pedantic, we should configure the PU and PD features
* in the "FLASH Bank" explicitly instead using the four
* SYS_CFG registers: 3080, 3081, 3085, and 3086. However, this
* would necessitate passing in the alternate function number
* to this function, and adding some horrible complexity here.
* Alternatively, we could just perform 4 32-bit "pokes" to
* these four SYS_CFG registers early in the initialization.
* In practice, these four SYS_CFG registers are correct
* after a reset, and U-Boot does not need to change them, so
* we (cheat and) rely on these registers being correct.
* WARNING: Please be aware of this (pragmatic) behaviour!
*/
int flashss = 0; /* bool: PIO in the Flash Sub-System ? */
switch (pin_desc->dir) {
case IN:
oe = 0; pu = 0; od = 0;
break;
case IN_PU:
oe = 0; pu = 1; od = 0;
break;
case OUT:
oe = 1; pu = 0; od = 0;
break;
case BIDIR:
oe = 1; pu = 0; od = 1;
break;
case BIDIR_PU:
oe = 1; pu = 1; od = 1;
break;
default:
pr_err("%s invalid direction value: 0x%x\n",
__func__, pin_desc->dir);
BUG();
break;
}
switch (bank) {
case 0 ... 5: /* in "SBC Bank" */
sysconfreg += bank / 4;
break;
case 10 ... 20: /* in "FRONT Bank" */
bank -= 10;
sysconfreg += bank / 4;
break;
case 30 ... 35: /* in "REAR Bank" */
bank -= 30;
sysconfreg += bank / 4;
break;
case 40 ... 42: /* in "FLASH Bank" */
bank -= 40;
sysconfreg += bank / 4;
flashss = 1; /* pin is in the Flash Sub-System */
break;
default:
BUG();
return;
}
bit = ((bank * 8) + pin_desc->pin) % 32;
/*
* set the "Output Enable" pin control
* but, do nothing if in the flashSS
*/
if (!flashss) {
if (oe)
generic_set_bit(bit, sysconfreg);
else
generic_clear_bit(bit, sysconfreg);
}
sysconfreg += 10; /* skip to next set of syscfg registers */
/*
* set the "Pull Up" pin control
* but, do nothing if in the FlashSS
*/
if (!flashss) {
if (pu)
generic_set_bit(bit, sysconfreg);
else
generic_clear_bit(bit, sysconfreg);
}
sysconfreg += 10; /* skip to next set of syscfg registers */
/* set the "Open Drain Enable" pin control */
if (od)
generic_set_bit(bit, sysconfreg);
else
generic_clear_bit(bit, sysconfreg);
}
static int sti_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
struct fdtdec_phandle_args args;
const void *blob = gd->fdt_blob;
const char *prop_name;
int node = dev_of_offset(config);
int property_offset, prop_len;
int pinconf_node, ret, count;
const char *bank_name;
u32 cells[MAX_STI_PINCONF_ENTRIES];
struct sti_pin_desc pin_desc;
/* go to next node "st,pins" which contains the pins configuration */
pinconf_node = fdt_subnode_offset(blob, node, "st,pins");
/*
* parse each pins configuration which looks like :
* pin_name = <bank_phandle pin_nb alt dir rt_type rt_delay rt_clk>
*/
fdt_for_each_property_offset(property_offset, blob, pinconf_node) {
fdt_getprop_by_offset(blob, property_offset, &prop_name,
&prop_len);
/* extract the bank of the pin description */
ret = fdtdec_parse_phandle_with_args(blob, pinconf_node,
prop_name, "#gpio-cells",
0, 0, &args);
if (ret < 0) {
pr_err("Can't get the gpio bank phandle: %d\n", ret);
return ret;
}
bank_name = fdt_getprop(blob, args.node, "st,bank-name",
&count);
if (count < 0) {
pr_err("Can't find bank-name property %d\n", count);
return -EINVAL;
}
pin_desc.bank = trailing_strtoln(bank_name, NULL);
count = fdtdec_get_int_array_count(blob, pinconf_node,
prop_name, cells,
ARRAY_SIZE(cells));
if (count < 0) {
pr_err("Bad pin configuration array %d\n", count);
return -EINVAL;
}
if (count > MAX_STI_PINCONF_ENTRIES) {
pr_err("Unsupported pinconf array count %d\n", count);
return -EINVAL;
}
pin_desc.pin = cells[1];
pin_desc.alt = cells[2];
pin_desc.dir = cells[3];
sti_alternate_select(dev, &pin_desc);
sti_pin_configure(dev, &pin_desc);
};
return 0;
}
static int sti_pinctrl_probe(struct udevice *dev)
{
struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
struct udevice *syscon;
int err;
/* get corresponding syscon phandle */
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
"st,syscfg", &syscon);
if (err) {
pr_err("unable to find syscon device\n");
return err;
}
plat->regmap = syscon_get_regmap(syscon);
if (!plat->regmap) {
pr_err("unable to find regmap\n");
return -ENODEV;
}
return 0;
}
static const struct udevice_id sti_pinctrl_ids[] = {
{ .compatible = "st,stih407-sbc-pinctrl" },
{ .compatible = "st,stih407-front-pinctrl" },
{ .compatible = "st,stih407-rear-pinctrl" },
{ .compatible = "st,stih407-flash-pinctrl" },
{ }
};
const struct pinctrl_ops sti_pinctrl_ops = {
.set_state = sti_pinctrl_set_state,
};
U_BOOT_DRIVER(pinctrl_sti) = {
.name = "pinctrl_sti",
.id = UCLASS_PINCTRL,
.of_match = sti_pinctrl_ids,
.ops = &sti_pinctrl_ops,
.probe = sti_pinctrl_probe,
.platdata_auto_alloc_size = sizeof(struct sti_pinctrl_platdata),
.ops = &sti_pinctrl_ops,
};
@@ -0,0 +1,431 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
*
* Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander
* based on Linux driver : pinctrl/pinctrl-stmfx.c
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <asm/gpio.h>
#include <dm/device.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <linux/bitfield.h>
#include <power/regulator.h>
/* STMFX pins = GPIO[15:0] + aGPIO[7:0] */
#define STMFX_MAX_GPIO 16
#define STMFX_MAX_AGPIO 8
/* General */
#define STMFX_REG_CHIP_ID 0x00 /* R */
#define STMFX_REG_FW_VERSION_MSB 0x01 /* R */
#define STMFX_REG_FW_VERSION_LSB 0x02 /* R */
#define STMFX_REG_SYS_CTRL 0x40 /* RW */
/* MFX boot time is around 10ms, so after reset, we have to wait this delay */
#define STMFX_BOOT_TIME_MS 10
/* GPIOs expander */
/* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */
#define STMFX_REG_GPIO_STATE 0x10 /* R */
/* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */
#define STMFX_REG_GPIO_DIR 0x60 /* RW */
/* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */
#define STMFX_REG_GPIO_TYPE 0x64 /* RW */
/* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */
#define STMFX_REG_GPIO_PUPD 0x68 /* RW */
/* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */
#define STMFX_REG_GPO_SET 0x6C /* RW */
/* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */
#define STMFX_REG_GPO_CLR 0x70 /* RW */
/* STMFX_REG_CHIP_ID bitfields */
#define STMFX_REG_CHIP_ID_MASK GENMASK(7, 0)
/* STMFX_REG_SYS_CTRL bitfields */
#define STMFX_REG_SYS_CTRL_GPIO_EN BIT(0)
#define STMFX_REG_SYS_CTRL_ALTGPIO_EN BIT(3)
#define STMFX_REG_SYS_CTRL_SWRST BIT(7)
#define NR_GPIO_REGS 3
#define NR_GPIOS_PER_REG 8
#define get_reg(offset) ((offset) / NR_GPIOS_PER_REG)
#define get_shift(offset) ((offset) % NR_GPIOS_PER_REG)
#define get_mask(offset) (BIT(get_shift(offset)))
struct stmfx_pinctrl {
struct udevice *gpio;
};
static int stmfx_read(struct udevice *dev, uint offset)
{
return dm_i2c_reg_read(dev_get_parent(dev), offset);
}
static int stmfx_write(struct udevice *dev, uint offset, unsigned int val)
{
return dm_i2c_reg_write(dev_get_parent(dev), offset, val);
}
static int stmfx_gpio_get(struct udevice *dev, unsigned int offset)
{
u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset);
u32 mask = get_mask(offset);
int ret;
ret = stmfx_read(dev, reg);
return ret < 0 ? ret : !!(ret & mask);
}
static int stmfx_gpio_set(struct udevice *dev, unsigned int offset, int value)
{
u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR;
u32 mask = get_mask(offset);
return stmfx_write(dev, reg + get_reg(offset), mask);
}
static int stmfx_gpio_get_function(struct udevice *dev, unsigned int offset)
{
u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
u32 mask = get_mask(offset);
int ret;
ret = stmfx_read(dev, reg);
if (ret < 0)
return ret;
/* On stmfx, gpio pins direction is (0)input, (1)output. */
return ret & mask ? GPIOF_OUTPUT : GPIOF_INPUT;
}
static int stmfx_gpio_direction_input(struct udevice *dev, unsigned int offset)
{
u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
u32 mask = get_mask(offset);
int ret;
ret = stmfx_read(dev, reg);
if (ret < 0)
return ret;
ret &= ~mask;
return stmfx_write(dev, reg, ret & ~mask);
}
static int stmfx_gpio_direction_output(struct udevice *dev,
unsigned int offset, int value)
{
u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
u32 mask = get_mask(offset);
int ret;
ret = stmfx_gpio_set(dev, offset, value);
if (ret < 0)
return ret;
ret = stmfx_read(dev, reg);
if (ret < 0)
return ret;
return stmfx_write(dev, reg, ret | mask);
}
static int stmfx_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct ofnode_phandle_args args;
u8 sys_ctrl;
uc_priv->bank_name = "stmfx";
uc_priv->gpio_count = STMFX_MAX_GPIO + STMFX_MAX_AGPIO;
if (!dev_read_phandle_with_args(dev, "gpio-ranges",
NULL, 3, 0, &args)) {
uc_priv->gpio_count = args.args[2];
}
/* enable GPIO function */
sys_ctrl = STMFX_REG_SYS_CTRL_GPIO_EN;
if (uc_priv->gpio_count > STMFX_MAX_GPIO)
sys_ctrl |= STMFX_REG_SYS_CTRL_ALTGPIO_EN;
stmfx_write(dev, STMFX_REG_SYS_CTRL, sys_ctrl);
return 0;
}
static const struct dm_gpio_ops stmfx_gpio_ops = {
.set_value = stmfx_gpio_set,
.get_value = stmfx_gpio_get,
.get_function = stmfx_gpio_get_function,
.direction_input = stmfx_gpio_direction_input,
.direction_output = stmfx_gpio_direction_output,
};
U_BOOT_DRIVER(stmfx_gpio) = {
.name = "stmfx-gpio",
.id = UCLASS_GPIO,
.probe = stmfx_gpio_probe,
.ops = &stmfx_gpio_ops,
};
#if CONFIG_IS_ENABLED(PINCONF)
static const struct pinconf_param stmfx_pinctrl_conf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 0 },
{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 0 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 },
{ "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
{ "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
{ "output-high", PIN_CONFIG_OUTPUT, 1 },
{ "output-low", PIN_CONFIG_OUTPUT, 0 },
};
static int stmfx_pinctrl_set_pupd(struct udevice *dev,
unsigned int pin, u32 pupd)
{
u8 reg = STMFX_REG_GPIO_PUPD + get_reg(pin);
u32 mask = get_mask(pin);
int ret;
ret = stmfx_read(dev, reg);
if (ret < 0)
return ret;
ret = (ret & ~mask) | (pupd ? mask : 0);
return stmfx_write(dev, reg, ret);
}
static int stmfx_pinctrl_set_type(struct udevice *dev,
unsigned int pin, u32 type)
{
u8 reg = STMFX_REG_GPIO_TYPE + get_reg(pin);
u32 mask = get_mask(pin);
int ret;
ret = stmfx_read(dev, reg);
if (ret < 0)
return ret;
ret = (ret & ~mask) | (type ? mask : 0);
return stmfx_write(dev, reg, ret);
}
static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin,
unsigned int param, unsigned int arg)
{
int ret, dir;
struct stmfx_pinctrl *plat = dev_get_platdata(dev);
dir = stmfx_gpio_get_function(plat->gpio, pin);
if (dir < 0)
return dir;
switch (param) {
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
case PIN_CONFIG_BIAS_DISABLE:
case PIN_CONFIG_DRIVE_PUSH_PULL:
ret = stmfx_pinctrl_set_type(dev, pin, 0);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
ret = stmfx_pinctrl_set_type(dev, pin, 1);
if (ret)
return ret;
ret = stmfx_pinctrl_set_pupd(dev, pin, 0);
break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = stmfx_pinctrl_set_type(dev, pin, 1);
if (ret)
return ret;
ret = stmfx_pinctrl_set_pupd(dev, pin, 1);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
ret = stmfx_pinctrl_set_type(dev, pin, 1);
break;
case PIN_CONFIG_OUTPUT:
ret = stmfx_gpio_direction_output(plat->gpio, pin, arg);
break;
default:
return -ENOTSUPP;
}
return ret;
}
#endif
static int stmfx_pinctrl_get_pins_count(struct udevice *dev)
{
struct stmfx_pinctrl *plat = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv;
uc_priv = dev_get_uclass_priv(plat->gpio);
return uc_priv->gpio_count;
}
/*
* STMFX pins[15:0] are called "gpio[15:0]"
* and STMFX pins[23:16] are called "agpio[7:0]"
*/
#define MAX_PIN_NAME_LEN 7
static char pin_name[MAX_PIN_NAME_LEN];
static const char *stmfx_pinctrl_get_pin_name(struct udevice *dev,
unsigned int selector)
{
if (selector < STMFX_MAX_GPIO)
snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
else
snprintf(pin_name, MAX_PIN_NAME_LEN, "agpio%u", selector - 16);
return pin_name;
}
static int stmfx_pinctrl_get_pin_muxing(struct udevice *dev,
unsigned int selector,
char *buf, int size)
{
struct stmfx_pinctrl *plat = dev_get_platdata(dev);
int func;
func = stmfx_gpio_get_function(plat->gpio, selector);
if (func < 0)
return func;
snprintf(buf, size, "%s", func == GPIOF_INPUT ? "input" : "output");
return 0;
}
static int stmfx_pinctrl_bind(struct udevice *dev)
{
struct stmfx_pinctrl *plat = dev_get_platdata(dev);
return device_bind_driver_to_node(dev->parent,
"stmfx-gpio", "stmfx-gpio",
dev_ofnode(dev), &plat->gpio);
};
static int stmfx_pinctrl_probe(struct udevice *dev)
{
struct stmfx_pinctrl *plat = dev_get_platdata(dev);
return device_probe(plat->gpio);
};
const struct pinctrl_ops stmfx_pinctrl_ops = {
.get_pins_count = stmfx_pinctrl_get_pins_count,
.get_pin_name = stmfx_pinctrl_get_pin_name,
.set_state = pinctrl_generic_set_state,
.get_pin_muxing = stmfx_pinctrl_get_pin_muxing,
#if CONFIG_IS_ENABLED(PINCONF)
.pinconf_set = stmfx_pinctrl_conf_set,
.pinconf_num_params = ARRAY_SIZE(stmfx_pinctrl_conf_params),
.pinconf_params = stmfx_pinctrl_conf_params,
#endif
};
static const struct udevice_id stmfx_pinctrl_match[] = {
{ .compatible = "st,stmfx-0300-pinctrl", },
};
U_BOOT_DRIVER(stmfx_pinctrl) = {
.name = "stmfx-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(stmfx_pinctrl_match),
.bind = stmfx_pinctrl_bind,
.probe = stmfx_pinctrl_probe,
.ops = &stmfx_pinctrl_ops,
.platdata_auto_alloc_size = sizeof(struct stmfx_pinctrl),
};
static int stmfx_chip_init(struct udevice *dev)
{
u8 id;
u8 version[2];
int ret;
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
id = dm_i2c_reg_read(dev, STMFX_REG_CHIP_ID);
if (id < 0) {
dev_err(dev, "error reading chip id: %d\n", id);
return ret;
}
/*
* Check that ID is the complement of the I2C address:
* STMFX I2C address follows the 7-bit format (MSB), that's why
* client->addr is shifted.
*
* STMFX_I2C_ADDR| STMFX | Linux
* input pin | I2C device address | I2C device address
*---------------------------------------------------------
* 0 | b: 1000 010x h:0x84 | 0x42
* 1 | b: 1000 011x h:0x86 | 0x43
*/
if (FIELD_GET(STMFX_REG_CHIP_ID_MASK, ~id) != (chip->chip_addr << 1)) {
dev_err(dev, "unknown chip id: %#x\n", id);
return -EINVAL;
}
ret = dm_i2c_read(dev, STMFX_REG_FW_VERSION_MSB,
version, sizeof(version));
if (ret) {
dev_err(dev, "error reading fw version: %d\n", ret);
return ret;
}
dev_info(dev, "STMFX id: %#x, fw version: %x.%02x\n",
id, version[0], version[1]);
ret = dm_i2c_reg_read(dev, STMFX_REG_SYS_CTRL);
if (ret < 0)
return ret;
ret = dm_i2c_reg_write(dev, STMFX_REG_SYS_CTRL,
ret | STMFX_REG_SYS_CTRL_SWRST);
if (ret)
return ret;
mdelay(STMFX_BOOT_TIME_MS);
return ret;
}
static int stmfx_probe(struct udevice *dev)
{
struct udevice *vdd;
int ret;
ret = device_get_supply_regulator(dev, "vdd-supply", &vdd);
if (ret && ret != -ENOENT) {
dev_err(dev, "vdd regulator error:%d\n", ret);
return ret;
}
if (!ret) {
ret = regulator_set_enable(vdd, true);
if (ret) {
dev_err(dev, "vdd enable failed: %d\n", ret);
return ret;
}
}
return stmfx_chip_init(dev);
}
static const struct udevice_id stmfx_match[] = {
{ .compatible = "st,stmfx-0300", },
};
U_BOOT_DRIVER(stmfx) = {
.name = "stmfx",
.id = UCLASS_I2C_GENERIC,
.of_match = of_match_ptr(stmfx_match),
.probe = stmfx_probe,
.bind = dm_scan_fdt_dev,
};
@@ -0,0 +1,420 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/libfdt.h>
#include <linux/err.h>
#include <linux/list.h>
#include <dm.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <dm/util.h>
#include <dm/of_access.h>
DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
/**
* pinctrl_config_one() - apply pinctrl settings for a single node
*
* @config: pin configuration node
* @return: 0 on success, or negative error code on failure
*/
static int pinctrl_config_one(struct udevice *config)
{
struct udevice *pctldev;
const struct pinctrl_ops *ops;
pctldev = config;
for (;;) {
pctldev = dev_get_parent(pctldev);
if (!pctldev) {
dev_err(config, "could not find pctldev\n");
return -EINVAL;
}
if (pctldev->uclass->uc_drv->id == UCLASS_PINCTRL)
break;
}
ops = pinctrl_get_ops(pctldev);
return ops->set_state(pctldev, config);
}
/**
* pinctrl_select_state_full() - full implementation of pinctrl_select_state
*
* @dev: peripheral device
* @statename: state name, like "default"
* @return: 0 on success, or negative error code on failure
*/
static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
{
char propname[32]; /* long enough */
const fdt32_t *list;
uint32_t phandle;
struct udevice *config;
int state, size, i, ret;
state = dev_read_stringlist_search(dev, "pinctrl-names", statename);
if (state < 0) {
char *end;
/*
* If statename is not found in "pinctrl-names",
* assume statename is just the integer state ID.
*/
state = simple_strtoul(statename, &end, 10);
if (*end)
return -EINVAL;
}
snprintf(propname, sizeof(propname), "pinctrl-%d", state);
list = dev_read_prop(dev, propname, &size);
if (!list)
return -EINVAL;
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);
if (ret) {
dev_warn(dev, "%s: uclass_get_device_by_phandle_id: err=%d\n",
__func__, ret);
continue;
}
ret = pinctrl_config_one(config);
if (ret) {
dev_warn(dev, "%s: pinctrl_config_one: err=%d\n",
__func__, ret);
continue;
}
}
return 0;
}
/**
* pinconfig_post_bind() - post binding for PINCONFIG uclass
* Recursively bind its children as pinconfig devices.
*
* @dev: pinconfig device
* @return: 0 on success, or negative error code on failure
*/
static int pinconfig_post_bind(struct udevice *dev)
{
bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
const char *name;
ofnode node;
int ret;
if (!dev_of_valid(dev))
return 0;
dev_for_each_subnode(node, dev) {
if (pre_reloc_only &&
!ofnode_pre_reloc(node))
continue;
/*
* If this node has "compatible" property, this is not
* a pin configuration node, but a normal device. skip.
*/
ofnode_get_property(node, "compatible", &ret);
if (ret >= 0)
continue;
/* If this node has "gpio-controller" property, skip */
if (ofnode_read_bool(node, "gpio-controller"))
continue;
if (ret != -FDT_ERR_NOTFOUND)
return ret;
name = ofnode_get_name(node);
if (!name)
return -EINVAL;
ret = device_bind_driver_to_node(dev, "pinconfig", name,
node, NULL);
if (ret)
return ret;
}
return 0;
}
UCLASS_DRIVER(pinconfig) = {
.id = UCLASS_PINCONFIG,
#if CONFIG_IS_ENABLED(PINCONF_RECURSIVE)
.post_bind = pinconfig_post_bind,
#endif
.name = "pinconfig",
};
U_BOOT_DRIVER(pinconfig_generic) = {
.name = "pinconfig",
.id = UCLASS_PINCONFIG,
};
#else
static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
{
return -ENODEV;
}
static int pinconfig_post_bind(struct udevice *dev)
{
return 0;
}
#endif
static int
pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset,
struct udevice **pctldev,
unsigned int *pin_selector)
{
struct ofnode_phandle_args args;
unsigned gpio_offset, pfc_base, pfc_pins;
int ret;
ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
0, &args);
if (ret) {
dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n",
__func__, ret);
return ret;
}
ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL,
args.node, pctldev);
if (ret) {
dev_dbg(dev,
"%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
}
gpio_offset = args.args[0];
pfc_base = args.args[1];
pfc_pins = args.args[2];
if (offset < gpio_offset || offset > gpio_offset + pfc_pins) {
dev_dbg(dev,
"%s: GPIO can not be mapped to pincontrol pin\n",
__func__);
return -EINVAL;
}
offset -= gpio_offset;
offset += pfc_base;
*pin_selector = offset;
return 0;
}
/**
* pinctrl_gpio_request() - request a single pin to be used as GPIO
*
* @dev: GPIO peripheral device
* @offset: the GPIO pin offset from the GPIO controller
* @return: 0 on success, or negative error code on failure
*/
int pinctrl_gpio_request(struct udevice *dev, unsigned offset)
{
const struct pinctrl_ops *ops;
struct udevice *pctldev;
unsigned int pin_selector;
int ret;
ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset,
&pctldev, &pin_selector);
if (ret)
return ret;
ops = pinctrl_get_ops(pctldev);
if (!ops || !ops->gpio_request_enable)
return -ENOTSUPP;
return ops->gpio_request_enable(pctldev, pin_selector);
}
/**
* pinctrl_gpio_free() - free a single pin used as GPIO
*
* @dev: GPIO peripheral device
* @offset: the GPIO pin offset from the GPIO controller
* @return: 0 on success, or negative error code on failure
*/
int pinctrl_gpio_free(struct udevice *dev, unsigned offset)
{
const struct pinctrl_ops *ops;
struct udevice *pctldev;
unsigned int pin_selector;
int ret;
ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset,
&pctldev, &pin_selector);
if (ret)
return ret;
ops = pinctrl_get_ops(pctldev);
if (!ops || !ops->gpio_disable_free)
return -ENOTSUPP;
return ops->gpio_disable_free(pctldev, pin_selector);
}
/**
* pinctrl_select_state_simple() - simple implementation of pinctrl_select_state
*
* @dev: peripheral device
* @return: 0 on success, or negative error code on failure
*/
static int pinctrl_select_state_simple(struct udevice *dev)
{
struct udevice *pctldev;
struct pinctrl_ops *ops;
int ret;
/*
* For most system, there is only one pincontroller device. But in
* case of multiple pincontroller devices, probe the one with sequence
* number 0 (defined by alias) to avoid race condition.
*/
ret = uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &pctldev);
if (ret)
/* if not found, get the first one */
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
if (ret)
return ret;
ops = pinctrl_get_ops(pctldev);
if (!ops->set_state_simple) {
dev_dbg(dev, "set_state_simple op missing\n");
return -ENOSYS;
}
return ops->set_state_simple(pctldev, dev);
}
int pinctrl_select_state(struct udevice *dev, const char *statename)
{
/*
* Some device which is logical like mmc.blk, do not have
* a valid ofnode.
*/
if (!ofnode_valid(dev->node))
return 0;
/*
* Try full-implemented pinctrl first.
* If it fails or is not implemented, try simple one.
*/
if (pinctrl_select_state_full(dev, statename))
return pinctrl_select_state_simple(dev);
return 0;
}
int pinctrl_request(struct udevice *dev, int func, int flags)
{
struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (!ops->request)
return -ENOSYS;
return ops->request(dev, func, flags);
}
int pinctrl_request_noflags(struct udevice *dev, int func)
{
return pinctrl_request(dev, func, 0);
}
int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph)
{
struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (!ops->get_periph_id)
return -ENOSYS;
return ops->get_periph_id(dev, periph);
}
int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index)
{
struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (!ops->get_gpio_mux)
return -ENOSYS;
return ops->get_gpio_mux(dev, banknum, index);
}
int pinctrl_get_pins_count(struct udevice *dev)
{
struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (!ops->get_pins_count)
return -ENOSYS;
return ops->get_pins_count(dev);
}
int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf,
int size)
{
struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (!ops->get_pin_name)
return -ENOSYS;
snprintf(buf, size, ops->get_pin_name(dev, selector));
return 0;
}
int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf,
int size)
{
struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (!ops->get_pin_muxing)
return -ENOSYS;
return ops->get_pin_muxing(dev, selector, buf, size);
}
/**
* pinconfig_post_bind() - post binding for PINCTRL uclass
* Recursively bind child nodes as pinconfig devices in case of full pinctrl.
*
* @dev: pinctrl device
* @return: 0 on success, or negative error code on failure
*/
static int __maybe_unused pinctrl_post_bind(struct udevice *dev)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
if (!ops) {
dev_dbg(dev, "ops is not set. Do not bind.\n");
return -EINVAL;
}
/*
* If set_state callback is set, we assume this pinctrl driver is the
* full implementation. In this case, its child nodes should be bound
* so that peripheral devices can easily search in parent devices
* during later DT-parsing.
*/
if (ops->set_state)
return pinconfig_post_bind(dev);
return 0;
}
UCLASS_DRIVER(pinctrl) = {
.id = UCLASS_PINCTRL,
.post_bind = pinctrl_post_bind,
.flags = DM_UC_FLAG_SEQ_ALIAS,
.name = "pinctrl",
};
@@ -0,0 +1,355 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Pinctrl driver for Microchip PIC32 SoCs
* Copyright (c) 2015 Microchip Technology Inc.
* Written by Purna Chandra Mandal <purna.mandal@microchip.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <dm/pinctrl.h>
#include <mach/pic32.h>
DECLARE_GLOBAL_DATA_PTR;
/* PIC32 has 10 peripheral ports with 16 pins each.
* Ports are marked PORTA-PORTK or PORT0-PORT9.
*/
enum {
PIC32_PORT_A = 0,
PIC32_PORT_B = 1,
PIC32_PORT_C = 2,
PIC32_PORT_D = 3,
PIC32_PORT_E = 4,
PIC32_PORT_F = 5,
PIC32_PORT_G = 6,
PIC32_PORT_H = 7,
PIC32_PORT_J = 8, /* no PORT_I */
PIC32_PORT_K = 9,
PIC32_PINS_PER_PORT = 16,
};
#define PIN_CONFIG_PIC32_DIGITAL (PIN_CONFIG_END + 1)
#define PIN_CONFIG_PIC32_ANALOG (PIN_CONFIG_END + 2)
/* pin configuration descriptor */
struct pic32_pin_config {
u16 port; /* port number */
u16 pin; /* pin number in the port */
u32 config; /* one of PIN_CONFIG_* */
};
#define PIN_CONFIG(_prt, _pin, _cfg) \
{.port = (_prt), .pin = (_pin), .config = (_cfg), }
/* In PIC32 muxing is performed at pin-level through two
* different set of registers - one set for input functions,
* and other for output functions.
* Pin configuration is handled through port register.
*/
/* Port control registers */
struct pic32_reg_port {
struct pic32_reg_atomic ansel;
struct pic32_reg_atomic tris;
struct pic32_reg_atomic port;
struct pic32_reg_atomic lat;
struct pic32_reg_atomic odc;
struct pic32_reg_atomic cnpu;
struct pic32_reg_atomic cnpd;
struct pic32_reg_atomic cncon;
struct pic32_reg_atomic unused[8];
};
/* Input function mux registers */
struct pic32_reg_in_mux {
u32 unused0;
u32 int1[4];
u32 unused1;
u32 t2ck[8];
u32 ic1[9];
u32 unused2;
u32 ocfar;
u32 unused3;
u32 u1rx;
u32 u1cts;
u32 u2rx;
u32 u2cts;
u32 u3rx;
u32 u3cts;
u32 u4rx;
u32 u4cts;
u32 u5rx;
u32 u5cts;
u32 u6rx;
u32 u6cts;
u32 unused4;
u32 sdi1;
u32 ss1;
u32 unused5;
u32 sdi2;
u32 ss2;
u32 unused6;
u32 sdi3;
u32 ss3;
u32 unused7;
u32 sdi4;
u32 ss4;
u32 unused8;
u32 sdi5;
u32 ss5;
u32 unused9;
u32 sdi6;
u32 ss6;
u32 c1rx;
u32 c2rx;
u32 refclki1;
u32 refclki2;
u32 refclki3;
u32 refclki4;
};
/* output mux register offset */
#define PPS_OUT(__port, __pin) \
(((__port) * PIC32_PINS_PER_PORT + (__pin)) << 2)
struct pic32_pinctrl_priv {
struct pic32_reg_in_mux *mux_in; /* mux input function */
struct pic32_reg_port *pinconf; /* pin configuration*/
void __iomem *mux_out; /* mux output function */
};
enum {
PERIPH_ID_UART1,
PERIPH_ID_UART2,
PERIPH_ID_ETH,
PERIPH_ID_USB,
PERIPH_ID_SDHCI,
PERIPH_ID_I2C1,
PERIPH_ID_I2C2,
PERIPH_ID_SPI1,
PERIPH_ID_SPI2,
PERIPH_ID_SQI,
};
static int pic32_pinconfig_one(struct pic32_pinctrl_priv *priv,
u32 port_nr, u32 pin, u32 param)
{
struct pic32_reg_port *port;
port = &priv->pinconf[port_nr];
switch (param) {
case PIN_CONFIG_PIC32_DIGITAL:
writel(BIT(pin), &port->ansel.clr);
break;
case PIN_CONFIG_PIC32_ANALOG:
writel(BIT(pin), &port->ansel.set);
break;
case PIN_CONFIG_INPUT_ENABLE:
writel(BIT(pin), &port->tris.set);
break;
case PIN_CONFIG_OUTPUT:
writel(BIT(pin), &port->tris.clr);
break;
case PIN_CONFIG_BIAS_PULL_UP:
writel(BIT(pin), &port->cnpu.set);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
writel(BIT(pin), &port->cnpd.set);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
writel(BIT(pin), &port->odc.set);
break;
default:
break;
}
return 0;
}
static int pic32_pinconfig_set(struct pic32_pinctrl_priv *priv,
const struct pic32_pin_config *list, int count)
{
int i;
for (i = 0 ; i < count; i++)
pic32_pinconfig_one(priv, list[i].port,
list[i].pin, list[i].config);
return 0;
}
static void pic32_eth_pin_config(struct udevice *dev)
{
struct pic32_pinctrl_priv *priv = dev_get_priv(dev);
const struct pic32_pin_config configs[] = {
/* EMDC - D11 */
PIN_CONFIG(PIC32_PORT_D, 11, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_D, 11, PIN_CONFIG_OUTPUT),
/* ETXEN */
PIN_CONFIG(PIC32_PORT_D, 6, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_D, 6, PIN_CONFIG_OUTPUT),
/* ECRSDV */
PIN_CONFIG(PIC32_PORT_H, 13, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_H, 13, PIN_CONFIG_INPUT_ENABLE),
/* ERXD0 */
PIN_CONFIG(PIC32_PORT_H, 8, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_H, 8, PIN_CONFIG_INPUT_ENABLE),
PIN_CONFIG(PIC32_PORT_H, 8, PIN_CONFIG_BIAS_PULL_DOWN),
/* ERXD1 */
PIN_CONFIG(PIC32_PORT_H, 5, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_H, 5, PIN_CONFIG_INPUT_ENABLE),
PIN_CONFIG(PIC32_PORT_H, 5, PIN_CONFIG_BIAS_PULL_DOWN),
/* EREFCLK */
PIN_CONFIG(PIC32_PORT_J, 11, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_J, 11, PIN_CONFIG_INPUT_ENABLE),
/* ETXD1 */
PIN_CONFIG(PIC32_PORT_J, 9, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_J, 9, PIN_CONFIG_OUTPUT),
/* ETXD0 */
PIN_CONFIG(PIC32_PORT_J, 8, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_J, 8, PIN_CONFIG_OUTPUT),
/* EMDIO */
PIN_CONFIG(PIC32_PORT_J, 1, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_J, 1, PIN_CONFIG_INPUT_ENABLE),
/* ERXERR */
PIN_CONFIG(PIC32_PORT_F, 3, PIN_CONFIG_PIC32_DIGITAL),
PIN_CONFIG(PIC32_PORT_F, 3, PIN_CONFIG_INPUT_ENABLE),
};
pic32_pinconfig_set(priv, configs, ARRAY_SIZE(configs));
}
static int pic32_pinctrl_request(struct udevice *dev, int func, int flags)
{
struct pic32_pinctrl_priv *priv = dev_get_priv(dev);
switch (func) {
case PERIPH_ID_UART2:
/* PPS for U2 RX/TX */
writel(0x02, priv->mux_out + PPS_OUT(PIC32_PORT_G, 9));
writel(0x05, &priv->mux_in->u2rx); /* B0 */
/* set digital mode */
pic32_pinconfig_one(priv, PIC32_PORT_G, 9,
PIN_CONFIG_PIC32_DIGITAL);
pic32_pinconfig_one(priv, PIC32_PORT_B, 0,
PIN_CONFIG_PIC32_DIGITAL);
break;
case PERIPH_ID_ETH:
pic32_eth_pin_config(dev);
break;
default:
debug("%s: unknown-unhandled case\n", __func__);
break;
}
return 0;
}
static int pic32_pinctrl_get_periph_id(struct udevice *dev,
struct udevice *periph)
{
int ret;
u32 cell[2];
ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(periph),
"interrupts", cell, ARRAY_SIZE(cell));
if (ret < 0)
return -EINVAL;
/* interrupt number */
switch (cell[0]) {
case 112 ... 114:
return PERIPH_ID_UART1;
case 145 ... 147:
return PERIPH_ID_UART2;
case 109 ... 111:
return PERIPH_ID_SPI1;
case 142 ... 144:
return PERIPH_ID_SPI2;
case 115 ... 117:
return PERIPH_ID_I2C1;
case 148 ... 150:
return PERIPH_ID_I2C2;
case 132 ... 133:
return PERIPH_ID_USB;
case 169:
return PERIPH_ID_SQI;
case 191:
return PERIPH_ID_SDHCI;
case 153:
return PERIPH_ID_ETH;
default:
break;
}
return -ENOENT;
}
static int pic32_pinctrl_set_state_simple(struct udevice *dev,
struct udevice *periph)
{
int func;
debug("%s: periph %s\n", __func__, periph->name);
func = pic32_pinctrl_get_periph_id(dev, periph);
if (func < 0)
return func;
return pic32_pinctrl_request(dev, func, 0);
}
static struct pinctrl_ops pic32_pinctrl_ops = {
.set_state_simple = pic32_pinctrl_set_state_simple,
.request = pic32_pinctrl_request,
.get_periph_id = pic32_pinctrl_get_periph_id,
};
static int pic32_pinctrl_probe(struct udevice *dev)
{
struct pic32_pinctrl_priv *priv = dev_get_priv(dev);
struct fdt_resource res;
void *fdt = (void *)gd->fdt_blob;
int node = dev_of_offset(dev);
int ret;
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"ppsin", &res);
if (ret < 0) {
printf("pinctrl: resource \"ppsin\" not found\n");
return ret;
}
priv->mux_in = ioremap(res.start, fdt_resource_size(&res));
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"ppsout", &res);
if (ret < 0) {
printf("pinctrl: resource \"ppsout\" not found\n");
return ret;
}
priv->mux_out = ioremap(res.start, fdt_resource_size(&res));
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"port", &res);
if (ret < 0) {
printf("pinctrl: resource \"port\" not found\n");
return ret;
}
priv->pinconf = ioremap(res.start, fdt_resource_size(&res));
return 0;
}
static const struct udevice_id pic32_pinctrl_ids[] = {
{ .compatible = "microchip,pic32mzda-pinctrl" },
{ }
};
U_BOOT_DRIVER(pinctrl_pic32) = {
.name = "pinctrl_pic32",
.id = UCLASS_PINCTRL,
.of_match = pic32_pinctrl_ids,
.ops = &pic32_pinctrl_ops,
.probe = pic32_pinctrl_probe,
.bind = dm_scan_fdt_dev,
.priv_auto_alloc_size = sizeof(struct pic32_pinctrl_priv),
};
@@ -0,0 +1,469 @@
#include <common.h>
#include <dm.h>
#include <hwspinlock.h>
#include <asm/arch/gpio.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
DECLARE_GLOBAL_DATA_PTR;
#define MAX_PINS_ONE_IP 70
#define MODE_BITS_MASK 3
#define OSPEED_MASK 3
#define PUPD_MASK 3
#define OTYPE_MSK 1
#define AFR_MASK 0xF
struct stm32_pinctrl_priv {
struct hwspinlock hws;
int pinctrl_ngpios;
struct list_head gpio_dev;
};
struct stm32_gpio_bank {
struct udevice *gpio_dev;
struct list_head list;
};
#ifndef CONFIG_SPL_BUILD
static char pin_name[PINNAME_SIZE];
#define PINMUX_MODE_COUNT 5
static const char * const pinmux_mode[PINMUX_MODE_COUNT] = {
"gpio input",
"gpio output",
"analog",
"unknown",
"alt function",
};
static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset)
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
struct stm32_gpio_regs *regs = priv->regs;
u32 af;
u32 alt_shift = (offset % 8) * 4;
u32 alt_index = offset / 8;
af = (readl(&regs->afr[alt_index]) &
GENMASK(alt_shift + 3, alt_shift)) >> alt_shift;
return af;
}
static int stm32_populate_gpio_dev_list(struct udevice *dev)
{
struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
struct udevice *gpio_dev;
struct udevice *child;
struct stm32_gpio_bank *gpio_bank;
int ret;
/*
* parse pin-controller sub-nodes (ie gpio bank nodes) and fill
* a list with all gpio device reference which belongs to the
* current pin-controller. This list is used to find pin_name and
* pin muxing
*/
list_for_each_entry(child, &dev->child_head, sibling_node) {
ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
&gpio_dev);
if (ret < 0)
continue;
gpio_bank = malloc(sizeof(*gpio_bank));
if (!gpio_bank) {
dev_err(dev, "Not enough memory\n");
return -ENOMEM;
}
gpio_bank->gpio_dev = gpio_dev;
list_add_tail(&gpio_bank->list, &priv->gpio_dev);
}
return 0;
}
static int stm32_pinctrl_get_pins_count(struct udevice *dev)
{
struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
struct gpio_dev_priv *uc_priv;
struct stm32_gpio_bank *gpio_bank;
/*
* if get_pins_count has already been executed once on this
* pin-controller, no need to run it again
*/
if (priv->pinctrl_ngpios)
return priv->pinctrl_ngpios;
if (list_empty(&priv->gpio_dev))
stm32_populate_gpio_dev_list(dev);
/*
* walk through all banks to retrieve the pin-controller
* pins number
*/
list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
priv->pinctrl_ngpios += uc_priv->gpio_count;
}
return priv->pinctrl_ngpios;
}
static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev,
unsigned int selector,
unsigned int *idx)
{
struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
struct stm32_gpio_bank *gpio_bank;
struct gpio_dev_priv *uc_priv;
int pin_count = 0;
if (list_empty(&priv->gpio_dev))
stm32_populate_gpio_dev_list(dev);
/* look up for the bank which owns the requested pin */
list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
if (selector < (pin_count + uc_priv->gpio_count)) {
/*
* we found the bank, convert pin selector to
* gpio bank index
*/
*idx = stm32_offset_to_index(gpio_bank->gpio_dev,
selector - pin_count);
if (IS_ERR_VALUE(*idx))
return NULL;
return gpio_bank->gpio_dev;
}
pin_count += uc_priv->gpio_count;
}
return NULL;
}
static const char *stm32_pinctrl_get_pin_name(struct udevice *dev,
unsigned int selector)
{
struct gpio_dev_priv *uc_priv;
struct udevice *gpio_dev;
unsigned int gpio_idx;
/* look up for the bank which owns the requested pin */
gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
if (!gpio_dev) {
snprintf(pin_name, PINNAME_SIZE, "Error");
} else {
uc_priv = dev_get_uclass_priv(gpio_dev);
snprintf(pin_name, PINNAME_SIZE, "%s%d",
uc_priv->bank_name,
gpio_idx);
}
return pin_name;
}
static int stm32_pinctrl_get_pin_muxing(struct udevice *dev,
unsigned int selector,
char *buf,
int size)
{
struct udevice *gpio_dev;
const char *label;
int mode;
int af_num;
unsigned int gpio_idx;
/* look up for the bank which owns the requested pin */
gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
if (!gpio_dev)
return -ENODEV;
mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label);
dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n",
selector, gpio_idx, mode);
switch (mode) {
case GPIOF_UNKNOWN:
/* should never happen */
return -EINVAL;
case GPIOF_UNUSED:
snprintf(buf, size, "%s", pinmux_mode[mode]);
break;
case GPIOF_FUNC:
af_num = stm32_pinctrl_get_af(gpio_dev, gpio_idx);
snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num);
break;
case GPIOF_OUTPUT:
case GPIOF_INPUT:
snprintf(buf, size, "%s %s",
pinmux_mode[mode], label ? label : "");
break;
}
return 0;
}
#endif
static int stm32_pinctrl_probe(struct udevice *dev)
{
struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
int ret;
INIT_LIST_HEAD(&priv->gpio_dev);
/* hwspinlock property is optional, just log the error */
ret = hwspinlock_get_by_index(dev, 0, &priv->hws);
if (ret)
debug("%s: hwspinlock_get_by_index may have failed (%d)\n",
__func__, ret);
return 0;
}
static int stm32_gpio_config(struct gpio_desc *desc,
const struct stm32_gpio_ctl *ctl)
{
struct stm32_gpio_priv *priv = dev_get_priv(desc->dev);
struct stm32_gpio_regs *regs = priv->regs;
struct stm32_pinctrl_priv *ctrl_priv;
int ret;
u32 index;
if (!ctl || ctl->af > 15 || ctl->mode > 3 || ctl->otype > 1 ||
ctl->pupd > 2 || ctl->speed > 3)
return -EINVAL;
ctrl_priv = dev_get_priv(dev_get_parent(desc->dev));
ret = hwspinlock_lock_timeout(&ctrl_priv->hws, 10);
if (ret == -ETIME) {
dev_err(desc->dev, "HWSpinlock timeout\n");
return ret;
}
index = (desc->offset & 0x07) * 4;
clrsetbits_le32(&regs->afr[desc->offset >> 3], AFR_MASK << index,
ctl->af << index);
index = desc->offset * 2;
clrsetbits_le32(&regs->moder, MODE_BITS_MASK << index,
ctl->mode << index);
clrsetbits_le32(&regs->ospeedr, OSPEED_MASK << index,
ctl->speed << index);
clrsetbits_le32(&regs->pupdr, PUPD_MASK << index, ctl->pupd << index);
index = desc->offset;
clrsetbits_le32(&regs->otyper, OTYPE_MSK << index, ctl->otype << index);
hwspinlock_unlock(&ctrl_priv->hws);
return 0;
}
static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin)
{
gpio_dsc->port = (port_pin & 0x1F000) >> 12;
gpio_dsc->pin = (port_pin & 0x0F00) >> 8;
debug("%s: GPIO:port= %d, pin= %d\n", __func__, gpio_dsc->port,
gpio_dsc->pin);
return 0;
}
static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node)
{
gpio_fn &= 0x00FF;
gpio_ctl->af = 0;
switch (gpio_fn) {
case 0:
gpio_ctl->mode = STM32_GPIO_MODE_IN;
break;
case 1 ... 16:
gpio_ctl->mode = STM32_GPIO_MODE_AF;
gpio_ctl->af = gpio_fn - 1;
break;
case 17:
gpio_ctl->mode = STM32_GPIO_MODE_AN;
break;
default:
gpio_ctl->mode = STM32_GPIO_MODE_OUT;
break;
}
gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0);
if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain"))
gpio_ctl->otype = STM32_GPIO_OTYPE_OD;
else
gpio_ctl->otype = STM32_GPIO_OTYPE_PP;
if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up"))
gpio_ctl->pupd = STM32_GPIO_PUPD_UP;
else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down"))
gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN;
else
gpio_ctl->pupd = STM32_GPIO_PUPD_NO;
debug("%s: gpio fn= %d, slew-rate= %x, op type= %x, pull-upd is = %x\n",
__func__, gpio_fn, gpio_ctl->speed, gpio_ctl->otype,
gpio_ctl->pupd);
return 0;
}
static int stm32_pinctrl_config(int offset)
{
u32 pin_mux[MAX_PINS_ONE_IP];
int rv, len;
/*
* check for "pinmux" property in each subnode (e.g. pins1 and pins2 for
* usart1) of pin controller phandle "pinctrl-0"
* */
fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
struct stm32_gpio_dsc gpio_dsc;
struct stm32_gpio_ctl gpio_ctl;
int i;
len = fdtdec_get_int_array_count(gd->fdt_blob, offset,
"pinmux", pin_mux,
ARRAY_SIZE(pin_mux));
debug("%s: no of pinmux entries= %d\n", __func__, len);
if (len < 0)
return -EINVAL;
for (i = 0; i < len; i++) {
struct gpio_desc desc;
debug("%s: pinmux = %x\n", __func__, *(pin_mux + i));
prep_gpio_dsc(&gpio_dsc, *(pin_mux + i));
prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), offset);
rv = uclass_get_device_by_seq(UCLASS_GPIO,
gpio_dsc.port,
&desc.dev);
if (rv)
return rv;
desc.offset = gpio_dsc.pin;
rv = stm32_gpio_config(&desc, &gpio_ctl);
debug("%s: rv = %d\n\n", __func__, rv);
if (rv)
return rv;
}
}
return 0;
}
static int stm32_pinctrl_bind(struct udevice *dev)
{
ofnode node;
const char *name;
int ret;
dev_for_each_subnode(node, dev) {
debug("%s: bind %s\n", __func__, ofnode_get_name(node));
ofnode_get_property(node, "gpio-controller", &ret);
if (ret < 0)
continue;
/* Get the name of each gpio node */
name = ofnode_get_name(node);
if (!name)
return -EINVAL;
/* Bind each gpio node */
ret = device_bind_driver_to_node(dev, "gpio_stm32",
name, node, NULL);
if (ret)
return ret;
debug("%s: bind %s\n", __func__, name);
}
return 0;
}
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
return stm32_pinctrl_config(dev_of_offset(config));
}
#else /* PINCTRL_FULL */
static int stm32_pinctrl_set_state_simple(struct udevice *dev,
struct udevice *periph)
{
const void *fdt = gd->fdt_blob;
const fdt32_t *list;
uint32_t phandle;
int config_node;
int size, i, ret;
list = fdt_getprop(fdt, dev_of_offset(periph), "pinctrl-0", &size);
if (!list)
return -EINVAL;
debug("%s: periph->name = %s\n", __func__, periph->name);
size /= sizeof(*list);
for (i = 0; i < size; i++) {
phandle = fdt32_to_cpu(*list++);
config_node = fdt_node_offset_by_phandle(fdt, phandle);
if (config_node < 0) {
pr_err("prop pinctrl-0 index %d invalid phandle\n", i);
return -EINVAL;
}
ret = stm32_pinctrl_config(config_node);
if (ret)
return ret;
}
return 0;
}
#endif /* PINCTRL_FULL */
static struct pinctrl_ops stm32_pinctrl_ops = {
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
.set_state = stm32_pinctrl_set_state,
#else /* PINCTRL_FULL */
.set_state_simple = stm32_pinctrl_set_state_simple,
#endif /* PINCTRL_FULL */
#ifndef CONFIG_SPL_BUILD
.get_pin_name = stm32_pinctrl_get_pin_name,
.get_pins_count = stm32_pinctrl_get_pins_count,
.get_pin_muxing = stm32_pinctrl_get_pin_muxing,
#endif
};
static const struct udevice_id stm32_pinctrl_ids[] = {
{ .compatible = "st,stm32f429-pinctrl" },
{ .compatible = "st,stm32f469-pinctrl" },
{ .compatible = "st,stm32f746-pinctrl" },
{ .compatible = "st,stm32f769-pinctrl" },
{ .compatible = "st,stm32h743-pinctrl" },
{ .compatible = "st,stm32mp157-pinctrl" },
{ .compatible = "st,stm32mp157-z-pinctrl" },
{ }
};
U_BOOT_DRIVER(pinctrl_stm32) = {
.name = "pinctrl_stm32",
.id = UCLASS_PINCTRL,
.of_match = stm32_pinctrl_ids,
.ops = &stm32_pinctrl_ops,
.bind = stm32_pinctrl_bind,
.probe = stm32_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv),
};
@@ -0,0 +1,141 @@
if ARCH_RMOBILE
config PINCTRL_PFC
bool "Renesas pin control drivers"
depends on DM && ARCH_RMOBILE
default n if CPU_RZA1
help
Enable support for clock present on Renesas RCar SoCs.
config PINCTRL_PFC_R8A7790
bool "Renesas RCar Gen2 R8A7790 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A7790 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A7791
bool "Renesas RCar Gen2 R8A7791 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A7791 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A7792
bool "Renesas RCar Gen2 R8A7792 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A7792 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A7793
bool "Renesas RCar Gen2 R8A7793 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A7793 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A7794
bool "Renesas RCar Gen2 R8A7794 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A7794 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A7795
bool "Renesas RCar Gen3 R8A7795 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A7795 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A7796
bool "Renesas RCar Gen3 R8A7796 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A7796 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A77965
bool "Renesas RCar Gen3 R8A77965 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A77965 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A77970
bool "Renesas RCar Gen3 R8A77970 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A77970 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A77980
bool "Renesas RCar Gen3 R8A77980 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A77980 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A77990
bool "Renesas RCar Gen3 R8A77990 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A77990 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R8A77995
bool "Renesas RCar Gen3 R8A77995 pin control driver"
depends on PINCTRL_PFC
help
Support pin multiplexing control on Renesas RCar Gen3 R8A77995 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
config PINCTRL_PFC_R7S72100
bool "Renesas RZ/A1 R7S72100 pin control driver"
depends on CPU_RZA1
default y if CPU_RZA1
help
Support pin multiplexing control on Renesas RZ/A1 R7S72100 SoCs.
The driver is controlled by a device tree node which contains both
the GPIO definitions and pin control functions for each available
multiplex function.
endif
@@ -0,0 +1,14 @@
obj-$(CONFIG_PINCTRL_PFC) += pfc.o
obj-$(CONFIG_PINCTRL_PFC_R8A7790) += pfc-r8a7790.o
obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o
obj-$(CONFIG_PINCTRL_PFC_R8A7792) += pfc-r8a7792.o
obj-$(CONFIG_PINCTRL_PFC_R8A7793) += pfc-r8a7791.o
obj-$(CONFIG_PINCTRL_PFC_R8A7794) += pfc-r8a7794.o
obj-$(CONFIG_PINCTRL_PFC_R8A7795) += pfc-r8a7795.o
obj-$(CONFIG_PINCTRL_PFC_R8A7796) += pfc-r8a7796.o
obj-$(CONFIG_PINCTRL_PFC_R8A77965) += pfc-r8a77965.o
obj-$(CONFIG_PINCTRL_PFC_R8A77970) += pfc-r8a77970.o
obj-$(CONFIG_PINCTRL_PFC_R8A77980) += pfc-r8a77980.o
obj-$(CONFIG_PINCTRL_PFC_R8A77990) += pfc-r8a77990.o
obj-$(CONFIG_PINCTRL_PFC_R8A77995) += pfc-r8a77995.o
obj-$(CONFIG_PINCTRL_PFC_R7S72100) += pfc-r7s72100.o
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* R7S72100 processor support
*
* Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <linux/io.h>
#include <linux/err.h>
#define P(bank) (0x0000 + (bank) * 4)
#define PSR(bank) (0x0100 + (bank) * 4)
#define PPR(bank) (0x0200 + (bank) * 4)
#define PM(bank) (0x0300 + (bank) * 4)
#define PMC(bank) (0x0400 + (bank) * 4)
#define PFC(bank) (0x0500 + (bank) * 4)
#define PFCE(bank) (0x0600 + (bank) * 4)
#define PNOT(bank) (0x0700 + (bank) * 4)
#define PMSR(bank) (0x0800 + (bank) * 4)
#define PMCSR(bank) (0x0900 + (bank) * 4)
#define PFCAE(bank) (0x0A00 + (bank) * 4)
#define PIBC(bank) (0x4000 + (bank) * 4)
#define PBDC(bank) (0x4100 + (bank) * 4)
#define PIPC(bank) (0x4200 + (bank) * 4)
#define RZA1_PINS_PER_PORT 16
DECLARE_GLOBAL_DATA_PTR;
struct r7s72100_pfc_platdata {
void __iomem *base;
};
static void r7s72100_pfc_set_function(struct udevice *dev, u16 bank, u16 line,
u16 func, u16 inbuf, u16 bidir)
{
struct r7s72100_pfc_platdata *plat = dev_get_platdata(dev);
clrsetbits_le16(plat->base + PFCAE(bank), BIT(line),
(func & BIT(2)) ? BIT(line) : 0);
clrsetbits_le16(plat->base + PFCE(bank), BIT(line),
(func & BIT(1)) ? BIT(line) : 0);
clrsetbits_le16(plat->base + PFC(bank), BIT(line),
(func & BIT(0)) ? BIT(line) : 0);
clrsetbits_le16(plat->base + PIBC(bank), BIT(line),
inbuf ? BIT(line) : 0);
clrsetbits_le16(plat->base + PBDC(bank), BIT(line),
bidir ? BIT(line) : 0);
setbits_le32(plat->base + PMCSR(bank), BIT(line + 16) | BIT(line));
setbits_le16(plat->base + PIPC(bank), BIT(line));
}
static int r7s72100_pfc_set_state(struct udevice *dev, struct udevice *config)
{
const void *blob = gd->fdt_blob;
int node = dev_of_offset(config);
u32 cells[32];
u16 bank, line, func;
int i, count, bidir;
count = fdtdec_get_int_array_count(blob, node, "pinmux",
cells, ARRAY_SIZE(cells));
if (count < 0) {
printf("%s: bad pinmux array %d\n", __func__, count);
return -EINVAL;
}
if (count > ARRAY_SIZE(cells)) {
printf("%s: unsupported pinmux array count %d\n",
__func__, count);
return -EINVAL;
}
for (i = 0 ; i < count; i++) {
func = (cells[i] >> 16) & 0xf;
if (func == 0 || func > 8) {
printf("Invalid cell %i in node %s!\n",
count, ofnode_get_name(dev_ofnode(config)));
continue;
}
func = (func - 1) & 0x7;
bank = (cells[i] / RZA1_PINS_PER_PORT) & 0xff;
line = cells[i] % RZA1_PINS_PER_PORT;
bidir = 0;
if (bank == 3 && line == 3 && func == 1)
bidir = 1;
r7s72100_pfc_set_function(dev, bank, line, func, 0, bidir);
}
return 0;
}
const struct pinctrl_ops r7s72100_pfc_ops = {
.set_state = r7s72100_pfc_set_state,
};
static int r7s72100_pfc_probe(struct udevice *dev)
{
struct r7s72100_pfc_platdata *plat = dev_get_platdata(dev);
fdt_addr_t addr_base;
ofnode node;
addr_base = devfdt_get_addr(dev);
if (addr_base == FDT_ADDR_T_NONE)
return -EINVAL;
plat->base = (void __iomem *)addr_base;
dev_for_each_subnode(node, dev) {
struct udevice *cdev;
if (!ofnode_read_bool(node, "gpio-controller"))
continue;
device_bind_driver_to_node(dev, "r7s72100-gpio",
ofnode_get_name(node),
node, &cdev);
}
return 0;
}
static const struct udevice_id r7s72100_pfc_match[] = {
{ .compatible = "renesas,r7s72100-ports" },
{}
};
U_BOOT_DRIVER(r7s72100_pfc) = {
.name = "r7s72100_pfc",
.id = UCLASS_PINCTRL,
.of_match = r7s72100_pfc_match,
.probe = r7s72100_pfc_probe,
.platdata_auto_alloc_size = sizeof(struct r7s72100_pfc_platdata),
.ops = &r7s72100_pfc_ops,
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,963 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Pin Control driver for SuperH Pin Function Controller.
*
* Authors: Magnus Damm, Paul Mundt, Laurent Pinchart
*
* Copyright (C) 2008 Magnus Damm
* Copyright (C) 2009 - 2012 Paul Mundt
* Copyright (C) 2017 Marek Vasut
*/
#define DRV_NAME "sh-pfc"
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <dm/pinctrl.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include "sh_pfc.h"
enum sh_pfc_model {
SH_PFC_R8A7790 = 0,
SH_PFC_R8A7791,
SH_PFC_R8A7792,
SH_PFC_R8A7793,
SH_PFC_R8A7794,
SH_PFC_R8A7795,
SH_PFC_R8A7796,
SH_PFC_R8A77965,
SH_PFC_R8A77970,
SH_PFC_R8A77980,
SH_PFC_R8A77990,
SH_PFC_R8A77995,
};
struct sh_pfc_pin_config {
u32 type;
};
struct sh_pfc_pinctrl {
struct sh_pfc *pfc;
struct sh_pfc_pin_config *configs;
const char *func_prop_name;
const char *groups_prop_name;
const char *pins_prop_name;
};
struct sh_pfc_pin_range {
u16 start;
u16 end;
};
struct sh_pfc_pinctrl_priv {
struct sh_pfc pfc;
struct sh_pfc_pinctrl pmx;
};
int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin)
{
unsigned int offset;
unsigned int i;
for (i = 0, offset = 0; i < pfc->nr_ranges; ++i) {
const struct sh_pfc_pin_range *range = &pfc->ranges[i];
if (pin <= range->end)
return pin >= range->start
? offset + pin - range->start : -1;
offset += range->end - range->start + 1;
}
return -EINVAL;
}
static int sh_pfc_enum_in_range(u16 enum_id, const struct pinmux_range *r)
{
if (enum_id < r->begin)
return 0;
if (enum_id > r->end)
return 0;
return 1;
}
u32 sh_pfc_read_raw_reg(void __iomem *mapped_reg, unsigned int reg_width)
{
switch (reg_width) {
case 8:
return readb(mapped_reg);
case 16:
return readw(mapped_reg);
case 32:
return readl(mapped_reg);
}
BUG();
return 0;
}
void sh_pfc_write_raw_reg(void __iomem *mapped_reg, unsigned int reg_width,
u32 data)
{
switch (reg_width) {
case 8:
writeb(data, mapped_reg);
return;
case 16:
writew(data, mapped_reg);
return;
case 32:
writel(data, mapped_reg);
return;
}
BUG();
}
u32 sh_pfc_read(struct sh_pfc *pfc, u32 reg)
{
return sh_pfc_read_raw_reg((void __iomem *)(uintptr_t)reg, 32);
}
void sh_pfc_write(struct sh_pfc *pfc, u32 reg, u32 data)
{
void __iomem *unlock_reg =
(void __iomem *)(uintptr_t)pfc->info->unlock_reg;
if (pfc->info->unlock_reg)
sh_pfc_write_raw_reg(unlock_reg, 32, ~data);
sh_pfc_write_raw_reg((void __iomem *)(uintptr_t)reg, 32, data);
}
static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
const struct pinmux_cfg_reg *crp,
unsigned int in_pos,
void __iomem **mapped_regp, u32 *maskp,
unsigned int *posp)
{
unsigned int k;
*mapped_regp = (void __iomem *)(uintptr_t)crp->reg;
if (crp->field_width) {
*maskp = (1 << crp->field_width) - 1;
*posp = crp->reg_width - ((in_pos + 1) * crp->field_width);
} else {
*maskp = (1 << crp->var_field_width[in_pos]) - 1;
*posp = crp->reg_width;
for (k = 0; k <= in_pos; k++)
*posp -= crp->var_field_width[k];
}
}
static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
const struct pinmux_cfg_reg *crp,
unsigned int field, u32 value)
{
void __iomem *mapped_reg;
void __iomem *unlock_reg =
(void __iomem *)(uintptr_t)pfc->info->unlock_reg;
unsigned int pos;
u32 mask, data;
sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
dev_dbg(pfc->dev, "write_reg addr = %x, value = 0x%x, field = %u, "
"r_width = %u, f_width = %u\n",
crp->reg, value, field, crp->reg_width, crp->field_width);
mask = ~(mask << pos);
value = value << pos;
data = sh_pfc_read_raw_reg(mapped_reg, crp->reg_width);
data &= mask;
data |= value;
if (pfc->info->unlock_reg)
sh_pfc_write_raw_reg(unlock_reg, 32, ~data);
sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data);
}
static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id,
const struct pinmux_cfg_reg **crp,
unsigned int *fieldp, u32 *valuep)
{
unsigned int k = 0;
while (1) {
const struct pinmux_cfg_reg *config_reg =
pfc->info->cfg_regs + k;
unsigned int r_width = config_reg->reg_width;
unsigned int f_width = config_reg->field_width;
unsigned int curr_width;
unsigned int bit_pos;
unsigned int pos = 0;
unsigned int m = 0;
if (!r_width)
break;
for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width) {
u32 ncomb;
u32 n;
if (f_width)
curr_width = f_width;
else
curr_width = config_reg->var_field_width[m];
ncomb = 1 << curr_width;
for (n = 0; n < ncomb; n++) {
if (config_reg->enum_ids[pos + n] == enum_id) {
*crp = config_reg;
*fieldp = m;
*valuep = n;
return 0;
}
}
pos += ncomb;
m++;
}
k++;
}
return -EINVAL;
}
static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, u16 mark, int pos,
u16 *enum_idp)
{
const u16 *data = pfc->info->pinmux_data;
unsigned int k;
if (pos) {
*enum_idp = data[pos + 1];
return pos + 1;
}
for (k = 0; k < pfc->info->pinmux_data_size; k++) {
if (data[k] == mark) {
*enum_idp = data[k + 1];
return k + 1;
}
}
dev_err(pfc->dev, "cannot locate data/mark enum_id for mark %d\n",
mark);
return -EINVAL;
}
int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
{
const struct pinmux_range *range;
int pos = 0;
switch (pinmux_type) {
case PINMUX_TYPE_GPIO:
case PINMUX_TYPE_FUNCTION:
range = NULL;
break;
case PINMUX_TYPE_OUTPUT:
range = &pfc->info->output;
break;
case PINMUX_TYPE_INPUT:
range = &pfc->info->input;
break;
default:
return -EINVAL;
}
/* Iterate over all the configuration fields we need to update. */
while (1) {
const struct pinmux_cfg_reg *cr;
unsigned int field;
u16 enum_id;
u32 value;
int in_range;
int ret;
pos = sh_pfc_mark_to_enum(pfc, mark, pos, &enum_id);
if (pos < 0)
return pos;
if (!enum_id)
break;
/* Check if the configuration field selects a function. If it
* doesn't, skip the field if it's not applicable to the
* requested pinmux type.
*/
in_range = sh_pfc_enum_in_range(enum_id, &pfc->info->function);
if (!in_range) {
if (pinmux_type == PINMUX_TYPE_FUNCTION) {
/* Functions are allowed to modify all
* fields.
*/
in_range = 1;
} else if (pinmux_type != PINMUX_TYPE_GPIO) {
/* Input/output types can only modify fields
* that correspond to their respective ranges.
*/
in_range = sh_pfc_enum_in_range(enum_id, range);
/*
* special case pass through for fixed
* input-only or output-only pins without
* function enum register association.
*/
if (in_range && enum_id == range->force)
continue;
}
/* GPIOs are only allowed to modify function fields. */
}
if (!in_range)
continue;
ret = sh_pfc_get_config_reg(pfc, enum_id, &cr, &field, &value);
if (ret < 0)
return ret;
sh_pfc_write_config_reg(pfc, cr, field, value);
}
return 0;
}
const struct pinmux_bias_reg *
sh_pfc_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin,
unsigned int *bit)
{
unsigned int i, j;
for (i = 0; pfc->info->bias_regs[i].puen; i++) {
for (j = 0; j < ARRAY_SIZE(pfc->info->bias_regs[i].pins); j++) {
if (pfc->info->bias_regs[i].pins[j] == pin) {
*bit = j;
return &pfc->info->bias_regs[i];
}
}
}
WARN_ONCE(1, "Pin %u is not in bias info list\n", pin);
return NULL;
}
static int sh_pfc_init_ranges(struct sh_pfc *pfc)
{
struct sh_pfc_pin_range *range;
unsigned int nr_ranges;
unsigned int i;
if (pfc->info->pins[0].pin == (u16)-1) {
/* Pin number -1 denotes that the SoC doesn't report pin numbers
* in its pin arrays yet. Consider the pin numbers range as
* continuous and allocate a single range.
*/
pfc->nr_ranges = 1;
pfc->ranges = kzalloc(sizeof(*pfc->ranges), GFP_KERNEL);
if (pfc->ranges == NULL)
return -ENOMEM;
pfc->ranges->start = 0;
pfc->ranges->end = pfc->info->nr_pins - 1;
pfc->nr_gpio_pins = pfc->info->nr_pins;
return 0;
}
/* Count, allocate and fill the ranges. The PFC SoC data pins array must
* be sorted by pin numbers, and pins without a GPIO port must come
* last.
*/
for (i = 1, nr_ranges = 1; i < pfc->info->nr_pins; ++i) {
if (pfc->info->pins[i-1].pin != pfc->info->pins[i].pin - 1)
nr_ranges++;
}
pfc->nr_ranges = nr_ranges;
pfc->ranges = kzalloc(sizeof(*pfc->ranges) * nr_ranges, GFP_KERNEL);
if (pfc->ranges == NULL)
return -ENOMEM;
range = pfc->ranges;
range->start = pfc->info->pins[0].pin;
for (i = 1; i < pfc->info->nr_pins; ++i) {
if (pfc->info->pins[i-1].pin == pfc->info->pins[i].pin - 1)
continue;
range->end = pfc->info->pins[i-1].pin;
if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO))
pfc->nr_gpio_pins = range->end + 1;
range++;
range->start = pfc->info->pins[i].pin;
}
range->end = pfc->info->pins[i-1].pin;
if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO))
pfc->nr_gpio_pins = range->end + 1;
return 0;
}
static int sh_pfc_pinctrl_get_pins_count(struct udevice *dev)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
return priv->pfc.info->nr_pins;
}
static const char *sh_pfc_pinctrl_get_pin_name(struct udevice *dev,
unsigned selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
return priv->pfc.info->pins[selector].name;
}
static int sh_pfc_pinctrl_get_groups_count(struct udevice *dev)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
return priv->pfc.info->nr_groups;
}
static const char *sh_pfc_pinctrl_get_group_name(struct udevice *dev,
unsigned selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
return priv->pfc.info->groups[selector].name;
}
static int sh_pfc_pinctrl_get_functions_count(struct udevice *dev)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
return priv->pfc.info->nr_functions;
}
static const char *sh_pfc_pinctrl_get_function_name(struct udevice *dev,
unsigned selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
return priv->pfc.info->functions[selector].name;
}
static int sh_pfc_gpio_request_enable(struct udevice *dev,
unsigned pin_selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
struct sh_pfc_pin_config *cfg;
const struct sh_pfc_pin *pin = NULL;
int i, ret, idx;
for (i = 0; i < pfc->info->nr_pins; i++) {
if (priv->pfc.info->pins[i].pin != pin_selector)
continue;
pin = &priv->pfc.info->pins[i];
break;
}
if (!pin)
return -EINVAL;
idx = sh_pfc_get_pin_index(pfc, pin->pin);
cfg = &pmx->configs[idx];
if (cfg->type != PINMUX_TYPE_NONE)
return -EBUSY;
ret = sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO);
if (ret)
return ret;
cfg->type = PINMUX_TYPE_GPIO;
return 0;
}
static int sh_pfc_gpio_disable_free(struct udevice *dev,
unsigned pin_selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
struct sh_pfc_pin_config *cfg;
const struct sh_pfc_pin *pin = NULL;
int i, idx;
for (i = 0; i < pfc->info->nr_pins; i++) {
if (priv->pfc.info->pins[i].pin != pin_selector)
continue;
pin = &priv->pfc.info->pins[i];
break;
}
if (!pin)
return -EINVAL;
idx = sh_pfc_get_pin_index(pfc, pin->pin);
cfg = &pmx->configs[idx];
cfg->type = PINMUX_TYPE_NONE;
return 0;
}
static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector,
unsigned func_selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
const struct sh_pfc_pin *pin = &priv->pfc.info->pins[pin_selector];
int idx = sh_pfc_get_pin_index(pfc, pin->pin);
struct sh_pfc_pin_config *cfg = &pmx->configs[idx];
if (cfg->type != PINMUX_TYPE_NONE)
return -EBUSY;
return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_FUNCTION);
}
static int sh_pfc_pinctrl_group_set(struct udevice *dev, unsigned group_selector,
unsigned func_selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
const struct sh_pfc_pin_group *grp = &priv->pfc.info->groups[group_selector];
unsigned int i;
int ret = 0;
for (i = 0; i < grp->nr_pins; ++i) {
int idx = sh_pfc_get_pin_index(pfc, grp->pins[i]);
struct sh_pfc_pin_config *cfg = &pmx->configs[idx];
if (cfg->type != PINMUX_TYPE_NONE) {
ret = -EBUSY;
goto done;
}
}
for (i = 0; i < grp->nr_pins; ++i) {
ret = sh_pfc_config_mux(pfc, grp->mux[i], PINMUX_TYPE_FUNCTION);
if (ret < 0)
break;
}
done:
return ret;
}
#if CONFIG_IS_ENABLED(PINCONF)
static const struct pinconf_param sh_pfc_pinconf_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
{ "power-source", PIN_CONFIG_POWER_SOURCE, 3300 },
};
static void __iomem *
sh_pfc_pinconf_find_drive_strength_reg(struct sh_pfc *pfc, unsigned int pin,
unsigned int *offset, unsigned int *size)
{
const struct pinmux_drive_reg_field *field;
const struct pinmux_drive_reg *reg;
unsigned int i;
for (reg = pfc->info->drive_regs; reg->reg; ++reg) {
for (i = 0; i < ARRAY_SIZE(reg->fields); ++i) {
field = &reg->fields[i];
if (field->size && field->pin == pin) {
*offset = field->offset;
*size = field->size;
return (void __iomem *)(uintptr_t)reg->reg;
}
}
}
return NULL;
}
static int sh_pfc_pinconf_set_drive_strength(struct sh_pfc *pfc,
unsigned int pin, u16 strength)
{
unsigned int offset;
unsigned int size;
unsigned int step;
void __iomem *reg;
void __iomem *unlock_reg =
(void __iomem *)(uintptr_t)pfc->info->unlock_reg;
u32 val;
reg = sh_pfc_pinconf_find_drive_strength_reg(pfc, pin, &offset, &size);
if (!reg)
return -EINVAL;
step = size == 2 ? 6 : 3;
if (strength < step || strength > 24)
return -EINVAL;
/* Convert the value from mA based on a full drive strength value of
* 24mA. We can make the full value configurable later if needed.
*/
strength = strength / step - 1;
val = sh_pfc_read_raw_reg(reg, 32);
val &= ~GENMASK(offset + 4 - 1, offset);
val |= strength << offset;
if (unlock_reg)
sh_pfc_write_raw_reg(unlock_reg, 32, ~val);
sh_pfc_write_raw_reg(reg, 32, val);
return 0;
}
/* Check whether the requested parameter is supported for a pin. */
static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin,
unsigned int param)
{
int idx = sh_pfc_get_pin_index(pfc, _pin);
const struct sh_pfc_pin *pin = &pfc->info->pins[idx];
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
return pin->configs &
(SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN);
case PIN_CONFIG_BIAS_PULL_UP:
return pin->configs & SH_PFC_PIN_CFG_PULL_UP;
case PIN_CONFIG_BIAS_PULL_DOWN:
return pin->configs & SH_PFC_PIN_CFG_PULL_DOWN;
case PIN_CONFIG_DRIVE_STRENGTH:
return pin->configs & SH_PFC_PIN_CFG_DRIVE_STRENGTH;
case PIN_CONFIG_POWER_SOURCE:
return pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE;
default:
return false;
}
}
static int sh_pfc_pinconf_set(struct sh_pfc_pinctrl *pmx, unsigned _pin,
unsigned int param, unsigned int arg)
{
struct sh_pfc *pfc = pmx->pfc;
void __iomem *pocctrl;
void __iomem *unlock_reg =
(void __iomem *)(uintptr_t)pfc->info->unlock_reg;
u32 addr, val;
int bit, ret;
if (!sh_pfc_pinconf_validate(pfc, _pin, param))
return -ENOTSUPP;
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_DISABLE:
if (!pfc->info->ops || !pfc->info->ops->set_bias)
return -ENOTSUPP;
pfc->info->ops->set_bias(pfc, _pin, param);
break;
case PIN_CONFIG_DRIVE_STRENGTH:
ret = sh_pfc_pinconf_set_drive_strength(pfc, _pin, arg);
if (ret < 0)
return ret;
break;
case PIN_CONFIG_POWER_SOURCE:
if (!pfc->info->ops || !pfc->info->ops->pin_to_pocctrl)
return -ENOTSUPP;
bit = pfc->info->ops->pin_to_pocctrl(pfc, _pin, &addr);
if (bit < 0) {
printf("invalid pin %#x", _pin);
return bit;
}
if (arg != 1800 && arg != 3300)
return -EINVAL;
pocctrl = (void __iomem *)(uintptr_t)addr;
val = sh_pfc_read_raw_reg(pocctrl, 32);
if (arg == 3300)
val |= BIT(bit);
else
val &= ~BIT(bit);
if (unlock_reg)
sh_pfc_write_raw_reg(unlock_reg, 32, ~val);
sh_pfc_write_raw_reg(pocctrl, 32, val);
break;
default:
return -ENOTSUPP;
}
return 0;
}
static int sh_pfc_pinconf_pin_set(struct udevice *dev,
unsigned int pin_selector,
unsigned int param, unsigned int arg)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
const struct sh_pfc_pin *pin = &pfc->info->pins[pin_selector];
sh_pfc_pinconf_set(pmx, pin->pin, param, arg);
return 0;
}
static int sh_pfc_pinconf_group_set(struct udevice *dev,
unsigned int group_selector,
unsigned int param, unsigned int arg)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
const struct sh_pfc_pin_group *grp = &pfc->info->groups[group_selector];
unsigned int i;
for (i = 0; i < grp->nr_pins; i++)
sh_pfc_pinconf_set(pmx, grp->pins[i], param, arg);
return 0;
}
#endif
static struct pinctrl_ops sh_pfc_pinctrl_ops = {
.get_pins_count = sh_pfc_pinctrl_get_pins_count,
.get_pin_name = sh_pfc_pinctrl_get_pin_name,
.get_groups_count = sh_pfc_pinctrl_get_groups_count,
.get_group_name = sh_pfc_pinctrl_get_group_name,
.get_functions_count = sh_pfc_pinctrl_get_functions_count,
.get_function_name = sh_pfc_pinctrl_get_function_name,
#if CONFIG_IS_ENABLED(PINCONF)
.pinconf_num_params = ARRAY_SIZE(sh_pfc_pinconf_params),
.pinconf_params = sh_pfc_pinconf_params,
.pinconf_set = sh_pfc_pinconf_pin_set,
.pinconf_group_set = sh_pfc_pinconf_group_set,
#endif
.pinmux_set = sh_pfc_pinctrl_pin_set,
.pinmux_group_set = sh_pfc_pinctrl_group_set,
.set_state = pinctrl_generic_set_state,
.gpio_request_enable = sh_pfc_gpio_request_enable,
.gpio_disable_free = sh_pfc_gpio_disable_free,
};
static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
{
unsigned int i;
/* Allocate and initialize the pins and configs arrays. */
pmx->configs = kzalloc(sizeof(*pmx->configs) * pfc->info->nr_pins,
GFP_KERNEL);
if (unlikely(!pmx->configs))
return -ENOMEM;
for (i = 0; i < pfc->info->nr_pins; ++i) {
struct sh_pfc_pin_config *cfg = &pmx->configs[i];
cfg->type = PINMUX_TYPE_NONE;
}
return 0;
}
static int sh_pfc_pinctrl_probe(struct udevice *dev)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
enum sh_pfc_model model = dev_get_driver_data(dev);
fdt_addr_t base;
base = devfdt_get_addr(dev);
if (base == FDT_ADDR_T_NONE)
return -EINVAL;
priv->pfc.regs = devm_ioremap(dev, base, SZ_2K);
if (!priv->pfc.regs)
return -ENOMEM;
#ifdef CONFIG_PINCTRL_PFC_R8A7790
if (model == SH_PFC_R8A7790)
priv->pfc.info = &r8a7790_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7791
if (model == SH_PFC_R8A7791)
priv->pfc.info = &r8a7791_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7792
if (model == SH_PFC_R8A7792)
priv->pfc.info = &r8a7792_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7793
if (model == SH_PFC_R8A7793)
priv->pfc.info = &r8a7793_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7794
if (model == SH_PFC_R8A7794)
priv->pfc.info = &r8a7794_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7795
if (model == SH_PFC_R8A7795)
priv->pfc.info = &r8a7795_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7796
if (model == SH_PFC_R8A7796)
priv->pfc.info = &r8a7796_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77965
if (model == SH_PFC_R8A77965)
priv->pfc.info = &r8a77965_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77970
if (model == SH_PFC_R8A77970)
priv->pfc.info = &r8a77970_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77980
if (model == SH_PFC_R8A77980)
priv->pfc.info = &r8a77980_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77990
if (model == SH_PFC_R8A77990)
priv->pfc.info = &r8a77990_pinmux_info;
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77995
if (model == SH_PFC_R8A77995)
priv->pfc.info = &r8a77995_pinmux_info;
#endif
priv->pmx.pfc = &priv->pfc;
sh_pfc_init_ranges(&priv->pfc);
sh_pfc_map_pins(&priv->pfc, &priv->pmx);
return 0;
}
static const struct udevice_id sh_pfc_pinctrl_ids[] = {
#ifdef CONFIG_PINCTRL_PFC_R8A7790
{
.compatible = "renesas,pfc-r8a7790",
.data = SH_PFC_R8A7790,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7791
{
.compatible = "renesas,pfc-r8a7791",
.data = SH_PFC_R8A7791,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7792
{
.compatible = "renesas,pfc-r8a7792",
.data = SH_PFC_R8A7792,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7793
{
.compatible = "renesas,pfc-r8a7793",
.data = SH_PFC_R8A7793,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7794
{
.compatible = "renesas,pfc-r8a7794",
.data = SH_PFC_R8A7794,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7795
{
.compatible = "renesas,pfc-r8a7795",
.data = SH_PFC_R8A7795,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7796
{
.compatible = "renesas,pfc-r8a7796",
.data = SH_PFC_R8A7796,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77965
{
.compatible = "renesas,pfc-r8a77965",
.data = SH_PFC_R8A77965,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77970
{
.compatible = "renesas,pfc-r8a77970",
.data = SH_PFC_R8A77970,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77980
{
.compatible = "renesas,pfc-r8a77980",
.data = SH_PFC_R8A77980,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77990
{
.compatible = "renesas,pfc-r8a77990",
.data = SH_PFC_R8A77990,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77995
{
.compatible = "renesas,pfc-r8a77995",
.data = SH_PFC_R8A77995,
},
#endif
{ },
};
U_BOOT_DRIVER(pinctrl_sh_pfc) = {
.name = "sh_pfc_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = sh_pfc_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct sh_pfc_pinctrl_priv),
.ops = &sh_pfc_pinctrl_ops,
.probe = sh_pfc_pinctrl_probe,
};
@@ -0,0 +1,675 @@
/*
* SuperH Pin Function Controller Support
*
* Copyright (c) 2008 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#ifndef __SH_PFC_H
#define __SH_PFC_H
#include <linux/stringify.h>
enum {
PINMUX_TYPE_NONE,
PINMUX_TYPE_FUNCTION,
PINMUX_TYPE_GPIO,
PINMUX_TYPE_OUTPUT,
PINMUX_TYPE_INPUT,
};
#define SH_PFC_PIN_CFG_INPUT (1 << 0)
#define SH_PFC_PIN_CFG_OUTPUT (1 << 1)
#define SH_PFC_PIN_CFG_PULL_UP (1 << 2)
#define SH_PFC_PIN_CFG_PULL_DOWN (1 << 3)
#define SH_PFC_PIN_CFG_IO_VOLTAGE (1 << 4)
#define SH_PFC_PIN_CFG_DRIVE_STRENGTH (1 << 5)
#define SH_PFC_PIN_CFG_NO_GPIO (1 << 31)
struct sh_pfc_pin {
u16 pin;
u16 enum_id;
const char *name;
unsigned int configs;
};
#define SH_PFC_PIN_GROUP_ALIAS(alias, n) \
{ \
.name = #alias, \
.pins = n##_pins, \
.mux = n##_mux, \
.nr_pins = ARRAY_SIZE(n##_pins) + \
BUILD_BUG_ON_ZERO(sizeof(n##_pins) != sizeof(n##_mux)), \
}
#define SH_PFC_PIN_GROUP(n) SH_PFC_PIN_GROUP_ALIAS(n, n)
struct sh_pfc_pin_group {
const char *name;
const unsigned int *pins;
const unsigned int *mux;
unsigned int nr_pins;
};
/*
* Using union vin_data{,12,16} saves memory occupied by the VIN data pins.
* VIN_DATA_PIN_GROUP() is a macro used to describe the VIN pin groups
* in this case. It accepts an optional 'version' argument used when the
* same group can appear on a different set of pins.
*/
#define VIN_DATA_PIN_GROUP(n, s, ...) \
{ \
.name = #n#s#__VA_ARGS__, \
.pins = n##__VA_ARGS__##_pins.data##s, \
.mux = n##__VA_ARGS__##_mux.data##s, \
.nr_pins = ARRAY_SIZE(n##__VA_ARGS__##_pins.data##s), \
}
union vin_data12 {
unsigned int data12[12];
unsigned int data10[10];
unsigned int data8[8];
};
union vin_data16 {
unsigned int data16[16];
unsigned int data12[12];
unsigned int data10[10];
unsigned int data8[8];
};
union vin_data {
unsigned int data24[24];
unsigned int data20[20];
unsigned int data16[16];
unsigned int data12[12];
unsigned int data10[10];
unsigned int data8[8];
unsigned int data4[4];
};
#define SH_PFC_FUNCTION(n) \
{ \
.name = #n, \
.groups = n##_groups, \
.nr_groups = ARRAY_SIZE(n##_groups), \
}
struct sh_pfc_function {
const char *name;
const char * const *groups;
unsigned int nr_groups;
};
struct pinmux_func {
u16 enum_id;
const char *name;
};
struct pinmux_cfg_reg {
u32 reg;
u8 reg_width, field_width;
#ifdef DEBUG
u16 nr_enum_ids; /* for variable width regs only */
#define SET_NR_ENUM_IDS(n) .nr_enum_ids = n,
#else
#define SET_NR_ENUM_IDS(n)
#endif
const u16 *enum_ids;
const u8 *var_field_width;
};
#define GROUP(...) __VA_ARGS__
/*
* Describe a config register consisting of several fields of the same width
* - name: Register name (unused, for documentation purposes only)
* - r: Physical register address
* - r_width: Width of the register (in bits)
* - f_width: Width of the fixed-width register fields (in bits)
* - ids: For each register field (from left to right, i.e. MSB to LSB),
* 2^f_width enum IDs must be specified, one for each possible
* combination of the register field bit values, all wrapped using
* the GROUP() macro.
*/
#define PINMUX_CFG_REG(name, r, r_width, f_width, ids) \
.reg = r, .reg_width = r_width, \
.field_width = f_width + BUILD_BUG_ON_ZERO(r_width % f_width) + \
BUILD_BUG_ON_ZERO(sizeof((const u16 []) { ids }) / sizeof(u16) != \
(r_width / f_width) * (1 << f_width)), \
.enum_ids = (const u16 [(r_width / f_width) * (1 << f_width)]) \
{ ids }
/*
* Describe a config register consisting of several fields of different widths
* - name: Register name (unused, for documentation purposes only)
* - r: Physical register address
* - r_width: Width of the register (in bits)
* - f_widths: List of widths of the register fields (in bits), from left
* to right (i.e. MSB to LSB), wrapped using the GROUP() macro.
* - ids: For each register field (from left to right, i.e. MSB to LSB),
* 2^f_widths[i] enum IDs must be specified, one for each possible
* combination of the register field bit values, all wrapped using
* the GROUP() macro.
*/
#define PINMUX_CFG_REG_VAR(name, r, r_width, f_widths, ids) \
.reg = r, .reg_width = r_width, \
.var_field_width = (const u8 []) { f_widths, 0 }, \
SET_NR_ENUM_IDS(sizeof((const u16 []) { ids }) / sizeof(u16)) \
.enum_ids = (const u16 []) { ids }
struct pinmux_drive_reg_field {
u16 pin;
u8 offset;
u8 size;
};
struct pinmux_drive_reg {
u32 reg;
const struct pinmux_drive_reg_field fields[8];
};
#define PINMUX_DRIVE_REG(name, r) \
.reg = r, \
.fields =
struct pinmux_bias_reg {
u32 puen; /* Pull-enable or pull-up control register */
u32 pud; /* Pull-up/down control register (optional) */
const u16 pins[32];
};
#define PINMUX_BIAS_REG(name1, r1, name2, r2) \
.puen = r1, \
.pud = r2, \
.pins =
struct pinmux_ioctrl_reg {
u32 reg;
};
struct pinmux_data_reg {
u32 reg;
u8 reg_width;
const u16 *enum_ids;
};
/*
* Describe a data register
* - name: Register name (unused, for documentation purposes only)
* - r: Physical register address
* - r_width: Width of the register (in bits)
* - ids: For each register bit (from left to right, i.e. MSB to LSB), one
* enum ID must be specified, all wrapped using the GROUP() macro.
*/
#define PINMUX_DATA_REG(name, r, r_width, ids) \
.reg = r, .reg_width = r_width + \
BUILD_BUG_ON_ZERO(sizeof((const u16 []) { ids }) / sizeof(u16) != \
r_width), \
.enum_ids = (const u16 [r_width]) { ids }
struct pinmux_irq {
const short *gpios;
};
/*
* Describe the mapping from GPIOs to a single IRQ
* - ids...: List of GPIOs that are mapped to the same IRQ
*/
#define PINMUX_IRQ(ids...) \
{ .gpios = (const short []) { ids, -1 } }
struct pinmux_range {
u16 begin;
u16 end;
u16 force;
};
struct sh_pfc_window {
phys_addr_t phys;
void __iomem *virt;
unsigned long size;
};
struct sh_pfc_pin_range;
struct sh_pfc {
struct device *dev;
const struct sh_pfc_soc_info *info;
void *regs;
struct sh_pfc_pin_range *ranges;
unsigned int nr_ranges;
unsigned int nr_gpio_pins;
struct sh_pfc_chip *gpio;
};
struct sh_pfc_soc_operations {
int (*init)(struct sh_pfc *pfc);
unsigned int (*get_bias)(struct sh_pfc *pfc, unsigned int pin);
void (*set_bias)(struct sh_pfc *pfc, unsigned int pin,
unsigned int bias);
int (*pin_to_pocctrl)(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl);
};
struct sh_pfc_soc_info {
const char *name;
const struct sh_pfc_soc_operations *ops;
struct pinmux_range input;
struct pinmux_range output;
struct pinmux_range function;
const struct sh_pfc_pin *pins;
unsigned int nr_pins;
const struct sh_pfc_pin_group *groups;
unsigned int nr_groups;
const struct sh_pfc_function *functions;
unsigned int nr_functions;
const struct pinmux_cfg_reg *cfg_regs;
const struct pinmux_drive_reg *drive_regs;
const struct pinmux_bias_reg *bias_regs;
const struct pinmux_ioctrl_reg *ioctrl_regs;
const struct pinmux_data_reg *data_regs;
const u16 *pinmux_data;
unsigned int pinmux_data_size;
const struct pinmux_irq *gpio_irq;
unsigned int gpio_irq_size;
u32 unlock_reg;
};
u32 sh_pfc_read(struct sh_pfc *pfc, u32 reg);
void sh_pfc_write(struct sh_pfc *pfc, u32 reg, u32 data);
const struct pinmux_bias_reg *
sh_pfc_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin,
unsigned int *bit);
extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
extern const struct sh_pfc_soc_info r8a7792_pinmux_info;
extern const struct sh_pfc_soc_info r8a7793_pinmux_info;
extern const struct sh_pfc_soc_info r8a7794_pinmux_info;
extern const struct sh_pfc_soc_info r8a7795_pinmux_info;
extern const struct sh_pfc_soc_info r8a7796_pinmux_info;
extern const struct sh_pfc_soc_info r8a77965_pinmux_info;
extern const struct sh_pfc_soc_info r8a77970_pinmux_info;
extern const struct sh_pfc_soc_info r8a77980_pinmux_info;
extern const struct sh_pfc_soc_info r8a77990_pinmux_info;
extern const struct sh_pfc_soc_info r8a77995_pinmux_info;
/* -----------------------------------------------------------------------------
* Helper macros to create pin and port lists
*/
/*
* sh_pfc_soc_info pinmux_data array macros
*/
/*
* Describe generic pinmux data
* - data_or_mark: *_DATA or *_MARK enum ID
* - ids...: List of enum IDs to associate with data_or_mark
*/
#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0
/*
* Describe a pinmux configuration without GPIO function that needs
* configuration in a Peripheral Function Select Register (IPSR)
* - ipsr: IPSR field (unused, for documentation purposes only)
* - fn: Function name, referring to a field in the IPSR
*/
#define PINMUX_IPSR_NOGP(ipsr, fn) \
PINMUX_DATA(fn##_MARK, FN_##fn)
/*
* Describe a pinmux configuration with GPIO function that needs configuration
* in both a Peripheral Function Select Register (IPSR) and in a
* GPIO/Peripheral Function Select Register (GPSR)
* - ipsr: IPSR field
* - fn: Function name, also referring to the IPSR field
*/
#define PINMUX_IPSR_GPSR(ipsr, fn) \
PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr)
/*
* Describe a pinmux configuration without GPIO function that needs
* configuration in a Peripheral Function Select Register (IPSR), and where the
* pinmux function has a representation in a Module Select Register (MOD_SEL).
* - ipsr: IPSR field (unused, for documentation purposes only)
* - fn: Function name, also referring to the IPSR field
* - msel: Module selector
*/
#define PINMUX_IPSR_NOGM(ipsr, fn, msel) \
PINMUX_DATA(fn##_MARK, FN_##fn, FN_##msel)
/*
* Describe a pinmux configuration with GPIO function where the pinmux function
* has no representation in a Peripheral Function Select Register (IPSR), but
* instead solely depends on a group selection.
* - gpsr: GPSR field
* - fn: Function name, also referring to the GPSR field
* - gsel: Group selector
*/
#define PINMUX_IPSR_NOFN(gpsr, fn, gsel) \
PINMUX_DATA(fn##_MARK, FN_##gpsr, FN_##gsel)
/*
* Describe a pinmux configuration with GPIO function that needs configuration
* in both a Peripheral Function Select Register (IPSR) and a GPIO/Peripheral
* Function Select Register (GPSR), and where the pinmux function has a
* representation in a Module Select Register (MOD_SEL).
* - ipsr: IPSR field
* - fn: Function name, also referring to the IPSR field
* - msel: Module selector
*/
#define PINMUX_IPSR_MSEL(ipsr, fn, msel) \
PINMUX_DATA(fn##_MARK, FN_##msel, FN_##fn, FN_##ipsr)
/*
* Describe a pinmux configuration similar to PINMUX_IPSR_MSEL, but with
* an additional select register that controls physical multiplexing
* with another pin.
* - ipsr: IPSR field
* - fn: Function name, also referring to the IPSR field
* - psel: Physical multiplexing selector
* - msel: Module selector
*/
#define PINMUX_IPSR_PHYS_MSEL(ipsr, fn, psel, msel) \
PINMUX_DATA(fn##_MARK, FN_##psel, FN_##msel, FN_##fn, FN_##ipsr)
/*
* Describe a pinmux configuration in which a pin is physically multiplexed
* with other pins.
* - ipsr: IPSR field (unused, for documentation purposes only)
* - fn: Function name
* - psel: Physical multiplexing selector
*/
#define PINMUX_IPSR_PHYS(ipsr, fn, psel) \
PINMUX_DATA(fn##_MARK, FN_##psel)
/*
* Describe a pinmux configuration for a single-function pin with GPIO
* capability.
* - fn: Function name
*/
#define PINMUX_SINGLE(fn) \
PINMUX_DATA(fn##_MARK, FN_##fn)
/*
* GP port style (32 ports banks)
*/
#define PORT_GP_CFG_1(bank, pin, fn, sfx, cfg) \
fn(bank, pin, GP_##bank##_##pin, sfx, cfg)
#define PORT_GP_1(bank, pin, fn, sfx) PORT_GP_CFG_1(bank, pin, fn, sfx, 0)
#define PORT_GP_CFG_4(bank, fn, sfx, cfg) \
PORT_GP_CFG_1(bank, 0, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 1, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 2, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 3, fn, sfx, cfg)
#define PORT_GP_4(bank, fn, sfx) PORT_GP_CFG_4(bank, fn, sfx, 0)
#define PORT_GP_CFG_6(bank, fn, sfx, cfg) \
PORT_GP_CFG_4(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 4, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 5, fn, sfx, cfg)
#define PORT_GP_6(bank, fn, sfx) PORT_GP_CFG_6(bank, fn, sfx, 0)
#define PORT_GP_CFG_8(bank, fn, sfx, cfg) \
PORT_GP_CFG_6(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 6, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 7, fn, sfx, cfg)
#define PORT_GP_8(bank, fn, sfx) PORT_GP_CFG_8(bank, fn, sfx, 0)
#define PORT_GP_CFG_9(bank, fn, sfx, cfg) \
PORT_GP_CFG_8(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 8, fn, sfx, cfg)
#define PORT_GP_9(bank, fn, sfx) PORT_GP_CFG_9(bank, fn, sfx, 0)
#define PORT_GP_CFG_10(bank, fn, sfx, cfg) \
PORT_GP_CFG_9(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 9, fn, sfx, cfg)
#define PORT_GP_10(bank, fn, sfx) PORT_GP_CFG_10(bank, fn, sfx, 0)
#define PORT_GP_CFG_11(bank, fn, sfx, cfg) \
PORT_GP_CFG_10(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 10, fn, sfx, cfg)
#define PORT_GP_11(bank, fn, sfx) PORT_GP_CFG_11(bank, fn, sfx, 0)
#define PORT_GP_CFG_12(bank, fn, sfx, cfg) \
PORT_GP_CFG_11(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 11, fn, sfx, cfg)
#define PORT_GP_12(bank, fn, sfx) PORT_GP_CFG_12(bank, fn, sfx, 0)
#define PORT_GP_CFG_14(bank, fn, sfx, cfg) \
PORT_GP_CFG_12(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 12, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 13, fn, sfx, cfg)
#define PORT_GP_14(bank, fn, sfx) PORT_GP_CFG_14(bank, fn, sfx, 0)
#define PORT_GP_CFG_15(bank, fn, sfx, cfg) \
PORT_GP_CFG_14(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 14, fn, sfx, cfg)
#define PORT_GP_15(bank, fn, sfx) PORT_GP_CFG_15(bank, fn, sfx, 0)
#define PORT_GP_CFG_16(bank, fn, sfx, cfg) \
PORT_GP_CFG_15(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 15, fn, sfx, cfg)
#define PORT_GP_16(bank, fn, sfx) PORT_GP_CFG_16(bank, fn, sfx, 0)
#define PORT_GP_CFG_17(bank, fn, sfx, cfg) \
PORT_GP_CFG_16(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 16, fn, sfx, cfg)
#define PORT_GP_17(bank, fn, sfx) PORT_GP_CFG_17(bank, fn, sfx, 0)
#define PORT_GP_CFG_18(bank, fn, sfx, cfg) \
PORT_GP_CFG_17(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 17, fn, sfx, cfg)
#define PORT_GP_18(bank, fn, sfx) PORT_GP_CFG_18(bank, fn, sfx, 0)
#define PORT_GP_CFG_20(bank, fn, sfx, cfg) \
PORT_GP_CFG_18(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 18, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 19, fn, sfx, cfg)
#define PORT_GP_20(bank, fn, sfx) PORT_GP_CFG_20(bank, fn, sfx, 0)
#define PORT_GP_CFG_21(bank, fn, sfx, cfg) \
PORT_GP_CFG_20(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 20, fn, sfx, cfg)
#define PORT_GP_21(bank, fn, sfx) PORT_GP_CFG_21(bank, fn, sfx, 0)
#define PORT_GP_CFG_22(bank, fn, sfx, cfg) \
PORT_GP_CFG_21(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 21, fn, sfx, cfg)
#define PORT_GP_22(bank, fn, sfx) PORT_GP_CFG_22(bank, fn, sfx, 0)
#define PORT_GP_CFG_23(bank, fn, sfx, cfg) \
PORT_GP_CFG_22(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 22, fn, sfx, cfg)
#define PORT_GP_23(bank, fn, sfx) PORT_GP_CFG_23(bank, fn, sfx, 0)
#define PORT_GP_CFG_24(bank, fn, sfx, cfg) \
PORT_GP_CFG_23(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 23, fn, sfx, cfg)
#define PORT_GP_24(bank, fn, sfx) PORT_GP_CFG_24(bank, fn, sfx, 0)
#define PORT_GP_CFG_25(bank, fn, sfx, cfg) \
PORT_GP_CFG_24(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 24, fn, sfx, cfg)
#define PORT_GP_25(bank, fn, sfx) PORT_GP_CFG_25(bank, fn, sfx, 0)
#define PORT_GP_CFG_26(bank, fn, sfx, cfg) \
PORT_GP_CFG_25(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 25, fn, sfx, cfg)
#define PORT_GP_26(bank, fn, sfx) PORT_GP_CFG_26(bank, fn, sfx, 0)
#define PORT_GP_CFG_28(bank, fn, sfx, cfg) \
PORT_GP_CFG_26(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 26, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 27, fn, sfx, cfg)
#define PORT_GP_28(bank, fn, sfx) PORT_GP_CFG_28(bank, fn, sfx, 0)
#define PORT_GP_CFG_29(bank, fn, sfx, cfg) \
PORT_GP_CFG_28(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 28, fn, sfx, cfg)
#define PORT_GP_29(bank, fn, sfx) PORT_GP_CFG_29(bank, fn, sfx, 0)
#define PORT_GP_CFG_30(bank, fn, sfx, cfg) \
PORT_GP_CFG_29(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 29, fn, sfx, cfg)
#define PORT_GP_30(bank, fn, sfx) PORT_GP_CFG_30(bank, fn, sfx, 0)
#define PORT_GP_CFG_32(bank, fn, sfx, cfg) \
PORT_GP_CFG_30(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 30, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 31, fn, sfx, cfg)
#define PORT_GP_32(bank, fn, sfx) PORT_GP_CFG_32(bank, fn, sfx, 0)
#define PORT_GP_32_REV(bank, fn, sfx) \
PORT_GP_1(bank, 31, fn, sfx), PORT_GP_1(bank, 30, fn, sfx), \
PORT_GP_1(bank, 29, fn, sfx), PORT_GP_1(bank, 28, fn, sfx), \
PORT_GP_1(bank, 27, fn, sfx), PORT_GP_1(bank, 26, fn, sfx), \
PORT_GP_1(bank, 25, fn, sfx), PORT_GP_1(bank, 24, fn, sfx), \
PORT_GP_1(bank, 23, fn, sfx), PORT_GP_1(bank, 22, fn, sfx), \
PORT_GP_1(bank, 21, fn, sfx), PORT_GP_1(bank, 20, fn, sfx), \
PORT_GP_1(bank, 19, fn, sfx), PORT_GP_1(bank, 18, fn, sfx), \
PORT_GP_1(bank, 17, fn, sfx), PORT_GP_1(bank, 16, fn, sfx), \
PORT_GP_1(bank, 15, fn, sfx), PORT_GP_1(bank, 14, fn, sfx), \
PORT_GP_1(bank, 13, fn, sfx), PORT_GP_1(bank, 12, fn, sfx), \
PORT_GP_1(bank, 11, fn, sfx), PORT_GP_1(bank, 10, fn, sfx), \
PORT_GP_1(bank, 9, fn, sfx), PORT_GP_1(bank, 8, fn, sfx), \
PORT_GP_1(bank, 7, fn, sfx), PORT_GP_1(bank, 6, fn, sfx), \
PORT_GP_1(bank, 5, fn, sfx), PORT_GP_1(bank, 4, fn, sfx), \
PORT_GP_1(bank, 3, fn, sfx), PORT_GP_1(bank, 2, fn, sfx), \
PORT_GP_1(bank, 1, fn, sfx), PORT_GP_1(bank, 0, fn, sfx)
/* GP_ALL(suffix) - Expand to a list of GP_#_#_suffix */
#define _GP_ALL(bank, pin, name, sfx, cfg) name##_##sfx
#define GP_ALL(str) CPU_ALL_PORT(_GP_ALL, str)
/* PINMUX_GPIO_GP_ALL - Expand to a list of sh_pfc_pin entries */
#define _GP_GPIO(bank, _pin, _name, sfx, cfg) \
{ \
.pin = (bank * 32) + _pin, \
.name = __stringify(_name), \
.enum_id = _name##_DATA, \
.configs = cfg, \
}
#define PINMUX_GPIO_GP_ALL() CPU_ALL_PORT(_GP_GPIO, unused)
/* PINMUX_DATA_GP_ALL - Expand to a list of name_DATA, name_FN marks */
#define _GP_DATA(bank, pin, name, sfx, cfg) PINMUX_DATA(name##_DATA, name##_FN)
#define PINMUX_DATA_GP_ALL() CPU_ALL_PORT(_GP_DATA, unused)
/*
* PORT style (linear pin space)
*/
#define PORT_1(pn, fn, pfx, sfx) fn(pn, pfx, sfx)
#define PORT_10(pn, fn, pfx, sfx) \
PORT_1(pn, fn, pfx##0, sfx), PORT_1(pn+1, fn, pfx##1, sfx), \
PORT_1(pn+2, fn, pfx##2, sfx), PORT_1(pn+3, fn, pfx##3, sfx), \
PORT_1(pn+4, fn, pfx##4, sfx), PORT_1(pn+5, fn, pfx##5, sfx), \
PORT_1(pn+6, fn, pfx##6, sfx), PORT_1(pn+7, fn, pfx##7, sfx), \
PORT_1(pn+8, fn, pfx##8, sfx), PORT_1(pn+9, fn, pfx##9, sfx)
#define PORT_90(pn, fn, pfx, sfx) \
PORT_10(pn+10, fn, pfx##1, sfx), PORT_10(pn+20, fn, pfx##2, sfx), \
PORT_10(pn+30, fn, pfx##3, sfx), PORT_10(pn+40, fn, pfx##4, sfx), \
PORT_10(pn+50, fn, pfx##5, sfx), PORT_10(pn+60, fn, pfx##6, sfx), \
PORT_10(pn+70, fn, pfx##7, sfx), PORT_10(pn+80, fn, pfx##8, sfx), \
PORT_10(pn+90, fn, pfx##9, sfx)
/* PORT_ALL(suffix) - Expand to a list of PORT_#_suffix */
#define _PORT_ALL(pn, pfx, sfx) pfx##_##sfx
#define PORT_ALL(str) CPU_ALL_PORT(_PORT_ALL, PORT, str)
/* PINMUX_GPIO - Expand to a sh_pfc_pin entry */
#define PINMUX_GPIO(_pin) \
[GPIO_##_pin] = { \
.pin = (u16)-1, \
.name = __stringify(GPIO_##_pin), \
.enum_id = _pin##_DATA, \
}
/* SH_PFC_PIN_CFG - Expand to a sh_pfc_pin entry (named PORT#) with config */
#define SH_PFC_PIN_CFG(_pin, cfgs) \
{ \
.pin = _pin, \
.name = __stringify(PORT##_pin), \
.enum_id = PORT##_pin##_DATA, \
.configs = cfgs, \
}
/* SH_PFC_PIN_NAMED - Expand to a sh_pfc_pin entry with the given name */
#define SH_PFC_PIN_NAMED(row, col, _name) \
{ \
.pin = PIN_NUMBER(row, col), \
.name = __stringify(PIN_##_name), \
.configs = SH_PFC_PIN_CFG_NO_GPIO, \
}
/* SH_PFC_PIN_NAMED_CFG - Expand to a sh_pfc_pin entry with the given name */
#define SH_PFC_PIN_NAMED_CFG(row, col, _name, cfgs) \
{ \
.pin = PIN_NUMBER(row, col), \
.name = __stringify(PIN_##_name), \
.configs = SH_PFC_PIN_CFG_NO_GPIO | cfgs, \
}
/* PINMUX_DATA_ALL - Expand to a list of PORT_name_DATA, PORT_name_FN0,
* PORT_name_OUT, PORT_name_IN marks
*/
#define _PORT_DATA(pn, pfx, sfx) \
PINMUX_DATA(PORT##pfx##_DATA, PORT##pfx##_FN0, \
PORT##pfx##_OUT, PORT##pfx##_IN)
#define PINMUX_DATA_ALL() CPU_ALL_PORT(_PORT_DATA, , unused)
/* GPIO_FN(name) - Expand to a sh_pfc_pin entry for a function GPIO */
#define PINMUX_GPIO_FN(gpio, base, data_or_mark) \
[gpio - (base)] = { \
.name = __stringify(gpio), \
.enum_id = data_or_mark, \
}
#define GPIO_FN(str) \
PINMUX_GPIO_FN(GPIO_FN_##str, PINMUX_FN_BASE, str##_MARK)
/*
* PORTnCR helper macro for SH-Mobile/R-Mobile
*/
#define PORTCR(nr, reg) \
{ \
PINMUX_CFG_REG_VAR("PORT" nr "CR", reg, 8, \
GROUP(2, 2, 1, 3), \
GROUP( \
/* PULMD[1:0], handled by .set_bias() */ \
0, 0, 0, 0, \
/* IE and OE */ \
0, PORT##nr##_OUT, PORT##nr##_IN, 0, \
/* SEC, not supported */ \
0, 0, \
/* PTMD[2:0] */ \
PORT##nr##_FN0, PORT##nr##_FN1, \
PORT##nr##_FN2, PORT##nr##_FN3, \
PORT##nr##_FN4, PORT##nr##_FN5, \
PORT##nr##_FN6, PORT##nr##_FN7 \
)) \
}
/*
* GPIO number helper macro for R-Car
*/
#define RCAR_GP_PIN(bank, pin) (((bank) * 32) + (pin))
#endif /* __SH_PFC_H */
@@ -0,0 +1,17 @@
if ARCH_ROCKCHIP
config PINCTRL_ROCKCHIP
bool "Rockchip pin control drivers"
depends on ARCH_ROCKCHIP && PINCTRL_GENERIC
default y
help
Enable support pin control functions for Rockchip SoCs.
config SPL_PINCTRL_ROCKCHIP
bool "Support Rockchip pin controllers in SPL"
depends on ARCH_ROCKCHIP && SPL_PINCTRL_GENERIC
default y
help
This option is an SPL-variant of the PINCTRL_ROCKCHIP option.
endif
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2017 Rockchip Electronics Co., Ltd
obj-y += pinctrl-rockchip-core.o
obj-$(CONFIG_ROCKCHIP_PX30) += pinctrl-px30.o
obj-$(CONFIG_ROCKCHIP_RK3036) += pinctrl-rk3036.o
obj-$(CONFIG_ROCKCHIP_RK3128) += pinctrl-rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) += pinctrl-rk3188.o
obj-$(CONFIG_ROCKCHIP_RK322X) += pinctrl-rk322x.o
obj-$(CONFIG_ROCKCHIP_RK3288) += pinctrl-rk3288.o
obj-$(CONFIG_ROCKCHIP_RK3308) += pinctrl-rk3308.o
obj-$(CONFIG_ROCKCHIP_RK3328) += pinctrl-rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += pinctrl-rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += pinctrl-rk3399.o
obj-$(CONFIG_ROCKCHIP_RV1108) += pinctrl-rv1108.o
@@ -0,0 +1,368 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2019 Rockchip Electronics Co., Ltd
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <regmap.h>
#include <syscon.h>
#include "pinctrl-rockchip.h"
static struct rockchip_mux_route_data px30_mux_route_data[] = {
{
/* cif-d2m0 */
.bank_num = 2,
.pin = 0,
.func = 1,
.route_offset = 0x184,
.route_val = BIT(16 + 7),
}, {
/* cif-d2m1 */
.bank_num = 3,
.pin = 3,
.func = 3,
.route_offset = 0x184,
.route_val = BIT(16 + 7) | BIT(7),
}, {
/* pdm-m0 */
.bank_num = 3,
.pin = 22,
.func = 2,
.route_offset = 0x184,
.route_val = BIT(16 + 8),
}, {
/* pdm-m1 */
.bank_num = 2,
.pin = 22,
.func = 1,
.route_offset = 0x184,
.route_val = BIT(16 + 8) | BIT(8),
}, {
/* uart2-rxm0 */
.bank_num = 1,
.pin = 27,
.func = 2,
.route_offset = 0x184,
.route_val = BIT(16 + 10),
}, {
/* uart2-rxm1 */
.bank_num = 2,
.pin = 14,
.func = 2,
.route_offset = 0x184,
.route_val = BIT(16 + 10) | BIT(10),
}, {
/* uart3-rxm0 */
.bank_num = 0,
.pin = 17,
.func = 2,
.route_offset = 0x184,
.route_val = BIT(16 + 9),
}, {
/* uart3-rxm1 */
.bank_num = 1,
.pin = 15,
.func = 2,
.route_offset = 0x184,
.route_val = BIT(16 + 9) | BIT(9),
},
};
static int px30_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
int iomux_num = (pin / 8);
struct regmap *regmap;
int reg, ret, mask, mux_type;
u8 bit;
u32 data, route_reg, route_val;
regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
? priv->regmap_pmu : priv->regmap_base;
/* get basic quadrupel of mux registers and the correct reg inside */
mux_type = bank->iomux[iomux_num].type;
reg = bank->iomux[iomux_num].offset;
reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
if (bank->route_mask & BIT(pin)) {
if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
&route_val)) {
ret = regmap_write(regmap, route_reg, route_val);
if (ret)
return ret;
}
}
data = (mask << (bit + 16));
data |= (mux & mask) << bit;
ret = regmap_write(regmap, reg, data);
return ret;
}
#define PX30_PULL_PMU_OFFSET 0x10
#define PX30_PULL_GRF_OFFSET 0x60
#define PX30_PULL_BITS_PER_PIN 2
#define PX30_PULL_PINS_PER_REG 8
#define PX30_PULL_BANK_STRIDE 16
static void px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
int pin_num, struct regmap **regmap,
int *reg, u8 *bit)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
/* The first 32 pins of the first bank are located in PMU */
if (bank->bank_num == 0) {
*regmap = priv->regmap_pmu;
*reg = PX30_PULL_PMU_OFFSET;
} else {
*regmap = priv->regmap_base;
*reg = PX30_PULL_GRF_OFFSET;
/* correct the offset, as we're starting with the 2nd bank */
*reg -= 0x10;
*reg += bank->bank_num * PX30_PULL_BANK_STRIDE;
}
*reg += ((pin_num / PX30_PULL_PINS_PER_REG) * 4);
*bit = (pin_num % PX30_PULL_PINS_PER_REG);
*bit *= PX30_PULL_BITS_PER_PIN;
}
static int px30_set_pull(struct rockchip_pin_bank *bank,
int pin_num, int pull)
{
struct regmap *regmap;
int reg, ret;
u8 bit, type;
u32 data;
if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
return -ENOTSUPP;
px30_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
type = bank->pull_type[pin_num / 8];
ret = rockchip_translate_pull_value(type, pull);
if (ret < 0) {
debug("unsupported pull setting %d\n", pull);
return ret;
}
/* enable the write to the equivalent lower bits */
data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
data |= (ret << bit);
ret = regmap_write(regmap, reg, data);
return ret;
}
#define PX30_DRV_PMU_OFFSET 0x20
#define PX30_DRV_GRF_OFFSET 0xf0
#define PX30_DRV_BITS_PER_PIN 2
#define PX30_DRV_PINS_PER_REG 8
#define PX30_DRV_BANK_STRIDE 16
static void px30_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
int pin_num, struct regmap **regmap,
int *reg, u8 *bit)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
/* The first 32 pins of the first bank are located in PMU */
if (bank->bank_num == 0) {
*regmap = priv->regmap_pmu;
*reg = PX30_DRV_PMU_OFFSET;
} else {
*regmap = priv->regmap_base;
*reg = PX30_DRV_GRF_OFFSET;
/* correct the offset, as we're starting with the 2nd bank */
*reg -= 0x10;
*reg += bank->bank_num * PX30_DRV_BANK_STRIDE;
}
*reg += ((pin_num / PX30_DRV_PINS_PER_REG) * 4);
*bit = (pin_num % PX30_DRV_PINS_PER_REG);
*bit *= PX30_DRV_BITS_PER_PIN;
}
static int px30_set_drive(struct rockchip_pin_bank *bank,
int pin_num, int strength)
{
struct regmap *regmap;
int reg, ret;
u32 data, rmask_bits, temp;
u8 bit;
int drv_type = bank->drv[pin_num / 8].drv_type;
px30_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
ret = rockchip_translate_drive_value(drv_type, strength);
if (ret < 0) {
debug("unsupported driver strength %d\n", strength);
return ret;
}
switch (drv_type) {
case DRV_TYPE_IO_1V8_3V0_AUTO:
case DRV_TYPE_IO_3V3_ONLY:
rmask_bits = ROCKCHIP_DRV_3BITS_PER_PIN;
switch (bit) {
case 0 ... 12:
/* regular case, nothing to do */
break;
case 15:
/*
* drive-strength offset is special, as it is spread
* over 2 registers, the bit data[15] contains bit 0
* of the value while temp[1:0] contains bits 2 and 1
*/
data = (ret & 0x1) << 15;
temp = (ret >> 0x1) & 0x3;
data |= BIT(31);
ret = regmap_write(regmap, reg, data);
if (ret)
return ret;
temp |= (0x3 << 16);
reg += 0x4;
ret = regmap_write(regmap, reg, temp);
return ret;
case 18 ... 21:
/* setting fully enclosed in the second register */
reg += 4;
bit -= 16;
break;
default:
debug("unsupported bit: %d for pinctrl drive type: %d\n",
bit, drv_type);
return -EINVAL;
}
break;
case DRV_TYPE_IO_DEFAULT:
case DRV_TYPE_IO_1V8_OR_3V0:
case DRV_TYPE_IO_1V8_ONLY:
rmask_bits = ROCKCHIP_DRV_BITS_PER_PIN;
break;
default:
debug("unsupported pinctrl drive type: %d\n",
drv_type);
return -EINVAL;
}
/* enable the write to the equivalent lower bits */
data = ((1 << rmask_bits) - 1) << (bit + 16);
data |= (ret << bit);
ret = regmap_write(regmap, reg, data);
return ret;
}
#define PX30_SCHMITT_PMU_OFFSET 0x38
#define PX30_SCHMITT_GRF_OFFSET 0xc0
#define PX30_SCHMITT_PINS_PER_PMU_REG 16
#define PX30_SCHMITT_BANK_STRIDE 16
#define PX30_SCHMITT_PINS_PER_GRF_REG 8
static int px30_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
int pin_num,
struct regmap **regmap,
int *reg, u8 *bit)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
int pins_per_reg;
if (bank->bank_num == 0) {
*regmap = priv->regmap_pmu;
*reg = PX30_SCHMITT_PMU_OFFSET;
pins_per_reg = PX30_SCHMITT_PINS_PER_PMU_REG;
} else {
*regmap = priv->regmap_base;
*reg = PX30_SCHMITT_GRF_OFFSET;
pins_per_reg = PX30_SCHMITT_PINS_PER_GRF_REG;
*reg += (bank->bank_num - 1) * PX30_SCHMITT_BANK_STRIDE;
}
*reg += ((pin_num / pins_per_reg) * 4);
*bit = pin_num % pins_per_reg;
return 0;
}
static int px30_set_schmitt(struct rockchip_pin_bank *bank,
int pin_num, int enable)
{
struct regmap *regmap;
int reg;
u8 bit;
u32 data;
px30_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
/* enable the write to the equivalent lower bits */
data = BIT(bit + 16) | (enable << bit);
return regmap_write(regmap, reg, data);
}
static struct rockchip_pin_bank px30_pin_banks[] = {
PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
IOMUX_SOURCE_PMU,
IOMUX_SOURCE_PMU,
IOMUX_SOURCE_PMU
),
PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT
),
PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT
),
PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT,
IOMUX_WIDTH_4BIT
),
};
static struct rockchip_pin_ctrl px30_pin_ctrl = {
.pin_banks = px30_pin_banks,
.nr_banks = ARRAY_SIZE(px30_pin_banks),
.grf_mux_offset = 0x0,
.pmu_mux_offset = 0x0,
.grf_drv_offset = 0xf0,
.pmu_drv_offset = 0x20,
.iomux_routes = px30_mux_route_data,
.niomux_routes = ARRAY_SIZE(px30_mux_route_data),
.set_mux = px30_set_mux,
.set_pull = px30_set_pull,
.set_drive = px30_set_drive,
.set_schmitt = px30_set_schmitt,
};
static const struct udevice_id px30_pinctrl_ids[] = {
{
.compatible = "rockchip,px30-pinctrl",
.data = (ulong)&px30_pin_ctrl
},
{ }
};
U_BOOT_DRIVER(pinctrl_px30) = {
.name = "rockchip_px30_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = px30_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct rockchip_pinctrl_priv),
.ops = &rockchip_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.bind = dm_scan_fdt_dev,
#endif
.probe = rockchip_pinctrl_probe,
};
@@ -0,0 +1,109 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2019 Rockchip Electronics Co., Ltd
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <regmap.h>
#include <syscon.h>
#include "pinctrl-rockchip.h"
static int rk3036_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
int iomux_num = (pin / 8);
struct regmap *regmap;
int reg, ret, mask, mux_type;
u8 bit;
u32 data;
regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
? priv->regmap_pmu : priv->regmap_base;
/* get basic quadrupel of mux registers and the correct reg inside */
mux_type = bank->iomux[iomux_num].type;
reg = bank->iomux[iomux_num].offset;
reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
data = (mask << (bit + 16));
data |= (mux & mask) << bit;
ret = regmap_write(regmap, reg, data);
return ret;
}
#define RK3036_PULL_OFFSET 0x118
#define RK3036_PULL_PINS_PER_REG 16
#define RK3036_PULL_BANK_STRIDE 8
static void rk3036_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
int pin_num, struct regmap **regmap,
int *reg, u8 *bit)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
*regmap = priv->regmap_base;
*reg = RK3036_PULL_OFFSET;
*reg += bank->bank_num * RK3036_PULL_BANK_STRIDE;
*reg += (pin_num / RK3036_PULL_PINS_PER_REG) * 4;
*bit = pin_num % RK3036_PULL_PINS_PER_REG;
};
static int rk3036_set_pull(struct rockchip_pin_bank *bank,
int pin_num, int pull)
{
struct regmap *regmap;
int reg, ret;
u8 bit;
u32 data;
if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT &&
pull != PIN_CONFIG_BIAS_DISABLE)
return -ENOTSUPP;
rk3036_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
data = BIT(bit + 16);
if (pull == PIN_CONFIG_BIAS_DISABLE)
data |= BIT(bit);
ret = regmap_write(regmap, reg, data);
return ret;
}
static struct rockchip_pin_bank rk3036_pin_banks[] = {
PIN_BANK(0, 32, "gpio0"),
PIN_BANK(1, 32, "gpio1"),
PIN_BANK(2, 32, "gpio2"),
};
static struct rockchip_pin_ctrl rk3036_pin_ctrl = {
.pin_banks = rk3036_pin_banks,
.nr_banks = ARRAY_SIZE(rk3036_pin_banks),
.grf_mux_offset = 0xa8,
.set_mux = rk3036_set_mux,
.set_pull = rk3036_set_pull,
};
static const struct udevice_id rk3036_pinctrl_ids[] = {
{
.compatible = "rockchip,rk3036-pinctrl",
.data = (ulong)&rk3036_pin_ctrl
},
{}
};
U_BOOT_DRIVER(pinctrl_rockchip) = {
.name = "rk3036-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = rk3036_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct rockchip_pinctrl_priv),
.ops = &rockchip_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.bind = dm_scan_fdt_dev,
#endif
.probe = rockchip_pinctrl_probe,
};
@@ -0,0 +1,211 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2019 Rockchip Electronics Co., Ltd
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <regmap.h>
#include <syscon.h>
#include "pinctrl-rockchip.h"
static struct rockchip_mux_recalced_data rk3128_mux_recalced_data[] = {
{
.num = 2,
.pin = 20,
.reg = 0xe8,
.bit = 0,
.mask = 0x7
}, {
.num = 2,
.pin = 21,
.reg = 0xe8,
.bit = 4,
.mask = 0x7
}, {
.num = 2,
.pin = 22,
.reg = 0xe8,
.bit = 8,
.mask = 0x7
}, {
.num = 2,
.pin = 23,
.reg = 0xe8,
.bit = 12,
.mask = 0x7
}, {
.num = 2,
.pin = 24,
.reg = 0xd4,
.bit = 12,
.mask = 0x7
},
};
static struct rockchip_mux_route_data rk3128_mux_route_data[] = {
{
/* spi-0 */
.bank_num = 1,
.pin = 10,
.func = 1,
.route_offset = 0x144,
.route_val = BIT(16 + 3) | BIT(16 + 4),
}, {
/* spi-1 */
.bank_num = 1,
.pin = 27,
.func = 3,
.route_offset = 0x144,
.route_val = BIT(16 + 3) | BIT(16 + 4) | BIT(3),
}, {
/* spi-2 */
.bank_num = 0,
.pin = 13,
.func = 2,
.route_offset = 0x144,
.route_val = BIT(16 + 3) | BIT(16 + 4) | BIT(4),
}, {
/* i2s-0 */
.bank_num = 1,
.pin = 5,
.func = 1,
.route_offset = 0x144,
.route_val = BIT(16 + 5),
}, {
/* i2s-1 */
.bank_num = 0,
.pin = 14,
.func = 1,
.route_offset = 0x144,
.route_val = BIT(16 + 5) | BIT(5),
}, {
/* emmc-0 */
.bank_num = 1,
.pin = 22,
.func = 2,
.route_offset = 0x144,
.route_val = BIT(16 + 6),
}, {
/* emmc-1 */
.bank_num = 2,
.pin = 4,
.func = 2,
.route_offset = 0x144,
.route_val = BIT(16 + 6) | BIT(6),
},
};
static int rk3128_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
int iomux_num = (pin / 8);
struct regmap *regmap;
int reg, ret, mask, mux_type;
u8 bit;
u32 data, route_reg, route_val;
regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
? priv->regmap_pmu : priv->regmap_base;
/* get basic quadrupel of mux registers and the correct reg inside */
mux_type = bank->iomux[iomux_num].type;
reg = bank->iomux[iomux_num].offset;
reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
if (bank->recalced_mask & BIT(pin))
rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
if (bank->route_mask & BIT(pin)) {
if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
&route_val)) {
ret = regmap_write(regmap, route_reg, route_val);
if (ret)
return ret;
}
}
data = (mask << (bit + 16));
data |= (mux & mask) << bit;
ret = regmap_write(regmap, reg, data);
return ret;
}
#define RK3128_PULL_OFFSET 0x118
#define RK3128_PULL_PINS_PER_REG 16
#define RK3128_PULL_BANK_STRIDE 8
static void rk3128_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
int pin_num, struct regmap **regmap,
int *reg, u8 *bit)
{
struct rockchip_pinctrl_priv *priv = bank->priv;
*regmap = priv->regmap_base;
*reg = RK3128_PULL_OFFSET;
*reg += bank->bank_num * RK3128_PULL_BANK_STRIDE;
*reg += ((pin_num / RK3128_PULL_PINS_PER_REG) * 4);
*bit = pin_num % RK3128_PULL_PINS_PER_REG;
}
static int rk3128_set_pull(struct rockchip_pin_bank *bank,
int pin_num, int pull)
{
struct regmap *regmap;
int reg, ret;
u8 bit;
u32 data;
if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT &&
pull != PIN_CONFIG_BIAS_DISABLE)
return -ENOTSUPP;
rk3128_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
data = BIT(bit + 16);
if (pull == PIN_CONFIG_BIAS_DISABLE)
data |= BIT(bit);
ret = regmap_write(regmap, reg, data);
return ret;
}
static struct rockchip_pin_bank rk3128_pin_banks[] = {
PIN_BANK(0, 32, "gpio0"),
PIN_BANK(1, 32, "gpio1"),
PIN_BANK(2, 32, "gpio2"),
PIN_BANK(3, 32, "gpio3"),
};
static struct rockchip_pin_ctrl rk3128_pin_ctrl = {
.pin_banks = rk3128_pin_banks,
.nr_banks = ARRAY_SIZE(rk3128_pin_banks),
.grf_mux_offset = 0xa8,
.iomux_recalced = rk3128_mux_recalced_data,
.niomux_recalced = ARRAY_SIZE(rk3128_mux_recalced_data),
.iomux_routes = rk3128_mux_route_data,
.niomux_routes = ARRAY_SIZE(rk3128_mux_route_data),
.set_mux = rk3128_set_mux,
.set_pull = rk3128_set_pull,
};
static const struct udevice_id rk3128_pinctrl_ids[] = {
{ .compatible = "rockchip,rk3128-pinctrl",
.data = (ulong)&rk3128_pin_ctrl },
{ }
};
U_BOOT_DRIVER(pinctrl_rk3128) = {
.name = "pinctrl_rk3128",
.id = UCLASS_PINCTRL,
.of_match = rk3128_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct rockchip_pinctrl_priv),
.ops = &rockchip_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.bind = dm_scan_fdt_dev,
#endif
.probe = rockchip_pinctrl_probe,
};

Some files were not shown because too many files have changed in this diff Show More