1603aed8fSIlpo Järvinen // SPDX-License-Identifier: GPL-2.0 2603aed8fSIlpo Järvinen /* 3603aed8fSIlpo Järvinen * Intel MAX 10 Board Management Controller chip - common code 4603aed8fSIlpo Järvinen * 5603aed8fSIlpo Järvinen * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. 6603aed8fSIlpo Järvinen */ 7603aed8fSIlpo Järvinen 8603aed8fSIlpo Järvinen #include <linux/bitfield.h> 9603aed8fSIlpo Järvinen #include <linux/device.h> 10603aed8fSIlpo Järvinen #include <linux/dev_printk.h> 11603aed8fSIlpo Järvinen #include <linux/mfd/core.h> 12603aed8fSIlpo Järvinen #include <linux/mfd/intel-m10-bmc.h> 13603aed8fSIlpo Järvinen #include <linux/module.h> 14603aed8fSIlpo Järvinen 15*867cae44SIlpo Järvinen void m10bmc_fw_state_set(struct intel_m10bmc *m10bmc, enum m10bmc_fw_state new_state) 16*867cae44SIlpo Järvinen { 17*867cae44SIlpo Järvinen /* bmcfw_state is only needed if handshake_sys_reg_nranges > 0 */ 18*867cae44SIlpo Järvinen if (!m10bmc->info->handshake_sys_reg_nranges) 19*867cae44SIlpo Järvinen return; 20*867cae44SIlpo Järvinen 21*867cae44SIlpo Järvinen down_write(&m10bmc->bmcfw_lock); 22*867cae44SIlpo Järvinen m10bmc->bmcfw_state = new_state; 23*867cae44SIlpo Järvinen up_write(&m10bmc->bmcfw_lock); 24*867cae44SIlpo Järvinen } 25*867cae44SIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_fw_state_set, INTEL_M10_BMC_CORE); 26*867cae44SIlpo Järvinen 27*867cae44SIlpo Järvinen /* 28*867cae44SIlpo Järvinen * For some Intel FPGA devices, the BMC firmware is not available to service 29*867cae44SIlpo Järvinen * handshake registers during a secure update. 30*867cae44SIlpo Järvinen */ 31*867cae44SIlpo Järvinen static bool m10bmc_reg_always_available(struct intel_m10bmc *m10bmc, unsigned int offset) 32*867cae44SIlpo Järvinen { 33*867cae44SIlpo Järvinen if (!m10bmc->info->handshake_sys_reg_nranges) 34*867cae44SIlpo Järvinen return true; 35*867cae44SIlpo Järvinen 36*867cae44SIlpo Järvinen return !regmap_reg_in_ranges(offset, m10bmc->info->handshake_sys_reg_ranges, 37*867cae44SIlpo Järvinen m10bmc->info->handshake_sys_reg_nranges); 38*867cae44SIlpo Järvinen } 39*867cae44SIlpo Järvinen 40*867cae44SIlpo Järvinen /* 41*867cae44SIlpo Järvinen * m10bmc_handshake_reg_unavailable - Checks if reg access collides with secure update state 42*867cae44SIlpo Järvinen * @m10bmc: M10 BMC structure 43*867cae44SIlpo Järvinen * 44*867cae44SIlpo Järvinen * For some Intel FPGA devices, the BMC firmware is not available to service 45*867cae44SIlpo Järvinen * handshake registers during a secure update erase and write phases. 46*867cae44SIlpo Järvinen * 47*867cae44SIlpo Järvinen * Context: @m10bmc->bmcfw_lock must be held. 48*867cae44SIlpo Järvinen */ 49*867cae44SIlpo Järvinen static bool m10bmc_handshake_reg_unavailable(struct intel_m10bmc *m10bmc) 50*867cae44SIlpo Järvinen { 51*867cae44SIlpo Järvinen return m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_PREPARE || 52*867cae44SIlpo Järvinen m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_WRITE; 53*867cae44SIlpo Järvinen } 54*867cae44SIlpo Järvinen 55e9c154eeSIlpo Järvinen /* 56e9c154eeSIlpo Järvinen * This function helps to simplify the accessing of the system registers. 57e9c154eeSIlpo Järvinen * 58e9c154eeSIlpo Järvinen * The base of the system registers is configured through the struct 59e9c154eeSIlpo Järvinen * csr_map. 60e9c154eeSIlpo Järvinen */ 61e9c154eeSIlpo Järvinen int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned int *val) 62e9c154eeSIlpo Järvinen { 63e9c154eeSIlpo Järvinen const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map; 64*867cae44SIlpo Järvinen int ret; 65e9c154eeSIlpo Järvinen 66*867cae44SIlpo Järvinen if (m10bmc_reg_always_available(m10bmc, offset)) 67e9c154eeSIlpo Järvinen return m10bmc_raw_read(m10bmc, csr_map->base + offset, val); 68*867cae44SIlpo Järvinen 69*867cae44SIlpo Järvinen down_read(&m10bmc->bmcfw_lock); 70*867cae44SIlpo Järvinen if (m10bmc_handshake_reg_unavailable(m10bmc)) 71*867cae44SIlpo Järvinen ret = -EBUSY; /* Reg not available during secure update */ 72*867cae44SIlpo Järvinen else 73*867cae44SIlpo Järvinen ret = m10bmc_raw_read(m10bmc, csr_map->base + offset, val); 74*867cae44SIlpo Järvinen up_read(&m10bmc->bmcfw_lock); 75*867cae44SIlpo Järvinen 76*867cae44SIlpo Järvinen return ret; 77e9c154eeSIlpo Järvinen } 78e9c154eeSIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, INTEL_M10_BMC_CORE); 79e9c154eeSIlpo Järvinen 80c452e3bdSIlpo Järvinen int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset, 81c452e3bdSIlpo Järvinen unsigned int msk, unsigned int val) 82c452e3bdSIlpo Järvinen { 83c452e3bdSIlpo Järvinen const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map; 84*867cae44SIlpo Järvinen int ret; 85c452e3bdSIlpo Järvinen 86*867cae44SIlpo Järvinen if (m10bmc_reg_always_available(m10bmc, offset)) 87c452e3bdSIlpo Järvinen return regmap_update_bits(m10bmc->regmap, csr_map->base + offset, msk, val); 88*867cae44SIlpo Järvinen 89*867cae44SIlpo Järvinen down_read(&m10bmc->bmcfw_lock); 90*867cae44SIlpo Järvinen if (m10bmc_handshake_reg_unavailable(m10bmc)) 91*867cae44SIlpo Järvinen ret = -EBUSY; /* Reg not available during secure update */ 92*867cae44SIlpo Järvinen else 93*867cae44SIlpo Järvinen ret = regmap_update_bits(m10bmc->regmap, csr_map->base + offset, msk, val); 94*867cae44SIlpo Järvinen up_read(&m10bmc->bmcfw_lock); 95*867cae44SIlpo Järvinen 96*867cae44SIlpo Järvinen return ret; 97c452e3bdSIlpo Järvinen } 98c452e3bdSIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, INTEL_M10_BMC_CORE); 99c452e3bdSIlpo Järvinen 100603aed8fSIlpo Järvinen static ssize_t bmc_version_show(struct device *dev, 101603aed8fSIlpo Järvinen struct device_attribute *attr, char *buf) 102603aed8fSIlpo Järvinen { 103603aed8fSIlpo Järvinen struct intel_m10bmc *ddata = dev_get_drvdata(dev); 104603aed8fSIlpo Järvinen unsigned int val; 105603aed8fSIlpo Järvinen int ret; 106603aed8fSIlpo Järvinen 1076052a005SIlpo Järvinen ret = m10bmc_sys_read(ddata, ddata->info->csr_map->build_version, &val); 108603aed8fSIlpo Järvinen if (ret) 109603aed8fSIlpo Järvinen return ret; 110603aed8fSIlpo Järvinen 111603aed8fSIlpo Järvinen return sprintf(buf, "0x%x\n", val); 112603aed8fSIlpo Järvinen } 113603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(bmc_version); 114603aed8fSIlpo Järvinen 115603aed8fSIlpo Järvinen static ssize_t bmcfw_version_show(struct device *dev, 116603aed8fSIlpo Järvinen struct device_attribute *attr, char *buf) 117603aed8fSIlpo Järvinen { 118603aed8fSIlpo Järvinen struct intel_m10bmc *ddata = dev_get_drvdata(dev); 119603aed8fSIlpo Järvinen unsigned int val; 120603aed8fSIlpo Järvinen int ret; 121603aed8fSIlpo Järvinen 1226052a005SIlpo Järvinen ret = m10bmc_sys_read(ddata, ddata->info->csr_map->fw_version, &val); 123603aed8fSIlpo Järvinen if (ret) 124603aed8fSIlpo Järvinen return ret; 125603aed8fSIlpo Järvinen 126603aed8fSIlpo Järvinen return sprintf(buf, "0x%x\n", val); 127603aed8fSIlpo Järvinen } 128603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(bmcfw_version); 129603aed8fSIlpo Järvinen 130603aed8fSIlpo Järvinen static ssize_t mac_address_show(struct device *dev, 131603aed8fSIlpo Järvinen struct device_attribute *attr, char *buf) 132603aed8fSIlpo Järvinen { 133603aed8fSIlpo Järvinen struct intel_m10bmc *ddata = dev_get_drvdata(dev); 134603aed8fSIlpo Järvinen unsigned int macaddr_low, macaddr_high; 135603aed8fSIlpo Järvinen int ret; 136603aed8fSIlpo Järvinen 1376052a005SIlpo Järvinen ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_low, &macaddr_low); 138603aed8fSIlpo Järvinen if (ret) 139603aed8fSIlpo Järvinen return ret; 140603aed8fSIlpo Järvinen 1416052a005SIlpo Järvinen ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high); 142603aed8fSIlpo Järvinen if (ret) 143603aed8fSIlpo Järvinen return ret; 144603aed8fSIlpo Järvinen 145603aed8fSIlpo Järvinen return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", 146bcababfcSIlpo Järvinen (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE1, macaddr_low), 147bcababfcSIlpo Järvinen (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE2, macaddr_low), 148bcababfcSIlpo Järvinen (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE3, macaddr_low), 149bcababfcSIlpo Järvinen (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE4, macaddr_low), 150bcababfcSIlpo Järvinen (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE5, macaddr_high), 151bcababfcSIlpo Järvinen (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE6, macaddr_high)); 152603aed8fSIlpo Järvinen } 153603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(mac_address); 154603aed8fSIlpo Järvinen 155603aed8fSIlpo Järvinen static ssize_t mac_count_show(struct device *dev, 156603aed8fSIlpo Järvinen struct device_attribute *attr, char *buf) 157603aed8fSIlpo Järvinen { 158603aed8fSIlpo Järvinen struct intel_m10bmc *ddata = dev_get_drvdata(dev); 159603aed8fSIlpo Järvinen unsigned int macaddr_high; 160603aed8fSIlpo Järvinen int ret; 161603aed8fSIlpo Järvinen 1626052a005SIlpo Järvinen ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high); 163603aed8fSIlpo Järvinen if (ret) 164603aed8fSIlpo Järvinen return ret; 165603aed8fSIlpo Järvinen 166bcababfcSIlpo Järvinen return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_N3000_MAC_COUNT, macaddr_high)); 167603aed8fSIlpo Järvinen } 168603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(mac_count); 169603aed8fSIlpo Järvinen 170603aed8fSIlpo Järvinen static struct attribute *m10bmc_attrs[] = { 171603aed8fSIlpo Järvinen &dev_attr_bmc_version.attr, 172603aed8fSIlpo Järvinen &dev_attr_bmcfw_version.attr, 173603aed8fSIlpo Järvinen &dev_attr_mac_address.attr, 174603aed8fSIlpo Järvinen &dev_attr_mac_count.attr, 175603aed8fSIlpo Järvinen NULL, 176603aed8fSIlpo Järvinen }; 177603aed8fSIlpo Järvinen 178603aed8fSIlpo Järvinen static const struct attribute_group m10bmc_group = { 179603aed8fSIlpo Järvinen .attrs = m10bmc_attrs, 180603aed8fSIlpo Järvinen }; 181603aed8fSIlpo Järvinen 182603aed8fSIlpo Järvinen const struct attribute_group *m10bmc_dev_groups[] = { 183603aed8fSIlpo Järvinen &m10bmc_group, 184603aed8fSIlpo Järvinen NULL, 185603aed8fSIlpo Järvinen }; 186b3ecc7f3SIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, INTEL_M10_BMC_CORE); 187603aed8fSIlpo Järvinen 188603aed8fSIlpo Järvinen int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info) 189603aed8fSIlpo Järvinen { 190603aed8fSIlpo Järvinen int ret; 191603aed8fSIlpo Järvinen 192603aed8fSIlpo Järvinen m10bmc->info = info; 193603aed8fSIlpo Järvinen dev_set_drvdata(m10bmc->dev, m10bmc); 194*867cae44SIlpo Järvinen init_rwsem(&m10bmc->bmcfw_lock); 195603aed8fSIlpo Järvinen 196603aed8fSIlpo Järvinen ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO, 197603aed8fSIlpo Järvinen info->cells, info->n_cells, 198603aed8fSIlpo Järvinen NULL, 0, NULL); 199603aed8fSIlpo Järvinen if (ret) 200603aed8fSIlpo Järvinen dev_err(m10bmc->dev, "Failed to register sub-devices: %d\n", ret); 201603aed8fSIlpo Järvinen 202603aed8fSIlpo Järvinen return ret; 203603aed8fSIlpo Järvinen } 204b3ecc7f3SIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, INTEL_M10_BMC_CORE); 205603aed8fSIlpo Järvinen 206603aed8fSIlpo Järvinen MODULE_DESCRIPTION("Intel MAX 10 BMC core driver"); 207603aed8fSIlpo Järvinen MODULE_AUTHOR("Intel Corporation"); 208603aed8fSIlpo Järvinen MODULE_LICENSE("GPL v2"); 209