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