|
| 1 | +#include "AzulSCSI_platform.h" |
| 2 | +#include "AzulSCSI_log.h" |
| 3 | +#include "AzulSCSI_config.h" |
| 4 | +#include <SdFat.h> |
| 5 | +#include <scsi.h> |
| 6 | +#include <assert.h> |
| 7 | +#include <hardware/gpio.h> |
| 8 | +#include <hardware/uart.h> |
| 9 | +#include <hardware/spi.h> |
| 10 | + |
| 11 | +extern "C" { |
| 12 | + |
| 13 | +const char *g_azplatform_name = PLATFORM_NAME; |
| 14 | + |
| 15 | +/***************/ |
| 16 | +/* GPIO init */ |
| 17 | +/***************/ |
| 18 | + |
| 19 | +// Helper function to configure whole GPIO in one line |
| 20 | +static void gpio_conf(uint gpio, enum gpio_function fn, bool pullup, bool pulldown, bool output, bool initial_state, bool fast_slew) |
| 21 | +{ |
| 22 | + gpio_put(gpio, initial_state); |
| 23 | + gpio_set_dir(gpio, output); |
| 24 | + gpio_set_pulls(gpio, pullup, pulldown); |
| 25 | + gpio_set_function(gpio, fn); |
| 26 | + |
| 27 | + if (fast_slew) |
| 28 | + { |
| 29 | + padsbank0_hw->io[gpio] |= PADS_BANK0_GPIO0_SLEWFAST_BITS; |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +void azplatform_init() |
| 34 | +{ |
| 35 | + /* First configure the pins that affect external buffer directions. |
| 36 | + * RP2040 defaults to pulldowns, while these pins have external pull-ups. |
| 37 | + */ |
| 38 | + // pin function pup pdown out state fast |
| 39 | + gpio_conf(SCSI_DATA_DIR, GPIO_FUNC_SIO, false,false, true, true, true); |
| 40 | + gpio_conf(SCSI_OUT_RST, GPIO_FUNC_SIO, false,false, true, true, true); |
| 41 | + gpio_conf(SCSI_OUT_BSY, GPIO_FUNC_SIO, false,false, true, true, true); |
| 42 | + gpio_conf(SCSI_OUT_SEL, GPIO_FUNC_SIO, false,false, true, true, true); |
| 43 | + |
| 44 | + /* Check dip switch settings */ |
| 45 | + gpio_conf(DIP_INITIATOR, GPIO_FUNC_SIO, false, false, false, false, false); |
| 46 | + gpio_conf(DIP_DBGLOG, GPIO_FUNC_SIO, false, false, false, false, false); |
| 47 | + gpio_conf(DIP_TERM, GPIO_FUNC_SIO, false, false, false, false, false); |
| 48 | + |
| 49 | + delay(10); // 10 ms delay to let pull-ups do their work |
| 50 | + |
| 51 | + bool initiator = !gpio_get(DIP_INITIATOR); |
| 52 | + bool dbglog = !gpio_get(DIP_DBGLOG); |
| 53 | + bool termination = !gpio_get(DIP_TERM); |
| 54 | + |
| 55 | + /* Initialize logging to SWO pin (UART0) */ |
| 56 | + gpio_conf(SWO_PIN, GPIO_FUNC_UART,false,false, true, false, true); |
| 57 | + uart_init(uart0, 2000000); |
| 58 | + |
| 59 | + azlog("DIP switch settings: initiator ", (int)initiator, ", debug log ", (int)dbglog, ", termination ", (int)termination); |
| 60 | + |
| 61 | + if (initiator) |
| 62 | + { |
| 63 | + azlog("ERROR: SCSI initiator mode is not implemented yet, turn DIP switch off for proper operation!"); |
| 64 | + } |
| 65 | + |
| 66 | + if (dbglog) |
| 67 | + { |
| 68 | + g_azlog_debug = true; |
| 69 | + } |
| 70 | + |
| 71 | + if (termination) |
| 72 | + { |
| 73 | + azlog("SCSI termination is enabled"); |
| 74 | + } |
| 75 | + else |
| 76 | + { |
| 77 | + azlog("NOTE: SCSI termination is disabled"); |
| 78 | + } |
| 79 | + |
| 80 | + /* Initialize SCSI and SD card pins to required modes. |
| 81 | + * SCSI pins should be inactive / input at this point. |
| 82 | + */ |
| 83 | + |
| 84 | + // SCSI data bus |
| 85 | + // pin function pup pdown out state fast |
| 86 | + gpio_conf(SCSI_IO_DB0, GPIO_FUNC_SIO, true, false, false, true, true); |
| 87 | + gpio_conf(SCSI_IO_DB1, GPIO_FUNC_SIO, true, false, false, true, true); |
| 88 | + gpio_conf(SCSI_IO_DB2, GPIO_FUNC_SIO, true, false, false, true, true); |
| 89 | + gpio_conf(SCSI_IO_DB3, GPIO_FUNC_SIO, true, false, false, true, true); |
| 90 | + gpio_conf(SCSI_IO_DB4, GPIO_FUNC_SIO, true, false, false, true, true); |
| 91 | + gpio_conf(SCSI_IO_DB5, GPIO_FUNC_SIO, true, false, false, true, true); |
| 92 | + gpio_conf(SCSI_IO_DB6, GPIO_FUNC_SIO, true, false, false, true, true); |
| 93 | + gpio_conf(SCSI_IO_DB7, GPIO_FUNC_SIO, true, false, false, true, true); |
| 94 | + gpio_conf(SCSI_IO_DBP, GPIO_FUNC_SIO, true, false, false, true, true); |
| 95 | + |
| 96 | + // SCSI control outputs |
| 97 | + // pin function pup pdown out state fast |
| 98 | + gpio_conf(SCSI_OUT_IO, GPIO_FUNC_SIO, false,false, true, true, true); |
| 99 | + gpio_conf(SCSI_OUT_MSG, GPIO_FUNC_SIO, false,false, true, true, true); |
| 100 | + gpio_conf(SCSI_OUT_REQ, GPIO_FUNC_SIO, false,false, true, true, true); |
| 101 | + |
| 102 | + // Shared pins are changed to input / output depending on communication phase |
| 103 | + gpio_conf(SCSI_IN_SEL, GPIO_FUNC_SIO, true, false, false, true, true); |
| 104 | + if (SCSI_OUT_CD != SCSI_IN_SEL) |
| 105 | + { |
| 106 | + gpio_conf(SCSI_OUT_CD, GPIO_FUNC_SIO, false,false, true, true, true); |
| 107 | + } |
| 108 | + |
| 109 | + gpio_conf(SCSI_IN_BSY, GPIO_FUNC_SIO, true, false, false, true, true); |
| 110 | + if (SCSI_OUT_MSG != SCSI_IN_BSY) |
| 111 | + { |
| 112 | + gpio_conf(SCSI_OUT_MSG, GPIO_FUNC_SIO, false,false, true, true, true); |
| 113 | + } |
| 114 | + |
| 115 | + // SCSI control inputs |
| 116 | + // pin function pup pdown out state fast |
| 117 | + gpio_conf(SCSI_IN_ACK, GPIO_FUNC_SIO, true, false, false, true, false); |
| 118 | + gpio_conf(SCSI_IN_ATN, GPIO_FUNC_SIO, true, false, false, true, false); |
| 119 | + gpio_conf(SCSI_IN_RST, GPIO_FUNC_SIO, true, false, false, true, false); |
| 120 | + |
| 121 | + // SD card pins |
| 122 | + gpio_conf(SD_SPI_SCK, GPIO_FUNC_SPI, false,false, true, true, true); |
| 123 | + gpio_conf(SD_SPI_MOSI, GPIO_FUNC_SPI, false,false, true, true, true); |
| 124 | + gpio_conf(SD_SPI_MISO, GPIO_FUNC_SPI, false,false, false, true, true); |
| 125 | + gpio_conf(SD_SPI_CS, GPIO_FUNC_SIO, false,false, true, true, true); |
| 126 | + |
| 127 | + // LED pin |
| 128 | + gpio_conf(LED_PIN, GPIO_FUNC_SIO, false,false, true, false, false); |
| 129 | +} |
| 130 | + |
| 131 | +void azplatform_late_init() |
| 132 | +{ |
| 133 | + /* This function can usually be left empty. |
| 134 | + * It can be used for initialization code that should not run in bootloader. |
| 135 | + */ |
| 136 | +} |
| 137 | + |
| 138 | +/*****************************************/ |
| 139 | +/* Crash handlers */ |
| 140 | +/*****************************************/ |
| 141 | + |
| 142 | +extern SdFs SD; |
| 143 | +extern uint32_t __StackTop; |
| 144 | + |
| 145 | +// void azplatform_emergency_log_save() |
| 146 | +// { |
| 147 | +// azplatform_set_sd_callback(NULL, NULL); |
| 148 | + |
| 149 | +// SD.begin(SD_CONFIG_CRASH); |
| 150 | +// FsFile crashfile = SD.open(CRASHFILE, O_WRONLY | O_CREAT | O_TRUNC); |
| 151 | + |
| 152 | +// if (!crashfile.isOpen()) |
| 153 | +// { |
| 154 | +// // Try to reinitialize |
| 155 | +// int max_retry = 10; |
| 156 | +// while (max_retry-- > 0 && !SD.begin(SD_CONFIG_CRASH)); |
| 157 | + |
| 158 | +// crashfile = SD.open(CRASHFILE, O_WRONLY | O_CREAT | O_TRUNC); |
| 159 | +// } |
| 160 | + |
| 161 | +// uint32_t startpos = 0; |
| 162 | +// crashfile.write(azlog_get_buffer(&startpos)); |
| 163 | +// crashfile.write(azlog_get_buffer(&startpos)); |
| 164 | +// crashfile.flush(); |
| 165 | +// crashfile.close(); |
| 166 | +// } |
| 167 | + |
| 168 | +// void mbed_error_hook(const mbed_error_ctx * error_context) |
| 169 | +// { |
| 170 | +// azlog("--------------"); |
| 171 | +// azlog("CRASH!"); |
| 172 | +// azlog("Platform: ", g_azplatform_name); |
| 173 | +// azlog("FW Version: ", g_azlog_firmwareversion); |
| 174 | +// azlog("error_status: ", (int)error_context->error_status); |
| 175 | +// azlog("error_address: ", error_context->error_address); |
| 176 | +// azlog("error_valu: ", error_context->error_value); |
| 177 | + |
| 178 | +// uint32_t *p = (uint32_t*)((uint32_t)error_context->thread_current_sp & ~3); |
| 179 | +// for (int i = 0; i < 8; i++) |
| 180 | +// { |
| 181 | +// if (p == &__StackTop) break; // End of stack |
| 182 | + |
| 183 | +// azlog("STACK ", (uint32_t)p, ": ", p[0], " ", p[1], " ", p[2], " ", p[3]); |
| 184 | +// p += 4; |
| 185 | +// } |
| 186 | + |
| 187 | +// azplatform_emergency_log_save(); |
| 188 | + |
| 189 | +// while (1) |
| 190 | +// { |
| 191 | +// // Flash the crash address on the LED |
| 192 | +// // Short pulse means 0, long pulse means 1 |
| 193 | +// int base_delay = 1000; |
| 194 | +// for (int i = 31; i >= 0; i--) |
| 195 | +// { |
| 196 | +// LED_OFF(); |
| 197 | +// for (int j = 0; j < base_delay; j++) delay_ns(100000); |
| 198 | + |
| 199 | +// int delay = (error_context->error_address & (1 << i)) ? (3 * base_delay) : base_delay; |
| 200 | +// LED_ON(); |
| 201 | +// for (int j = 0; j < delay; j++) delay_ns(100000); |
| 202 | +// LED_OFF(); |
| 203 | +// } |
| 204 | + |
| 205 | +// for (int j = 0; j < base_delay * 10; j++) delay_ns(100000); |
| 206 | +// } |
| 207 | +// } |
| 208 | + |
| 209 | +// void __assert_func(const char *file, int line, const char *func, const char *expr) |
| 210 | +// { |
| 211 | +// uint32_t dummy = 0; |
| 212 | + |
| 213 | +// azlog("--------------"); |
| 214 | +// azlog("ASSERT FAILED!"); |
| 215 | +// azlog("Platform: ", g_azplatform_name); |
| 216 | +// azlog("FW Version: ", g_azlog_firmwareversion); |
| 217 | +// azlog("Assert failed: ", file , ":", line, " in ", func, ":", expr); |
| 218 | + |
| 219 | +// uint32_t *p = (uint32_t*)((uint32_t)&dummy & ~3); |
| 220 | +// for (int i = 0; i < 8; i++) |
| 221 | +// { |
| 222 | +// if (p == &__StackTop) break; // End of stack |
| 223 | + |
| 224 | +// azlog("STACK ", (uint32_t)p, ": ", p[0], " ", p[1], " ", p[2], " ", p[3]); |
| 225 | +// p += 4; |
| 226 | +// } |
| 227 | + |
| 228 | +// azplatform_emergency_log_save(); |
| 229 | + |
| 230 | +// while(1) |
| 231 | +// { |
| 232 | +// LED_OFF(); |
| 233 | +// for (int j = 0; j < 1000; j++) delay_ns(100000); |
| 234 | +// LED_ON(); |
| 235 | +// for (int j = 0; j < 1000; j++) delay_ns(100000); |
| 236 | +// } |
| 237 | +// } |
| 238 | + |
| 239 | +/*****************************************/ |
| 240 | +/* Debug logging and watchdor */ |
| 241 | +/*****************************************/ |
| 242 | + |
| 243 | +// This function is called for every log message. |
| 244 | +void azplatform_log(const char *s) |
| 245 | +{ |
| 246 | + uart_puts(uart0, s); |
| 247 | +} |
| 248 | + |
| 249 | +// This function can be used to periodically reset watchdog timer for crash handling. |
| 250 | +// It can also be left empty if the platform does not use a watchdog timer. |
| 251 | +void azplatform_reset_watchdog() |
| 252 | +{ |
| 253 | +} |
| 254 | + |
| 255 | +/**********************************************/ |
| 256 | +/* Mapping from data bytes to GPIO BOP values */ |
| 257 | +/**********************************************/ |
| 258 | + |
| 259 | +/* A lookup table is the fastest way to calculate parity and convert the IO pin mapping for |
| 260 | + * data bus. The method below uses the BOP register of GD32, this is called BSRR on STM32. |
| 261 | + * If there are no other pins on the same port, you can also use direct writes to the GPIO. |
| 262 | + */ |
| 263 | + |
| 264 | +#define PARITY(n) ((1 ^ (n) ^ ((n)>>1) ^ ((n)>>2) ^ ((n)>>3) ^ ((n)>>4) ^ ((n)>>5) ^ ((n)>>6) ^ ((n)>>7)) & 1) |
| 265 | +#define X(n) (\ |
| 266 | + ((n & 0x01) ? 0 : (1 << SCSI_IO_DB0)) | \ |
| 267 | + ((n & 0x02) ? 0 : (1 << SCSI_IO_DB1)) | \ |
| 268 | + ((n & 0x04) ? 0 : (1 << SCSI_IO_DB2)) | \ |
| 269 | + ((n & 0x08) ? 0 : (1 << SCSI_IO_DB3)) | \ |
| 270 | + ((n & 0x10) ? 0 : (1 << SCSI_IO_DB4)) | \ |
| 271 | + ((n & 0x20) ? 0 : (1 << SCSI_IO_DB5)) | \ |
| 272 | + ((n & 0x40) ? 0 : (1 << SCSI_IO_DB6)) | \ |
| 273 | + ((n & 0x80) ? 0 : (1 << SCSI_IO_DB7)) | \ |
| 274 | + (PARITY(n) ? 0 : (1 << SCSI_IO_DBP)) | \ |
| 275 | + (1 << SCSI_OUT_REQ) \ |
| 276 | +) |
| 277 | + |
| 278 | +const uint32_t g_scsi_out_byte_lookup[256] = |
| 279 | +{ |
| 280 | + X(0x00), X(0x01), X(0x02), X(0x03), X(0x04), X(0x05), X(0x06), X(0x07), X(0x08), X(0x09), X(0x0a), X(0x0b), X(0x0c), X(0x0d), X(0x0e), X(0x0f), |
| 281 | + X(0x10), X(0x11), X(0x12), X(0x13), X(0x14), X(0x15), X(0x16), X(0x17), X(0x18), X(0x19), X(0x1a), X(0x1b), X(0x1c), X(0x1d), X(0x1e), X(0x1f), |
| 282 | + X(0x20), X(0x21), X(0x22), X(0x23), X(0x24), X(0x25), X(0x26), X(0x27), X(0x28), X(0x29), X(0x2a), X(0x2b), X(0x2c), X(0x2d), X(0x2e), X(0x2f), |
| 283 | + X(0x30), X(0x31), X(0x32), X(0x33), X(0x34), X(0x35), X(0x36), X(0x37), X(0x38), X(0x39), X(0x3a), X(0x3b), X(0x3c), X(0x3d), X(0x3e), X(0x3f), |
| 284 | + X(0x40), X(0x41), X(0x42), X(0x43), X(0x44), X(0x45), X(0x46), X(0x47), X(0x48), X(0x49), X(0x4a), X(0x4b), X(0x4c), X(0x4d), X(0x4e), X(0x4f), |
| 285 | + X(0x50), X(0x51), X(0x52), X(0x53), X(0x54), X(0x55), X(0x56), X(0x57), X(0x58), X(0x59), X(0x5a), X(0x5b), X(0x5c), X(0x5d), X(0x5e), X(0x5f), |
| 286 | + X(0x60), X(0x61), X(0x62), X(0x63), X(0x64), X(0x65), X(0x66), X(0x67), X(0x68), X(0x69), X(0x6a), X(0x6b), X(0x6c), X(0x6d), X(0x6e), X(0x6f), |
| 287 | + X(0x70), X(0x71), X(0x72), X(0x73), X(0x74), X(0x75), X(0x76), X(0x77), X(0x78), X(0x79), X(0x7a), X(0x7b), X(0x7c), X(0x7d), X(0x7e), X(0x7f), |
| 288 | + X(0x80), X(0x81), X(0x82), X(0x83), X(0x84), X(0x85), X(0x86), X(0x87), X(0x88), X(0x89), X(0x8a), X(0x8b), X(0x8c), X(0x8d), X(0x8e), X(0x8f), |
| 289 | + X(0x90), X(0x91), X(0x92), X(0x93), X(0x94), X(0x95), X(0x96), X(0x97), X(0x98), X(0x99), X(0x9a), X(0x9b), X(0x9c), X(0x9d), X(0x9e), X(0x9f), |
| 290 | + X(0xa0), X(0xa1), X(0xa2), X(0xa3), X(0xa4), X(0xa5), X(0xa6), X(0xa7), X(0xa8), X(0xa9), X(0xaa), X(0xab), X(0xac), X(0xad), X(0xae), X(0xaf), |
| 291 | + X(0xb0), X(0xb1), X(0xb2), X(0xb3), X(0xb4), X(0xb5), X(0xb6), X(0xb7), X(0xb8), X(0xb9), X(0xba), X(0xbb), X(0xbc), X(0xbd), X(0xbe), X(0xbf), |
| 292 | + X(0xc0), X(0xc1), X(0xc2), X(0xc3), X(0xc4), X(0xc5), X(0xc6), X(0xc7), X(0xc8), X(0xc9), X(0xca), X(0xcb), X(0xcc), X(0xcd), X(0xce), X(0xcf), |
| 293 | + X(0xd0), X(0xd1), X(0xd2), X(0xd3), X(0xd4), X(0xd5), X(0xd6), X(0xd7), X(0xd8), X(0xd9), X(0xda), X(0xdb), X(0xdc), X(0xdd), X(0xde), X(0xdf), |
| 294 | + X(0xe0), X(0xe1), X(0xe2), X(0xe3), X(0xe4), X(0xe5), X(0xe6), X(0xe7), X(0xe8), X(0xe9), X(0xea), X(0xeb), X(0xec), X(0xed), X(0xee), X(0xef), |
| 295 | + X(0xf0), X(0xf1), X(0xf2), X(0xf3), X(0xf4), X(0xf5), X(0xf6), X(0xf7), X(0xf8), X(0xf9), X(0xfa), X(0xfb), X(0xfc), X(0xfd), X(0xfe), X(0xff) |
| 296 | +}; |
| 297 | + |
| 298 | +#undef X |
| 299 | + |
| 300 | +} /* extern "C" */ |
0 commit comments