blob: aed47be337d8dae11a6d200cf0ac4701fd09a66e [file] [log] [blame]
Alice Guoaeb03192025-04-28 18:37:26 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2025 NXP
4 */
5
6#include <asm/io.h>
7#include <asm/mach-imx/sys_proto.h>
8#include <dm.h>
9#include <dm/device_compat.h>
10#include <dm/devres.h>
11#include <dm/pinctrl.h>
12#include <scmi_agent.h>
Alice Guo52291d52025-04-28 18:37:27 +080013#include <scmi_agent-uclass.h>
Alice Guoaeb03192025-04-28 18:37:26 +080014#include <scmi_protocols.h>
15
16#include "pinctrl-imx.h"
17
18#define DAISY_OFFSET_IMX95 0x408
19
20/* SCMI pin control types */
21#define PINCTRL_TYPE_MUX 192
22#define PINCTRL_TYPE_CONFIG 193
23#define PINCTRL_TYPE_DAISY_ID 194
24#define PINCTRL_TYPE_DAISY_CFG 195
25#define PINCTRL_NUM_CFGS_SHIFT 2
26
27struct imx_scmi_pinctrl_priv {
28 u16 daisy_offset;
29};
30
31static int imx_pinconf_scmi_set(struct udevice *dev, u32 mux_ofs, u32 mux, u32 config_val,
32 u32 input_ofs, u32 input_val)
33{
34 struct imx_scmi_pinctrl_priv *priv = dev_get_priv(dev);
35 int ret, num_cfgs = 0;
36 struct scmi_msg msg;
37
38 /* Call SCMI API to set the pin mux and configuration. */
39 struct scmi_pinctrl_config_set_out out;
40 struct scmi_pinctrl_config_set_in in = {
41 .identifier = mux_ofs / 4,
42 .function_id = 0xFFFFFFFF,
43 .attributes = 0,
44 };
45
46 if (mux_ofs) {
47 in.configs[num_cfgs].type = PINCTRL_TYPE_MUX;
48 in.configs[num_cfgs].val = mux;
49 num_cfgs++;
50 }
51
52 if (config_val) {
53 in.configs[num_cfgs].type = PINCTRL_TYPE_CONFIG;
54 in.configs[num_cfgs].val = config_val;
55 num_cfgs++;
56 }
57
58 if (input_ofs) {
59 in.configs[num_cfgs].type = PINCTRL_TYPE_DAISY_ID;
60 in.configs[num_cfgs].val = (input_ofs - priv->daisy_offset) / 4;
61 num_cfgs++;
62 in.configs[num_cfgs].type = PINCTRL_TYPE_DAISY_CFG;
63 in.configs[num_cfgs].val = input_val;
64 num_cfgs++;
65 }
66
67 /* Update the number of configs sent in this call. */
68 in.attributes = num_cfgs << PINCTRL_NUM_CFGS_SHIFT;
69
70 msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_PINCTRL,
71 SCMI_MSG_PINCTRL_CONFIG_SET, in, out);
72
73 ret = devm_scmi_process_msg(dev, &msg);
74 if (ret || out.status) {
75 dev_err(dev, "Failed to set PAD = %d, daisy = %d, scmi_err = %d, ret = %d\n",
76 mux_ofs / 4, input_ofs / 4, out.status, ret);
77 }
78
79 return ret;
80}
81
82static int imx_pinctrl_set_state_scmi(struct udevice *dev, struct udevice *config)
83{
84 int mux_ofs, mux, config_val, input_reg, input_val;
85 u32 *pin_data;
86 int i, j = 0;
87 int npins;
88 int ret;
89
90 ret = imx_pinctrl_set_state_common(dev, config, FSL_PIN_SIZE,
91 &pin_data, &npins);
92 if (ret)
93 return ret;
94
95 /*
96 * Refer to linux documentation for details:
97 * Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
98 */
99 for (i = 0; i < npins; i++) {
100 mux_ofs = pin_data[j++];
101 /* Skip config_reg */
102 j++;
103 input_reg = pin_data[j++];
104
105 mux = pin_data[j++];
106 input_val = pin_data[j++];
107 config_val = pin_data[j++];
108
109 if (config_val & IMX_PAD_SION)
110 mux |= IOMUXC_CONFIG_SION;
111
112 config_val &= ~IMX_PAD_SION;
113
114 ret = imx_pinconf_scmi_set(dev, mux_ofs, mux, config_val, input_reg, input_val);
115 if (ret && ret != -EPERM) {
116 dev_err(dev, "Set pin %d, mux %d, val %d, error\n",
117 mux_ofs, mux, config_val);
118 }
119 }
120
121 devm_kfree(dev, pin_data);
122
123 return ret;
124}
125
126static const struct pinctrl_ops imx_scmi_pinctrl_ops = {
127 .set_state = imx_pinctrl_set_state_scmi,
128};
129
130static int imx_scmi_pinctrl_probe(struct udevice *dev)
131{
132 struct imx_scmi_pinctrl_priv *priv = dev_get_priv(dev);
133
134 if (IS_ENABLED(CONFIG_IMX95))
135 priv->daisy_offset = DAISY_OFFSET_IMX95;
136 else
137 return -EINVAL;
138
139 return devm_scmi_of_get_channel(dev);
140}
141
142static int imx_scmi_pinctrl_bind(struct udevice *dev)
143{
144 if (IS_ENABLED(CONFIG_IMX95))
145 return 0;
146
147 return -ENODEV;
148}
149
150U_BOOT_DRIVER(scmi_pinctrl_imx) = {
151 .name = "scmi_pinctrl_imx",
152 .id = UCLASS_PINCTRL,
153 .bind = imx_scmi_pinctrl_bind,
154 .probe = imx_scmi_pinctrl_probe,
155 .priv_auto = sizeof(struct imx_scmi_pinctrl_priv),
156 .ops = &imx_scmi_pinctrl_ops,
157 .flags = DM_FLAG_PRE_RELOC,
158};
Alice Guo52291d52025-04-28 18:37:27 +0800159
160static struct scmi_proto_match match[] = {
161 { .proto_id = SCMI_PROTOCOL_ID_PINCTRL },
162 { /* Sentinel */ }
163};
164
165U_BOOT_SCMI_PROTO_DRIVER(scmi_pinctrl_imx, match);