diff options
author | Peng Fan <peng.fan@nxp.com> | 2017-02-18 20:08:43 +0800 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:25:36 +0800 |
commit | 4f719fa0c290f006e75b999cdc0d1134b0cfde9f (patch) | |
tree | d3dd5e8e79b8bbe87bae8ff667caf3d5fbbfd854 /drivers | |
parent | da4135e8d44c2ca953ee5150979a562fd2a0e2f7 (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')
-rw-r--r-- | drivers/pinctrl/freescale/Kconfig | 19 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/Makefile | 2 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-imx.c | 262 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-imx.h | 32 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-memmap.c | 216 | ||||
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-scu.c | 103 |
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; +} |