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*e9c154eeSIlpo Järvinen /*
16*e9c154eeSIlpo Järvinen  * This function helps to simplify the accessing of the system registers.
17*e9c154eeSIlpo Järvinen  *
18*e9c154eeSIlpo Järvinen  * The base of the system registers is configured through the struct
19*e9c154eeSIlpo Järvinen  * csr_map.
20*e9c154eeSIlpo Järvinen  */
21*e9c154eeSIlpo Järvinen int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned int *val)
22*e9c154eeSIlpo Järvinen {
23*e9c154eeSIlpo Järvinen 	const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map;
24*e9c154eeSIlpo Järvinen 
25*e9c154eeSIlpo Järvinen 	return m10bmc_raw_read(m10bmc, csr_map->base + offset, val);
26*e9c154eeSIlpo Järvinen }
27*e9c154eeSIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, INTEL_M10_BMC_CORE);
28*e9c154eeSIlpo Järvinen 
29c452e3bdSIlpo Järvinen int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset,
30c452e3bdSIlpo Järvinen 			   unsigned int msk, unsigned int val)
31c452e3bdSIlpo Järvinen {
32c452e3bdSIlpo Järvinen 	const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map;
33c452e3bdSIlpo Järvinen 
34c452e3bdSIlpo Järvinen 	return regmap_update_bits(m10bmc->regmap, csr_map->base + offset, msk, val);
35c452e3bdSIlpo Järvinen }
36c452e3bdSIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, INTEL_M10_BMC_CORE);
37c452e3bdSIlpo Järvinen 
38603aed8fSIlpo Järvinen static ssize_t bmc_version_show(struct device *dev,
39603aed8fSIlpo Järvinen 				struct device_attribute *attr, char *buf)
40603aed8fSIlpo Järvinen {
41603aed8fSIlpo Järvinen 	struct intel_m10bmc *ddata = dev_get_drvdata(dev);
42603aed8fSIlpo Järvinen 	unsigned int val;
43603aed8fSIlpo Järvinen 	int ret;
44603aed8fSIlpo Järvinen 
456052a005SIlpo Järvinen 	ret = m10bmc_sys_read(ddata, ddata->info->csr_map->build_version, &val);
46603aed8fSIlpo Järvinen 	if (ret)
47603aed8fSIlpo Järvinen 		return ret;
48603aed8fSIlpo Järvinen 
49603aed8fSIlpo Järvinen 	return sprintf(buf, "0x%x\n", val);
50603aed8fSIlpo Järvinen }
51603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(bmc_version);
52603aed8fSIlpo Järvinen 
53603aed8fSIlpo Järvinen static ssize_t bmcfw_version_show(struct device *dev,
54603aed8fSIlpo Järvinen 				  struct device_attribute *attr, char *buf)
55603aed8fSIlpo Järvinen {
56603aed8fSIlpo Järvinen 	struct intel_m10bmc *ddata = dev_get_drvdata(dev);
57603aed8fSIlpo Järvinen 	unsigned int val;
58603aed8fSIlpo Järvinen 	int ret;
59603aed8fSIlpo Järvinen 
606052a005SIlpo Järvinen 	ret = m10bmc_sys_read(ddata, ddata->info->csr_map->fw_version, &val);
61603aed8fSIlpo Järvinen 	if (ret)
62603aed8fSIlpo Järvinen 		return ret;
63603aed8fSIlpo Järvinen 
64603aed8fSIlpo Järvinen 	return sprintf(buf, "0x%x\n", val);
65603aed8fSIlpo Järvinen }
66603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(bmcfw_version);
67603aed8fSIlpo Järvinen 
68603aed8fSIlpo Järvinen static ssize_t mac_address_show(struct device *dev,
69603aed8fSIlpo Järvinen 				struct device_attribute *attr, char *buf)
70603aed8fSIlpo Järvinen {
71603aed8fSIlpo Järvinen 	struct intel_m10bmc *ddata = dev_get_drvdata(dev);
72603aed8fSIlpo Järvinen 	unsigned int macaddr_low, macaddr_high;
73603aed8fSIlpo Järvinen 	int ret;
74603aed8fSIlpo Järvinen 
756052a005SIlpo Järvinen 	ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_low, &macaddr_low);
76603aed8fSIlpo Järvinen 	if (ret)
77603aed8fSIlpo Järvinen 		return ret;
78603aed8fSIlpo Järvinen 
796052a005SIlpo Järvinen 	ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
80603aed8fSIlpo Järvinen 	if (ret)
81603aed8fSIlpo Järvinen 		return ret;
82603aed8fSIlpo Järvinen 
83603aed8fSIlpo Järvinen 	return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
84bcababfcSIlpo Järvinen 			  (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE1, macaddr_low),
85bcababfcSIlpo Järvinen 			  (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE2, macaddr_low),
86bcababfcSIlpo Järvinen 			  (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE3, macaddr_low),
87bcababfcSIlpo Järvinen 			  (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE4, macaddr_low),
88bcababfcSIlpo Järvinen 			  (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE5, macaddr_high),
89bcababfcSIlpo Järvinen 			  (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE6, macaddr_high));
90603aed8fSIlpo Järvinen }
91603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(mac_address);
92603aed8fSIlpo Järvinen 
93603aed8fSIlpo Järvinen static ssize_t mac_count_show(struct device *dev,
94603aed8fSIlpo Järvinen 			      struct device_attribute *attr, char *buf)
95603aed8fSIlpo Järvinen {
96603aed8fSIlpo Järvinen 	struct intel_m10bmc *ddata = dev_get_drvdata(dev);
97603aed8fSIlpo Järvinen 	unsigned int macaddr_high;
98603aed8fSIlpo Järvinen 	int ret;
99603aed8fSIlpo Järvinen 
1006052a005SIlpo Järvinen 	ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
101603aed8fSIlpo Järvinen 	if (ret)
102603aed8fSIlpo Järvinen 		return ret;
103603aed8fSIlpo Järvinen 
104bcababfcSIlpo Järvinen 	return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_N3000_MAC_COUNT, macaddr_high));
105603aed8fSIlpo Järvinen }
106603aed8fSIlpo Järvinen static DEVICE_ATTR_RO(mac_count);
107603aed8fSIlpo Järvinen 
108603aed8fSIlpo Järvinen static struct attribute *m10bmc_attrs[] = {
109603aed8fSIlpo Järvinen 	&dev_attr_bmc_version.attr,
110603aed8fSIlpo Järvinen 	&dev_attr_bmcfw_version.attr,
111603aed8fSIlpo Järvinen 	&dev_attr_mac_address.attr,
112603aed8fSIlpo Järvinen 	&dev_attr_mac_count.attr,
113603aed8fSIlpo Järvinen 	NULL,
114603aed8fSIlpo Järvinen };
115603aed8fSIlpo Järvinen 
116603aed8fSIlpo Järvinen static const struct attribute_group m10bmc_group = {
117603aed8fSIlpo Järvinen 	.attrs = m10bmc_attrs,
118603aed8fSIlpo Järvinen };
119603aed8fSIlpo Järvinen 
120603aed8fSIlpo Järvinen const struct attribute_group *m10bmc_dev_groups[] = {
121603aed8fSIlpo Järvinen 	&m10bmc_group,
122603aed8fSIlpo Järvinen 	NULL,
123603aed8fSIlpo Järvinen };
124b3ecc7f3SIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, INTEL_M10_BMC_CORE);
125603aed8fSIlpo Järvinen 
126603aed8fSIlpo Järvinen int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info)
127603aed8fSIlpo Järvinen {
128603aed8fSIlpo Järvinen 	int ret;
129603aed8fSIlpo Järvinen 
130603aed8fSIlpo Järvinen 	m10bmc->info = info;
131603aed8fSIlpo Järvinen 	dev_set_drvdata(m10bmc->dev, m10bmc);
132603aed8fSIlpo Järvinen 
133603aed8fSIlpo Järvinen 	ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO,
134603aed8fSIlpo Järvinen 				   info->cells, info->n_cells,
135603aed8fSIlpo Järvinen 				   NULL, 0, NULL);
136603aed8fSIlpo Järvinen 	if (ret)
137603aed8fSIlpo Järvinen 		dev_err(m10bmc->dev, "Failed to register sub-devices: %d\n", ret);
138603aed8fSIlpo Järvinen 
139603aed8fSIlpo Järvinen 	return ret;
140603aed8fSIlpo Järvinen }
141b3ecc7f3SIlpo Järvinen EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, INTEL_M10_BMC_CORE);
142603aed8fSIlpo Järvinen 
143603aed8fSIlpo Järvinen MODULE_DESCRIPTION("Intel MAX 10 BMC core driver");
144603aed8fSIlpo Järvinen MODULE_AUTHOR("Intel Corporation");
145603aed8fSIlpo Järvinen MODULE_LICENSE("GPL v2");
146