diff --git a/apps/SOURCES b/apps/SOURCES index 2c002b51cd..1c454b3dae 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -299,4 +299,6 @@ keymaps/keymap-fiiom3k.c keymaps/keymap-erosq.c #elif CONFIG_KEYPAD == SHANLING_Q1_PAD keymaps/keymap-shanlingq1.c +#elif CONFIG_KEYPAD == ECHO_R1_PAD +keymaps/keymap-echor1.c #endif diff --git a/apps/keymaps/keymap-echor1.c b/apps/keymaps/keymap-echor1.c new file mode 100644 index 0000000000..e4b108f033 --- /dev/null +++ b/apps/keymaps/keymap-echor1.c @@ -0,0 +1,42 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* Button Code Definitions for Echo R1 */ + +#include "config.h" +#include "action.h" +#include "button.h" +#include "settings.h" + +/* {Action Code, Button code, Prereq button code } */ + +static const struct button_mapping button_context_standard[] = { + LAST_ITEM_IN_LIST +}; /* button_context_standard */ + +const struct button_mapping* get_context_mapping(int context) +{ + switch (context) + { + default: + return button_context_standard; + } +} diff --git a/apps/settings.h b/apps/settings.h index f3932a071a..81c247abb0 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -238,6 +238,9 @@ enum { ALARM_START_WPS = 0, #elif CONFIG_CPU == S3C2440 || defined(CPU_PP) || CONFIG_CPU==IMX31L /* up to 64MB of DRAM at 0x0 */ #define VIRT_PTR ((unsigned char*)0x4000000) +#elif CONFIG_CPU == STM32H743 +/* 64k ITCM at 0x0 */ +#define VIRT_PTR ((unsigned char*)0x10000) #else /* offset from 0x0 slightly */ #define VIRT_PTR ((unsigned char*)sizeof(char*)) diff --git a/bootloader/SOURCES b/bootloader/SOURCES index e4e240713c..fb3cc1e6c3 100644 --- a/bootloader/SOURCES +++ b/bootloader/SOURCES @@ -94,4 +94,7 @@ x1000/install.c x1000/main.c x1000/recovery.c x1000/utils.c +#elif defined(ECHO_R1) +echoplayer.c +show_logo.c #endif diff --git a/bootloader/echoplayer.c b/bootloader/echoplayer.c new file mode 100644 index 0000000000..da7d9fecb3 --- /dev/null +++ b/bootloader/echoplayer.c @@ -0,0 +1,47 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "kernel/kernel-internal.h" +#include "system.h" +#include "power.h" +#include "rtc.h" +#include "lcd.h" +#include "backlight.h" +#include "button.h" + +extern void show_logo(void); + +void main(void) +{ + system_init(); + kernel_init(); + rtc_init(); + + lcd_init(); + backlight_init(); + backlight_on(); + + show_logo(); + + while (1) { + lcd_putsxyf(60, 140, "btn: %08x", button_read_device()); + lcd_update(); + } +} diff --git a/firmware/SOURCES b/firmware/SOURCES index bbe7f06f31..cd10ae2f98 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -423,6 +423,8 @@ drivers/rtc/rtc_s35380a.c drivers/rtc/rtc_d2.c #elif (CONFIG_RTC == RTC_IMX233) drivers/rtc/rtc_imx233.c +#elif (CONFIG_RTC == RTC_STM32H743) +drivers/rtc/rtc_stm32h7.c #endif /* (CONFIG_RTC == RTC_) */ #endif /* PLATFORM_NATIVE */ @@ -1970,6 +1972,30 @@ target/arm/rk27xx/ihifi2/audio-ihifi800.c #endif #endif +#if CONFIG_CPU == STM32H743 +target/arm/stm32/crt0-stm32h7.S +target/arm/stm32/vectors-stm32h7.S +target/arm/stm32/adc-stm32h7.c +target/arm/stm32/debug-stm32h7.c +target/arm/stm32/gpio-stm32h7.c +target/arm/stm32/i2c-stm32h7.c +target/arm/stm32/pcm-stm32h7.c +target/arm/stm32/sd-stm32h7.c +target/arm/stm32/spi-stm32h7.c +target/arm/stm32/system-stm32h7.c +target/arm/stm32/timer-stm32h7.c +target/arm/stm32/usb-stm32h7.c +#endif + +#if defined(ECHO_R1) +target/arm/stm32/echoplayer/audiohw-echoplayer.c +target/arm/stm32/echoplayer/backlight-echoplayer.c +target/arm/stm32/echoplayer/button-echoplayer.c +target/arm/stm32/echoplayer/lcd-echoplayer.c +target/arm/stm32/echoplayer/power-echoplayer.c +target/arm/stm32/echoplayer/system-echoplayer.c +#endif + #if (CONFIG_PLATFORM & PLATFORM_ANDROID) target/hosted/kernel-unix.c target/hosted/filesystem-unix.c diff --git a/firmware/drivers/rtc/rtc_stm32h7.c b/firmware/drivers/rtc/rtc_stm32h7.c new file mode 100644 index 0000000000..b3b7b56d28 --- /dev/null +++ b/firmware/drivers/rtc/rtc_stm32h7.c @@ -0,0 +1,172 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "rtc.h" +#include "timefuncs.h" +#include "stm32h7/rtc.h" +#include "stm32h7/rcc.h" +#include "stm32h7/pwr.h" + +void rtc_init(void) +{ + st_writef(RCC_APB4ENR, RTCAPBEN(1)); + + /* Initialize RTC if needed */ + if (!st_readf(RTC_ISR, INITS)) + { + struct tm tm = { + .tm_hour = 0, + .tm_min = 0, + .tm_sec = 0, + .tm_year = 101, + .tm_mon = 0, + .tm_mday = 1, + .tm_wday = 1, + .tm_isdst = 0, + }; + + rtc_write_datetime(&tm); + } +} + +int rtc_read_datetime(struct tm *tm) +{ + /* + * Wait for RSF bit to indicate time/date registers are valid. + * But if the calendar is not initialized, then don't wait as + * they will never be valid. + */ + bool valid = false; + while (!valid) + { + uint32_t isr = REG_RTC_ISR; + + if (!st_vreadf(isr, RTC_ISR, INITS)) + break; + + if (st_vreadf(isr, RTC_ISR, RSF)) + valid = true; + } + + if (valid) + { + uint32_t tr = REG_RTC_TR; + uint32_t dr = REG_RTC_DR; + + tm->tm_sec = st_vreadf(tr, RTC_TR, ST)*10 + st_vreadf(tr, RTC_TR, SU); + tm->tm_min = st_vreadf(tr, RTC_TR, MNT)*10 + st_vreadf(tr, RTC_TR, MNU); + tm->tm_hour = st_vreadf(tr, RTC_TR, HT)*10 + st_vreadf(tr, RTC_TR, HU); + tm->tm_mday = st_vreadf(dr, RTC_DR, DT)*10 + st_vreadf(dr, RTC_DR, DU); + tm->tm_mon = st_vreadf(dr, RTC_DR, MT)*10 + st_vreadf(dr, RTC_DR, MU) - 1; + tm->tm_year = 100 + st_vreadf(dr, RTC_DR, YT)*10 + st_vreadf(dr, RTC_DR, YU); + tm->tm_isdst = st_readf(RTC_CR, BKP); + } + else + { + tm->tm_sec = 0; + tm->tm_min = 0; + tm->tm_hour = 0; + tm->tm_mday = 1; + tm->tm_mon = 0; + tm->tm_year = 101; + tm->tm_isdst = 0; + } + + set_day_of_week(tm); + set_day_of_year(tm); + + return 1; +} + +int rtc_write_datetime(const struct tm *tm) +{ + /* Allow RTC write protection */ + st_writef(PWR_CR1, DBP(1)); + + /* Unlock registers */ + st_writef(RTC_WPR, KEY_V(KEY1)); + st_writef(RTC_WPR, KEY_V(KEY2)); + + /* Enter initialization mode */ + st_writef(RTC_ISR, INIT(1)); + while (!st_readf(RTC_ISR, INITF)); + + /* Program calendar and dividers */ + st_writef(RTC_PRER, PREDIV_A(127), PREDIV_S(255)); + st_writef(RTC_TR, + PM(0), + HT(tm->tm_hour / 10), + HU(tm->tm_hour % 10), + MNT(tm->tm_min / 10), + MNU(tm->tm_min % 10), + ST(tm->tm_sec / 10), + SU(tm->tm_sec % 10)); + st_writef(RTC_DR, + WDU(tm->tm_wday == 0 ? 7 : tm->tm_wday), + YT((tm->tm_year / 10) % 10), + YU(tm->tm_year % 10), + MT((tm->tm_mon + 1) / 10), + MU((tm->tm_mon + 1) % 10), + DT(tm->tm_mday / 10), + DU(tm->tm_mday % 10)); + st_writef(RTC_CR, + FMT(0), + BKP(!!tm->tm_isdst)); + + /* Exit initialization */ + st_writef(RTC_ISR, INIT(0)); + + /* Lock registers */ + st_writef(RTC_WPR, KEY(0)); + st_writef(PWR_CR1, DBP(0)); + + return 1; +} + +#ifdef HAVE_RTC_ALARM +/* TODO */ +void rtc_set_alarm(int h, int m) +{ + (void)h; + (void)m; +} + +void rtc_get_alarm(int *h, int *m) +{ + *h = 0; + *m = 0; +} + +void rtc_enable_alarm(bool enable) +{ + (void)enable; +} + +bool rtc_check_alarm_started(bool release_alarm) +{ + (void)release_alarm; + return false; +} + +bool rtc_check_alarm_flag(void) +{ + return false; +} +#endif diff --git a/firmware/drivers/usb-designware.c b/firmware/drivers/usb-designware.c index 2933526a1e..01552d9c94 100644 --- a/firmware/drivers/usb-designware.c +++ b/firmware/drivers/usb-designware.c @@ -76,6 +76,9 @@ #elif CONFIG_CPU == S5L8702 || CONFIG_CPU == S5L8720 # define USB_DW_PHYSADDR(x) S5L8702_PHYSICAL_ADDR(x) # define USB_DW_UNCACHEDADDR(x) S5L8702_UNCACHED_ADDR(x) +#elif CONFIG_CPU == STM32H743 +# define USB_DW_PHYSADDR(x) x +# define NO_UNCACHED_ADDR /* TODO: maybe implement this */ #elif !defined(USB_DW_ARCH_SLAVE) # error "Must define USB_DW_PHYSADDR / USB_DW_UNCACHEDADDR!" #endif diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index 067118000e..b9cf87557d 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -238,6 +238,8 @@ struct sound_settings_info #include "fiiolinux_codec.h" #elif defined(HAVE_EROSQ_LINUX_CODEC) #include "erosqlinux_codec.h" +#elif defined(HAVE_TLV320AIC3104) +#include "tlv320aic3104_codec.h" #endif #if defined(HAVE_X1000_ICODEC_REC) && !defined(HAVE_X1000_ICODEC_PLAY) diff --git a/firmware/export/config.h b/firmware/export/config.h index f9cb7786a0..e5af82983e 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -84,6 +84,7 @@ #define IMX233 233 #define RK27XX 2700 #define X1000 1000 +#define STM32H743 32743 /* platforms * bit fields to allow PLATFORM_HOSTED to be OR'ed e.g. with a @@ -163,6 +164,7 @@ #define EROSQ_PAD 72 #define FIIO_M3K_PAD 73 #define SHANLING_Q1_PAD 74 +#define ECHO_R1_PAD 75 /* CONFIG_REMOTE_KEYPAD */ #define H100_REMOTE 1 @@ -282,6 +284,7 @@ #define LCD_FIIOM3K 69 /* as used by the FiiO M3K */ #define LCD_SHANLING_Q1 70 /* as used by the Shanling Q1 */ #define LCD_EROSQ 71 /* as used by the ErosQ (native) */ +#define LCD_ECHO_R1 72 /* ILI9342, as used by the Echo R1 */ /* LCD_PIXELFORMAT */ #define HORIZONTAL_PACKING 1 @@ -359,6 +362,7 @@ Lyre prototype 1 */ #define RTC_CONNECT 24 /* Sansa Connect AVR */ #define RTC_NANO3G 25 /* Dialog Semiconductor D1671 ??? */ #define RTC_NANO4G 26 /* Dialog Semiconductor D1759 ??? */ +#define RTC_STM32H743 27 /* USB On-the-go */ #define USBOTG_M66591 6591 /* M:Robe 500 */ @@ -610,6 +614,8 @@ Lyre prototype 1 */ #include "config/shanlingq1.h" #elif defined(EROS_QN) #include "config/erosqnative.h" +#elif defined(ECHO_R1) +#include "config/echor1.h" #else //#error "unknown hwardware platform!" #endif diff --git a/firmware/export/config/echor1.h b/firmware/export/config/echor1.h new file mode 100644 index 0000000000..7467ebcc97 --- /dev/null +++ b/firmware/export/config/echor1.h @@ -0,0 +1,114 @@ +/* RoLo-related defines */ +#define MODEL_NAME "Echo R1" +#define MODEL_NUMBER 119 +#define BOOTFILE_EXT "echo" +#define BOOTFILE "rockbox." BOOTFILE_EXT +#define BOOTDIR "/.rockbox" + +/* CPU defines */ +#define CONFIG_CPU STM32H743 +#define STM32_LSE_FREQ 32768 +#define STM32_HSE_FREQ 24000000 +#define CPU_FREQ 480000000 + +#ifndef SIMULATOR +#define TIMER_FREQ STM32_HSE_FREQ +#endif + +/* Kernel defines */ +#define INCLUDE_TIMEOUT_API +#define HAVE_SEMAPHORE_OBJECTS + +/* Buffer for plugins and codecs. */ +#define PLUGIN_BUFFER_SIZE 0x200000 /* 2 MiB */ +#define CODEC_SIZE 0x100000 /* 1 MiB */ + +/* LCD defines */ +#define CONFIG_LCD LCD_ECHO_R1 +#define LCD_WIDTH 320 +#define LCD_HEIGHT 240 +#define LCD_DEPTH 16 +#define LCD_PIXELFORMAT RGB565 +#define LCD_DPI 240 // FIXME: review this. +#define HAVE_LCD_COLOR +#define HAVE_LCD_BITMAP +#define HAVE_LCD_ENABLE + +/* Backlight defines */ +#define HAVE_BACKLIGHT +#define HAVE_BACKLIGHT_BRIGHTNESS +#define MIN_BRIGHTNESS_SETTING 1 +#define MAX_BRIGHTNESS_SETTING 100 +#define BRIGHTNESS_STEP 5 +#define DEFAULT_BRIGHTNESS_SETTING 70 +#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING + +/* Codec / audio hardware defines */ +#define HW_SAMPR_CAPS SAMPR_CAP_ALL_96 // FIXME: check this section +#define REC_SAMPR_CAPS SAMPR_CAP_ALL_96 +#define INPUT_SRC_CAPS SRC_CAP_MIC +#define AUDIOHW_CAPS MIC_GAIN_CAP +#define HAVE_RECORDING +#define HAVE_TLV320AIC3104 // TODO: Sansa connect uses the AIC3106, possible code sharing? +#define HAVE_SW_TONE_CONTROLS +#define HAVE_SW_VOLUME_CONTROL +#define DEFAULT_REC_MIC_GAIN 12 + +/* Button defines */ +#define CONFIG_KEYPAD ECHO_R1_PAD +#define HAVE_HEADPHONE_DETECTION +#define HAVE_LINEOUT_DETECTION + +/* Storage defines */ +#define CONFIG_STORAGE STORAGE_SD +#define HAVE_HOTSWAP +#define HAVE_HOTSWAP_STORAGE_AS_MAIN +#define HAVE_MULTIVOLUME +#define STORAGE_WANTS_ALIGN +#define STORAGE_NEEDS_BOUNCE_BUFFER + +/* RTC settings */ +#define CONFIG_RTC RTC_STM32H743 +#define HAVE_RTC_ALARM + +/* Power management */ +#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE +#define CONFIG_CHARGING CHARGING_MONITOR +#define HAVE_SW_POWEROFF + +/* Only one battery type */ +#define BATTERY_CAPACITY_DEFAULT 1100 +#define BATTERY_CAPACITY_MIN 1100 +#define BATTERY_CAPACITY_MAX 1100 +#define BATTERY_CAPACITY_INC 0 + +/* Multiboot */ +#define HAVE_BOOTDATA +#define BOOT_REDIR "rockbox_main.echor1" + +/* USB support */ +#ifndef SIMULATOR +#define CONFIG_USBOTG USBOTG_DESIGNWARE +#define USB_DW_TURNAROUND 5 +#define HAVE_USBSTACK +#define USB_VENDOR_ID 0x1 +#define USB_PRODUCT_ID 0x2 +#define USB_DEVBSS_ATTR __attribute__((aligned(32))) +#define HAVE_USB_POWER +//#define HAVE_USB_CHARGING_ENABLE +//#define HAVE_USB_CHARGING_IN_THREAD +//#define TARGET_USB_CHARGING_DEFAULT USB_CHARGING_FORCE +#define HAVE_BOOTLOADER_USB_MODE +#endif + +/* Rockbox capabilities */ +#define HAVE_FAT16SUPPORT +#define HAVE_ALBUMART +#define HAVE_BMP_SCALING +#define HAVE_JPEG +#define HAVE_TAGCACHE +#define HAVE_VOLUME_IN_LIST +#define HAVE_QUICKSCREEN +#define HAVE_HOTKEY +#define AB_REPEAT_ENABLE +#define HAVE_BOOTLOADER_SCREENDUMP diff --git a/firmware/export/cpu.h b/firmware/export/cpu.h index e985f4473b..701baa9e78 100644 --- a/firmware/export/cpu.h +++ b/firmware/export/cpu.h @@ -77,3 +77,6 @@ #if CONFIG_CPU == X1000 #include "x1000.h" #endif +#if CONFIG_CPU == STM32H743 +#include "cpu-stm32h743.h" +#endif diff --git a/firmware/export/tlv320aic3104_codec.h b/firmware/export/tlv320aic3104_codec.h new file mode 100644 index 0000000000..7caee62f4e --- /dev/null +++ b/firmware/export/tlv320aic3104_codec.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __TLV320AIC3104_CODEC__ +#define __TLV320AIC3104_CODEC__ + +// FIXME: range +AUDIOHW_SETTING(VOLUME, "dB", 0, 2, -74, -2, -40) +AUDIOHW_SETTING(MIC_GAIN, "dB", 0, 1, 0, 63, 12) + +#endif /* __TLV320AIC3104_CODEC__ */ diff --git a/firmware/target/arm/stm32/adc-stm32h7.c b/firmware/target/arm/stm32/adc-stm32h7.c new file mode 100644 index 0000000000..8d53ba8e1f --- /dev/null +++ b/firmware/target/arm/stm32/adc-stm32h7.c @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "adc.h" + +void adc_init(void) +{ +} diff --git a/firmware/target/arm/stm32/app.lds b/firmware/target/arm/stm32/app.lds new file mode 100644 index 0000000000..4e5e393d28 --- /dev/null +++ b/firmware/target/arm/stm32/app.lds @@ -0,0 +1,97 @@ +#include "cpu.h" + +/* + * TODO: this is temporary and has not been tested + */ + +ENTRY(main) +OUTPUT_FORMAT(elf32-littlearm) +OUTPUT_ARCH(arm) +STARTUP(target/arm/stm32/crt0-stm32h7.o) + +MEMORY +{ + SRAM_AXI (rwx) : ORIGIN = STM32_SRAM_AXI_BASE, LENGTH = STM32_SRAM_AXI_SIZE + DTCM (rwx) : ORIGIN = STM32_DTCM_BASE, LENGTH = STM32_DTCM_SIZE + ITCM (rwx) : ORIGIN = STM32_ITCM_BASE, LENGTH = STM32_ITCM_SIZE + SDRAM (rwx) : ORIGIN = STM32_SDRAM1_BASE, LENGTH = MEMORYSIZE * 1024 * 1024 +} + +/* + * to control section alignment (only affects on-disk alignment): + * -Wl,-z,max-page-size=0x1 + */ + +PHDRS +{ + sram_rx PT_LOAD ; + sram_ro PT_LOAD ; + sram_rw PT_LOAD ; + itcm PT_LOAD ; + dtcm PT_LOAD ; + sdram_rx PT_LOAD ; + sdram_rw PT_LOAD ; +} + +SECTIONS +{ + .text : + { + loadaddress = .; /* only needed to keep ROLO happy */ + + KEEP(*(.bootdata)) + *(.init.text*) + *(.text*) + } > SRAM_AXI :sram_rx + + .rodata : + { + *(.rodata*) + } > SRAM_AXI :sram_ro + + .data : + { + _databegin = .; + *(.data*) + _dataend = .; + } > SRAM_AXI :sram_rw + _datacopy = LOADADDR(.data); + + .itext : + { + KEEP(*(.vectors.arm)) + KEEP(*(.vectors.platform)) + *(.icode*); + } > ITCM :itcm + + .stack (NOLOAD) : + { + irqstackbegin = .; + . += 0x400; + irqstackend = .; + + stackbegin = .; + . += 0x2000; + stackend = .; + + *(.stack); + } > DTCM :dtcm + + .bss (NOLOAD) : + { + _bssbegin = .; + *(.bss*); + *(COMMON); + _bssend = .; + } > SDRAM :sdram_rw + + audiobuffer = ALIGN(32); + audiobufend = ORIGIN(SDRAM) + LENGTH(SDRAM) - CODEC_SIZE - PLUGIN_BUFFER_SIZE; + codecbuf = audiobufend; + pluginbuf = codecbuf + CODEC_SIZE; +} + +EXTERN(__vectors_arm); +EXTERN(__vectors_platform); +ASSERT(DEFINED(__vectors_arm), "ARM exception vectors are not defined."); +ASSERT(DEFINED(__vectors_platform), "Platform exception vectors are not defined."); diff --git a/firmware/target/arm/stm32/boot.lds b/firmware/target/arm/stm32/boot.lds new file mode 100644 index 0000000000..8355660eaa --- /dev/null +++ b/firmware/target/arm/stm32/boot.lds @@ -0,0 +1,70 @@ +#include "cpu.h" + +#if 0 +/* version for openocd load to ram -- faster to upload than flash */ +# define TEXT_MEM SRAM_AXI +# define DATA_MEM SRAM_AXI +#else +# define TEXT_MEM FLASH1 +# define DATA_MEM SRAM_AXI +#endif + +ENTRY(reset_handler) +OUTPUT_FORMAT(elf32-littlearm) +OUTPUT_ARCH(arm) +STARTUP(target/arm/stm32/crt0-stm32h7.o) + +MEMORY +{ + SRAM_AXI (rwx) : ORIGIN = STM32_SRAM_AXI_BASE, LENGTH = STM32_SRAM_AXI_SIZE + ITCM (rwx) : ORIGIN = STM32_ITCM_BASE, LENGTH = STM32_ITCM_SIZE + DTCM (rwx) : ORIGIN = STM32_DTCM_BASE, LENGTH = STM32_DTCM_SIZE + FLASH1 (rx) : ORIGIN = STM32_FLASH_BANK1_BASE, LENGTH = STM32_FLASH_BANK1_SIZE + FLASH2 (rx) : ORIGIN = STM32_FLASH_BANK2_BASE, LENGTH = STM32_FLASH_BANK2_SIZE +} + +SECTIONS +{ + .text : + { + KEEP(*(.vectors.arm)) + KEEP(*(.vectors.platform)) + *(.init.text*) + *(.text*) + *(.rodata*) + } > TEXT_MEM + + .data : + { + _databegin = .; + *(.data*) + _dataend = .; + } > DATA_MEM AT> TEXT_MEM + _datacopy = LOADADDR(.data); + + .bss (NOLOAD) : + { + _bssbegin = .; + *(.bss*); + *(COMMON); + _bssend = .; + } > DATA_MEM + + .stack (NOLOAD) : ALIGN(4) + { + irqstackbegin = .; + . += 0x400; + irqstackend = .; + + stackbegin = .; + . += 0x2000; + stackend = .; + + *(.stack); + } > DTCM +} + +EXTERN(__vectors_arm); +EXTERN(__vectors_platform); +ASSERT(DEFINED(__vectors_arm), "ARM exception vectors are not defined."); +ASSERT(DEFINED(__vectors_platform), "Platform exception vectors are not defined."); diff --git a/firmware/target/arm/stm32/cpu-stm32h743.h b/firmware/target/arm/stm32/cpu-stm32h743.h new file mode 100644 index 0000000000..fc10fdb954 --- /dev/null +++ b/firmware/target/arm/stm32/cpu-stm32h743.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __CPU_STM32H743_H__ +#define __CPU_STM32H743_H__ + +#define CACHE_SIZE (16 * 1024) +#define CACHEALIGN_BITS 5 + +#define DCACHE_SIZE CACHE_SIZE +#define DCACHE_WAYS 0x4 +#define DCACHE_SETS 0x80 +#define DCACHE_LINESIZE (1 << CACHEALIGN_BITS) + +#define STM32_LSI_FREQ 32000 +#define STM32_HSI_FREQ 64000000 +#define STM32_CSI_FREQ 4000000 +#define STM32_HSI48_FREQ 48000000 + +#define OTGBASE 0x40080000 +#define USB_NUM_ENDPOINTS 9 + +#define STM32_ITCM_BASE 0x00000000 +#define STM32_ITCM_SIZE (64 * 1024) + +#define STM32_DTCM_BASE 0x20000000 +#define STM32_DTCM_SIZE (128 * 1024) + +#define STM32_SRAM_AXI_BASE 0x24000000 +#define STM32_SRAM_AXI_SIZE (512 * 1024) + +#define STM32_SRAM1_BASE 0x30000000 +#define STM32_SRAM1_SIZE (128 * 1024) + +#define STM32_SRAM2_BASE 0x30020000 +#define STM32_SRAM2_SIZE (128 * 1024) + +#define STM32_SRAM3_BASE 0x30040000 +#define STM32_SRAM3_SIZE (128 * 1024) + +#define STM32_SRAM4_BASE 0x38000000 +#define STM32_SRAM4_SIZE (64 * 1024) + +#define STM32_SRAM_BKP_BASE 0x38800000 +#define STM32_SRAM_BKP_SIZE (4 * 1024) + +#define STM32_FLASH_BANK1_BASE 0x08000000 +#define STM32_FLASH_BANK1_SIZE (1024 * 1024) + +#define STM32_FLASH_BANK2_BASE 0x08100000 +#define STM32_FLASH_BANK2_SIZE (1024 * 1024) + +/* FIXME: this changes depending on target settings */ +#define STM32_SDRAM1_BASE 0x70000000 + +#endif /* __CPU_STM32H743_H__ */ diff --git a/firmware/target/arm/stm32/crt0-stm32h7.S b/firmware/target/arm/stm32/crt0-stm32h7.S new file mode 100644 index 0000000000..2eafbc3123 --- /dev/null +++ b/firmware/target/arm/stm32/crt0-stm32h7.S @@ -0,0 +1,124 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "bootdata.h" +#include "stm32h7/pwr.h" + + .syntax unified + .text + +#if defined(HAVE_BOOTDATA) && !defined(BOOTLOADER) + .section .bootdata + +put_boot_data_here +#endif + + .section .init.text,"ax",%progbits + + .global reset_handler + .type reset_handler, function +reset_handler: + /* + * After power-up the CPU will be in limited Run* mode and many things + * won't work; we need to program the power supply configuration first + * before doing anything else. Below the internal LDO is configured as + * the power supply. + */ + ldr r0, =STA_PWR_CR3 + ldr r1, [r0] @ Read PWR_CR3 + orr r1, #BM_PWR_CR3_LDOEN @ Set LDOEN=1 + bic r1, #BM_PWR_CR3_BYPASS @ Set BYPASS=0 + str r1, [r0] @ Write updated value to PWR_CR3 + + /* Wait for PSR_CSR1.ACTVOSRDY, which indicates we exited Run* mode */ + ldr r0, =STA_PWR_CSR1 +1: + ldr r1, [r0] @ Read PWR_CSR1 + ands r1, #BM_PWR_CSR1_ACTVOSRDY + beq 1b @ Loop back if ACTVOSRDY==0 + + /* Now jump to the common startup code */ + b crt0_start + + + .global start + .type start, function +crt0_start: + /* Zero out BSS */ + ldr a1, =_bssbegin + ldr a2, =_bssend + mov a3, #0 + bl crt0_area_clear + + /* Copy data section */ + ldr a1, =_databegin + ldr a2, =_dataend + ldr a3, =_datacopy + bl crt0_area_copy + + /* Clear the main thread stack */ + ldr a1, =stackbegin + ldr a2, =stackend + ldr a3, =0xdeadbeef + bl crt0_area_clear + + /* Clear the IRQ stack */ + ldr a1, =irqstackbegin + ldr a2, =irqstackend + ldr a3, =0xdeadbeef + bl crt0_area_clear + + /* Use MSP for IRQ handlers */ + ldr r0, =irqstackend + msr msp, r0 + + /* Use PSP for application code */ + ldr r0, =stackend + msr psp, r0 + + /* Enter thread mode; now sp points to PSP */ + mrs r2, control + orr r2, #2 + msr control, r2 + + /* Jump to main */ + b main + + + .local crt0_area_copy + .type crt0_area_copy, function +/* crt0_area_copy(uint32_t *dst, uint32_t *dst_end, const void *src) */ +crt0_area_copy: + cmp a2, a1 + ldrhi v1, [a3], #4 + strhi v1, [a1], #4 + bhi crt0_area_copy + bx lr + + + .local crt0_area_clear + .type crt0_area_clear, function +/* crt0_area_clear(const uint32_t *dst, const uint32_t *end, uint32_t value) */ +crt0_area_clear: + cmp a2, a1 + strhi a3, [a1], #4 + bhi crt0_area_clear + bx lr diff --git a/firmware/target/arm/stm32/debug-stm32h7.c b/firmware/target/arm/stm32/debug-stm32h7.c new file mode 100644 index 0000000000..e7ffd1c37a --- /dev/null +++ b/firmware/target/arm/stm32/debug-stm32h7.c @@ -0,0 +1,31 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" + +bool dbg_hw_info(void) +{ + return false; +} + +bool dbg_ports(void) +{ + return false; +} diff --git a/firmware/target/arm/stm32/echoplayer/adc-target.h b/firmware/target/arm/stm32/echoplayer/adc-target.h new file mode 100644 index 0000000000..6c0eafc463 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/adc-target.h @@ -0,0 +1,24 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __ECHOPLAYER_ADC_TARGET_H__ +#define __ECHOPLAYER_ADC_TARGET_H__ + +#endif /* __ECHOPLAYER_ADC_TARGET_H__ */ diff --git a/firmware/target/arm/stm32/echoplayer/audiohw-echoplayer.c b/firmware/target/arm/stm32/echoplayer/audiohw-echoplayer.c new file mode 100644 index 0000000000..b1a0c39fa8 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/audiohw-echoplayer.c @@ -0,0 +1,57 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "audiohw.h" + +void audiohw_init(void) +{ +} + +void audiohw_postinit(void) +{ +} + +void audiohw_close(void) +{ +} + +void audio_set_output_source(int source) +{ + (void)source; +} + +void audiohw_set_recvol(int left, int right, int type) +{ + (void)left; + (void)right; + (void)type; +} + +void audiohw_set_volume(int vol_l, int vol_r) +{ + (void)vol_l; + (void)vol_r; +} + +void audio_input_mux(int source, unsigned flags) +{ + (void)source; + (void)flags; +} diff --git a/firmware/target/arm/stm32/echoplayer/backlight-echoplayer.c b/firmware/target/arm/stm32/echoplayer/backlight-echoplayer.c new file mode 100644 index 0000000000..ea278afb6a --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/backlight-echoplayer.c @@ -0,0 +1,46 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "backlight.h" +#include "gpio-stm32h7.h" + +bool backlight_hw_init(void) +{ + /* FIXME: override PWM config for now, rev1 has broken backlight */ + gpio_configure_single(GPIO_BACKLIGHT, + GPIOF_OUTPUT(1, GPIO_TYPE_PUSH_PULL, + GPIO_SPEED_LOW, GPIO_PULL_DISABLED)); + return true; +} + +void backlight_hw_on(void) +{ + gpio_set_level(GPIO_BACKLIGHT, 1); +} + +void backlight_hw_off(void) +{ + gpio_set_level(GPIO_BACKLIGHT, 0); +} + +void backlight_hw_brightness(int brightness) +{ + (void)brightness; +} diff --git a/firmware/target/arm/stm32/echoplayer/backlight-target.h b/firmware/target/arm/stm32/echoplayer/backlight-target.h new file mode 100644 index 0000000000..2af6fdf6ff --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/backlight-target.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __ECHOPLAYER_BACKLIGHT_TARGET_H__ +#define __ECHOPLAYER_BACKLIGHT_TARGET_H__ + +#include + +extern bool backlight_hw_init(void); + +extern void backlight_hw_on(void); +extern void backlight_hw_off(void); +extern void backlight_hw_brightness(int brightness); + +#endif /* __ECHOPLAYER_BACKLIGHT_TARGET_H__ */ diff --git a/firmware/target/arm/stm32/echoplayer/button-echoplayer.c b/firmware/target/arm/stm32/echoplayer/button-echoplayer.c new file mode 100644 index 0000000000..1b1cc47c70 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/button-echoplayer.c @@ -0,0 +1,85 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "button.h" +#include "gpio-stm32h7.h" + +void button_init_device(void) +{ +} + +int button_read_device(void) +{ + int buttons = 0; + + /* Most buttons are active low, so invert the read */ + uint32_t ga = ~REG_GPIO_IDR(GPIO_A); + uint32_t gb = ~REG_GPIO_IDR(GPIO_B); + uint32_t gc = ~REG_GPIO_IDR(GPIO_C); + uint32_t gd = ~REG_GPIO_IDR(GPIO_D); + uint32_t gf = ~REG_GPIO_IDR(GPIO_F); + uint32_t gh = ~REG_GPIO_IDR(GPIO_H); + + if (ga & BIT_N(GPION_PIN(GPIO_BUTTON_A))) + buttons |= BUTTON_A; + if (ga & BIT_N(GPION_PIN(GPIO_BUTTON_B))) + buttons |= BUTTON_B; + if (ga & BIT_N(GPION_PIN(GPIO_BUTTON_X))) + buttons |= BUTTON_X; + if (ga & BIT_N(GPION_PIN(GPIO_BUTTON_Y))) + buttons |= BUTTON_A; + + if (!(gb & BIT_N(GPION_PIN(GPIO_BUTTON_SELECT)))) + buttons |= BUTTON_SELECT; + if (gb & BIT_N(GPION_PIN(GPIO_BUTTON_UP))) + buttons |= BUTTON_UP; + if (gb & BIT_N(GPION_PIN(GPIO_BUTTON_VOL_DOWN))) + buttons |= BUTTON_UP; + + if (gc & BIT_N(GPION_PIN(GPIO_BUTTON_RIGHT))) + buttons |= BUTTON_RIGHT; + + if (gd & BIT_N(GPION_PIN(GPIO_BUTTON_START))) + buttons |= BUTTON_START; + if (gd & BIT_N(GPION_PIN(GPIO_BUTTON_DOWN))) + buttons |= BUTTON_DOWN; + if (gd & BIT_N(GPION_PIN(GPIO_BUTTON_LEFT))) + buttons |= BUTTON_LEFT; + + if (!(gf & BIT_N(GPION_PIN(GPIO_BUTTON_POWER)))) + buttons |= BUTTON_POWER; + + if (gh & BIT_N(GPION_PIN(GPIO_BUTTON_VOL_UP))) + buttons |= BUTTON_VOL_UP; + if (gh & BIT_N(GPION_PIN(GPIO_BUTTON_HOLD))) + buttons |= BUTTON_HOLD; + + return buttons; +} + +bool headphones_inserted(void) +{ + return true; +} + +bool lineout_inserted(void) +{ + return false; +} diff --git a/firmware/target/arm/stm32/echoplayer/button-target.h b/firmware/target/arm/stm32/echoplayer/button-target.h new file mode 100644 index 0000000000..e8233c4a74 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/button-target.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __ECHOPLAYER_BUTTON_TARGET_H__ +#define __ECHOPLAYER_BUTTON_TARGET_H__ + +#define BUTTON_POWER 0x00000001 +#define BUTTON_HOLD 0x00000002 +#define BUTTON_VOL_UP 0x00000004 +#define BUTTON_VOL_DOWN 0x00000008 +#define BUTTON_UP 0x00000010 +#define BUTTON_DOWN 0x00000020 +#define BUTTON_LEFT 0x00000040 +#define BUTTON_RIGHT 0x00000080 +#define BUTTON_A 0x00000100 +#define BUTTON_B 0x00000200 +#define BUTTON_X 0x00000400 +#define BUTTON_Y 0x00000800 +#define BUTTON_START 0x00001000 +#define BUTTON_SELECT 0x00002000 + +#define BUTTON_MAIN 0x00003fff + +#define POWEROFF_BUTTON BUTTON_POWER +#define POWEROFF_COUNT 30 + +#endif /* __ECHOPLAYER_BUTTON_TARGET_H__ */ diff --git a/firmware/target/arm/stm32/echoplayer/gpio-target.h b/firmware/target/arm/stm32/echoplayer/gpio-target.h new file mode 100644 index 0000000000..122bef0818 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/gpio-target.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __ECHOPLAYER_GPIO_TARGET_H__ +#define __ECHOPLAYER_GPIO_TARGET_H__ + +#define GPIO_BUTTON_A GPIO_PA(0) +#define GPIO_BUTTON_B GPIO_PA(1) +#define GPIO_BUTTON_X GPIO_PA(6) +#define GPIO_BUTTON_Y GPIO_PA(4) +#define GPIO_BUTTON_START GPIO_PD(12) +#define GPIO_BUTTON_SELECT GPIO_PB(8) +#define GPIO_BUTTON_UP GPIO_PB(14) +#define GPIO_BUTTON_DOWN GPIO_PD(6) +#define GPIO_BUTTON_LEFT GPIO_PD(7) +#define GPIO_BUTTON_RIGHT GPIO_PC(6) +#define GPIO_BUTTON_VOL_UP GPIO_PH(6) +#define GPIO_BUTTON_VOL_DOWN GPIO_PB(15) +#define GPIO_BUTTON_POWER GPIO_PF(8) +#define GPIO_BUTTON_HOLD GPIO_PH(7) + +#define GPIO_CPU_POWER_ON GPIO_PA(2) +#define GPIO_POWER_1V8 GPIO_PD(3) +#define GPIO_CODEC_AVDD_EN GPIO_PB(9) +#define GPIO_CODEC_DVDD_EN GPIO_PC(5) +#define GPIO_CODEC_RESET GPIO_PC(4) +#define GPIO_USBPHY_POWER_EN GPIO_PD(4) +#define GPIO_USBPHY_RESET GPIO_PD(5) + +#define GPIO_CHARGER_CHARGING GPIO_PA(10) +#define GPIO_CHARGER_ENABLE GPIO_PA(15) + +#define GPIO_SDMMC_DETECT GPIO_PC(7) +#define GPIO_LINEOUT_DETECT GPIO_PG(13) + +#define GPIO_LCD_RESET GPIO_PD(11) +#define GPIO_BACKLIGHT GPIO_PD(13) + +#endif /* __ECHOPLAYER_GPIO_TARGET_H__ */ diff --git a/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c b/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c new file mode 100644 index 0000000000..a60c9635eb --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c @@ -0,0 +1,134 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "kernel.h" +#include "lcd.h" +#include "spi-stm32h7.h" +#include "gpio-stm32h7.h" +#include "stm32h7/rcc.h" + +struct stm_spi_config spi_cfg = { + .num = STM_SPI5, + .mode = STM_SPIMODE_HALF_DUPLEX, + .proto = STM_SPIPROTO_MOTOROLA, + .frame_bits = 9, + .hw_cs_output = true, +}; + +struct stm_spi spi; + +#define ili_cmd(cmd, ...) \ + do { \ + uint16_t arr[] = {cmd, __VA_ARGS__}; \ + for (size_t i = 1; i < ARRAYLEN(arr); ++i) \ + arr[i] |= 0x100; \ + stm_spi_transmit(&spi, arr, sizeof(arr)); \ + } while (0) + +static void set_row_column_address(int x, int y, int w, int h) +{ + ili_cmd(0x2a, x >> 8, x & 0xff, (w-1) >> 8, (w-1) & 0xff); + ili_cmd(0x2b, y >> 8, y & 0xff, (h-1) >> 8, (h-1) & 0xff); +} + +void lcd_init_device(void) +{ + /* Clock configuration -- should be 12 MHz (SPI clock is 1/2 of HSE) */ + st_writef(RCC_D2CCIP1R, SPI45SEL_V(HSE)); + st_writef(RCC_APB2ENR, SPI5EN(1)); + + /* Configure SPI bus */ + stm_spi_init(&spi, &spi_cfg); + + /* Ensure controller is reset */ + gpio_set_level(GPIO_LCD_RESET, 0); + sleep(12); + + gpio_set_level(GPIO_LCD_RESET, 1); + sleep(12); + + /* Sleep out */ + ili_cmd(0x11); + sleep(12); + + /* memory access control (X/Y invert, BGR panel) */ + ili_cmd(0x36, 0xc8); + + /* pixel format set (16bpp) */ + ili_cmd(0x3a, 0x55); + + /* display ON */ + ili_cmd(0x29); +} + +bool lcd_active(void) +{ + return true; +} + +void lcd_update(void) +{ + lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); +} + +void lcd_update_rect(int x, int y, int width, int height) +{ + /* row buffer to minimize time wasted in post-transaction delay */ + static uint16_t row[LCD_WIDTH * 2]; + + if (x < 0) + x = 0; + else if (x >= LCD_WIDTH) + x = LCD_WIDTH - 1; + + if (y < 0) + y = 0; + else if (y >= LCD_HEIGHT) + y = LCD_HEIGHT - 1; + + if (width > LCD_WIDTH - x) + width = LCD_WIDTH - x; + + if (height > LCD_HEIGHT - y) + height = LCD_HEIGHT - y; + + set_row_column_address(x, y, width, height); + ili_cmd(0x2c); + + for (int py = y; py < height; ++py) + { + for (int px = x; px < width; ++px) + { + fb_data *fb = FBADDR(px, py); + uint16_t *data = &row[px * 2]; + + data[0] = 0x100; + data[0] |= (FB_UNPACK_RED(*fb) >> 3) << 3; + data[0] |= (FB_UNPACK_GREEN(*fb) >> 5); + + data[1] = 0x100; + data[1] |= ((FB_UNPACK_GREEN(*fb) >> 2) & 0x7) << 5; + data[1] |= (FB_UNPACK_BLUE(*fb) >> 3); + } + + stm_spi_transmit(&spi, &row[x * 2], width * sizeof(*row) * 2); + } +} diff --git a/firmware/target/arm/stm32/echoplayer/power-echoplayer.c b/firmware/target/arm/stm32/echoplayer/power-echoplayer.c new file mode 100644 index 0000000000..e001a3a6f2 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/power-echoplayer.c @@ -0,0 +1,64 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "power.h" + +unsigned short battery_level_disksafe = 3500; +unsigned short battery_level_shutoff = 3400; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ +unsigned short percent_to_volt_discharge[11] = +{ + 3400, 3639, 3697, 3723, 3757, 3786, 3836, 3906, 3980, 4050, 4159 +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ +unsigned short percent_to_volt_charge[11] = +{ + 3485, 3780, 3836, 3857, 3890, 3930, 3986, 4062, 4158, 4185, 4196 +}; + +/* Power management */ +void power_init(void) +{ +} + +void power_off(void) +{ +} + +void system_reboot(void) +{ +} + +unsigned int power_input_status(void) +{ + return POWER_INPUT_USB_CHARGER; +} + +bool charging_state(void) +{ + return true; +} + +int _battery_voltage(void) +{ + return 4000; +} diff --git a/firmware/target/arm/stm32/echoplayer/system-echoplayer.c b/firmware/target/arm/stm32/echoplayer/system-echoplayer.c new file mode 100644 index 0000000000..9a3d16b615 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/system-echoplayer.c @@ -0,0 +1,173 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "gpio-stm32h7.h" +#include "stm32h7/rcc.h" +#include "stm32h7/fmc.h" + +#define F_INPUT GPIOF_INPUT(GPIO_PULL_DISABLED) +#define F_INPUT_PU GPIOF_INPUT(GPIO_PULL_UP) +#define F_INPUT_PD GPIOF_INPUT(GPIO_PULL_DOWN) +#define F_OUT_LS(x) GPIOF_OUTPUT(x, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_LOW, GPIO_PULL_DISABLED) +#define F_SDRAM GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_OTG_FS GPIOF_ANALOG() +#define F_ULPI GPIOF_FUNCTION(10, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_MCO1 GPIOF_FUNCTION(0, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_I2C1 GPIOF_FUNCTION(4, GPIO_TYPE_OPEN_DRAIN, GPIO_SPEED_LOW, GPIO_PULL_DISABLED) +#define F_SDMMC1 GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_SAI1 GPIOF_FUNCTION(6, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_SPI5 GPIOF_FUNCTION(5, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_LCD_AF14 GPIOF_FUNCTION(14, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_LCD_AF9 GPIOF_FUNCTION(9, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_LPTIM4_OUT GPIOF_FUNCTION(3, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_LOW, GPIO_PULL_DISABLED) +#define F_LPTIM1_OUT GPIOF_FUNCTION(1, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) + +static const struct gpio_setting gpios[] = { + STM_DEFGPIO(GPIO_BUTTON_A, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_B, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_X, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_Y, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_START, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_SELECT, F_INPUT), /* external pulldown */ + STM_DEFGPIO(GPIO_BUTTON_UP, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_DOWN, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_LEFT, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_RIGHT, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_VOL_UP, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_VOL_DOWN, F_INPUT_PU), + STM_DEFGPIO(GPIO_BUTTON_POWER, F_INPUT_PD), + STM_DEFGPIO(GPIO_BUTTON_HOLD, F_INPUT_PU), + STM_DEFGPIO(GPIO_CPU_POWER_ON, F_LPTIM4_OUT), + STM_DEFGPIO(GPIO_POWER_1V8, F_OUT_LS(0)), /* active high */ + STM_DEFGPIO(GPIO_CODEC_AVDD_EN, F_OUT_LS(1)), /* active low */ + STM_DEFGPIO(GPIO_CODEC_DVDD_EN, F_OUT_LS(1)), /* active low */ + STM_DEFGPIO(GPIO_CODEC_RESET, F_OUT_LS(0)), /* active low */ + STM_DEFGPIO(GPIO_USBPHY_POWER_EN, F_OUT_LS(1)), /* active low */ + STM_DEFGPIO(GPIO_USBPHY_RESET, F_OUT_LS(0)), /* active low */ + STM_DEFGPIO(GPIO_CHARGER_CHARGING, F_INPUT_PU), /* active low */ + STM_DEFGPIO(GPIO_CHARGER_ENABLE, F_INPUT), /* hi-z: off, gnd: on */ + STM_DEFGPIO(GPIO_SDMMC_DETECT, F_INPUT_PU), /* active low */ + STM_DEFGPIO(GPIO_LINEOUT_DETECT, F_INPUT), /* external pullup */ + STM_DEFGPIO(GPIO_LCD_RESET, F_OUT_LS(0)), /* active low */ + STM_DEFGPIO(GPIO_BACKLIGHT, F_LPTIM1_OUT), +}; + +/* TODO - replace hex constants - there are probably mistakes here */ + +static const struct pingroup_setting pingroups[] = { + /* FMC - SDRAM1 */ + STM_DEFPINS(GPIO_A, 0x0080, F_SDRAM), + STM_DEFPINS(GPIO_C, 0x000c, F_SDRAM), + STM_DEFPINS(GPIO_D, 0xc703, F_SDRAM), + STM_DEFPINS(GPIO_E, 0xff83, F_SDRAM), + STM_DEFPINS(GPIO_F, 0xf83f, F_SDRAM), + STM_DEFPINS(GPIO_G, 0x8137, F_SDRAM), + /* OTG_FS */ + STM_DEFPINS(GPIO_A, 0x1a00, F_OTG_FS), + /* OTG_HS - ULPI */ + STM_DEFPINS(GPIO_A, 0x0028, F_ULPI), + STM_DEFPINS(GPIO_B, 0x3c23, F_ULPI), + STM_DEFPINS(GPIO_C, 0x0001, F_ULPI), + STM_DEFPINS(GPIO_H, 0x0010, F_ULPI), + STM_DEFPINS(GPIO_I, 0x0100, F_ULPI), + /* MCO1 for USB PHY */ + STM_DEFPINS(GPIO_A, 0x0100, F_MCO1), + /* I2C1 */ + STM_DEFPINS(GPIO_B, 0x00c0, F_I2C1), + /* SDMMC1 */ + STM_DEFPINS(GPIO_C, 0x1f00, F_SDMMC1), + STM_DEFPINS(GPIO_D, 0x0004, F_SDMMC1), + /* SAI1 */ + STM_DEFPINS(GPIO_E, 0x007c, F_SAI1), + /* SPI5 */ + STM_DEFPINS(GPIO_F, 0x02c0, F_SPI5), + /* LCD */ + STM_DEFPINS(GPIO_F, 0x0400, F_LCD_AF14), + STM_DEFPINS(GPIO_G, 0x0cc0, F_LCD_AF14), + STM_DEFPINS(GPIO_G, 0x1000, F_LCD_AF9), + STM_DEFPINS(GPIO_H, 0xff00, F_LCD_AF14), + STM_DEFPINS(GPIO_I, 0x06e7, F_LCD_AF14), +}; + +void gpio_init(void) +{ + /* Enable clocks for all used GPIO banks */ + st_writef(RCC_AHB4ENR, + GPIOAEN(1), GPIOBEN(1), GPIOCEN(1), GPIODEN(1), + GPIOEEN(1), GPIOFEN(1), GPIOGEN(1), GPIOHEN(1), GPIOIEN(1)); + + /* + * NOTE: I think it's possible to disable clocks for the banks which + * we don't need to access at runtime because these are only clocking + * register access. Probably a micro-optimization but it supposedly + * does save a few uA/MHz. + */ + + gpio_configure_all(gpios, ARRAYLEN(gpios), + pingroups, ARRAYLEN(pingroups)); +} + +void fmc_init(void) +{ + /* configure clock */ + st_writef(RCC_D1CCIPR, FMCSEL_V(AHB)); + + /* ungate FMC peripheral */ + st_writef(RCC_AHB3ENR, FMCEN(1)); + + /* configure FMC */ + st_writef(FMC_SDCR(0), + RPIPE(0), /* Not clear why this would be useful so leave at 0 */ + RBURST(1), /* Enable burst read optimization */ + SDCLK(2), /* 2x fmc_ker_ck per sdclk (120 MHz, tCK = 8.33ns) */ + WP(0), /* Write protect off */ + CAS(2), /* 2 cycle CAS latency */ + NB(1), /* 4 internal banks */ + MWID(1), /* 16-bit data bus width */ + NR(2), /* 13 row address bits */ + NC(1)); /* 9 column address bits */ + st_writef(FMC_SDTR(0), + TRCD(2), /* 15-20 ns <= 3 tCK */ + TRP(2), /* 15-20 ns <= 3 tCK */ + TWR(2), /* WR delay >= 2 tCK, but must be >= RAS - RCD (3 tCK) */ + TRC(7), /* 55-65 ns <= 7-8 tCK */ + TRAS(5), /* 40-45 ns <= 5-6 tCK */ + TXSR(8), /* 70-75 ns <= 9 tCK */ + TMRD(1)); /* MR delay == 2 tCK */ + + st_writef(FMC_BCR(0), FMCEN(1)); + + /* send SDRAM initialization commands */ + st_writef(FMC_SDCMR, CTB1(1), CTB2(0), MODE(1), NRFS(1)); + udelay(100); + + st_writef(FMC_SDCMR, CTB1(1), CTB2(0), MODE(2), NRFS(1)); + st_writef(FMC_SDCMR, CTB1(1), CTB2(0), MODE(3), NRFS(8)); + st_writef(FMC_SDCMR, CTB1(1), CTB2(0), MODE(4), NRFS(1), MRD(0x220)); + st_writef(FMC_SDCMR, CTB1(1), CTB2(0), MODE(3), NRFS(8)); + + /* + * Refresh time calculation: + * -> 64ms/8192 rows = 7.81 us/row + * -> 937 tCK per row, minus 20 tCK margin from datasheet + */ + st_writef(FMC_SDRTR, REIE(0), COUNT(917), CRE(0)); +} diff --git a/firmware/target/arm/stm32/gpio-stm32h7.c b/firmware/target/arm/stm32/gpio-stm32h7.c new file mode 100644 index 0000000000..020c3cb86f --- /dev/null +++ b/firmware/target/arm/stm32/gpio-stm32h7.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "gpio-stm32h7.h" + +void gpio_configure_single(int gpio, int confbits) +{ + int mode = GPIO_F_GETMODE(confbits); + + if (mode == GPIO_MODE_OUTPUT) + gpio_set_level(gpio, GPIO_F_GETINITLEVEL(confbits)); + else if (mode == GPIO_MODE_FUNCTION) + gpio_set_function(gpio, GPIO_F_GETAFNUM(confbits)); + + gpio_set_pull(gpio, GPIO_F_GETPULL(confbits)); + gpio_set_type(gpio, GPIO_F_GETTYPE(confbits)); + gpio_set_speed(gpio, GPIO_F_GETSPEED(confbits)); + gpio_set_mode(gpio, mode); +} + +void gpio_configure_port(int port, uint16_t mask, int confbits) +{ + for (int pin = 0; pin < 16; ++pin) + { + if (mask & BIT_N(pin)) + { + int gpio = GPION_CREATE(port, pin); + + gpio_configure_single(gpio, confbits); + } + } +} + +void gpio_configure_all( + const struct gpio_setting *gpios, size_t ngpios, + const struct pingroup_setting *pingroups, size_t ngroups) +{ + for (size_t i = 0; i < ngpios; ++i) + { + gpio_configure_single(gpios[i].gpio, gpios[i].func); + } + + for (size_t i = 0; i < ngroups; ++i) + { + gpio_configure_port(pingroups[i].port, + pingroups[i].pins, + pingroups[i].func); + } +} diff --git a/firmware/target/arm/stm32/gpio-stm32h7.h b/firmware/target/arm/stm32/gpio-stm32h7.h new file mode 100644 index 0000000000..ed412ab6d3 --- /dev/null +++ b/firmware/target/arm/stm32/gpio-stm32h7.h @@ -0,0 +1,256 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __GPIO_STM32_H__ +#define __GPIO_STM32_H__ + +#include "system.h" +#include "gpio-target.h" +#include "stm32h7/gpio.h" +#include +#include + +/* GPIO port numbers */ +#define GPIO_A 0 +#define GPIO_B 1 +#define GPIO_C 2 +#define GPIO_D 3 +#define GPIO_E 4 +#define GPIO_F 5 +#define GPIO_G 6 +#define GPIO_H 7 +#define GPIO_I 8 +#define GPIO_J 9 +#define GPIO_K 10 + +/* GPIO pin numbers */ +#define GPION_CREATE(port, pin) ((((port) & 0xf) << 4) | ((pin) & 0xf)) +#define GPION_PORT(gpio) (((gpio) >> 4) & 0xf) +#define GPION_PIN(gpio) ((gpio) & 0xf) + +/* Easy pin number macros */ +#define GPIO_PA(x) GPION_CREATE(GPIO_A, x) +#define GPIO_PB(x) GPION_CREATE(GPIO_B, x) +#define GPIO_PC(x) GPION_CREATE(GPIO_C, x) +#define GPIO_PD(x) GPION_CREATE(GPIO_D, x) +#define GPIO_PE(x) GPION_CREATE(GPIO_E, x) +#define GPIO_PF(x) GPION_CREATE(GPIO_F, x) +#define GPIO_PG(x) GPION_CREATE(GPIO_G, x) +#define GPIO_PH(x) GPION_CREATE(GPIO_H, x) +#define GPIO_PI(x) GPION_CREATE(GPIO_I, x) +#define GPIO_PJ(x) GPION_CREATE(GPIO_J, x) +#define GPIO_PK(x) GPION_CREATE(GPIO_K, x) + +/* GPIO modes */ +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 +#define GPIO_MODE_FUNCTION 2 +#define GPIO_MODE_ANALOG 3 + +/* GPIO output types */ +#define GPIO_TYPE_PUSH_PULL 0 +#define GPIO_TYPE_OPEN_DRAIN 1 + +/* GPIO output speeds */ +#define GPIO_SPEED_LOW 0 +#define GPIO_SPEED_MEDIUM 1 +#define GPIO_SPEED_HIGH 2 +#define GPIO_SPEED_VERYHIGH 3 + +/* GPIO pullup settings */ +#define GPIO_PULL_DISABLED 0 +#define GPIO_PULL_UP 1 +#define GPIO_PULL_DOWN 2 + +/* Helpers for GPIO library functions */ +#define GPIO_SETTING_MASK(n) (0x3u << GPIO_SETTING_LSB(n)) +#define GPIO_SETTING_LSB(n) ((n)*2) + +#define GPIO_AF_MASK(n) (0xFu << GPIO_AF_LSB(n)) +#define GPIO_AF_LSB(n) ((n)*4) + +/* GPIO function attributes */ +#define GPIO_F_MODE(n) (((n) & 0x3) << 0) +#define GPIO_F_TYPE(n) (((n) & 0x1) << 2) +#define GPIO_F_SPEED(n) (((n) & 0x3) << 3) +#define GPIO_F_PULL(n) (((n) & 0x3) << 5) +#define GPIO_F_AFNUM(n) (((n) & 0xf) << 7) +#define GPIO_F_INITLEVEL(n) (((n) & 0x1) << 11) + +#define GPIO_F_GETMODE(x) (((x) >> 0) & 0x3) +#define GPIO_F_GETTYPE(x) (((x) >> 2) & 0x1) +#define GPIO_F_GETSPEED(x) (((x) >> 3) & 0x3) +#define GPIO_F_GETPULL(x) (((x) >> 5) & 0x3) +#define GPIO_F_GETAFNUM(x) (((x) >> 7) & 0xf) +#define GPIO_F_GETINITLEVEL(x) (((x) >> 11) & 0x1) + +#define GPIOF_ANALOG() \ + (GPIO_F_MODE(GPIO_MODE_ANALOG) | \ + GPIO_F_TYPE(GPIO_TYPE_PUSH_PULL) | \ + GPIO_F_SPEED(GPIO_SPEED_LOW) | \ + GPIO_F_PULL(GPIO_PULL_DISABLED)) + +#define GPIOF_INPUT(pull) \ + (GPIO_F_MODE(GPIO_MODE_INPUT) | \ + GPIO_F_PULL(pull)) + +#define GPIOF_OUTPUT(initlevel, type, speed, pull) \ + (GPIO_F_MODE(GPIO_MODE_OUTPUT) | \ + GPIO_F_INITLEVEL(initlevel) | \ + GPIO_F_TYPE(type) | \ + GPIO_F_SPEED(speed) | \ + GPIO_F_PULL(pull)) + +#define GPIOF_FUNCTION(afnum, type, speed, pull) \ + (GPIO_F_MODE(GPIO_MODE_FUNCTION) | \ + GPIO_F_AFNUM(afnum) | \ + GPIO_F_TYPE(type) | \ + GPIO_F_SPEED(speed) | \ + GPIO_F_PULL(pull)) + +struct gpio_setting +{ + uint16_t gpio; + uint16_t func; +}; + +struct pingroup_setting +{ + int port; + uint16_t pins; + uint16_t func; +}; + +#define STM_DEFGPIO(_gpio, _func) \ + {.gpio = (_gpio), .func = (_func)} + +#define STM_DEFPINS(_port, _pins, _func) \ + {.port = (_port), .pins = (_pins), .func = (_func)} + +/* + * Configure a single GPIO or multiple GPIOs on one port. + * 'confbits' describe the configuration to apply: see GPIO_F macros above. + */ +void gpio_configure_single(int gpio, int confbits); +void gpio_configure_port(int port, uint16_t mask, int confbits); + +/* + * Configure multiple GPIO ports according to a list of settings. + * + * Identical to calling gpio_configure_single() with each GPIO setting + * and gpio_configure_port() with each pingroup setting. It is mainly + * to make the organization of the initial GPIO configuration tidier + * and intended to be called from gpio_init(). + */ +void gpio_configure_all( + const struct gpio_setting *gpios, size_t ngpios, + const struct pingroup_setting *pingroups, size_t ngroups) INIT_ATTR; + +static inline void gpio_set_mode(int gpio, int mode) +{ + int port = GPION_PORT(gpio); + int pin = GPION_PIN(gpio); + uint32_t val = REG_GPIO_MODER(port); + uint32_t mask = GPIO_SETTING_MASK(pin); + + val &= ~mask; + val |= (mode << GPIO_SETTING_LSB(pin)) & mask; + + REG_GPIO_MODER(port) = val; +} + +static inline void gpio_set_type(int gpio, int type) +{ + int port = GPION_PORT(gpio); + int pin = GPION_PIN(gpio); + uint32_t val = REG_GPIO_OTYPER(port); + uint32_t mask = BIT_N(pin); + + val &= ~mask; + val |= (type << pin) & mask; + + REG_GPIO_OTYPER(port) = val; +} + +static inline void gpio_set_speed(int gpio, int speed) +{ + int port = GPION_PORT(gpio); + int pin = GPION_PIN(gpio); + uint32_t val = REG_GPIO_OSPEEDR(port); + uint32_t mask = GPIO_SETTING_MASK(pin); + + val &= ~mask; + val |= (speed << GPIO_SETTING_LSB(pin)) & mask; + + REG_GPIO_OSPEEDR(port) = val; +} + +static inline void gpio_set_pull(int gpio, int pull) +{ + int port = GPION_PORT(gpio); + int pin = GPION_PIN(gpio); + uint32_t val = REG_GPIO_PUPDR(port); + uint32_t mask = GPIO_SETTING_MASK(pin); + + val &= ~mask; + val |= (pull << GPIO_SETTING_LSB(pin)) & mask; + + REG_GPIO_PUPDR(port) = val; +} + +static inline void gpio_set_function(int gpio, int func) +{ + int port = GPION_PORT(gpio); + int pin = GPION_PIN(gpio); + volatile uint32_t *addr = ®_GPIO_AFRL(port); + if (pin >= 8) { + addr += ®_GPIO_AFRH(0) - ®_GPIO_AFRL(0); + pin -= 8; + } + + uint32_t val = *addr; + uint32_t mask = GPIO_AF_MASK(pin); + + val &= ~mask; + val |= (func << GPIO_AF_LSB(pin)) & mask; + + *addr = val; +} + +static inline int gpio_get_level(int gpio) +{ + int port = GPION_PORT(gpio); + int pin = GPION_PIN(gpio); + + return REG_GPIO_IDR(port) & BIT_N(pin); +} + +static inline void gpio_set_level(int gpio, int value) +{ + int port = GPION_PORT(gpio); + int pin = GPION_PIN(gpio); + + if (value) + REG_GPIO_BSRR(port) = BIT_N(pin); + else + REG_GPIO_BSRR(port) = BIT_N(pin + 16); +} + +#endif /* __GPIO_STM32_H__ */ diff --git a/firmware/target/arm/stm32/i2c-stm32h7.c b/firmware/target/arm/stm32/i2c-stm32h7.c new file mode 100644 index 0000000000..87f3f17bda --- /dev/null +++ b/firmware/target/arm/stm32/i2c-stm32h7.c @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "i2c.h" + +void i2c_init(void) +{ +} diff --git a/firmware/target/arm/stm32/irqhandlers-stm32h743.c b/firmware/target/arm/stm32/irqhandlers-stm32h743.c new file mode 100644 index 0000000000..35e53d1656 --- /dev/null +++ b/firmware/target/arm/stm32/irqhandlers-stm32h743.c @@ -0,0 +1,32 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * NOTE: This file must be included from system-arm-micro.c! + */ + +void dma_irq_handler(void) ATTR_IRQ_HANDLER; +void i2c_irq_handler(void) ATTR_IRQ_HANDLER; +void lcdc_irq_handler(void) ATTR_IRQ_HANDLER; +void otg_hs_irq_handler(void) ATTR_IRQ_HANDLER; +void sai_irq_handler(void) ATTR_IRQ_HANDLER; +void sdmmc_irq_handler(void) ATTR_IRQ_HANDLER; +void spi_irq_handler(void) ATTR_IRQ_HANDLER; diff --git a/firmware/target/arm/stm32/pcm-stm32h7.c b/firmware/target/arm/stm32/pcm-stm32h7.c new file mode 100644 index 0000000000..e9d9696d19 --- /dev/null +++ b/firmware/target/arm/stm32/pcm-stm32h7.c @@ -0,0 +1,85 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "pcm.h" +#include "pcm-internal.h" + +void pcm_dma_apply_settings(void) +{ +} + +void pcm_play_dma_init(void) +{ +} + +void pcm_play_dma_postinit(void) +{ +} + +void pcm_play_dma_start(const void *addr, size_t size) +{ + (void)addr; + (void)size; +} + +void pcm_play_dma_stop(void) +{ +} + +void pcm_play_lock(void) +{ +} + +void pcm_play_unlock(void) +{ +} + +#ifdef HAVE_RECORDING +void pcm_rec_dma_init(void) +{ +} + +void pcm_rec_dma_close(void) +{ +} + +void pcm_rec_dma_start(void *addr, size_t size) +{ + (void)addr; + (void)size; +} + +void pcm_rec_dma_stop(void) +{ +} + +void pcm_rec_lock(void) +{ +} + +void pcm_rec_unlock(void) +{ +} + +const void *pcm_rec_dma_get_peak_buffer(void) +{ + return NULL; +} +#endif diff --git a/firmware/target/arm/stm32/sd-stm32h7.c b/firmware/target/arm/stm32/sd-stm32h7.c new file mode 100644 index 0000000000..85f9526278 --- /dev/null +++ b/firmware/target/arm/stm32/sd-stm32h7.c @@ -0,0 +1,81 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "storage.h" +#include "sdmmc.h" +#include "sd.h" + +int sd_init(void) +{ + return 0; +} + +void sd_enable(bool on) +{ + (void)on; +} + +int sd_event(long id, intptr_t data) +{ + return storage_event_default_handler(id, data, 0, STORAGE_SD); +} + +long sd_last_disk_activity(void) +{ + return 0; +} + +bool sd_present(IF_MD_NONVOID(int drive)) +{ + IF_MD((void)drive); + return true; +} + +bool sd_removable(IF_MD_NONVOID(int card_no)) +{ + IF_MD((void)card_no); + return true; +} + +tCardInfo *card_get_info_target(int card_no) +{ + (void)card_no; + + static tCardInfo null_info = {0}; + return &null_info; +} + +int sd_read_sectors(IF_MD(int drive,) sector_t start, int count, void *buf) +{ + IF_MD((void)drive); + (void)start; + (void)count; + (void)buf; + return -1; +} + +int sd_write_sectors(IF_MD(int drive,) sector_t start, int count, const void *buf) +{ + IF_MD((void)drive); + (void)start; + (void)count; + (void)buf; + return -1; +} diff --git a/firmware/target/arm/stm32/spi-stm32h7.c b/firmware/target/arm/stm32/spi-stm32h7.c new file mode 100644 index 0000000000..56cbf67bd8 --- /dev/null +++ b/firmware/target/arm/stm32/spi-stm32h7.c @@ -0,0 +1,302 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "spi-stm32h7.h" +#include "stm32h7/spi.h" + +/* + * Align the max transfer size to ensure it will always be a multiple + * of 32 bits. This is necessary because an unaligned TSIZE will cause + * some data written to the FIFO to be ignored -- this is OK and the + * intended behavior when it happens at the end of the transfer. But + * we don't want this to happen when TSER > 0 when we're still in the + * middle of the transfer, as it will throw away valid data. + */ +#define TSIZE_MAX \ + ALIGN_DOWN(st_vreadf(BM_SPI_CR2_TSIZE, SPI_CR2, TSIZE), sizeof(uint32_t)) + +static struct stm_spi *spi_map[STM_SPI_COUNT]; +static const uint32_t spi_addr[STM_SPI_COUNT] INITDATA_ATTR = { + [STM_SPI1] = STA_SPI1, + [STM_SPI2] = STA_SPI2, + [STM_SPI3] = STA_SPI3, + [STM_SPI4] = STA_SPI4, + [STM_SPI5] = STA_SPI5, + [STM_SPI6] = STA_SPI6, +}; + +static void stm_spi_set_cs(struct stm_spi *spi, bool enable) +{ + if (spi->set_cs) + spi->set_cs(spi, enable); + + st_writelf(spi->regs, SPI_CR1, SSI(1)); +} + +static void stm_spi_enable(struct stm_spi *spi, bool hd_tx, size_t size) +{ + size_t tsize = size / spi->frame_size; + size_t tser = 0; + size_t left = 0; + + if (tsize > TSIZE_MAX) + { + tser = tsize - TSIZE_MAX; + tsize = TSIZE_MAX; + + if (tser > TSIZE_MAX) + { + left = tser - TSIZE_MAX; + tser = TSIZE_MAX; + } + } + + /* + * Save number of bytes left for next TSER load, tracked + * separately from the overall transfer size because the + * timing of the SPI_SR.TSERF interrupt isn't clear. We'll + * decrement this by TSIZE_MAX whenever we load TSER in the + * middle of a transfer. + */ + spi->tser_left = left; + + /* TSIZE must be programmed before setting SPE. */ + st_overwritelf(spi->regs, SPI_CR2, TSIZE(tsize), TSER(tser)); + st_writelf(spi->regs, SPI_CR1, HDDIR(hd_tx), SPE(1)); +} + +static void stm_spi_disable(struct stm_spi *spi) +{ + st_overwritelf(spi->regs, SPI_IFCR, TSERFC(1), TXTFC(1), EOTC(1)); + st_writelf(spi->regs, SPI_CR1, SPE(0)); +} + +static void stm_spi_start(struct stm_spi *spi) +{ + st_writelf(spi->regs, SPI_CR1, CSTART(1)); +} + +static uint32_t stm_spi_pack(const void **bufp, size_t *sizep) +{ + const uint8_t *buf = *bufp; + uint32_t data = 0; + + if (LIKELY(*sizep >= sizeof(uint32_t))) + { + data = load_le32(buf); + *bufp += sizeof(uint32_t); + *sizep -= sizeof(uint32_t); + return data; + } + + switch (*sizep) { + case 3: data |= buf[2] << 16; /* fallthrough */ + case 2: data |= buf[1] << 8; /* fallthrough */ + case 1: data |= buf[0]; /* fallthrough */ + } + + *bufp += *sizep; + *sizep = 0; + return data; +} + +static void stm_spi_unpack(void **bufp, size_t *sizep, uint32_t data) +{ + uint8_t *buf = *bufp; + + if (LIKELY(*sizep >= sizeof(uint32_t))) + { + store_le32(buf, data); + *bufp += sizeof(uint32_t); + *sizep -= sizeof(uint32_t); + return; + } + + switch (*sizep) { + case 3: buf[2] = (data >> 16) & 0xff; /* fallthrough */ + case 2: buf[1] = (data >> 8) & 0xff; /* fallthrough */ + case 1: buf[0] = data & 0xff; /* fallthrough */ + } + + *bufp += *sizep; + *sizep = 0; +} + +void stm_spi_init(struct stm_spi *spi, + const struct stm_spi_config *config) +{ + uint32_t ftlevel; + + spi->regs = spi_addr[config->num]; + spi->mode = config->mode; + spi->set_cs = config->set_cs; + + /* Set FIFO level based on 32-bit packed writes */ + if (config->frame_bits > 16) + { + spi->frame_size = 4; + ftlevel = 1; + } + else if (config->frame_bits > 8) + { + spi->frame_size = 2; + ftlevel = 2; + } + else + { + spi->frame_size = 1; + ftlevel = 4; + } + + /* + * SPI1-3 have a 16-byte FIFO, SPI4-6 have only 8 bytes. + * So we can double the threshold setting for SPI1-3. + * (Maximum allowable threshold is 1/2 the FIFO size.) + */ + if (config->num <= STM_SPI3) + ftlevel *= 2; + + /* TODO: allow setting MBR here */ + st_writelf(spi->regs, SPI_CFG1, + MBR(0), + CRCEN(0), + CRCSIZE(7), + TXDMAEN(0), + RXDMAEN(0), + UDRDET(0), + UDRCFG(0), + FTHLV(ftlevel - 1), + DSIZE(config->frame_bits - 1)); + st_writelf(spi->regs, SPI_CFG2, + AFCNTR(1), + SSM(config->hw_cs_input ? 0 : 1), + SSOE(config->hw_cs_output), + SSIOP(config->hw_cs_polarity), + CPOL(config->cpol), + CPHA(config->cpha), + LSBFIRST(config->send_lsb_first), + COMM(config->mode), + SP(config->proto), + MASTER(1), + SSOM(0), + IOSWP(config->swap_mosi_miso), + MIDI(0), + MSSI(0)); + + spi_map[config->num] = spi; +} + +int stm_spi_xfer(struct stm_spi *spi, size_t size, + const void *tx_buf, void *rx_buf) +{ + bool hd_tx = false; + size_t size_tx = tx_buf ? size : 0; + size_t size_rx = rx_buf ? size : 0; + + /* Ignore zero-length transfers. */ + if (size == 0) + return 0; + + /* Reject nonsensical transfers (no data or less than 1 frame) */ + if (!tx_buf && !rx_buf) + return -1; + if (size < spi->frame_size) + return -1; + + if (spi->mode == STM_SPIMODE_HALF_DUPLEX) + { + /* Half duplex mode can't support duplex transfers. */ + if (tx_buf && rx_buf) + return -1; + + if (tx_buf) + hd_tx = true; + } + + stm_spi_set_cs(spi, true); + stm_spi_enable(spi, hd_tx, size); + stm_spi_start(spi); + + while (size_tx > 0 || size_rx > 0) + { + uint32_t sr = st_readl(spi->regs, SPI_SR); + + /* + * Handle continuation of large transfers + * + * TODO - something is not right with this code + */ + if (spi->tser_left > 0 && st_vreadf(sr, SPI_SR, TSERF)) + { + if (spi->tser_left < TSIZE_MAX) + { + st_writelf(spi->regs, SPI_CR2, TSER(spi->tser_left)); + spi->tser_left = 0; + } + else + { + st_writelf(spi->regs, SPI_CR2, TSER(TSIZE_MAX)); + spi->tser_left -= TSIZE_MAX; + } + } + + /* Handle FIFO write */ + if (size_tx > 0 && st_vreadf(sr, SPI_SR, TXP)) + { + uint32_t data = stm_spi_pack(&tx_buf, &size_tx); + + st_writel(spi->regs, SPI_TXDR32, data); + } + + /* + * Handle FIFO read. Since RXP is set only if the FIFO level + * exceeds the threshold we can't rely on it at the end of a + * transfer, and must check EOT as well. + */ + if (size_rx > 0 && + (st_vreadf(sr, SPI_SR, RXP) || st_vreadf(sr, SPI_SR, EOT))) + { + uint32_t data = st_readl(spi->regs, SPI_RXDR32); + + stm_spi_unpack(&rx_buf, &size_rx, data); + } + } + + /* + * Errata 2.22.2: Master data transfer stall at system clock much faster than SCK + * Errata 2.22.6: Truncation of SPI output signals after EOT event + * + * For 2.22.2 we need to wait at least 1 SCK cycle before starting the + * next transaction. For 2.22.6, waiting 1/2 SCK cycle should be enough + * since the EOT event is raised on a clock edge. + * + * TODO: calculate this delay time. doesn't seem to match assumptions above + */ + udelay(5); + + stm_spi_disable(spi); + stm_spi_set_cs(spi, false); + return 0; +} + +void spi_irq_handler(void) +{ + while (1); +} diff --git a/firmware/target/arm/stm32/spi-stm32h7.h b/firmware/target/arm/stm32/spi-stm32h7.h new file mode 100644 index 0000000000..6a8e440695 --- /dev/null +++ b/firmware/target/arm/stm32/spi-stm32h7.h @@ -0,0 +1,101 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __SPI_STM32H743_H__ +#define __SPI_STM32H743_H__ + +#include "system.h" +#include + +struct stm_spi; + +enum stm_spi_num +{ + STM_SPI1, + STM_SPI2, + STM_SPI3, + STM_SPI4, + STM_SPI5, + STM_SPI6, + STM_SPI_COUNT, +}; + +/* Must match the SPI_CFG2.COMM register */ +enum stm_spi_mode +{ + STM_SPIMODE_DUPLEX, + STM_SPIMODE_TXONLY, + STM_SPIMODE_RXONLY, + STM_SPIMODE_HALF_DUPLEX, +}; + +/* Must match the SPI_CFG2.SP register */ +enum stm_spi_protocol +{ + STM_SPIPROTO_MOTOROLA, + STM_SPIPROTO_TI, +}; + +typedef void (*stm_spi_set_cs_t) (struct stm_spi *spi, bool enable); + +struct stm_spi_config +{ + enum stm_spi_num num; + enum stm_spi_mode mode; + enum stm_spi_protocol proto; + stm_spi_set_cs_t set_cs; + uint32_t frame_bits: 6; + uint32_t cpha: 1; + uint32_t cpol: 1; + uint32_t hw_cs_input: 1; + uint32_t hw_cs_output: 1; + uint32_t hw_cs_polarity: 1; + uint32_t send_lsb_first: 1; + uint32_t swap_mosi_miso: 1; +}; + +struct stm_spi +{ + uint32_t regs; + enum stm_spi_mode mode; + stm_spi_set_cs_t set_cs; + uint32_t frame_size; + size_t tser_left; +}; + +void stm_spi_init(struct stm_spi *spi, + const struct stm_spi_config *config) INIT_ATTR; + +int stm_spi_xfer(struct stm_spi *spi, size_t size, + const void *tx_buf, void *rx_buf); + +static inline int stm_spi_transmit(struct stm_spi *spi, + const void *buf, size_t size) +{ + return stm_spi_xfer(spi, size, buf, NULL); +} + +static inline int stm_spi_receive(struct stm_spi *spi, + void *buf, size_t size) +{ + return stm_spi_xfer(spi, size, NULL, buf); +} + +#endif /* __SPI_STM32H743_H__ */ diff --git a/firmware/target/arm/stm32/system-stm32h7.c b/firmware/target/arm/stm32/system-stm32h7.c new file mode 100644 index 0000000000..45fc58db62 --- /dev/null +++ b/firmware/target/arm/stm32/system-stm32h7.c @@ -0,0 +1,261 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "tick.h" +#include "gpio-stm32h7.h" +#include "cortex-m/scb.h" +#include "cortex-m/systick.h" +#include "stm32h7/rcc.h" +#include "stm32h7/pwr.h" +#include "stm32h7/syscfg.h" +#include "stm32h7/flash.h" + +/* EXT timer is 1/8th of CPU clock */ +#define SYSTICK_FREQ (CPU_FREQ / 8) +#define SYSTICK_PER_MS (SYSTICK_FREQ / 1000) +#define SYSTICK_PER_US (SYSTICK_FREQ / 1000000) + +/* Max delay is limited by kernel tick interval + safety margin */ +#define SYSTICK_DELAY_MAX_US (1000000 / HZ / 2) +#define SYSTICK_DELAY_MAX_MS (SYSTICK_DELAY_MAX_US / 1000) + +/* Flag to use VOS0 */ +#define STM32H743_USE_VOS0 (CPU_FREQ > 400000000) + +/* Base address of vector table */ +extern char __vectors_arm[]; + +static void systick_init(unsigned int interval_in_ms) +{ + cm_writef(SYSTICK_RVR, VALUE(SYSTICK_PER_MS * interval_in_ms - 1)); + cm_writef(SYSTICK_CVR, VALUE(0)); + cm_writef(SYSTICK_CSR, CLKSOURCE_V(EXT), ENABLE(1)); +} + +static void stm_enable_caches(void) +{ + __discard_idcache(); + + cm_writef(SCB_CCR, IC(1), DC(1)); + + arm_dsb(); + arm_isb(); +} + +static void stm_init_hse(void) +{ + st_writef(RCC_CR, HSEON(1)); + + while (!st_readf(RCC_CR, HSERDY)); +} + +static void stm_init_pll(void) +{ + /* TODO - this should be determined by the target in some way. */ + + /* Select HSE/4 input for PLL1 (6 MHz) */ + st_writef(RCC_PLLCKSELR, + PLLSRC_V(HSE), + DIVM1(4), + DIVM2(0), + DIVM3(0)); + + /* Enable PLL1P and PLL1Q */ + st_writef(RCC_PLLCFGR, + DIVP1EN(1), + DIVQ1EN(1), + DIVR1EN(0), + DIVP2EN(0), + DIVQ2EN(0), + DIVR2EN(0), + DIVP3EN(0), + DIVQ3EN(0), + DIVR3EN(0), + PLL1RGE_V(4_8MHz), + PLL1VCOSEL_V(WIDE)); + + st_writef(RCC_PLL1DIVR, + DIVN(80 - 1), /* 6 * 80 = 480 MHz */ + DIVP(1 - 1), /* 480 / 1 = 480 MHz */ + DIVQ(8 - 1), /* 480 / 8 = 60 MHz */ + DIVR(1 - 1)); + + st_writef(RCC_CR, PLL1ON(1)); + while (!st_readf(RCC_CR, PLL1RDY)); +} + +static void stm_init_vos(void) +{ + st_writef(PWR_D3CR, VOS_V(VOS1)); + while (!st_readf(PWR_D3CR, VOSRDY)); + + if (STM32H743_USE_VOS0) + { + st_writef(RCC_APB4ENR, SYSCFGEN(1)); + + /* Set ODEN bit to enter VOS0 */ + st_writef(SYSCFG_PWRCFG, ODEN(1)); + while (!st_readf(PWR_D3CR, VOSRDY)); + + st_writef(RCC_APB4ENR, SYSCFGEN(0)); + } +} + +static void stm_init_system_clock(void) +{ + /* Enable HCLK /2 divider (CPU is at 480 MHz, HCLK limit is 240 MHz) */ + st_writef(RCC_D1CFGR, HPRE(8)); + while (st_readf(RCC_D1CFGR, HPRE) != 8); + + /* Enable ABP /2 dividers (HCLK/2, APB limit is 120 MHz) */ + st_writef(RCC_D1CFGR, D1PPRE(4)); + st_writef(RCC_D2CFGR, D2PPRE1(4), D2PPRE2(4)); + st_writef(RCC_D3CFGR, D3PPRE(4)); + + /* Switch to PLL1P system clock source */ + st_writef(RCC_CFGR, SW_V(PLL1P)); + while (st_readf(RCC_CFGR, SWS) != BV_RCC_CFGR_SW__PLL1P); + + /* Reduce flash access latency */ + st_writef(FLASH_ACR, LATENCY(4), WRHIGHFREQ(2)); + while (st_readf(FLASH_ACR, LATENCY) != 4); +} + +static void stm_init_lse(void) +{ + /* + * Skip if LSE and RTC are already enabled. + */ + if (st_readf(RCC_BDCR, LSERDY) && + st_readf(RCC_BDCR, RTCEN)) + return; + + /* + * Enable LSE and set it as RTC clock source, + * then re-enable backup domain write protection. + */ + + st_writef(PWR_CR1, DBP(1)); + + /* Reset backup domain */ + st_writef(RCC_BDCR, BDRST(1)); + st_writef(RCC_BDCR, BDRST(0)); + + st_writef(RCC_BDCR, LSEON(1), LSEDRV(3)); + while (!st_readf(RCC_BDCR, LSERDY)); + + st_writef(RCC_BDCR, RTCEN(1), RTCSEL_V(LSE)); + st_writef(PWR_CR1, DBP(0)); +} + +void system_init(void) +{ + /* Ensure IRQs are disabled and set vector table address */ + disable_irq(); + cm_write(SCB_VTOR, (uint32_t)__vectors_arm); + + /* Enable CPU caches */ + stm_enable_caches(); + + /* Start up clocks and get running at max CPU frequency */ + stm_init_hse(); + stm_init_pll(); + stm_init_vos(); + stm_init_system_clock(); + + /* Start up LSE and RTC if necessary so backup domain works */ + stm_init_lse(); + + /* TODO: move this */ + systick_init(1000/HZ); + + /* Call target-specific initialization */ + gpio_init(); + fmc_init(); +} + +void tick_start(unsigned int interval_in_ms) +{ + (void)interval_in_ms; + + cm_writef(SYSTICK_CSR, TICKINT(1)); +} + +void systick_handler(void) +{ + call_tick_tasks(); +} + +/* + * NOTE: This assumes that the CPU cannot be reclocked during an interrupt. + * If that happens, the systick interval and reload value would be modified + * to maintain the kernel tick interval and the code here will break. + */ +static void __udelay(uint32_t us) +{ + uint32_t start = cm_readf(SYSTICK_CVR, VALUE); + uint32_t max = cm_readf(SYSTICK_RVR, VALUE); + uint32_t delay = us * SYSTICK_PER_US; + + for (;;) + { + uint32_t value = cm_readf(SYSTICK_CVR, VALUE); + uint32_t diff = start - value; + if (value > start) + diff += max; + if (diff >= delay) + break; + } +} + +void udelay(uint32_t us) +{ + while (us > SYSTICK_DELAY_MAX_US) + { + __udelay(SYSTICK_DELAY_MAX_US); + us -= SYSTICK_DELAY_MAX_US; + } + + __udelay(us); +} + +void mdelay(uint32_t ms) +{ + while (ms > SYSTICK_DELAY_MAX_MS) + { + __udelay(SYSTICK_DELAY_MAX_MS * 1000); + ms -= SYSTICK_DELAY_MAX_MS; + } + + __udelay(ms * 1000); +} + +void system_exception_wait(void) +{ + while (1); +} + +int system_memory_guard(int newmode) +{ + /* TODO -- maybe use MPU here to give some basic protection */ + (void)newmode; + return MEMGUARD_NONE; +} diff --git a/firmware/target/arm/stm32/system-target.h b/firmware/target/arm/stm32/system-target.h new file mode 100644 index 0000000000..58d37145ca --- /dev/null +++ b/firmware/target/arm/stm32/system-target.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __STM32_SYSTEM_TARGET_H__ +#define __STM32_SYSTEM_TARGET_H__ + +#include "system-arm.h" +#include "cpucache-armv7m.h" + +/* Implemented by the target -- can be a no-op if not needed */ +void gpio_init(void) INIT_ATTR; +void fmc_init(void) INIT_ATTR; + +void udelay(uint32_t us); +void mdelay(uint32_t ms); + +#endif /* __STM32_SYSTEM_TARGET_H__ */ diff --git a/firmware/target/arm/stm32/timer-stm32h7.c b/firmware/target/arm/stm32/timer-stm32h7.c new file mode 100644 index 0000000000..30a13fad10 --- /dev/null +++ b/firmware/target/arm/stm32/timer-stm32h7.c @@ -0,0 +1,37 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "timer.h" + +bool timer_set(long cycles, bool start) +{ + (void)cycles; + (void)start; + return false; +} + +bool timer_start(void) +{ + return false; +} + +void timer_stop(void) +{ +} diff --git a/firmware/target/arm/stm32/usb-stm32h7.c b/firmware/target/arm/stm32/usb-stm32h7.c new file mode 100644 index 0000000000..02291a4bab --- /dev/null +++ b/firmware/target/arm/stm32/usb-stm32h7.c @@ -0,0 +1,86 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "usb.h" +#include "usb_core.h" +#include "usb_drv.h" +#include "usb-designware.h" + +const struct usb_dw_config usb_dw_config = { + .phytype = DWC_PHYTYPE_ULPI_SDR, + /* + * Available FIFO memory: 1024 words (TODO: check this) + * Number of endpoints: 9 + * Max packet size: 512 bytes + */ + .rx_fifosz = 224, /* shared RxFIFO */ + .nptx_fifosz = 32, /* only used for EP0 IN */ + .ptx_fifosz = 192, /* room for 4 IN EPs */ + +#ifndef USB_DW_ARCH_SLAVE + .ahb_burst_len = HBSTLEN_INCR8, + /* Disable Rx FIFO thresholding. It appears to cause problems, + * apparently a known issue -- Synopsys recommends disabling it + * because it can cause issues during certain error conditions. + */ + .ahb_threshold = 0, +#else + .disable_double_buffering = false, +#endif +}; + +void usb_enable(bool on) +{ + if (on) + usb_core_init(); + else + usb_core_exit(); +} + +void usb_init_device(void) +{ + /* TODO - this is highly target specific */ +} + +int usb_detect(void) +{ + return USB_EXTRACTED; +} + +void usb_dw_target_enable_clocks(void) +{ +} + +void usb_dw_target_disable_clocks(void) +{ +} + +void usb_dw_target_enable_irq(void) +{ +} + +void usb_dw_target_disable_irq(void) +{ +} + +void usb_dw_target_clear_irq(void) +{ +} diff --git a/firmware/target/arm/stm32/vectors-stm32h7.S b/firmware/target/arm/stm32/vectors-stm32h7.S new file mode 100644 index 0000000000..52c7c7ba05 --- /dev/null +++ b/firmware/target/arm/stm32/vectors-stm32h7.S @@ -0,0 +1,179 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * 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 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" + + .syntax unified + .text + + .section .vectors.platform,"ax",%progbits + + .global __vectors_platform +__vectors_platform: + .word UIE /* [ 0] */ + .word UIE /* [ 1] */ + .word UIE /* [ 2] */ + .word UIE /* [ 3] */ + .word UIE /* [ 4] */ + .word UIE /* [ 5] */ + .word UIE /* [ 6] */ + .word UIE /* [ 7] */ + .word UIE /* [ 8] */ + .word UIE /* [ 9] */ + .word UIE /* [ 10] */ + .word dma_irq_handler /* [ 11] DMA1 Stream0 */ + .word dma_irq_handler /* [ 12] DMA1 Stream1 */ + .word dma_irq_handler /* [ 13] DMA1 Stream2 */ + .word dma_irq_handler /* [ 14] DMA1 Stream3 */ + .word dma_irq_handler /* [ 15] DMA1 Stream4 */ + .word dma_irq_handler /* [ 16] DMA1 Stream5 */ + .word dma_irq_handler /* [ 17] DMA1 Stream6 */ + .word UIE /* [ 18] */ + .word UIE /* [ 19] */ + .word UIE /* [ 20] */ + .word UIE /* [ 21] */ + .word UIE /* [ 22] */ + .word UIE /* [ 23] */ + .word UIE /* [ 24] */ + .word UIE /* [ 25] */ + .word UIE /* [ 26] */ + .word UIE /* [ 27] */ + .word UIE /* [ 28] */ + .word UIE /* [ 29] */ + .word UIE /* [ 30] */ + .word i2c_irq_handler /* [ 31] I2C1 event */ + .word i2c_irq_handler /* [ 32] I2C1 error */ + .word i2c_irq_handler /* [ 33] I2C2 event */ + .word i2c_irq_handler /* [ 34] I2C2 error */ + .word spi_irq_handler /* [ 35] SPI1 */ + .word spi_irq_handler /* [ 36] SPI2 */ + .word UIE /* [ 37] */ + .word UIE /* [ 38] */ + .word UIE /* [ 39] */ + .word UIE /* [ 40] */ + .word UIE /* [ 41] */ + .word UIE /* [ 42] */ + .word UIE /* [ 43] */ + .word UIE /* [ 44] */ + .word UIE /* [ 45] */ + .word UIE /* [ 46] */ + .word dma_irq_handler /* [ 47] DMA1 Stream7 */ + .word UIE /* [ 48] */ + .word sdmmc_irq_handler /* [ 49] SDMMC1 */ + .word UIE /* [ 50] */ + .word spi_irq_handler /* [ 51] SPI3 */ + .word UIE /* [ 52] */ + .word UIE /* [ 53] */ + .word UIE /* [ 54] */ + .word UIE /* [ 55] */ + .word dma_irq_handler /* [ 56] DMA2 Stream0 */ + .word dma_irq_handler /* [ 57] DMA2 Stream1 */ + .word dma_irq_handler /* [ 58] DMA2 Stream2 */ + .word dma_irq_handler /* [ 59] DMA2 Stream3 */ + .word dma_irq_handler /* [ 60] DMA2 Stream4 */ + .word UIE /* [ 61] */ + .word UIE /* [ 62] */ + .word UIE /* [ 63] */ + .word UIE /* [ 64] */ + .word UIE /* [ 65] */ + .word UIE /* [ 66] */ + .word UIE /* [ 67] */ + .word dma_irq_handler /* [ 68] DMA2 Stream5 */ + .word dma_irq_handler /* [ 69] DMA2 Stream6 */ + .word dma_irq_handler /* [ 70] DMA2 Stream7 */ + .word UIE /* [ 71] */ + .word i2c_irq_handler /* [ 72] I2C3 event */ + .word i2c_irq_handler /* [ 73] I2C3 error */ + .word UIE /* [ 74] */ + .word UIE /* [ 75] */ + .word UIE /* [ 76] */ + .word otg_hs_irq_handler /* [ 77] OTG HS */ + .word UIE /* [ 78] */ + .word UIE /* [ 79] */ + .word UIE /* [ 80] */ + .word UIE /* [ 81] */ + .word UIE /* [ 82] */ + .word UIE /* [ 83] */ + .word spi_irq_handler /* [ 84] SPI4 */ + .word spi_irq_handler /* [ 85] SPI5 */ + .word spi_irq_handler /* [ 86] SPI6 */ + .word sai_irq_handler /* [ 87] SAI1 */ + .word lcdc_irq_handler /* [ 88] LCDC */ + .word lcdc_irq_handler /* [ 89] LCDC error */ + .word dma_irq_handler /* [ 90] DMA2D */ + .word sai_irq_handler /* [ 91] SAI2 */ + .word UIE /* [ 92] */ + .word UIE /* [ 93] */ + .word UIE /* [ 94] */ + .word i2c_irq_handler /* [ 95] I2C4 event */ + .word i2c_irq_handler /* [ 96] I2C4 error */ + .word UIE /* [ 97] */ + .word UIE /* [ 98] */ + .word UIE /* [ 99] */ + .word UIE /* [100] */ + .word UIE /* [101] */ + .word dma_irq_handler /* [102] DMAMUX1 overrun */ + .word UIE /* [103] */ + .word UIE /* [104] */ + .word UIE /* [105] */ + .word UIE /* [106] */ + .word UIE /* [107] */ + .word UIE /* [108] */ + .word UIE /* [109] */ + .word UIE /* [110] */ + .word UIE /* [111] */ + .word UIE /* [112] */ + .word UIE /* [113] */ + .word sai_irq_handler /* [114] SAI3 */ + .word UIE /* [115] */ + .word UIE /* [116] */ + .word UIE /* [117] */ + .word UIE /* [118] */ + .word UIE /* [119] */ + .word UIE /* [120] */ + .word UIE /* [121] */ + .word dma_irq_handler /* [122] MDMA */ + .word UIE /* [123] */ + .word sdmmc_irq_handler /* [124] SDMMC2 */ + .word UIE /* [125] */ + .word UIE /* [126] */ + .word UIE /* [127] */ + .word dma_irq_handler /* [128] DMAMUX2 overrun */ + .word dma_irq_handler /* [129] BDMA channel 0 */ + .word dma_irq_handler /* [130] BDMA channel 1 */ + .word dma_irq_handler /* [131] BDMA channel 2 */ + .word dma_irq_handler /* [132] BDMA channel 3 */ + .word dma_irq_handler /* [133] BDMA channel 4 */ + .word dma_irq_handler /* [134] BDMA channel 5 */ + .word dma_irq_handler /* [135] BDMA channel 6 */ + .word dma_irq_handler /* [136] BDMA channel 7 */ + .word UIE /* [137] */ + .word UIE /* [138] */ + .word UIE /* [139] */ + .word UIE /* [140] */ + .word UIE /* [141] */ + .word UIE /* [142] */ + .word UIE /* [143] */ + .word UIE /* [144] */ + .word UIE /* [145] */ + .word sai_irq_handler /* [146] SAI4 */ + .word UIE /* [147] */ + .word UIE /* [148] */ + .word UIE /* [149] */ diff --git a/firmware/target/arm/system-arm-micro.c b/firmware/target/arm/system-arm-micro.c index 9e23a9fb02..b9aa20733c 100644 --- a/firmware/target/arm/system-arm-micro.c +++ b/firmware/target/arm/system-arm-micro.c @@ -64,3 +64,13 @@ void debugmonitor_handler(void) ATTR_IRQ_HANDLER; #if ARCH_VERSION >= 8 void securefault_handler(void) ATTR_IRQ_HANDLER; #endif + +/* + * The weak alias attribute above only works if the alias is defined + * in the same translation unit. So each platform should declare its + * IRQ handlers in a file and include it below, so that unused ones + * can be aliased to UIE. + */ +#if CONFIG_CPU == STM32H743 +# include "irqhandlers-stm32h743.c" +#endif diff --git a/tools/configure b/tools/configure index b74aaed302..a8911ba995 100755 --- a/tools/configure +++ b/tools/configure @@ -609,6 +609,13 @@ arm7ejscc () { endian="little" } +armcortexm7cc () { + findarmgcc + GCCOPTS="$CCOPTS -march=armv7e-m -mcpu=cortex-m7" + GCCOPTIMIZE="-fomit-frame-pointer" + endian="little" +} + mipselcc () { prefixtools mipsel-elf- # mips is predefined, but we want it for paths. use __mips instead @@ -1724,6 +1731,8 @@ cat <