From ad8c34e825944aef3d2c348dd1cf666a66d6a7e7 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Thu, 30 Jan 2025 16:25:33 +0100 Subject: [PATCH] feat(core): introduce TPS61062 backlight driver [no changelog] --- core/embed/io/backlight/stm32u5/tps61062.c | 271 ++++++++++++++++++ .../models/T3W1/boards/trezor_t3w1_revA.h | 19 +- .../models/T3W1/boards/trezor_t3w1_revA0.h | 19 +- .../models/T3W1/boards/trezor_t3w1_revB.h | 19 +- .../models/T3W1/trezor_t3w1_revA.py | 2 +- .../models/T3W1/trezor_t3w1_revA0.py | 2 +- .../models/T3W1/trezor_t3w1_revB.py | 2 +- 7 files changed, 292 insertions(+), 42 deletions(-) create mode 100644 core/embed/io/backlight/stm32u5/tps61062.c diff --git a/core/embed/io/backlight/stm32u5/tps61062.c b/core/embed/io/backlight/stm32u5/tps61062.c new file mode 100644 index 0000000000..43c2af36b2 --- /dev/null +++ b/core/embed/io/backlight/stm32u5/tps61062.c @@ -0,0 +1,271 @@ +/* + * 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 . + */ + +#ifdef KERNEL_MODE + +#include +#include +#include +#include + +#include + +#define BACKLIGHT_CONTROL_T_UP_US 30 // may be in range 1-75 +#define BACKLIGHT_CONTROL_T_DOWN_US 198 // may be in range 180-300 + +// unused - for reference +// #define BACKLIGHT_CONTROL_T_START_US 110 // may be in range 100-150 +// #define BACKLIGHT_CONTROL_T_D_US 2 +// #define BACKLIGHT_CONTROL_T_OFF_US 550 + +#define TIMER_PERIOD 32000 // 5 kHz @ 160MHz +#define MAX_PULSE_WIDTH_US 200 // 5kHz + +#define TIM_PULSE(width) \ + (TIMER_PERIOD - (width) * TIMER_PERIOD / MAX_PULSE_WIDTH_US) + +#define MAX_STEPS 32 +#define DEFAULT_STEP 16 // DAC value after reset + +// Backlight driver state +typedef struct { + // Set if driver is initialized + bool initialized; + // Level requested (0-255) + int current_level; + // Current step in range 0-32 + int current_step; + + DMA_HandleTypeDef dma; + TIM_HandleTypeDef tim; + + uint32_t pwm_data[MAX_STEPS + 2]; // max steps + 2 for start and end + +} backlight_driver_t; + +static backlight_driver_t g_backlight_driver = { + .initialized = false, +}; + +static void backlight_control_up(uint32_t *data, int steps); +static void backlight_control_down(uint32_t *data, int steps); +static void backlight_shutdown(); + +void backlight_init(backlight_action_t action) { + backlight_driver_t *drv = &g_backlight_driver; + + if (drv->initialized) { + return; + } + + memset(drv, 0, sizeof(backlight_driver_t)); + + TPS61062_ILED_CLK_ENA(); + TPS61062_EN_CLK_ENA(); + + // action = BACKLIGHT_RESET. + // action = BACKLIGHT_RETAIN is not implemented + + // Initialize EN GPIO + GPIO_InitTypeDef GPIO_EN_InitStructure = {0}; + GPIO_EN_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_EN_InitStructure.Pull = GPIO_NOPULL; + GPIO_EN_InitStructure.Speed = GPIO_SPEED_LOW; + GPIO_EN_InitStructure.Pin = TPS61062_EN_PIN; + HAL_GPIO_Init(TPS61062_EN_PORT, &GPIO_EN_InitStructure); + + HAL_GPIO_WritePin(TPS61062_EN_PORT, TPS61062_EN_PIN, GPIO_PIN_RESET); + + __HAL_RCC_TIM3_CLK_ENABLE(); + __HAL_RCC_TIM3_FORCE_RESET(); + __HAL_RCC_TIM3_RELEASE_RESET(); + drv->tim.State = HAL_TIM_STATE_RESET; + drv->tim.Instance = TIM3; + drv->tim.Init.Period = TIMER_PERIOD; + drv->tim.Init.Prescaler = 0; + drv->tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + drv->tim.Init.CounterMode = TIM_COUNTERMODE_UP; + drv->tim.Init.RepetitionCounter = 0; + HAL_TIM_PWM_Init(&drv->tim); + + TIM_OC_InitTypeDef TIM_OC_InitStructure = {0}; + TIM_OC_InitStructure.Pulse = 0; + TIM_OC_InitStructure.OCMode = TIM_OCMODE_PWM1; + TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_HIGH; + TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE; + TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH; + TIM_OC_InitStructure.OCIdleState = TIM_OCIDLESTATE_RESET; + TIM_OC_InitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET; + HAL_TIM_PWM_ConfigChannel(&drv->tim, &TIM_OC_InitStructure, TIM_CHANNEL_1); + + // Initialize ILED GPIO + GPIO_InitTypeDef GPIO_ILED_InitStructure = {0}; + GPIO_ILED_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_ILED_InitStructure.Pull = GPIO_NOPULL; + GPIO_ILED_InitStructure.Speed = GPIO_SPEED_LOW; + GPIO_ILED_InitStructure.Pin = TPS61062_ILED_PIN; + GPIO_ILED_InitStructure.Alternate = GPIO_AF2_TIM3; + HAL_GPIO_Init(TPS61062_ILED_PORT, &GPIO_ILED_InitStructure); + + __HAL_RCC_GPDMA1_CLK_ENABLE(); + drv->dma.Instance = GPDMA1_Channel3; + drv->dma.Init.Direction = DMA_MEMORY_TO_PERIPH; + drv->dma.Init.Mode = DMA_NORMAL; + drv->dma.Init.Request = GPDMA1_REQUEST_TIM3_UP; + drv->dma.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; + drv->dma.Init.SrcInc = DMA_SINC_INCREMENTED; + drv->dma.Init.DestInc = DMA_DINC_FIXED; + drv->dma.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; + drv->dma.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; + drv->dma.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; + drv->dma.Init.SrcBurstLength = 1; + drv->dma.Init.DestBurstLength = 1; + drv->dma.Init.TransferAllocatedPort = + DMA_SRC_ALLOCATED_PORT1 | DMA_DEST_ALLOCATED_PORT0; + drv->dma.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; + + HAL_DMA_Init(&drv->dma); + HAL_DMA_ConfigChannelAttributes( + &drv->dma, DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC | DMA_CHANNEL_SRC_SEC | + DMA_CHANNEL_DEST_SEC); + + __HAL_TIM_ENABLE_DMA(&drv->tim, TIM_DMA_UPDATE); + + HAL_TIM_Base_Start(&drv->tim); + HAL_TIM_PWM_Start(&drv->tim, TIM_CHANNEL_1); + + drv->initialized = true; +} + +void backlight_deinit(backlight_action_t action) { + backlight_driver_t *drv = &g_backlight_driver; + + if (!drv->initialized) { + return; + } + + if (HAL_DMA_GetState(&drv->dma) == HAL_DMA_STATE_BUSY) { + while (HAL_DMA_PollForTransfer(&drv->dma, HAL_DMA_FULL_TRANSFER, + HAL_MAX_DELAY) != HAL_OK) { + } + } + + if (action == BACKLIGHT_RESET) { + backlight_shutdown(); + HAL_GPIO_DeInit(TPS61062_ILED_PORT, TPS61062_ILED_PIN); + HAL_GPIO_DeInit(TPS61062_EN_PORT, TPS61062_EN_PIN); + + __HAL_RCC_TIM3_FORCE_RESET(); + __HAL_RCC_TIM3_RELEASE_RESET(); + __HAL_RCC_TIM3_CLK_DISABLE(); + } + + drv->initialized = false; +} + +int backlight_set(int val) { + backlight_driver_t *drv = &g_backlight_driver; + + if (!drv->initialized) { + return 0; + } + + if (val < 0 || val > 255) { + return drv->current_level; + } + + if (val == drv->current_level) { + return val; + } + + drv->current_level = val; + int set_step = MAX_STEPS * val / 255; + + if (set_step == 0) { + backlight_shutdown(); + drv->current_step = 0; + return drv->current_level; + } + + if (HAL_DMA_GetState(&drv->dma) == HAL_DMA_STATE_BUSY) { + while (HAL_DMA_PollForTransfer(&drv->dma, HAL_DMA_FULL_TRANSFER, + HAL_MAX_DELAY) != HAL_OK) { + } + } + + int pwm_data_idx = 0; + memset(drv->pwm_data, 0, sizeof(drv->pwm_data)); + + if (drv->current_step == 0) { + HAL_GPIO_WritePin(TPS61062_EN_PORT, TPS61062_EN_PIN, GPIO_PIN_SET); + // if brightness control is shutdown, start with initial pulse + drv->pwm_data[0] = TIMER_PERIOD; + pwm_data_idx++; + drv->current_step = DEFAULT_STEP; + } + + if (set_step > drv->current_step) { + int steps = set_step - drv->current_step; + backlight_control_up(&drv->pwm_data[pwm_data_idx], steps); + pwm_data_idx += steps; + + } else if (set_step < drv->current_step) { + int steps = drv->current_step - set_step; + backlight_control_down(&drv->pwm_data[pwm_data_idx], steps); + pwm_data_idx += steps; + } + + drv->pwm_data[pwm_data_idx] = TIMER_PERIOD; + + HAL_DMA_Start(&drv->dma, (uint32_t)drv->pwm_data, + (uint32_t)&drv->tim.Instance->CCR1, + (pwm_data_idx + 1) * sizeof(uint32_t)); + + drv->current_step = set_step; + + return drv->current_level; +} + +int backlight_get(void) { + backlight_driver_t *drv = &g_backlight_driver; + + if (!drv->initialized) { + return 0; + } + + return drv->current_level; +} + +static void backlight_control_up(uint32_t *data, int steps) { + for (int i = 0; i < steps; i++) { + data[i] = TIM_PULSE(BACKLIGHT_CONTROL_T_UP_US); + } +} + +static void backlight_control_down(uint32_t *data, int steps) { + for (int i = 0; i < steps; i++) { + data[i] = TIM_PULSE(BACKLIGHT_CONTROL_T_DOWN_US); + } +} + +static void backlight_shutdown() { + HAL_GPIO_WritePin(TPS61062_EN_PORT, TPS61062_EN_PIN, GPIO_PIN_RESET); +} + +#endif diff --git a/core/embed/models/T3W1/boards/trezor_t3w1_revA.h b/core/embed/models/T3W1/boards/trezor_t3w1_revA.h index f0acaac7eb..03201c74d4 100644 --- a/core/embed/models/T3W1/boards/trezor_t3w1_revA.h +++ b/core/embed/models/T3W1/boards/trezor_t3w1_revA.h @@ -23,19 +23,12 @@ #define DISPLAY_PWREN_PORT GPIOE #define DISPLAY_PWREN_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE -#define TPS61043_FREQ 200 -#define TPS61043_TIM TIM17 -#define TPS61043_TIM_CLK_EN __HAL_RCC_TIM17_CLK_ENABLE -#define TPS61043_TIM_CLK_DIS __HAL_RCC_TIM17_CLK_DISABLE -#define TPS61043_TIM_FORCE_RESET __HAL_RCC_TIM17_FORCE_RESET -#define TPS61043_TIM_RELEASE_RESET __HAL_RCC_TIM17_RELEASE_RESET -#define TPS61043_TIM_AF GPIO_AF14_TIM17 -#define TPS61043_TIM_OCMODE TIM_OCMODE_PWM1 -#define TPS61043_TIM_CHANNEL TIM_CHANNEL_1 -#define TPS61043_TIM_CCR CCR1 -#define TPS61043_PIN GPIO_PIN_9 -#define TPS61043_PORT GPIOB -#define TPS61043_PORT_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define TPS61062_ILED_PIN GPIO_PIN_3 +#define TPS61062_ILED_PORT GPIOE +#define TPS61062_ILED_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE +#define TPS61062_EN_PIN GPIO_PIN_9 +#define TPS61062_EN_PORT GPIOB +#define TPS61062_EN_CLK_ENA __HAL_RCC_GPIOB_CLK_ENABLE #define NPM1300_I2C_INSTANCE 0 diff --git a/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h b/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h index d702173c81..c305bbc9eb 100644 --- a/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h +++ b/core/embed/models/T3W1/boards/trezor_t3w1_revA0.h @@ -22,19 +22,12 @@ #define DISPLAY_PWREN_PORT GPIOE #define DISPLAY_PWREN_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE -#define TPS61043_FREQ 200 -#define TPS61043_TIM TIM17 -#define TPS61043_TIM_CLK_EN __HAL_RCC_TIM17_CLK_ENABLE -#define TPS61043_TIM_CLK_DIS __HAL_RCC_TIM17_CLK_DISABLE -#define TPS61043_TIM_FORCE_RESET __HAL_RCC_TIM17_FORCE_RESET -#define TPS61043_TIM_RELEASE_RESET __HAL_RCC_TIM17_RELEASE_RESET -#define TPS61043_TIM_AF GPIO_AF14_TIM17 -#define TPS61043_TIM_OCMODE TIM_OCMODE_PWM1 -#define TPS61043_TIM_CHANNEL TIM_CHANNEL_1 -#define TPS61043_TIM_CCR CCR1 -#define TPS61043_PIN GPIO_PIN_9 -#define TPS61043_PORT GPIOB -#define TPS61043_PORT_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define TPS61062_ILED_PIN GPIO_PIN_3 +#define TPS61062_ILED_PORT GPIOE +#define TPS61062_ILED_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE +#define TPS61062_EN_PIN GPIO_PIN_9 +#define TPS61062_EN_PORT GPIOB +#define TPS61062_EN_CLK_ENA __HAL_RCC_GPIOB_CLK_ENABLE #define NPM1300_I2C_INSTANCE 0 diff --git a/core/embed/models/T3W1/boards/trezor_t3w1_revB.h b/core/embed/models/T3W1/boards/trezor_t3w1_revB.h index 8616806fa6..8ce642c412 100644 --- a/core/embed/models/T3W1/boards/trezor_t3w1_revB.h +++ b/core/embed/models/T3W1/boards/trezor_t3w1_revB.h @@ -23,19 +23,12 @@ #define DISPLAY_PWREN_PORT GPIOG #define DISPLAY_PWREN_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE -#define TPS61043_FREQ 200 -#define TPS61043_TIM TIM17 -#define TPS61043_TIM_CLK_EN __HAL_RCC_TIM17_CLK_ENABLE -#define TPS61043_TIM_CLK_DIS __HAL_RCC_TIM17_CLK_DISABLE -#define TPS61043_TIM_FORCE_RESET __HAL_RCC_TIM17_FORCE_RESET -#define TPS61043_TIM_RELEASE_RESET __HAL_RCC_TIM17_RELEASE_RESET -#define TPS61043_TIM_AF GPIO_AF14_TIM17 -#define TPS61043_TIM_OCMODE TIM_OCMODE_PWM1 -#define TPS61043_TIM_CHANNEL TIM_CHANNEL_1 -#define TPS61043_TIM_CCR CCR1 -#define TPS61043_PIN GPIO_PIN_9 -#define TPS61043_PORT GPIOB -#define TPS61043_PORT_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define TPS61062_ILED_PIN GPIO_PIN_3 +#define TPS61062_ILED_PORT GPIOE +#define TPS61062_ILED_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE +#define TPS61062_EN_PIN GPIO_PIN_9 +#define TPS61062_EN_PORT GPIOB +#define TPS61062_EN_CLK_ENA __HAL_RCC_GPIOB_CLK_ENABLE #define NPM1300_I2C_INSTANCE 0 diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py index c4bed75ca1..fdce74d845 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py @@ -51,7 +51,7 @@ def configure( features_available.append("backlight") defines += [("USE_BACKLIGHT", "1")] - sources += ["embed/io/backlight/stm32/tps61043.c"] + sources += ["embed/io/backlight/stm32u5/tps61062.c"] paths += ["embed/io/backlight/inc"] if "input" in features_wanted: diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA0.py b/core/site_scons/models/T3W1/trezor_t3w1_revA0.py index 14815122ac..23c81d2af3 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revA0.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revA0.py @@ -50,7 +50,7 @@ def configure( features_available.append("backlight") defines += [("USE_BACKLIGHT", "1")] - sources += ["embed/io/backlight/stm32/tps61043.c"] + sources += ["embed/io/backlight/stm32u5/tps61062.c"] paths += ["embed/io/backlight/inc"] if "input" in features_wanted: diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py index 34f088950a..2a765279fe 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py @@ -51,7 +51,7 @@ def configure( features_available.append("backlight") defines += [("USE_BACKLIGHT", "1")] - sources += ["embed/io/backlight/stm32/tps61043.c"] + sources += ["embed/io/backlight/stm32u5/tps61062.c"] paths += ["embed/io/backlight/inc"] if "input" in features_wanted: