pinctrl-scmi.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-11-26 GuEe-GUI first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #define DBG_TAG "pinctrl.scmi"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. #define ATTR_SEL(x) ((rt_uint32_t)(x) & 0x3U)
  16. #define ATTR_NUM(n) ((((rt_uint32_t)(n)) & 0xffU) << 2)
  17. #define ATTR_FUNCSEL (1u << 10)
  18. struct scmi_pinctrl_info
  19. {
  20. rt_uint32_t identifier;
  21. char name[64];
  22. };
  23. struct scmi_pinctrl
  24. {
  25. struct rt_device_pin parent;
  26. struct rt_scmi_device *sdev;
  27. rt_size_t pins_nr;
  28. struct scmi_pinctrl_info *pins;
  29. rt_size_t groups_nr;
  30. struct scmi_pinctrl_info *groups;
  31. rt_size_t function_nr;
  32. struct scmi_pinctrl_info *function;
  33. };
  34. #define raw_to_scmi_pinctrl(raw) rt_container_of(raw, struct scmi_pinctrl, parent)
  35. static const struct rt_pin_ctrl_conf_params scmi_conf_params[] =
  36. {
  37. { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
  38. { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
  39. { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
  40. { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
  41. { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
  42. { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
  43. { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
  44. { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
  45. { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
  46. { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
  47. { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
  48. { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
  49. { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
  50. { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
  51. { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
  52. { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
  53. { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
  54. { "low-power-disable", PIN_CONFIG_MODE_LOW_POWER, 0 },
  55. { "low-power-enable", PIN_CONFIG_MODE_LOW_POWER, 1 },
  56. { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
  57. { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
  58. { "output-high", PIN_CONFIG_OUTPUT, 1, },
  59. { "output-impedance-ohms", PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, 0 },
  60. { "output-low", PIN_CONFIG_OUTPUT, 0, },
  61. { "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
  62. { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
  63. };
  64. static enum scmi_pinctrl_conf_type scmi_conf_params_map[] =
  65. {
  66. SCMI_PINCTRL_BIAS_BUS_HOLD,
  67. SCMI_PINCTRL_BIAS_DISABLE,
  68. SCMI_PINCTRL_BIAS_HIGH_IMPEDANCE,
  69. SCMI_PINCTRL_BIAS_PULL_UP,
  70. SCMI_PINCTRL_BIAS_PULL_DEFAULT,
  71. SCMI_PINCTRL_BIAS_PULL_DOWN,
  72. SCMI_PINCTRL_DRIVE_OPEN_DRAIN,
  73. SCMI_PINCTRL_DRIVE_OPEN_SOURCE,
  74. SCMI_PINCTRL_DRIVE_PUSH_PULL,
  75. SCMI_PINCTRL_DRIVE_STRENGTH,
  76. SCMI_PINCTRL_DRIVE_STRENGTH,
  77. SCMI_PINCTRL_INPUT_DEBOUNCE,
  78. SCMI_PINCTRL_INPUT_MODE,
  79. SCMI_PINCTRL_INPUT_MODE,
  80. SCMI_PINCTRL_INPUT_SCHMITT,
  81. SCMI_PINCTRL_INPUT_MODE,
  82. SCMI_PINCTRL_INPUT_MODE,
  83. SCMI_PINCTRL_LOW_POWER_MODE,
  84. SCMI_PINCTRL_LOW_POWER_MODE,
  85. SCMI_PINCTRL_OUTPUT_MODE,
  86. SCMI_PINCTRL_OUTPUT_MODE,
  87. SCMI_PINCTRL_OUTPUT_VALUE,
  88. SCMI_PINCTRL_OUTPUT_VALUE,
  89. SCMI_PINCTRL_OUTPUT_VALUE,
  90. SCMI_PINCTRL_POWER_SOURCE,
  91. SCMI_PINCTRL_SLEW_RATE,
  92. };
  93. static rt_bool_t scmi_pinconf_prop_name_to_param(const char *propname,
  94. rt_uint32_t *default_value, rt_uint32_t *out_type)
  95. {
  96. const struct rt_pin_ctrl_conf_params *params = scmi_conf_params;
  97. for (int i = 0; i < RT_ARRAY_SIZE(scmi_conf_params); ++i, ++params)
  98. {
  99. if (!rt_strcmp(params->propname, propname))
  100. {
  101. *out_type = scmi_conf_params_map[i];
  102. *default_value = params->default_value;
  103. return RT_TRUE;
  104. }
  105. }
  106. return RT_FALSE;
  107. }
  108. static rt_bool_t scmi_lookup_id(const struct scmi_pinctrl_info *info,
  109. rt_size_t nr, const char *name, rt_uint32_t *out_id)
  110. {
  111. for (rt_size_t i = 0; i < nr; ++i)
  112. {
  113. if (!rt_strcmp((const char *)info[i].name, name))
  114. {
  115. *out_id = info[i].identifier;
  116. return RT_TRUE;
  117. }
  118. }
  119. return RT_FALSE;
  120. }
  121. static rt_err_t scmi_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np)
  122. {
  123. rt_err_t err = RT_EOK;
  124. const char *string;
  125. rt_uint32_t function_id = 0xffffffffU;
  126. rt_size_t pins_nr = 0, groups_nr = 0, params_nr = 0;
  127. rt_uint32_t pins_id[32], groups_id[32], params_type[32], params_val[32];
  128. struct rt_ofw_prop *prop;
  129. struct rt_ofw_node *np = fw_conf_np;
  130. struct scmi_pinctrl *spctl = raw_to_scmi_pinctrl(device);
  131. LOG_D("Pinctrl apply '%s'", rt_ofw_node_full_name(np));
  132. rt_ofw_foreach_prop(np, prop)
  133. {
  134. if (!rt_strcmp(prop->name, "phandle"))
  135. {
  136. continue;
  137. }
  138. else if (!rt_strcmp(prop->name, "groups"))
  139. {
  140. for (string = rt_ofw_prop_next_string(prop, RT_NULL); string;
  141. string = rt_ofw_prop_next_string(prop, string))
  142. {
  143. if (groups_nr >= RT_ARRAY_SIZE(groups_id))
  144. {
  145. return -RT_EFULL;
  146. }
  147. if (!scmi_lookup_id(spctl->groups, spctl->groups_nr, string, &groups_id[groups_nr]))
  148. {
  149. return -RT_EINVAL;
  150. }
  151. ++groups_nr;
  152. }
  153. }
  154. else if (!rt_strcmp(prop->name, "pins"))
  155. {
  156. for (string = rt_ofw_prop_next_string(prop, RT_NULL); string;
  157. string = rt_ofw_prop_next_string(prop, string))
  158. {
  159. if (pins_nr >= RT_ARRAY_SIZE(pins_id))
  160. {
  161. return -RT_EFULL;
  162. }
  163. if (!scmi_lookup_id(spctl->pins, spctl->pins_nr, string, &pins_id[pins_nr]))
  164. {
  165. return -RT_EINVAL;
  166. }
  167. ++pins_nr;
  168. }
  169. }
  170. else if (!rt_strcmp(prop->name, "function"))
  171. {
  172. string = rt_ofw_prop_next_string(prop, RT_NULL);
  173. if (!scmi_lookup_id(spctl->function, spctl->function_nr, string, &function_id))
  174. {
  175. return -RT_EINVAL;
  176. }
  177. }
  178. else
  179. {
  180. if (params_nr >= RT_ARRAY_SIZE(params_type))
  181. {
  182. return -RT_EFULL;
  183. }
  184. if (!scmi_pinconf_prop_name_to_param(prop->name, &params_val[params_nr], &params_type[params_nr]))
  185. {
  186. return -RT_EINVAL;
  187. }
  188. if (prop->length >= sizeof(rt_uint32_t))
  189. {
  190. rt_ofw_prop_next_u32(prop, RT_NULL, &params_val[params_nr]);
  191. }
  192. ++params_nr;
  193. }
  194. }
  195. if (function_id != 0xffffffffU)
  196. {
  197. for (rt_size_t i = 0; i < groups_nr; ++i)
  198. {
  199. struct scmi_pinctrl_settings_conf_in in =
  200. {
  201. .identifier = rt_cpu_to_le32(groups_id[i]),
  202. .function_id = rt_cpu_to_le32(function_id),
  203. .attributes = rt_cpu_to_le32(ATTR_SEL(SCMI_PINCTRL_TYPE_GROUP) | ATTR_FUNCSEL),
  204. };
  205. struct scmi_pinctrl_settings_conf_out out = {0};
  206. struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_PINCTRL_SETTINGS_CONFIGURE, &in, &out);
  207. if ((err = rt_scmi_process_msg(spctl->sdev, &msg)))
  208. {
  209. return err;
  210. }
  211. if (rt_le32_to_cpu(out.status) != 0)
  212. {
  213. return -RT_ERROR;
  214. }
  215. }
  216. }
  217. if (params_nr)
  218. {
  219. struct
  220. {
  221. struct scmi_pinctrl_settings_conf_in hdr;
  222. rt_le32_t config[2 * 32];
  223. } in;
  224. struct scmi_pinctrl_settings_conf_out out = {0};
  225. struct rt_scmi_msg msg = {
  226. .sdev = spctl->sdev,
  227. .message_id = SCMI_PINCTRL_SETTINGS_CONFIGURE,
  228. .out_msg = (rt_uint8_t *)&out,
  229. .out_msg_size = sizeof(out),
  230. };
  231. for (rt_size_t i = 0; i < params_nr; ++i)
  232. {
  233. in.config[2 * i + 0] = rt_cpu_to_le32(params_type[i]);
  234. in.config[2 * i + 1] = rt_cpu_to_le32(params_val[i]);
  235. }
  236. for (rt_size_t i = 0; i < groups_nr; i++)
  237. {
  238. in.hdr.identifier = rt_cpu_to_le32(groups_id[i]);
  239. in.hdr.function_id = rt_cpu_to_le32(0xffffffffU);
  240. in.hdr.attributes = rt_cpu_to_le32(ATTR_SEL(SCMI_PINCTRL_TYPE_GROUP) | ATTR_NUM(params_nr));
  241. msg.in_msg = (rt_uint8_t *)&in;
  242. msg.in_msg_size = (rt_uint32_t)(sizeof(in.hdr) + params_nr * 2 * sizeof(rt_le32_t));
  243. if ((err = rt_scmi_process_msg(spctl->sdev, &msg)))
  244. {
  245. return err;
  246. }
  247. if (rt_le32_to_cpu(out.status) != 0)
  248. {
  249. return -RT_ERROR;
  250. }
  251. }
  252. for (rt_size_t i = 0; i < pins_nr; i++)
  253. {
  254. in.hdr.identifier = rt_cpu_to_le32(pins_id[i]);
  255. in.hdr.function_id = rt_cpu_to_le32(0xffffffffU);
  256. in.hdr.attributes = rt_cpu_to_le32(ATTR_SEL(SCMI_PINCTRL_TYPE_PIN) | ATTR_NUM(params_nr));
  257. msg.in_msg = (rt_uint8_t *)&in;
  258. msg.in_msg_size = (rt_uint32_t)(sizeof(in.hdr) + params_nr * 2 * sizeof(rt_le32_t));
  259. if ((err = rt_scmi_process_msg(spctl->sdev, &msg)))
  260. {
  261. return err;
  262. }
  263. if (rt_le32_to_cpu(out.status) != 0)
  264. {
  265. return -RT_ERROR;
  266. }
  267. }
  268. }
  269. return err;
  270. }
  271. static const struct rt_pin_ops scmi_pinctrl_ops =
  272. {
  273. .pin_ctrl_confs_apply = scmi_pinctrl_confs_apply,
  274. };
  275. static rt_err_t scmi_pinctrl_name_parse_one(struct rt_scmi_device *sdev,
  276. enum scmi_pinctrl_selector_type sel, rt_size_t id, char *name)
  277. {
  278. rt_err_t err;
  279. struct scmi_pinctrl_attributes_in attr_in =
  280. {
  281. .identifier = rt_cpu_to_le32(id),
  282. .flags = rt_cpu_to_le32(sel),
  283. };
  284. struct scmi_pinctrl_attributes_out attr_out = {0};
  285. struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_PINCTRL_ATTRIBUTES, &attr_in, &attr_out);
  286. name[0] = '\0';
  287. if ((err = rt_scmi_process_msg(sdev, &msg)))
  288. {
  289. return err;
  290. }
  291. if (rt_le32_to_cpu(attr_out.status) != 0)
  292. {
  293. return -RT_ERROR;
  294. }
  295. rt_strncpy(name, (char *)attr_out.name, sizeof(attr_out.name));
  296. if (SCMI_PINCTRL_EXT_NAME_FLAG(rt_le32_to_cpu(attr_out.attributes)))
  297. {
  298. struct scmi_pinctrl_name_get_in name_in =
  299. {
  300. .identifier = rt_cpu_to_le32(id),
  301. .flags = rt_cpu_to_le32(sel),
  302. };
  303. struct scmi_pinctrl_name_get_out name_out = {0};
  304. msg = RT_SCMI_MSG_IN_OUT(SCMI_PINCTRL_NAME_GET, &name_in, &name_out);
  305. if ((err = rt_scmi_process_msg(sdev, &msg)))
  306. {
  307. return err;
  308. }
  309. if (rt_le32_to_cpu(name_out.status) != 0)
  310. {
  311. return -RT_ERROR;
  312. }
  313. rt_strncpy(name, (char *)name_out.name, sizeof(name_out.name));
  314. }
  315. return RT_EOK;
  316. }
  317. static rt_err_t scmi_pinctrl_probe(struct rt_scmi_device *sdev)
  318. {
  319. rt_err_t err;
  320. struct rt_scmi_msg msg;
  321. struct rt_device *dev = &sdev->parent;
  322. struct scmi_pinctrl_protocol_attributes protocol_attr_out;
  323. struct scmi_pinctrl *spctl = rt_calloc(1, sizeof(*spctl));
  324. if (!spctl)
  325. {
  326. return -RT_ENOMEM;
  327. }
  328. rt_memset(&protocol_attr_out, 0, sizeof(protocol_attr_out));
  329. msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &protocol_attr_out);
  330. if ((err = rt_scmi_process_msg(sdev, &msg)))
  331. {
  332. goto _fail;
  333. }
  334. if (rt_le32_to_cpu(protocol_attr_out.status) != 0)
  335. {
  336. err = -RT_ERROR;
  337. goto _fail;
  338. }
  339. spctl->pins_nr = SCMI_PINCTRL_PINS_NR(rt_le32_to_cpu(protocol_attr_out.attributes_low));
  340. spctl->groups_nr = SCMI_PINCTRL_GROUPS_NR(rt_le32_to_cpu(protocol_attr_out.attributes_low));
  341. spctl->function_nr = SCMI_PINCTRL_FUNCTIONS_NR(rt_le32_to_cpu(protocol_attr_out.attributes_high));
  342. spctl->pins = rt_malloc(sizeof(*spctl->pins) * spctl->pins_nr);
  343. spctl->groups = rt_malloc(sizeof(*spctl->groups) * spctl->groups_nr);
  344. spctl->function = rt_malloc(sizeof(*spctl->function) * spctl->function_nr);
  345. if (!spctl->pins || !spctl->groups || !spctl->function)
  346. {
  347. err = -RT_ENOMEM;
  348. goto _fail;
  349. }
  350. for (rt_size_t i = 0; i < spctl->pins_nr; ++i)
  351. {
  352. if (scmi_pinctrl_name_parse_one(sdev, SCMI_PINCTRL_TYPE_PIN, i, spctl->pins[i].name))
  353. {
  354. LOG_E("%s parse identifier = %d fail", "Pin", i);
  355. continue;
  356. }
  357. spctl->pins[i].identifier = i;
  358. }
  359. for (rt_size_t i = 0; i < spctl->groups_nr; ++i)
  360. {
  361. if (scmi_pinctrl_name_parse_one(sdev, SCMI_PINCTRL_TYPE_GROUP, i, spctl->groups[i].name))
  362. {
  363. LOG_E("%s parse identifier = %d fail", "Group", i);
  364. continue;
  365. }
  366. spctl->groups[i].identifier = i;
  367. }
  368. for (rt_size_t i = 0; i < spctl->function_nr; ++i)
  369. {
  370. if (scmi_pinctrl_name_parse_one(sdev, SCMI_PINCTRL_TYPE_FUNCTION, i, spctl->function[i].name))
  371. {
  372. LOG_E("%s parse identifier = %d fail", "Function", i);
  373. continue;
  374. }
  375. spctl->function[i].identifier = i;
  376. }
  377. spctl->parent.ops = &scmi_pinctrl_ops;
  378. spctl->sdev = sdev;
  379. rt_ofw_data(dev->ofw_node) = &spctl->parent;
  380. return RT_EOK;
  381. _fail:
  382. if (spctl->pins)
  383. {
  384. rt_free(spctl->pins);
  385. }
  386. if (spctl->groups)
  387. {
  388. rt_free(spctl->groups);
  389. }
  390. if (spctl->function)
  391. {
  392. rt_free(spctl->function);
  393. }
  394. rt_free(spctl);
  395. return err;
  396. }
  397. static const struct rt_scmi_device_id scmi_pinctrl_ids[] =
  398. {
  399. { SCMI_PROTOCOL_ID_PINCTRL, "pinctrl" },
  400. { /* sentinel */ },
  401. };
  402. static struct rt_scmi_driver scmi_pinctrl_driver =
  403. {
  404. .name = "pinctrl-scmi",
  405. .ids = scmi_pinctrl_ids,
  406. .probe = scmi_pinctrl_probe,
  407. };
  408. RT_SCMI_DRIVER_EXPORT(scmi_pinctrl_driver);