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