1869b9eddSIlpo Järvinen // SPDX-License-Identifier: GPL-2.0
2869b9eddSIlpo Järvinen /*
3869b9eddSIlpo Järvinen  * MAX10 BMC Platform Management Component Interface (PMCI) based
4869b9eddSIlpo Järvinen  * interface.
5869b9eddSIlpo Järvinen  *
6869b9eddSIlpo Järvinen  * Copyright (C) 2020-2023 Intel Corporation.
7869b9eddSIlpo Järvinen  */
8869b9eddSIlpo Järvinen 
9acf63c45SIlpo Järvinen #include <linux/bitfield.h>
10869b9eddSIlpo Järvinen #include <linux/device.h>
11869b9eddSIlpo Järvinen #include <linux/dfl.h>
12869b9eddSIlpo Järvinen #include <linux/mfd/core.h>
13869b9eddSIlpo Järvinen #include <linux/mfd/intel-m10-bmc.h>
14acf63c45SIlpo Järvinen #include <linux/minmax.h>
15869b9eddSIlpo Järvinen #include <linux/module.h>
16869b9eddSIlpo Järvinen #include <linux/regmap.h>
17869b9eddSIlpo Järvinen 
18869b9eddSIlpo Järvinen struct m10bmc_pmci_device {
19869b9eddSIlpo Järvinen 	void __iomem *base;
20869b9eddSIlpo Järvinen 	struct intel_m10bmc m10bmc;
21acf63c45SIlpo Järvinen 	struct mutex flash_mutex;	/* protects flash_busy and serializes flash read/read */
22acf63c45SIlpo Järvinen 	bool flash_busy;
23869b9eddSIlpo Järvinen };
24869b9eddSIlpo Järvinen 
25869b9eddSIlpo Järvinen /*
26869b9eddSIlpo Järvinen  * Intel FGPA indirect register access via hardware controller/bridge.
27869b9eddSIlpo Järvinen  */
28869b9eddSIlpo Järvinen #define INDIRECT_CMD_OFF	0
29869b9eddSIlpo Järvinen #define INDIRECT_CMD_CLR	0
30869b9eddSIlpo Järvinen #define INDIRECT_CMD_RD		BIT(0)
31869b9eddSIlpo Järvinen #define INDIRECT_CMD_WR		BIT(1)
32869b9eddSIlpo Järvinen #define INDIRECT_CMD_ACK	BIT(2)
33869b9eddSIlpo Järvinen 
34869b9eddSIlpo Järvinen #define INDIRECT_ADDR_OFF	0x4
35869b9eddSIlpo Järvinen #define INDIRECT_RD_OFF		0x8
36869b9eddSIlpo Järvinen #define INDIRECT_WR_OFF		0xc
37869b9eddSIlpo Järvinen 
38869b9eddSIlpo Järvinen #define INDIRECT_INT_US		1
39869b9eddSIlpo Järvinen #define INDIRECT_TIMEOUT_US	10000
40869b9eddSIlpo Järvinen 
41869b9eddSIlpo Järvinen struct indirect_ctx {
42869b9eddSIlpo Järvinen 	void __iomem *base;
43869b9eddSIlpo Järvinen 	struct device *dev;
44869b9eddSIlpo Järvinen };
45869b9eddSIlpo Järvinen 
indirect_clear_cmd(struct indirect_ctx * ctx)46869b9eddSIlpo Järvinen static int indirect_clear_cmd(struct indirect_ctx *ctx)
47869b9eddSIlpo Järvinen {
48869b9eddSIlpo Järvinen 	unsigned int cmd;
49869b9eddSIlpo Järvinen 	int ret;
50869b9eddSIlpo Järvinen 
51869b9eddSIlpo Järvinen 	writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF);
52869b9eddSIlpo Järvinen 
53869b9eddSIlpo Järvinen 	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd,
54869b9eddSIlpo Järvinen 				 cmd == INDIRECT_CMD_CLR,
55869b9eddSIlpo Järvinen 				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
56869b9eddSIlpo Järvinen 	if (ret)
57869b9eddSIlpo Järvinen 		dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd);
58869b9eddSIlpo Järvinen 
59869b9eddSIlpo Järvinen 	return ret;
60869b9eddSIlpo Järvinen }
61869b9eddSIlpo Järvinen 
indirect_reg_read(void * context,unsigned int reg,unsigned int * val)62869b9eddSIlpo Järvinen static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val)
63869b9eddSIlpo Järvinen {
64869b9eddSIlpo Järvinen 	struct indirect_ctx *ctx = context;
65869b9eddSIlpo Järvinen 	unsigned int cmd, ack, tmpval;
66869b9eddSIlpo Järvinen 	int ret, ret2;
67869b9eddSIlpo Järvinen 
68869b9eddSIlpo Järvinen 	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
69869b9eddSIlpo Järvinen 	if (cmd != INDIRECT_CMD_CLR)
70869b9eddSIlpo Järvinen 		dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd);
71869b9eddSIlpo Järvinen 
72869b9eddSIlpo Järvinen 	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
73869b9eddSIlpo Järvinen 	writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF);
74869b9eddSIlpo Järvinen 
75869b9eddSIlpo Järvinen 	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
76869b9eddSIlpo Järvinen 				 (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
77869b9eddSIlpo Järvinen 				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
78869b9eddSIlpo Järvinen 	if (ret)
79869b9eddSIlpo Järvinen 		dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack);
80869b9eddSIlpo Järvinen 	else
81869b9eddSIlpo Järvinen 		tmpval = readl(ctx->base + INDIRECT_RD_OFF);
82869b9eddSIlpo Järvinen 
83869b9eddSIlpo Järvinen 	ret2 = indirect_clear_cmd(ctx);
84869b9eddSIlpo Järvinen 
85869b9eddSIlpo Järvinen 	if (ret)
86869b9eddSIlpo Järvinen 		return ret;
87869b9eddSIlpo Järvinen 	if (ret2)
88869b9eddSIlpo Järvinen 		return ret2;
89869b9eddSIlpo Järvinen 
90869b9eddSIlpo Järvinen 	*val = tmpval;
91869b9eddSIlpo Järvinen 	return 0;
92869b9eddSIlpo Järvinen }
93869b9eddSIlpo Järvinen 
indirect_reg_write(void * context,unsigned int reg,unsigned int val)94869b9eddSIlpo Järvinen static int indirect_reg_write(void *context, unsigned int reg, unsigned int val)
95869b9eddSIlpo Järvinen {
96869b9eddSIlpo Järvinen 	struct indirect_ctx *ctx = context;
97869b9eddSIlpo Järvinen 	unsigned int cmd, ack;
98869b9eddSIlpo Järvinen 	int ret, ret2;
99869b9eddSIlpo Järvinen 
100869b9eddSIlpo Järvinen 	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
101869b9eddSIlpo Järvinen 	if (cmd != INDIRECT_CMD_CLR)
102869b9eddSIlpo Järvinen 		dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd);
103869b9eddSIlpo Järvinen 
104869b9eddSIlpo Järvinen 	writel(val, ctx->base + INDIRECT_WR_OFF);
105869b9eddSIlpo Järvinen 	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
106869b9eddSIlpo Järvinen 	writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF);
107869b9eddSIlpo Järvinen 
108869b9eddSIlpo Järvinen 	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
109869b9eddSIlpo Järvinen 				 (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
110869b9eddSIlpo Järvinen 				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
111869b9eddSIlpo Järvinen 	if (ret)
112869b9eddSIlpo Järvinen 		dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack);
113869b9eddSIlpo Järvinen 
114869b9eddSIlpo Järvinen 	ret2 = indirect_clear_cmd(ctx);
115869b9eddSIlpo Järvinen 
116869b9eddSIlpo Järvinen 	if (ret)
117869b9eddSIlpo Järvinen 		return ret;
118869b9eddSIlpo Järvinen 	return ret2;
119869b9eddSIlpo Järvinen }
120869b9eddSIlpo Järvinen 
pmci_write_fifo(void __iomem * base,const u32 * buf,size_t count)121acf63c45SIlpo Järvinen static void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count)
122acf63c45SIlpo Järvinen {
123acf63c45SIlpo Järvinen 	while (count--)
124acf63c45SIlpo Järvinen 		writel(*buf++, base);
125acf63c45SIlpo Järvinen }
126acf63c45SIlpo Järvinen 
pmci_read_fifo(void __iomem * base,u32 * buf,size_t count)127acf63c45SIlpo Järvinen static void pmci_read_fifo(void __iomem *base, u32 *buf, size_t count)
128acf63c45SIlpo Järvinen {
129acf63c45SIlpo Järvinen 	while (count--)
130acf63c45SIlpo Järvinen 		*buf++ = readl(base);
131acf63c45SIlpo Järvinen }
132acf63c45SIlpo Järvinen 
pmci_get_write_space(struct m10bmc_pmci_device * pmci)133acf63c45SIlpo Järvinen static u32 pmci_get_write_space(struct m10bmc_pmci_device *pmci)
134acf63c45SIlpo Järvinen {
135acf63c45SIlpo Järvinen 	u32 val;
136acf63c45SIlpo Järvinen 	int ret;
137acf63c45SIlpo Järvinen 
138acf63c45SIlpo Järvinen 	ret = read_poll_timeout(readl, val,
139acf63c45SIlpo Järvinen 				FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) ==
140acf63c45SIlpo Järvinen 				M10BMC_N6000_FIFO_MAX_WORDS,
141acf63c45SIlpo Järvinen 				M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US,
142acf63c45SIlpo Järvinen 				false, pmci->base + M10BMC_N6000_FLASH_CTRL);
143acf63c45SIlpo Järvinen 	if (ret == -ETIMEDOUT)
144acf63c45SIlpo Järvinen 		return 0;
145acf63c45SIlpo Järvinen 
146acf63c45SIlpo Järvinen 	return FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) * M10BMC_N6000_FIFO_WORD_SIZE;
147acf63c45SIlpo Järvinen }
148acf63c45SIlpo Järvinen 
pmci_flash_bulk_write(struct intel_m10bmc * m10bmc,const u8 * buf,u32 size)149acf63c45SIlpo Järvinen static int pmci_flash_bulk_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 size)
150acf63c45SIlpo Järvinen {
151acf63c45SIlpo Järvinen 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
152acf63c45SIlpo Järvinen 	u32 blk_size, offset = 0, write_count;
153acf63c45SIlpo Järvinen 
154acf63c45SIlpo Järvinen 	while (size) {
155acf63c45SIlpo Järvinen 		blk_size = min(pmci_get_write_space(pmci), size);
156acf63c45SIlpo Järvinen 		if (blk_size == 0) {
157acf63c45SIlpo Järvinen 			dev_err(m10bmc->dev, "get FIFO available size fail\n");
158acf63c45SIlpo Järvinen 			return -EIO;
159acf63c45SIlpo Järvinen 		}
160acf63c45SIlpo Järvinen 
161acf63c45SIlpo Järvinen 		if (size < M10BMC_N6000_FIFO_WORD_SIZE)
162acf63c45SIlpo Järvinen 			break;
163acf63c45SIlpo Järvinen 
164acf63c45SIlpo Järvinen 		write_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
165acf63c45SIlpo Järvinen 		pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
166acf63c45SIlpo Järvinen 				(u32 *)(buf + offset), write_count);
167acf63c45SIlpo Järvinen 
168acf63c45SIlpo Järvinen 		size -= blk_size;
169acf63c45SIlpo Järvinen 		offset += blk_size;
170acf63c45SIlpo Järvinen 	}
171acf63c45SIlpo Järvinen 
172acf63c45SIlpo Järvinen 	/* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
173acf63c45SIlpo Järvinen 	if (size) {
174acf63c45SIlpo Järvinen 		u32 tmp = 0;
175acf63c45SIlpo Järvinen 
176acf63c45SIlpo Järvinen 		memcpy(&tmp, buf + offset, size);
177acf63c45SIlpo Järvinen 		pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
178acf63c45SIlpo Järvinen 	}
179acf63c45SIlpo Järvinen 
180acf63c45SIlpo Järvinen 	return 0;
181acf63c45SIlpo Järvinen }
182acf63c45SIlpo Järvinen 
pmci_flash_bulk_read(struct intel_m10bmc * m10bmc,u8 * buf,u32 addr,u32 size)183acf63c45SIlpo Järvinen static int pmci_flash_bulk_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
184acf63c45SIlpo Järvinen {
185acf63c45SIlpo Järvinen 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
186acf63c45SIlpo Järvinen 	u32 blk_size, offset = 0, val, full_read_count, read_count;
187acf63c45SIlpo Järvinen 	int ret;
188acf63c45SIlpo Järvinen 
189acf63c45SIlpo Järvinen 	while (size) {
190acf63c45SIlpo Järvinen 		blk_size = min_t(u32, size, M10BMC_N6000_READ_BLOCK_SIZE);
191acf63c45SIlpo Järvinen 		full_read_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
192acf63c45SIlpo Järvinen 
193acf63c45SIlpo Järvinen 		read_count = full_read_count;
194acf63c45SIlpo Järvinen 		if (full_read_count * M10BMC_N6000_FIFO_WORD_SIZE < blk_size)
195acf63c45SIlpo Järvinen 			read_count++;
196acf63c45SIlpo Järvinen 
197acf63c45SIlpo Järvinen 		writel(addr + offset, pmci->base + M10BMC_N6000_FLASH_ADDR);
198acf63c45SIlpo Järvinen 		writel(FIELD_PREP(M10BMC_N6000_FLASH_READ_COUNT, read_count) |
199acf63c45SIlpo Järvinen 		       M10BMC_N6000_FLASH_RD_MODE,
200acf63c45SIlpo Järvinen 		       pmci->base + M10BMC_N6000_FLASH_CTRL);
201acf63c45SIlpo Järvinen 
202acf63c45SIlpo Järvinen 		ret = readl_poll_timeout((pmci->base + M10BMC_N6000_FLASH_CTRL), val,
203acf63c45SIlpo Järvinen 					 !(val & M10BMC_N6000_FLASH_BUSY),
204acf63c45SIlpo Järvinen 					 M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
205acf63c45SIlpo Järvinen 		if (ret) {
206acf63c45SIlpo Järvinen 			dev_err(m10bmc->dev, "read timed out on reading flash 0x%xn", val);
207acf63c45SIlpo Järvinen 			return ret;
208acf63c45SIlpo Järvinen 		}
209acf63c45SIlpo Järvinen 
210acf63c45SIlpo Järvinen 		pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
211acf63c45SIlpo Järvinen 			       (u32 *)(buf + offset), full_read_count);
212acf63c45SIlpo Järvinen 
213acf63c45SIlpo Järvinen 		size -= blk_size;
214acf63c45SIlpo Järvinen 		offset += blk_size;
215acf63c45SIlpo Järvinen 
216acf63c45SIlpo Järvinen 		if (full_read_count < read_count)
217acf63c45SIlpo Järvinen 			break;
218acf63c45SIlpo Järvinen 
219acf63c45SIlpo Järvinen 		writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
220acf63c45SIlpo Järvinen 	}
221acf63c45SIlpo Järvinen 
222acf63c45SIlpo Järvinen 	/* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
223acf63c45SIlpo Järvinen 	if (size) {
224acf63c45SIlpo Järvinen 		u32 tmp;
225acf63c45SIlpo Järvinen 
226acf63c45SIlpo Järvinen 		pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
227acf63c45SIlpo Järvinen 		memcpy(buf + offset, &tmp, size);
228acf63c45SIlpo Järvinen 
229acf63c45SIlpo Järvinen 		writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
230acf63c45SIlpo Järvinen 	}
231acf63c45SIlpo Järvinen 
232acf63c45SIlpo Järvinen 	return 0;
233acf63c45SIlpo Järvinen }
234acf63c45SIlpo Järvinen 
m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc * m10bmc,bool request)235acf63c45SIlpo Järvinen static int m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc *m10bmc, bool request)
236acf63c45SIlpo Järvinen {
237acf63c45SIlpo Järvinen 	u32 ctrl;
238acf63c45SIlpo Järvinen 	int ret;
239acf63c45SIlpo Järvinen 
240acf63c45SIlpo Järvinen 	ret = regmap_update_bits(m10bmc->regmap, M10BMC_N6000_FLASH_MUX_CTRL,
241acf63c45SIlpo Järvinen 				 M10BMC_N6000_FLASH_HOST_REQUEST,
242acf63c45SIlpo Järvinen 				 FIELD_PREP(M10BMC_N6000_FLASH_HOST_REQUEST, request));
243acf63c45SIlpo Järvinen 	if (ret)
244acf63c45SIlpo Järvinen 		return ret;
245acf63c45SIlpo Järvinen 
246acf63c45SIlpo Järvinen 	return regmap_read_poll_timeout(m10bmc->regmap,
247acf63c45SIlpo Järvinen 					M10BMC_N6000_FLASH_MUX_CTRL, ctrl,
248acf63c45SIlpo Järvinen 					request ?
249acf63c45SIlpo Järvinen 					(get_flash_mux(ctrl) == M10BMC_N6000_FLASH_MUX_HOST) :
250acf63c45SIlpo Järvinen 					(get_flash_mux(ctrl) != M10BMC_N6000_FLASH_MUX_HOST),
251acf63c45SIlpo Järvinen 					M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
252acf63c45SIlpo Järvinen }
253acf63c45SIlpo Järvinen 
m10bmc_pmci_flash_read(struct intel_m10bmc * m10bmc,u8 * buf,u32 addr,u32 size)254acf63c45SIlpo Järvinen static int m10bmc_pmci_flash_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
255acf63c45SIlpo Järvinen {
256acf63c45SIlpo Järvinen 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
257acf63c45SIlpo Järvinen 	int ret, ret2;
258acf63c45SIlpo Järvinen 
259acf63c45SIlpo Järvinen 	mutex_lock(&pmci->flash_mutex);
260acf63c45SIlpo Järvinen 	if (pmci->flash_busy) {
261acf63c45SIlpo Järvinen 		ret = -EBUSY;
262acf63c45SIlpo Järvinen 		goto unlock;
263acf63c45SIlpo Järvinen 	}
264acf63c45SIlpo Järvinen 
265acf63c45SIlpo Järvinen 	ret = m10bmc_pmci_set_flash_host_mux(m10bmc, true);
266acf63c45SIlpo Järvinen 	if (ret)
267acf63c45SIlpo Järvinen 		goto mux_fail;
268acf63c45SIlpo Järvinen 
269acf63c45SIlpo Järvinen 	ret = pmci_flash_bulk_read(m10bmc, buf, addr, size);
270acf63c45SIlpo Järvinen 
271acf63c45SIlpo Järvinen mux_fail:
272acf63c45SIlpo Järvinen 	ret2 = m10bmc_pmci_set_flash_host_mux(m10bmc, false);
273acf63c45SIlpo Järvinen 
274acf63c45SIlpo Järvinen unlock:
275acf63c45SIlpo Järvinen 	mutex_unlock(&pmci->flash_mutex);
276acf63c45SIlpo Järvinen 	if (ret)
277acf63c45SIlpo Järvinen 		return ret;
278acf63c45SIlpo Järvinen 	return ret2;
279acf63c45SIlpo Järvinen }
280acf63c45SIlpo Järvinen 
m10bmc_pmci_flash_write(struct intel_m10bmc * m10bmc,const u8 * buf,u32 offset,u32 size)281acf63c45SIlpo Järvinen static int m10bmc_pmci_flash_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 offset, u32 size)
282acf63c45SIlpo Järvinen {
283acf63c45SIlpo Järvinen 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
284acf63c45SIlpo Järvinen 	int ret;
285acf63c45SIlpo Järvinen 
286acf63c45SIlpo Järvinen 	mutex_lock(&pmci->flash_mutex);
287acf63c45SIlpo Järvinen 	WARN_ON_ONCE(!pmci->flash_busy);
288acf63c45SIlpo Järvinen 	/* On write, firmware manages flash MUX */
289acf63c45SIlpo Järvinen 	ret = pmci_flash_bulk_write(m10bmc, buf + offset, size);
290acf63c45SIlpo Järvinen 	mutex_unlock(&pmci->flash_mutex);
291acf63c45SIlpo Järvinen 
292acf63c45SIlpo Järvinen 	return ret;
293acf63c45SIlpo Järvinen }
294acf63c45SIlpo Järvinen 
m10bmc_pmci_flash_lock(struct intel_m10bmc * m10bmc)295acf63c45SIlpo Järvinen static int m10bmc_pmci_flash_lock(struct intel_m10bmc *m10bmc)
296acf63c45SIlpo Järvinen {
297acf63c45SIlpo Järvinen 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
298acf63c45SIlpo Järvinen 	int ret = 0;
299acf63c45SIlpo Järvinen 
300acf63c45SIlpo Järvinen 	mutex_lock(&pmci->flash_mutex);
301acf63c45SIlpo Järvinen 	if (pmci->flash_busy) {
302acf63c45SIlpo Järvinen 		ret = -EBUSY;
303acf63c45SIlpo Järvinen 		goto unlock;
304acf63c45SIlpo Järvinen 	}
305acf63c45SIlpo Järvinen 
306acf63c45SIlpo Järvinen 	pmci->flash_busy = true;
307acf63c45SIlpo Järvinen 
308acf63c45SIlpo Järvinen unlock:
309acf63c45SIlpo Järvinen 	mutex_unlock(&pmci->flash_mutex);
310acf63c45SIlpo Järvinen 	return ret;
311acf63c45SIlpo Järvinen }
312acf63c45SIlpo Järvinen 
m10bmc_pmci_flash_unlock(struct intel_m10bmc * m10bmc)313acf63c45SIlpo Järvinen static void m10bmc_pmci_flash_unlock(struct intel_m10bmc *m10bmc)
314acf63c45SIlpo Järvinen {
315acf63c45SIlpo Järvinen 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
316acf63c45SIlpo Järvinen 
317acf63c45SIlpo Järvinen 	mutex_lock(&pmci->flash_mutex);
318acf63c45SIlpo Järvinen 	WARN_ON_ONCE(!pmci->flash_busy);
319acf63c45SIlpo Järvinen 	pmci->flash_busy = false;
320acf63c45SIlpo Järvinen 	mutex_unlock(&pmci->flash_mutex);
321acf63c45SIlpo Järvinen }
322acf63c45SIlpo Järvinen 
323acf63c45SIlpo Järvinen static const struct intel_m10bmc_flash_bulk_ops m10bmc_pmci_flash_bulk_ops = {
324acf63c45SIlpo Järvinen 	.read = m10bmc_pmci_flash_read,
325acf63c45SIlpo Järvinen 	.write = m10bmc_pmci_flash_write,
326acf63c45SIlpo Järvinen 	.lock_write = m10bmc_pmci_flash_lock,
327acf63c45SIlpo Järvinen 	.unlock_write = m10bmc_pmci_flash_unlock,
328acf63c45SIlpo Järvinen };
329acf63c45SIlpo Järvinen 
330869b9eddSIlpo Järvinen static const struct regmap_range m10bmc_pmci_regmap_range[] = {
331869b9eddSIlpo Järvinen 	regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END),
332869b9eddSIlpo Järvinen };
333869b9eddSIlpo Järvinen 
334869b9eddSIlpo Järvinen static const struct regmap_access_table m10bmc_pmci_access_table = {
335869b9eddSIlpo Järvinen 	.yes_ranges	= m10bmc_pmci_regmap_range,
336869b9eddSIlpo Järvinen 	.n_yes_ranges	= ARRAY_SIZE(m10bmc_pmci_regmap_range),
337869b9eddSIlpo Järvinen };
338869b9eddSIlpo Järvinen 
339869b9eddSIlpo Järvinen static struct regmap_config m10bmc_pmci_regmap_config = {
340869b9eddSIlpo Järvinen 	.reg_bits = 32,
341869b9eddSIlpo Järvinen 	.reg_stride = 4,
342869b9eddSIlpo Järvinen 	.val_bits = 32,
343869b9eddSIlpo Järvinen 	.wr_table = &m10bmc_pmci_access_table,
344869b9eddSIlpo Järvinen 	.rd_table = &m10bmc_pmci_access_table,
345869b9eddSIlpo Järvinen 	.reg_read = &indirect_reg_read,
346869b9eddSIlpo Järvinen 	.reg_write = &indirect_reg_write,
347869b9eddSIlpo Järvinen 	.max_register = M10BMC_N6000_SYS_END,
348869b9eddSIlpo Järvinen };
349869b9eddSIlpo Järvinen 
350869b9eddSIlpo Järvinen static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = {
351869b9eddSIlpo Järvinen 	{ .name = "n6000bmc-hwmon" },
352acf63c45SIlpo Järvinen 	{ .name = "n6000bmc-sec-update" },
353869b9eddSIlpo Järvinen };
354869b9eddSIlpo Järvinen 
355869b9eddSIlpo Järvinen static const struct m10bmc_csr_map m10bmc_n6000_csr_map = {
356869b9eddSIlpo Järvinen 	.base = M10BMC_N6000_SYS_BASE,
357869b9eddSIlpo Järvinen 	.build_version = M10BMC_N6000_BUILD_VER,
358869b9eddSIlpo Järvinen 	.fw_version = NIOS2_N6000_FW_VERSION,
359869b9eddSIlpo Järvinen 	.mac_low = M10BMC_N6000_MAC_LOW,
360869b9eddSIlpo Järvinen 	.mac_high = M10BMC_N6000_MAC_HIGH,
361869b9eddSIlpo Järvinen 	.doorbell = M10BMC_N6000_DOORBELL,
362869b9eddSIlpo Järvinen 	.auth_result = M10BMC_N6000_AUTH_RESULT,
363869b9eddSIlpo Järvinen 	.bmc_prog_addr = M10BMC_N6000_BMC_PROG_ADDR,
364869b9eddSIlpo Järvinen 	.bmc_reh_addr = M10BMC_N6000_BMC_REH_ADDR,
365869b9eddSIlpo Järvinen 	.bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC,
366869b9eddSIlpo Järvinen 	.sr_prog_addr = M10BMC_N6000_SR_PROG_ADDR,
367869b9eddSIlpo Järvinen 	.sr_reh_addr = M10BMC_N6000_SR_REH_ADDR,
368869b9eddSIlpo Järvinen 	.sr_magic = M10BMC_N6000_SR_PROG_MAGIC,
369869b9eddSIlpo Järvinen 	.pr_prog_addr = M10BMC_N6000_PR_PROG_ADDR,
370869b9eddSIlpo Järvinen 	.pr_reh_addr = M10BMC_N6000_PR_REH_ADDR,
371869b9eddSIlpo Järvinen 	.pr_magic = M10BMC_N6000_PR_PROG_MAGIC,
372869b9eddSIlpo Järvinen 	.rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT,
373869b9eddSIlpo Järvinen };
374869b9eddSIlpo Järvinen 
375869b9eddSIlpo Järvinen static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = {
376869b9eddSIlpo Järvinen 	.cells = m10bmc_pmci_n6000_bmc_subdevs,
377869b9eddSIlpo Järvinen 	.n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs),
378869b9eddSIlpo Järvinen 	.csr_map = &m10bmc_n6000_csr_map,
379869b9eddSIlpo Järvinen };
380869b9eddSIlpo Järvinen 
m10bmc_pmci_probe(struct dfl_device * ddev)381869b9eddSIlpo Järvinen static int m10bmc_pmci_probe(struct dfl_device *ddev)
382869b9eddSIlpo Järvinen {
383869b9eddSIlpo Järvinen 	struct device *dev = &ddev->dev;
384869b9eddSIlpo Järvinen 	struct m10bmc_pmci_device *pmci;
385869b9eddSIlpo Järvinen 	struct indirect_ctx *ctx;
386acf63c45SIlpo Järvinen 	int ret;
387869b9eddSIlpo Järvinen 
388869b9eddSIlpo Järvinen 	pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL);
389869b9eddSIlpo Järvinen 	if (!pmci)
390869b9eddSIlpo Järvinen 		return -ENOMEM;
391869b9eddSIlpo Järvinen 
392acf63c45SIlpo Järvinen 	pmci->m10bmc.flash_bulk_ops = &m10bmc_pmci_flash_bulk_ops;
393869b9eddSIlpo Järvinen 	pmci->m10bmc.dev = dev;
394869b9eddSIlpo Järvinen 
395869b9eddSIlpo Järvinen 	pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res);
396869b9eddSIlpo Järvinen 	if (IS_ERR(pmci->base))
397869b9eddSIlpo Järvinen 		return PTR_ERR(pmci->base);
398869b9eddSIlpo Järvinen 
399869b9eddSIlpo Järvinen 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
400869b9eddSIlpo Järvinen 	if (!ctx)
401869b9eddSIlpo Järvinen 		return -ENOMEM;
402869b9eddSIlpo Järvinen 
403acf63c45SIlpo Järvinen 	mutex_init(&pmci->flash_mutex);
404acf63c45SIlpo Järvinen 
405869b9eddSIlpo Järvinen 	ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE;
406869b9eddSIlpo Järvinen 	ctx->dev = dev;
407869b9eddSIlpo Järvinen 	indirect_clear_cmd(ctx);
408869b9eddSIlpo Järvinen 	pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config);
409869b9eddSIlpo Järvinen 
410acf63c45SIlpo Järvinen 	if (IS_ERR(pmci->m10bmc.regmap)) {
411acf63c45SIlpo Järvinen 		ret = PTR_ERR(pmci->m10bmc.regmap);
412acf63c45SIlpo Järvinen 		goto destroy_mutex;
413acf63c45SIlpo Järvinen 	}
414869b9eddSIlpo Järvinen 
415acf63c45SIlpo Järvinen 	ret = m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000);
416acf63c45SIlpo Järvinen 	if (ret)
417acf63c45SIlpo Järvinen 		goto destroy_mutex;
418acf63c45SIlpo Järvinen 	return 0;
419acf63c45SIlpo Järvinen 
420acf63c45SIlpo Järvinen destroy_mutex:
421acf63c45SIlpo Järvinen 	mutex_destroy(&pmci->flash_mutex);
422acf63c45SIlpo Järvinen 	return ret;
423acf63c45SIlpo Järvinen }
424acf63c45SIlpo Järvinen 
m10bmc_pmci_remove(struct dfl_device * ddev)425acf63c45SIlpo Järvinen static void m10bmc_pmci_remove(struct dfl_device *ddev)
426acf63c45SIlpo Järvinen {
427acf63c45SIlpo Järvinen 	struct intel_m10bmc *m10bmc = dev_get_drvdata(&ddev->dev);
428acf63c45SIlpo Järvinen 	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
429acf63c45SIlpo Järvinen 
430acf63c45SIlpo Järvinen 	mutex_destroy(&pmci->flash_mutex);
431869b9eddSIlpo Järvinen }
432869b9eddSIlpo Järvinen 
433869b9eddSIlpo Järvinen #define FME_FEATURE_ID_M10BMC_PMCI	0x12
434869b9eddSIlpo Järvinen 
435869b9eddSIlpo Järvinen static const struct dfl_device_id m10bmc_pmci_ids[] = {
436869b9eddSIlpo Järvinen 	{ FME_ID, FME_FEATURE_ID_M10BMC_PMCI },
437869b9eddSIlpo Järvinen 	{ }
438869b9eddSIlpo Järvinen };
439869b9eddSIlpo Järvinen MODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids);
440869b9eddSIlpo Järvinen 
441869b9eddSIlpo Järvinen static struct dfl_driver m10bmc_pmci_driver = {
442869b9eddSIlpo Järvinen 	.drv	= {
443869b9eddSIlpo Järvinen 		.name       = "intel-m10-bmc",
444869b9eddSIlpo Järvinen 		.dev_groups = m10bmc_dev_groups,
445869b9eddSIlpo Järvinen 	},
446869b9eddSIlpo Järvinen 	.id_table = m10bmc_pmci_ids,
447869b9eddSIlpo Järvinen 	.probe    = m10bmc_pmci_probe,
448acf63c45SIlpo Järvinen 	.remove   = m10bmc_pmci_remove,
449869b9eddSIlpo Järvinen };
450869b9eddSIlpo Järvinen 
451869b9eddSIlpo Järvinen module_dfl_driver(m10bmc_pmci_driver);
452869b9eddSIlpo Järvinen 
453869b9eddSIlpo Järvinen MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface");
454869b9eddSIlpo Järvinen MODULE_AUTHOR("Intel Corporation");
455869b9eddSIlpo Järvinen MODULE_LICENSE("GPL");
456*b3ecc7f3SIlpo Järvinen MODULE_IMPORT_NS(INTEL_M10_BMC_CORE);
457