diff --git a/firmware/application/apps/ui_sd_over_usb.cpp b/firmware/application/apps/ui_sd_over_usb.cpp index b8d6c911..068579d6 100644 --- a/firmware/application/apps/ui_sd_over_usb.cpp +++ b/firmware/application/apps/ui_sd_over_usb.cpp @@ -31,7 +31,7 @@ SdOverUsbView::SdOverUsbView(NavigationView& nav) : nav_ (nav) { sdcStop(&SDCD1); portapack::shutdown(); - m4_init(portapack::spi_flash::image_tag_usb_sd, portapack::memory::map::m4_code, true); + m4_init(portapack::spi_flash::image_tag_usb_sd, portapack::memory::map::m4_code, false); //m4_init(portapack::spi_flash::image_tag_hackrf, portapack::memory::map::m4_code_hackrf, true); m0_halt(); /* will not return*/ //baseband::run_image(); diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 2d7cbb6c..1deaa6b4 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -515,7 +515,7 @@ set(MODE_CPPSRC ) DeclareTargets(PFUT flash_utility) -### SD over USB ${PATH_HACKRF_FIRMWARE} +### SD over USB set(MODE_INCDIR ${HACKRF_PATH}/firmware @@ -526,17 +526,18 @@ set(MODE_CPPSRC sd_over_usb/proc_sd_over_usb.cpp sd_over_usb/scsi.c + sd_over_usb/diskio.c sd_over_usb/sd_over_usb.c sd_over_usb/usb_descriptor.c sd_over_usb/usb_device.c sd_over_usb/usb_endpoint.c sd_over_usb/usb.c + sd_over_usb/hackrf_core.c ${HACKRF_PATH}/firmware/common/usb_queue.c ${HACKRF_PATH}/firmware/common/usb_request.c ${HACKRF_PATH}/firmware/common/usb_standard_request.c ${HACKRF_PATH}/firmware/common/platform_detect.c - ${HACKRF_PATH}/firmware/common/hackrf_core.c ${HACKRF_PATH}/firmware/common/gpio_lpc.c ${HACKRF_PATH}/firmware/common/firmware_info.c ${HACKRF_PATH}/firmware/common/si5351c.c @@ -558,7 +559,6 @@ set(MODE_CPPSRC ${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/scu.c ${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/timer.c ${HACKRF_PATH}/firmware/libopencm3/lib/lpc43xx/i2c.c - ) DeclareTargets(PUSB sd_over_usb) diff --git a/firmware/baseband/halconf.h b/firmware/baseband/halconf.h index d79a158e..3f24c699 100755 --- a/firmware/baseband/halconf.h +++ b/firmware/baseband/halconf.h @@ -119,7 +119,7 @@ * @brief Enables the SDC subsystem. */ #if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) -#ifdef BASEBAND_flash_utility +#if defined(BASEBAND_flash_utility) || defined(BASEBAND_sd_over_usb) #define HAL_USE_SDC TRUE #else #define HAL_USE_SDC FALSE diff --git a/firmware/baseband/sd_over_usb/diskio.c b/firmware/baseband/sd_over_usb/diskio.c new file mode 100644 index 00000000..2fcbcfd9 --- /dev/null +++ b/firmware/baseband/sd_over_usb/diskio.c @@ -0,0 +1,12 @@ +#include "diskio.h" + +#include "ch.h" +#include "hal.h" + +uint32_t get_capacity(void) { + return mmcsdGetCardCapacity(&SDCD1); +} + +bool_t read_block(uint32_t startblk, uint8_t *buf, uint32_t n) { + return sdcRead(&SDCD1, startblk, buf, n); +} diff --git a/firmware/baseband/sd_over_usb/diskio.h b/firmware/baseband/sd_over_usb/diskio.h new file mode 100644 index 00000000..5bfe9b30 --- /dev/null +++ b/firmware/baseband/sd_over_usb/diskio.h @@ -0,0 +1,10 @@ +#ifndef __DISKIO_H__ +#define __DISKIO_H__ + +#include +#include + +uint32_t get_capacity(void); +bool_t read_block(uint32_t startblk, uint8_t *buf, uint32_t n); + +#endif /* __DISKIO_H__ */ \ No newline at end of file diff --git a/firmware/baseband/sd_over_usb/hackrf_core.c b/firmware/baseband/sd_over_usb/hackrf_core.c new file mode 100644 index 00000000..73d91a4b --- /dev/null +++ b/firmware/baseband/sd_over_usb/hackrf_core.c @@ -0,0 +1,1089 @@ +/* + * Copyright 2012-2022 Great Scott Gadgets + * Copyright 2012 Jared Boone + * Copyright 2013 Benjamin Vernoux + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "hackrf_core.h" +#include "hackrf_ui.h" +#include "sgpio.h" +#include "si5351c.h" +#include "spi_ssp.h" +#include "max283x.h" +#include "max5864.h" +#include "max5864_target.h" +#include "w25q80bv.h" +#include "w25q80bv_target.h" +#include "i2c_bus.h" +#include "i2c_lpc.h" +#include "cpld_jtag.h" +#include "platform_detect.h" +#include "clkin.h" +#include +#include +#include +#include + +#ifdef HACKRF_ONE + #include "portapack.h" +#endif + +#include "gpio_lpc.h" + +/* GPIO Output PinMux */ +static struct gpio_t gpio_led[] = { + GPIO(2, 1), + GPIO(2, 2), + GPIO(2, 8), +#ifdef RAD1O + GPIO(5, 26), +#endif +}; + +// clang-format off +static struct gpio_t gpio_1v8_enable = GPIO(3, 6); + +/* MAX283x GPIO (XCVR_CTL) PinMux */ +static struct gpio_t gpio_max283x_select = GPIO(0, 15); + +/* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ +static struct gpio_t gpio_max5864_select = GPIO(2, 7); + +/* RFFC5071 GPIO serial interface PinMux */ +// #ifdef RAD1O +// static struct gpio_t gpio_rffc5072_select = GPIO(2, 13); +// static struct gpio_t gpio_rffc5072_clock = GPIO(5, 6); +// static struct gpio_t gpio_rffc5072_data = GPIO(3, 3); +// static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14); +// #endif + +/* RF supply (VAA) control */ +#ifdef HACKRF_ONE +static struct gpio_t gpio_vaa_disable = GPIO(2, 9); +#endif +#ifdef RAD1O +static struct gpio_t gpio_vaa_enable = GPIO(2, 9); +#endif + +static struct gpio_t gpio_w25q80bv_hold = GPIO(1, 14); +static struct gpio_t gpio_w25q80bv_wp = GPIO(1, 15); +static struct gpio_t gpio_w25q80bv_select = GPIO(5, 11); + +/* RF switch control */ +#ifdef HACKRF_ONE +static struct gpio_t gpio_hp = GPIO(2, 0); +static struct gpio_t gpio_lp = GPIO(2, 10); +static struct gpio_t gpio_tx_mix_bp = GPIO(2, 11); +static struct gpio_t gpio_no_mix_bypass = GPIO(1, 0); +static struct gpio_t gpio_rx_mix_bp = GPIO(2, 12); +static struct gpio_t gpio_tx_amp = GPIO(2, 15); +static struct gpio_t gpio_tx = GPIO(5, 15); +static struct gpio_t gpio_mix_bypass = GPIO(5, 16); +static struct gpio_t gpio_rx = GPIO(5, 5); +static struct gpio_t gpio_no_tx_amp_pwr = GPIO(3, 5); +static struct gpio_t gpio_amp_bypass = GPIO(0, 14); +static struct gpio_t gpio_rx_amp = GPIO(1, 11); +static struct gpio_t gpio_no_rx_amp_pwr = GPIO(1, 12); +#endif +#ifdef RAD1O +static struct gpio_t gpio_tx_rx_n = GPIO(1, 11); +static struct gpio_t gpio_tx_rx = GPIO(0, 14); +static struct gpio_t gpio_by_mix = GPIO(1, 12); +static struct gpio_t gpio_by_mix_n = GPIO(2, 10); +static struct gpio_t gpio_by_amp = GPIO(1, 0); +static struct gpio_t gpio_by_amp_n = GPIO(5, 5); +static struct gpio_t gpio_mixer_en = GPIO(5, 16); +static struct gpio_t gpio_low_high_filt = GPIO(2, 11); +static struct gpio_t gpio_low_high_filt_n = GPIO(2, 12); +static struct gpio_t gpio_tx_amp = GPIO(2, 15); +static struct gpio_t gpio_rx_lna = GPIO(5, 15); +#endif + +/* CPLD JTAG interface GPIO pins */ +static struct gpio_t gpio_cpld_tdo = GPIO(5, 18); +static struct gpio_t gpio_cpld_tck = GPIO(3, 0); +#if (defined HACKRF_ONE || defined RAD1O) +static struct gpio_t gpio_cpld_tms = GPIO(3, 4); +static struct gpio_t gpio_cpld_tdi = GPIO(3, 1); +#else +static struct gpio_t gpio_cpld_tms = GPIO(3, 1); +static struct gpio_t gpio_cpld_tdi = GPIO(3, 4); +#endif + +#ifdef HACKRF_ONE +static struct gpio_t gpio_cpld_pp_tms = GPIO(1, 1); +static struct gpio_t gpio_cpld_pp_tdo = GPIO(1, 8); +#endif + +/* other CPLD interface GPIO pins */ +static struct gpio_t gpio_hw_sync_enable = GPIO(5, 12); +static struct gpio_t gpio_q_invert = GPIO(0, 13); + +/* HackRF One r9 */ +#ifdef HACKRF_ONE +static struct gpio_t gpio_h1r9_rx = GPIO(0, 7); +static struct gpio_t gpio_h1r9_1v8_enable = GPIO(2, 9); +static struct gpio_t gpio_h1r9_vaa_disable = GPIO(3, 6); +static struct gpio_t gpio_h1r9_hw_sync_enable = GPIO(5, 5); +#endif +// clang-format on + +i2c_bus_t i2c0 = { + .obj = (void*) I2C0_BASE, + .start = i2c_lpc_start, + .stop = i2c_lpc_stop, + .transfer = i2c_lpc_transfer, +}; + +i2c_bus_t i2c1 = { + .obj = (void*) I2C1_BASE, + .start = i2c_lpc_start, + .stop = i2c_lpc_stop, + .transfer = i2c_lpc_transfer, +}; + +// const i2c_lpc_config_t i2c_config_si5351c_slow_clock = { +// .duty_cycle_count = 15, +// }; + +const i2c_lpc_config_t i2c_config_si5351c_fast_clock = { + .duty_cycle_count = 255, +}; + +si5351c_driver_t clock_gen = { + .bus = &i2c0, + .i2c_address = 0x60, +}; + +const ssp_config_t ssp_config_max283x = { + /* FIXME speed up once everything is working reliably */ + /* + // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + const uint8_t serial_clock_rate = 32; + const uint8_t clock_prescale_rate = 128; + */ + // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + .data_bits = SSP_DATA_16BITS, + .serial_clock_rate = 21, + .clock_prescale_rate = 2, + .gpio_select = &gpio_max283x_select, +}; + +const ssp_config_t ssp_config_max5864 = { + /* FIXME speed up once everything is working reliably */ + /* + // Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + const uint8_t serial_clock_rate = 32; + const uint8_t clock_prescale_rate = 128; + */ + // Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz + .data_bits = SSP_DATA_8BITS, + .serial_clock_rate = 21, + .clock_prescale_rate = 2, + .gpio_select = &gpio_max5864_select, +}; + +spi_bus_t spi_bus_ssp1 = { + .obj = (void*) SSP1_BASE, + .config = &ssp_config_max5864, + .start = spi_ssp_start, + .stop = spi_ssp_stop, + .transfer = spi_ssp_transfer, + .transfer_gather = spi_ssp_transfer_gather, +}; + +max283x_driver_t max283x = {}; + +max5864_driver_t max5864 = { + .bus = &spi_bus_ssp1, + .target_init = max5864_target_init, +}; + +const ssp_config_t ssp_config_w25q80bv = { + .data_bits = SSP_DATA_8BITS, + .serial_clock_rate = 2, + .clock_prescale_rate = 2, + .gpio_select = &gpio_w25q80bv_select, +}; + +spi_bus_t spi_bus_ssp0 = { + .obj = (void*) SSP0_BASE, + .config = &ssp_config_w25q80bv, + .start = spi_ssp_start, + .stop = spi_ssp_stop, + .transfer = spi_ssp_transfer, + .transfer_gather = spi_ssp_transfer_gather, +}; + +w25q80bv_driver_t spi_flash = { + .bus = &spi_bus_ssp0, + .gpio_hold = &gpio_w25q80bv_hold, + .gpio_wp = &gpio_w25q80bv_wp, + .target_init = w25q80bv_target_init, +}; + +sgpio_config_t sgpio_config = { + .gpio_q_invert = &gpio_q_invert, + .gpio_hw_sync_enable = &gpio_hw_sync_enable, + .slice_mode_multislice = true, +}; + +rf_path_t rf_path = { + .switchctrl = 0, +#ifdef HACKRF_ONE + .gpio_hp = &gpio_hp, + .gpio_lp = &gpio_lp, + .gpio_tx_mix_bp = &gpio_tx_mix_bp, + .gpio_no_mix_bypass = &gpio_no_mix_bypass, + .gpio_rx_mix_bp = &gpio_rx_mix_bp, + .gpio_tx_amp = &gpio_tx_amp, + .gpio_tx = &gpio_tx, + .gpio_mix_bypass = &gpio_mix_bypass, + .gpio_rx = &gpio_rx, + .gpio_no_tx_amp_pwr = &gpio_no_tx_amp_pwr, + .gpio_amp_bypass = &gpio_amp_bypass, + .gpio_rx_amp = &gpio_rx_amp, + .gpio_no_rx_amp_pwr = &gpio_no_rx_amp_pwr, +#endif +#ifdef RAD1O + .gpio_tx_rx_n = &gpio_tx_rx_n, + .gpio_tx_rx = &gpio_tx_rx, + .gpio_by_mix = &gpio_by_mix, + .gpio_by_mix_n = &gpio_by_mix_n, + .gpio_by_amp = &gpio_by_amp, + .gpio_by_amp_n = &gpio_by_amp_n, + .gpio_mixer_en = &gpio_mixer_en, + .gpio_low_high_filt = &gpio_low_high_filt, + .gpio_low_high_filt_n = &gpio_low_high_filt_n, + .gpio_tx_amp = &gpio_tx_amp, + .gpio_rx_lna = &gpio_rx_lna, +#endif +}; + +jtag_gpio_t jtag_gpio_cpld = { + .gpio_tms = &gpio_cpld_tms, + .gpio_tck = &gpio_cpld_tck, + .gpio_tdi = &gpio_cpld_tdi, + .gpio_tdo = &gpio_cpld_tdo, +#ifdef HACKRF_ONE + .gpio_pp_tms = &gpio_cpld_pp_tms, + .gpio_pp_tdo = &gpio_cpld_pp_tdo, +#endif +}; + +jtag_t jtag_cpld = { + .gpio = &jtag_gpio_cpld, +}; + +void delay(uint32_t duration) +{ + uint32_t i; + + for (i = 0; i < duration; i++) { + __asm__("nop"); + } +} + +void delay_us_at_mhz(uint32_t us, uint32_t mhz) +{ + // The loop below takes 3 cycles per iteration. + uint32_t loop_iterations = (us * mhz) / 3; + asm volatile("start%=:\n" + " subs %[ITERATIONS], #1\n" // 1 cycle + " bpl start%=\n" // 2 cycles + : + : [ITERATIONS] "r"(loop_iterations)); +} + +/* GCD algo from wikipedia */ +/* http://en.wikipedia.org/wiki/Greatest_common_divisor */ +static uint32_t gcd(uint32_t u, uint32_t v) +{ + int s; + + if (!u || !v) { + return u | v; + } + + for (s = 0; !((u | v) & 1); s++) { + u >>= 1; + v >>= 1; + } + + while (!(u & 1)) { + u >>= 1; + } + + do { + while (!(v & 1)) { + v >>= 1; + } + + if (u > v) { + uint32_t t; + t = v; + v = u; + u = t; + } + + v = v - u; + } while (v); + + return u << s; +} + +bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom) +{ + const uint64_t VCO_FREQ = 800 * 1000 * 1000; /* 800 MHz */ + uint32_t MSx_P1, MSx_P2, MSx_P3; + uint32_t a, b, c; + uint32_t rem; + + hackrf_ui()->set_sample_rate(rate_num / 2); + + /* Find best config */ + a = (VCO_FREQ * rate_denom) / rate_num; + + rem = (VCO_FREQ * rate_denom) - (a * rate_num); + + if (!rem) { + /* Integer mode */ + b = 0; + c = 1; + } else { + /* Fractional */ + uint32_t g = gcd(rem, rate_num); + rem /= g; + rate_num /= g; + + if (rate_num < (1 << 20)) { + /* Perfect match */ + b = rem; + c = rate_num; + } else { + /* Approximate */ + c = (1 << 20) - 1; + b = ((uint64_t) c * (uint64_t) rem) / rate_num; + + g = gcd(b, c); + b /= g; + c /= g; + } + } + + bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config); + + if (streaming) { + sgpio_cpld_stream_disable(&sgpio_config); + } + + /* Can we enable integer mode ? */ + if (a & 0x1 || b) { + si5351c_set_int_mode(&clock_gen, 0, 0); + } else { + si5351c_set_int_mode(&clock_gen, 0, 1); + } + + /* Final MS values */ + MSx_P1 = 128 * a + (128 * b / c) - 512; + MSx_P2 = (128 * b) % c; + MSx_P3 = c; + + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* + * On HackRF One r9 all sample clocks are externally derived + * from MS1/CLK1 operating at twice the sample rate. + */ + si5351c_configure_multisynth(&clock_gen, 1, MSx_P1, MSx_P2, MSx_P3, 0); + } else { + /* + * On other platforms the clock generator produces three + * different sample clocks, all derived from multisynth 0. + */ + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1); + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter + } + + if (streaming) { + sgpio_cpld_stream_enable(&sgpio_config); + } + + return true; +} + +bool sample_rate_set(const uint32_t sample_rate_hz) +{ + uint32_t p1 = 4608; + uint32_t p2 = 0; + uint32_t p3 = 0; + + switch (sample_rate_hz) { + case 8000000: + p1 = SI_INTDIV(50); // 800MHz / 50 = 16 MHz (SGPIO), 8 MHz (codec) + break; + + case 9216000: + // 43.40277777777778: a = 43; b = 29; c = 72 + p1 = 5043; + p2 = 40; + p3 = 72; + break; + + case 10000000: + p1 = SI_INTDIV(40); // 800MHz / 40 = 20 MHz (SGPIO), 10 MHz (codec) + break; + + case 12288000: + // 32.552083333333336: a = 32; b = 159; c = 288 + p1 = 3654; + p2 = 192; + p3 = 288; + break; + + case 12500000: + p1 = SI_INTDIV(32); // 800MHz / 32 = 25 MHz (SGPIO), 12.5 MHz (codec) + break; + + case 16000000: + p1 = SI_INTDIV(25); // 800MHz / 25 = 32 MHz (SGPIO), 16 MHz (codec) + break; + + case 18432000: + // 21.70138888889: a = 21; b = 101; c = 144 + p1 = 2265; + p2 = 112; + p3 = 144; + break; + + case 20000000: + p1 = SI_INTDIV(20); // 800MHz / 20 = 40 MHz (SGPIO), 20 MHz (codec) + break; + + default: + return false; + } + + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* + * On HackRF One r9 all sample clocks are externally derived + * from MS1/CLK1 operating at twice the sample rate. + */ + si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 0); + } else { + /* + * On other platforms the clock generator produces three + * different sample clocks, all derived from multisynth 0. + */ + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth( + &clock_gen, + 1, + p1, + 0, + 1, + 0); //p1 doesn't matter + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth( + &clock_gen, + 2, + p1, + 0, + 1, + 0); //p1 doesn't matter + } + + return true; +} + +bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) +{ + uint32_t bandwidth_hz_real; + bandwidth_hz_real = max283x_set_lpf_bandwidth(&max283x, bandwidth_hz); + + if (bandwidth_hz_real) { + hackrf_ui()->set_filter_bw(bandwidth_hz_real); + } + + return bandwidth_hz_real != 0; +} + +/* +Configure PLL1 (Main MCU Clock) to max speed (204MHz). +Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. +This function shall be called after cpu_clock_init(). +*/ +static void cpu_clock_pll1_max_speed(void) +{ + uint32_t reg_val; + + /* This function implements the sequence recommended in: + * UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */ + + /* 1. Select the IRC as BASE_M4_CLK source. */ + reg_val = CGU_BASE_M4_CLK; + reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; + reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) | CGU_BASE_M4_CLK_AUTOBLOCK(1); + CGU_BASE_M4_CLK = reg_val; + + /* 2. Enable the crystal oscillator. */ + CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK; + + /* 3. Wait 250us. */ + delay_us_at_mhz(250, 12); + + /* 4. Set the AUTOBLOCK bit. */ + CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1); + + /* 5. Reconfigure PLL1 to produce the final output frequency, with the + * crystal oscillator as clock source. */ + reg_val = CGU_PLL1_CTRL; + // clang-format off + reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | + CGU_PLL1_CTRL_PD_MASK | + CGU_PLL1_CTRL_FBSEL_MASK | + CGU_PLL1_CTRL_BYPASS_MASK | + CGU_PLL1_CTRL_DIRECT_MASK | + CGU_PLL1_CTRL_PSEL_MASK | + CGU_PLL1_CTRL_MSEL_MASK | + CGU_PLL1_CTRL_NSEL_MASK ); + /* Set PLL1 up to 12MHz * 17 = 204MHz. + * Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */ + reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) | + CGU_PLL1_CTRL_PSEL(0) | + CGU_PLL1_CTRL_NSEL(0) | + CGU_PLL1_CTRL_MSEL(16) | + CGU_PLL1_CTRL_FBSEL(0) | + CGU_PLL1_CTRL_DIRECT(1); + // clang-format on + CGU_PLL1_CTRL = reg_val; + + /* 6. Wait for PLL1 to lock. */ + while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK)) {} + + /* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */ + CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK; + + /* 8. Select PLL1 as BASE_M4_CLK source. */ + reg_val = CGU_BASE_M4_CLK; + reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; + reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1); + CGU_BASE_M4_CLK = reg_val; + + /* 9. Wait 50us. */ + delay_us_at_mhz(50, 102); + + /* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */ + CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK; +} + +/* clock startup for LPC4320 configure PLL1 to max speed (204MHz). +Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */ +void cpu_clock_init(void) +{ + /* use IRC as clock source for APB1 (including I2C0) */ + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC); + + /* use IRC as clock source for APB3 */ + CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC); + + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + + si5351c_init(&clock_gen); + si5351c_disable_all_outputs(&clock_gen); + si5351c_disable_oeb_pin_control(&clock_gen); + si5351c_power_down_all_clocks(&clock_gen); + si5351c_set_crystal_configuration(&clock_gen); + si5351c_enable_xo_and_ms_fanout(&clock_gen); + si5351c_configure_pll_sources(&clock_gen); + si5351c_configure_pll_multisynth(&clock_gen); + + /* + * Clocks on HackRF One r9: + * CLK0 -> MAX5864/CPLD/SGPIO (sample clocks) + * CLK1 -> RFFC5072/MAX2839 + * CLK2 -> External Clock Output/LPC43xx (power down at boot) + * + * Clocks on other platforms: + * CLK0 -> MAX5864/CPLD + * CLK1 -> CPLD + * CLK2 -> SGPIO + * CLK3 -> External Clock Output (power down at boot) + * CLK4 -> RFFC5072 (MAX2837 on rad1o) + * CLK5 -> MAX2837 (MAX2871 on rad1o) + * CLK6 -> none + * CLK7 -> LPC43xx (uses a 12MHz crystal by default) + */ + + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + /* MS0/CLK0 is the reference for both RFFC5071 and MAX2839. */ + si5351c_configure_multisynth( + &clock_gen, + 0, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } else { + /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 4, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + /* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 5, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } + + /* MS6/CLK6 is unused. */ + /* MS7/CLK7 is unused. */ + + /* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */ + sample_rate_set(10000000); + + si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL); + // soft reset + si5351c_reset_pll(&clock_gen); + si5351c_enable_clock_outputs(&clock_gen); + + //FIXME disable I2C + /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + + /* + * 12MHz clock is entering LPC XTAL1/OSC input now. + * On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC. + * Set up PLL1 to run from XTAL1 input. + */ + + //FIXME a lot of the details here should be in a CGU driver + + /* set xtal oscillator to low frequency mode */ + CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK; + + cpu_clock_pll1_max_speed(); + + /* use XTAL_OSC as clock source for APB1 */ + CGU_BASE_APB1_CLK = + CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL); + + /* use XTAL_OSC as clock source for APB3 */ + CGU_BASE_APB3_CLK = + CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL); + + /* use XTAL_OSC as clock source for PLL0USB */ + CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_AUTOBLOCK(1) | + CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL); + while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK) {} + + /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */ + /* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */ + CGU_PLL0USB_MDIV = 0x06167FFA; + CGU_PLL0USB_NP_DIV = 0x00302062; + CGU_PLL0USB_CTRL |= + (CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_DIRECTI(1) | + CGU_PLL0USB_CTRL_DIRECTO(1) | CGU_PLL0USB_CTRL_CLKEN(1)); + + /* power on PLL0USB and wait until stable */ + CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK; + while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK)) {} + + /* use PLL0USB as clock source for USB0 */ + CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1) | + CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB); + + /* Switch peripheral clock over to use PLL1 (204MHz) */ + CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1) | + CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); + + /* Switch APB1 clock over to use PLL1 (204MHz) */ + CGU_BASE_APB1_CLK = + CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); + + /* Switch APB3 clock over to use PLL1 (204MHz) */ + CGU_BASE_APB3_CLK = + CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1); + + CGU_BASE_SSP0_CLK = + CGU_BASE_SSP0_CLK_AUTOBLOCK(1) | CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1); + + CGU_BASE_SSP1_CLK = + CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1); + + // \/ breaks below + +#if (defined JAWBREAKER || defined HACKRF_ONE) + /* Disable unused clocks */ + /* Start with PLLs */ + CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1); + + /* Dividers */ + CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1); + CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1); + CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1); + CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1); + CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1); + + /* Base clocks */ + CGU_BASE_SPIFI_CLK = CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */ + CGU_BASE_USB1_CLK = CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */ + CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1); + CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1); + CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1); + CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1); + //CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(1); // << BREAKS + CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1); + CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1); + CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1); + CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1); + CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1); + CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1); + CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1); + CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1); + +// /\ breaks above + + + /* Disable unused peripheral clocks */ + CCU1_CLK_APB1_CAN1_CFG = 0; + CCU1_CLK_APB1_I2S_CFG = 0; + CCU1_CLK_APB1_MOTOCONPWM_CFG = 0; + CCU1_CLK_APB3_ADC0_CFG = 0; + CCU1_CLK_APB3_ADC1_CFG = 0; + CCU1_CLK_APB3_CAN0_CFG = 0; + CCU1_CLK_APB3_DAC_CFG = 0; + //CCU1_CLK_M4_DMA_CFG = 0; + CCU1_CLK_M4_EMC_CFG = 0; + CCU1_CLK_M4_EMCDIV_CFG = 0; + CCU1_CLK_M4_ETHERNET_CFG = 0; + CCU1_CLK_M4_LCD_CFG = 0; + CCU1_CLK_M4_QEI_CFG = 0; + CCU1_CLK_M4_RITIMER_CFG = 0; + // CCU1_CLK_M4_SCT_CFG = 0; + //CCU1_CLK_M4_SDIO_CFG = 0; // << BREAKS + CCU1_CLK_M4_SPIFI_CFG = 0; + CCU1_CLK_M4_TIMER0_CFG = 0; + //CCU1_CLK_M4_TIMER1_CFG = 0; + //CCU1_CLK_M4_TIMER2_CFG = 0; + CCU1_CLK_M4_TIMER3_CFG = 0; + CCU1_CLK_M4_UART1_CFG = 0; + CCU1_CLK_M4_USART0_CFG = 0; + CCU1_CLK_M4_USART2_CFG = 0; + CCU1_CLK_M4_USART3_CFG = 0; + CCU1_CLK_M4_USB1_CFG = 0; + CCU1_CLK_M4_VADC_CFG = 0; + // CCU1_CLK_SPIFI_CFG = 0; + // CCU1_CLK_USB1_CFG = 0; + // CCU1_CLK_VADC_CFG = 0; + // CCU2_CLK_APB0_UART1_CFG = 0; + // CCU2_CLK_APB0_USART0_CFG = 0; + // CCU2_CLK_APB2_USART2_CFG = 0; + // CCU2_CLK_APB2_USART3_CFG = 0; + // CCU2_CLK_APLL_CFG = 0; + // CCU2_CLK_SDIO_CFG = 0; +#endif + + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + clkin_detect_init(); + } +} + +clock_source_t activate_best_clock_source(void) +{ +#ifdef HACKRF_ONE + /* Ensure PortaPack reference oscillator is off while checking for external clock input. */ + if (portapack_reference_oscillator && portapack()) { + portapack_reference_oscillator(false); + } +#endif + + clock_source_t source = CLOCK_SOURCE_HACKRF; + + /* Check for external clock input. */ + if (si5351c_clkin_signal_valid(&clock_gen)) { + source = CLOCK_SOURCE_EXTERNAL; + } else { +#ifdef HACKRF_ONE + /* Enable PortaPack reference oscillator (if present), and check for valid clock. */ + if (portapack_reference_oscillator && portapack()) { + portapack_reference_oscillator(true); + delay(510000); /* loop iterations @ 204MHz for >10ms for oscillator to enable. */ + if (si5351c_clkin_signal_valid(&clock_gen)) { + source = CLOCK_SOURCE_PORTAPACK; + } else { + portapack_reference_oscillator(false); + } + } +#endif + /* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */ + } + + si5351c_set_clock_source( + &clock_gen, + (source == CLOCK_SOURCE_HACKRF) ? PLL_SOURCE_XTAL : PLL_SOURCE_CLKIN); + hackrf_ui()->set_clock_source(source); + return source; +} + +void ssp1_set_mode_max283x(void) +{ + spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); +} + +void ssp1_set_mode_max5864(void) +{ + spi_bus_start(max5864.bus, &ssp_config_max5864); +} + +void pin_setup(void) +{ + /* Configure all GPIO as Input (safe state) */ + //gpio_init(); + + /* TDI and TMS pull-ups are required in all JTAG-compliant devices. + * + * The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS. + * + * The PortaPack may not be present, so pull up the PortaPack TMS pin from the + * microcontroller. + * + * TCK is recommended to be held low, so use microcontroller pull-down. + * + * TDO is undriven except when in Shift-IR or Shift-DR phases. + * Use the microcontroller to pull down to keep from floating. + * + * LPC43xx pull-up and pull-down resistors are approximately 53K. + */ +#ifdef HACKRF_ONE + scu_pinmux(SCU_PINMUX_PP_TMS, SCU_GPIO_PUP | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_PP_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); +#endif + scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION4); + scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + + /* Configure SCU Pin Mux as GPIO */ + scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_NOPULL); + scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_NOPULL); +#ifdef RAD1O + scu_pinmux(SCU_PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); +#endif + + /* Configure USB indicators */ +#ifdef JAWBREAKER + scu_pinmux(SCU_PINMUX_USB_LED0, SCU_CONF_FUNCTION3); + scu_pinmux(SCU_PINMUX_USB_LED1, SCU_CONF_FUNCTION3); +#endif + + gpio_output(&gpio_led[0]); + gpio_output(&gpio_led[1]); + gpio_output(&gpio_led[2]); +#ifdef RAD1O + gpio_output(&gpio_led[3]); +#endif + + disable_1v8_power(); + if (detected_platform() == BOARD_ID_HACKRF1_R9) { +#ifdef HACKRF_ONE + gpio_output(&gpio_h1r9_1v8_enable); + scu_pinmux(SCU_H1R9_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); +#endif + } else { + gpio_output(&gpio_1v8_enable); + scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + } + +#ifdef HACKRF_ONE + /* Safe state: start with VAA turned off: */ + disable_rf_power(); + + /* Configure RF power supply (VAA) switch control signal as output */ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_output(&gpio_h1r9_vaa_disable); + } else { + gpio_output(&gpio_vaa_disable); + } +#endif + +#ifdef RAD1O + /* Safe state: start with VAA turned off: */ + disable_rf_power(); + + /* Configure RF power supply (VAA) switch control signal as output */ + gpio_output(&gpio_vaa_enable); + + /* Disable unused clock outputs. They generate noise. */ + scu_pinmux(CLK0, SCU_CLK_IN | SCU_CONF_FUNCTION7); + scu_pinmux(CLK2, SCU_CLK_IN | SCU_CONF_FUNCTION7); + + scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + +#endif + + /* enable input on SCL and SDA pins */ + SCU_SFSI2C0 = SCU_I2C0_NOMINAL; + + spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); + + mixer_bus_setup(&mixer); + +#ifdef HACKRF_ONE + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + rf_path.gpio_rx = &gpio_h1r9_rx; + sgpio_config.gpio_hw_sync_enable = &gpio_h1r9_hw_sync_enable; + } +#endif + rf_path_pin_setup(&rf_path); + + /* Configure external clock in */ + scu_pinmux(SCU_PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1); + + sgpio_configure_pin_functions(&sgpio_config); +} + +void enable_1v8_power(void) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { +#ifdef HACKRF_ONE + gpio_set(&gpio_h1r9_1v8_enable); +#endif + } else { + gpio_set(&gpio_1v8_enable); + } +} + +void disable_1v8_power(void) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { +#ifdef HACKRF_ONE + gpio_clear(&gpio_h1r9_1v8_enable); +#endif + } else { + gpio_clear(&gpio_1v8_enable); + } +} + +#ifdef HACKRF_ONE +void enable_rf_power(void) +{ + uint32_t i; + + /* many short pulses to avoid one big voltage glitch */ + for (i = 0; i < 1000; i++) { + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(&gpio_h1r9_vaa_disable); + gpio_clear(&gpio_h1r9_vaa_disable); + } else { + gpio_set(&gpio_vaa_disable); + gpio_clear(&gpio_vaa_disable); + } + } +} + +void disable_rf_power(void) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(&gpio_h1r9_vaa_disable); + } else { + gpio_set(&gpio_vaa_disable); + } +} +#endif + +#ifdef RAD1O +void enable_rf_power(void) +{ + gpio_set(&gpio_vaa_enable); + + /* Let the voltage stabilize */ + delay(1000000); +} + +void disable_rf_power(void) +{ + gpio_clear(&gpio_vaa_enable); +} +#endif + +void led_on(const led_t led) +{ + gpio_set(&gpio_led[led]); +} + +void led_off(const led_t led) +{ + gpio_clear(&gpio_led[led]); +} + +void led_toggle(const led_t led) +{ + gpio_toggle(&gpio_led[led]); +} + +void set_leds(const uint8_t state) +{ + int num_leds = 3; +#ifdef RAD1O + num_leds = 4; +#endif + for (int i = 0; i < num_leds; i++) { + gpio_write(&gpio_led[i], ((state >> i) & 1) == 1); + } +} + +void hw_sync_enable(const hw_sync_mode_t hw_sync_mode) +{ + gpio_write(sgpio_config.gpio_hw_sync_enable, hw_sync_mode == 1); +} + +void halt_and_flash(const uint32_t duration) +{ + /* blink LED1, LED2, and LED3 */ + while (1) { + led_on(LED1); + led_on(LED2); + led_on(LED3); + delay(duration); + led_off(LED1); + led_off(LED2); + led_off(LED3); + delay(duration); + } +} diff --git a/firmware/baseband/sd_over_usb/proc_sd_over_usb.cpp b/firmware/baseband/sd_over_usb/proc_sd_over_usb.cpp index 9dec3bbc..04fb8ee0 100644 --- a/firmware/baseband/sd_over_usb/proc_sd_over_usb.cpp +++ b/firmware/baseband/sd_over_usb/proc_sd_over_usb.cpp @@ -27,7 +27,6 @@ #include "debug.hpp" #include "portapack_shared_memory.hpp" -#include "event_m4.hpp" extern "C" { void start_usb(void); @@ -40,34 +39,22 @@ CH_IRQ_HANDLER(Vector60) { } } +//uint8_t buf[512]; + int main() { - //EventDispatcher event_dispatcher { std::make_unique() }; - //HALT_UNTIL_DEBUGGING(); + sdcStart(&SDCD1, nullptr); + if (sdcConnect(&SDCD1) == CH_FAILED) chDbgPanic("no sd card #1"); + + // memset(&buf[0], 0, 512); + // if (sdcRead(&SDCD1, 0, &buf[0], 1) == CH_FAILED) chDbgPanic("no sd card #2"); - //LPC_CGU->PLL0USB_CTRL.PD = 1; - //LPC_CGU->PLL0USB_CTRL.AUTOBLOCK = 1; - //LPC_CGU->PLL0USB_CTRL.CLK_SEL = 0x06; -// - //while (LPC_CGU->PLL0USB_STAT.LOCK) {} - // - //LPC_CGU->PLL0USB_MDIV = 0x06167FFA; // 0x71A7FAA; // - //LPC_CGU->PLL0USB_NP_DIV = 0x00302062; -// - ////LPC_CGU->PLL0USB_CTRL.PD |= 1; - //LPC_CGU->PLL0USB_CTRL.DIRECTI = 1; - //LPC_CGU->PLL0USB_CTRL.DIRECTO = 1; - //LPC_CGU->PLL0USB_CTRL.CLKEN = 1; -// - //LPC_CGU->PLL0USB_CTRL.PD = 0; -// - //while (!(LPC_CGU->PLL0USB_STAT.LOCK)) {} - ////chThdSleepMilliseconds(800); -// - //LPC_CGU->BASE_USB0_CLK.AUTOBLOCK = 1; - //LPC_CGU->BASE_USB0_CLK.CLK_SEL = 0x07; start_usb(); + + // memset(&buf[0], 0, 512); + // if (sdcRead(&SDCD1, 0, &buf[0], 1) == CH_FAILED) chDbgPanic("no sd card #3"); + //event_dispatcher.run(); while (true) { usb_transfer(); diff --git a/firmware/baseband/sd_over_usb/scsi.c b/firmware/baseband/sd_over_usb/scsi.c index 18397ecd..1150bda2 100644 --- a/firmware/baseband/sd_over_usb/scsi.c +++ b/firmware/baseband/sd_over_usb/scsi.c @@ -1,210 +1,125 @@ #include "scsi.h" - +#include "diskio.h" #define HALT_UNTIL_DEBUGGING() \ while (!((*(volatile uint32_t *)0xE000EDF0) & (1 << 0))) {} \ __asm__ __volatile__("bkpt 1") -typedef struct { - uint8_t peripheral; - uint8_t removable; - uint8_t version; - uint8_t response_data_format; - uint8_t additional_length; - uint8_t sccstp; - uint8_t bqueetc; - uint8_t cmdque; - uint8_t vendorID[8]; - uint8_t productID[16]; - uint8_t productRev[4]; -} scsi_inquiry_response_t; +volatile bool usb_bulk_block_send = false; -static const scsi_inquiry_response_t default_scsi_inquiry_response = { - 0x00, /* direct access block device */ - 0x80, /* removable */ - 0x04, /* SPC-2 */ - 0x02, /* response data format */ - 0x20, /* response has 0x20 + 4 bytes */ - 0x00, - 0x00, - 0x00, - "Mayhem", - "Mass Storage", - {'v','1','.','6'} -}; +void usb_bulk_block_cb(void* user_data, unsigned int bytes_transferred) { + usb_bulk_block_send = true; -typedef struct { - uint32_t signature; - uint32_t tag; - uint32_t data_residue; - uint8_t status; -} __attribute__((packed)) msd_csw_t; - -#define MSD_CBW_SIGNATURE 0x43425355 -#define MSD_CSW_SIGNATURE 0x53425355 - -// void handle_inquiry_4(void* user_data, unsigned int bytes_transferred) { -// HALT_UNTIL_DEBUGGING(); -// } - -// void handle_inquiry_3(void* user_data, unsigned int bytes_transferred) -// { -// //msd_cbw_t *msd_cbw_data = (msd_cbw_t *)user_data; - -// //HALT_UNTIL_DEBUGGING(); - - -// } - - -volatile bool inquiry_stage_one_send = false; -void inquiry_cb(void* user_data, unsigned int bytes_transferred) -{ - inquiry_stage_one_send = true; + (void)user_data; + (void)bytes_transferred; } -void handle_inquiry(msd_cbw_t *msd_cbw_data) { - inquiry_stage_one_send = false; - memcpy(&usb_bulk_buffer[0], &default_scsi_inquiry_response, sizeof(scsi_inquiry_response_t)); +void usb_send_bulk(void* const data, const uint32_t maximum_length) { + usb_bulk_block_send = false; + usb_transfer_schedule_block( &usb_endpoint_bulk_in, - &usb_bulk_buffer[0], - sizeof(scsi_inquiry_response_t), - inquiry_cb, - msd_cbw_data); + data, + maximum_length, + usb_bulk_block_cb, + NULL); - while (!inquiry_stage_one_send); + while (!usb_bulk_block_send); +} +void usb_send_csw(msd_cbw_t *msd_cbw_data, uint8_t status) { msd_csw_t csw = { .signature = MSD_CSW_SIGNATURE, .tag = msd_cbw_data->tag, .data_residue = 0, - .status = 0 + .status = status }; - memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0x4000], - sizeof(msd_csw_t), - NULL, - NULL); - + memcpy(&usb_bulk_buffer[0], &csw, sizeof(msd_csw_t)); + usb_send_bulk(&usb_bulk_buffer[0], sizeof(msd_csw_t)); } -typedef struct { - uint8_t header[4]; - uint8_t blocknum[4]; - uint8_t blocklen[4]; -} scsi_read_format_capacities_response_t; +uint8_t handle_inquiry(msd_cbw_t *msd_cbw_data) { + (void)msd_cbw_data; -volatile bool capacities_stage_one_send = false; -void capacities_cb(void* user_data, unsigned int bytes_transferred) -{ - capacities_stage_one_send = true; + scsi_inquiry_response_t ret = { + 0x00, /* direct access block device */ + 0x80, /* removable */ + 0x00, //0x04, /* SPC-2 */ + 0x00, //0x02, /* response data format */ + 0x20, /* response has 0x20 + 4 bytes */ + 0x00, + 0x00, + 0x00, + "Mayhem", + "Portapack MSD", + {'v','1','.','6'} + }; + + memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_inquiry_response_t)); + usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_inquiry_response_t)); + + return 0; } -void read_format_capacities(msd_cbw_t *msd_cbw_data) { +uint8_t handle_inquiry_serial_number(msd_cbw_t *msd_cbw_data) { + (void)msd_cbw_data; + + scsi_unit_serial_number_inquiry_response_t ret = { + .peripheral = 0x00, + .page_code = 0x80, + .reserved = 0, + .page_length = 0x08, + .serialNumber = "Mayhem" + }; + + memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_unit_serial_number_inquiry_response_t)); + usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_unit_serial_number_inquiry_response_t)); + + return 0; +} + + +uint8_t read_format_capacities(msd_cbw_t *msd_cbw_data) { uint16_t len = msd_cbw_data->cmd_data[7] << 8 | msd_cbw_data->cmd_data[8]; if (len != 0) { + size_t num_blocks = get_capacity(); + scsi_read_format_capacities_response_t ret = { .header = {0, 0, 0, 1 * 8 /* num_entries * 8 */}, - .blocknum = {0, 0, (1024 * 8) >> 8, 0}, // 32GB - .blocklen = {0b10 /* formated */, 0, (512) >> 8, 0} + .blocknum = {((num_blocks) >> 24)& 0xff, ((num_blocks) >> 16)& 0xff, ((num_blocks) >> 8)& 0xff, num_blocks & 0xff}, + .blocklen = {0b10 /* formated */, 0, (512) >> 8, 0}, + // .blocknum2 = {((num_blocks) >> 24)& 0xff, ((num_blocks) >> 16)& 0xff, ((num_blocks) >> 8)& 0xff, num_blocks & 0xff}, + // .blocklen2 = {0 /* formated */, 0, (512) >> 8, 0} }; - capacities_stage_one_send = false; memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_format_capacities_response_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0], - sizeof(scsi_inquiry_response_t), - capacities_cb, - msd_cbw_data); - - while (!capacities_stage_one_send); + usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_read_format_capacities_response_t)); } - - msd_csw_t csw = { - .signature = MSD_CSW_SIGNATURE, - .tag = msd_cbw_data->tag, - .data_residue = 0, - .status = 0 - }; - - memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0x4000], - sizeof(msd_csw_t), - NULL, - NULL); - + return 0; } -typedef struct { - uint32_t last_block_addr; - uint32_t block_size; -} scsi_read_capacity10_response_t; +uint8_t read_capacity10(msd_cbw_t *msd_cbw_data) { + (void)msd_cbw_data; -volatile bool capacity10_stage_one_send = false; -void capacity10_cb(void* user_data, unsigned int bytes_transferred) -{ - capacity10_stage_one_send = true; -} - -void read_capacity10(msd_cbw_t *msd_cbw_data) { - capacity10_stage_one_send = false; + size_t num_blocks = get_capacity(); scsi_read_capacity10_response_t ret = { - .last_block_addr = cpu_to_be32(8 * 1024 * 1024 - 1), + .last_block_addr = cpu_to_be32(num_blocks - 1), .block_size = cpu_to_be32(512) }; memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_capacity10_response_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0], - sizeof(scsi_read_capacity10_response_t), - capacity10_cb, - msd_cbw_data); - - while (!capacity10_stage_one_send); - - msd_csw_t csw = { - .signature = MSD_CSW_SIGNATURE, - .tag = msd_cbw_data->tag, - .data_residue = 0, - .status = 0 - }; - - memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0x4000], - sizeof(msd_csw_t), - NULL, - NULL); + usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_read_capacity10_response_t)); + return 0; } - -typedef struct { - uint8_t byte[18]; -} scsi_sense_response_t; - -volatile bool sense_stage_one_send = false; -void sense_cb(void* user_data, unsigned int bytes_transferred) -{ - sense_stage_one_send = true; -} - - -void request_sense(msd_cbw_t *msd_cbw_data) { - sense_stage_one_send = false; +uint8_t request_sense(msd_cbw_t *msd_cbw_data) { + (void)msd_cbw_data; scsi_sense_response_t ret = { .byte = { 0x70, 0, SCSI_SENSE_KEY_GOOD, 0, @@ -215,83 +130,28 @@ void request_sense(msd_cbw_t *msd_cbw_data) { }; memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_sense_response_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0], - sizeof(scsi_sense_response_t), - sense_cb, - msd_cbw_data); + usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_sense_response_t)); - while (!sense_stage_one_send); - - msd_csw_t csw = { - .signature = MSD_CSW_SIGNATURE, - .tag = msd_cbw_data->tag, - .data_residue = 0, - .status = 0 - }; - - memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0x4000], - sizeof(msd_csw_t), - NULL, - NULL); + return 0; } -typedef struct { - uint8_t byte[4]; -} scsi_mode_sense6_response_t; +uint8_t mode_sense6 (msd_cbw_t *msd_cbw_data) { + (void)msd_cbw_data; -volatile bool sense6_stage_one_send = false; -void sense6_cb(void* user_data, unsigned int bytes_transferred) -{ - sense6_stage_one_send = true; -} - -void mode_sense6 (msd_cbw_t *msd_cbw_data) { - sense6_stage_one_send = false; - - scsi_mode_sense6_response_t ret = { + scsi_mode_sense6_response_t ret = { .byte = { sizeof(scsi_mode_sense6_response_t) - 1, 0, - 0x01 << 7, // 0 for not write protected + 0, // 0x01 << 7, // 0 for not write protected 0 } }; memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_mode_sense6_response_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0], - sizeof(scsi_mode_sense6_response_t), - sense6_cb, - msd_cbw_data); + usb_send_bulk(&usb_bulk_buffer[0], sizeof(scsi_mode_sense6_response_t)); - while (!sense6_stage_one_send); - - msd_csw_t csw = { - .signature = MSD_CSW_SIGNATURE, - .tag = msd_cbw_data->tag, - .data_residue = 0, - .status = 0 - }; - - memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0x4000], - sizeof(msd_csw_t), - NULL, - NULL); + return 0; } -typedef struct { - uint32_t first_lba; - uint16_t blk_cnt; -} data_request_t; - static data_request_t decode_data_request(const uint8_t *cmd) { data_request_t req; @@ -307,122 +167,102 @@ static data_request_t decode_data_request(const uint8_t *cmd) { return req; } -volatile uint32_t read10_blocks_send = 0; -void read10_cb(void* user_data, unsigned int bytes_transferred) -{ - read10_blocks_send++; +uint8_t data_read10(msd_cbw_t *msd_cbw_data) { + data_request_t req = decode_data_request(msd_cbw_data->cmd_data); + + for (size_t block_index = 0; block_index < req.blk_cnt; block_index++) { + read_block(req.first_lba + block_index, &usb_bulk_buffer[0], 1 /* n blocks */); + usb_send_bulk(&usb_bulk_buffer[0], 512); + } + + return 0; } +volatile uint32_t write10_blocks_send = 0; +void write10_cb(void* user_data, unsigned int bytes_transferred) +{ + write10_blocks_send++; + + (void)user_data; + (void)bytes_transferred; +} -void data_read10(msd_cbw_t *msd_cbw_data) { - read10_blocks_send = 0; +uint8_t data_write10(msd_cbw_t *msd_cbw_data) { + write10_blocks_send = 0; data_request_t req = decode_data_request(msd_cbw_data->cmd_data); for (size_t block_index = 0; block_index < req.blk_cnt; block_index++) { - memset(&usb_bulk_buffer[0], 0, 512); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, + &usb_endpoint_bulk_out, &usb_bulk_buffer[0], 512, - read10_cb, + write10_cb, msd_cbw_data); - while (read10_blocks_send <= block_index); + while (write10_blocks_send <= block_index); + + //TODO: write to SD } - msd_csw_t csw = { - .signature = MSD_CSW_SIGNATURE, - .tag = msd_cbw_data->tag, - .data_residue = 0, - .status = 0 - }; - - memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0x4000], - sizeof(msd_csw_t), - NULL, - NULL); -} - - - - -void test_unit_ready(msd_cbw_t *msd_cbw_data) { - msd_csw_t csw = { - .signature = MSD_CSW_SIGNATURE, - .tag = msd_cbw_data->tag, - .data_residue = 0, - .status = 0 - }; - - memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - usb_transfer_schedule_block( - &usb_endpoint_bulk_in, - &usb_bulk_buffer[0x4000], - sizeof(msd_csw_t), - NULL, - NULL); + return 0; } void scsi_command(msd_cbw_t *msd_cbw_data) { + uint8_t status = 1; - switch (msd_cbw_data->cmd_data[0]) { - case SCSI_CMD_INQUIRY: - handle_inquiry(msd_cbw_data); + switch (msd_cbw_data->cmd_data[0]) { + case SCSI_CMD_INQUIRY: + //status = handle_inquiry(msd_cbw_data); + if ((msd_cbw_data->cmd_data[1] & 0b1) && msd_cbw_data->cmd_data[2] == 0x80) { + status = handle_inquiry_serial_number(msd_cbw_data); + } + else if ((msd_cbw_data->cmd_data[1] & 0b11) || msd_cbw_data->cmd_data[2] != 0) { + //TODO: implement sense + status = 1; + } + else { + status = handle_inquiry(msd_cbw_data); + } + break; - break; + case SCSI_CMD_REQUEST_SENSE: + status = request_sense(msd_cbw_data); + break; - case SCSI_CMD_REQUEST_SENSE: - request_sense(msd_cbw_data); - break; + case SCSI_CMD_READ_CAPACITY_10: + status = read_capacity10(msd_cbw_data); + break; - case SCSI_CMD_READ_CAPACITY_10: - read_capacity10(msd_cbw_data); - break; + case SCSI_CMD_READ_10: + status = data_read10(msd_cbw_data); + break; - case SCSI_CMD_READ_10: - data_read10(msd_cbw_data); - break; + case SCSI_CMD_WRITE_10: + status = data_write10(msd_cbw_data); + break; - /* - case SCSI_CMD_WRITE_10: - ret = data_read_write10(scsip, cmd); - break; -*/ - case SCSI_CMD_TEST_UNIT_READY: - test_unit_ready(msd_cbw_data); - break; + case SCSI_CMD_TEST_UNIT_READY: + status = 0; + break; - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - test_unit_ready(msd_cbw_data); - // ret = cmd_ignored(scsip, cmd); - break; - - case SCSI_CMD_MODE_SENSE_6: - mode_sense6(msd_cbw_data); - break; - - case SCSI_CMD_READ_FORMAT_CAPACITIES: - read_format_capacities(msd_cbw_data); - break; - - case SCSI_CMD_VERIFY_10: - test_unit_ready(msd_cbw_data); - break; -/* - default: - ret = cmd_unhandled(scsip, cmd); - break; - */ - } - -// if (ret == SCSI_SUCCESS) -// set_sense_ok(scsip); + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + status = 0; + break; + case SCSI_CMD_MODE_SENSE_6: + status = mode_sense6(msd_cbw_data); + break; + + case SCSI_CMD_READ_FORMAT_CAPACITIES: + status = read_format_capacities(msd_cbw_data); + break; + + case SCSI_CMD_VERIFY_10: + status = 0; + break; + } + usb_send_csw(msd_cbw_data, status); } \ No newline at end of file diff --git a/firmware/baseband/sd_over_usb/scsi.h b/firmware/baseband/sd_over_usb/scsi.h index 85dedd1a..26ab04f6 100644 --- a/firmware/baseband/sd_over_usb/scsi.h +++ b/firmware/baseband/sd_over_usb/scsi.h @@ -13,6 +13,9 @@ #include "hackrf_core.h" #include "usb_bulk_buffer.h" +#define MSD_CBW_SIGNATURE 0x43425355 +#define MSD_CSW_SIGNATURE 0x53425355 + #define SCSI_CMD_TEST_UNIT_READY 0x00 #define SCSI_CMD_REQUEST_SENSE 0x03 #define SCSI_CMD_INQUIRY 0x12 @@ -71,6 +74,67 @@ typedef struct { uint8_t cmd_data[16]; } __attribute__((packed)) msd_cbw_t; +typedef struct { + uint8_t peripheral; + uint8_t removable; + uint8_t version; + uint8_t response_data_format; + uint8_t additional_length; + uint8_t sccstp; + uint8_t bqueetc; + uint8_t cmdque; + uint8_t vendorID[8]; + uint8_t productID[16]; + uint8_t productRev[4]; +} scsi_inquiry_response_t; + +typedef struct { + uint32_t signature; + uint32_t tag; + uint32_t data_residue; + uint8_t status; +} __attribute__((packed)) msd_csw_t; + +typedef struct { + uint8_t header[4]; + uint8_t blocknum[4]; + uint8_t blocklen[4]; +} scsi_read_format_capacities_response_t; + +typedef struct { + uint8_t header[4]; + uint8_t blocknum[4]; + uint8_t blocklen[4]; + uint8_t blocknum2[4]; + uint8_t blocklen2[4]; +} scsi_read_format_capacities_double_response_t; + +typedef struct { + uint32_t last_block_addr; + uint32_t block_size; +} scsi_read_capacity10_response_t; + +typedef struct { + uint8_t byte[18]; +} scsi_sense_response_t; + +typedef struct { + uint8_t byte[4]; +} scsi_mode_sense6_response_t; + +typedef struct { + uint32_t first_lba; + uint16_t blk_cnt; +} data_request_t; + +typedef struct { + uint8_t peripheral; + uint8_t page_code; + uint8_t reserved; + uint8_t page_length; + uint8_t serialNumber[8]; +} scsi_unit_serial_number_inquiry_response_t; + static inline uint16_t bswap_16(const uint16_t x) __attribute__ ((warn_unused_result)) __attribute__ ((const)) diff --git a/firmware/baseband/sd_over_usb/sd_over_usb.c b/firmware/baseband/sd_over_usb/sd_over_usb.c index 5557d0ac..64bd3c50 100644 --- a/firmware/baseband/sd_over_usb/sd_over_usb.c +++ b/firmware/baseband/sd_over_usb/sd_over_usb.c @@ -94,16 +94,16 @@ usb_request_status_t usb_vendor_request( { usb_request_status_t status = USB_REQUEST_STATUS_STALL; - volatile uint_fast8_t address = endpoint->address; + // volatile uint_fast8_t address = endpoint->address; volatile uint8_t request = endpoint->setup.request; - volatile uint32_t b = 0; + // volatile uint32_t b = 0; if (request == 25) { // unknown code return report_magic_scsi(endpoint, stage); } - b = request + (address << 16); - HALT_UNTIL_DEBUGGING(); + // b = request + (address << 16); + // HALT_UNTIL_DEBUGGING(); return status; @@ -115,16 +115,15 @@ usb_request_status_t usb_class_request( { usb_request_status_t status = USB_REQUEST_STATUS_STALL; - volatile uint_fast8_t address = endpoint->address; volatile uint8_t request = endpoint->setup.request; - volatile uint32_t b = 0; + // volatile uint32_t b = 0; if (request == 0xFE) { return report_max_lun(endpoint, stage); } - b = request + (address << 16); - HALT_UNTIL_DEBUGGING(); + // b = request + (address << 16); + // HALT_UNTIL_DEBUGGING(); // if (address == 0x80) { @@ -149,7 +148,7 @@ usb_request_status_t usb_class_request( // HALT_UNTIL_DEBUGGING(); - return status + b; + return status; } const usb_request_handlers_t usb_request_handlers = { @@ -168,7 +167,7 @@ void usb_configuration_changed(usb_device_t* const device) void start_usb(void) { detect_hardware_platform(); pin_setup(); - cpu_clock_init(); + cpu_clock_init(); // required usb_set_configuration_changed_cb(usb_configuration_changed); usb_peripheral_reset();