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