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
18struct 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
41struct indirect_ctx {
42	void __iomem *base;
43	struct device *dev;
44};
45
46static 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
62static 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
94static 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
121static void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count)
122{
123	while (count--)
124		writel(*buf++, base);
125}
126
127static void pmci_read_fifo(void __iomem *base, u32 *buf, size_t count)
128{
129	while (count--)
130		*buf++ = readl(base);
131}
132
133static 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
149static 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
183static 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
235static 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
254static 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
271mux_fail:
272	ret2 = m10bmc_pmci_set_flash_host_mux(m10bmc, false);
273
274unlock:
275	mutex_unlock(&pmci->flash_mutex);
276	if (ret)
277		return ret;
278	return ret2;
279}
280
281static 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
295static 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
308unlock:
309	mutex_unlock(&pmci->flash_mutex);
310	return ret;
311}
312
313static 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
323static 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
330static const struct regmap_range m10bmc_pmci_regmap_range[] = {
331	regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END),
332};
333
334static 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
339static 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
350static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = {
351	{ .name = "n6000bmc-hwmon" },
352	{ .name = "n6000bmc-sec-update" },
353};
354
355static 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
375static 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
381static 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
420destroy_mutex:
421	mutex_destroy(&pmci->flash_mutex);
422	return ret;
423}
424
425static 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
435static const struct dfl_device_id m10bmc_pmci_ids[] = {
436	{ FME_ID, FME_FEATURE_ID_M10BMC_PMCI },
437	{ }
438};
439MODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids);
440
441static 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
451module_dfl_driver(m10bmc_pmci_driver);
452
453MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface");
454MODULE_AUTHOR("Intel Corporation");
455MODULE_LICENSE("GPL");
456MODULE_IMPORT_NS(INTEL_M10_BMC_CORE);
457