scsi_accel_host.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Accelerated SCSI subroutines for SCSI initiator/host side communication
  2. #include "scsi_accel_host.h"
  3. #include "BlueSCSI_platform.h"
  4. #include "BlueSCSI_log.h"
  5. #include "scsi_accel_host.pio.h"
  6. #include <hardware/pio.h>
  7. #include <hardware/dma.h>
  8. #include <hardware/irq.h>
  9. #include <hardware/structs/iobank0.h>
  10. #include <hardware/sync.h>
  11. #define SCSI_PIO pio0
  12. #define SCSI_SM 0
  13. static struct {
  14. // PIO configurations
  15. uint32_t pio_offset_async_read;
  16. pio_sm_config pio_cfg_async_read;
  17. } g_scsi_host;
  18. enum scsidma_state_t { SCSIHOST_IDLE = 0,
  19. SCSIHOST_READ };
  20. static volatile scsidma_state_t g_scsi_host_state;
  21. static void scsi_accel_host_config_gpio()
  22. {
  23. if (g_scsi_host_state == SCSIHOST_IDLE)
  24. {
  25. iobank0_hw->io[SCSI_IO_DB0].ctrl = GPIO_FUNC_SIO;
  26. iobank0_hw->io[SCSI_IO_DB1].ctrl = GPIO_FUNC_SIO;
  27. iobank0_hw->io[SCSI_IO_DB2].ctrl = GPIO_FUNC_SIO;
  28. iobank0_hw->io[SCSI_IO_DB3].ctrl = GPIO_FUNC_SIO;
  29. iobank0_hw->io[SCSI_IO_DB4].ctrl = GPIO_FUNC_SIO;
  30. iobank0_hw->io[SCSI_IO_DB5].ctrl = GPIO_FUNC_SIO;
  31. iobank0_hw->io[SCSI_IO_DB6].ctrl = GPIO_FUNC_SIO;
  32. iobank0_hw->io[SCSI_IO_DB7].ctrl = GPIO_FUNC_SIO;
  33. iobank0_hw->io[SCSI_IO_DBP].ctrl = GPIO_FUNC_SIO;
  34. iobank0_hw->io[SCSI_OUT_ACK].ctrl = GPIO_FUNC_SIO;
  35. }
  36. else if (g_scsi_host_state == SCSIHOST_READ)
  37. {
  38. // Data bus and REQ as input, ACK pin as output
  39. pio_sm_set_pins(SCSI_PIO, SCSI_SM, 0x7FF);
  40. pio_sm_set_consecutive_pindirs(SCSI_PIO, SCSI_SM, 0, 10, false);
  41. pio_sm_set_consecutive_pindirs(SCSI_PIO, SCSI_SM, 10, 1, true);
  42. iobank0_hw->io[SCSI_IO_DB0].ctrl = GPIO_FUNC_SIO;
  43. iobank0_hw->io[SCSI_IO_DB1].ctrl = GPIO_FUNC_SIO;
  44. iobank0_hw->io[SCSI_IO_DB2].ctrl = GPIO_FUNC_SIO;
  45. iobank0_hw->io[SCSI_IO_DB3].ctrl = GPIO_FUNC_SIO;
  46. iobank0_hw->io[SCSI_IO_DB4].ctrl = GPIO_FUNC_SIO;
  47. iobank0_hw->io[SCSI_IO_DB5].ctrl = GPIO_FUNC_SIO;
  48. iobank0_hw->io[SCSI_IO_DB6].ctrl = GPIO_FUNC_SIO;
  49. iobank0_hw->io[SCSI_IO_DB7].ctrl = GPIO_FUNC_SIO;
  50. iobank0_hw->io[SCSI_IO_DBP].ctrl = GPIO_FUNC_SIO;
  51. iobank0_hw->io[SCSI_OUT_ACK].ctrl = GPIO_FUNC_PIO0;
  52. }
  53. }
  54. uint32_t scsi_accel_host_read(uint8_t *buf, uint32_t count, int *parityError, volatile int *resetFlag)
  55. {
  56. // Currently this method just reads from the PIO RX fifo directly in software loop.
  57. // The SD card access is parallelized using DMA, so there is limited benefit from using DMA here.
  58. g_scsi_host_state = SCSIHOST_READ;
  59. int cd_start = SCSI_IN(CD);
  60. int msg_start = SCSI_IN(MSG);
  61. pio_sm_init(SCSI_PIO, SCSI_SM, g_scsi_host.pio_offset_async_read, &g_scsi_host.pio_cfg_async_read);
  62. scsi_accel_host_config_gpio();
  63. pio_sm_set_enabled(SCSI_PIO, SCSI_SM, true);
  64. // Set the number of bytes to read, must be divisible by 2.
  65. assert((count & 1) == 0);
  66. pio_sm_put(SCSI_PIO, SCSI_SM, count - 1);
  67. // Read results from PIO RX FIFO
  68. uint8_t *dst = buf;
  69. uint8_t *end = buf + count;
  70. uint32_t paritycheck = 0;
  71. while (dst < end)
  72. {
  73. uint32_t available = pio_sm_get_rx_fifo_level(SCSI_PIO, SCSI_SM);
  74. if (available == 0)
  75. {
  76. if (*resetFlag || !SCSI_IN(IO) || SCSI_IN(CD) != cd_start || SCSI_IN(MSG) != msg_start)
  77. {
  78. // Target switched out of DATA_IN mode
  79. count = dst - buf;
  80. break;
  81. }
  82. }
  83. while (available > 0)
  84. {
  85. available--;
  86. uint32_t word = pio_sm_get(SCSI_PIO, SCSI_SM);
  87. paritycheck ^= word;
  88. word = ~word;
  89. *dst++ = word & 0xFF;
  90. *dst++ = word >> 16;
  91. }
  92. }
  93. // Check parity errors in whole block
  94. // This doesn't detect if there is even number of parity errors in block.
  95. uint8_t byte0 = ~(paritycheck & 0xFF);
  96. uint8_t byte1 = ~(paritycheck >> 16);
  97. if (paritycheck != ((g_scsi_parity_lookup[byte1] << 16) | g_scsi_parity_lookup[byte0]))
  98. {
  99. log("Parity error in scsi_accel_host_read(): ", paritycheck);
  100. *parityError = 1;
  101. }
  102. g_scsi_host_state = SCSIHOST_IDLE;
  103. SCSI_RELEASE_DATA_REQ();
  104. scsi_accel_host_config_gpio();
  105. pio_sm_set_enabled(SCSI_PIO, SCSI_SM, false);
  106. return count;
  107. }
  108. void scsi_accel_host_init()
  109. {
  110. g_scsi_host_state = SCSIHOST_IDLE;
  111. scsi_accel_host_config_gpio();
  112. // Load PIO programs
  113. pio_clear_instruction_memory(SCSI_PIO);
  114. // Asynchronous / synchronous SCSI read
  115. g_scsi_host.pio_offset_async_read = pio_add_program(SCSI_PIO, &scsi_host_async_read_program);
  116. g_scsi_host.pio_cfg_async_read = scsi_host_async_read_program_get_default_config(g_scsi_host.pio_offset_async_read);
  117. sm_config_set_in_pins(&g_scsi_host.pio_cfg_async_read, SCSI_IO_DB0);
  118. sm_config_set_sideset_pins(&g_scsi_host.pio_cfg_async_read, SCSI_OUT_ACK);
  119. sm_config_set_out_shift(&g_scsi_host.pio_cfg_async_read, true, false, 32);
  120. sm_config_set_in_shift(&g_scsi_host.pio_cfg_async_read, true, true, 32);
  121. }