Skip to content

Commit

Permalink
Initiator Mode Beta Software
Browse files Browse the repository at this point in the history
  • Loading branch information
androda committed Oct 12, 2023
1 parent a590424 commit 6da6061
Show file tree
Hide file tree
Showing 15 changed files with 303 additions and 185 deletions.
221 changes: 117 additions & 104 deletions lib/BlueSCSI_platform_RP2040/BlueSCSI_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,36 @@
#endif
#include <pico/multicore.h>
#include "scsi_accel_rp2040.h"
#include "hardware/i2c.h"

extern "C" {
#include <pico/cyw43_arch.h>

const char *g_platform_name = PLATFORM_NAME;
static bool g_scsi_initiator = false;
static bool g_supports_initiator = false;
static uint32_t g_flash_chip_size = 0;
static bool g_uart_initialized = false;
SCSI_PINS scsi_pins = { // Default values, to be tweaked later as needed
.OUT_IO = SCSI_OUT_IO,
.OUT_CD = SCSI_OUT_CD,
.OUT_REQ = SCSI_OUT_REQ,
.OUT_SEL = SCSI_OUT_SEL,
.OUT_MSG = SCSI_OUT_MSG,
.OUT_RST = SCSI_OUT_RST,
.OUT_BSY = SCSI_OUT_BSY,
.OUT_ACK = SCSI_OUT_ACK,

.IN_IO = SCSI_IN_IO,
.IN_CD = SCSI_IN_CD,
.IN_MSG = SCSI_IN_MSG,
.IN_REQ = SCSI_IN_REQ,
.IN_SEL = SCSI_IN_SEL,
.IN_BSY = SCSI_IN_BSY,
.IN_RST = SCSI_IN_RST,
.IN_ACK = SCSI_IN_ACK,
.IN_ATN = SCSI_IN_ATN
};

#ifdef MBED
void mbed_error_hook(const mbed_error_ctx * error_context);
Expand Down Expand Up @@ -93,46 +115,68 @@ void platform_init()
// Make sure second core is stopped
multicore_reset_core1();

// Default debug logging to disabled
g_log_debug = false;

// Report platform and firmware version
log("Platform: ", g_platform_name);
log("FW Version: ", g_log_firmwareversion);

/* First configure the pins that affect external buffer directions.
* RP2040 defaults to pulldowns, while these pins have external pull-ups.
*/
// pin function pup pdown out state fast
gpio_conf(SCSI_DATA_DIR, GPIO_FUNC_SIO, false,false, true, false, true);
//gpio_conf(SCSI_OUT_RST, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(SCSI_OUT_BSY, GPIO_FUNC_SIO, false,false, true, true, false);

gpio_conf(scsi_pins.OUT_BSY, GPIO_FUNC_SIO, false,false, true, true, false);
//gpio_set_drive_strength(SCSI_OUT_BSY, GPIO_DRIVE_STRENGTH_8MA);
gpio_conf(SCSI_OUT_SEL, GPIO_FUNC_SIO, false,false, true, true, false);

/* Check dip switch settings */
// Option switches: S1 is iATN, S2 is iACK
gpio_conf(SCSI_IN_ACK, GPIO_FUNC_SIO, false, false, false, false, false);
gpio_conf(SCSI_IN_ATN, GPIO_FUNC_SIO, false, false, false, false, false);
delay(10); /// Settle time
(void)!gpio_get(SCSI_IN_ATN); // S1
(void)!gpio_get(SCSI_IN_ACK); // S2

/* Initialize logging to SWO pin (UART0) */
gpio_conf(SWO_PIN, GPIO_FUNC_UART,false,false, true, false, true);
uart_init(uart0, 115200);
g_uart_initialized = true;
gpio_conf(scsi_pins.OUT_SEL, GPIO_FUNC_SIO, true, false, true, true, false);
gpio_conf(scsi_pins.OUT_ACK, GPIO_FUNC_SIO, true, false, true, true, false);
gpio_conf(scsi_pins.OUT_IO, GPIO_FUNC_SIO, true, false, true, true, false);
gpio_conf(scsi_pins.OUT_REQ, GPIO_FUNC_SIO, true, false, true, true, false);

// Determine whether initiator and I2C are supported
// If G16 and G17 are high, this is the 2023_09a revision or later desktop board
gpio_conf(GPIO_I2C_SCL, GPIO_FUNC_I2C, false, false, false, false, true);
gpio_conf(GPIO_I2C_SDA, GPIO_FUNC_I2C, false, false, false, false, true);
delay(10);
bool d50_2023_09a = gpio_get(GPIO_I2C_SCL) && gpio_get(GPIO_I2C_SDA);

if (d50_2023_09a) {
log("Initiator and I2C Supported");
g_supports_initiator = true;
gpio_conf(GPIO_I2C_SCL, GPIO_FUNC_I2C, true, false, false, true, true);
gpio_conf(GPIO_I2C_SDA, GPIO_FUNC_I2C, true, false, false, true, true);

// Use Pico SDK methods
gpio_set_function(GPIO_I2C_SCL, GPIO_FUNC_I2C);
gpio_set_function(GPIO_I2C_SDA, GPIO_FUNC_I2C);
// gpio_pull_up(GPIO_I2C_SCL); // TODO necessary?
// gpio_pull_up(GPIO_I2C_SDA);
} else {
/* Check option switch settings */
// Option switches: S1 is iATN, S2 is iACK
gpio_conf(scsi_pins.IN_ACK, GPIO_FUNC_SIO, false, false, false, false, false);
gpio_conf(scsi_pins.IN_ATN, GPIO_FUNC_SIO, false, false, false, false, false);
delay(10); /// Settle time
// Check option switches
bool optionS1 = !gpio_get(scsi_pins.IN_ATN);
bool optionS2 = !gpio_get(scsi_pins.IN_ACK);

// Reset REQ to appropriate pin for older hardware
scsi_pins.OUT_REQ = SCSI_OUT_REQ_BEFORE_2023_09a;

// Initialize logging to SWO pin (UART0)
gpio_conf(SWO_PIN, GPIO_FUNC_UART,false,false, true, false, true);
uart_init(uart0, 1000000);
g_uart_initialized = true;
#ifdef MBED
mbed_set_error_hook(mbed_error_hook);
mbed_set_error_hook(mbed_error_hook);
#endif
}
// TODO Disable I2C if debug logging is enabled later? Switch to Serial output mode?

//log("DIP switch settings: debug log ", (int)dbglog, ", termination ", (int)termination);
log("Platform: ", g_platform_name);
log("FW Version: ", g_log_firmwareversion);

g_log_debug = false; // Debug logging can be handled with a debug firmware, very easy to reflash

// if (termination) // Termination is handled by hardware jumper
// {
// log("SCSI termination is enabled");
// }
// else
// {
// log("NOTE: SCSI termination is disabled");
// }

#ifdef ENABLE_AUDIO_OUTPUT
log("SP/DIF audio to expansion header enabled");
Expand Down Expand Up @@ -179,57 +223,10 @@ void platform_init()
#endif
}

static bool read_initiator_dip_switch()
{
/* Revision 2022d hardware has problems reading initiator DIP switch setting.
* The 74LVT245 hold current is keeping the GPIO_ACK state too strongly.
* Detect this condition by toggling the pin up and down and seeing if it sticks.
*/

// Strong output high, then pulldown
// pin function pup pdown out state fast
//gpio_conf(DIP_INITIATOR, GPIO_FUNC_SIO, false, false, true, true, false);
//gpio_conf(DIP_INITIATOR, GPIO_FUNC_SIO, false, true, false, true, false);
//delay(1);
//bool initiator_state1 = gpio_get(DIP_INITIATOR);

// Strong output low, then pullup
// pin function pup pdown out state fast
//gpio_conf(DIP_INITIATOR, GPIO_FUNC_SIO, false, false, true, false, false);
//gpio_conf(DIP_INITIATOR, GPIO_FUNC_SIO, true, false, false, false, false);
//delay(1);
//bool initiator_state2 = gpio_get(DIP_INITIATOR);

//if (initiator_state1 == initiator_state2)
//{
// Ok, was able to read the state directly
//return !initiator_state1;
//}

// Enable OUT_BSY for a short time.
// If in target mode, this will force GPIO_ACK high.
gpio_put(SCSI_OUT_BSY, 0);
delay_100ns();
gpio_put(SCSI_OUT_BSY, 1);

//return !gpio_get(DIP_INITIATOR);
return false;
}

// late_init() only runs in main application, SCSI not needed in bootloader
void platform_late_init()
{
if (read_initiator_dip_switch())
{
g_scsi_initiator = true;
log("SCSI initiator mode selected by DIP switch, expecting SCSI disks on the bus");
}
else
{
g_scsi_initiator = false;
// log("SCSI target/disk mode selected by DIP switch, acting as a SCSI disk");
}

/* Initialize SCSI pins to required modes.
* SCSI pins should be inactive / input at this point.
*/
Expand All @@ -252,31 +249,31 @@ void platform_late_init()
// Act as SCSI device / target

// SCSI control outputs
// pin function pup pdown out state fast
gpio_conf(SCSI_OUT_IO, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(SCSI_OUT_MSG, GPIO_FUNC_SIO, false,false, true, true, true);
// pin function pup pdown out state fast
gpio_conf(scsi_pins.OUT_IO, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(scsi_pins.OUT_MSG, GPIO_FUNC_SIO, false,false, true, true, true);

// REQ pin is switched between PIO and SIO, pull-up makes sure no glitches
gpio_conf(SCSI_OUT_REQ, GPIO_FUNC_SIO, true ,false, true, true, true);
gpio_conf(scsi_pins.OUT_REQ, GPIO_FUNC_SIO, true ,false, true, true, true);

// Shared pins are changed to input / output depending on communication phase
gpio_conf(SCSI_IN_SEL, GPIO_FUNC_SIO, true, false, false, true, true);
if (SCSI_OUT_CD != SCSI_IN_SEL)
gpio_conf(scsi_pins.IN_SEL, GPIO_FUNC_SIO, true, false, false, true, true);
if (scsi_pins.OUT_CD != scsi_pins.IN_SEL)
{
gpio_conf(SCSI_OUT_CD, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(scsi_pins.OUT_CD, GPIO_FUNC_SIO, false,false, true, true, true);
}

gpio_conf(SCSI_IN_BSY, GPIO_FUNC_SIO, true, false, false, true, true);
if (SCSI_OUT_MSG != SCSI_IN_BSY)
gpio_conf(scsi_pins.IN_BSY, GPIO_FUNC_SIO, true, false, false, true, true);
if (scsi_pins.OUT_MSG != scsi_pins.IN_BSY)
{
gpio_conf(SCSI_OUT_MSG, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(scsi_pins.OUT_MSG, GPIO_FUNC_SIO, false,false, true, true, true);
}

// SCSI control inputs
// pin function pup pdown out state fast
gpio_conf(SCSI_IN_ACK, GPIO_FUNC_SIO, false, false, false, true, false);
gpio_conf(SCSI_IN_ATN, GPIO_FUNC_SIO, false, false, false, true, false);
gpio_conf(SCSI_IN_RST, GPIO_FUNC_SIO, true, false, false, true, false);
// pin function pup pdown out state fast
gpio_conf(scsi_pins.IN_ACK, GPIO_FUNC_SIO, false, false, false, true, false);
gpio_conf(scsi_pins.IN_ATN, GPIO_FUNC_SIO, false, false, false, true, false);
gpio_conf(scsi_pins.IN_RST, GPIO_FUNC_SIO, true, false, false, true, false);

#ifdef ENABLE_AUDIO_OUTPUT
// one-time control setup for DMA channels and second core
Expand All @@ -285,18 +282,27 @@ void platform_late_init()
}
else
{
// Act as SCSI initiator

// pin function pup pdown out state fast
gpio_conf(SCSI_IN_IO, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(SCSI_IN_MSG, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(SCSI_IN_CD, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(SCSI_IN_REQ, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(SCSI_IN_BSY, GPIO_FUNC_SIO, true, false, false, true, false);
gpio_conf(SCSI_IN_RST, GPIO_FUNC_SIO, true, false, false, true, false);
gpio_conf(SCSI_OUT_SEL, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(SCSI_OUT_ACK, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(SCSI_OUT_ATN, GPIO_FUNC_SIO, false,false, true, true, true);
// Act as SCSI Initiator

// pin function pup pdown out state fast
gpio_conf(scsi_pins.IN_IO, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(scsi_pins.IN_MSG, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(scsi_pins.IN_CD, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(scsi_pins.IN_REQ, GPIO_FUNC_SIO, true ,false, false, true, false);
gpio_conf(scsi_pins.IN_BSY, GPIO_FUNC_SIO, true, false, false, true, false);
gpio_conf(scsi_pins.IN_RST, GPIO_FUNC_SIO, true, false, false, true, false);
gpio_conf(scsi_pins.OUT_SEL, GPIO_FUNC_SIO, false,false, true, true, true);
gpio_conf(scsi_pins.OUT_ACK, GPIO_FUNC_SIO, false,false, true, true, true);
//gpio_conf(SCSI_OUT_ATN, GPIO_FUNC_SIO, false,false, true, true, true); // ATN output is unused
}
}

void platform_enable_initiator_mode() {
if (g_supports_initiator) {
g_scsi_initiator = true;
log("SCSI Initiator Mode. Will scan the bus for drives to image.");
} else {
log("SCSI Initiator Mode requested, but not supported.");
}
}

Expand Down Expand Up @@ -621,7 +627,9 @@ void platform_poll()
#endif
}

uint8_t platform_get_buttons()
uint8_t platform_get_buttons() {return 0;}
// TODO figure this out
/*uint8_t platform_get_buttons()
{
uint8_t buttons = 0;
Expand Down Expand Up @@ -649,6 +657,11 @@ uint8_t platform_get_buttons()
}
return buttons_debounced;
}*/

// Used by setup methods to determine which hardware version is in use
bool is202309a() {
return scsi_pins.OUT_REQ == SCSI_OUT_REQ;
}

/*****************************************/
Expand Down
Loading

0 comments on commit 6da6061

Please sign in to comment.