1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel MAX 10 Board Management Controller chip - common code 4 * 5 * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. 6 */ 7 8 #include <linux/bitfield.h> 9 #include <linux/device.h> 10 #include <linux/dev_printk.h> 11 #include <linux/mfd/core.h> 12 #include <linux/mfd/intel-m10-bmc.h> 13 #include <linux/module.h> 14 15 void m10bmc_fw_state_set(struct intel_m10bmc *m10bmc, enum m10bmc_fw_state new_state) 16 { 17 /* bmcfw_state is only needed if handshake_sys_reg_nranges > 0 */ 18 if (!m10bmc->info->handshake_sys_reg_nranges) 19 return; 20 21 down_write(&m10bmc->bmcfw_lock); 22 m10bmc->bmcfw_state = new_state; 23 up_write(&m10bmc->bmcfw_lock); 24 } 25 EXPORT_SYMBOL_NS_GPL(m10bmc_fw_state_set, INTEL_M10_BMC_CORE); 26 27 /* 28 * For some Intel FPGA devices, the BMC firmware is not available to service 29 * handshake registers during a secure update. 30 */ 31 static bool m10bmc_reg_always_available(struct intel_m10bmc *m10bmc, unsigned int offset) 32 { 33 if (!m10bmc->info->handshake_sys_reg_nranges) 34 return true; 35 36 return !regmap_reg_in_ranges(offset, m10bmc->info->handshake_sys_reg_ranges, 37 m10bmc->info->handshake_sys_reg_nranges); 38 } 39 40 /* 41 * m10bmc_handshake_reg_unavailable - Checks if reg access collides with secure update state 42 * @m10bmc: M10 BMC structure 43 * 44 * For some Intel FPGA devices, the BMC firmware is not available to service 45 * handshake registers during a secure update erase and write phases. 46 * 47 * Context: @m10bmc->bmcfw_lock must be held. 48 */ 49 static bool m10bmc_handshake_reg_unavailable(struct intel_m10bmc *m10bmc) 50 { 51 return m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_PREPARE || 52 m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_WRITE; 53 } 54 55 /* 56 * This function helps to simplify the accessing of the system registers. 57 * 58 * The base of the system registers is configured through the struct 59 * csr_map. 60 */ 61 int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned int *val) 62 { 63 const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map; 64 int ret; 65 66 if (m10bmc_reg_always_available(m10bmc, offset)) 67 return m10bmc_raw_read(m10bmc, csr_map->base + offset, val); 68 69 down_read(&m10bmc->bmcfw_lock); 70 if (m10bmc_handshake_reg_unavailable(m10bmc)) 71 ret = -EBUSY; /* Reg not available during secure update */ 72 else 73 ret = m10bmc_raw_read(m10bmc, csr_map->base + offset, val); 74 up_read(&m10bmc->bmcfw_lock); 75 76 return ret; 77 } 78 EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, INTEL_M10_BMC_CORE); 79 80 int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset, 81 unsigned int msk, unsigned int val) 82 { 83 const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map; 84 int ret; 85 86 if (m10bmc_reg_always_available(m10bmc, offset)) 87 return regmap_update_bits(m10bmc->regmap, csr_map->base + offset, msk, val); 88 89 down_read(&m10bmc->bmcfw_lock); 90 if (m10bmc_handshake_reg_unavailable(m10bmc)) 91 ret = -EBUSY; /* Reg not available during secure update */ 92 else 93 ret = regmap_update_bits(m10bmc->regmap, csr_map->base + offset, msk, val); 94 up_read(&m10bmc->bmcfw_lock); 95 96 return ret; 97 } 98 EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, INTEL_M10_BMC_CORE); 99 100 static ssize_t bmc_version_show(struct device *dev, 101 struct device_attribute *attr, char *buf) 102 { 103 struct intel_m10bmc *ddata = dev_get_drvdata(dev); 104 unsigned int val; 105 int ret; 106 107 ret = m10bmc_sys_read(ddata, ddata->info->csr_map->build_version, &val); 108 if (ret) 109 return ret; 110 111 return sprintf(buf, "0x%x\n", val); 112 } 113 static DEVICE_ATTR_RO(bmc_version); 114 115 static ssize_t bmcfw_version_show(struct device *dev, 116 struct device_attribute *attr, char *buf) 117 { 118 struct intel_m10bmc *ddata = dev_get_drvdata(dev); 119 unsigned int val; 120 int ret; 121 122 ret = m10bmc_sys_read(ddata, ddata->info->csr_map->fw_version, &val); 123 if (ret) 124 return ret; 125 126 return sprintf(buf, "0x%x\n", val); 127 } 128 static DEVICE_ATTR_RO(bmcfw_version); 129 130 static ssize_t mac_address_show(struct device *dev, 131 struct device_attribute *attr, char *buf) 132 { 133 struct intel_m10bmc *ddata = dev_get_drvdata(dev); 134 unsigned int macaddr_low, macaddr_high; 135 int ret; 136 137 ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_low, &macaddr_low); 138 if (ret) 139 return ret; 140 141 ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high); 142 if (ret) 143 return ret; 144 145 return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", 146 (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE1, macaddr_low), 147 (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE2, macaddr_low), 148 (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE3, macaddr_low), 149 (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE4, macaddr_low), 150 (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE5, macaddr_high), 151 (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE6, macaddr_high)); 152 } 153 static DEVICE_ATTR_RO(mac_address); 154 155 static ssize_t mac_count_show(struct device *dev, 156 struct device_attribute *attr, char *buf) 157 { 158 struct intel_m10bmc *ddata = dev_get_drvdata(dev); 159 unsigned int macaddr_high; 160 int ret; 161 162 ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high); 163 if (ret) 164 return ret; 165 166 return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_N3000_MAC_COUNT, macaddr_high)); 167 } 168 static DEVICE_ATTR_RO(mac_count); 169 170 static struct attribute *m10bmc_attrs[] = { 171 &dev_attr_bmc_version.attr, 172 &dev_attr_bmcfw_version.attr, 173 &dev_attr_mac_address.attr, 174 &dev_attr_mac_count.attr, 175 NULL, 176 }; 177 178 static const struct attribute_group m10bmc_group = { 179 .attrs = m10bmc_attrs, 180 }; 181 182 const struct attribute_group *m10bmc_dev_groups[] = { 183 &m10bmc_group, 184 NULL, 185 }; 186 EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, INTEL_M10_BMC_CORE); 187 188 int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info) 189 { 190 int ret; 191 192 m10bmc->info = info; 193 dev_set_drvdata(m10bmc->dev, m10bmc); 194 init_rwsem(&m10bmc->bmcfw_lock); 195 196 ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO, 197 info->cells, info->n_cells, 198 NULL, 0, NULL); 199 if (ret) 200 dev_err(m10bmc->dev, "Failed to register sub-devices: %d\n", ret); 201 202 return ret; 203 } 204 EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, INTEL_M10_BMC_CORE); 205 206 MODULE_DESCRIPTION("Intel MAX 10 BMC core driver"); 207 MODULE_AUTHOR("Intel Corporation"); 208 MODULE_LICENSE("GPL v2"); 209