1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2020 Linaro Limited. 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <dm/device.h> 9 #include <errno.h> 10 #include <scmi_agent-uclass.h> 11 #include <scmi_protocols.h> 12 13 #include <dm/device-internal.h> 14 #include <linux/compat.h> 15 16 /** 17 * struct error_code - Helper structure for SCMI error code conversion 18 * @scmi: SCMI error code 19 * @errno: Related standard error number 20 */ 21 struct error_code { 22 int scmi; 23 int errno; 24 }; 25 26 static const struct error_code scmi_linux_errmap[] = { 27 { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, }, 28 { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, }, 29 { .scmi = SCMI_DENIED, .errno = -EACCES, }, 30 { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, }, 31 { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, }, 32 { .scmi = SCMI_BUSY, .errno = -EBUSY, }, 33 { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, }, 34 { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, }, 35 { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, }, 36 { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, }, 37 }; 38 39 int scmi_to_linux_errno(s32 scmi_code) 40 { 41 int n; 42 43 if (!scmi_code) 44 return 0; 45 46 for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++) 47 if (scmi_code == scmi_linux_errmap[n].scmi) 48 return scmi_linux_errmap[1].errno; 49 50 return -EPROTO; 51 } 52 53 /* 54 * SCMI agent devices binds devices of various uclasses depeding on 55 * the FDT description. scmi_bind_protocol() is a generic bind sequence 56 * called by the uclass at bind stage, that is uclass post_bind. 57 */ 58 static int scmi_bind_protocols(struct udevice *dev) 59 { 60 int ret = 0; 61 ofnode node; 62 63 dev_for_each_subnode(node, dev) { 64 struct driver *drv = NULL; 65 u32 protocol_id; 66 67 if (!ofnode_is_available(node)) 68 continue; 69 70 if (ofnode_read_u32(node, "reg", &protocol_id)) 71 continue; 72 73 switch (protocol_id) { 74 case SCMI_PROTOCOL_ID_CLOCK: 75 if (IS_ENABLED(CONFIG_CLK_SCMI)) 76 drv = DM_GET_DRIVER(scmi_clock); 77 break; 78 case SCMI_PROTOCOL_ID_RESET_DOMAIN: 79 if (IS_ENABLED(CONFIG_RESET_SCMI)) 80 drv = DM_GET_DRIVER(scmi_reset_domain); 81 break; 82 default: 83 break; 84 } 85 86 if (!drv) { 87 dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n", 88 protocol_id); 89 continue; 90 } 91 92 ret = device_bind_with_driver_data(dev, drv, 93 ofnode_get_name(node), 0, node, NULL); 94 if (ret) 95 break; 96 } 97 98 99 return ret; 100 } 101 102 static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev) 103 { 104 return (const struct scmi_agent_ops *)dev->driver->ops; 105 } 106 107 int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) 108 { 109 const struct scmi_agent_ops *ops = transport_dev_ops(dev); 110 111 if (ops->process_msg) 112 return ops->process_msg(dev, msg); 113 114 return -EPROTONOSUPPORT; 115 } 116 117 UCLASS_DRIVER(scmi_agent) = { 118 .id = UCLASS_SCMI_AGENT, 119 .name = "scmi_agent", 120 .post_bind = scmi_bind_protocols, 121 }; 122