xref: /optee_os/core/arch/arm/plat-hikey/spi_test.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <drivers/pl022_spi.h>
30 #include <drivers/pl061_gpio.h>
31 #include <hikey_peripherals.h>
32 #include <io.h>
33 #include <kernel/tee_time.h>
34 #include <mm/core_memprot.h>
35 #include <stdint.h>
36 #include <trace.h>
37 #include <util.h>
38 
39 #define PL022_STAT	0x00C
40 #define PL022_STAT_BSY	SHIFT_U32(1, 4)
41 
42 static void spi_cs_callback(enum gpio_level value)
43 {
44 	static bool inited;
45 	static struct pl061_data pd;
46 	vaddr_t gpio6_base = core_mmu_get_va(GPIO6_BASE, MEM_AREA_IO_NSEC);
47 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC);
48 
49 	if (!inited) {
50 		pl061_init(&pd);
51 		pl061_register(gpio6_base, 6);
52 		pl061_set_mode_control(GPIO6_2, PL061_MC_SW);
53 		pd.chip.ops->set_interrupt(GPIO6_2, GPIO_INTERRUPT_DISABLE);
54 		pd.chip.ops->set_direction(GPIO6_2, GPIO_DIR_OUT);
55 		inited = true;
56 	}
57 
58 	if (read8(spi_base + PL022_STAT) & PL022_STAT_BSY)
59 		DMSG("pl022 busy - do NOT set CS!");
60 	while (read8(spi_base + PL022_STAT) & PL022_STAT_BSY)
61 		;
62 	DMSG("pl022 done - set CS!");
63 
64 	pd.chip.ops->set_value(GPIO6_2, value);
65 }
66 
67 static void spi_set_cs_mux(uint32_t val)
68 {
69 	uint32_t data;
70 	vaddr_t pmx0_base = core_mmu_get_va(PMX0_BASE, MEM_AREA_IO_NSEC);
71 
72 	if (val == PINMUX_SPI) {
73 		DMSG("Configure gpio6 pin2 as SPI");
74 		write32(PINMUX_SPI, pmx0_base + PMX0_IOMG106);
75 	} else {
76 		DMSG("Configure gpio6 pin2 as GPIO");
77 		write32(PINMUX_GPIO, pmx0_base + PMX0_IOMG106);
78 	}
79 
80 	data = read32(pmx0_base + PMX0_IOMG106);
81 	if (data)
82 		DMSG("gpio6 pin2 is SPI");
83 	else
84 		DMSG("gpio6 pin2 is GPIO");
85 }
86 
87 static void spi_test_with_manual_cs_control(void)
88 {
89 	struct pl022_data pd;
90 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC);
91 	uint8_t tx[3] = {0x01, 0x80, 0x00};
92 	uint8_t rx[3] = {0};
93 	size_t i, j, len = 3;
94 	enum spi_result res;
95 
96 	spi_set_cs_mux(PINMUX_GPIO);
97 
98 	DMSG("Set CS callback");
99 	pd.cs_control = PL022_CS_CTRL_MANUAL;
100 
101 	DMSG("spi_base: 0x%" PRIxVA "\n", spi_base);
102 	DMSG("Configure SPI");
103 	pd.base = spi_base;
104 	pd.clk_hz = SPI_CLK_HZ;
105 	pd.speed_hz = SPI_10_KHZ;
106 	pd.mode = SPI_MODE0;
107 	pd.data_size_bits = 8;
108 	pd.loopback = true;
109 
110 	pl022_init(&pd);
111 	pd.chip.ops->configure(&pd.chip);
112 	pd.chip.ops->start(&pd.chip);
113 
114 	/*
115 	 * Pulse CS only once for the whole transmission.
116 	 * This is the scheme used by the pl022 driver.
117 	 */
118 	spi_cs_callback(GPIO_LEVEL_HIGH);
119 	tee_time_busy_wait(2);
120 	spi_cs_callback(GPIO_LEVEL_LOW);
121 	for (j = 0; j < 10; j++) {
122 		DMSG("SPI test loop: %zu", j);
123 		res = pd.chip.ops->txrx8(&pd.chip, tx, rx, len);
124 		if (res) {
125 			EMSG("SPI transceive error %d", res);
126 			break;
127 		}
128 
129 		for (i = 0; i < len; i++)
130 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
131 
132 		tee_time_busy_wait(20);
133 	}
134 	spi_cs_callback(GPIO_LEVEL_HIGH);
135 
136 	/* Pulse CS once per transfer */
137 	spi_cs_callback(GPIO_LEVEL_HIGH);
138 	tee_time_busy_wait(2);
139 	for (j = 10; j < 20; j++) {
140 		DMSG("SPI test loop: %zu", j);
141 		spi_cs_callback(GPIO_LEVEL_LOW);
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 		spi_cs_callback(GPIO_LEVEL_HIGH);
153 	}
154 
155 	/* Pulse CS once per word/byte */
156 	spi_set_cs_mux(PINMUX_SPI);
157 	tee_time_busy_wait(2);
158 	for (j = 20; j < 30; j++) {
159 		DMSG("SPI test loop: %zu", j);
160 		res = pd.chip.ops->txrx8(&pd.chip, tx, rx, len);
161 		if (res) {
162 			EMSG("SPI transceive error %d", res);
163 			break;
164 		}
165 
166 		for (i = 0; i < len; i++)
167 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
168 
169 		tee_time_busy_wait(20);
170 	}
171 
172 	pd.chip.ops->end(&pd.chip);
173 }
174 
175 static void spi_test_with_registered_cs_cb(void)
176 {
177 	struct pl022_data pd;
178 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC);
179 	uint8_t tx[3] = {0x01, 0x80, 0x00};
180 	uint8_t rx[3] = {0};
181 	size_t i, j, len = 3;
182 	enum spi_result res;
183 
184 	spi_set_cs_mux(PINMUX_GPIO);
185 
186 	DMSG("Set CS callback");
187 	pd.cs_data.cs_cb = spi_cs_callback;
188 	pd.cs_control = PL022_CS_CTRL_CB;
189 
190 	DMSG("spi_base: 0x%" PRIxVA "\n", spi_base);
191 	DMSG("Configure SPI");
192 	pd.base = spi_base;
193 	pd.clk_hz = SPI_CLK_HZ;
194 	pd.speed_hz = SPI_10_KHZ;
195 	pd.mode = SPI_MODE0;
196 	pd.data_size_bits = 8;
197 	pd.loopback = true;
198 
199 	pl022_init(&pd);
200 	pd.chip.ops->configure(&pd.chip);
201 	pd.chip.ops->start(&pd.chip);
202 
203 	for (j = 0; j < 20; j++) {
204 		DMSG("SPI test loop: %zu", j);
205 		res = pd.chip.ops->txrx8(&pd.chip, tx, rx, len);
206 		if (res) {
207 			EMSG("SPI transceive error %d", res);
208 			break;
209 		}
210 
211 		for (i = 0; i < len; i++)
212 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
213 
214 		tee_time_busy_wait(20);
215 	}
216 
217 	pd.chip.ops->end(&pd.chip);
218 }
219 
220 static void spi_test_with_builtin_cs_control(void)
221 {
222 	struct pl061_data pd061;
223 	struct pl022_data pd022;
224 	vaddr_t gpio6_base = core_mmu_get_va(GPIO6_BASE, MEM_AREA_IO_NSEC);
225 	vaddr_t spi_base = core_mmu_get_va(SPI_BASE, MEM_AREA_IO_NSEC);
226 	uint8_t tx[3] = {0x01, 0x80, 0x00};
227 	uint8_t rx[3] = {0};
228 	size_t i, j, len = 3;
229 	enum spi_result res;
230 
231 	spi_set_cs_mux(PINMUX_GPIO);
232 
233 	DMSG("gpio6_base: 0x%" PRIxVA "\n", gpio6_base);
234 	DMSG("Configure GPIO");
235 	pl061_init(&pd061);
236 	pl061_register(gpio6_base, 6);
237 	DMSG("Enable software mode control for chip select");
238 	pl061_set_mode_control(GPIO6_2, PL061_MC_SW);
239 
240 	pd022.cs_data.gpio_data.chip = &pd061.chip;
241 	pd022.cs_data.gpio_data.pin_num = GPIO6_2;
242 	pd022.cs_control = PL022_CS_CTRL_AUTO_GPIO;
243 
244 	DMSG("spi_base: 0x%" PRIxVA "\n", spi_base);
245 	DMSG("Configure SPI");
246 	pd022.base = spi_base;
247 	pd022.clk_hz = SPI_CLK_HZ;
248 	pd022.speed_hz = SPI_10_KHZ;
249 	pd022.mode = SPI_MODE0;
250 	pd022.data_size_bits = 8;
251 	pd022.loopback = true;
252 
253 	pl022_init(&pd022);
254 	pd022.chip.ops->configure(&pd022.chip);
255 	pd022.chip.ops->start(&pd022.chip);
256 
257 	for (j = 0; j < 20; j++) {
258 		DMSG("SPI test loop: %zu", j);
259 		res = pd022.chip.ops->txrx8(&pd022.chip, tx, rx, len);
260 		if (res) {
261 			EMSG("SPI transceive error %d", res);
262 			break;
263 		}
264 
265 		for (i = 0; i < len; i++)
266 			DMSG("rx[%zu] = 0x%x", i, rx[i]);
267 
268 		tee_time_busy_wait(20);
269 	}
270 
271 	pd022.chip.ops->end(&pd022.chip);
272 }
273 
274 /*
275  * spi_init() MUST be run before calling this function!
276  *
277  * spi_test runs some loopback tests, so the SPI module will just receive
278  * what is transmitted, i.e. 0x01, 0x80, 0x00.
279  *
280  * In non-loopback mode, the transmitted value will elicit a readback of
281  * the measured value from the ADC chip on the Linksprite 96Boards
282  * Mezzanine card [1], which can be connected to either a sliding
283  * rheostat [2] or photoresistor [3].
284  *
285  * [1] http://linksprite.com/wiki/index.php5?title=Linker_Mezzanine_card_for_96board
286  * [2] http://learn.linksprite.com/96-board/sliding-rheostat
287  * [3] http://learn.linksprite.com/96-board/photoresistor
288  */
289 void spi_test(void)
290 {
291 	spi_test_with_builtin_cs_control();
292 	spi_test_with_registered_cs_cb();
293 	spi_test_with_manual_cs_control();
294 }
295