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