xref: /optee_os/core/drivers/pl022_spi.c (revision bbab0cddf30062d57795452fdd05a54803e3994e)
1aca1545dSVictor Chong /*
2aca1545dSVictor Chong  * Copyright (c) 2016, Linaro Limited
3aca1545dSVictor Chong  * All rights reserved.
4aca1545dSVictor Chong  *
5aca1545dSVictor Chong  * Redistribution and use in source and binary forms, with or without
6aca1545dSVictor Chong  * modification, are permitted provided that the following conditions are met:
7aca1545dSVictor Chong  *
8aca1545dSVictor Chong  * 1. Redistributions of source code must retain the above copyright notice,
9aca1545dSVictor Chong  * this list of conditions and the following disclaimer.
10aca1545dSVictor Chong  *
11aca1545dSVictor Chong  * 2. Redistributions in binary form must reproduce the above copyright notice,
12aca1545dSVictor Chong  * this list of conditions and the following disclaimer in the documentation
13aca1545dSVictor Chong  * and/or other materials provided with the distribution.
14aca1545dSVictor Chong  *
15aca1545dSVictor Chong  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16aca1545dSVictor Chong  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17aca1545dSVictor Chong  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18aca1545dSVictor Chong  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19aca1545dSVictor Chong  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20aca1545dSVictor Chong  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21aca1545dSVictor Chong  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22aca1545dSVictor Chong  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23aca1545dSVictor Chong  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24aca1545dSVictor Chong  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25aca1545dSVictor Chong  * POSSIBILITY OF SUCH DAMAGE.
26aca1545dSVictor Chong  *
27aca1545dSVictor Chong  */
28aca1545dSVictor Chong 
29aca1545dSVictor Chong #include <assert.h>
30aca1545dSVictor Chong #include <drivers/pl022_spi.h>
31aca1545dSVictor Chong #include <gpio.h>
32aca1545dSVictor Chong #include <initcall.h>
33aca1545dSVictor Chong #include <io.h>
34aca1545dSVictor Chong #include <kernel/panic.h>
35aca1545dSVictor Chong #include <kernel/tee_time.h>
36aca1545dSVictor Chong #include <platform_config.h>
37aca1545dSVictor Chong #include <trace.h>
38aca1545dSVictor Chong #include <util.h>
39aca1545dSVictor Chong 
40aca1545dSVictor Chong /* SPI register offsets */
41aca1545dSVictor Chong #define SSPCR0		0x000
42aca1545dSVictor Chong #define SSPCR1		0x004
43aca1545dSVictor Chong #define SSPDR		0x008
44aca1545dSVictor Chong #define SSPSR		0x00C
45aca1545dSVictor Chong #define SSPCPSR		0x010
46aca1545dSVictor Chong #define SSPIMSC		0x014
47aca1545dSVictor Chong #define SSPRIS		0x018
48aca1545dSVictor Chong #define SSPMIS		0x01C
49aca1545dSVictor Chong #define SSPICR		0x020
50aca1545dSVictor Chong #define SSPDMACR	0x024
51aca1545dSVictor Chong 
52aca1545dSVictor Chong #ifdef PLATFORM_hikey
53aca1545dSVictor Chong /* HiKey extensions */
54aca1545dSVictor Chong #define SSPTXFIFOCR	0x028
55aca1545dSVictor Chong #define SSPRXFIFOCR	0x02C
56aca1545dSVictor Chong #define SSPB2BTRANS	0x030
57aca1545dSVictor Chong #endif
58aca1545dSVictor Chong 
59aca1545dSVictor Chong /* test registers */
60aca1545dSVictor Chong #define SSPTCR		0x080
61aca1545dSVictor Chong #define SSPITIP		0x084
62aca1545dSVictor Chong #define SSPITOP		0x088
63aca1545dSVictor Chong #define SSPTDR		0x08C
64aca1545dSVictor Chong 
65aca1545dSVictor Chong #define SSPPeriphID0	0xFE0
66aca1545dSVictor Chong #define SSPPeriphID1	0xFE4
67aca1545dSVictor Chong #define SSPPeriphID2	0xFE8
68aca1545dSVictor Chong #define SSPPeriphID3	0xFEC
69aca1545dSVictor Chong 
70aca1545dSVictor Chong #define SSPPCellID0	0xFF0
71aca1545dSVictor Chong #define SSPPCellID1	0xFF4
72aca1545dSVictor Chong #define SSPPCellID2	0xFF8
73aca1545dSVictor Chong #define SSPPCellID3	0xFFC
74aca1545dSVictor Chong 
75aca1545dSVictor Chong /* SPI register masks */
76aca1545dSVictor Chong #define SSPCR0_SCR		SHIFT_U32(0xFF, 8)
77aca1545dSVictor Chong #define SSPCR0_SPH		SHIFT_U32(1, 7)
78aca1545dSVictor Chong #define SSPCR0_SPH1		SHIFT_U32(1, 7)
79aca1545dSVictor Chong #define SSPCR0_SPH0		SHIFT_U32(0, 7)
80aca1545dSVictor Chong #define SSPCR0_SPO		SHIFT_U32(1, 6)
81aca1545dSVictor Chong #define SSPCR0_SPO1		SHIFT_U32(1, 6)
82aca1545dSVictor Chong #define SSPCR0_SPO0		SHIFT_U32(0, 6)
83aca1545dSVictor Chong #define SSPCR0_FRF		SHIFT_U32(3, 4)
84aca1545dSVictor Chong #define SSPCR0_FRF_SPI		SHIFT_U32(0, 4)
85aca1545dSVictor Chong #define SSPCR0_DSS		SHIFT_U32(0xFF, 0)
86aca1545dSVictor Chong #define SSPCR0_DSS_16BIT	SHIFT_U32(0xF, 0)
87aca1545dSVictor Chong #define SSPCR0_DSS_8BIT		SHIFT_U32(7, 0)
88aca1545dSVictor Chong 
89aca1545dSVictor Chong #define SSPCR1_SOD		SHIFT_U32(1, 3)
90aca1545dSVictor Chong #define SSPCR1_SOD_ENABLE	SHIFT_U32(1, 3)
91aca1545dSVictor Chong #define SSPCR1_SOD_DISABLE	SHIFT_U32(0, 3)
92aca1545dSVictor Chong #define SSPCR1_MS		SHIFT_U32(1, 2)
93aca1545dSVictor Chong #define SSPCR1_MS_SLAVE		SHIFT_U32(1, 2)
94aca1545dSVictor Chong #define SSPCR1_MS_MASTER	SHIFT_U32(0, 2)
95aca1545dSVictor Chong #define SSPCR1_SSE		SHIFT_U32(1, 1)
96aca1545dSVictor Chong #define SSPCR1_SSE_ENABLE	SHIFT_U32(1, 1)
97aca1545dSVictor Chong #define SSPCR1_SSE_DISABLE	SHIFT_U32(0, 1)
98aca1545dSVictor Chong #define SSPCR1_LBM		SHIFT_U32(1, 0)
99aca1545dSVictor Chong #define SSPCR1_LBM_YES		SHIFT_U32(1, 0)
100aca1545dSVictor Chong #define SSPCR1_LBM_NO		SHIFT_U32(0, 0)
101aca1545dSVictor Chong 
102aca1545dSVictor Chong #define SSPDR_DATA	SHIFT_U32(0xFFFF, 0)
103aca1545dSVictor Chong 
104aca1545dSVictor Chong #define SSPSR_BSY	SHIFT_U32(1, 4)
105aca1545dSVictor Chong #define SSPSR_RNF	SHIFT_U32(1, 3)
106aca1545dSVictor Chong #define SSPSR_RNE	SHIFT_U32(1, 2)
107aca1545dSVictor Chong #define SSPSR_TNF	SHIFT_U32(1, 1)
108aca1545dSVictor Chong #define SSPSR_TFE	SHIFT_U32(1, 0)
109aca1545dSVictor Chong 
110aca1545dSVictor Chong #define SSPCPSR_CPSDVR	SHIFT_U32(0xFF, 0)
111aca1545dSVictor Chong 
112aca1545dSVictor Chong #define SSPIMSC_TXIM	SHIFT_U32(1, 3)
113aca1545dSVictor Chong #define SSPIMSC_RXIM	SHIFT_U32(1, 2)
114aca1545dSVictor Chong #define SSPIMSC_RTIM	SHIFT_U32(1, 1)
115aca1545dSVictor Chong #define SSPIMSC_RORIM	SHIFT_U32(1, 0)
116aca1545dSVictor Chong 
117aca1545dSVictor Chong #define SSPRIS_TXRIS	SHIFT_U32(1, 3)
118aca1545dSVictor Chong #define SSPRIS_RXRIS	SHIFT_U32(1, 2)
119aca1545dSVictor Chong #define SSPRIS_RTRIS	SHIFT_U32(1, 1)
120aca1545dSVictor Chong #define SSPRIS_RORRIS	SHIFT_U32(1, 0)
121aca1545dSVictor Chong 
122aca1545dSVictor Chong #define SSPMIS_TXMIS	SHIFT_U32(1, 3)
123aca1545dSVictor Chong #define SSPMIS_RXMIS	SHIFT_U32(1, 2)
124aca1545dSVictor Chong #define SSPMIS_RTMIS	SHIFT_U32(1, 1)
125aca1545dSVictor Chong #define SSPMIS_RORMIS	SHIFT_U32(1, 0)
126aca1545dSVictor Chong 
127aca1545dSVictor Chong #define SSPICR_RTIC	SHIFT_U32(1, 1)
128aca1545dSVictor Chong #define SSPICR_RORIC	SHIFT_U32(1, 0)
129aca1545dSVictor Chong 
130aca1545dSVictor Chong #define SSPDMACR_TXDMAE	SHIFT_U32(1, 1)
131aca1545dSVictor Chong #define SSPDMACR_RXDMAE	SHIFT_U32(1, 0)
132aca1545dSVictor Chong 
133aca1545dSVictor Chong #define SSPPeriphID0_PartNumber0	SHIFT_U32(0xFF, 0) /* 0x22 */
134aca1545dSVictor Chong #define SSPPeriphID1_Designer0		SHIFT_U32(0xF, 4) /* 0x1 */
135aca1545dSVictor Chong #define SSPPeriphID1_PartNumber1	SHIFT_U32(0xF, 0) /* 0x0 */
136aca1545dSVictor Chong #define SSPPeriphID2_Revision		SHIFT_U32(0xF, 4)
137aca1545dSVictor Chong #define SSPPeriphID2_Designer1		SHIFT_U32(0xF, 0) /* 0x4 */
138aca1545dSVictor Chong #define SSPPeriphID3_Configuration	SHIFT_U32(0xFF, 0) /* 0x00 */
139aca1545dSVictor Chong 
140aca1545dSVictor Chong #define SSPPCellID_0	SHIFT_U32(0xFF, 0) /* 0x0D */
141aca1545dSVictor Chong #define SSPPCellID_1	SHIFT_U32(0xFF, 0) /* 0xF0 */
142aca1545dSVictor Chong #define SSPPPCellID_2	SHIFT_U32(0xFF, 0) /* 0x05 */
143aca1545dSVictor Chong #define SSPPPCellID_3	SHIFT_U32(0xFF, 0) /* 0xB1 */
144aca1545dSVictor Chong 
145aca1545dSVictor Chong #define MASK_32 0xFFFFFFFF
146aca1545dSVictor Chong #define MASK_28 0xFFFFFFF
147aca1545dSVictor Chong #define MASK_24 0xFFFFFF
148aca1545dSVictor Chong #define MASK_20 0xFFFFF
149aca1545dSVictor Chong #define MASK_16 0xFFFF
150aca1545dSVictor Chong #define MASK_12 0xFFF
151aca1545dSVictor Chong #define MASK_8 0xFF
152aca1545dSVictor Chong #define MASK_4 0xF
153aca1545dSVictor Chong /* SPI register masks */
154aca1545dSVictor Chong 
155aca1545dSVictor Chong #define SSP_CPSDVR_MAX		254
156aca1545dSVictor Chong #define SSP_CPSDVR_MIN		2
157aca1545dSVictor Chong #define SSP_SCR_MAX		255
158aca1545dSVictor Chong #define SSP_SCR_MIN		0
159aca1545dSVictor Chong #define SSP_DATASIZE_MAX	16
160aca1545dSVictor Chong 
161aca1545dSVictor Chong enum pl022_data_size {
162aca1545dSVictor Chong 	PL022_DATA_SIZE4 = 0x3,
163aca1545dSVictor Chong 	PL022_DATA_SIZE5,
164aca1545dSVictor Chong 	PL022_DATA_SIZE6,
165aca1545dSVictor Chong 	PL022_DATA_SIZE7,
166aca1545dSVictor Chong 	PL022_DATA_SIZE8 = SSPCR0_DSS_8BIT,
167aca1545dSVictor Chong 	PL022_DATA_SIZE9,
168aca1545dSVictor Chong 	PL022_DATA_SIZE10,
169aca1545dSVictor Chong 	PL022_DATA_SIZE11,
170aca1545dSVictor Chong 	PL022_DATA_SIZE12,
171aca1545dSVictor Chong 	PL022_DATA_SIZE13,
172aca1545dSVictor Chong 	PL022_DATA_SIZE14,
173aca1545dSVictor Chong 	PL022_DATA_SIZE15,
174aca1545dSVictor Chong 	PL022_DATA_SIZE16 = SSPCR0_DSS_16BIT
175aca1545dSVictor Chong };
176aca1545dSVictor Chong 
177aca1545dSVictor Chong enum pl022_spi_mode {
178aca1545dSVictor Chong 	PL022_SPI_MODE0 = SSPCR0_SPO0 | SSPCR0_SPH0, /* 0x00 */
179aca1545dSVictor Chong 	PL022_SPI_MODE1 = SSPCR0_SPO0 | SSPCR0_SPH1, /* 0x80 */
180aca1545dSVictor Chong 	PL022_SPI_MODE2 = SSPCR0_SPO1 | SSPCR0_SPH0, /* 0x40 */
181aca1545dSVictor Chong 	PL022_SPI_MODE3 = SSPCR0_SPO1 | SSPCR0_SPH1  /* 0xC0 */
182aca1545dSVictor Chong };
183aca1545dSVictor Chong 
184aca1545dSVictor Chong static void pl022_txrx8(struct spi_chip *chip, uint8_t *wdat,
185aca1545dSVictor Chong 	uint8_t *rdat, size_t num_txpkts, size_t *num_rxpkts)
186aca1545dSVictor Chong {
187aca1545dSVictor Chong 	size_t i = 0;
188aca1545dSVictor Chong 	size_t j = 0;
189aca1545dSVictor Chong 	struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
190aca1545dSVictor Chong 
191*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW);
192aca1545dSVictor Chong 
193aca1545dSVictor Chong 	while (i < num_txpkts) {
194aca1545dSVictor Chong 		if (read8(pd->base + SSPSR) & SSPSR_TNF)
195aca1545dSVictor Chong 			/* tx 1 packet */
196aca1545dSVictor Chong 			write8(wdat[i++], pd->base + SSPDR);
197aca1545dSVictor Chong 	}
198aca1545dSVictor Chong 
199aca1545dSVictor Chong 	do {
200aca1545dSVictor Chong 		while ((read8(pd->base + SSPSR) & SSPSR_RNE) &&
201aca1545dSVictor Chong 			(j < *num_rxpkts))
202aca1545dSVictor Chong 			/* rx 1 packet */
203aca1545dSVictor Chong 			rdat[j++] = read8(pd->base + SSPDR);
204aca1545dSVictor Chong 	} while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts));
205aca1545dSVictor Chong 
206aca1545dSVictor Chong 	*num_rxpkts = j;
207aca1545dSVictor Chong 
208*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH);
209aca1545dSVictor Chong }
210aca1545dSVictor Chong 
211aca1545dSVictor Chong static void pl022_txrx16(struct spi_chip *chip, uint16_t *wdat,
212aca1545dSVictor Chong 	uint16_t *rdat, size_t num_txpkts, size_t *num_rxpkts)
213aca1545dSVictor Chong {
214aca1545dSVictor Chong 	size_t i = 0;
215aca1545dSVictor Chong 	size_t j = 0;
216aca1545dSVictor Chong 	struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
217aca1545dSVictor Chong 
218*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW);
219aca1545dSVictor Chong 
220aca1545dSVictor Chong 	while (i < num_txpkts) {
221aca1545dSVictor Chong 		if (read8(pd->base + SSPSR) & SSPSR_TNF)
222aca1545dSVictor Chong 			/* tx 1 packet */
223aca1545dSVictor Chong 			write16(wdat[i++], pd->base + SSPDR);
224aca1545dSVictor Chong 	}
225aca1545dSVictor Chong 
226aca1545dSVictor Chong 	do {
227aca1545dSVictor Chong 		while ((read8(pd->base + SSPSR) & SSPSR_RNE)
228aca1545dSVictor Chong 			&& (j < *num_rxpkts))
229aca1545dSVictor Chong 			/* rx 1 packet */
230aca1545dSVictor Chong 			rdat[j++] = read16(pd->base + SSPDR);
231aca1545dSVictor Chong 	} while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts));
232aca1545dSVictor Chong 
233aca1545dSVictor Chong 	*num_rxpkts = j;
234aca1545dSVictor Chong 
235*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH);
236aca1545dSVictor Chong }
237aca1545dSVictor Chong 
238aca1545dSVictor Chong static void pl022_tx8(struct spi_chip *chip, uint8_t *wdat,
239aca1545dSVictor Chong 	size_t num_txpkts)
240aca1545dSVictor Chong {
241aca1545dSVictor Chong 	size_t i = 0;
242aca1545dSVictor Chong 	struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
243aca1545dSVictor Chong 
244*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW);
245aca1545dSVictor Chong 
246aca1545dSVictor Chong 	while (i < num_txpkts) {
247aca1545dSVictor Chong 		if (read8(pd->base + SSPSR) & SSPSR_TNF)
248aca1545dSVictor Chong 			/* tx 1 packet */
249aca1545dSVictor Chong 			write8(wdat[i++], pd->base + SSPDR);
250aca1545dSVictor Chong 	}
251aca1545dSVictor Chong 
252*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH);
253aca1545dSVictor Chong }
254aca1545dSVictor Chong 
255aca1545dSVictor Chong static void pl022_tx16(struct spi_chip *chip, uint16_t *wdat,
256aca1545dSVictor Chong 	size_t num_txpkts)
257aca1545dSVictor Chong {
258aca1545dSVictor Chong 	size_t i = 0;
259aca1545dSVictor Chong 	struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
260aca1545dSVictor Chong 
261*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW);
262aca1545dSVictor Chong 
263aca1545dSVictor Chong 	while (i < num_txpkts) {
264aca1545dSVictor Chong 		if (read8(pd->base + SSPSR) & SSPSR_TNF)
265aca1545dSVictor Chong 			/* tx 1 packet */
266aca1545dSVictor Chong 			write16(wdat[i++], pd->base + SSPDR);
267aca1545dSVictor Chong 	}
268aca1545dSVictor Chong 
269*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH);
270aca1545dSVictor Chong }
271aca1545dSVictor Chong 
272aca1545dSVictor Chong static void pl022_rx8(struct spi_chip *chip, uint8_t *rdat,
273aca1545dSVictor Chong 	size_t *num_rxpkts)
274aca1545dSVictor Chong {
275aca1545dSVictor Chong 	size_t j = 0;
276aca1545dSVictor Chong 	struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
277aca1545dSVictor Chong 
278*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW);
279aca1545dSVictor Chong 
280aca1545dSVictor Chong 	do {
281aca1545dSVictor Chong 		while ((read8(pd->base + SSPSR) & SSPSR_RNE) &&
282aca1545dSVictor Chong 			(j < *num_rxpkts))
283aca1545dSVictor Chong 			/* rx 1 packet */
284aca1545dSVictor Chong 			rdat[j++] = read8(pd->base + SSPDR);
285aca1545dSVictor Chong 	} while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts));
286aca1545dSVictor Chong 
287aca1545dSVictor Chong 	*num_rxpkts = j;
288aca1545dSVictor Chong 
289*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH);
290aca1545dSVictor Chong }
291aca1545dSVictor Chong 
292aca1545dSVictor Chong static void pl022_rx16(struct spi_chip *chip, uint16_t *rdat,
293aca1545dSVictor Chong 	size_t *num_rxpkts)
294aca1545dSVictor Chong {
295aca1545dSVictor Chong 	size_t j = 0;
296aca1545dSVictor Chong 	struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
297aca1545dSVictor Chong 
298*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_LOW);
299aca1545dSVictor Chong 
300aca1545dSVictor Chong 	do {
301aca1545dSVictor Chong 		while ((read8(pd->base + SSPSR) & SSPSR_RNE) &&
302aca1545dSVictor Chong 			(j < *num_rxpkts))
303aca1545dSVictor Chong 			/* rx 1 packet */
304aca1545dSVictor Chong 			rdat[j++] = read16(pd->base + SSPDR);
305aca1545dSVictor Chong 	} while ((read8(pd->base + SSPSR) & SSPSR_BSY) && (j < *num_rxpkts));
306aca1545dSVictor Chong 
307aca1545dSVictor Chong 	*num_rxpkts = j;
308aca1545dSVictor Chong 
309*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH);
310aca1545dSVictor Chong }
311aca1545dSVictor Chong 
312aca1545dSVictor Chong static void pl022_print_peri_id(struct pl022_data *pd __maybe_unused)
313aca1545dSVictor Chong {
314aca1545dSVictor Chong 	DMSG("Expected: 0x 22 10 ?4 00");
315aca1545dSVictor Chong 	DMSG("Read: 0x %02x %02x %02x %02x",
316aca1545dSVictor Chong 		read32(pd->base + SSPPeriphID0),
317aca1545dSVictor Chong 		read32(pd->base + SSPPeriphID1),
318aca1545dSVictor Chong 		read32(pd->base + SSPPeriphID2),
319aca1545dSVictor Chong 		read32(pd->base + SSPPeriphID3));
320aca1545dSVictor Chong }
321aca1545dSVictor Chong 
322aca1545dSVictor Chong static void pl022_print_cell_id(struct pl022_data *pd __maybe_unused)
323aca1545dSVictor Chong {
324aca1545dSVictor Chong 	DMSG("Expected: 0x 0d f0 05 b1");
325aca1545dSVictor Chong 	DMSG("Read: 0x %02x %02x %02x %02x",
326aca1545dSVictor Chong 		read32(pd->base + SSPPCellID0),
327aca1545dSVictor Chong 		read32(pd->base + SSPPCellID1),
328aca1545dSVictor Chong 		read32(pd->base + SSPPCellID2),
329aca1545dSVictor Chong 		read32(pd->base + SSPPCellID3));
330aca1545dSVictor Chong }
331aca1545dSVictor Chong 
332aca1545dSVictor Chong static void pl022_sanity_check(struct pl022_data *pd)
333aca1545dSVictor Chong {
334aca1545dSVictor Chong 	assert(pd);
335aca1545dSVictor Chong 	assert(pd->chip.ops);
336*bbab0cddSVictor Chong 	assert(pd->gpio);
337*bbab0cddSVictor Chong 	assert(pd->gpio->ops);
338aca1545dSVictor Chong 	assert(pd->base);
339aca1545dSVictor Chong 	assert(pd->cs_gpio_base);
340aca1545dSVictor Chong 	assert(pd->clk_hz);
341aca1545dSVictor Chong 	assert(pd->speed_hz && pd->speed_hz <= pd->clk_hz/2);
342aca1545dSVictor Chong 	assert(pd->mode <= SPI_MODE3);
343aca1545dSVictor Chong 	assert(pd->data_size_bits == 8 || pd->data_size_bits == 16);
344aca1545dSVictor Chong 
345aca1545dSVictor Chong 	#ifdef PLATFORM_hikey
346aca1545dSVictor Chong 	DMSG("SSPB2BTRANS: Expected: 0x2. Read: 0x%x",
347aca1545dSVictor Chong 		read32(pd->base + SSPB2BTRANS));
348aca1545dSVictor Chong 	#endif
349aca1545dSVictor Chong 	pl022_print_peri_id(pd);
350aca1545dSVictor Chong 	pl022_print_cell_id(pd);
351aca1545dSVictor Chong }
352aca1545dSVictor Chong 
353aca1545dSVictor Chong static inline uint32_t pl022_calc_freq(struct pl022_data *pd,
354aca1545dSVictor Chong 	uint8_t cpsdvr, uint8_t scr)
355aca1545dSVictor Chong {
356aca1545dSVictor Chong 	return pd->clk_hz / (cpsdvr * (1 + scr));
357aca1545dSVictor Chong }
358aca1545dSVictor Chong 
359aca1545dSVictor Chong static void pl022_calc_clk_divisors(struct pl022_data *pd,
360aca1545dSVictor Chong 	uint8_t *cpsdvr, uint8_t *scr)
361aca1545dSVictor Chong {
362aca1545dSVictor Chong 	unsigned int freq1 = 0;
363aca1545dSVictor Chong 	unsigned int freq2 = 0;
364aca1545dSVictor Chong 	uint8_t tmp_cpsdvr1;
365aca1545dSVictor Chong 	uint8_t tmp_scr1;
366aca1545dSVictor Chong 	uint8_t tmp_cpsdvr2 = 0;
367aca1545dSVictor Chong 	uint8_t tmp_scr2 = 0;
368aca1545dSVictor Chong 
369aca1545dSVictor Chong 	for (tmp_scr1 = SSP_SCR_MIN; tmp_scr1 < SSP_SCR_MAX; tmp_scr1++) {
370aca1545dSVictor Chong 		for (tmp_cpsdvr1 = SSP_CPSDVR_MIN; tmp_cpsdvr1 < SSP_CPSDVR_MAX;
371aca1545dSVictor Chong 			tmp_cpsdvr1++) {
372aca1545dSVictor Chong 			freq1 = pl022_calc_freq(pd, tmp_cpsdvr1, tmp_scr1);
373aca1545dSVictor Chong 			if (freq1 == pd->speed_hz)
374aca1545dSVictor Chong 				goto done;
375aca1545dSVictor Chong 			else if (freq1 < pd->speed_hz)
376aca1545dSVictor Chong 				goto stage2;
377aca1545dSVictor Chong 		}
378aca1545dSVictor Chong 	}
379aca1545dSVictor Chong 
380aca1545dSVictor Chong stage2:
381aca1545dSVictor Chong 	for (tmp_cpsdvr2 = SSP_CPSDVR_MIN; tmp_cpsdvr2 < SSP_CPSDVR_MAX;
382aca1545dSVictor Chong 		tmp_cpsdvr2++) {
383aca1545dSVictor Chong 		for (tmp_scr2 = SSP_SCR_MIN; tmp_scr2 < SSP_SCR_MAX;
384aca1545dSVictor Chong 			tmp_scr2++) {
385aca1545dSVictor Chong 			freq2 = pl022_calc_freq(pd, tmp_cpsdvr2, tmp_scr2);
386aca1545dSVictor Chong 			if (freq2 <= pd->speed_hz)
387aca1545dSVictor Chong 				goto done;
388aca1545dSVictor Chong 		}
389aca1545dSVictor Chong 	}
390aca1545dSVictor Chong 
391aca1545dSVictor Chong done:
392aca1545dSVictor Chong 	if (freq1 >= freq2) {
393aca1545dSVictor Chong 		*cpsdvr = tmp_cpsdvr1;
394aca1545dSVictor Chong 		*scr = tmp_scr1;
395aca1545dSVictor Chong 		DMSG("speed: requested: %u, closest1: %u",
396aca1545dSVictor Chong 			pd->speed_hz, freq1);
397aca1545dSVictor Chong 	} else {
398aca1545dSVictor Chong 		*cpsdvr = tmp_cpsdvr2;
399aca1545dSVictor Chong 		*scr = tmp_scr2;
400aca1545dSVictor Chong 		DMSG("speed: requested: %u, closest2: %u",
401aca1545dSVictor Chong 			pd->speed_hz, freq2);
402aca1545dSVictor Chong 	}
403aca1545dSVictor Chong 	DMSG("CPSDVR: %u (0x%x), SCR: %u (0x%x)",
404aca1545dSVictor Chong 		*cpsdvr, *cpsdvr, *scr, *scr);
405aca1545dSVictor Chong }
406aca1545dSVictor Chong 
407aca1545dSVictor Chong static void pl022_flush_fifo(struct pl022_data *pd)
408aca1545dSVictor Chong {
409aca1545dSVictor Chong 	uint32_t __maybe_unused rdat;
410aca1545dSVictor Chong 
411aca1545dSVictor Chong 	do {
412aca1545dSVictor Chong 		while (read32(pd->base + SSPSR) & SSPSR_RNE) {
413aca1545dSVictor Chong 			rdat = read32(pd->base + SSPDR);
414aca1545dSVictor Chong 			DMSG("rdat: 0x%x", rdat);
415aca1545dSVictor Chong 		}
416aca1545dSVictor Chong 	} while (read32(pd->base + SSPSR) & SSPSR_BSY);
417aca1545dSVictor Chong }
418aca1545dSVictor Chong 
419aca1545dSVictor Chong static const struct spi_ops pl022_ops = {
420aca1545dSVictor Chong 	.txrx8 = pl022_txrx8,
421aca1545dSVictor Chong 	.txrx16 = pl022_txrx16,
422aca1545dSVictor Chong 	.tx8 = pl022_tx8,
423aca1545dSVictor Chong 	.tx16 = pl022_tx16,
424aca1545dSVictor Chong 	.rx8 = pl022_rx8,
425aca1545dSVictor Chong 	.rx16 = pl022_rx16,
426aca1545dSVictor Chong };
427aca1545dSVictor Chong 
428aca1545dSVictor Chong void pl022_configure(struct pl022_data *pd)
429aca1545dSVictor Chong {
430aca1545dSVictor Chong 	uint16_t mode;
431aca1545dSVictor Chong 	uint16_t data_size;
432aca1545dSVictor Chong 	uint8_t cpsdvr;
433aca1545dSVictor Chong 	uint8_t scr;
434aca1545dSVictor Chong 	uint8_t lbm;
435aca1545dSVictor Chong 
436aca1545dSVictor Chong 	pd->chip.ops = &pl022_ops;
437aca1545dSVictor Chong 	pl022_sanity_check(pd);
438aca1545dSVictor Chong 	pl022_calc_clk_divisors(pd, &cpsdvr, &scr);
439aca1545dSVictor Chong 
440aca1545dSVictor Chong 	/* configure ssp based on platform settings */
441aca1545dSVictor Chong 	switch (pd->mode) {
442aca1545dSVictor Chong 	case SPI_MODE0:
443aca1545dSVictor Chong 		DMSG("SPI_MODE0");
444aca1545dSVictor Chong 		mode = PL022_SPI_MODE0;
445aca1545dSVictor Chong 		break;
446aca1545dSVictor Chong 	case SPI_MODE1:
447aca1545dSVictor Chong 		DMSG("SPI_MODE1");
448aca1545dSVictor Chong 		mode = PL022_SPI_MODE1;
449aca1545dSVictor Chong 		break;
450aca1545dSVictor Chong 	case SPI_MODE2:
451aca1545dSVictor Chong 		DMSG("SPI_MODE2");
452aca1545dSVictor Chong 		mode = PL022_SPI_MODE2;
453aca1545dSVictor Chong 		break;
454aca1545dSVictor Chong 	case SPI_MODE3:
455aca1545dSVictor Chong 		DMSG("SPI_MODE3");
456aca1545dSVictor Chong 		mode = PL022_SPI_MODE3;
457aca1545dSVictor Chong 		break;
458aca1545dSVictor Chong 	default:
459aca1545dSVictor Chong 		EMSG("Invalid SPI mode: %u", pd->mode);
460aca1545dSVictor Chong 		panic();
461aca1545dSVictor Chong 	}
462aca1545dSVictor Chong 
463aca1545dSVictor Chong 	switch (pd->data_size_bits) {
464aca1545dSVictor Chong 	case 8:
465aca1545dSVictor Chong 		DMSG("Data size: 8");
466aca1545dSVictor Chong 		data_size = PL022_DATA_SIZE8;
467aca1545dSVictor Chong 		break;
468aca1545dSVictor Chong 	case 16:
469aca1545dSVictor Chong 		DMSG("Data size: 16");
470aca1545dSVictor Chong 		data_size = PL022_DATA_SIZE16;
471aca1545dSVictor Chong 		break;
472aca1545dSVictor Chong 	default:
473aca1545dSVictor Chong 		EMSG("Unsupported data size: %u bits", pd->data_size_bits);
474aca1545dSVictor Chong 		panic();
475aca1545dSVictor Chong 	}
476aca1545dSVictor Chong 
477aca1545dSVictor Chong 	if (pd->loopback) {
478aca1545dSVictor Chong 		DMSG("Starting in loopback mode!");
479aca1545dSVictor Chong 		lbm = SSPCR1_LBM_YES;
480aca1545dSVictor Chong 	} else {
481aca1545dSVictor Chong 		DMSG("Starting in regular (non-loopback) mode!");
482aca1545dSVictor Chong 		lbm = SSPCR1_LBM_NO;
483aca1545dSVictor Chong 	}
484aca1545dSVictor Chong 
485aca1545dSVictor Chong 	DMSG("set Serial Clock Rate (SCR), SPI mode (phase and clock)");
486aca1545dSVictor Chong 	DMSG("set frame format (SPI) and data size (8- or 16-bit)");
487aca1545dSVictor Chong 	io_mask16(pd->base + SSPCR0, SHIFT_U32(scr, 8) | mode | SSPCR0_FRF_SPI |
488aca1545dSVictor Chong 		data_size, MASK_16);
489aca1545dSVictor Chong 
490aca1545dSVictor Chong 	DMSG("set master mode, disable SSP, set loopback mode");
491aca1545dSVictor Chong 	io_mask8(pd->base + SSPCR1, SSPCR1_SOD_DISABLE | SSPCR1_MS_MASTER |
492aca1545dSVictor Chong 		SSPCR1_SSE_DISABLE | lbm, MASK_4);
493aca1545dSVictor Chong 
494aca1545dSVictor Chong 	DMSG("set clock prescale");
495aca1545dSVictor Chong 	io_mask8(pd->base + SSPCPSR, cpsdvr, SSPCPSR_CPSDVR);
496aca1545dSVictor Chong 
497aca1545dSVictor Chong 	DMSG("disable interrupts");
498aca1545dSVictor Chong 	io_mask8(pd->base + SSPIMSC, 0, MASK_4);
499aca1545dSVictor Chong 
500aca1545dSVictor Chong 	DMSG("set CS GPIO dir to out");
501*bbab0cddSVictor Chong 	pd->gpio->ops->set_direction(pd->cs_gpio_pin, GPIO_DIR_OUT);
502aca1545dSVictor Chong 
503aca1545dSVictor Chong 	DMSG("pull CS high");
504*bbab0cddSVictor Chong 	pd->gpio->ops->set_value(pd->cs_gpio_pin, GPIO_LEVEL_HIGH);
505aca1545dSVictor Chong }
506aca1545dSVictor Chong 
507aca1545dSVictor Chong void pl022_start(struct pl022_data *pd)
508aca1545dSVictor Chong {
509aca1545dSVictor Chong 	DMSG("empty FIFO before starting");
510aca1545dSVictor Chong 	pl022_flush_fifo(pd);
511aca1545dSVictor Chong 
512aca1545dSVictor Chong 	DMSG("enable SSP");
513aca1545dSVictor Chong 	io_mask8(pd->base + SSPCR1, SSPCR1_SSE_ENABLE, SSPCR1_SSE);
514aca1545dSVictor Chong }
515aca1545dSVictor Chong 
516aca1545dSVictor Chong void pl022_end(struct pl022_data *pd)
517aca1545dSVictor Chong {
518aca1545dSVictor Chong 	/* disable ssp */
519aca1545dSVictor Chong 	io_mask8(pd->base + SSPCR1, SSPCR1_SSE_DISABLE, SSPCR1_SSE);
520aca1545dSVictor Chong }
521aca1545dSVictor Chong 
522