11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2aca1545dSVictor Chong /*
3aca1545dSVictor Chong * Copyright (c) 2016, Linaro Limited
4aca1545dSVictor Chong *
5aca1545dSVictor Chong */
6aca1545dSVictor Chong
7aca1545dSVictor Chong #include <assert.h>
8aca1545dSVictor Chong #include <drivers/pl022_spi.h>
9aca1545dSVictor Chong #include <initcall.h>
10aca1545dSVictor Chong #include <io.h>
1147c0e86cSVictor Chong #include <keep.h>
12aca1545dSVictor Chong #include <kernel/panic.h>
13aca1545dSVictor Chong #include <kernel/tee_time.h>
14aca1545dSVictor Chong #include <platform_config.h>
15aca1545dSVictor Chong #include <trace.h>
16aca1545dSVictor Chong #include <util.h>
17aca1545dSVictor Chong
18aca1545dSVictor Chong /* SPI register offsets */
19aca1545dSVictor Chong #define SSPCR0 0x000
20aca1545dSVictor Chong #define SSPCR1 0x004
21aca1545dSVictor Chong #define SSPDR 0x008
22aca1545dSVictor Chong #define SSPSR 0x00C
23aca1545dSVictor Chong #define SSPCPSR 0x010
24aca1545dSVictor Chong #define SSPIMSC 0x014
25aca1545dSVictor Chong #define SSPRIS 0x018
26aca1545dSVictor Chong #define SSPMIS 0x01C
27aca1545dSVictor Chong #define SSPICR 0x020
28aca1545dSVictor Chong #define SSPDMACR 0x024
29aca1545dSVictor Chong
30aca1545dSVictor Chong #ifdef PLATFORM_hikey
31aca1545dSVictor Chong /* HiKey extensions */
32aca1545dSVictor Chong #define SSPTXFIFOCR 0x028
33aca1545dSVictor Chong #define SSPRXFIFOCR 0x02C
34aca1545dSVictor Chong #define SSPB2BTRANS 0x030
35aca1545dSVictor Chong #endif
36aca1545dSVictor Chong
37aca1545dSVictor Chong /* test registers */
38aca1545dSVictor Chong #define SSPTCR 0x080
39aca1545dSVictor Chong #define SSPITIP 0x084
40aca1545dSVictor Chong #define SSPITOP 0x088
41aca1545dSVictor Chong #define SSPTDR 0x08C
42aca1545dSVictor Chong
43aca1545dSVictor Chong #define SSPPeriphID0 0xFE0
44aca1545dSVictor Chong #define SSPPeriphID1 0xFE4
45aca1545dSVictor Chong #define SSPPeriphID2 0xFE8
46aca1545dSVictor Chong #define SSPPeriphID3 0xFEC
47aca1545dSVictor Chong
48aca1545dSVictor Chong #define SSPPCellID0 0xFF0
49aca1545dSVictor Chong #define SSPPCellID1 0xFF4
50aca1545dSVictor Chong #define SSPPCellID2 0xFF8
51aca1545dSVictor Chong #define SSPPCellID3 0xFFC
52aca1545dSVictor Chong
53aca1545dSVictor Chong /* SPI register masks */
54aca1545dSVictor Chong #define SSPCR0_SCR SHIFT_U32(0xFF, 8)
55aca1545dSVictor Chong #define SSPCR0_SPH SHIFT_U32(1, 7)
56aca1545dSVictor Chong #define SSPCR0_SPH1 SHIFT_U32(1, 7)
57aca1545dSVictor Chong #define SSPCR0_SPH0 SHIFT_U32(0, 7)
58aca1545dSVictor Chong #define SSPCR0_SPO SHIFT_U32(1, 6)
59aca1545dSVictor Chong #define SSPCR0_SPO1 SHIFT_U32(1, 6)
60aca1545dSVictor Chong #define SSPCR0_SPO0 SHIFT_U32(0, 6)
61aca1545dSVictor Chong #define SSPCR0_FRF SHIFT_U32(3, 4)
62aca1545dSVictor Chong #define SSPCR0_FRF_SPI SHIFT_U32(0, 4)
63aca1545dSVictor Chong #define SSPCR0_DSS SHIFT_U32(0xFF, 0)
64aca1545dSVictor Chong #define SSPCR0_DSS_16BIT SHIFT_U32(0xF, 0)
65aca1545dSVictor Chong #define SSPCR0_DSS_8BIT SHIFT_U32(7, 0)
66aca1545dSVictor Chong
67aca1545dSVictor Chong #define SSPCR1_SOD SHIFT_U32(1, 3)
68aca1545dSVictor Chong #define SSPCR1_SOD_ENABLE SHIFT_U32(1, 3)
69aca1545dSVictor Chong #define SSPCR1_SOD_DISABLE SHIFT_U32(0, 3)
70aca1545dSVictor Chong #define SSPCR1_MS SHIFT_U32(1, 2)
71aca1545dSVictor Chong #define SSPCR1_MS_SLAVE SHIFT_U32(1, 2)
72aca1545dSVictor Chong #define SSPCR1_MS_MASTER SHIFT_U32(0, 2)
73aca1545dSVictor Chong #define SSPCR1_SSE SHIFT_U32(1, 1)
74aca1545dSVictor Chong #define SSPCR1_SSE_ENABLE SHIFT_U32(1, 1)
75aca1545dSVictor Chong #define SSPCR1_SSE_DISABLE SHIFT_U32(0, 1)
76aca1545dSVictor Chong #define SSPCR1_LBM SHIFT_U32(1, 0)
77aca1545dSVictor Chong #define SSPCR1_LBM_YES SHIFT_U32(1, 0)
78aca1545dSVictor Chong #define SSPCR1_LBM_NO SHIFT_U32(0, 0)
79aca1545dSVictor Chong
80aca1545dSVictor Chong #define SSPDR_DATA SHIFT_U32(0xFFFF, 0)
81aca1545dSVictor Chong
82aca1545dSVictor Chong #define SSPSR_BSY SHIFT_U32(1, 4)
83aca1545dSVictor Chong #define SSPSR_RNF SHIFT_U32(1, 3)
84aca1545dSVictor Chong #define SSPSR_RNE SHIFT_U32(1, 2)
85aca1545dSVictor Chong #define SSPSR_TNF SHIFT_U32(1, 1)
86aca1545dSVictor Chong #define SSPSR_TFE SHIFT_U32(1, 0)
87aca1545dSVictor Chong
88aca1545dSVictor Chong #define SSPCPSR_CPSDVR SHIFT_U32(0xFF, 0)
89aca1545dSVictor Chong
90aca1545dSVictor Chong #define SSPIMSC_TXIM SHIFT_U32(1, 3)
91aca1545dSVictor Chong #define SSPIMSC_RXIM SHIFT_U32(1, 2)
92aca1545dSVictor Chong #define SSPIMSC_RTIM SHIFT_U32(1, 1)
93aca1545dSVictor Chong #define SSPIMSC_RORIM SHIFT_U32(1, 0)
94aca1545dSVictor Chong
95aca1545dSVictor Chong #define SSPRIS_TXRIS SHIFT_U32(1, 3)
96aca1545dSVictor Chong #define SSPRIS_RXRIS SHIFT_U32(1, 2)
97aca1545dSVictor Chong #define SSPRIS_RTRIS SHIFT_U32(1, 1)
98aca1545dSVictor Chong #define SSPRIS_RORRIS SHIFT_U32(1, 0)
99aca1545dSVictor Chong
100aca1545dSVictor Chong #define SSPMIS_TXMIS SHIFT_U32(1, 3)
101aca1545dSVictor Chong #define SSPMIS_RXMIS SHIFT_U32(1, 2)
102aca1545dSVictor Chong #define SSPMIS_RTMIS SHIFT_U32(1, 1)
103aca1545dSVictor Chong #define SSPMIS_RORMIS SHIFT_U32(1, 0)
104aca1545dSVictor Chong
105aca1545dSVictor Chong #define SSPICR_RTIC SHIFT_U32(1, 1)
106aca1545dSVictor Chong #define SSPICR_RORIC SHIFT_U32(1, 0)
107aca1545dSVictor Chong
108aca1545dSVictor Chong #define SSPDMACR_TXDMAE SHIFT_U32(1, 1)
109aca1545dSVictor Chong #define SSPDMACR_RXDMAE SHIFT_U32(1, 0)
110aca1545dSVictor Chong
111aca1545dSVictor Chong #define SSPPeriphID0_PartNumber0 SHIFT_U32(0xFF, 0) /* 0x22 */
112aca1545dSVictor Chong #define SSPPeriphID1_Designer0 SHIFT_U32(0xF, 4) /* 0x1 */
113aca1545dSVictor Chong #define SSPPeriphID1_PartNumber1 SHIFT_U32(0xF, 0) /* 0x0 */
114aca1545dSVictor Chong #define SSPPeriphID2_Revision SHIFT_U32(0xF, 4)
115aca1545dSVictor Chong #define SSPPeriphID2_Designer1 SHIFT_U32(0xF, 0) /* 0x4 */
116aca1545dSVictor Chong #define SSPPeriphID3_Configuration SHIFT_U32(0xFF, 0) /* 0x00 */
117aca1545dSVictor Chong
118aca1545dSVictor Chong #define SSPPCellID_0 SHIFT_U32(0xFF, 0) /* 0x0D */
119aca1545dSVictor Chong #define SSPPCellID_1 SHIFT_U32(0xFF, 0) /* 0xF0 */
120aca1545dSVictor Chong #define SSPPPCellID_2 SHIFT_U32(0xFF, 0) /* 0x05 */
121aca1545dSVictor Chong #define SSPPPCellID_3 SHIFT_U32(0xFF, 0) /* 0xB1 */
122aca1545dSVictor Chong
123aca1545dSVictor Chong #define MASK_32 0xFFFFFFFF
124aca1545dSVictor Chong #define MASK_28 0xFFFFFFF
125aca1545dSVictor Chong #define MASK_24 0xFFFFFF
126aca1545dSVictor Chong #define MASK_20 0xFFFFF
127aca1545dSVictor Chong #define MASK_16 0xFFFF
128aca1545dSVictor Chong #define MASK_12 0xFFF
129aca1545dSVictor Chong #define MASK_8 0xFF
130aca1545dSVictor Chong #define MASK_4 0xF
131aca1545dSVictor Chong /* SPI register masks */
132aca1545dSVictor Chong
133aca1545dSVictor Chong #define SSP_CPSDVR_MAX 254
134aca1545dSVictor Chong #define SSP_CPSDVR_MIN 2
135aca1545dSVictor Chong #define SSP_SCR_MAX 255
136aca1545dSVictor Chong #define SSP_SCR_MIN 0
137aca1545dSVictor Chong #define SSP_DATASIZE_MAX 16
138aca1545dSVictor Chong
pl022_txrx8(struct spi_chip * chip,uint8_t * wdat,uint8_t * rdat,size_t num_pkts)1399a2efe04SVictor Chong static enum spi_result pl022_txrx8(struct spi_chip *chip, uint8_t *wdat,
1409a2efe04SVictor Chong uint8_t *rdat, size_t num_pkts)
141aca1545dSVictor Chong {
142aca1545dSVictor Chong size_t i = 0;
143aca1545dSVictor Chong size_t j = 0;
144aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
145aca1545dSVictor Chong
1469a2efe04SVictor Chong
1479a2efe04SVictor Chong if (pd->data_size_bits != 8) {
1489a2efe04SVictor Chong EMSG("data_size_bits should be 8, not %u",
1499a2efe04SVictor Chong pd->data_size_bits);
1509a2efe04SVictor Chong return SPI_ERR_CFG;
1519a2efe04SVictor Chong }
1529a2efe04SVictor Chong
1532ff86f60SVictor Chong if (wdat)
15472057c7cSVictor Chong while (i < num_pkts) {
155918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_TNF) {
156aca1545dSVictor Chong /* tx 1 packet */
157918bb3a5SEtienne Carriere io_write8(pd->base + SSPDR, wdat[i++]);
158aca1545dSVictor Chong }
159aca1545dSVictor Chong
16072057c7cSVictor Chong if (rdat)
161918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_RNE) {
16272057c7cSVictor Chong /* rx 1 packet */
163918bb3a5SEtienne Carriere rdat[j++] = io_read8(pd->base + SSPDR);
16472057c7cSVictor Chong }
16572057c7cSVictor Chong }
16672057c7cSVictor Chong
16772057c7cSVictor Chong /* Capture remaining rdat not read above */
1689a2efe04SVictor Chong if (rdat) {
1699a2efe04SVictor Chong while ((j < num_pkts) &&
170e4b2e43cSVictor Chong (io_read8(pd->base + SSPSR) & SSPSR_RNE)) {
171aca1545dSVictor Chong /* rx 1 packet */
172918bb3a5SEtienne Carriere rdat[j++] = io_read8(pd->base + SSPDR);
1732ff86f60SVictor Chong }
174aca1545dSVictor Chong
1759a2efe04SVictor Chong if (j < num_pkts) {
1769a2efe04SVictor Chong EMSG("Packets requested %zu, received %zu",
1779a2efe04SVictor Chong num_pkts, j);
1789a2efe04SVictor Chong return SPI_ERR_PKTCNT;
1799a2efe04SVictor Chong }
180aca1545dSVictor Chong }
181aca1545dSVictor Chong
1829a2efe04SVictor Chong return SPI_OK;
1839a2efe04SVictor Chong }
1849a2efe04SVictor Chong
pl022_txrx16(struct spi_chip * chip,uint16_t * wdat,uint16_t * rdat,size_t num_pkts)1859a2efe04SVictor Chong static enum spi_result pl022_txrx16(struct spi_chip *chip, uint16_t *wdat,
1869a2efe04SVictor Chong uint16_t *rdat, size_t num_pkts)
187aca1545dSVictor Chong {
188aca1545dSVictor Chong size_t i = 0;
189aca1545dSVictor Chong size_t j = 0;
190aca1545dSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
191aca1545dSVictor Chong
1929a2efe04SVictor Chong if (pd->data_size_bits != 16) {
1939a2efe04SVictor Chong EMSG("data_size_bits should be 16, not %u",
1949a2efe04SVictor Chong pd->data_size_bits);
1959a2efe04SVictor Chong return SPI_ERR_CFG;
1969a2efe04SVictor Chong }
1979a2efe04SVictor Chong
1982ff86f60SVictor Chong if (wdat)
19972057c7cSVictor Chong while (i < num_pkts) {
200918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_TNF) {
201aca1545dSVictor Chong /* tx 1 packet */
202918bb3a5SEtienne Carriere io_write16(pd->base + SSPDR, wdat[i++]);
203aca1545dSVictor Chong }
204aca1545dSVictor Chong
20572057c7cSVictor Chong if (rdat)
206918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_RNE) {
20772057c7cSVictor Chong /* rx 1 packet */
208074131b0SVictor Chong rdat[j++] = io_read16(pd->base + SSPDR);
20972057c7cSVictor Chong }
21072057c7cSVictor Chong }
21172057c7cSVictor Chong
21272057c7cSVictor Chong /* Capture remaining rdat not read above */
2139a2efe04SVictor Chong if (rdat) {
2149a2efe04SVictor Chong while ((j < num_pkts) &&
215e4b2e43cSVictor Chong (io_read8(pd->base + SSPSR) & SSPSR_RNE)) {
216aca1545dSVictor Chong /* rx 1 packet */
217074131b0SVictor Chong rdat[j++] = io_read16(pd->base + SSPDR);
218aca1545dSVictor Chong }
219aca1545dSVictor Chong
2209a2efe04SVictor Chong if (j < num_pkts) {
2219a2efe04SVictor Chong EMSG("Packets requested %zu, received %zu",
2229a2efe04SVictor Chong num_pkts, j);
2239a2efe04SVictor Chong return SPI_ERR_PKTCNT;
2249a2efe04SVictor Chong }
2259a2efe04SVictor Chong }
2269a2efe04SVictor Chong
2279a2efe04SVictor Chong return SPI_OK;
228aca1545dSVictor Chong }
229aca1545dSVictor Chong
pl022_print_peri_id(struct pl022_data * pd __maybe_unused)230aca1545dSVictor Chong static void pl022_print_peri_id(struct pl022_data *pd __maybe_unused)
231aca1545dSVictor Chong {
232aca1545dSVictor Chong DMSG("Expected: 0x 22 10 ?4 00");
233aca1545dSVictor Chong DMSG("Read: 0x %02x %02x %02x %02x",
234918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID0),
235918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID1),
236918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID2),
237918bb3a5SEtienne Carriere io_read8(pd->base + SSPPeriphID3));
238aca1545dSVictor Chong }
239aca1545dSVictor Chong
pl022_print_cell_id(struct pl022_data * pd __maybe_unused)240aca1545dSVictor Chong static void pl022_print_cell_id(struct pl022_data *pd __maybe_unused)
241aca1545dSVictor Chong {
242aca1545dSVictor Chong DMSG("Expected: 0x 0d f0 05 b1");
243aca1545dSVictor Chong DMSG("Read: 0x %02x %02x %02x %02x",
244918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID0),
245918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID1),
246918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID2),
247918bb3a5SEtienne Carriere io_read8(pd->base + SSPPCellID3));
248aca1545dSVictor Chong }
249aca1545dSVictor Chong
pl022_sanity_check(struct pl022_data * pd)250aca1545dSVictor Chong static void pl022_sanity_check(struct pl022_data *pd)
251aca1545dSVictor Chong {
252aca1545dSVictor Chong assert(pd);
253aca1545dSVictor Chong assert(pd->chip.ops);
25426128b8fSVictor Chong assert(pd->cs_control <= PL022_CS_CTRL_MANUAL);
25526128b8fSVictor Chong switch (pd->cs_control) {
25626128b8fSVictor Chong case PL022_CS_CTRL_AUTO_GPIO:
25726128b8fSVictor Chong assert(pd->cs_data.gpio_data.chip);
25826128b8fSVictor Chong assert(pd->cs_data.gpio_data.chip->ops);
25926128b8fSVictor Chong break;
26026128b8fSVictor Chong case PL022_CS_CTRL_CB:
26126128b8fSVictor Chong assert(pd->cs_data.cs_cb);
26226128b8fSVictor Chong break;
26326128b8fSVictor Chong default:
26426128b8fSVictor Chong break;
26526128b8fSVictor Chong }
266aca1545dSVictor Chong assert(pd->clk_hz);
267aca1545dSVictor Chong assert(pd->speed_hz && pd->speed_hz <= pd->clk_hz/2);
268aca1545dSVictor Chong assert(pd->mode <= SPI_MODE3);
269aca1545dSVictor Chong assert(pd->data_size_bits == 8 || pd->data_size_bits == 16);
270aca1545dSVictor Chong
271aca1545dSVictor Chong #ifdef PLATFORM_hikey
272aca1545dSVictor Chong DMSG("SSPB2BTRANS: Expected: 0x2. Read: 0x%x",
273918bb3a5SEtienne Carriere io_read8(pd->base + SSPB2BTRANS));
274aca1545dSVictor Chong #endif
275aca1545dSVictor Chong pl022_print_peri_id(pd);
276aca1545dSVictor Chong pl022_print_cell_id(pd);
277aca1545dSVictor Chong }
278aca1545dSVictor Chong
pl022_calc_freq(struct pl022_data * pd,uint8_t cpsdvr,uint8_t scr)279aca1545dSVictor Chong static inline uint32_t pl022_calc_freq(struct pl022_data *pd,
280aca1545dSVictor Chong uint8_t cpsdvr, uint8_t scr)
281aca1545dSVictor Chong {
282aca1545dSVictor Chong return pd->clk_hz / (cpsdvr * (1 + scr));
283aca1545dSVictor Chong }
284aca1545dSVictor Chong
pl022_control_cs(struct spi_chip * chip,enum gpio_level value)28526128b8fSVictor Chong static void pl022_control_cs(struct spi_chip *chip, enum gpio_level value)
28626128b8fSVictor Chong {
28726128b8fSVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
28826128b8fSVictor Chong
28926128b8fSVictor Chong switch (pd->cs_control) {
29026128b8fSVictor Chong case PL022_CS_CTRL_AUTO_GPIO:
291918bb3a5SEtienne Carriere if (io_read8(pd->base + SSPSR) & SSPSR_BSY)
29226128b8fSVictor Chong DMSG("pl022 busy - do NOT set CS!");
293918bb3a5SEtienne Carriere while (io_read8(pd->base + SSPSR) & SSPSR_BSY)
29426128b8fSVictor Chong ;
29526128b8fSVictor Chong DMSG("pl022 done - set CS!");
29626128b8fSVictor Chong
297*fc5d98e8SManish Tomar pd->cs_data.gpio_data.chip->ops->set_value(NULL,
29826128b8fSVictor Chong pd->cs_data.gpio_data.pin_num, value);
29926128b8fSVictor Chong break;
30026128b8fSVictor Chong case PL022_CS_CTRL_CB:
30126128b8fSVictor Chong pd->cs_data.cs_cb(value);
30226128b8fSVictor Chong break;
30326128b8fSVictor Chong default:
30426128b8fSVictor Chong break;
30526128b8fSVictor Chong }
30626128b8fSVictor Chong }
30726128b8fSVictor Chong
pl022_calc_clk_divisors(struct pl022_data * pd,uint8_t * cpsdvr,uint8_t * scr)308aca1545dSVictor Chong static void pl022_calc_clk_divisors(struct pl022_data *pd,
309aca1545dSVictor Chong uint8_t *cpsdvr, uint8_t *scr)
310aca1545dSVictor Chong {
311aca1545dSVictor Chong unsigned int freq1 = 0;
312aca1545dSVictor Chong unsigned int freq2 = 0;
313aca1545dSVictor Chong uint8_t tmp_cpsdvr1;
314aca1545dSVictor Chong uint8_t tmp_scr1;
315aca1545dSVictor Chong uint8_t tmp_cpsdvr2 = 0;
316aca1545dSVictor Chong uint8_t tmp_scr2 = 0;
317aca1545dSVictor Chong
318aca1545dSVictor Chong for (tmp_scr1 = SSP_SCR_MIN; tmp_scr1 < SSP_SCR_MAX; tmp_scr1++) {
319aca1545dSVictor Chong for (tmp_cpsdvr1 = SSP_CPSDVR_MIN; tmp_cpsdvr1 < SSP_CPSDVR_MAX;
320aca1545dSVictor Chong tmp_cpsdvr1++) {
321aca1545dSVictor Chong freq1 = pl022_calc_freq(pd, tmp_cpsdvr1, tmp_scr1);
322aca1545dSVictor Chong if (freq1 == pd->speed_hz)
323aca1545dSVictor Chong goto done;
324aca1545dSVictor Chong else if (freq1 < pd->speed_hz)
325aca1545dSVictor Chong goto stage2;
326aca1545dSVictor Chong }
327aca1545dSVictor Chong }
328aca1545dSVictor Chong
329aca1545dSVictor Chong stage2:
330aca1545dSVictor Chong for (tmp_cpsdvr2 = SSP_CPSDVR_MIN; tmp_cpsdvr2 < SSP_CPSDVR_MAX;
331aca1545dSVictor Chong tmp_cpsdvr2++) {
332aca1545dSVictor Chong for (tmp_scr2 = SSP_SCR_MIN; tmp_scr2 < SSP_SCR_MAX;
333aca1545dSVictor Chong tmp_scr2++) {
334aca1545dSVictor Chong freq2 = pl022_calc_freq(pd, tmp_cpsdvr2, tmp_scr2);
335aca1545dSVictor Chong if (freq2 <= pd->speed_hz)
336aca1545dSVictor Chong goto done;
337aca1545dSVictor Chong }
338aca1545dSVictor Chong }
339aca1545dSVictor Chong
340aca1545dSVictor Chong done:
341aca1545dSVictor Chong if (freq1 >= freq2) {
342aca1545dSVictor Chong *cpsdvr = tmp_cpsdvr1;
343aca1545dSVictor Chong *scr = tmp_scr1;
344aca1545dSVictor Chong DMSG("speed: requested: %u, closest1: %u",
345aca1545dSVictor Chong pd->speed_hz, freq1);
346aca1545dSVictor Chong } else {
347aca1545dSVictor Chong *cpsdvr = tmp_cpsdvr2;
348aca1545dSVictor Chong *scr = tmp_scr2;
349aca1545dSVictor Chong DMSG("speed: requested: %u, closest2: %u",
350aca1545dSVictor Chong pd->speed_hz, freq2);
351aca1545dSVictor Chong }
352aca1545dSVictor Chong DMSG("CPSDVR: %u (0x%x), SCR: %u (0x%x)",
353aca1545dSVictor Chong *cpsdvr, *cpsdvr, *scr, *scr);
354aca1545dSVictor Chong }
355aca1545dSVictor Chong
pl022_flush_fifo(struct spi_chip * chip)35671716c2aSVahid Dukandar static void pl022_flush_fifo(struct spi_chip *chip)
357aca1545dSVictor Chong {
358aca1545dSVictor Chong uint32_t __maybe_unused rdat;
35971716c2aSVahid Dukandar struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
360aca1545dSVictor Chong do {
361918bb3a5SEtienne Carriere while (io_read32(pd->base + SSPSR) & SSPSR_RNE) {
362918bb3a5SEtienne Carriere rdat = io_read32(pd->base + SSPDR);
363aca1545dSVictor Chong DMSG("rdat: 0x%x", rdat);
364aca1545dSVictor Chong }
365918bb3a5SEtienne Carriere } while (io_read32(pd->base + SSPSR) & SSPSR_BSY);
366aca1545dSVictor Chong }
367aca1545dSVictor Chong
pl022_configure(struct spi_chip * chip)3686356eeb2SVictor Chong static void pl022_configure(struct spi_chip *chip)
369aca1545dSVictor Chong {
370aca1545dSVictor Chong uint16_t mode;
371aca1545dSVictor Chong uint16_t data_size;
372aca1545dSVictor Chong uint8_t cpsdvr;
373aca1545dSVictor Chong uint8_t scr;
374aca1545dSVictor Chong uint8_t lbm;
3756356eeb2SVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
376aca1545dSVictor Chong
377aca1545dSVictor Chong pl022_sanity_check(pd);
37826128b8fSVictor Chong
37926128b8fSVictor Chong switch (pd->cs_control) {
38026128b8fSVictor Chong case PL022_CS_CTRL_AUTO_GPIO:
38126128b8fSVictor Chong DMSG("Use auto GPIO CS control");
38226128b8fSVictor Chong DMSG("Mask/disable interrupt for CS GPIO");
383*fc5d98e8SManish Tomar pd->cs_data.gpio_data.chip->ops->set_interrupt(NULL,
38426128b8fSVictor Chong pd->cs_data.gpio_data.pin_num,
38526128b8fSVictor Chong GPIO_INTERRUPT_DISABLE);
38626128b8fSVictor Chong DMSG("Set CS GPIO dir to out");
387*fc5d98e8SManish Tomar pd->cs_data.gpio_data.chip->ops->set_direction(NULL,
38826128b8fSVictor Chong pd->cs_data.gpio_data.pin_num,
38926128b8fSVictor Chong GPIO_DIR_OUT);
39026128b8fSVictor Chong break;
39126128b8fSVictor Chong case PL022_CS_CTRL_CB:
39226128b8fSVictor Chong DMSG("Use registered CS callback");
39326128b8fSVictor Chong break;
39426128b8fSVictor Chong case PL022_CS_CTRL_MANUAL:
39526128b8fSVictor Chong DMSG("Use manual CS control");
39626128b8fSVictor Chong break;
39726128b8fSVictor Chong default:
39826128b8fSVictor Chong EMSG("Invalid CS control type: %d", pd->cs_control);
39926128b8fSVictor Chong panic();
40026128b8fSVictor Chong }
40126128b8fSVictor Chong
40226128b8fSVictor Chong DMSG("Pull CS high");
40326128b8fSVictor Chong pl022_control_cs(chip, GPIO_LEVEL_HIGH);
40426128b8fSVictor Chong
405aca1545dSVictor Chong pl022_calc_clk_divisors(pd, &cpsdvr, &scr);
406aca1545dSVictor Chong
407aca1545dSVictor Chong /* configure ssp based on platform settings */
408aca1545dSVictor Chong switch (pd->mode) {
409aca1545dSVictor Chong case SPI_MODE0:
4102ff86f60SVictor Chong DMSG("SPI mode 0");
4112ff86f60SVictor Chong mode = SSPCR0_SPO0 | SSPCR0_SPH0;
412aca1545dSVictor Chong break;
413aca1545dSVictor Chong case SPI_MODE1:
4142ff86f60SVictor Chong DMSG("SPI mode 1");
4152ff86f60SVictor Chong mode = SSPCR0_SPO0 | SSPCR0_SPH1;
416aca1545dSVictor Chong break;
417aca1545dSVictor Chong case SPI_MODE2:
4182ff86f60SVictor Chong DMSG("SPI mode 2");
4192ff86f60SVictor Chong mode = SSPCR0_SPO1 | SSPCR0_SPH0;
420aca1545dSVictor Chong break;
421aca1545dSVictor Chong case SPI_MODE3:
4222ff86f60SVictor Chong DMSG("SPI mode 3");
4232ff86f60SVictor Chong mode = SSPCR0_SPO1 | SSPCR0_SPH1;
424aca1545dSVictor Chong break;
425aca1545dSVictor Chong default:
426aca1545dSVictor Chong EMSG("Invalid SPI mode: %u", pd->mode);
427aca1545dSVictor Chong panic();
428aca1545dSVictor Chong }
429aca1545dSVictor Chong
430aca1545dSVictor Chong switch (pd->data_size_bits) {
431aca1545dSVictor Chong case 8:
432aca1545dSVictor Chong DMSG("Data size: 8");
4332ff86f60SVictor Chong data_size = SSPCR0_DSS_8BIT;
434aca1545dSVictor Chong break;
435aca1545dSVictor Chong case 16:
436aca1545dSVictor Chong DMSG("Data size: 16");
4372ff86f60SVictor Chong data_size = SSPCR0_DSS_16BIT;
438aca1545dSVictor Chong break;
439aca1545dSVictor Chong default:
440aca1545dSVictor Chong EMSG("Unsupported data size: %u bits", pd->data_size_bits);
441aca1545dSVictor Chong panic();
442aca1545dSVictor Chong }
443aca1545dSVictor Chong
444aca1545dSVictor Chong if (pd->loopback) {
445aca1545dSVictor Chong DMSG("Starting in loopback mode!");
446aca1545dSVictor Chong lbm = SSPCR1_LBM_YES;
447aca1545dSVictor Chong } else {
448aca1545dSVictor Chong DMSG("Starting in regular (non-loopback) mode!");
449aca1545dSVictor Chong lbm = SSPCR1_LBM_NO;
450aca1545dSVictor Chong }
451aca1545dSVictor Chong
45226128b8fSVictor Chong DMSG("Set Serial Clock Rate (SCR), SPI mode (phase and clock)");
45326128b8fSVictor Chong DMSG("Set frame format (SPI) and data size (8- or 16-bit)");
454aca1545dSVictor Chong io_mask16(pd->base + SSPCR0, SHIFT_U32(scr, 8) | mode | SSPCR0_FRF_SPI |
455aca1545dSVictor Chong data_size, MASK_16);
456aca1545dSVictor Chong
45726128b8fSVictor Chong DMSG("Set master mode, disable SSP, set loopback mode");
458aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SOD_DISABLE | SSPCR1_MS_MASTER |
459aca1545dSVictor Chong SSPCR1_SSE_DISABLE | lbm, MASK_4);
460aca1545dSVictor Chong
46126128b8fSVictor Chong DMSG("Set clock prescale");
462aca1545dSVictor Chong io_mask8(pd->base + SSPCPSR, cpsdvr, SSPCPSR_CPSDVR);
463aca1545dSVictor Chong
46426128b8fSVictor Chong DMSG("Disable interrupts");
465aca1545dSVictor Chong io_mask8(pd->base + SSPIMSC, 0, MASK_4);
466aca1545dSVictor Chong
46726128b8fSVictor Chong DMSG("Clear interrupts");
4689a2efe04SVictor Chong io_mask8(pd->base + SSPICR, SSPICR_RORIC | SSPICR_RTIC,
4699a2efe04SVictor Chong SSPICR_RORIC | SSPICR_RTIC);
4709a2efe04SVictor Chong
47126128b8fSVictor Chong DMSG("Empty FIFO before starting");
47271716c2aSVahid Dukandar pl022_flush_fifo(chip);
473aca1545dSVictor Chong }
474aca1545dSVictor Chong
pl022_start(struct spi_chip * chip)4756356eeb2SVictor Chong static void pl022_start(struct spi_chip *chip)
476aca1545dSVictor Chong {
4776356eeb2SVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
478aca1545dSVictor Chong
47926128b8fSVictor Chong DMSG("Enable SSP");
480aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SSE_ENABLE, SSPCR1_SSE);
48126128b8fSVictor Chong
48226128b8fSVictor Chong pl022_control_cs(chip, GPIO_LEVEL_LOW);
483aca1545dSVictor Chong }
484aca1545dSVictor Chong
pl022_end(struct spi_chip * chip)4856356eeb2SVictor Chong static void pl022_end(struct spi_chip *chip)
486aca1545dSVictor Chong {
4876356eeb2SVictor Chong struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
4886356eeb2SVictor Chong
48926128b8fSVictor Chong pl022_control_cs(chip, GPIO_LEVEL_HIGH);
49026128b8fSVictor Chong
49126128b8fSVictor Chong DMSG("Disable SSP");
492aca1545dSVictor Chong io_mask8(pd->base + SSPCR1, SSPCR1_SSE_DISABLE, SSPCR1_SSE);
493aca1545dSVictor Chong }
494aca1545dSVictor Chong
4956356eeb2SVictor Chong static const struct spi_ops pl022_ops = {
4966356eeb2SVictor Chong .configure = pl022_configure,
4976356eeb2SVictor Chong .start = pl022_start,
4986356eeb2SVictor Chong .txrx8 = pl022_txrx8,
4996356eeb2SVictor Chong .txrx16 = pl022_txrx16,
5006356eeb2SVictor Chong .end = pl022_end,
50171716c2aSVahid Dukandar .flushfifo = pl022_flush_fifo,
5026356eeb2SVictor Chong };
5033639b55fSJerome Forissier DECLARE_KEEP_PAGER(pl022_ops);
5046356eeb2SVictor Chong
pl022_init(struct pl022_data * pd)5056356eeb2SVictor Chong void pl022_init(struct pl022_data *pd)
5066356eeb2SVictor Chong {
5076356eeb2SVictor Chong assert(pd);
5086356eeb2SVictor Chong pd->chip.ops = &pl022_ops;
5096356eeb2SVictor Chong }
510