summaryrefslogtreecommitdiff
path: root/drivers/pinctrl
diff options
context:
space:
mode:
authorPeng Fan <peng.fan@nxp.com>2017-02-18 20:08:43 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:25:36 +0800
commit4f719fa0c290f006e75b999cdc0d1134b0cfde9f (patch)
treed3dd5e8e79b8bbe87bae8ff667caf3d5fbbfd854 /drivers/pinctrl
parentda4135e8d44c2ca953ee5150979a562fd2a0e2f7 (diff)
MLK-13911-7 drivers: pinctrl: support i.MX8 SCU
On i.MX8QM/QXP, pin is handled by SCU, A53/72 can not directly handle pinmux as i.MX6/7. Split the original pinctrl-imx.c to two parts, the pinctrl-memmap.c will handle the memory mapped access for i.MX6/7. pinctrl-imx.c will be shared by legacy i.mx and i.MX8. Introduce pinctrl-scu.c to handle the connection with SCU to configure pin settings. Signed-off-by: Peng Fan <peng.fan@nxp.com> Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Rebased on top of 4.14 changes Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r--drivers/pinctrl/freescale/Kconfig19
-rw-r--r--drivers/pinctrl/freescale/Makefile2
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c262
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.h32
-rw-r--r--drivers/pinctrl/freescale/pinctrl-memmap.c216
-rw-r--r--drivers/pinctrl/freescale/pinctrl-scu.c103
6 files changed, 435 insertions, 199 deletions
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index e213fc90b876..ab0e8564eb3a 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -5,6 +5,12 @@ config PINCTRL_IMX
select GENERIC_PINCONF
select REGMAP
+config PINCTRL_IMX_SCU
+ bool
+
+config PINCTRL_IMX_MEMMAP
+ bool
+
config PINCTRL_IMX1_CORE
bool
select PINMUX
@@ -37,6 +43,7 @@ config PINCTRL_IMX25
depends on OF
depends on SOC_IMX25
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx25 pinctrl driver
@@ -44,6 +51,7 @@ config PINCTRL_IMX35
bool "IMX35 pinctrl driver"
depends on SOC_IMX35
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx35 pinctrl driver
@@ -51,6 +59,7 @@ config PINCTRL_IMX50
bool "IMX50 pinctrl driver"
depends on SOC_IMX50
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx50 pinctrl driver
@@ -58,6 +67,7 @@ config PINCTRL_IMX51
bool "IMX51 pinctrl driver"
depends on SOC_IMX51
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx51 pinctrl driver
@@ -65,6 +75,7 @@ config PINCTRL_IMX53
bool "IMX53 pinctrl driver"
depends on SOC_IMX53
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx53 pinctrl driver
@@ -72,6 +83,7 @@ config PINCTRL_IMX6Q
bool "IMX6Q/DL pinctrl driver"
depends on SOC_IMX6Q
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6q/dl pinctrl driver
@@ -79,6 +91,7 @@ config PINCTRL_IMX6SL
bool "IMX6SL pinctrl driver"
depends on SOC_IMX6SL
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6sl pinctrl driver
@@ -86,6 +99,7 @@ config PINCTRL_IMX6SX
bool "IMX6SX pinctrl driver"
depends on SOC_IMX6SX
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6sx pinctrl driver
@@ -93,6 +107,7 @@ config PINCTRL_IMX6UL
bool "IMX6UL pinctrl driver"
depends on SOC_IMX6UL
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6ul pinctrl driver
@@ -100,6 +115,7 @@ config PINCTRL_IMX6SLL
bool "IMX6SLL pinctrl driver"
depends on SOC_IMX6SLL
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6sll pinctrl driver
@@ -107,6 +123,7 @@ config PINCTRL_IMX7D
bool "IMX7D pinctrl driver"
depends on SOC_IMX7D
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx7d pinctrl driver
@@ -114,6 +131,7 @@ config PINCTRL_IMX7ULP
bool "IMX7ULP pinctrl driver"
depends on SOC_IMX7ULP
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx7ulp pinctrl driver
@@ -121,6 +139,7 @@ config PINCTRL_VF610
bool "Freescale Vybrid VF610 pinctrl driver"
depends on SOC_VF610
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the Freescale Vybrid VF610 pinctrl driver
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index bbb9c9c01435..8987cc6f29f9 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
# Freescale pin control drivers
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
+obj-$(CONFIG_PINCTRL_IMX_MEMMAP)+= pinctrl-memmap.o
+obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o
obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o
obj-$(CONFIG_PINCTRL_IMX1) += pinctrl-imx1.o
obj-$(CONFIG_PINCTRL_IMX21) += pinctrl-imx21.o
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index dd359637e399..df12a08e4694 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -33,7 +33,6 @@
/* The bits in CONFIG cell defined in binding doc*/
#define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */
-#define IMX_PAD_SION 0x40000000 /* set SION */
static inline const struct group_desc *imx_pinctrl_find_group_by_name(
struct pinctrl_dev *pctldev,
@@ -80,11 +79,15 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
return -EINVAL;
}
- for (i = 0; i < grp->num_pins; i++) {
- struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
+ if (info->flags & IMX8_USE_SCU) {
+ map_num += grp->num_pins;
+ } else {
+ for (i = 0; i < grp->num_pins; i++) {
+ struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
- if (!(pin->config & IMX_NO_PAD_CTL))
- map_num++;
+ if (!(pin->pin_conf.pin_memmap.config & IMX_NO_PAD_CTL))
+ map_num++;
+ }
}
new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);
@@ -110,11 +113,20 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
for (i = j = 0; i < grp->num_pins; i++) {
struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
- if (!(pin->config & IMX_NO_PAD_CTL)) {
+ if (info->flags & IMX8_USE_SCU) {
+ new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
+ new_map[j].data.configs.group_or_pin =
+ pin_get_name(pctldev, pin->pin);
+ new_map[j].data.configs.configs =
+ (unsigned long *)&pin->pin_conf.pin_scu.all;
+ new_map[j].data.configs.num_configs = 1;
+ j++;
+ } else if (!(pin->pin_conf.pin_memmap.config & IMX_NO_PAD_CTL)) {
new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
new_map[j].data.configs.group_or_pin =
pin_get_name(pctldev, pin->pin);
- new_map[j].data.configs.configs = &pin->config;
+ new_map[j].data.configs.configs =
+ &pin->pin_conf.pin_memmap.config;
new_map[j].data.configs.num_configs = 1;
j++;
}
@@ -146,10 +158,8 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
unsigned group)
{
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg;
- unsigned int npins, pin_id;
- int i;
+ unsigned int npins;
+ int i, err;
struct group_desc *grp = NULL;
struct function_desc *func = NULL;
@@ -171,73 +181,9 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
func->name, grp->name);
for (i = 0; i < npins; i++) {
- struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
-
- pin_id = pin->pin;
- pin_reg = &info->pin_regs[pin_id];
-
- if (pin_reg->mux_reg == -1) {
- dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n",
- info->pins[pin_id].name);
- continue;
- }
-
- if (info->flags & SHARE_MUX_CONF_REG) {
- u32 reg;
- reg = readl(ipctl->base + pin_reg->mux_reg);
- reg &= ~info->mux_mask;
- reg |= (pin->mux_mode << info->mux_shift);
- writel(reg, ipctl->base + pin_reg->mux_reg);
- dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
- pin_reg->mux_reg, reg);
- } else {
- writel(pin->mux_mode, ipctl->base + pin_reg->mux_reg);
- dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
- pin_reg->mux_reg, pin->mux_mode);
- }
-
- /*
- * 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 (pin->input_val >> 24 == 0xff) {
- u32 val = pin->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(ipctl->base + pin->input_reg);
- val &= ~mask;
- val |= select << shift;
- writel(val, ipctl->base + pin->input_reg);
- } else if (pin->input_reg) {
- /*
- * Regular select input register can never be at offset
- * 0, and we only print register value for regular case.
- */
- if (ipctl->input_sel_base)
- writel(pin->input_val, ipctl->input_sel_base +
- pin->input_reg);
- else
- writel(pin->input_val, ipctl->base +
- pin->input_reg);
- dev_dbg(ipctl->dev,
- "==>select_input: offset 0x%x val 0x%x\n",
- pin->input_reg, pin->input_val);
- }
+ err = imx_pmx_set_one_pin(ipctl, &((struct imx_pin *)(grp->data))[i]);
+ if (err)
+ return err;
}
return 0;
@@ -309,75 +255,28 @@ static u32 imx_pinconf_parse_generic_config(struct device_node *np,
static int imx_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin_id, unsigned long *config)
{
- struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
-
- if (pin_reg->conf_reg == -1) {
- dev_err(info->dev, "Pin(%s) does not support config function\n",
- info->pins[pin_id].name);
- return -EINVAL;
- }
-
- *config = readl(ipctl->base + pin_reg->conf_reg);
-
- if (info->flags & SHARE_MUX_CONF_REG)
- *config &= ~info->mux_mask;
-
- return 0;
+ return imx_pinconf_backend_get(pctldev, pin_id, config);
}
static int imx_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin_id, unsigned long *configs,
unsigned num_configs)
{
- struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
- int i;
-
- if (pin_reg->conf_reg == -1) {
- dev_err(info->dev, "Pin(%s) does not support config function\n",
- info->pins[pin_id].name);
- return -EINVAL;
- }
-
- dev_dbg(ipctl->dev, "pinconf set pin %s\n",
- info->pins[pin_id].name);
-
- for (i = 0; i < num_configs; i++) {
- if (info->flags & SHARE_MUX_CONF_REG) {
- u32 reg;
- reg = readl(ipctl->base + pin_reg->conf_reg);
- reg &= info->mux_mask;
- reg |= configs[i];
- writel(reg, ipctl->base + pin_reg->conf_reg);
- dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
- pin_reg->conf_reg, reg);
- } else {
- writel(configs[i], ipctl->base + pin_reg->conf_reg);
- dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
- pin_reg->conf_reg, configs[i]);
- }
- } /* for each config */
-
- return 0;
+ return imx_pinconf_backend_set(pctldev, pin_id, configs, num_configs);
}
static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned pin_id)
{
- struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
unsigned long config;
+ int ret;
- if (!pin_reg || pin_reg->conf_reg == -1) {
+ ret = imx_pinconf_backend_get(pctldev, pin_id, &config);
+ if (ret) {
seq_printf(s, "N/A");
return;
}
- config = readl(ipctl->base + pin_reg->conf_reg);
seq_printf(s, "0x%lx", config);
}
@@ -419,6 +318,7 @@ static const struct pinconf_ops imx_pinconf_ops = {
* 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_IMX8_PIN_SIZE 8
#define FSL_PIN_SIZE 24
#define SHARE_FSL_PIN_SIZE 20
@@ -429,13 +329,15 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
{
struct imx_pinctrl_soc_info *info = ipctl->info;
int size, pin_size;
- const __be32 *list;
- int i;
+ const __be32 *list, **list_p;
u32 config;
+ int i;
dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
- if (info->flags & SHARE_MUX_CONF_REG)
+ if (info->flags & IMX8_USE_SCU)
+ pin_size = FSL_IMX8_PIN_SIZE;
+ else if (info->flags & SHARE_MUX_CONF_REG)
pin_size = SHARE_FSL_PIN_SIZE;
else
pin_size = FSL_PIN_SIZE;
@@ -466,6 +368,8 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
}
}
+ list_p = &list;
+
/* we do not check return since it's safe node passed down */
if (!size || size % pin_size) {
dev_err(info->dev, "Invalid fsl,pins or pins property in node %pOF\n", np);
@@ -484,48 +388,10 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
return -ENOMEM;
for (i = 0; i < grp->num_pins; i++) {
- u32 mux_reg = be32_to_cpu(*list++);
- u32 conf_reg;
- unsigned int pin_id;
- struct imx_pin_reg *pin_reg;
struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
- 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 = be32_to_cpu(*list++);
- if (!conf_reg)
- conf_reg = -1;
- }
-
- pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
- pin_reg = &info->pin_regs[pin_id];
- pin->pin = pin_id;
- grp->pins[i] = pin_id;
- pin_reg->mux_reg = mux_reg;
- pin_reg->conf_reg = conf_reg;
- pin->input_reg = be32_to_cpu(*list++);
- pin->mux_mode = be32_to_cpu(*list++);
- pin->input_val = be32_to_cpu(*list++);
-
- if (info->generic_pinconf) {
- /* generic pin config decoded */
- pin->config = config;
- } else {
- /* legacy pin config read from devicetree */
- config = be32_to_cpu(*list++);
-
- /* SION bit is in mux register */
- if (config & IMX_PAD_SION)
- pin->mux_mode |= IOMUXC_CONFIG_SION;
- pin->config = config & ~IMX_PAD_SION;
- }
-
- dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
- pin->mux_mode, pin->config);
+ imx_pinctrl_parse_pin(info, &grp->pins[i], pin,
+ list_p, config);
}
return 0;
@@ -700,34 +566,36 @@ int imx_pinctrl_probe(struct platform_device *pdev,
if (!ipctl)
return -ENOMEM;
- info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
- info->npins, GFP_KERNEL);
- if (!info->pin_regs)
- return -ENOMEM;
+ if (!(info->flags & IMX8_USE_SCU)) {
+ info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
+ info->npins, GFP_KERNEL);
+ if (!info->pin_regs)
+ return -ENOMEM;
- for (i = 0; i < info->npins; i++) {
- info->pin_regs[i].mux_reg = -1;
- info->pin_regs[i].conf_reg = -1;
- }
+ for (i = 0; i < info->npins; i++) {
+ info->pin_regs[i].mux_reg = -1;
+ info->pin_regs[i].conf_reg = -1;
+ }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ipctl->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ipctl->base))
- return PTR_ERR(ipctl->base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ipctl->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ipctl->base))
+ return PTR_ERR(ipctl->base);
- if (of_property_read_bool(dev_np, "fsl,input-sel")) {
- np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
- if (!np) {
- dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
- return -EINVAL;
- }
+ if (of_property_read_bool(dev_np, "fsl,input-sel")) {
+ np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
+ if (!np) {
+ dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
+ return -EINVAL;
+ }
- ipctl->input_sel_base = of_iomap(np, 0);
- of_node_put(np);
- if (!ipctl->input_sel_base) {
- dev_err(&pdev->dev,
- "iomuxc input select base address not found\n");
- return -ENOMEM;
+ ipctl->input_sel_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!ipctl->input_sel_base) {
+ dev_err(&pdev->dev,
+ "iomuxc input select base address not found\n");
+ return -ENOMEM;
+ }
}
}
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h
index 15a92fa724d7..f915bf93aef4 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.h
+++ b/drivers/pinctrl/freescale/pinctrl-imx.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
+ * Copyright 2017 NXP
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
@@ -31,14 +32,25 @@ extern struct pinmux_ops imx_pmx_ops;
* @input_val: the select input value for this pin.
* @configs: the config for this pin.
*/
-struct imx_pin {
- unsigned int pin;
+struct imx_pin_memmap {
unsigned int mux_mode;
u16 input_reg;
unsigned int input_val;
unsigned long config;
};
+struct imx_pin_scu {
+ unsigned int all;
+};
+
+struct imx_pin {
+ unsigned int pin;
+ union {
+ struct imx_pin_memmap pin_memmap;
+ struct imx_pin_scu pin_scu;
+ } pin_conf;
+};
+
/**
* struct imx_pin_reg - describe a pin reg map
* @mux_reg: mux register offset
@@ -106,6 +118,14 @@ struct imx_pinctrl {
#define SHARE_MUX_CONF_REG 0x1
#define ZERO_OFFSET_VALID 0x2
+#define CONFIG_IBE_OBE 0x4
+
+#define IMX8_ENABLE_MUX_CONFIG (1 << 29)
+#define IMX8_ENABLE_PAD_CONFIG (1 << 30)
+#define IMX8_USE_SCU (1 << 31)
+
+#define BM_IMX8_GP_ENABLE (1 << 30)
+#define BM_IMX8_IFMUX_ENABLE (1 << 31)
#define NO_MUX 0x0
#define NO_PAD 0x0
@@ -120,4 +140,12 @@ int imx_pinctrl_probe(struct platform_device *pdev,
struct imx_pinctrl_soc_info *info);
int imx_pinctrl_suspend(struct device *dev);
int imx_pinctrl_resume(struct device *dev);
+int imx_pmx_set_one_pin(struct imx_pinctrl *ipctl, struct imx_pin *pin);
+int imx_pinconf_backend_get(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *config);
+int imx_pinconf_backend_set(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs);
+int imx_pinctrl_parse_pin(struct imx_pinctrl_soc_info *info,
+ unsigned int *pin_id, struct imx_pin *pin,
+ const __be32 **list_p, u32 generic_config);
#endif /* __DRIVERS_PINCTRL_IMX_H */
diff --git a/drivers/pinctrl/freescale/pinctrl-memmap.c b/drivers/pinctrl/freescale/pinctrl-memmap.c
new file mode 100644
index 000000000000..a1f02a97cdc2
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-memmap.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "pinctrl-imx.h"
+
+#define IMX_PAD_SION 0x40000000 /* set SION */
+
+#define IOMUXC_IBE (1 << 16)
+#define IOMUXC_OBE (1 << 17)
+
+int imx_pmx_set_one_pin(struct imx_pinctrl *ipctl, struct imx_pin *pin)
+{
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ unsigned int pin_id = pin->pin;
+ struct imx_pin_reg *pin_reg;
+ struct imx_pin_memmap *pin_memmap;
+ pin_reg = &info->pin_regs[pin_id];
+ pin_memmap = &pin->pin_conf.pin_memmap;
+
+ if (pin_reg->mux_reg == -1) {
+ dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ if (info->flags & SHARE_MUX_CONF_REG) {
+ u32 reg;
+ reg = readl(ipctl->base + pin_reg->mux_reg);
+ reg &= ~info->mux_mask;
+ reg |= (pin_memmap->mux_mode << info->mux_shift);
+ writel(reg, ipctl->base + pin_reg->mux_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
+ pin_reg->mux_reg, reg);
+ } else {
+ writel(pin_memmap->mux_mode, ipctl->base + pin_reg->mux_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
+ pin_reg->mux_reg, pin_memmap->mux_mode);
+ }
+
+ /*
+ * 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 (pin_memmap->input_val >> 24 == 0xff) {
+ u32 val = pin_memmap->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(ipctl->base + pin_memmap->input_reg);
+ val &= ~mask;
+ val |= select << shift;
+ writel(val, ipctl->base + pin_memmap->input_reg);
+ } else if (pin_memmap->input_reg) {
+ /*
+ * Regular select input register can never be at offset
+ * 0, and we only print register value for regular case.
+ */
+ if (ipctl->input_sel_base)
+ writel(pin_memmap->input_val, ipctl->input_sel_base +
+ pin_memmap->input_reg);
+ else
+ writel(pin_memmap->input_val, ipctl->base +
+ pin_memmap->input_reg);
+ dev_dbg(ipctl->dev,
+ "==>select_input: offset 0x%x val 0x%x\n",
+ pin_memmap->input_reg, pin_memmap->input_val);
+ }
+
+ return 0;
+}
+
+int imx_pinconf_backend_get(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *config)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+
+ if (pin_reg->conf_reg == -1) {
+ dev_err(info->dev, "Pin(%s) does not support config function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ *config = readl(ipctl->base + pin_reg->conf_reg);
+
+ if (info->flags & SHARE_MUX_CONF_REG)
+ *config &= ~info->mux_mask;
+
+ return 0;
+}
+
+int imx_pinconf_backend_set(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *configs,
+ unsigned num_configs)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+ int i;
+
+ if (pin_reg->conf_reg == -1) {
+ dev_err(info->dev, "Pin(%s) does not support config function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ dev_dbg(ipctl->dev, "pinconf set pin %s\n",
+ info->pins[pin_id].name);
+
+ for (i = 0; i < num_configs; i++) {
+ if (info->flags & SHARE_MUX_CONF_REG) {
+ u32 reg;
+ reg = readl(ipctl->base + pin_reg->conf_reg);
+ reg &= info->mux_mask;
+ reg |= configs[i];
+ writel(reg, ipctl->base + pin_reg->conf_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
+ pin_reg->conf_reg, reg);
+ } else {
+ writel(configs[i], ipctl->base + pin_reg->conf_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
+ pin_reg->conf_reg, configs[i]);
+ }
+ } /* for each config */
+
+ return 0;
+}
+
+int imx_pinctrl_parse_pin(struct imx_pinctrl_soc_info *info,
+ unsigned int *grp_pin_id, struct imx_pin *pin,
+ const __be32 **list_p, u32 generic_config)
+{
+ struct imx_pin_memmap *pin_memmap = &pin->pin_conf.pin_memmap;
+ const __be32 *list = *list_p;
+ u32 mux_reg = be32_to_cpu(*list++);
+ u32 conf_reg;
+ u32 config;
+ unsigned int pin_id;
+ struct imx_pin_reg *pin_reg;
+
+ if (info->flags & SHARE_MUX_CONF_REG) {
+ conf_reg = mux_reg;
+ } else {
+ conf_reg = be32_to_cpu(*list++);
+ if (!conf_reg)
+ conf_reg = -1;
+ }
+
+ pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
+ pin_reg = &info->pin_regs[pin_id];
+ pin->pin = pin_id;
+ *grp_pin_id = pin_id;
+ pin_reg->mux_reg = mux_reg;
+ pin_reg->conf_reg = conf_reg;
+ pin_memmap->input_reg = be32_to_cpu(*list++);
+ pin_memmap->mux_mode = be32_to_cpu(*list++);
+ pin_memmap->input_val = be32_to_cpu(*list++);
+
+ if (info->generic_pinconf) {
+ /* generic pin config decoded */
+ pin_memmap->config = generic_config;
+ } else {
+ /* legacy pin config read from devicetree */
+ config = be32_to_cpu(*list++);
+
+ /* SION bit is in mux register */
+ if (config & IMX_PAD_SION)
+ pin_memmap->mux_mode |= IOMUXC_CONFIG_SION;
+ pin_memmap->config = config & ~IMX_PAD_SION;
+ }
+
+ dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
+ pin_memmap->mux_mode, pin_memmap->config);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/freescale/pinctrl-scu.c b/drivers/pinctrl/freescale/pinctrl-scu.c
new file mode 100644
index 000000000000..00bc4e6c1c18
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-scu.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "../core.h"
+#include "pinctrl-imx.h"
+
+sc_ipc_t pinctrl_ipcHandle;
+
+int imx_pmx_set_one_pin(struct imx_pinctrl *ipctl, struct imx_pin *pin)
+{
+ return 0;
+}
+
+int imx_pinconf_backend_get(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *config)
+{
+ sc_err_t err = SC_ERR_NONE;
+ sc_ipc_t ipc = pinctrl_ipcHandle;
+
+ if (ipc == -1) {
+ printk("IPC handle not initialized!\n");
+ return -EIO;
+ }
+
+ err = sc_pad_get(ipc, pin_id, (unsigned int *)config);
+
+ if (err != SC_ERR_NONE)
+ return -EIO;
+
+ return 0;
+}
+int imx_pinconf_backend_set(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs)
+{
+ sc_err_t err = SC_ERR_NONE;
+ sc_ipc_t ipc = pinctrl_ipcHandle;
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ unsigned int val = configs[0];
+
+ if (ipc == -1) {
+ printk("IPC handle not initialized!\n");
+ return -EIO;
+ }
+
+ if (info->flags & IMX8_ENABLE_MUX_CONFIG)
+ val |= BM_IMX8_IFMUX_ENABLE;
+
+ if (info->flags & IMX8_ENABLE_PAD_CONFIG)
+ val |= BM_IMX8_GP_ENABLE;
+
+ if (info->flags & SHARE_MUX_CONF_REG)
+ err = sc_pad_set(ipc, pin_id, val);
+
+ if (err != SC_ERR_NONE)
+ return -EIO;
+
+ return 0;
+}
+
+int imx_pinctrl_parse_pin(struct imx_pinctrl_soc_info *info,
+ unsigned int *pin_id, struct imx_pin *pin,
+ const __be32 **list_p, u32 generic_config)
+{
+ const __be32 *list = *list_p;
+ struct imx_pin_scu *pin_scu = &pin->pin_conf.pin_scu;
+
+ pin->pin = be32_to_cpu(*list++);
+ *pin_id = pin->pin;
+ pin_scu->all = be32_to_cpu(*list++);
+
+ *list_p = list;
+
+ dev_dbg(info->dev, "%s: 0x%x",
+ info->pins[pin->pin].name, pin_scu->all);
+
+ return 0;
+}