Commit | Line | Data |
---|---|---|
876611c4 XY |
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> | |
603aed8f | 8 | #include <linux/dev_printk.h> |
876611c4 XY |
9 | #include <linux/init.h> |
10 | #include <linux/mfd/core.h> | |
11 | #include <linux/mfd/intel-m10-bmc.h> | |
12 | #include <linux/module.h> | |
876611c4 XY |
13 | #include <linux/regmap.h> |
14 | #include <linux/spi/spi.h> | |
15 | ||
8169f74c | 16 | static const struct regmap_range m10bmc_regmap_range[] = { |
bcababfc IJ |
17 | regmap_reg_range(M10BMC_N3000_LEGACY_BUILD_VER, M10BMC_N3000_LEGACY_BUILD_VER), |
18 | regmap_reg_range(M10BMC_N3000_SYS_BASE, M10BMC_N3000_SYS_END), | |
19 | regmap_reg_range(M10BMC_N3000_FLASH_BASE, M10BMC_N3000_FLASH_END), | |
8169f74c MG |
20 | }; |
21 | ||
22 | static const struct regmap_access_table m10bmc_access_table = { | |
23 | .yes_ranges = m10bmc_regmap_range, | |
24 | .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range), | |
25 | }; | |
26 | ||
876611c4 XY |
27 | static struct regmap_config intel_m10bmc_regmap_config = { |
28 | .reg_bits = 32, | |
29 | .val_bits = 32, | |
30 | .reg_stride = 4, | |
8169f74c MG |
31 | .wr_table = &m10bmc_access_table, |
32 | .rd_table = &m10bmc_access_table, | |
bcababfc | 33 | .max_register = M10BMC_N3000_MEM_END, |
876611c4 XY |
34 | }; |
35 | ||
876611c4 XY |
36 | static int check_m10bmc_version(struct intel_m10bmc *ddata) |
37 | { | |
38 | unsigned int v; | |
39 | int ret; | |
40 | ||
41 | /* | |
5893f4d1 XY |
42 | * This check is to filter out the very old legacy BMC versions. In the |
43 | * old BMC chips, the BMC version info is stored in the old version | |
bcababfc IJ |
44 | * register (M10BMC_N3000_LEGACY_BUILD_VER), so its read out value would have |
45 | * not been M10BMC_N3000_VER_LEGACY_INVALID (0xffffffff). But in new BMC | |
5893f4d1 | 46 | * chips that the driver supports, the value of this register should be |
bcababfc | 47 | * M10BMC_N3000_VER_LEGACY_INVALID. |
876611c4 | 48 | */ |
bcababfc | 49 | ret = m10bmc_raw_read(ddata, M10BMC_N3000_LEGACY_BUILD_VER, &v); |
876611c4 XY |
50 | if (ret) |
51 | return -ENODEV; | |
52 | ||
bcababfc | 53 | if (v != M10BMC_N3000_VER_LEGACY_INVALID) { |
876611c4 XY |
54 | dev_err(ddata->dev, "bad version M10BMC detected\n"); |
55 | return -ENODEV; | |
56 | } | |
57 | ||
58 | return 0; | |
59 | } | |
60 | ||
61 | static int intel_m10_bmc_spi_probe(struct spi_device *spi) | |
62 | { | |
63 | const struct spi_device_id *id = spi_get_device_id(spi); | |
16e5d95a | 64 | const struct intel_m10bmc_platform_info *info; |
876611c4 | 65 | struct device *dev = &spi->dev; |
876611c4 | 66 | struct intel_m10bmc *ddata; |
16e5d95a | 67 | int ret; |
876611c4 XY |
68 | |
69 | ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); | |
70 | if (!ddata) | |
71 | return -ENOMEM; | |
72 | ||
16e5d95a | 73 | info = (struct intel_m10bmc_platform_info *)id->driver_data; |
876611c4 XY |
74 | ddata->dev = dev; |
75 | ||
603aed8f | 76 | ddata->regmap = devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config); |
876611c4 XY |
77 | if (IS_ERR(ddata->regmap)) { |
78 | ret = PTR_ERR(ddata->regmap); | |
79 | dev_err(dev, "Failed to allocate regmap: %d\n", ret); | |
80 | return ret; | |
81 | } | |
82 | ||
83 | spi_set_drvdata(spi, ddata); | |
84 | ||
85 | ret = check_m10bmc_version(ddata); | |
86 | if (ret) { | |
87 | dev_err(dev, "Failed to identify m10bmc hardware\n"); | |
88 | return ret; | |
89 | } | |
90 | ||
603aed8f | 91 | return m10bmc_dev_init(ddata, info); |
876611c4 XY |
92 | } |
93 | ||
6052a005 | 94 | static const struct m10bmc_csr_map m10bmc_n3000_csr_map = { |
bcababfc IJ |
95 | .base = M10BMC_N3000_SYS_BASE, |
96 | .build_version = M10BMC_N3000_BUILD_VER, | |
97 | .fw_version = NIOS2_N3000_FW_VERSION, | |
98 | .mac_low = M10BMC_N3000_MAC_LOW, | |
99 | .mac_high = M10BMC_N3000_MAC_HIGH, | |
100 | .doorbell = M10BMC_N3000_DOORBELL, | |
101 | .auth_result = M10BMC_N3000_AUTH_RESULT, | |
102 | .bmc_prog_addr = M10BMC_N3000_BMC_PROG_ADDR, | |
103 | .bmc_reh_addr = M10BMC_N3000_BMC_REH_ADDR, | |
104 | .bmc_magic = M10BMC_N3000_BMC_PROG_MAGIC, | |
105 | .sr_prog_addr = M10BMC_N3000_SR_PROG_ADDR, | |
106 | .sr_reh_addr = M10BMC_N3000_SR_REH_ADDR, | |
107 | .sr_magic = M10BMC_N3000_SR_PROG_MAGIC, | |
108 | .pr_prog_addr = M10BMC_N3000_PR_PROG_ADDR, | |
109 | .pr_reh_addr = M10BMC_N3000_PR_REH_ADDR, | |
110 | .pr_magic = M10BMC_N3000_PR_PROG_MAGIC, | |
111 | .rsu_update_counter = M10BMC_N3000_STAGING_FLASH_COUNT, | |
6052a005 IJ |
112 | }; |
113 | ||
603aed8f IJ |
114 | static struct mfd_cell m10bmc_d5005_subdevs[] = { |
115 | { .name = "d5005bmc-hwmon" }, | |
116 | { .name = "d5005bmc-sec-update" }, | |
117 | }; | |
118 | ||
119 | static struct mfd_cell m10bmc_pacn3000_subdevs[] = { | |
120 | { .name = "n3000bmc-hwmon" }, | |
121 | { .name = "n3000bmc-retimer" }, | |
122 | { .name = "n3000bmc-sec-update" }, | |
123 | }; | |
124 | ||
125 | static struct mfd_cell m10bmc_n5010_subdevs[] = { | |
126 | { .name = "n5010bmc-hwmon" }, | |
127 | }; | |
128 | ||
16e5d95a IJ |
129 | static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { |
130 | .cells = m10bmc_pacn3000_subdevs, | |
131 | .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs), | |
6052a005 | 132 | .csr_map = &m10bmc_n3000_csr_map, |
16e5d95a IJ |
133 | }; |
134 | ||
135 | static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = { | |
136 | .cells = m10bmc_d5005_subdevs, | |
137 | .n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs), | |
6052a005 | 138 | .csr_map = &m10bmc_n3000_csr_map, |
16e5d95a IJ |
139 | }; |
140 | ||
141 | static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = { | |
142 | .cells = m10bmc_n5010_subdevs, | |
143 | .n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs), | |
6052a005 | 144 | .csr_map = &m10bmc_n3000_csr_map, |
16e5d95a IJ |
145 | }; |
146 | ||
876611c4 | 147 | static const struct spi_device_id m10bmc_spi_id[] = { |
16e5d95a IJ |
148 | { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 }, |
149 | { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 }, | |
150 | { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 }, | |
876611c4 XY |
151 | { } |
152 | }; | |
153 | MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); | |
154 | ||
155 | static struct spi_driver intel_m10bmc_spi_driver = { | |
156 | .driver = { | |
157 | .name = "intel-m10-bmc", | |
603aed8f | 158 | .dev_groups = m10bmc_dev_groups, |
876611c4 XY |
159 | }, |
160 | .probe = intel_m10_bmc_spi_probe, | |
161 | .id_table = m10bmc_spi_id, | |
162 | }; | |
163 | module_spi_driver(intel_m10bmc_spi_driver); | |
164 | ||
603aed8f | 165 | MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface"); |
876611c4 XY |
166 | MODULE_AUTHOR("Intel Corporation"); |
167 | MODULE_LICENSE("GPL v2"); | |
168 | MODULE_ALIAS("spi:intel-m10-bmc"); |