1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  */
5 
6 #include <drivers/pl022_spi.h>
7 #include <drivers/pl061_gpio.h>
8 #include <hikey_peripherals.h>
9 #include <io.h>
10 #include <kernel/tee_time.h>
11 #include <mm/core_memprot.h>
12 #include <stdint.h>
13 #include <trace.h>
14 #include <util.h>
15 
16 #define PL022_STAT	0x00C
17 #define PL022_STAT_BSY	SHIFT_U32(1, 4)
18 
spi_cs_callback(enum gpio_level value)19 static void spi_cs_callback(enum gpio_level value)
20 {
21 	static bool inited;
22 	static struct pl061_data pd;
23 	vaddr_t gpio6_base = core_mmu_get_va(GPIO6_BASE, MEM_AREA_IO_NSEC,
24 					     PL061_REG_SIZE);
25 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC,
26 					   PL022_REG_SIZE);
27 
28 	if (!inited) {
29 		pl061_init(&pd);
30 		pl061_register(gpio6_base, 6);
31 		pl061_set_mode_control(GPIO6_2, PL061_MC_SW);
32 		pd.chip.ops->set_interrupt(NULL, GPIO6_2,
33 					   GPIO_INTERRUPT_DISABLE);
34 		pd.chip.ops->set_direction(NULL, GPIO6_2, GPIO_DIR_OUT);
35 		inited = true;
36 	}
37 
38 	if (io_read8(spi_base + PL022_STAT) & PL022_STAT_BSY)
39 		DMSG("pl022 busy - do NOT set CS!");
40 	while (io_read8(spi_base + PL022_STAT) & PL022_STAT_BSY)
41 		;
42 	DMSG("pl022 done - set CS!");
43 
44 	pd.chip.ops->set_value(NULL, GPIO6_2, value);
45 }
46 
spi_set_cs_mux(uint32_t val)47 static void spi_set_cs_mux(uint32_t val)
48 {
49 	uint32_t data;
50 	vaddr_t pmx0_base = core_mmu_get_va(PMX0_BASE, MEM_AREA_IO_NSEC,
51 					    PMX0_REG_SIZE);
52 
53 	if (val == PINMUX_SPI) {
54 		DMSG("Configure gpio6 pin2 as SPI");
55 		io_write32(pmx0_base + PMX0_IOMG106, PINMUX_SPI);
56 	} else {
57 		DMSG("Configure gpio6 pin2 as GPIO");
58 		io_write32(pmx0_base + PMX0_IOMG106, PINMUX_GPIO);
59 	}
60 
61 	data = io_read32(pmx0_base + PMX0_IOMG106);
62 	if (data)
63 		DMSG("gpio6 pin2 is SPI");
64 	else
65 		DMSG("gpio6 pin2 is GPIO");
66 }
67 
spi_test_with_manual_cs_control(void)68 static void spi_test_with_manual_cs_control(void)
69 {
70 	struct pl022_data pd;
71 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC,
72 					   PL022_REG_SIZE);
73 	uint8_t tx[3] = {0x01, 0x80, 0x00};
74 	uint8_t rx[3] = {0};
75 	size_t i, j, len = 3;
76 	enum spi_result res;
77 
78 	spi_set_cs_mux(PINMUX_GPIO);
79 
80 	DMSG("Set CS callback");
81 	pd.cs_control = PL022_CS_CTRL_MANUAL;
82 
83 	DMSG("spi_base: 0x%" PRIxVA "\n", spi_base);
84 	DMSG("Configure SPI");
85 	pd.base = spi_base;
86 	pd.clk_hz = SPI_CLK_HZ;
87 	pd.speed_hz = SPI_10_KHZ;
88 	pd.mode = SPI_MODE0;
89 	pd.data_size_bits = 8;
90 	pd.loopback = true;
91 
92 	pl022_init(&pd);
93 	pd.chip.ops->configure(&pd.chip);
94 	pd.chip.ops->start(&pd.chip);
95 
96 	/*
97 	 * Pulse CS only once for the whole transmission.
98 	 * This is the scheme used by the pl022 driver.
99 	 */
100 	spi_cs_callback(GPIO_LEVEL_HIGH);
101 	tee_time_busy_wait(2);
102 	spi_cs_callback(GPIO_LEVEL_LOW);
103 	for (j = 0; j < 10; j++) {
104 		DMSG("SPI test loop: %zu", j);
105 		res = pd.chip.ops->txrx8(&pd.chip, tx, rx, len);
106 		if (res) {
107 			EMSG("SPI transceive error %d", res);
108 			break;
109 		}
110 
111 		for (i = 0; i < len; i++)
112 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
113 
114 		tee_time_busy_wait(20);
115 	}
116 	spi_cs_callback(GPIO_LEVEL_HIGH);
117 
118 	/* Pulse CS once per transfer */
119 	spi_cs_callback(GPIO_LEVEL_HIGH);
120 	tee_time_busy_wait(2);
121 	for (j = 10; j < 20; j++) {
122 		DMSG("SPI test loop: %zu", j);
123 		spi_cs_callback(GPIO_LEVEL_LOW);
124 		res = pd.chip.ops->txrx8(&pd.chip, tx, rx, len);
125 		if (res) {
126 			EMSG("SPI transceive error %d", res);
127 			break;
128 		}
129 
130 		for (i = 0; i < len; i++)
131 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
132 
133 		tee_time_busy_wait(20);
134 		spi_cs_callback(GPIO_LEVEL_HIGH);
135 	}
136 
137 	/* Pulse CS once per word/byte */
138 	spi_set_cs_mux(PINMUX_SPI);
139 	tee_time_busy_wait(2);
140 	for (j = 20; j < 30; j++) {
141 		DMSG("SPI test loop: %zu", j);
142 		res = pd.chip.ops->txrx8(&pd.chip, tx, rx, len);
143 		if (res) {
144 			EMSG("SPI transceive error %d", res);
145 			break;
146 		}
147 
148 		for (i = 0; i < len; i++)
149 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
150 
151 		tee_time_busy_wait(20);
152 	}
153 
154 	pd.chip.ops->end(&pd.chip);
155 }
156 
spi_test_with_registered_cs_cb(void)157 static void spi_test_with_registered_cs_cb(void)
158 {
159 	struct pl022_data pd;
160 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC,
161 					   PL022_REG_SIZE);
162 	uint8_t tx[3] = {0x01, 0x80, 0x00};
163 	uint8_t rx[3] = {0};
164 	size_t i, j, len = 3;
165 	enum spi_result res;
166 
167 	spi_set_cs_mux(PINMUX_GPIO);
168 
169 	DMSG("Set CS callback");
170 	pd.cs_data.cs_cb = spi_cs_callback;
171 	pd.cs_control = PL022_CS_CTRL_CB;
172 
173 	DMSG("spi_base: 0x%" PRIxVA "\n", spi_base);
174 	DMSG("Configure SPI");
175 	pd.base = spi_base;
176 	pd.clk_hz = SPI_CLK_HZ;
177 	pd.speed_hz = SPI_10_KHZ;
178 	pd.mode = SPI_MODE0;
179 	pd.data_size_bits = 8;
180 	pd.loopback = true;
181 
182 	pl022_init(&pd);
183 	pd.chip.ops->configure(&pd.chip);
184 	pd.chip.ops->start(&pd.chip);
185 
186 	for (j = 0; j < 20; j++) {
187 		DMSG("SPI test loop: %zu", j);
188 		res = pd.chip.ops->txrx8(&pd.chip, tx, rx, len);
189 		if (res) {
190 			EMSG("SPI transceive error %d", res);
191 			break;
192 		}
193 
194 		for (i = 0; i < len; i++)
195 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
196 
197 		tee_time_busy_wait(20);
198 	}
199 
200 	pd.chip.ops->end(&pd.chip);
201 }
202 
spi_test_with_builtin_cs_control(void)203 static void spi_test_with_builtin_cs_control(void)
204 {
205 	struct pl061_data pd061;
206 	struct pl022_data pd022;
207 	vaddr_t gpio6_base = core_mmu_get_va(GPIO6_BASE, MEM_AREA_IO_NSEC,
208 					     PL061_REG_SIZE);
209 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC,
210 					   PL022_REG_SIZE);
211 	uint8_t tx[3] = {0x01, 0x80, 0x00};
212 	uint8_t rx[3] = {0};
213 	size_t i, j, len = 3;
214 	enum spi_result res;
215 
216 	spi_set_cs_mux(PINMUX_GPIO);
217 
218 	DMSG("gpio6_base: 0x%" PRIxVA "\n", gpio6_base);
219 	DMSG("Configure GPIO");
220 	pl061_init(&pd061);
221 	pl061_register(gpio6_base, 6);
222 	DMSG("Enable software mode control for chip select");
223 	pl061_set_mode_control(GPIO6_2, PL061_MC_SW);
224 
225 	pd022.cs_data.gpio_data.chip = &pd061.chip;
226 	pd022.cs_data.gpio_data.pin_num = GPIO6_2;
227 	pd022.cs_control = PL022_CS_CTRL_AUTO_GPIO;
228 
229 	DMSG("spi_base: 0x%" PRIxVA "\n", spi_base);
230 	DMSG("Configure SPI");
231 	pd022.base = spi_base;
232 	pd022.clk_hz = SPI_CLK_HZ;
233 	pd022.speed_hz = SPI_10_KHZ;
234 	pd022.mode = SPI_MODE0;
235 	pd022.data_size_bits = 8;
236 	pd022.loopback = true;
237 
238 	pl022_init(&pd022);
239 	pd022.chip.ops->configure(&pd022.chip);
240 	pd022.chip.ops->start(&pd022.chip);
241 
242 	for (j = 0; j < 20; j++) {
243 		DMSG("SPI test loop: %zu", j);
244 		res = pd022.chip.ops->txrx8(&pd022.chip, tx, rx, len);
245 		if (res) {
246 			EMSG("SPI transceive error %d", res);
247 			break;
248 		}
249 
250 		for (i = 0; i < len; i++)
251 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
252 
253 		tee_time_busy_wait(20);
254 	}
255 
256 	pd022.chip.ops->end(&pd022.chip);
257 }
258 
259 /*
260  * spi_init() MUST be run before calling this function!
261  *
262  * spi_test runs some loopback tests, so the SPI module will just receive
263  * what is transmitted, i.e. 0x01, 0x80, 0x00.
264  *
265  * In non-loopback mode, the transmitted value will elicit a readback of
266  * the measured value from the ADC chip on the Linksprite 96Boards
267  * Mezzanine card [1], which can be connected to either a sliding
268  * rheostat [2] or photoresistor [3].
269  *
270  * [1] http://linksprite.com/wiki/index.php5?title=Linker_Mezzanine_card_for_96board
271  * [2] http://learn.linksprite.com/96-board/sliding-rheostat
272  * [3] http://learn.linksprite.com/96-board/photoresistor
273  */
spi_test(void)274 void spi_test(void)
275 {
276 	spi_test_with_builtin_cs_control();
277 	spi_test_with_registered_cs_cb();
278 	spi_test_with_manual_cs_control();
279 }
280