Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
  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
 15void 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}
 25EXPORT_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 */
 31static 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 */
 49static 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 */
 61int 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}
 78EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, INTEL_M10_BMC_CORE);
 79
 80int 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}
 98EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, INTEL_M10_BMC_CORE);
 99
100static 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}
113static DEVICE_ATTR_RO(bmc_version);
114
115static 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}
128static DEVICE_ATTR_RO(bmcfw_version);
129
130static 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}
153static DEVICE_ATTR_RO(mac_address);
154
155static 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}
168static DEVICE_ATTR_RO(mac_count);
169
170static 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
178static const struct attribute_group m10bmc_group = {
179	.attrs = m10bmc_attrs,
180};
181
182const struct attribute_group *m10bmc_dev_groups[] = {
183	&m10bmc_group,
184	NULL,
185};
186EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, INTEL_M10_BMC_CORE);
187
188int 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}
204EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, INTEL_M10_BMC_CORE);
205
206MODULE_DESCRIPTION("Intel MAX 10 BMC core driver");
207MODULE_AUTHOR("Intel Corporation");
208MODULE_LICENSE("GPL v2");
1