Commit 15669d09e26002c8915e00f6b9d200a161c44277

Authored by Ye Li
1 parent f4ebe53335

MLK-16094-1 pinctrl: Add pinctrl driver for i.MX8 platform

Add pinctrl driver for i.MX8 platform (QM/QXP). The driver can
parse the iomuxc settings from DTB and set them through IPC to SCU.

Enable CONFIG_PINCTRL_IMX8 to use this pinctrl driver.

Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit e881106f14f879a0861caa39ce0cdc278e0806a6)

Showing 6 changed files with 254 additions and 93 deletions Side-by-side Diff

drivers/pinctrl/nxp/Kconfig
1 1 config PINCTRL_IMX
2 2 bool
3 3  
  4 +config PINCTRL_IMX_SCU
  5 + bool
  6 +
4 7 config PINCTRL_IMX5
5 8 bool "IMX5 pinctrl driver"
6 9 depends on ARCH_MX5 && PINCTRL_FULL
... ... @@ -66,6 +69,21 @@
66 69 Say Y here to enable the imx8m pinctrl driver
67 70  
68 71 This provides a simple pinctrl driver for i.MX8M SoC familiy.
  72 + This feature depends on device tree configuration. This driver
  73 + is different from the linux one, this is a simple implementation,
  74 + only parses the 'fsl,pins' property and configure related
  75 + registers.
  76 +
  77 +config PINCTRL_IMX8
  78 + bool "IMX8 pinctrl driver"
  79 + depends on ARCH_IMX8 && PINCTRL_FULL
  80 + select DEVRES
  81 + select PINCTRL_IMX
  82 + select PINCTRL_IMX_SCU
  83 + help
  84 + Say Y here to enable the imx8 pinctrl driver
  85 +
  86 + This provides a simple pinctrl driver for i.MX8 SoC familiy.
69 87 This feature depends on device tree configuration. This driver
70 88 is different from the linux one, this is a simple implementation,
71 89 only parses the 'fsl,pins' property and configure related
drivers/pinctrl/nxp/Makefile
... ... @@ -3,5 +3,7 @@
3 3 obj-$(CONFIG_PINCTRL_IMX6) += pinctrl-imx6.o
4 4 obj-$(CONFIG_PINCTRL_IMX7) += pinctrl-imx7.o
5 5 obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o
  6 +obj-$(CONFIG_PINCTRL_IMX8) += pinctrl-imx8.o
6 7 obj-$(CONFIG_PINCTRL_IMX8M) += pinctrl-imx8m.o
  8 +obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o
drivers/pinctrl/nxp/pinctrl-imx.c
1 1 /*
2 2 * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
  3 + * Copyright 2017 NXP
3 4 *
4 5 * SPDX-License-Identifier: GPL-2.0+
5 6 */
... ... @@ -29,7 +30,9 @@
29 30  
30 31 dev_dbg(dev, "%s: %s\n", __func__, config->name);
31 32  
32   - if (info->flags & SHARE_MUX_CONF_REG)
  33 + if (info->flags & IMX8_USE_SCU)
  34 + pin_size = SHARE_IMX8_PIN_SIZE;
  35 + else if (info->flags & SHARE_MUX_CONF_REG)
33 36 pin_size = SHARE_FSL_PIN_SIZE;
34 37 else
35 38 pin_size = FSL_PIN_SIZE;
36 39  
37 40  
38 41  
39 42  
40 43  
41 44  
42 45  
43 46  
44 47  
45 48  
46 49  
47 50  
48 51  
49 52  
50 53  
... ... @@ -59,112 +62,116 @@
59 62  
60 63 npins = size / pin_size;
61 64  
62   - /*
63   - * Refer to linux documentation for details:
64   - * Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
65   - */
66   - for (i = 0; i < npins; i++) {
67   - mux_reg = pin_data[j++];
  65 + if (info->flags & IMX8_USE_SCU) {
  66 + imx_pinctrl_scu_process_pins(info, pin_data, npins);
  67 + } else {
  68 + /*
  69 + * Refer to linux documentation for details:
  70 + * Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
  71 + */
  72 + for (i = 0; i < npins; i++) {
  73 + mux_reg = pin_data[j++];
68 74  
69   - if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
70   - mux_reg = -1;
  75 + if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
  76 + mux_reg = -1;
71 77  
72   - if (info->flags & SHARE_MUX_CONF_REG) {
73   - conf_reg = mux_reg;
74   - } else {
75   - conf_reg = pin_data[j++];
76   - if (!(info->flags & ZERO_OFFSET_VALID) && !conf_reg)
77   - conf_reg = -1;
78   - }
  78 + if (info->flags & SHARE_MUX_CONF_REG) {
  79 + conf_reg = mux_reg;
  80 + } else {
  81 + conf_reg = pin_data[j++];
  82 + if (!(info->flags & ZERO_OFFSET_VALID) && !conf_reg)
  83 + conf_reg = -1;
  84 + }
79 85  
80   - if ((mux_reg == -1) || (conf_reg == -1)) {
81   - dev_err(dev, "Error mux_reg or conf_reg\n");
82   - devm_kfree(dev, pin_data);
83   - return -EINVAL;
84   - }
  86 + if ((mux_reg == -1) || (conf_reg == -1)) {
  87 + dev_err(dev, "Error mux_reg or conf_reg\n");
  88 + devm_kfree(dev, pin_data);
  89 + return -EINVAL;
  90 + }
85 91  
86   - input_reg = pin_data[j++];
87   - mux_mode = pin_data[j++];
88   - input_val = pin_data[j++];
89   - config_val = pin_data[j++];
  92 + input_reg = pin_data[j++];
  93 + mux_mode = pin_data[j++];
  94 + input_val = pin_data[j++];
  95 + config_val = pin_data[j++];
90 96  
91   - dev_dbg(dev, "mux_reg 0x%x, conf_reg 0x%x, input_reg 0x%x, "
92   - "mux_mode 0x%x, input_val 0x%x, config_val 0x%x\n",
93   - mux_reg, conf_reg, input_reg, mux_mode, input_val,
94   - config_val);
  97 + dev_dbg(dev, "mux_reg 0x%x, conf_reg 0x%x, input_reg 0x%x, "
  98 + "mux_mode 0x%x, input_val 0x%x, config_val 0x%x\n",
  99 + mux_reg, conf_reg, input_reg, mux_mode, input_val,
  100 + config_val);
95 101  
96   - if (config_val & IMX_PAD_SION)
97   - mux_mode |= IOMUXC_CONFIG_SION;
  102 + if (config_val & IMX_PAD_SION)
  103 + mux_mode |= IOMUXC_CONFIG_SION;
98 104  
99   - config_val &= ~IMX_PAD_SION;
  105 + config_val &= ~IMX_PAD_SION;
100 106  
101   - /* Set Mux */
102   - if (info->flags & SHARE_MUX_CONF_REG) {
103   - clrsetbits_le32(info->base + mux_reg, info->mux_mask,
104   - mux_mode << mux_shift);
105   - } else {
106   - writel(mux_mode, info->base + mux_reg);
107   - }
  107 + /* Set Mux */
  108 + if (info->flags & SHARE_MUX_CONF_REG) {
  109 + clrsetbits_le32(info->base + mux_reg, info->mux_mask,
  110 + mux_mode << mux_shift);
  111 + } else {
  112 + writel(mux_mode, info->base + mux_reg);
  113 + }
108 114  
109   - dev_dbg(dev, "write mux: offset 0x%x val 0x%x\n", mux_reg,
110   - mux_mode);
  115 + dev_dbg(dev, "write mux: offset 0x%x val 0x%x\n", mux_reg,
  116 + mux_mode);
111 117  
112   - /*
113   - * Set select input
114   - *
115   - * If the select input value begins with 0xff, it's a quirky
116   - * select input and the value should be interpreted as below.
117   - * 31 23 15 7 0
118   - * | 0xff | shift | width | select |
119   - * It's used to work around the problem that the select
120   - * input for some pin is not implemented in the select
121   - * input register but in some general purpose register.
122   - * We encode the select input value, width and shift of
123   - * the bit field into input_val cell of pin function ID
124   - * in device tree, and then decode them here for setting
125   - * up the select input bits in general purpose register.
126   - */
127   -
128   - if (input_val >> 24 == 0xff) {
129   - u32 val = input_val;
130   - u8 select = val & 0xff;
131   - u8 width = (val >> 8) & 0xff;
132   - u8 shift = (val >> 16) & 0xff;
133   - u32 mask = ((1 << width) - 1) << shift;
134 118 /*
135   - * The input_reg[i] here is actually some IOMUXC general
136   - * purpose register, not regular select input register.
  119 + * Set select input
  120 + *
  121 + * If the select input value begins with 0xff, it's a quirky
  122 + * select input and the value should be interpreted as below.
  123 + * 31 23 15 7 0
  124 + * | 0xff | shift | width | select |
  125 + * It's used to work around the problem that the select
  126 + * input for some pin is not implemented in the select
  127 + * input register but in some general purpose register.
  128 + * We encode the select input value, width and shift of
  129 + * the bit field into input_val cell of pin function ID
  130 + * in device tree, and then decode them here for setting
  131 + * up the select input bits in general purpose register.
137 132 */
138   - val = readl(info->base + input_reg);
139   - val &= ~mask;
140   - val |= select << shift;
141   - writel(val, info->base + input_reg);
142   - } else if (input_reg) {
143   - /*
144   - * Regular select input register can never be at offset
145   - * 0, and we only print register value for regular case.
146   - */
147   - if (info->input_sel_base)
148   - writel(input_val, info->input_sel_base +
149   - input_reg);
150   - else
151   - writel(input_val, info->base + input_reg);
152 133  
153   - dev_dbg(dev, "select_input: offset 0x%x val 0x%x\n",
154   - input_reg, input_val);
155   - }
  134 + if (input_val >> 24 == 0xff) {
  135 + u32 val = input_val;
  136 + u8 select = val & 0xff;
  137 + u8 width = (val >> 8) & 0xff;
  138 + u8 shift = (val >> 16) & 0xff;
  139 + u32 mask = ((1 << width) - 1) << shift;
  140 + /*
  141 + * The input_reg[i] here is actually some IOMUXC general
  142 + * purpose register, not regular select input register.
  143 + */
  144 + val = readl(info->base + input_reg);
  145 + val &= ~mask;
  146 + val |= select << shift;
  147 + writel(val, info->base + input_reg);
  148 + } else if (input_reg) {
  149 + /*
  150 + * Regular select input register can never be at offset
  151 + * 0, and we only print register value for regular case.
  152 + */
  153 + if (info->input_sel_base)
  154 + writel(input_val, info->input_sel_base +
  155 + input_reg);
  156 + else
  157 + writel(input_val, info->base + input_reg);
156 158  
157   - /* Set config */
158   - if (!(config_val & IMX_NO_PAD_CTL)) {
159   - if (info->flags & SHARE_MUX_CONF_REG) {
160   - clrsetbits_le32(info->base + conf_reg,
161   - ~info->mux_mask, config_val);
162   - } else {
163   - writel(config_val, info->base + conf_reg);
  159 + dev_dbg(dev, "select_input: offset 0x%x val 0x%x\n",
  160 + input_reg, input_val);
164 161 }
165 162  
166   - dev_dbg(dev, "write config: offset 0x%x val 0x%x\n",
167   - conf_reg, config_val);
  163 + /* Set config */
  164 + if (!(config_val & IMX_NO_PAD_CTL)) {
  165 + if (info->flags & SHARE_MUX_CONF_REG) {
  166 + clrsetbits_le32(info->base + conf_reg,
  167 + (~info->mux_mask), config_val);
  168 + } else {
  169 + writel(config_val, info->base + conf_reg);
  170 + }
  171 +
  172 + dev_dbg(dev, "write config: offset 0x%x val 0x%x\n",
  173 + conf_reg, config_val);
  174 + }
168 175 }
169 176 }
170 177  
... ... @@ -194,6 +201,9 @@
194 201 priv->dev = dev;
195 202 priv->info = info;
196 203  
  204 + if (info->flags & IMX8_USE_SCU)
  205 + return 0;
  206 +
197 207 addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
198 208 &size);
199 209  
... ... @@ -238,6 +248,9 @@
238 248 {
239 249 struct imx_pinctrl_priv *priv = dev_get_priv(dev);
240 250 struct imx_pinctrl_soc_info *info = priv->info;
  251 +
  252 + if (info->flags & IMX8_USE_SCU)
  253 + return 0;
241 254  
242 255 if (info->input_sel_base)
243 256 unmap_sysmem(info->input_sel_base);
drivers/pinctrl/nxp/pinctrl-imx.h
... ... @@ -41,14 +41,28 @@
41 41 #define FSL_PIN_SIZE 24
42 42 #define SHARE_FSL_PIN_SIZE 20
43 43  
  44 +/* Each pin on imx8qm/qxp consists of 2 u32 PIN_FUNC_ID and 1 u32 CONFIG */
  45 +#define SHARE_IMX8_PIN_SIZE 12
  46 +
44 47 #define SHARE_MUX_CONF_REG 0x1
45 48 #define ZERO_OFFSET_VALID 0x2
46 49 #define CONFIG_IBE_OBE 0x4
  50 +#define IMX8_USE_SCU 0x8
47 51  
48 52 #define IOMUXC_CONFIG_SION (0x1 << 4)
49 53  
50 54 int imx_pinctrl_probe(struct udevice *dev, struct imx_pinctrl_soc_info *info);
51 55  
52 56 int imx_pinctrl_remove(struct udevice *dev);
  57 +
  58 +#ifdef CONFIG_PINCTRL_IMX_SCU
  59 +int imx_pinctrl_scu_process_pins(struct imx_pinctrl_soc_info *info, u32 *pin_data, int npins);
  60 +#else
  61 +static inline int imx_pinctrl_scu_process_pins(struct imx_pinctrl_soc_info *info, u32 *pin_data, int npins)
  62 +{
  63 + return 0;
  64 +}
  65 +#endif
  66 +
53 67 #endif /* __DRIVERS_PINCTRL_IMX_H */
drivers/pinctrl/nxp/pinctrl-imx8.c
  1 +/*
  2 + * Copyright 2017 NXP
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <dm/device.h>
  9 +#include <dm/pinctrl.h>
  10 +
  11 +#include "pinctrl-imx.h"
  12 +
  13 +DECLARE_GLOBAL_DATA_PTR;
  14 +
  15 +static struct imx_pinctrl_soc_info imx8_pinctrl_soc_info = {
  16 + .flags = IMX8_USE_SCU,
  17 +};
  18 +
  19 +static int imx8_pinctrl_probe(struct udevice *dev)
  20 +{
  21 + struct imx_pinctrl_soc_info *info =
  22 + (struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
  23 +
  24 + info->base = (void *)gd->arch.ipc_channel_handle;
  25 + return imx_pinctrl_probe(dev, info);
  26 +}
  27 +
  28 +static const struct udevice_id imx8_pinctrl_match[] = {
  29 + { .compatible = "fsl,imx8qm-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
  30 + { .compatible = "fsl,imx8qxp-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
  31 + { /* sentinel */ }
  32 +};
  33 +
  34 +U_BOOT_DRIVER(imx8_pinctrl) = {
  35 + .name = "imx8_pinctrl",
  36 + .id = UCLASS_PINCTRL,
  37 + .of_match = of_match_ptr(imx8_pinctrl_match),
  38 + .probe = imx8_pinctrl_probe,
  39 + .remove = imx_pinctrl_remove,
  40 + .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
  41 + .ops = &imx_pinctrl_ops,
  42 + .flags = DM_FLAG_PRE_RELOC,
  43 +};
drivers/pinctrl/nxp/pinctrl-scu.c
  1 +/*
  2 + * Copyright 2017 NXP
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <errno.h>
  9 +#include <asm/io.h>
  10 +#include <asm/mach-imx/sci/sci.h>
  11 +#include "pinctrl-imx.h"
  12 +
  13 +#define PADRING_IFMUX_EN_SHIFT 31
  14 +#define PADRING_IFMUX_EN_MASK (1 << 31)
  15 +#define PADRING_GP_EN_SHIFT 30
  16 +#define PADRING_GP_EN_MASK (1 << 30)
  17 +#define PADRING_IFMUX_SHIFT 27
  18 +#define PADRING_IFMUX_MASK (0x7 << 27)
  19 +
  20 +
  21 +static int imx_pinconf_scu_set(struct imx_pinctrl_soc_info *info,
  22 + unsigned int pin_id, unsigned int mux, unsigned int val)
  23 +{
  24 + sc_err_t err = SC_ERR_NONE;
  25 + sc_ipc_t ipcHndl = (sc_ipc_t)info->base;
  26 +
  27 + /*
  28 + * Mux should be done in pmx set, but we do not have a good api
  29 + * to handle that in scfw, so config it in pad conf func
  30 + */
  31 +
  32 + if (ipcHndl == 0) {
  33 + printf("IPC handle not initialized!\n");
  34 + return -EIO;
  35 + }
  36 +
  37 + val |= PADRING_IFMUX_EN_MASK;
  38 + val |= PADRING_GP_EN_MASK;
  39 + val |= (mux << PADRING_IFMUX_SHIFT) & PADRING_IFMUX_MASK;
  40 +
  41 + err = sc_pad_set(ipcHndl, pin_id, val);
  42 +
  43 + if (err != SC_ERR_NONE)
  44 + return -EIO;
  45 +
  46 + return 0;
  47 +}
  48 +
  49 +
  50 +int imx_pinctrl_scu_process_pins(struct imx_pinctrl_soc_info *info, u32 *pin_data, int npins)
  51 +{
  52 + int pin_id, mux, config_val;
  53 + int i, j = 0;
  54 + int ret;
  55 +
  56 + /*
  57 + * Refer to linux documentation for details:
  58 + * Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
  59 + */
  60 + for (i = 0; i < npins; i++) {
  61 + pin_id = pin_data[j++];
  62 + mux = pin_data[j++];
  63 + config_val = pin_data[j++];
  64 +
  65 + ret = imx_pinconf_scu_set(info, pin_id, mux, config_val);
  66 + if (ret)
  67 + printf("Set pin %d, mux %d, val %d, error\n", pin_id, mux, config_val);
  68 + }
  69 +
  70 + return 0;
  71 +}