diff --git a/core/.changelog.d/2243.added b/core/.changelog.d/2243.added new file mode 100644 index 0000000000..c595a95a2d --- /dev/null +++ b/core/.changelog.d/2243.added @@ -0,0 +1 @@ +Add basic Trezor Model R hardware support diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index e3af2a677d..7e5e00b05c 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -48,6 +48,9 @@ SOURCE_MOD += [ 'embed/extmod/modtrezorui/font_bitmap.c', 'embed/extmod/modtrezorui/font_roboto_regular_20.c', 'embed/extmod/modtrezorui/font_robotomono_regular_20.c', + 'embed/extmod/modtrezorui/font_pixeloperator_bold_8.c', + 'embed/extmod/modtrezorui/font_pixeloperator_regular_8.c', + 'embed/extmod/modtrezorui/font_pixeloperatormono_regular_8.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', @@ -108,7 +111,7 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/vectortable.s', ] -if TREZOR_MODEL in ['1', 'R']: +if TREZOR_MODEL in ('1', 'R'): SOURCE_TREZORHAL.append('embed/trezorhal/button.c') if TREZOR_MODEL in ('T',): SOURCE_TREZORHAL.append('embed/trezorhal/touch.c') diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 9b665e7340..5621f9d146 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -151,7 +151,7 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]: SOURCE_MOD += [ 'embed/extmod/modtrezorio/modtrezorio.c', ] -if TREZOR_MODEL in ("T",): +if TREZOR_MODEL in ('T',): SOURCE_MOD += [ 'embed/extmod/modtrezorio/ff.c', 'embed/extmod/modtrezorio/ffunicode.c', diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 7039311f0f..081de7bde4 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -32,6 +32,7 @@ SOURCE_MOD += [ 'embed/extmod/modtrezorui/display.c', 'embed/extmod/modtrezorui/font_bitmap.c', 'embed/extmod/modtrezorui/font_roboto_bold_20.c', + 'embed/extmod/modtrezorui/font_pixeloperator_bold_8.c', 'embed/extmod/modtrezorui/qr-code-generator/qrcodegen.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', diff --git a/core/SConscript.unix b/core/SConscript.unix index eaebdf1906..92ee230794 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -147,7 +147,7 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]: SOURCE_MOD += [ 'embed/extmod/modtrezorio/modtrezorio.c', ] -if TREZOR_MODEL in ("T",): +if TREZOR_MODEL in ('T',): SOURCE_MOD += [ 'embed/extmod/modtrezorio/ff.c', 'embed/extmod/modtrezorio/ffunicode.c', diff --git a/core/embed/boardloader/.changelog.d/2243.added b/core/embed/boardloader/.changelog.d/2243.added new file mode 100644 index 0000000000..c595a95a2d --- /dev/null +++ b/core/embed/boardloader/.changelog.d/2243.added @@ -0,0 +1 @@ +Add basic Trezor Model R hardware support diff --git a/core/embed/bootloader/.changelog.d/2243.added b/core/embed/bootloader/.changelog.d/2243.added new file mode 100644 index 0000000000..c595a95a2d --- /dev/null +++ b/core/embed/bootloader/.changelog.d/2243.added @@ -0,0 +1 @@ +Add basic Trezor Model R hardware support diff --git a/core/embed/bootloader_ci/.changelog.d/2243.added b/core/embed/bootloader_ci/.changelog.d/2243.added new file mode 100644 index 0000000000..c595a95a2d --- /dev/null +++ b/core/embed/bootloader_ci/.changelog.d/2243.added @@ -0,0 +1 @@ +Add basic Trezor Model R hardware support diff --git a/core/embed/extmod/modtrezorui/display-stm32_R.h b/core/embed/extmod/modtrezorui/display-stm32_R.h new file mode 100644 index 0000000000..ce14b5abe4 --- /dev/null +++ b/core/embed/extmod/modtrezorui/display-stm32_R.h @@ -0,0 +1,337 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include STM32_HAL_H + +// FSMC/FMC Bank 1 - NOR/PSRAM 1 +#define DISPLAY_MEMORY_BASE 0x60000000 +#define DISPLAY_MEMORY_PIN 16 + +#define CMD(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE))) = (X)) +#define ADDR \ + (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | \ + (1 << DISPLAY_MEMORY_PIN))))) +#define DATA(X) (ADDR) = (X) + +// noop on TR as we don't need to push data to display +#define PIXELDATA_DIRTY() + +struct { + uint8_t RAM[DISPLAY_RESY / 8][DISPLAY_RESX]; + uint32_t row; + uint32_t col; + uint32_t window_x0; + uint32_t window_x1; + uint32_t window_y0; + uint32_t window_y1; +} DISPLAY_STATE; + +static void display_set_page_and_col(uint8_t page, uint8_t col) { + if (page < (DISPLAY_RESY / 8)) { + CMD(0xB0 | (page & 0xF)); + + if (col < DISPLAY_RESX) { + CMD(0x10 | ((col & 0x70) >> 4)); + CMD(0x00 | (col & 0x0F)); + } else { + // Reset column to start + CMD(0x10); + CMD(0x00); + } + } +} + +void PIXELDATA(uint16_t c) { + uint8_t data = DISPLAY_STATE.RAM[DISPLAY_STATE.row / 8][DISPLAY_STATE.col]; + + uint8_t bit = 1 << (DISPLAY_STATE.row % 8); + + // set to white if highest bits of all R, G, B values are set to 1 + // bin(10000 100000 10000) = hex(0x8410) + // otherwise set to black + if (c & 0x8410) { + data |= bit; + } else { + data &= ~bit; + } + + DISPLAY_STATE.RAM[DISPLAY_STATE.row / 8][DISPLAY_STATE.col] = data; + + DATA(data); + + DISPLAY_STATE.col++; + + if (DISPLAY_STATE.col > DISPLAY_STATE.window_x1) { + // next line + DISPLAY_STATE.col = DISPLAY_STATE.window_x0; + DISPLAY_STATE.row++; + + if (DISPLAY_STATE.row > DISPLAY_STATE.window_y1) { + // reached end of the window, go to start + DISPLAY_STATE.row = DISPLAY_STATE.window_y1; + } + + // set display to start of next line, sets also page, even if it stays on + // the same one + display_set_page_and_col(DISPLAY_STATE.row / 8, DISPLAY_STATE.col); + } +} + +static void display_reset_state(void) { + memset(DISPLAY_STATE.RAM, 0, sizeof(DISPLAY_STATE.RAM)); + DISPLAY_STATE.row = 0; + DISPLAY_STATE.col = 0; + DISPLAY_STATE.window_x0 = 0; + DISPLAY_STATE.window_x1 = DISPLAY_RESX - 1; + DISPLAY_STATE.window_y0 = 0; + DISPLAY_STATE.window_y1 = DISPLAY_RESY - 1; +} + +static void __attribute__((unused)) display_sleep(void) { + CMD(0xAE); // DISPOFF: Display Off + HAL_Delay(5); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET); // Vpp disable +} + +static void display_unsleep(void) { + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_SET); // Vpp enable + HAL_Delay(100); // 100 ms mandatory wait + CMD(0xAF); // Display ON +} + +static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, + uint16_t y1) { + if (x1 >= DISPLAY_RESX) { + x1 = DISPLAY_RESX - 1; + } + if (y1 >= DISPLAY_RESY) { + y1 = DISPLAY_RESY - 1; + } + + if (x0 < DISPLAY_RESX && x1 < DISPLAY_RESX && x0 <= x1 && y0 < DISPLAY_RESY && + y1 < DISPLAY_RESY && y0 <= y1) { + DISPLAY_STATE.window_x0 = x0; + DISPLAY_STATE.window_x1 = x1; + DISPLAY_STATE.window_y0 = y0; + DISPLAY_STATE.window_y1 = y1; + DISPLAY_STATE.row = y0; + DISPLAY_STATE.col = x0; + + display_set_page_and_col(DISPLAY_STATE.row / 8, DISPLAY_STATE.col); + } +} + +static void display_set_orientation(int degrees) { + if (degrees == 0) { + // Set Segment Re-map: (A0H - A1H) + CMD(0xA1); + // Set COM Output Scan Direction + CMD(0xC8); + } + if (degrees == 180) { + // Set Segment Re-map: (A0H - A1H) + CMD(0xA0); + // Set COM Output Scan Direction + CMD(0xC0); + } +} + +static void display_set_backlight(int val) { + // Set Contrast Control Register: (Double Bytes Command) + CMD(0x81); + CMD(val & 0xFF); +} + +static void send_init_seq_SH1107(void) { + // Display OFF + CMD(0xAE); + + // Set Display Clock Divide Ratio/Oscillator Frequency: (Double Bytes Command) + CMD(0xD5); + // Divide ratio 0, Oscillator Frequency +0% + CMD(0x50); + + // Set Memory Addressing Mode - page addressing mode + CMD(0x20); + + // Set Contrast Control Register: (Double Bytes Command) + CMD(0x81); + CMD(0x8F); + + // Set DC-DC Setting: (Double Bytes Command) + CMD(0xAD); + CMD(0x8A); + + // Set Segment Re-map: (A0H - A1H) + // CMD(0xA0); + CMD(0xA1); + + // Set COM Output Scan Direction + CMD(0xC8); + // CMD(0xC0); + + // Set Display Start Line:(Double Bytes Command) + CMD(0xDC); + CMD(0x00); + + // Set Display Offset:(Double Bytes Command) + CMD(0xD3); + CMD(0x00); + + // Set Discharge / Pre-Charge Period (Double Bytes Command) + CMD(0xD9); + CMD(0x22); + + // Set VCOM Deselect Level + CMD(0xDB); + CMD(0x35); + + // Set Multiplex Ratio + CMD(0xA8); + CMD(0x7F); + + // Set Page + CMD(0xB0); + // Set Column + CMD(0x00); + CMD(0x10); + + // Set Entire Display Off + // to be clear, this command turns of the function + // which turns entire display on, but it does not clear + // the data in display RAM + CMD(0xA4); + + // Set Normal Display + CMD(0xA6); + + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_SET); // Vpp enable + + // Vpp stabilization period + HAL_Delay(100); + + // Display ON + CMD(0xAF); +} + +void display_init_seq(void) { + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14 + // wait 10 milliseconds. only needs to be low for 10 microseconds. + // my dev display module ties display reset and touch panel reset together. + // keeping this low for max(display_reset_time, ctpm_reset_time) aids + // development and does not hurt. + HAL_Delay(10); + + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); // LCD_RST/PC14 + // max wait time for hardware reset is 120 milliseconds + // (experienced display flakiness using only 5ms wait before sending commands) + HAL_Delay(120); + + send_init_seq_SH1107(); + + display_clear(); + display_unsleep(); +} + +void display_init(void) { + // init peripherals + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_FMC_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStructure; + + // LCD_RST/PC14 + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Alternate = 0; + GPIO_InitStructure.Pin = GPIO_PIN_14; + // default to keeping display in reset + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + + // VPP Enable + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Alternate = 0; + GPIO_InitStructure.Pin = GPIO_PIN_8; + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET); + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = GPIO_AF12_FMC; + // LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5 + GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + // LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1 + GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + // LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10 + GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOE, &GPIO_InitStructure); + + // Reference UM1725 "Description of STM32F4 HAL and LL drivers", + // section 64.2.1 "How to use this driver" + SRAM_HandleTypeDef external_display_data_sram; + external_display_data_sram.Instance = FMC_NORSRAM_DEVICE; + external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1; + external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8; + external_display_data_sram.Init.BurstAccessMode = + FMC_BURST_ACCESS_MODE_DISABLE; + external_display_data_sram.Init.WaitSignalPolarity = + FMC_WAIT_SIGNAL_POLARITY_LOW; + external_display_data_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE; + external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + external_display_data_sram.Init.AsynchronousWait = + FMC_ASYNCHRONOUS_WAIT_DISABLE; + external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; + external_display_data_sram.Init.ContinuousClock = + FMC_CONTINUOUS_CLOCK_SYNC_ONLY; + external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE; + + // reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6 + FMC_NORSRAM_TimingTypeDef normal_mode_timing; + normal_mode_timing.AddressSetupTime = 10; + normal_mode_timing.AddressHoldTime = 10; + normal_mode_timing.DataSetupTime = 10; + normal_mode_timing.BusTurnAroundDuration = 0; + normal_mode_timing.CLKDivision = 2; + normal_mode_timing.DataLatency = 2; + normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A; + + HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL); + + display_init_seq(); +} + +void display_refresh(void) {} + +const char *display_save(const char *prefix) { return NULL; } + +void display_clear_save(void) {} diff --git a/core/embed/extmod/modtrezorui/display.c b/core/embed/extmod/modtrezorui/display.c index c505d87c56..7e4944c77b 100644 --- a/core/embed/extmod/modtrezorui/display.c +++ b/core/embed/extmod/modtrezorui/display.c @@ -117,8 +117,10 @@ static struct { int x, y; } DISPLAY_OFFSET; #else #if defined TREZOR_MODEL_T #include "display-stm32_T.h" -#elif defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R +#elif defined TREZOR_MODEL_1 #include "display-stm32_1.h" +#elif defined TREZOR_MODEL_R +#include "display-stm32_R.h" #else #error Unknown Trezor model #endif @@ -930,7 +932,7 @@ int display_orientation(int degrees) { } int display_backlight(int val) { -#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R +#if defined TREZOR_MODEL_1 val = 255; #endif if (DISPLAY_BACKLIGHT != val && val >= 0 && val <= 255) { diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index c331281ec9..2146f40979 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -91,6 +91,11 @@ int main(void) { button_init(); #endif +#if defined TREZOR_MODEL_R + button_init(); + display_clear(); +#endif + #if defined TREZOR_MODEL_T // display_init_seq(); sdcard_init();