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 
m10bmc_fw_state_set(struct intel_m10bmc * m10bmc,enum m10bmc_fw_state new_state)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  */
m10bmc_reg_always_available(struct intel_m10bmc * m10bmc,unsigned int offset)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  */
m10bmc_handshake_reg_unavailable(struct intel_m10bmc * m10bmc)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  */
m10bmc_sys_read(struct intel_m10bmc * m10bmc,unsigned int offset,unsigned int * val)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 
m10bmc_sys_update_bits(struct intel_m10bmc * m10bmc,unsigned int offset,unsigned int msk,unsigned int val)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 
bmc_version_show(struct device * dev,struct device_attribute * attr,char * buf)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 
bmcfw_version_show(struct device * dev,struct device_attribute * attr,char * buf)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 
mac_address_show(struct device * dev,struct device_attribute * attr,char * buf)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 
mac_count_show(struct device * dev,struct device_attribute * attr,char * buf)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 
m10bmc_dev_init(struct intel_m10bmc * m10bmc,const struct intel_m10bmc_platform_info * info)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