1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MAX10 BMC Platform Management Component Interface (PMCI) based
4  * interface.
5  *
6  * Copyright (C) 2020-2023 Intel Corporation.
7  */
8 
9 #include <linux/bitfield.h>
10 #include <linux/device.h>
11 #include <linux/dfl.h>
12 #include <linux/mfd/core.h>
13 #include <linux/mfd/intel-m10-bmc.h>
14 #include <linux/minmax.h>
15 #include <linux/module.h>
16 #include <linux/regmap.h>
17 
18 struct m10bmc_pmci_device {
19 	void __iomem *base;
20 	struct intel_m10bmc m10bmc;
21 	struct mutex flash_mutex;	/* protects flash_busy and serializes flash read/read */
22 	bool flash_busy;
23 };
24 
25 /*
26  * Intel FGPA indirect register access via hardware controller/bridge.
27  */
28 #define INDIRECT_CMD_OFF	0
29 #define INDIRECT_CMD_CLR	0
30 #define INDIRECT_CMD_RD		BIT(0)
31 #define INDIRECT_CMD_WR		BIT(1)
32 #define INDIRECT_CMD_ACK	BIT(2)
33 
34 #define INDIRECT_ADDR_OFF	0x4
35 #define INDIRECT_RD_OFF		0x8
36 #define INDIRECT_WR_OFF		0xc
37 
38 #define INDIRECT_INT_US		1
39 #define INDIRECT_TIMEOUT_US	10000
40 
41 struct indirect_ctx {
42 	void __iomem *base;
43 	struct device *dev;
44 };
45 
indirect_clear_cmd(struct indirect_ctx * ctx)46 static int indirect_clear_cmd(struct indirect_ctx *ctx)
47 {
48 	unsigned int cmd;
49 	int ret;
50 
51 	writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF);
52 
53 	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd,
54 				 cmd == INDIRECT_CMD_CLR,
55 				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
56 	if (ret)
57 		dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd);
58 
59 	return ret;
60 }
61 
indirect_reg_read(void * context,unsigned int reg,unsigned int * val)62 static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val)
63 {
64 	struct indirect_ctx *ctx = context;
65 	unsigned int cmd, ack, tmpval;
66 	int ret, ret2;
67 
68 	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
69 	if (cmd != INDIRECT_CMD_CLR)
70 		dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd);
71 
72 	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
73 	writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF);
74 
75 	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
76 				 (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
77 				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
78 	if (ret)
79 		dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack);
80 	else
81 		tmpval = readl(ctx->base + INDIRECT_RD_OFF);
82 
83 	ret2 = indirect_clear_cmd(ctx);
84 
85 	if (ret)
86 		return ret;
87 	if (ret2)
88 		return ret2;
89 
90 	*val = tmpval;
91 	return 0;
92 }
93 
indirect_reg_write(void * context,unsigned int reg,unsigned int val)94 static int indirect_reg_write(void *context, unsigned int reg, unsigned int val)
95 {
96 	struct indirect_ctx *ctx = context;
97 	unsigned int cmd, ack;
98 	int ret, ret2;
99 
100 	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
101 	if (cmd != INDIRECT_CMD_CLR)
102 		dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd);
103 
104 	writel(val, ctx->base + INDIRECT_WR_OFF);
105 	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
106 	writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF);
107 
108 	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
109 				 (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
110 				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
111 	if (ret)
112 		dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack);
113 
114 	ret2 = indirect_clear_cmd(ctx);
115 
116 	if (ret)
117 		return ret;
118 	return ret2;
119 }
120 
pmci_write_fifo(void __iomem * base,const u32 * buf,size_t count)121 static void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count)
122 {
123 	while (count--)
124 		writel(*buf++, base);
125 }
126 
pmci_read_fifo(void __iomem * base,u32 * buf,size_t count)127 static void pmci_read_fifo(void __iomem *base, u32 *buf, size_t count)
128 {
129 	while (count--)
130 		*buf++ = readl(base);
131 }
132 
pmci_get_write_space(struct m10bmc_pmci_device * pmci)133 static u32 pmci_get_write_space(struct m10bmc_pmci_device *pmci)
134 {
135 	u32 val;
136 	int ret;
137 
138 	ret = read_poll_timeout(readl, val,
139 				FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) ==
140 				M10BMC_N6000_FIFO_MAX_WORDS,
141 				M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US,
142 				false, pmci->base + M10BMC_N6000_FLASH_CTRL);
143 	if (ret == -ETIMEDOUT)
144 		return 0;
145 
146 	return FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) * M10BMC_N6000_FIFO_WORD_SIZE;
147 }
148 
pmci_flash_bulk_write(struct intel_m10bmc * m10bmc,const u8 * buf,u32 size)149 static int pmci_flash_bulk_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 size)
150 {
151 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
152 	u32 blk_size, offset = 0, write_count;
153 
154 	while (size) {
155 		blk_size = min(pmci_get_write_space(pmci), size);
156 		if (blk_size == 0) {
157 			dev_err(m10bmc->dev, "get FIFO available size fail\n");
158 			return -EIO;
159 		}
160 
161 		if (size < M10BMC_N6000_FIFO_WORD_SIZE)
162 			break;
163 
164 		write_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
165 		pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
166 				(u32 *)(buf + offset), write_count);
167 
168 		size -= blk_size;
169 		offset += blk_size;
170 	}
171 
172 	/* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
173 	if (size) {
174 		u32 tmp = 0;
175 
176 		memcpy(&tmp, buf + offset, size);
177 		pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
178 	}
179 
180 	return 0;
181 }
182 
pmci_flash_bulk_read(struct intel_m10bmc * m10bmc,u8 * buf,u32 addr,u32 size)183 static int pmci_flash_bulk_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
184 {
185 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
186 	u32 blk_size, offset = 0, val, full_read_count, read_count;
187 	int ret;
188 
189 	while (size) {
190 		blk_size = min_t(u32, size, M10BMC_N6000_READ_BLOCK_SIZE);
191 		full_read_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
192 
193 		read_count = full_read_count;
194 		if (full_read_count * M10BMC_N6000_FIFO_WORD_SIZE < blk_size)
195 			read_count++;
196 
197 		writel(addr + offset, pmci->base + M10BMC_N6000_FLASH_ADDR);
198 		writel(FIELD_PREP(M10BMC_N6000_FLASH_READ_COUNT, read_count) |
199 		       M10BMC_N6000_FLASH_RD_MODE,
200 		       pmci->base + M10BMC_N6000_FLASH_CTRL);
201 
202 		ret = readl_poll_timeout((pmci->base + M10BMC_N6000_FLASH_CTRL), val,
203 					 !(val & M10BMC_N6000_FLASH_BUSY),
204 					 M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
205 		if (ret) {
206 			dev_err(m10bmc->dev, "read timed out on reading flash 0x%xn", val);
207 			return ret;
208 		}
209 
210 		pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
211 			       (u32 *)(buf + offset), full_read_count);
212 
213 		size -= blk_size;
214 		offset += blk_size;
215 
216 		if (full_read_count < read_count)
217 			break;
218 
219 		writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
220 	}
221 
222 	/* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
223 	if (size) {
224 		u32 tmp;
225 
226 		pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
227 		memcpy(buf + offset, &tmp, size);
228 
229 		writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
230 	}
231 
232 	return 0;
233 }
234 
m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc * m10bmc,bool request)235 static int m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc *m10bmc, bool request)
236 {
237 	u32 ctrl;
238 	int ret;
239 
240 	ret = regmap_update_bits(m10bmc->regmap, M10BMC_N6000_FLASH_MUX_CTRL,
241 				 M10BMC_N6000_FLASH_HOST_REQUEST,
242 				 FIELD_PREP(M10BMC_N6000_FLASH_HOST_REQUEST, request));
243 	if (ret)
244 		return ret;
245 
246 	return regmap_read_poll_timeout(m10bmc->regmap,
247 					M10BMC_N6000_FLASH_MUX_CTRL, ctrl,
248 					request ?
249 					(get_flash_mux(ctrl) == M10BMC_N6000_FLASH_MUX_HOST) :
250 					(get_flash_mux(ctrl) != M10BMC_N6000_FLASH_MUX_HOST),
251 					M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
252 }
253 
m10bmc_pmci_flash_read(struct intel_m10bmc * m10bmc,u8 * buf,u32 addr,u32 size)254 static int m10bmc_pmci_flash_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
255 {
256 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
257 	int ret, ret2;
258 
259 	mutex_lock(&pmci->flash_mutex);
260 	if (pmci->flash_busy) {
261 		ret = -EBUSY;
262 		goto unlock;
263 	}
264 
265 	ret = m10bmc_pmci_set_flash_host_mux(m10bmc, true);
266 	if (ret)
267 		goto mux_fail;
268 
269 	ret = pmci_flash_bulk_read(m10bmc, buf, addr, size);
270 
271 mux_fail:
272 	ret2 = m10bmc_pmci_set_flash_host_mux(m10bmc, false);
273 
274 unlock:
275 	mutex_unlock(&pmci->flash_mutex);
276 	if (ret)
277 		return ret;
278 	return ret2;
279 }
280 
m10bmc_pmci_flash_write(struct intel_m10bmc * m10bmc,const u8 * buf,u32 offset,u32 size)281 static int m10bmc_pmci_flash_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 offset, u32 size)
282 {
283 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
284 	int ret;
285 
286 	mutex_lock(&pmci->flash_mutex);
287 	WARN_ON_ONCE(!pmci->flash_busy);
288 	/* On write, firmware manages flash MUX */
289 	ret = pmci_flash_bulk_write(m10bmc, buf + offset, size);
290 	mutex_unlock(&pmci->flash_mutex);
291 
292 	return ret;
293 }
294 
m10bmc_pmci_flash_lock(struct intel_m10bmc * m10bmc)295 static int m10bmc_pmci_flash_lock(struct intel_m10bmc *m10bmc)
296 {
297 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
298 	int ret = 0;
299 
300 	mutex_lock(&pmci->flash_mutex);
301 	if (pmci->flash_busy) {
302 		ret = -EBUSY;
303 		goto unlock;
304 	}
305 
306 	pmci->flash_busy = true;
307 
308 unlock:
309 	mutex_unlock(&pmci->flash_mutex);
310 	return ret;
311 }
312 
m10bmc_pmci_flash_unlock(struct intel_m10bmc * m10bmc)313 static void m10bmc_pmci_flash_unlock(struct intel_m10bmc *m10bmc)
314 {
315 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
316 
317 	mutex_lock(&pmci->flash_mutex);
318 	WARN_ON_ONCE(!pmci->flash_busy);
319 	pmci->flash_busy = false;
320 	mutex_unlock(&pmci->flash_mutex);
321 }
322 
323 static const struct intel_m10bmc_flash_bulk_ops m10bmc_pmci_flash_bulk_ops = {
324 	.read = m10bmc_pmci_flash_read,
325 	.write = m10bmc_pmci_flash_write,
326 	.lock_write = m10bmc_pmci_flash_lock,
327 	.unlock_write = m10bmc_pmci_flash_unlock,
328 };
329 
330 static const struct regmap_range m10bmc_pmci_regmap_range[] = {
331 	regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END),
332 };
333 
334 static const struct regmap_access_table m10bmc_pmci_access_table = {
335 	.yes_ranges	= m10bmc_pmci_regmap_range,
336 	.n_yes_ranges	= ARRAY_SIZE(m10bmc_pmci_regmap_range),
337 };
338 
339 static struct regmap_config m10bmc_pmci_regmap_config = {
340 	.reg_bits = 32,
341 	.reg_stride = 4,
342 	.val_bits = 32,
343 	.wr_table = &m10bmc_pmci_access_table,
344 	.rd_table = &m10bmc_pmci_access_table,
345 	.reg_read = &indirect_reg_read,
346 	.reg_write = &indirect_reg_write,
347 	.max_register = M10BMC_N6000_SYS_END,
348 };
349 
350 static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = {
351 	{ .name = "n6000bmc-hwmon" },
352 	{ .name = "n6000bmc-sec-update" },
353 };
354 
355 static const struct m10bmc_csr_map m10bmc_n6000_csr_map = {
356 	.base = M10BMC_N6000_SYS_BASE,
357 	.build_version = M10BMC_N6000_BUILD_VER,
358 	.fw_version = NIOS2_N6000_FW_VERSION,
359 	.mac_low = M10BMC_N6000_MAC_LOW,
360 	.mac_high = M10BMC_N6000_MAC_HIGH,
361 	.doorbell = M10BMC_N6000_DOORBELL,
362 	.auth_result = M10BMC_N6000_AUTH_RESULT,
363 	.bmc_prog_addr = M10BMC_N6000_BMC_PROG_ADDR,
364 	.bmc_reh_addr = M10BMC_N6000_BMC_REH_ADDR,
365 	.bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC,
366 	.sr_prog_addr = M10BMC_N6000_SR_PROG_ADDR,
367 	.sr_reh_addr = M10BMC_N6000_SR_REH_ADDR,
368 	.sr_magic = M10BMC_N6000_SR_PROG_MAGIC,
369 	.pr_prog_addr = M10BMC_N6000_PR_PROG_ADDR,
370 	.pr_reh_addr = M10BMC_N6000_PR_REH_ADDR,
371 	.pr_magic = M10BMC_N6000_PR_PROG_MAGIC,
372 	.rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT,
373 };
374 
375 static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = {
376 	.cells = m10bmc_pmci_n6000_bmc_subdevs,
377 	.n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs),
378 	.csr_map = &m10bmc_n6000_csr_map,
379 };
380 
m10bmc_pmci_probe(struct dfl_device * ddev)381 static int m10bmc_pmci_probe(struct dfl_device *ddev)
382 {
383 	struct device *dev = &ddev->dev;
384 	struct m10bmc_pmci_device *pmci;
385 	struct indirect_ctx *ctx;
386 	int ret;
387 
388 	pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL);
389 	if (!pmci)
390 		return -ENOMEM;
391 
392 	pmci->m10bmc.flash_bulk_ops = &m10bmc_pmci_flash_bulk_ops;
393 	pmci->m10bmc.dev = dev;
394 
395 	pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res);
396 	if (IS_ERR(pmci->base))
397 		return PTR_ERR(pmci->base);
398 
399 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
400 	if (!ctx)
401 		return -ENOMEM;
402 
403 	mutex_init(&pmci->flash_mutex);
404 
405 	ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE;
406 	ctx->dev = dev;
407 	indirect_clear_cmd(ctx);
408 	pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config);
409 
410 	if (IS_ERR(pmci->m10bmc.regmap)) {
411 		ret = PTR_ERR(pmci->m10bmc.regmap);
412 		goto destroy_mutex;
413 	}
414 
415 	ret = m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000);
416 	if (ret)
417 		goto destroy_mutex;
418 	return 0;
419 
420 destroy_mutex:
421 	mutex_destroy(&pmci->flash_mutex);
422 	return ret;
423 }
424 
m10bmc_pmci_remove(struct dfl_device * ddev)425 static void m10bmc_pmci_remove(struct dfl_device *ddev)
426 {
427 	struct intel_m10bmc *m10bmc = dev_get_drvdata(&ddev->dev);
428 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
429 
430 	mutex_destroy(&pmci->flash_mutex);
431 }
432 
433 #define FME_FEATURE_ID_M10BMC_PMCI	0x12
434 
435 static const struct dfl_device_id m10bmc_pmci_ids[] = {
436 	{ FME_ID, FME_FEATURE_ID_M10BMC_PMCI },
437 	{ }
438 };
439 MODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids);
440 
441 static struct dfl_driver m10bmc_pmci_driver = {
442 	.drv	= {
443 		.name       = "intel-m10-bmc",
444 		.dev_groups = m10bmc_dev_groups,
445 	},
446 	.id_table = m10bmc_pmci_ids,
447 	.probe    = m10bmc_pmci_probe,
448 	.remove   = m10bmc_pmci_remove,
449 };
450 
451 module_dfl_driver(m10bmc_pmci_driver);
452 
453 MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface");
454 MODULE_AUTHOR("Intel Corporation");
455 MODULE_LICENSE("GPL");
456 MODULE_IMPORT_NS(INTEL_M10_BMC_CORE);
457