Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.2-rc8 238 lines 6.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Intel MAX 10 Board Management Controller chip 4 * 5 * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. 6 */ 7#include <linux/bitfield.h> 8#include <linux/init.h> 9#include <linux/mfd/core.h> 10#include <linux/mfd/intel-m10-bmc.h> 11#include <linux/module.h> 12#include <linux/mutex.h> 13#include <linux/regmap.h> 14#include <linux/spi/spi.h> 15 16enum m10bmc_type { 17 M10_N3000, 18 M10_D5005, 19 M10_N5010, 20}; 21 22static struct mfd_cell m10bmc_d5005_subdevs[] = { 23 { .name = "d5005bmc-hwmon" }, 24 { .name = "d5005bmc-sec-update" } 25}; 26 27static struct mfd_cell m10bmc_pacn3000_subdevs[] = { 28 { .name = "n3000bmc-hwmon" }, 29 { .name = "n3000bmc-retimer" }, 30 { .name = "n3000bmc-sec-update" }, 31}; 32 33static struct mfd_cell m10bmc_n5010_subdevs[] = { 34 { .name = "n5010bmc-hwmon" }, 35}; 36 37static const struct regmap_range m10bmc_regmap_range[] = { 38 regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER), 39 regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END), 40 regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END), 41}; 42 43static const struct regmap_access_table m10bmc_access_table = { 44 .yes_ranges = m10bmc_regmap_range, 45 .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range), 46}; 47 48static struct regmap_config intel_m10bmc_regmap_config = { 49 .reg_bits = 32, 50 .val_bits = 32, 51 .reg_stride = 4, 52 .wr_table = &m10bmc_access_table, 53 .rd_table = &m10bmc_access_table, 54 .max_register = M10BMC_MEM_END, 55}; 56 57static ssize_t bmc_version_show(struct device *dev, 58 struct device_attribute *attr, char *buf) 59{ 60 struct intel_m10bmc *ddata = dev_get_drvdata(dev); 61 unsigned int val; 62 int ret; 63 64 ret = m10bmc_sys_read(ddata, M10BMC_BUILD_VER, &val); 65 if (ret) 66 return ret; 67 68 return sprintf(buf, "0x%x\n", val); 69} 70static DEVICE_ATTR_RO(bmc_version); 71 72static ssize_t bmcfw_version_show(struct device *dev, 73 struct device_attribute *attr, char *buf) 74{ 75 struct intel_m10bmc *ddata = dev_get_drvdata(dev); 76 unsigned int val; 77 int ret; 78 79 ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val); 80 if (ret) 81 return ret; 82 83 return sprintf(buf, "0x%x\n", val); 84} 85static DEVICE_ATTR_RO(bmcfw_version); 86 87static ssize_t mac_address_show(struct device *dev, 88 struct device_attribute *attr, char *buf) 89{ 90 struct intel_m10bmc *max10 = dev_get_drvdata(dev); 91 unsigned int macaddr_low, macaddr_high; 92 int ret; 93 94 ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low); 95 if (ret) 96 return ret; 97 98 ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high); 99 if (ret) 100 return ret; 101 102 return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", 103 (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low), 104 (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low), 105 (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low), 106 (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low), 107 (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high), 108 (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high)); 109} 110static DEVICE_ATTR_RO(mac_address); 111 112static ssize_t mac_count_show(struct device *dev, 113 struct device_attribute *attr, char *buf) 114{ 115 struct intel_m10bmc *max10 = dev_get_drvdata(dev); 116 unsigned int macaddr_high; 117 int ret; 118 119 ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high); 120 if (ret) 121 return ret; 122 123 return sysfs_emit(buf, "%u\n", 124 (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high)); 125} 126static DEVICE_ATTR_RO(mac_count); 127 128static struct attribute *m10bmc_attrs[] = { 129 &dev_attr_bmc_version.attr, 130 &dev_attr_bmcfw_version.attr, 131 &dev_attr_mac_address.attr, 132 &dev_attr_mac_count.attr, 133 NULL, 134}; 135ATTRIBUTE_GROUPS(m10bmc); 136 137static int check_m10bmc_version(struct intel_m10bmc *ddata) 138{ 139 unsigned int v; 140 int ret; 141 142 /* 143 * This check is to filter out the very old legacy BMC versions. In the 144 * old BMC chips, the BMC version info is stored in the old version 145 * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have 146 * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC 147 * chips that the driver supports, the value of this register should be 148 * M10BMC_VER_LEGACY_INVALID. 149 */ 150 ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v); 151 if (ret) 152 return -ENODEV; 153 154 if (v != M10BMC_VER_LEGACY_INVALID) { 155 dev_err(ddata->dev, "bad version M10BMC detected\n"); 156 return -ENODEV; 157 } 158 159 return 0; 160} 161 162static int intel_m10_bmc_spi_probe(struct spi_device *spi) 163{ 164 const struct spi_device_id *id = spi_get_device_id(spi); 165 struct device *dev = &spi->dev; 166 struct mfd_cell *cells; 167 struct intel_m10bmc *ddata; 168 int ret, n_cell; 169 170 ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); 171 if (!ddata) 172 return -ENOMEM; 173 174 ddata->dev = dev; 175 176 ddata->regmap = 177 devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config); 178 if (IS_ERR(ddata->regmap)) { 179 ret = PTR_ERR(ddata->regmap); 180 dev_err(dev, "Failed to allocate regmap: %d\n", ret); 181 return ret; 182 } 183 184 spi_set_drvdata(spi, ddata); 185 186 ret = check_m10bmc_version(ddata); 187 if (ret) { 188 dev_err(dev, "Failed to identify m10bmc hardware\n"); 189 return ret; 190 } 191 192 switch (id->driver_data) { 193 case M10_N3000: 194 cells = m10bmc_pacn3000_subdevs; 195 n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs); 196 break; 197 case M10_D5005: 198 cells = m10bmc_d5005_subdevs; 199 n_cell = ARRAY_SIZE(m10bmc_d5005_subdevs); 200 break; 201 case M10_N5010: 202 cells = m10bmc_n5010_subdevs; 203 n_cell = ARRAY_SIZE(m10bmc_n5010_subdevs); 204 break; 205 default: 206 return -ENODEV; 207 } 208 209 ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cell, 210 NULL, 0, NULL); 211 if (ret) 212 dev_err(dev, "Failed to register sub-devices: %d\n", ret); 213 214 return ret; 215} 216 217static const struct spi_device_id m10bmc_spi_id[] = { 218 { "m10-n3000", M10_N3000 }, 219 { "m10-d5005", M10_D5005 }, 220 { "m10-n5010", M10_N5010 }, 221 { } 222}; 223MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); 224 225static struct spi_driver intel_m10bmc_spi_driver = { 226 .driver = { 227 .name = "intel-m10-bmc", 228 .dev_groups = m10bmc_groups, 229 }, 230 .probe = intel_m10_bmc_spi_probe, 231 .id_table = m10bmc_spi_id, 232}; 233module_spi_driver(intel_m10bmc_spi_driver); 234 235MODULE_DESCRIPTION("Intel MAX 10 BMC Device Driver"); 236MODULE_AUTHOR("Intel Corporation"); 237MODULE_LICENSE("GPL v2"); 238MODULE_ALIAS("spi:intel-m10-bmc");