162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ASPEED FMC/SPI Memory Controller Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015-2022, IBM Corporation.
662306a36Sopenharmony_ci * Copyright (c) 2020, ASPEED Corporation.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/of_platform.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/spi/spi.h>
1562306a36Sopenharmony_ci#include <linux/spi/spi-mem.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define DEVICE_NAME "spi-aspeed-smc"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* Type setting Register */
2062306a36Sopenharmony_ci#define CONFIG_REG			0x0
2162306a36Sopenharmony_ci#define   CONFIG_TYPE_SPI		0x2
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* CE Control Register */
2462306a36Sopenharmony_ci#define CE_CTRL_REG			0x4
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* CEx Control Register */
2762306a36Sopenharmony_ci#define CE0_CTRL_REG			0x10
2862306a36Sopenharmony_ci#define   CTRL_IO_MODE_MASK		GENMASK(30, 28)
2962306a36Sopenharmony_ci#define   CTRL_IO_SINGLE_DATA	        0x0
3062306a36Sopenharmony_ci#define   CTRL_IO_DUAL_DATA		BIT(29)
3162306a36Sopenharmony_ci#define   CTRL_IO_QUAD_DATA		BIT(30)
3262306a36Sopenharmony_ci#define   CTRL_COMMAND_SHIFT		16
3362306a36Sopenharmony_ci#define   CTRL_IO_ADDRESS_4B		BIT(13)	/* AST2400 SPI only */
3462306a36Sopenharmony_ci#define   CTRL_IO_DUMMY_SET(dummy)					\
3562306a36Sopenharmony_ci	(((((dummy) >> 2) & 0x1) << 14) | (((dummy) & 0x3) << 6))
3662306a36Sopenharmony_ci#define   CTRL_FREQ_SEL_SHIFT		8
3762306a36Sopenharmony_ci#define   CTRL_FREQ_SEL_MASK		GENMASK(11, CTRL_FREQ_SEL_SHIFT)
3862306a36Sopenharmony_ci#define   CTRL_CE_STOP_ACTIVE		BIT(2)
3962306a36Sopenharmony_ci#define   CTRL_IO_MODE_CMD_MASK		GENMASK(1, 0)
4062306a36Sopenharmony_ci#define   CTRL_IO_MODE_NORMAL		0x0
4162306a36Sopenharmony_ci#define   CTRL_IO_MODE_READ		0x1
4262306a36Sopenharmony_ci#define   CTRL_IO_MODE_WRITE		0x2
4362306a36Sopenharmony_ci#define   CTRL_IO_MODE_USER		0x3
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define   CTRL_IO_CMD_MASK		0xf0ff40c3
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* CEx Address Decoding Range Register */
4862306a36Sopenharmony_ci#define CE0_SEGMENT_ADDR_REG		0x30
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* CEx Read timing compensation register */
5162306a36Sopenharmony_ci#define CE0_TIMING_COMPENSATION_REG	0x94
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cienum aspeed_spi_ctl_reg_value {
5462306a36Sopenharmony_ci	ASPEED_SPI_BASE,
5562306a36Sopenharmony_ci	ASPEED_SPI_READ,
5662306a36Sopenharmony_ci	ASPEED_SPI_WRITE,
5762306a36Sopenharmony_ci	ASPEED_SPI_MAX,
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct aspeed_spi;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistruct aspeed_spi_chip {
6362306a36Sopenharmony_ci	struct aspeed_spi	*aspi;
6462306a36Sopenharmony_ci	u32			 cs;
6562306a36Sopenharmony_ci	void __iomem		*ctl;
6662306a36Sopenharmony_ci	void __iomem		*ahb_base;
6762306a36Sopenharmony_ci	u32			 ahb_window_size;
6862306a36Sopenharmony_ci	u32			 ctl_val[ASPEED_SPI_MAX];
6962306a36Sopenharmony_ci	u32			 clk_freq;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct aspeed_spi_data {
7362306a36Sopenharmony_ci	u32	ctl0;
7462306a36Sopenharmony_ci	u32	max_cs;
7562306a36Sopenharmony_ci	bool	hastype;
7662306a36Sopenharmony_ci	u32	mode_bits;
7762306a36Sopenharmony_ci	u32	we0;
7862306a36Sopenharmony_ci	u32	timing;
7962306a36Sopenharmony_ci	u32	hclk_mask;
8062306a36Sopenharmony_ci	u32	hdiv_max;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	u32 (*segment_start)(struct aspeed_spi *aspi, u32 reg);
8362306a36Sopenharmony_ci	u32 (*segment_end)(struct aspeed_spi *aspi, u32 reg);
8462306a36Sopenharmony_ci	u32 (*segment_reg)(struct aspeed_spi *aspi, u32 start, u32 end);
8562306a36Sopenharmony_ci	int (*calibrate)(struct aspeed_spi_chip *chip, u32 hdiv,
8662306a36Sopenharmony_ci			 const u8 *golden_buf, u8 *test_buf);
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define ASPEED_SPI_MAX_NUM_CS	5
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistruct aspeed_spi {
9262306a36Sopenharmony_ci	const struct aspeed_spi_data	*data;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	void __iomem		*regs;
9562306a36Sopenharmony_ci	void __iomem		*ahb_base;
9662306a36Sopenharmony_ci	u32			 ahb_base_phy;
9762306a36Sopenharmony_ci	u32			 ahb_window_size;
9862306a36Sopenharmony_ci	struct device		*dev;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	struct clk		*clk;
10162306a36Sopenharmony_ci	u32			 clk_freq;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	struct aspeed_spi_chip	 chips[ASPEED_SPI_MAX_NUM_CS];
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic u32 aspeed_spi_get_io_mode(const struct spi_mem_op *op)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	switch (op->data.buswidth) {
10962306a36Sopenharmony_ci	case 1:
11062306a36Sopenharmony_ci		return CTRL_IO_SINGLE_DATA;
11162306a36Sopenharmony_ci	case 2:
11262306a36Sopenharmony_ci		return CTRL_IO_DUAL_DATA;
11362306a36Sopenharmony_ci	case 4:
11462306a36Sopenharmony_ci		return CTRL_IO_QUAD_DATA;
11562306a36Sopenharmony_ci	default:
11662306a36Sopenharmony_ci		return CTRL_IO_SINGLE_DATA;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void aspeed_spi_set_io_mode(struct aspeed_spi_chip *chip, u32 io_mode)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	u32 ctl;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (io_mode > 0) {
12562306a36Sopenharmony_ci		ctl = readl(chip->ctl) & ~CTRL_IO_MODE_MASK;
12662306a36Sopenharmony_ci		ctl |= io_mode;
12762306a36Sopenharmony_ci		writel(ctl, chip->ctl);
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void aspeed_spi_start_user(struct aspeed_spi_chip *chip)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	u32 ctl = chip->ctl_val[ASPEED_SPI_BASE];
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ctl |= CTRL_IO_MODE_USER | CTRL_CE_STOP_ACTIVE;
13662306a36Sopenharmony_ci	writel(ctl, chip->ctl);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	ctl &= ~CTRL_CE_STOP_ACTIVE;
13962306a36Sopenharmony_ci	writel(ctl, chip->ctl);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void aspeed_spi_stop_user(struct aspeed_spi_chip *chip)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	u32 ctl = chip->ctl_val[ASPEED_SPI_READ] |
14562306a36Sopenharmony_ci		CTRL_IO_MODE_USER | CTRL_CE_STOP_ACTIVE;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	writel(ctl, chip->ctl);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Restore defaults */
15062306a36Sopenharmony_ci	writel(chip->ctl_val[ASPEED_SPI_READ], chip->ctl);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic int aspeed_spi_read_from_ahb(void *buf, void __iomem *src, size_t len)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	size_t offset = 0;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (IS_ALIGNED((uintptr_t)src, sizeof(uintptr_t)) &&
15862306a36Sopenharmony_ci	    IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) {
15962306a36Sopenharmony_ci		ioread32_rep(src, buf, len >> 2);
16062306a36Sopenharmony_ci		offset = len & ~0x3;
16162306a36Sopenharmony_ci		len -= offset;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	ioread8_rep(src, (u8 *)buf + offset, len);
16462306a36Sopenharmony_ci	return 0;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic int aspeed_spi_write_to_ahb(void __iomem *dst, const void *buf, size_t len)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	size_t offset = 0;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (IS_ALIGNED((uintptr_t)dst, sizeof(uintptr_t)) &&
17262306a36Sopenharmony_ci	    IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) {
17362306a36Sopenharmony_ci		iowrite32_rep(dst, buf, len >> 2);
17462306a36Sopenharmony_ci		offset = len & ~0x3;
17562306a36Sopenharmony_ci		len -= offset;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci	iowrite8_rep(dst, (const u8 *)buf + offset, len);
17862306a36Sopenharmony_ci	return 0;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int aspeed_spi_send_cmd_addr(struct aspeed_spi_chip *chip, u8 addr_nbytes,
18262306a36Sopenharmony_ci				    u64 offset, u32 opcode)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	__be32 temp;
18562306a36Sopenharmony_ci	u32 cmdaddr;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	switch (addr_nbytes) {
18862306a36Sopenharmony_ci	case 3:
18962306a36Sopenharmony_ci		cmdaddr = offset & 0xFFFFFF;
19062306a36Sopenharmony_ci		cmdaddr |= opcode << 24;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		temp = cpu_to_be32(cmdaddr);
19362306a36Sopenharmony_ci		aspeed_spi_write_to_ahb(chip->ahb_base, &temp, 4);
19462306a36Sopenharmony_ci		break;
19562306a36Sopenharmony_ci	case 4:
19662306a36Sopenharmony_ci		temp = cpu_to_be32(offset);
19762306a36Sopenharmony_ci		aspeed_spi_write_to_ahb(chip->ahb_base, &opcode, 1);
19862306a36Sopenharmony_ci		aspeed_spi_write_to_ahb(chip->ahb_base, &temp, 4);
19962306a36Sopenharmony_ci		break;
20062306a36Sopenharmony_ci	default:
20162306a36Sopenharmony_ci		WARN_ONCE(1, "Unexpected address width %u", addr_nbytes);
20262306a36Sopenharmony_ci		return -EOPNOTSUPP;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int aspeed_spi_read_reg(struct aspeed_spi_chip *chip,
20862306a36Sopenharmony_ci			       const struct spi_mem_op *op)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	aspeed_spi_start_user(chip);
21162306a36Sopenharmony_ci	aspeed_spi_write_to_ahb(chip->ahb_base, &op->cmd.opcode, 1);
21262306a36Sopenharmony_ci	aspeed_spi_read_from_ahb(op->data.buf.in,
21362306a36Sopenharmony_ci				 chip->ahb_base, op->data.nbytes);
21462306a36Sopenharmony_ci	aspeed_spi_stop_user(chip);
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int aspeed_spi_write_reg(struct aspeed_spi_chip *chip,
21962306a36Sopenharmony_ci				const struct spi_mem_op *op)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	aspeed_spi_start_user(chip);
22262306a36Sopenharmony_ci	aspeed_spi_write_to_ahb(chip->ahb_base, &op->cmd.opcode, 1);
22362306a36Sopenharmony_ci	aspeed_spi_write_to_ahb(chip->ahb_base, op->data.buf.out,
22462306a36Sopenharmony_ci				op->data.nbytes);
22562306a36Sopenharmony_ci	aspeed_spi_stop_user(chip);
22662306a36Sopenharmony_ci	return 0;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic ssize_t aspeed_spi_read_user(struct aspeed_spi_chip *chip,
23062306a36Sopenharmony_ci				    const struct spi_mem_op *op,
23162306a36Sopenharmony_ci				    u64 offset, size_t len, void *buf)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	int io_mode = aspeed_spi_get_io_mode(op);
23462306a36Sopenharmony_ci	u8 dummy = 0xFF;
23562306a36Sopenharmony_ci	int i;
23662306a36Sopenharmony_ci	int ret;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	aspeed_spi_start_user(chip);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, offset, op->cmd.opcode);
24162306a36Sopenharmony_ci	if (ret < 0)
24262306a36Sopenharmony_ci		return ret;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (op->dummy.buswidth && op->dummy.nbytes) {
24562306a36Sopenharmony_ci		for (i = 0; i < op->dummy.nbytes / op->dummy.buswidth; i++)
24662306a36Sopenharmony_ci			aspeed_spi_write_to_ahb(chip->ahb_base, &dummy,	sizeof(dummy));
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	aspeed_spi_set_io_mode(chip, io_mode);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	aspeed_spi_read_from_ahb(buf, chip->ahb_base, len);
25262306a36Sopenharmony_ci	aspeed_spi_stop_user(chip);
25362306a36Sopenharmony_ci	return 0;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip,
25762306a36Sopenharmony_ci				     const struct spi_mem_op *op)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	int ret;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	aspeed_spi_start_user(chip);
26262306a36Sopenharmony_ci	ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, op->addr.val, op->cmd.opcode);
26362306a36Sopenharmony_ci	if (ret < 0)
26462306a36Sopenharmony_ci		return ret;
26562306a36Sopenharmony_ci	aspeed_spi_write_to_ahb(chip->ahb_base, op->data.buf.out, op->data.nbytes);
26662306a36Sopenharmony_ci	aspeed_spi_stop_user(chip);
26762306a36Sopenharmony_ci	return 0;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/* support for 1-1-1, 1-1-2 or 1-1-4 */
27162306a36Sopenharmony_cistatic bool aspeed_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	if (op->cmd.buswidth > 1)
27462306a36Sopenharmony_ci		return false;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (op->addr.nbytes != 0) {
27762306a36Sopenharmony_ci		if (op->addr.buswidth > 1)
27862306a36Sopenharmony_ci			return false;
27962306a36Sopenharmony_ci		if (op->addr.nbytes < 3 || op->addr.nbytes > 4)
28062306a36Sopenharmony_ci			return false;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (op->dummy.nbytes != 0) {
28462306a36Sopenharmony_ci		if (op->dummy.buswidth > 1 || op->dummy.nbytes > 7)
28562306a36Sopenharmony_ci			return false;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (op->data.nbytes != 0 && op->data.buswidth > 4)
28962306a36Sopenharmony_ci		return false;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return spi_mem_default_supports_op(mem, op);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2400_spi_data;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int do_aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->controller);
29962306a36Sopenharmony_ci	struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(mem->spi, 0)];
30062306a36Sopenharmony_ci	u32 addr_mode, addr_mode_backup;
30162306a36Sopenharmony_ci	u32 ctl_val;
30262306a36Sopenharmony_ci	int ret = 0;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	dev_dbg(aspi->dev,
30562306a36Sopenharmony_ci		"CE%d %s OP %#x mode:%d.%d.%d.%d naddr:%#x ndummies:%#x len:%#x",
30662306a36Sopenharmony_ci		chip->cs, op->data.dir == SPI_MEM_DATA_IN ? "read" : "write",
30762306a36Sopenharmony_ci		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
30862306a36Sopenharmony_ci		op->dummy.buswidth, op->data.buswidth,
30962306a36Sopenharmony_ci		op->addr.nbytes, op->dummy.nbytes, op->data.nbytes);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	addr_mode = readl(aspi->regs + CE_CTRL_REG);
31262306a36Sopenharmony_ci	addr_mode_backup = addr_mode;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	ctl_val = chip->ctl_val[ASPEED_SPI_BASE];
31562306a36Sopenharmony_ci	ctl_val &= ~CTRL_IO_CMD_MASK;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	ctl_val |= op->cmd.opcode << CTRL_COMMAND_SHIFT;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* 4BYTE address mode */
32062306a36Sopenharmony_ci	if (op->addr.nbytes) {
32162306a36Sopenharmony_ci		if (op->addr.nbytes == 4)
32262306a36Sopenharmony_ci			addr_mode |= (0x11 << chip->cs);
32362306a36Sopenharmony_ci		else
32462306a36Sopenharmony_ci			addr_mode &= ~(0x11 << chip->cs);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		if (op->addr.nbytes == 4 && chip->aspi->data == &ast2400_spi_data)
32762306a36Sopenharmony_ci			ctl_val |= CTRL_IO_ADDRESS_4B;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (op->dummy.nbytes)
33162306a36Sopenharmony_ci		ctl_val |= CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (op->data.nbytes)
33462306a36Sopenharmony_ci		ctl_val |= aspeed_spi_get_io_mode(op);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_OUT)
33762306a36Sopenharmony_ci		ctl_val |= CTRL_IO_MODE_WRITE;
33862306a36Sopenharmony_ci	else
33962306a36Sopenharmony_ci		ctl_val |= CTRL_IO_MODE_READ;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (addr_mode != addr_mode_backup)
34262306a36Sopenharmony_ci		writel(addr_mode, aspi->regs + CE_CTRL_REG);
34362306a36Sopenharmony_ci	writel(ctl_val, chip->ctl);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
34662306a36Sopenharmony_ci		if (!op->addr.nbytes)
34762306a36Sopenharmony_ci			ret = aspeed_spi_read_reg(chip, op);
34862306a36Sopenharmony_ci		else
34962306a36Sopenharmony_ci			ret = aspeed_spi_read_user(chip, op, op->addr.val,
35062306a36Sopenharmony_ci						   op->data.nbytes, op->data.buf.in);
35162306a36Sopenharmony_ci	} else {
35262306a36Sopenharmony_ci		if (!op->addr.nbytes)
35362306a36Sopenharmony_ci			ret = aspeed_spi_write_reg(chip, op);
35462306a36Sopenharmony_ci		else
35562306a36Sopenharmony_ci			ret = aspeed_spi_write_user(chip, op);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* Restore defaults */
35962306a36Sopenharmony_ci	if (addr_mode != addr_mode_backup)
36062306a36Sopenharmony_ci		writel(addr_mode_backup, aspi->regs + CE_CTRL_REG);
36162306a36Sopenharmony_ci	writel(chip->ctl_val[ASPEED_SPI_READ], chip->ctl);
36262306a36Sopenharmony_ci	return ret;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	int ret;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	ret = do_aspeed_spi_exec_op(mem, op);
37062306a36Sopenharmony_ci	if (ret)
37162306a36Sopenharmony_ci		dev_err(&mem->spi->dev, "operation failed: %d\n", ret);
37262306a36Sopenharmony_ci	return ret;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic const char *aspeed_spi_get_name(struct spi_mem *mem)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->controller);
37862306a36Sopenharmony_ci	struct device *dev = aspi->dev;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
38162306a36Sopenharmony_ci			      spi_get_chipselect(mem->spi, 0));
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistruct aspeed_spi_window {
38562306a36Sopenharmony_ci	u32 cs;
38662306a36Sopenharmony_ci	u32 offset;
38762306a36Sopenharmony_ci	u32 size;
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void aspeed_spi_get_windows(struct aspeed_spi *aspi,
39162306a36Sopenharmony_ci				   struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS])
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	const struct aspeed_spi_data *data = aspi->data;
39462306a36Sopenharmony_ci	u32 reg_val;
39562306a36Sopenharmony_ci	u32 cs;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	for (cs = 0; cs < aspi->data->max_cs; cs++) {
39862306a36Sopenharmony_ci		reg_val = readl(aspi->regs + CE0_SEGMENT_ADDR_REG + cs * 4);
39962306a36Sopenharmony_ci		windows[cs].cs = cs;
40062306a36Sopenharmony_ci		windows[cs].size = data->segment_end(aspi, reg_val) -
40162306a36Sopenharmony_ci			data->segment_start(aspi, reg_val);
40262306a36Sopenharmony_ci		windows[cs].offset = data->segment_start(aspi, reg_val) - aspi->ahb_base_phy;
40362306a36Sopenharmony_ci		dev_vdbg(aspi->dev, "CE%d offset=0x%.8x size=0x%x\n", cs,
40462306a36Sopenharmony_ci			 windows[cs].offset, windows[cs].size);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci/*
40962306a36Sopenharmony_ci * On the AST2600, some CE windows are closed by default at reset but
41062306a36Sopenharmony_ci * U-Boot should open all.
41162306a36Sopenharmony_ci */
41262306a36Sopenharmony_cistatic int aspeed_spi_chip_set_default_window(struct aspeed_spi_chip *chip)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct aspeed_spi *aspi = chip->aspi;
41562306a36Sopenharmony_ci	struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS] = { 0 };
41662306a36Sopenharmony_ci	struct aspeed_spi_window *win = &windows[chip->cs];
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* No segment registers for the AST2400 SPI controller */
41962306a36Sopenharmony_ci	if (aspi->data == &ast2400_spi_data) {
42062306a36Sopenharmony_ci		win->offset = 0;
42162306a36Sopenharmony_ci		win->size = aspi->ahb_window_size;
42262306a36Sopenharmony_ci	} else {
42362306a36Sopenharmony_ci		aspeed_spi_get_windows(aspi, windows);
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	chip->ahb_base = aspi->ahb_base + win->offset;
42762306a36Sopenharmony_ci	chip->ahb_window_size = win->size;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	dev_dbg(aspi->dev, "CE%d default window [ 0x%.8x - 0x%.8x ] %dMB",
43062306a36Sopenharmony_ci		chip->cs, aspi->ahb_base_phy + win->offset,
43162306a36Sopenharmony_ci		aspi->ahb_base_phy + win->offset + win->size - 1,
43262306a36Sopenharmony_ci		win->size >> 20);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return chip->ahb_window_size ? 0 : -1;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int aspeed_spi_set_window(struct aspeed_spi *aspi,
43862306a36Sopenharmony_ci				 const struct aspeed_spi_window *win)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	u32 start = aspi->ahb_base_phy + win->offset;
44162306a36Sopenharmony_ci	u32 end = start + win->size;
44262306a36Sopenharmony_ci	void __iomem *seg_reg = aspi->regs + CE0_SEGMENT_ADDR_REG + win->cs * 4;
44362306a36Sopenharmony_ci	u32 seg_val_backup = readl(seg_reg);
44462306a36Sopenharmony_ci	u32 seg_val = aspi->data->segment_reg(aspi, start, end);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (seg_val == seg_val_backup)
44762306a36Sopenharmony_ci		return 0;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	writel(seg_val, seg_reg);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/*
45262306a36Sopenharmony_ci	 * Restore initial value if something goes wrong else we could
45362306a36Sopenharmony_ci	 * loose access to the chip.
45462306a36Sopenharmony_ci	 */
45562306a36Sopenharmony_ci	if (seg_val != readl(seg_reg)) {
45662306a36Sopenharmony_ci		dev_err(aspi->dev, "CE%d invalid window [ 0x%.8x - 0x%.8x ] %dMB",
45762306a36Sopenharmony_ci			win->cs, start, end - 1, win->size >> 20);
45862306a36Sopenharmony_ci		writel(seg_val_backup, seg_reg);
45962306a36Sopenharmony_ci		return -EIO;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (win->size)
46362306a36Sopenharmony_ci		dev_dbg(aspi->dev, "CE%d new window [ 0x%.8x - 0x%.8x ] %dMB",
46462306a36Sopenharmony_ci			win->cs, start, end - 1,  win->size >> 20);
46562306a36Sopenharmony_ci	else
46662306a36Sopenharmony_ci		dev_dbg(aspi->dev, "CE%d window closed", win->cs);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	return 0;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci/*
47262306a36Sopenharmony_ci * Yet to be done when possible :
47362306a36Sopenharmony_ci * - Align mappings on flash size (we don't have the info)
47462306a36Sopenharmony_ci * - ioremap each window, not strictly necessary since the overall window
47562306a36Sopenharmony_ci *   is correct.
47662306a36Sopenharmony_ci */
47762306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2500_spi_data;
47862306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2600_spi_data;
47962306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2600_fmc_data;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
48262306a36Sopenharmony_ci					 u32 local_offset, u32 size)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct aspeed_spi *aspi = chip->aspi;
48562306a36Sopenharmony_ci	struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS] = { 0 };
48662306a36Sopenharmony_ci	struct aspeed_spi_window *win = &windows[chip->cs];
48762306a36Sopenharmony_ci	int ret;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* No segment registers for the AST2400 SPI controller */
49062306a36Sopenharmony_ci	if (aspi->data == &ast2400_spi_data)
49162306a36Sopenharmony_ci		return 0;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	/*
49462306a36Sopenharmony_ci	 * Due to an HW issue on the AST2500 SPI controller, the CE0
49562306a36Sopenharmony_ci	 * window size should be smaller than the maximum 128MB.
49662306a36Sopenharmony_ci	 */
49762306a36Sopenharmony_ci	if (aspi->data == &ast2500_spi_data && chip->cs == 0 && size == SZ_128M) {
49862306a36Sopenharmony_ci		size = 120 << 20;
49962306a36Sopenharmony_ci		dev_info(aspi->dev, "CE%d window resized to %dMB (AST2500 HW quirk)",
50062306a36Sopenharmony_ci			 chip->cs, size >> 20);
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/*
50462306a36Sopenharmony_ci	 * The decoding size of AST2600 SPI controller should set at
50562306a36Sopenharmony_ci	 * least 2MB.
50662306a36Sopenharmony_ci	 */
50762306a36Sopenharmony_ci	if ((aspi->data == &ast2600_spi_data || aspi->data == &ast2600_fmc_data) &&
50862306a36Sopenharmony_ci	    size < SZ_2M) {
50962306a36Sopenharmony_ci		size = SZ_2M;
51062306a36Sopenharmony_ci		dev_info(aspi->dev, "CE%d window resized to %dMB (AST2600 Decoding)",
51162306a36Sopenharmony_ci			 chip->cs, size >> 20);
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	aspeed_spi_get_windows(aspi, windows);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* Adjust this chip window */
51762306a36Sopenharmony_ci	win->offset += local_offset;
51862306a36Sopenharmony_ci	win->size = size;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (win->offset + win->size > aspi->ahb_window_size) {
52162306a36Sopenharmony_ci		win->size = aspi->ahb_window_size - win->offset;
52262306a36Sopenharmony_ci		dev_warn(aspi->dev, "CE%d window resized to %dMB", chip->cs, win->size >> 20);
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	ret = aspeed_spi_set_window(aspi, win);
52662306a36Sopenharmony_ci	if (ret)
52762306a36Sopenharmony_ci		return ret;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* Update chip mapping info */
53062306a36Sopenharmony_ci	chip->ahb_base = aspi->ahb_base + win->offset;
53162306a36Sopenharmony_ci	chip->ahb_window_size = win->size;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/*
53462306a36Sopenharmony_ci	 * Also adjust next chip window to make sure that it does not
53562306a36Sopenharmony_ci	 * overlap with the current window.
53662306a36Sopenharmony_ci	 */
53762306a36Sopenharmony_ci	if (chip->cs < aspi->data->max_cs - 1) {
53862306a36Sopenharmony_ci		struct aspeed_spi_window *next = &windows[chip->cs + 1];
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		/* Change offset and size to keep the same end address */
54162306a36Sopenharmony_ci		if ((next->offset + next->size) > (win->offset + win->size))
54262306a36Sopenharmony_ci			next->size = (next->offset + next->size) - (win->offset + win->size);
54362306a36Sopenharmony_ci		else
54462306a36Sopenharmony_ci			next->size = 0;
54562306a36Sopenharmony_ci		next->offset = win->offset + win->size;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		aspeed_spi_set_window(aspi, next);
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci	return 0;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller);
55762306a36Sopenharmony_ci	struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)];
55862306a36Sopenharmony_ci	struct spi_mem_op *op = &desc->info.op_tmpl;
55962306a36Sopenharmony_ci	u32 ctl_val;
56062306a36Sopenharmony_ci	int ret = 0;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	dev_dbg(aspi->dev,
56362306a36Sopenharmony_ci		"CE%d %s dirmap [ 0x%.8llx - 0x%.8llx ] OP %#x mode:%d.%d.%d.%d naddr:%#x ndummies:%#x\n",
56462306a36Sopenharmony_ci		chip->cs, op->data.dir == SPI_MEM_DATA_IN ? "read" : "write",
56562306a36Sopenharmony_ci		desc->info.offset, desc->info.offset + desc->info.length,
56662306a36Sopenharmony_ci		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
56762306a36Sopenharmony_ci		op->dummy.buswidth, op->data.buswidth,
56862306a36Sopenharmony_ci		op->addr.nbytes, op->dummy.nbytes);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	chip->clk_freq = desc->mem->spi->max_speed_hz;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* Only for reads */
57362306a36Sopenharmony_ci	if (op->data.dir != SPI_MEM_DATA_IN)
57462306a36Sopenharmony_ci		return -EOPNOTSUPP;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	aspeed_spi_chip_adjust_window(chip, desc->info.offset, desc->info.length);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (desc->info.length > chip->ahb_window_size)
57962306a36Sopenharmony_ci		dev_warn(aspi->dev, "CE%d window (%dMB) too small for mapping",
58062306a36Sopenharmony_ci			 chip->cs, chip->ahb_window_size >> 20);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* Define the default IO read settings */
58362306a36Sopenharmony_ci	ctl_val = readl(chip->ctl) & ~CTRL_IO_CMD_MASK;
58462306a36Sopenharmony_ci	ctl_val |= aspeed_spi_get_io_mode(op) |
58562306a36Sopenharmony_ci		op->cmd.opcode << CTRL_COMMAND_SHIFT |
58662306a36Sopenharmony_ci		CTRL_IO_MODE_READ;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (op->dummy.nbytes)
58962306a36Sopenharmony_ci		ctl_val |= CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* Tune 4BYTE address mode */
59262306a36Sopenharmony_ci	if (op->addr.nbytes) {
59362306a36Sopenharmony_ci		u32 addr_mode = readl(aspi->regs + CE_CTRL_REG);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci		if (op->addr.nbytes == 4)
59662306a36Sopenharmony_ci			addr_mode |= (0x11 << chip->cs);
59762306a36Sopenharmony_ci		else
59862306a36Sopenharmony_ci			addr_mode &= ~(0x11 << chip->cs);
59962306a36Sopenharmony_ci		writel(addr_mode, aspi->regs + CE_CTRL_REG);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		/* AST2400 SPI controller sets 4BYTE address mode in
60262306a36Sopenharmony_ci		 * CE0 Control Register
60362306a36Sopenharmony_ci		 */
60462306a36Sopenharmony_ci		if (op->addr.nbytes == 4 && chip->aspi->data == &ast2400_spi_data)
60562306a36Sopenharmony_ci			ctl_val |= CTRL_IO_ADDRESS_4B;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* READ mode is the controller default setting */
60962306a36Sopenharmony_ci	chip->ctl_val[ASPEED_SPI_READ] = ctl_val;
61062306a36Sopenharmony_ci	writel(chip->ctl_val[ASPEED_SPI_READ], chip->ctl);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	ret = aspeed_spi_do_calibration(chip);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	dev_info(aspi->dev, "CE%d read buswidth:%d [0x%08x]\n",
61562306a36Sopenharmony_ci		 chip->cs, op->data.buswidth, chip->ctl_val[ASPEED_SPI_READ]);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return ret;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
62162306a36Sopenharmony_ci				      u64 offset, size_t len, void *buf)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller);
62462306a36Sopenharmony_ci	struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)];
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* Switch to USER command mode if mapping window is too small */
62762306a36Sopenharmony_ci	if (chip->ahb_window_size < offset + len) {
62862306a36Sopenharmony_ci		int ret;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		ret = aspeed_spi_read_user(chip, &desc->info.op_tmpl, offset, len, buf);
63162306a36Sopenharmony_ci		if (ret < 0)
63262306a36Sopenharmony_ci			return ret;
63362306a36Sopenharmony_ci	} else {
63462306a36Sopenharmony_ci		memcpy_fromio(buf, chip->ahb_base + offset, len);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return len;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic const struct spi_controller_mem_ops aspeed_spi_mem_ops = {
64162306a36Sopenharmony_ci	.supports_op = aspeed_spi_supports_op,
64262306a36Sopenharmony_ci	.exec_op = aspeed_spi_exec_op,
64362306a36Sopenharmony_ci	.get_name = aspeed_spi_get_name,
64462306a36Sopenharmony_ci	.dirmap_create = aspeed_spi_dirmap_create,
64562306a36Sopenharmony_ci	.dirmap_read = aspeed_spi_dirmap_read,
64662306a36Sopenharmony_ci};
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void aspeed_spi_chip_set_type(struct aspeed_spi *aspi, unsigned int cs, int type)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	u32 reg;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	reg = readl(aspi->regs + CONFIG_REG);
65362306a36Sopenharmony_ci	reg &= ~(0x3 << (cs * 2));
65462306a36Sopenharmony_ci	reg |= type << (cs * 2);
65562306a36Sopenharmony_ci	writel(reg, aspi->regs + CONFIG_REG);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic void aspeed_spi_chip_enable(struct aspeed_spi *aspi, unsigned int cs, bool enable)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	u32 we_bit = BIT(aspi->data->we0 + cs);
66162306a36Sopenharmony_ci	u32 reg = readl(aspi->regs + CONFIG_REG);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	if (enable)
66462306a36Sopenharmony_ci		reg |= we_bit;
66562306a36Sopenharmony_ci	else
66662306a36Sopenharmony_ci		reg &= ~we_bit;
66762306a36Sopenharmony_ci	writel(reg, aspi->regs + CONFIG_REG);
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int aspeed_spi_setup(struct spi_device *spi)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	struct aspeed_spi *aspi = spi_controller_get_devdata(spi->controller);
67362306a36Sopenharmony_ci	const struct aspeed_spi_data *data = aspi->data;
67462306a36Sopenharmony_ci	unsigned int cs = spi_get_chipselect(spi, 0);
67562306a36Sopenharmony_ci	struct aspeed_spi_chip *chip = &aspi->chips[cs];
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	chip->aspi = aspi;
67862306a36Sopenharmony_ci	chip->cs = cs;
67962306a36Sopenharmony_ci	chip->ctl = aspi->regs + data->ctl0 + cs * 4;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	/* The driver only supports SPI type flash */
68262306a36Sopenharmony_ci	if (data->hastype)
68362306a36Sopenharmony_ci		aspeed_spi_chip_set_type(aspi, cs, CONFIG_TYPE_SPI);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (aspeed_spi_chip_set_default_window(chip) < 0) {
68662306a36Sopenharmony_ci		dev_warn(aspi->dev, "CE%d window invalid", cs);
68762306a36Sopenharmony_ci		return -EINVAL;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	aspeed_spi_chip_enable(aspi, cs, true);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	chip->ctl_val[ASPEED_SPI_BASE] = CTRL_CE_STOP_ACTIVE | CTRL_IO_MODE_USER;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	dev_dbg(aspi->dev, "CE%d setup done\n", cs);
69562306a36Sopenharmony_ci	return 0;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic void aspeed_spi_cleanup(struct spi_device *spi)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct aspeed_spi *aspi = spi_controller_get_devdata(spi->controller);
70162306a36Sopenharmony_ci	unsigned int cs = spi_get_chipselect(spi, 0);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	aspeed_spi_chip_enable(aspi, cs, false);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	dev_dbg(aspi->dev, "CE%d cleanup done\n", cs);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic void aspeed_spi_enable(struct aspeed_spi *aspi, bool enable)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	int cs;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	for (cs = 0; cs < aspi->data->max_cs; cs++)
71362306a36Sopenharmony_ci		aspeed_spi_chip_enable(aspi, cs, enable);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int aspeed_spi_probe(struct platform_device *pdev)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
71962306a36Sopenharmony_ci	const struct aspeed_spi_data *data;
72062306a36Sopenharmony_ci	struct spi_controller *ctlr;
72162306a36Sopenharmony_ci	struct aspeed_spi *aspi;
72262306a36Sopenharmony_ci	struct resource *res;
72362306a36Sopenharmony_ci	int ret;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	data = of_device_get_match_data(&pdev->dev);
72662306a36Sopenharmony_ci	if (!data)
72762306a36Sopenharmony_ci		return -ENODEV;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	ctlr = devm_spi_alloc_host(dev, sizeof(*aspi));
73062306a36Sopenharmony_ci	if (!ctlr)
73162306a36Sopenharmony_ci		return -ENOMEM;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	aspi = spi_controller_get_devdata(ctlr);
73462306a36Sopenharmony_ci	platform_set_drvdata(pdev, aspi);
73562306a36Sopenharmony_ci	aspi->data = data;
73662306a36Sopenharmony_ci	aspi->dev = dev;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	aspi->regs = devm_platform_ioremap_resource(pdev, 0);
73962306a36Sopenharmony_ci	if (IS_ERR(aspi->regs))
74062306a36Sopenharmony_ci		return PTR_ERR(aspi->regs);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	aspi->ahb_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
74362306a36Sopenharmony_ci	if (IS_ERR(aspi->ahb_base)) {
74462306a36Sopenharmony_ci		dev_err(dev, "missing AHB mapping window\n");
74562306a36Sopenharmony_ci		return PTR_ERR(aspi->ahb_base);
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	aspi->ahb_window_size = resource_size(res);
74962306a36Sopenharmony_ci	aspi->ahb_base_phy = res->start;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	aspi->clk = devm_clk_get(&pdev->dev, NULL);
75262306a36Sopenharmony_ci	if (IS_ERR(aspi->clk)) {
75362306a36Sopenharmony_ci		dev_err(dev, "missing clock\n");
75462306a36Sopenharmony_ci		return PTR_ERR(aspi->clk);
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	aspi->clk_freq = clk_get_rate(aspi->clk);
75862306a36Sopenharmony_ci	if (!aspi->clk_freq) {
75962306a36Sopenharmony_ci		dev_err(dev, "invalid clock\n");
76062306a36Sopenharmony_ci		return -EINVAL;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	ret = clk_prepare_enable(aspi->clk);
76462306a36Sopenharmony_ci	if (ret) {
76562306a36Sopenharmony_ci		dev_err(dev, "can not enable the clock\n");
76662306a36Sopenharmony_ci		return ret;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* IRQ is for DMA, which the driver doesn't support yet */
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	ctlr->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | data->mode_bits;
77262306a36Sopenharmony_ci	ctlr->bus_num = pdev->id;
77362306a36Sopenharmony_ci	ctlr->mem_ops = &aspeed_spi_mem_ops;
77462306a36Sopenharmony_ci	ctlr->setup = aspeed_spi_setup;
77562306a36Sopenharmony_ci	ctlr->cleanup = aspeed_spi_cleanup;
77662306a36Sopenharmony_ci	ctlr->num_chipselect = data->max_cs;
77762306a36Sopenharmony_ci	ctlr->dev.of_node = dev->of_node;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	ret = devm_spi_register_controller(dev, ctlr);
78062306a36Sopenharmony_ci	if (ret) {
78162306a36Sopenharmony_ci		dev_err(&pdev->dev, "spi_register_controller failed\n");
78262306a36Sopenharmony_ci		goto disable_clk;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci	return 0;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cidisable_clk:
78762306a36Sopenharmony_ci	clk_disable_unprepare(aspi->clk);
78862306a36Sopenharmony_ci	return ret;
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic void aspeed_spi_remove(struct platform_device *pdev)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	struct aspeed_spi *aspi = platform_get_drvdata(pdev);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	aspeed_spi_enable(aspi, false);
79662306a36Sopenharmony_ci	clk_disable_unprepare(aspi->clk);
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci/*
80062306a36Sopenharmony_ci * AHB mappings
80162306a36Sopenharmony_ci */
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci/*
80462306a36Sopenharmony_ci * The Segment Registers of the AST2400 and AST2500 use a 8MB unit.
80562306a36Sopenharmony_ci * The address range is encoded with absolute addresses in the overall
80662306a36Sopenharmony_ci * mapping window.
80762306a36Sopenharmony_ci */
80862306a36Sopenharmony_cistatic u32 aspeed_spi_segment_start(struct aspeed_spi *aspi, u32 reg)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	return ((reg >> 16) & 0xFF) << 23;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistatic u32 aspeed_spi_segment_end(struct aspeed_spi *aspi, u32 reg)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	return ((reg >> 24) & 0xFF) << 23;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, u32 start, u32 end)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	return (((start >> 23) & 0xFF) << 16) | (((end >> 23) & 0xFF) << 24);
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci/*
82462306a36Sopenharmony_ci * The Segment Registers of the AST2600 use a 1MB unit. The address
82562306a36Sopenharmony_ci * range is encoded with offsets in the overall mapping window.
82662306a36Sopenharmony_ci */
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci#define AST2600_SEG_ADDR_MASK 0x0ff00000
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic u32 aspeed_spi_segment_ast2600_start(struct aspeed_spi *aspi,
83162306a36Sopenharmony_ci					    u32 reg)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	u32 start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	return aspi->ahb_base_phy + start_offset;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic u32 aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi,
83962306a36Sopenharmony_ci					  u32 reg)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	u32 end_offset = reg & AST2600_SEG_ADDR_MASK;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	/* segment is disabled */
84462306a36Sopenharmony_ci	if (!end_offset)
84562306a36Sopenharmony_ci		return aspi->ahb_base_phy;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return aspi->ahb_base_phy + end_offset + 0x100000;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic u32 aspeed_spi_segment_ast2600_reg(struct aspeed_spi *aspi,
85162306a36Sopenharmony_ci					  u32 start, u32 end)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	/* disable zero size segments */
85462306a36Sopenharmony_ci	if (start == end)
85562306a36Sopenharmony_ci		return 0;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return ((start & AST2600_SEG_ADDR_MASK) >> 16) |
85862306a36Sopenharmony_ci		((end - 1) & AST2600_SEG_ADDR_MASK);
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci/*
86262306a36Sopenharmony_ci * Read timing compensation sequences
86362306a36Sopenharmony_ci */
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci#define CALIBRATE_BUF_SIZE SZ_16K
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic bool aspeed_spi_check_reads(struct aspeed_spi_chip *chip,
86862306a36Sopenharmony_ci				   const u8 *golden_buf, u8 *test_buf)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	int i;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
87362306a36Sopenharmony_ci		memcpy_fromio(test_buf, chip->ahb_base, CALIBRATE_BUF_SIZE);
87462306a36Sopenharmony_ci		if (memcmp(test_buf, golden_buf, CALIBRATE_BUF_SIZE) != 0) {
87562306a36Sopenharmony_ci#if defined(VERBOSE_DEBUG)
87662306a36Sopenharmony_ci			print_hex_dump_bytes(DEVICE_NAME "  fail: ", DUMP_PREFIX_NONE,
87762306a36Sopenharmony_ci					     test_buf, 0x100);
87862306a36Sopenharmony_ci#endif
87962306a36Sopenharmony_ci			return false;
88062306a36Sopenharmony_ci		}
88162306a36Sopenharmony_ci	}
88262306a36Sopenharmony_ci	return true;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci#define FREAD_TPASS(i)	(((i) / 2) | (((i) & 1) ? 0 : 8))
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci/*
88862306a36Sopenharmony_ci * The timing register is shared by all devices. Only update for CE0.
88962306a36Sopenharmony_ci */
89062306a36Sopenharmony_cistatic int aspeed_spi_calibrate(struct aspeed_spi_chip *chip, u32 hdiv,
89162306a36Sopenharmony_ci				const u8 *golden_buf, u8 *test_buf)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	struct aspeed_spi *aspi = chip->aspi;
89462306a36Sopenharmony_ci	const struct aspeed_spi_data *data = aspi->data;
89562306a36Sopenharmony_ci	int i;
89662306a36Sopenharmony_ci	int good_pass = -1, pass_count = 0;
89762306a36Sopenharmony_ci	u32 shift = (hdiv - 1) << 2;
89862306a36Sopenharmony_ci	u32 mask = ~(0xfu << shift);
89962306a36Sopenharmony_ci	u32 fread_timing_val = 0;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	/* Try HCLK delay 0..5, each one with/without delay and look for a
90262306a36Sopenharmony_ci	 * good pair.
90362306a36Sopenharmony_ci	 */
90462306a36Sopenharmony_ci	for (i = 0; i < 12; i++) {
90562306a36Sopenharmony_ci		bool pass;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci		if (chip->cs == 0) {
90862306a36Sopenharmony_ci			fread_timing_val &= mask;
90962306a36Sopenharmony_ci			fread_timing_val |= FREAD_TPASS(i) << shift;
91062306a36Sopenharmony_ci			writel(fread_timing_val, aspi->regs + data->timing);
91162306a36Sopenharmony_ci		}
91262306a36Sopenharmony_ci		pass = aspeed_spi_check_reads(chip, golden_buf, test_buf);
91362306a36Sopenharmony_ci		dev_dbg(aspi->dev,
91462306a36Sopenharmony_ci			"  * [%08x] %d HCLK delay, %dns DI delay : %s",
91562306a36Sopenharmony_ci			fread_timing_val, i / 2, (i & 1) ? 0 : 4,
91662306a36Sopenharmony_ci			pass ? "PASS" : "FAIL");
91762306a36Sopenharmony_ci		if (pass) {
91862306a36Sopenharmony_ci			pass_count++;
91962306a36Sopenharmony_ci			if (pass_count == 3) {
92062306a36Sopenharmony_ci				good_pass = i - 1;
92162306a36Sopenharmony_ci				break;
92262306a36Sopenharmony_ci			}
92362306a36Sopenharmony_ci		} else {
92462306a36Sopenharmony_ci			pass_count = 0;
92562306a36Sopenharmony_ci		}
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	/* No good setting for this frequency */
92962306a36Sopenharmony_ci	if (good_pass < 0)
93062306a36Sopenharmony_ci		return -1;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	/* We have at least one pass of margin, let's use first pass */
93362306a36Sopenharmony_ci	if (chip->cs == 0) {
93462306a36Sopenharmony_ci		fread_timing_val &= mask;
93562306a36Sopenharmony_ci		fread_timing_val |= FREAD_TPASS(good_pass) << shift;
93662306a36Sopenharmony_ci		writel(fread_timing_val, aspi->regs + data->timing);
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci	dev_dbg(aspi->dev, " * -> good is pass %d [0x%08x]",
93962306a36Sopenharmony_ci		good_pass, fread_timing_val);
94062306a36Sopenharmony_ci	return 0;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic bool aspeed_spi_check_calib_data(const u8 *test_buf, u32 size)
94462306a36Sopenharmony_ci{
94562306a36Sopenharmony_ci	const u32 *tb32 = (const u32 *)test_buf;
94662306a36Sopenharmony_ci	u32 i, cnt = 0;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	/* We check if we have enough words that are neither all 0
94962306a36Sopenharmony_ci	 * nor all 1's so the calibration can be considered valid.
95062306a36Sopenharmony_ci	 *
95162306a36Sopenharmony_ci	 * I use an arbitrary threshold for now of 64
95262306a36Sopenharmony_ci	 */
95362306a36Sopenharmony_ci	size >>= 2;
95462306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
95562306a36Sopenharmony_ci		if (tb32[i] != 0 && tb32[i] != 0xffffffff)
95662306a36Sopenharmony_ci			cnt++;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci	return cnt >= 64;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic const u32 aspeed_spi_hclk_divs[] = {
96262306a36Sopenharmony_ci	0xf, /* HCLK */
96362306a36Sopenharmony_ci	0x7, /* HCLK/2 */
96462306a36Sopenharmony_ci	0xe, /* HCLK/3 */
96562306a36Sopenharmony_ci	0x6, /* HCLK/4 */
96662306a36Sopenharmony_ci	0xd, /* HCLK/5 */
96762306a36Sopenharmony_ci};
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci#define ASPEED_SPI_HCLK_DIV(i) \
97062306a36Sopenharmony_ci	(aspeed_spi_hclk_divs[(i) - 1] << CTRL_FREQ_SEL_SHIFT)
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_cistatic int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	struct aspeed_spi *aspi = chip->aspi;
97562306a36Sopenharmony_ci	const struct aspeed_spi_data *data = aspi->data;
97662306a36Sopenharmony_ci	u32 ahb_freq = aspi->clk_freq;
97762306a36Sopenharmony_ci	u32 max_freq = chip->clk_freq;
97862306a36Sopenharmony_ci	u32 ctl_val;
97962306a36Sopenharmony_ci	u8 *golden_buf = NULL;
98062306a36Sopenharmony_ci	u8 *test_buf = NULL;
98162306a36Sopenharmony_ci	int i, rc, best_div = -1;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	dev_dbg(aspi->dev, "calculate timing compensation - AHB freq: %d MHz",
98462306a36Sopenharmony_ci		ahb_freq / 1000000);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	/*
98762306a36Sopenharmony_ci	 * use the related low frequency to get check calibration data
98862306a36Sopenharmony_ci	 * and get golden data.
98962306a36Sopenharmony_ci	 */
99062306a36Sopenharmony_ci	ctl_val = chip->ctl_val[ASPEED_SPI_READ] & data->hclk_mask;
99162306a36Sopenharmony_ci	writel(ctl_val, chip->ctl);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	test_buf = kzalloc(CALIBRATE_BUF_SIZE * 2, GFP_KERNEL);
99462306a36Sopenharmony_ci	if (!test_buf)
99562306a36Sopenharmony_ci		return -ENOMEM;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	golden_buf = test_buf + CALIBRATE_BUF_SIZE;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	memcpy_fromio(golden_buf, chip->ahb_base, CALIBRATE_BUF_SIZE);
100062306a36Sopenharmony_ci	if (!aspeed_spi_check_calib_data(golden_buf, CALIBRATE_BUF_SIZE)) {
100162306a36Sopenharmony_ci		dev_info(aspi->dev, "Calibration area too uniform, using low speed");
100262306a36Sopenharmony_ci		goto no_calib;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci#if defined(VERBOSE_DEBUG)
100662306a36Sopenharmony_ci	print_hex_dump_bytes(DEVICE_NAME "  good: ", DUMP_PREFIX_NONE,
100762306a36Sopenharmony_ci			     golden_buf, 0x100);
100862306a36Sopenharmony_ci#endif
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/* Now we iterate the HCLK dividers until we find our breaking point */
101162306a36Sopenharmony_ci	for (i = ARRAY_SIZE(aspeed_spi_hclk_divs); i > data->hdiv_max - 1; i--) {
101262306a36Sopenharmony_ci		u32 tv, freq;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		freq = ahb_freq / i;
101562306a36Sopenharmony_ci		if (freq > max_freq)
101662306a36Sopenharmony_ci			continue;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci		/* Set the timing */
101962306a36Sopenharmony_ci		tv = chip->ctl_val[ASPEED_SPI_READ] | ASPEED_SPI_HCLK_DIV(i);
102062306a36Sopenharmony_ci		writel(tv, chip->ctl);
102162306a36Sopenharmony_ci		dev_dbg(aspi->dev, "Trying HCLK/%d [%08x] ...", i, tv);
102262306a36Sopenharmony_ci		rc = data->calibrate(chip, i, golden_buf, test_buf);
102362306a36Sopenharmony_ci		if (rc == 0)
102462306a36Sopenharmony_ci			best_div = i;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	/* Nothing found ? */
102862306a36Sopenharmony_ci	if (best_div < 0) {
102962306a36Sopenharmony_ci		dev_warn(aspi->dev, "No good frequency, using dumb slow");
103062306a36Sopenharmony_ci	} else {
103162306a36Sopenharmony_ci		dev_dbg(aspi->dev, "Found good read timings at HCLK/%d", best_div);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		/* Record the freq */
103462306a36Sopenharmony_ci		for (i = 0; i < ASPEED_SPI_MAX; i++)
103562306a36Sopenharmony_ci			chip->ctl_val[i] = (chip->ctl_val[i] & data->hclk_mask) |
103662306a36Sopenharmony_ci				ASPEED_SPI_HCLK_DIV(best_div);
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cino_calib:
104062306a36Sopenharmony_ci	writel(chip->ctl_val[ASPEED_SPI_READ], chip->ctl);
104162306a36Sopenharmony_ci	kfree(test_buf);
104262306a36Sopenharmony_ci	return 0;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci#define TIMING_DELAY_DI		BIT(3)
104662306a36Sopenharmony_ci#define TIMING_DELAY_HCYCLE_MAX	5
104762306a36Sopenharmony_ci#define TIMING_REG_AST2600(chip)				\
104862306a36Sopenharmony_ci	((chip)->aspi->regs + (chip)->aspi->data->timing +	\
104962306a36Sopenharmony_ci	 (chip)->cs * 4)
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic int aspeed_spi_ast2600_calibrate(struct aspeed_spi_chip *chip, u32 hdiv,
105262306a36Sopenharmony_ci					const u8 *golden_buf, u8 *test_buf)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct aspeed_spi *aspi = chip->aspi;
105562306a36Sopenharmony_ci	int hcycle;
105662306a36Sopenharmony_ci	u32 shift = (hdiv - 2) << 3;
105762306a36Sopenharmony_ci	u32 mask = ~(0xfu << shift);
105862306a36Sopenharmony_ci	u32 fread_timing_val = 0;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) {
106162306a36Sopenharmony_ci		int delay_ns;
106262306a36Sopenharmony_ci		bool pass = false;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci		fread_timing_val &= mask;
106562306a36Sopenharmony_ci		fread_timing_val |= hcycle << shift;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		/* no DI input delay first  */
106862306a36Sopenharmony_ci		writel(fread_timing_val, TIMING_REG_AST2600(chip));
106962306a36Sopenharmony_ci		pass = aspeed_spi_check_reads(chip, golden_buf, test_buf);
107062306a36Sopenharmony_ci		dev_dbg(aspi->dev,
107162306a36Sopenharmony_ci			"  * [%08x] %d HCLK delay, DI delay none : %s",
107262306a36Sopenharmony_ci			fread_timing_val, hcycle, pass ? "PASS" : "FAIL");
107362306a36Sopenharmony_ci		if (pass)
107462306a36Sopenharmony_ci			return 0;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		/* Add DI input delays  */
107762306a36Sopenharmony_ci		fread_timing_val &= mask;
107862306a36Sopenharmony_ci		fread_timing_val |= (TIMING_DELAY_DI | hcycle) << shift;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci		for (delay_ns = 0; delay_ns < 0x10; delay_ns++) {
108162306a36Sopenharmony_ci			fread_timing_val &= ~(0xf << (4 + shift));
108262306a36Sopenharmony_ci			fread_timing_val |= delay_ns << (4 + shift);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci			writel(fread_timing_val, TIMING_REG_AST2600(chip));
108562306a36Sopenharmony_ci			pass = aspeed_spi_check_reads(chip, golden_buf, test_buf);
108662306a36Sopenharmony_ci			dev_dbg(aspi->dev,
108762306a36Sopenharmony_ci				"  * [%08x] %d HCLK delay, DI delay %d.%dns : %s",
108862306a36Sopenharmony_ci				fread_timing_val, hcycle, (delay_ns + 1) / 2,
108962306a36Sopenharmony_ci				(delay_ns + 1) & 1 ? 5 : 5, pass ? "PASS" : "FAIL");
109062306a36Sopenharmony_ci			/*
109162306a36Sopenharmony_ci			 * TODO: This is optimistic. We should look
109262306a36Sopenharmony_ci			 * for a working interval and save the middle
109362306a36Sopenharmony_ci			 * value in the read timing register.
109462306a36Sopenharmony_ci			 */
109562306a36Sopenharmony_ci			if (pass)
109662306a36Sopenharmony_ci				return 0;
109762306a36Sopenharmony_ci		}
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* No good setting for this frequency */
110162306a36Sopenharmony_ci	return -1;
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci/*
110562306a36Sopenharmony_ci * Platform definitions
110662306a36Sopenharmony_ci */
110762306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2400_fmc_data = {
110862306a36Sopenharmony_ci	.max_cs	       = 5,
110962306a36Sopenharmony_ci	.hastype       = true,
111062306a36Sopenharmony_ci	.we0	       = 16,
111162306a36Sopenharmony_ci	.ctl0	       = CE0_CTRL_REG,
111262306a36Sopenharmony_ci	.timing	       = CE0_TIMING_COMPENSATION_REG,
111362306a36Sopenharmony_ci	.hclk_mask     = 0xfffff0ff,
111462306a36Sopenharmony_ci	.hdiv_max      = 1,
111562306a36Sopenharmony_ci	.calibrate     = aspeed_spi_calibrate,
111662306a36Sopenharmony_ci	.segment_start = aspeed_spi_segment_start,
111762306a36Sopenharmony_ci	.segment_end   = aspeed_spi_segment_end,
111862306a36Sopenharmony_ci	.segment_reg   = aspeed_spi_segment_reg,
111962306a36Sopenharmony_ci};
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2400_spi_data = {
112262306a36Sopenharmony_ci	.max_cs	       = 1,
112362306a36Sopenharmony_ci	.hastype       = false,
112462306a36Sopenharmony_ci	.we0	       = 0,
112562306a36Sopenharmony_ci	.ctl0	       = 0x04,
112662306a36Sopenharmony_ci	.timing	       = 0x14,
112762306a36Sopenharmony_ci	.hclk_mask     = 0xfffff0ff,
112862306a36Sopenharmony_ci	.hdiv_max      = 1,
112962306a36Sopenharmony_ci	.calibrate     = aspeed_spi_calibrate,
113062306a36Sopenharmony_ci	/* No segment registers */
113162306a36Sopenharmony_ci};
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2500_fmc_data = {
113462306a36Sopenharmony_ci	.max_cs	       = 3,
113562306a36Sopenharmony_ci	.hastype       = true,
113662306a36Sopenharmony_ci	.we0	       = 16,
113762306a36Sopenharmony_ci	.ctl0	       = CE0_CTRL_REG,
113862306a36Sopenharmony_ci	.timing	       = CE0_TIMING_COMPENSATION_REG,
113962306a36Sopenharmony_ci	.hclk_mask     = 0xffffd0ff,
114062306a36Sopenharmony_ci	.hdiv_max      = 1,
114162306a36Sopenharmony_ci	.calibrate     = aspeed_spi_calibrate,
114262306a36Sopenharmony_ci	.segment_start = aspeed_spi_segment_start,
114362306a36Sopenharmony_ci	.segment_end   = aspeed_spi_segment_end,
114462306a36Sopenharmony_ci	.segment_reg   = aspeed_spi_segment_reg,
114562306a36Sopenharmony_ci};
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2500_spi_data = {
114862306a36Sopenharmony_ci	.max_cs	       = 2,
114962306a36Sopenharmony_ci	.hastype       = false,
115062306a36Sopenharmony_ci	.we0	       = 16,
115162306a36Sopenharmony_ci	.ctl0	       = CE0_CTRL_REG,
115262306a36Sopenharmony_ci	.timing	       = CE0_TIMING_COMPENSATION_REG,
115362306a36Sopenharmony_ci	.hclk_mask     = 0xffffd0ff,
115462306a36Sopenharmony_ci	.hdiv_max      = 1,
115562306a36Sopenharmony_ci	.calibrate     = aspeed_spi_calibrate,
115662306a36Sopenharmony_ci	.segment_start = aspeed_spi_segment_start,
115762306a36Sopenharmony_ci	.segment_end   = aspeed_spi_segment_end,
115862306a36Sopenharmony_ci	.segment_reg   = aspeed_spi_segment_reg,
115962306a36Sopenharmony_ci};
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2600_fmc_data = {
116262306a36Sopenharmony_ci	.max_cs	       = 3,
116362306a36Sopenharmony_ci	.hastype       = false,
116462306a36Sopenharmony_ci	.mode_bits     = SPI_RX_QUAD | SPI_TX_QUAD,
116562306a36Sopenharmony_ci	.we0	       = 16,
116662306a36Sopenharmony_ci	.ctl0	       = CE0_CTRL_REG,
116762306a36Sopenharmony_ci	.timing	       = CE0_TIMING_COMPENSATION_REG,
116862306a36Sopenharmony_ci	.hclk_mask     = 0xf0fff0ff,
116962306a36Sopenharmony_ci	.hdiv_max      = 2,
117062306a36Sopenharmony_ci	.calibrate     = aspeed_spi_ast2600_calibrate,
117162306a36Sopenharmony_ci	.segment_start = aspeed_spi_segment_ast2600_start,
117262306a36Sopenharmony_ci	.segment_end   = aspeed_spi_segment_ast2600_end,
117362306a36Sopenharmony_ci	.segment_reg   = aspeed_spi_segment_ast2600_reg,
117462306a36Sopenharmony_ci};
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic const struct aspeed_spi_data ast2600_spi_data = {
117762306a36Sopenharmony_ci	.max_cs	       = 2,
117862306a36Sopenharmony_ci	.hastype       = false,
117962306a36Sopenharmony_ci	.mode_bits     = SPI_RX_QUAD | SPI_TX_QUAD,
118062306a36Sopenharmony_ci	.we0	       = 16,
118162306a36Sopenharmony_ci	.ctl0	       = CE0_CTRL_REG,
118262306a36Sopenharmony_ci	.timing	       = CE0_TIMING_COMPENSATION_REG,
118362306a36Sopenharmony_ci	.hclk_mask     = 0xf0fff0ff,
118462306a36Sopenharmony_ci	.hdiv_max      = 2,
118562306a36Sopenharmony_ci	.calibrate     = aspeed_spi_ast2600_calibrate,
118662306a36Sopenharmony_ci	.segment_start = aspeed_spi_segment_ast2600_start,
118762306a36Sopenharmony_ci	.segment_end   = aspeed_spi_segment_ast2600_end,
118862306a36Sopenharmony_ci	.segment_reg   = aspeed_spi_segment_ast2600_reg,
118962306a36Sopenharmony_ci};
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic const struct of_device_id aspeed_spi_matches[] = {
119262306a36Sopenharmony_ci	{ .compatible = "aspeed,ast2400-fmc", .data = &ast2400_fmc_data },
119362306a36Sopenharmony_ci	{ .compatible = "aspeed,ast2400-spi", .data = &ast2400_spi_data },
119462306a36Sopenharmony_ci	{ .compatible = "aspeed,ast2500-fmc", .data = &ast2500_fmc_data },
119562306a36Sopenharmony_ci	{ .compatible = "aspeed,ast2500-spi", .data = &ast2500_spi_data },
119662306a36Sopenharmony_ci	{ .compatible = "aspeed,ast2600-fmc", .data = &ast2600_fmc_data },
119762306a36Sopenharmony_ci	{ .compatible = "aspeed,ast2600-spi", .data = &ast2600_spi_data },
119862306a36Sopenharmony_ci	{ }
119962306a36Sopenharmony_ci};
120062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, aspeed_spi_matches);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic struct platform_driver aspeed_spi_driver = {
120362306a36Sopenharmony_ci	.probe			= aspeed_spi_probe,
120462306a36Sopenharmony_ci	.remove_new		= aspeed_spi_remove,
120562306a36Sopenharmony_ci	.driver	= {
120662306a36Sopenharmony_ci		.name		= DEVICE_NAME,
120762306a36Sopenharmony_ci		.of_match_table = aspeed_spi_matches,
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci};
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cimodule_platform_driver(aspeed_spi_driver);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ciMODULE_DESCRIPTION("ASPEED Static Memory Controller Driver");
121462306a36Sopenharmony_ciMODULE_AUTHOR("Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>");
121562306a36Sopenharmony_ciMODULE_AUTHOR("Cedric Le Goater <clg@kaod.org>");
121662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1217