xref: /linux/drivers/mfd/intel-m10-bmc-core.c (revision cdd30ebb1b9f36159d66f088b61aee264e649d7a)
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 
m10bmc_fw_state_set(struct intel_m10bmc * m10bmc,enum m10bmc_fw_state new_state)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  */
m10bmc_reg_always_available(struct intel_m10bmc * m10bmc,unsigned int offset)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  */
m10bmc_handshake_reg_unavailable(struct intel_m10bmc * m10bmc)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  */
m10bmc_sys_read(struct intel_m10bmc * m10bmc,unsigned int offset,unsigned int * val)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 
m10bmc_sys_update_bits(struct intel_m10bmc * m10bmc,unsigned int offset,unsigned int msk,unsigned int val)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 
bmc_version_show(struct device * dev,struct device_attribute * attr,char * buf)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 
bmcfw_version_show(struct device * dev,struct device_attribute * attr,char * buf)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 
mac_address_show(struct device * dev,struct device_attribute * attr,char * buf)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 
mac_count_show(struct device * dev,struct device_attribute * attr,char * buf)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 
m10bmc_dev_init(struct intel_m10bmc * m10bmc,const struct intel_m10bmc_platform_info * info)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