162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * MAX10 BMC Platform Management Component Interface (PMCI) based
462306a36Sopenharmony_ci * interface.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2020-2023 Intel Corporation.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitfield.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/dfl.h>
1262306a36Sopenharmony_ci#include <linux/mfd/core.h>
1362306a36Sopenharmony_ci#include <linux/mfd/intel-m10-bmc.h>
1462306a36Sopenharmony_ci#include <linux/minmax.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/regmap.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct m10bmc_pmci_device {
1962306a36Sopenharmony_ci	void __iomem *base;
2062306a36Sopenharmony_ci	struct intel_m10bmc m10bmc;
2162306a36Sopenharmony_ci	struct mutex flash_mutex;	/* protects flash_busy and serializes flash read/read */
2262306a36Sopenharmony_ci	bool flash_busy;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*
2662306a36Sopenharmony_ci * Intel FGPA indirect register access via hardware controller/bridge.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci#define INDIRECT_CMD_OFF	0
2962306a36Sopenharmony_ci#define INDIRECT_CMD_CLR	0
3062306a36Sopenharmony_ci#define INDIRECT_CMD_RD		BIT(0)
3162306a36Sopenharmony_ci#define INDIRECT_CMD_WR		BIT(1)
3262306a36Sopenharmony_ci#define INDIRECT_CMD_ACK	BIT(2)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define INDIRECT_ADDR_OFF	0x4
3562306a36Sopenharmony_ci#define INDIRECT_RD_OFF		0x8
3662306a36Sopenharmony_ci#define INDIRECT_WR_OFF		0xc
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define INDIRECT_INT_US		1
3962306a36Sopenharmony_ci#define INDIRECT_TIMEOUT_US	10000
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistruct indirect_ctx {
4262306a36Sopenharmony_ci	void __iomem *base;
4362306a36Sopenharmony_ci	struct device *dev;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int indirect_clear_cmd(struct indirect_ctx *ctx)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	unsigned int cmd;
4962306a36Sopenharmony_ci	int ret;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd,
5462306a36Sopenharmony_ci				 cmd == INDIRECT_CMD_CLR,
5562306a36Sopenharmony_ci				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
5662306a36Sopenharmony_ci	if (ret)
5762306a36Sopenharmony_ci		dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return ret;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int indirect_reg_read(void *context, unsigned int reg, unsigned int *val)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct indirect_ctx *ctx = context;
6562306a36Sopenharmony_ci	unsigned int cmd, ack, tmpval;
6662306a36Sopenharmony_ci	int ret, ret2;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
6962306a36Sopenharmony_ci	if (cmd != INDIRECT_CMD_CLR)
7062306a36Sopenharmony_ci		dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
7362306a36Sopenharmony_ci	writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
7662306a36Sopenharmony_ci				 (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
7762306a36Sopenharmony_ci				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
7862306a36Sopenharmony_ci	if (ret)
7962306a36Sopenharmony_ci		dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack);
8062306a36Sopenharmony_ci	else
8162306a36Sopenharmony_ci		tmpval = readl(ctx->base + INDIRECT_RD_OFF);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	ret2 = indirect_clear_cmd(ctx);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (ret)
8662306a36Sopenharmony_ci		return ret;
8762306a36Sopenharmony_ci	if (ret2)
8862306a36Sopenharmony_ci		return ret2;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	*val = tmpval;
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int indirect_reg_write(void *context, unsigned int reg, unsigned int val)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct indirect_ctx *ctx = context;
9762306a36Sopenharmony_ci	unsigned int cmd, ack;
9862306a36Sopenharmony_ci	int ret, ret2;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	cmd = readl(ctx->base + INDIRECT_CMD_OFF);
10162306a36Sopenharmony_ci	if (cmd != INDIRECT_CMD_CLR)
10262306a36Sopenharmony_ci		dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	writel(val, ctx->base + INDIRECT_WR_OFF);
10562306a36Sopenharmony_ci	writel(reg, ctx->base + INDIRECT_ADDR_OFF);
10662306a36Sopenharmony_ci	writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
10962306a36Sopenharmony_ci				 (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
11062306a36Sopenharmony_ci				 INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
11162306a36Sopenharmony_ci	if (ret)
11262306a36Sopenharmony_ci		dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	ret2 = indirect_clear_cmd(ctx);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (ret)
11762306a36Sopenharmony_ci		return ret;
11862306a36Sopenharmony_ci	return ret2;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	while (count--)
12462306a36Sopenharmony_ci		writel(*buf++, base);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic void pmci_read_fifo(void __iomem *base, u32 *buf, size_t count)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	while (count--)
13062306a36Sopenharmony_ci		*buf++ = readl(base);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic u32 pmci_get_write_space(struct m10bmc_pmci_device *pmci)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	u32 val;
13662306a36Sopenharmony_ci	int ret;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	ret = read_poll_timeout(readl, val,
13962306a36Sopenharmony_ci				FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) ==
14062306a36Sopenharmony_ci				M10BMC_N6000_FIFO_MAX_WORDS,
14162306a36Sopenharmony_ci				M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US,
14262306a36Sopenharmony_ci				false, pmci->base + M10BMC_N6000_FLASH_CTRL);
14362306a36Sopenharmony_ci	if (ret == -ETIMEDOUT)
14462306a36Sopenharmony_ci		return 0;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) * M10BMC_N6000_FIFO_WORD_SIZE;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int pmci_flash_bulk_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 size)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
15262306a36Sopenharmony_ci	u32 blk_size, offset = 0, write_count;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	while (size) {
15562306a36Sopenharmony_ci		blk_size = min(pmci_get_write_space(pmci), size);
15662306a36Sopenharmony_ci		if (blk_size == 0) {
15762306a36Sopenharmony_ci			dev_err(m10bmc->dev, "get FIFO available size fail\n");
15862306a36Sopenharmony_ci			return -EIO;
15962306a36Sopenharmony_ci		}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		if (size < M10BMC_N6000_FIFO_WORD_SIZE)
16262306a36Sopenharmony_ci			break;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		write_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
16562306a36Sopenharmony_ci		pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
16662306a36Sopenharmony_ci				(u32 *)(buf + offset), write_count);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		size -= blk_size;
16962306a36Sopenharmony_ci		offset += blk_size;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
17362306a36Sopenharmony_ci	if (size) {
17462306a36Sopenharmony_ci		u32 tmp = 0;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		memcpy(&tmp, buf + offset, size);
17762306a36Sopenharmony_ci		pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int pmci_flash_bulk_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
18662306a36Sopenharmony_ci	u32 blk_size, offset = 0, val, full_read_count, read_count;
18762306a36Sopenharmony_ci	int ret;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	while (size) {
19062306a36Sopenharmony_ci		blk_size = min_t(u32, size, M10BMC_N6000_READ_BLOCK_SIZE);
19162306a36Sopenharmony_ci		full_read_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		read_count = full_read_count;
19462306a36Sopenharmony_ci		if (full_read_count * M10BMC_N6000_FIFO_WORD_SIZE < blk_size)
19562306a36Sopenharmony_ci			read_count++;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		writel(addr + offset, pmci->base + M10BMC_N6000_FLASH_ADDR);
19862306a36Sopenharmony_ci		writel(FIELD_PREP(M10BMC_N6000_FLASH_READ_COUNT, read_count) |
19962306a36Sopenharmony_ci		       M10BMC_N6000_FLASH_RD_MODE,
20062306a36Sopenharmony_ci		       pmci->base + M10BMC_N6000_FLASH_CTRL);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		ret = readl_poll_timeout((pmci->base + M10BMC_N6000_FLASH_CTRL), val,
20362306a36Sopenharmony_ci					 !(val & M10BMC_N6000_FLASH_BUSY),
20462306a36Sopenharmony_ci					 M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
20562306a36Sopenharmony_ci		if (ret) {
20662306a36Sopenharmony_ci			dev_err(m10bmc->dev, "read timed out on reading flash 0x%xn", val);
20762306a36Sopenharmony_ci			return ret;
20862306a36Sopenharmony_ci		}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
21162306a36Sopenharmony_ci			       (u32 *)(buf + offset), full_read_count);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		size -= blk_size;
21462306a36Sopenharmony_ci		offset += blk_size;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		if (full_read_count < read_count)
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
22362306a36Sopenharmony_ci	if (size) {
22462306a36Sopenharmony_ci		u32 tmp;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
22762306a36Sopenharmony_ci		memcpy(buf + offset, &tmp, size);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic int m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc *m10bmc, bool request)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	u32 ctrl;
23862306a36Sopenharmony_ci	int ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ret = regmap_update_bits(m10bmc->regmap, M10BMC_N6000_FLASH_MUX_CTRL,
24162306a36Sopenharmony_ci				 M10BMC_N6000_FLASH_HOST_REQUEST,
24262306a36Sopenharmony_ci				 FIELD_PREP(M10BMC_N6000_FLASH_HOST_REQUEST, request));
24362306a36Sopenharmony_ci	if (ret)
24462306a36Sopenharmony_ci		return ret;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return regmap_read_poll_timeout(m10bmc->regmap,
24762306a36Sopenharmony_ci					M10BMC_N6000_FLASH_MUX_CTRL, ctrl,
24862306a36Sopenharmony_ci					request ?
24962306a36Sopenharmony_ci					(get_flash_mux(ctrl) == M10BMC_N6000_FLASH_MUX_HOST) :
25062306a36Sopenharmony_ci					(get_flash_mux(ctrl) != M10BMC_N6000_FLASH_MUX_HOST),
25162306a36Sopenharmony_ci					M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int m10bmc_pmci_flash_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
25762306a36Sopenharmony_ci	int ret, ret2;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	mutex_lock(&pmci->flash_mutex);
26062306a36Sopenharmony_ci	if (pmci->flash_busy) {
26162306a36Sopenharmony_ci		ret = -EBUSY;
26262306a36Sopenharmony_ci		goto unlock;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ret = m10bmc_pmci_set_flash_host_mux(m10bmc, true);
26662306a36Sopenharmony_ci	if (ret)
26762306a36Sopenharmony_ci		goto mux_fail;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	ret = pmci_flash_bulk_read(m10bmc, buf, addr, size);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cimux_fail:
27262306a36Sopenharmony_ci	ret2 = m10bmc_pmci_set_flash_host_mux(m10bmc, false);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ciunlock:
27562306a36Sopenharmony_ci	mutex_unlock(&pmci->flash_mutex);
27662306a36Sopenharmony_ci	if (ret)
27762306a36Sopenharmony_ci		return ret;
27862306a36Sopenharmony_ci	return ret2;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int m10bmc_pmci_flash_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 offset, u32 size)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
28462306a36Sopenharmony_ci	int ret;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	mutex_lock(&pmci->flash_mutex);
28762306a36Sopenharmony_ci	WARN_ON_ONCE(!pmci->flash_busy);
28862306a36Sopenharmony_ci	/* On write, firmware manages flash MUX */
28962306a36Sopenharmony_ci	ret = pmci_flash_bulk_write(m10bmc, buf + offset, size);
29062306a36Sopenharmony_ci	mutex_unlock(&pmci->flash_mutex);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return ret;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int m10bmc_pmci_flash_lock(struct intel_m10bmc *m10bmc)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
29862306a36Sopenharmony_ci	int ret = 0;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	mutex_lock(&pmci->flash_mutex);
30162306a36Sopenharmony_ci	if (pmci->flash_busy) {
30262306a36Sopenharmony_ci		ret = -EBUSY;
30362306a36Sopenharmony_ci		goto unlock;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	pmci->flash_busy = true;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ciunlock:
30962306a36Sopenharmony_ci	mutex_unlock(&pmci->flash_mutex);
31062306a36Sopenharmony_ci	return ret;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic void m10bmc_pmci_flash_unlock(struct intel_m10bmc *m10bmc)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	mutex_lock(&pmci->flash_mutex);
31862306a36Sopenharmony_ci	WARN_ON_ONCE(!pmci->flash_busy);
31962306a36Sopenharmony_ci	pmci->flash_busy = false;
32062306a36Sopenharmony_ci	mutex_unlock(&pmci->flash_mutex);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic const struct intel_m10bmc_flash_bulk_ops m10bmc_pmci_flash_bulk_ops = {
32462306a36Sopenharmony_ci	.read = m10bmc_pmci_flash_read,
32562306a36Sopenharmony_ci	.write = m10bmc_pmci_flash_write,
32662306a36Sopenharmony_ci	.lock_write = m10bmc_pmci_flash_lock,
32762306a36Sopenharmony_ci	.unlock_write = m10bmc_pmci_flash_unlock,
32862306a36Sopenharmony_ci};
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic const struct regmap_range m10bmc_pmci_regmap_range[] = {
33162306a36Sopenharmony_ci	regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END),
33262306a36Sopenharmony_ci};
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic const struct regmap_access_table m10bmc_pmci_access_table = {
33562306a36Sopenharmony_ci	.yes_ranges	= m10bmc_pmci_regmap_range,
33662306a36Sopenharmony_ci	.n_yes_ranges	= ARRAY_SIZE(m10bmc_pmci_regmap_range),
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic struct regmap_config m10bmc_pmci_regmap_config = {
34062306a36Sopenharmony_ci	.reg_bits = 32,
34162306a36Sopenharmony_ci	.reg_stride = 4,
34262306a36Sopenharmony_ci	.val_bits = 32,
34362306a36Sopenharmony_ci	.wr_table = &m10bmc_pmci_access_table,
34462306a36Sopenharmony_ci	.rd_table = &m10bmc_pmci_access_table,
34562306a36Sopenharmony_ci	.reg_read = &indirect_reg_read,
34662306a36Sopenharmony_ci	.reg_write = &indirect_reg_write,
34762306a36Sopenharmony_ci	.max_register = M10BMC_N6000_SYS_END,
34862306a36Sopenharmony_ci};
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = {
35162306a36Sopenharmony_ci	{ .name = "n6000bmc-hwmon" },
35262306a36Sopenharmony_ci	{ .name = "n6000bmc-sec-update" },
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic const struct m10bmc_csr_map m10bmc_n6000_csr_map = {
35662306a36Sopenharmony_ci	.base = M10BMC_N6000_SYS_BASE,
35762306a36Sopenharmony_ci	.build_version = M10BMC_N6000_BUILD_VER,
35862306a36Sopenharmony_ci	.fw_version = NIOS2_N6000_FW_VERSION,
35962306a36Sopenharmony_ci	.mac_low = M10BMC_N6000_MAC_LOW,
36062306a36Sopenharmony_ci	.mac_high = M10BMC_N6000_MAC_HIGH,
36162306a36Sopenharmony_ci	.doorbell = M10BMC_N6000_DOORBELL,
36262306a36Sopenharmony_ci	.auth_result = M10BMC_N6000_AUTH_RESULT,
36362306a36Sopenharmony_ci	.bmc_prog_addr = M10BMC_N6000_BMC_PROG_ADDR,
36462306a36Sopenharmony_ci	.bmc_reh_addr = M10BMC_N6000_BMC_REH_ADDR,
36562306a36Sopenharmony_ci	.bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC,
36662306a36Sopenharmony_ci	.sr_prog_addr = M10BMC_N6000_SR_PROG_ADDR,
36762306a36Sopenharmony_ci	.sr_reh_addr = M10BMC_N6000_SR_REH_ADDR,
36862306a36Sopenharmony_ci	.sr_magic = M10BMC_N6000_SR_PROG_MAGIC,
36962306a36Sopenharmony_ci	.pr_prog_addr = M10BMC_N6000_PR_PROG_ADDR,
37062306a36Sopenharmony_ci	.pr_reh_addr = M10BMC_N6000_PR_REH_ADDR,
37162306a36Sopenharmony_ci	.pr_magic = M10BMC_N6000_PR_PROG_MAGIC,
37262306a36Sopenharmony_ci	.rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT,
37362306a36Sopenharmony_ci};
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = {
37662306a36Sopenharmony_ci	.cells = m10bmc_pmci_n6000_bmc_subdevs,
37762306a36Sopenharmony_ci	.n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs),
37862306a36Sopenharmony_ci	.csr_map = &m10bmc_n6000_csr_map,
37962306a36Sopenharmony_ci};
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic int m10bmc_pmci_probe(struct dfl_device *ddev)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct device *dev = &ddev->dev;
38462306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci;
38562306a36Sopenharmony_ci	struct indirect_ctx *ctx;
38662306a36Sopenharmony_ci	int ret;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL);
38962306a36Sopenharmony_ci	if (!pmci)
39062306a36Sopenharmony_ci		return -ENOMEM;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	pmci->m10bmc.flash_bulk_ops = &m10bmc_pmci_flash_bulk_ops;
39362306a36Sopenharmony_ci	pmci->m10bmc.dev = dev;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res);
39662306a36Sopenharmony_ci	if (IS_ERR(pmci->base))
39762306a36Sopenharmony_ci		return PTR_ERR(pmci->base);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
40062306a36Sopenharmony_ci	if (!ctx)
40162306a36Sopenharmony_ci		return -ENOMEM;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	mutex_init(&pmci->flash_mutex);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE;
40662306a36Sopenharmony_ci	ctx->dev = dev;
40762306a36Sopenharmony_ci	indirect_clear_cmd(ctx);
40862306a36Sopenharmony_ci	pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (IS_ERR(pmci->m10bmc.regmap)) {
41162306a36Sopenharmony_ci		ret = PTR_ERR(pmci->m10bmc.regmap);
41262306a36Sopenharmony_ci		goto destroy_mutex;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	ret = m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000);
41662306a36Sopenharmony_ci	if (ret)
41762306a36Sopenharmony_ci		goto destroy_mutex;
41862306a36Sopenharmony_ci	return 0;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cidestroy_mutex:
42162306a36Sopenharmony_ci	mutex_destroy(&pmci->flash_mutex);
42262306a36Sopenharmony_ci	return ret;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic void m10bmc_pmci_remove(struct dfl_device *ddev)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct intel_m10bmc *m10bmc = dev_get_drvdata(&ddev->dev);
42862306a36Sopenharmony_ci	struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	mutex_destroy(&pmci->flash_mutex);
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci#define FME_FEATURE_ID_M10BMC_PMCI	0x12
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic const struct dfl_device_id m10bmc_pmci_ids[] = {
43662306a36Sopenharmony_ci	{ FME_ID, FME_FEATURE_ID_M10BMC_PMCI },
43762306a36Sopenharmony_ci	{ }
43862306a36Sopenharmony_ci};
43962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic struct dfl_driver m10bmc_pmci_driver = {
44262306a36Sopenharmony_ci	.drv	= {
44362306a36Sopenharmony_ci		.name       = "intel-m10-bmc",
44462306a36Sopenharmony_ci		.dev_groups = m10bmc_dev_groups,
44562306a36Sopenharmony_ci	},
44662306a36Sopenharmony_ci	.id_table = m10bmc_pmci_ids,
44762306a36Sopenharmony_ci	.probe    = m10bmc_pmci_probe,
44862306a36Sopenharmony_ci	.remove   = m10bmc_pmci_remove,
44962306a36Sopenharmony_ci};
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cimodule_dfl_driver(m10bmc_pmci_driver);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ciMODULE_DESCRIPTION("MAX10 BMC PMCI-based interface");
45462306a36Sopenharmony_ciMODULE_AUTHOR("Intel Corporation");
45562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
45662306a36Sopenharmony_ciMODULE_IMPORT_NS(INTEL_M10_BMC_CORE);
457