aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mpc85xx/image/spi-loader/drivers/spi/fsl_espi.c
blob: 7e9d8ed11f240bdfa4d3b63c7a4d3015bc5db648 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * eSPI controller driver.
 *
 * Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
 *
 * Based on U-Boot code:
 *
 * Copyright 2010-2011 Freescale Semiconductor, Inc.
 * Copyright 2020 NXP
 * Author: Mingkai Hu (Mingkai.hu@freescale.com)
 *	   Chuanhua Han (chuanhua.han@nxp.com)
 */

#include <io.h>
#include <stdio.h>
#include <spi.h>

/* eSPI Registers */
typedef struct ccsr_espi {
	uint32_t mode;       /* eSPI mode */
	uint32_t event;      /* eSPI event */
	uint32_t mask;       /* eSPI mask */
	uint32_t com;        /* eSPI command */
	uint32_t tx;         /* eSPI transmit FIFO access */
	uint32_t rx;         /* eSPI receive FIFO access */
	uint8_t  res1[8];    /* reserved */
	uint32_t csmode[4];  /* 0x2c: sSPI CS0/1/2/3 mode */
	uint8_t  res2[4048]; /* fill up to 0x1000 */
} ccsr_espi_t;

struct fsl_spi {
	ccsr_espi_t	*espi;
	uint32_t	cs;
	uint32_t	div16;
	uint32_t	pm;
	uint32_t	mode;
};

#define ESPI_MAX_CS_NUM		4
#define ESPI_FIFO_WIDTH_BIT	32

#define ESPI_EV_RNE		BIT(9)
#define ESPI_EV_TNF		BIT(8)
#define ESPI_EV_DON		BIT(14)
#define ESPI_EV_TXE		BIT(15)
#define ESPI_EV_RFCNT_SHIFT	24
#define ESPI_EV_RFCNT_MASK	(0x3f << ESPI_EV_RFCNT_SHIFT)

#define ESPI_MODE_EN		BIT(31)	/* Enable interface */
#define ESPI_MODE_TXTHR(x)	((x) << 8)	/* Tx FIFO threshold */
#define ESPI_MODE_RXTHR(x)	((x) << 0)	/* Rx FIFO threshold */

#define ESPI_COM_CS(x)		((x) << 30)
#define ESPI_COM_TRANLEN(x)	((x) << 0)

#define ESPI_CSMODE_CI_INACTIVEHIGH	BIT(31)
#define ESPI_CSMODE_CP_BEGIN_EDGCLK	BIT(30)
#define ESPI_CSMODE_REV_MSB_FIRST	BIT(29)
#define ESPI_CSMODE_DIV16		BIT(28)
#define ESPI_CSMODE_PM(x)		((x) << 24)
#define ESPI_CSMODE_POL_ASSERTED_LOW	BIT(20)
#define ESPI_CSMODE_LEN(x)		((x) << 16)
#define ESPI_CSMODE_CSBEF(x)		((x) << 12)
#define ESPI_CSMODE_CSAFT(x)		((x) << 8)
#define ESPI_CSMODE_CSCG(x)		((x) << 3)

#define ESPI_CSMODE_INIT_VAL (ESPI_CSMODE_POL_ASSERTED_LOW | \
		ESPI_CSMODE_CSBEF(0) | ESPI_CSMODE_CSAFT(0) | \
		ESPI_CSMODE_CSCG(1))

#define ESPI_MAX_DATA_TRANSFER_LEN 0x10000

static int espi_xfer(struct fsl_spi *fsl, const struct spi_transfer *msg, int n)
{
	ccsr_espi_t *espi = fsl->espi;
	size_t len = spi_message_len(msg, n);

	if (len > ESPI_MAX_DATA_TRANSFER_LEN)
		return -1;

	/* clear the RXCNT and TXCNT */
	out_be32(&espi->mode, in_be32(&espi->mode) & (~ESPI_MODE_EN));
	out_be32(&espi->mode, in_be32(&espi->mode) | ESPI_MODE_EN);
	out_be32(&espi->com, ESPI_COM_CS(fsl->cs) | ESPI_COM_TRANLEN(len - 1));

	int last_msg = n - 1;
	int tx_msg = -1, rx_msg = -1;
	size_t tx_len = 0, rx_len = 0, tx_pos = 0, rx_pos = 0;

	while (true) {
		if (tx_pos == tx_len && tx_msg < last_msg) {
			tx_msg++;
			tx_pos = 0;
			tx_len = msg[tx_msg].len;
		}
		if (rx_pos == rx_len && rx_msg < last_msg) {
			rx_msg++;
			rx_pos = 0;
			rx_len = msg[rx_msg].len;
		}
		if (rx_pos == rx_len)
			break;

		const uint8_t *tx_buf = msg[tx_msg].tx_buf;
		uint8_t *rx_buf = msg[rx_msg].rx_buf;

		uint32_t event = in_be32(&espi->event);

		/* TX */
		if ((event & ESPI_EV_TNF) && tx_len > 0) {
			uint8_t v = 0;
			if (tx_buf)
				v = tx_buf[tx_pos];
			out_8((uint8_t *)&espi->tx, v);
			tx_pos++;
		}

		/* RX */
		if (event & ESPI_EV_RNE) {
			uint8_t v = in_8((uint8_t *)&espi->rx);
			if (rx_buf)
				rx_buf[rx_pos] = v;
			rx_pos++;
		}
	}

	return 0;
}

static void espi_claim_bus(struct fsl_spi *fsl)
{
	ccsr_espi_t *espi = fsl->espi;
	uint32_t csmode;
	int i;

	/* Enable eSPI interface */
	out_be32(&espi->mode, ESPI_MODE_RXTHR(3)
			| ESPI_MODE_TXTHR(4) | ESPI_MODE_EN);

	out_be32(&espi->mask, 0x00000000); /* Mask  all eSPI interrupts */

	/* Init CS mode interface */
	for (i = 0; i < ESPI_MAX_CS_NUM; i++)
		out_be32(&espi->csmode[i], ESPI_CSMODE_INIT_VAL);

	csmode = ESPI_CSMODE_INIT_VAL;

	/* Set eSPI BRG clock source */
	csmode |= ESPI_CSMODE_PM(fsl->pm) | fsl->div16;

	/* Set eSPI mode */
	if (fsl->mode & SPI_CPHA)
		csmode |= ESPI_CSMODE_CP_BEGIN_EDGCLK;
	if (fsl->mode & SPI_CPOL)
		csmode |= ESPI_CSMODE_CI_INACTIVEHIGH;

	/* Character bit order: msb first */
	csmode |= ESPI_CSMODE_REV_MSB_FIRST;

	/* Character length in bits, between 0x3~0xf, i.e. 4bits~16bits */
	csmode |= ESPI_CSMODE_LEN(7);

	out_be32(&espi->csmode[fsl->cs], csmode);
}

static void espi_release_bus(struct fsl_spi *fsl)
{
	/* Disable the SPI hardware */
	out_be32(&fsl->espi->mode,
		in_be32(&fsl->espi->mode) & (~ESPI_MODE_EN));
}

static void espi_setup_spi(struct fsl_spi *fsl, unsigned int max_hz)
{
	unsigned long spibrg;
	uint32_t pm;

	spibrg = CONFIG_FREQ_SYSTEMBUS / 2;
	fsl->div16 = 0;
	if ((spibrg / max_hz) > 32) {
		fsl->div16 = ESPI_CSMODE_DIV16;
		pm = spibrg / (max_hz * 16 * 2);
		if (pm > 16) {
			/* max_hz too low */
			pm = 16;
		}
	} else {
		pm = spibrg / (max_hz * 2);
	}
	if (pm)
		pm--;
	fsl->pm = pm;
}

static struct fsl_spi spi;

int spi_init(unsigned int cs, unsigned int max_hz, unsigned int mode)
{
	if (cs >= ESPI_MAX_CS_NUM)
		return -1;

	spi.espi = (ccsr_espi_t *)CONFIG_SPI_FSL_ESPI_REG_BASE;
	spi.cs = cs;
	spi.mode = mode;

	espi_setup_spi(&spi, max_hz);

	return 0;
}

int spi_claim_bus(void)
{
	espi_claim_bus(&spi);

	return 0;
}

void spi_release_bus(void)
{
	espi_release_bus(&spi);
}

int spi_xfer(const struct spi_transfer *msg, int n)
{
	return espi_xfer(&spi, msg, n);
}

size_t spi_max_xfer(void)
{
	return ESPI_MAX_DATA_TRANSFER_LEN;
}