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