diff options
author | Nick Sanders <nsanders@chromium.org> | 2016-07-26 13:17:09 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-08-17 16:19:07 -0700 |
commit | 6fcd163da5169bfca36ab8c15cfd9d0624acae19 (patch) | |
tree | cc1e3cd999fa3df95547356e8160fd966aa26bc3 | |
parent | 6fad4f8588242cd6202e1177e145073c6aff6b7a (diff) | |
download | chrome-ec-6fcd163da5169bfca36ab8c15cfd9d0624acae19.tar.gz |
stm32f446e-eval: add support for stm32f446
This adds basic support for the stm32f446.
This consists of:
* New DMA model for stm32f4
* New clock domain support.
* MCO oscillator gpio export support.
* Flash support for irregular blocks.
BUG=chromium:608039
TEST=boots w/ correct clock, stm32f0 also boots.
BRANCH=None
Change-Id: I1c5cf6ddca09009c9dac60da8a3d0c5ceedfcf4d
Signed-off-by: Nick Sanders <nsanders@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/363992
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r-- | board/stm32f446e-eval/board.c | 58 | ||||
-rw-r--r-- | board/stm32f446e-eval/board.h | 54 | ||||
-rw-r--r-- | board/stm32f446e-eval/build.mk | 12 | ||||
-rw-r--r-- | board/stm32f446e-eval/ec.tasklist | 21 | ||||
-rw-r--r-- | board/stm32f446e-eval/gpio.inc | 62 | ||||
-rw-r--r-- | chip/npcx/peci.c | 2 | ||||
-rw-r--r-- | chip/stm32/build.mk | 8 | ||||
-rw-r--r-- | chip/stm32/clock-f.c | 209 | ||||
-rw-r--r-- | chip/stm32/clock-f.h | 70 | ||||
-rw-r--r-- | chip/stm32/clock-stm32f0.c | 192 | ||||
-rw-r--r-- | chip/stm32/clock-stm32f4.c | 254 | ||||
-rw-r--r-- | chip/stm32/config-stm32f446.h | 63 | ||||
-rw-r--r-- | chip/stm32/config_chip.h | 10 | ||||
-rw-r--r-- | chip/stm32/dma-stm32f4.c | 308 | ||||
-rw-r--r-- | chip/stm32/dma.c | 34 | ||||
-rw-r--r-- | chip/stm32/flash-f.c | 16 | ||||
-rw-r--r-- | chip/stm32/flash-stm32f4.c | 384 | ||||
-rw-r--r-- | chip/stm32/gpio-stm32f4.c | 26 | ||||
-rw-r--r-- | chip/stm32/gpio.c | 2 | ||||
-rw-r--r-- | chip/stm32/jtag-stm32f4.c | 17 | ||||
-rw-r--r-- | chip/stm32/registers.h | 537 | ||||
-rw-r--r-- | chip/stm32/system.c | 12 | ||||
-rw-r--r-- | chip/stm32/uart.c | 17 | ||||
-rw-r--r-- | include/config.h | 8 | ||||
-rw-r--r-- | include/module_id.h | 1 | ||||
-rw-r--r-- | include/task.h | 19 | ||||
-rwxr-xr-x | util/flash_ec | 1 |
27 files changed, 2186 insertions, 211 deletions
diff --git a/board/stm32f446e-eval/board.c b/board/stm32f446e-eval/board.c new file mode 100644 index 0000000000..0b8691278c --- /dev/null +++ b/board/stm32f446e-eval/board.c @@ -0,0 +1,58 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "common.h" +#include "dma.h" +#include "ec_version.h" +#include "gpio.h" +#include "gpio_list.h" +#include "hooks.h" +#include "registers.h" +#include "stm32-dma.h" + +#define GPIO_SET_HS(bank, number) \ + (STM32_GPIO_OSPEEDR(GPIO_##bank) |= (0x3 << (number * 2))) + +void board_config_post_gpio_init(void) +{ + /* We use MCO2 clock passthrough to provide a clock to USB HS */ + gpio_config_module(MODULE_MCO, 1); + /* GPIO PC9 to high speed */ + GPIO_SET_HS(C, 9); + + /* Set USB GPIO to high speed */ + GPIO_SET_HS(A, 11); + GPIO_SET_HS(A, 12); + + GPIO_SET_HS(C, 3); + GPIO_SET_HS(C, 2); + GPIO_SET_HS(C, 0); + GPIO_SET_HS(A, 5); + + GPIO_SET_HS(B, 5); + GPIO_SET_HS(B, 13); + GPIO_SET_HS(B, 12); + GPIO_SET_HS(B, 2); + GPIO_SET_HS(B, 10); + GPIO_SET_HS(B, 1); + GPIO_SET_HS(B, 0); + GPIO_SET_HS(A, 3); + + /* Set I2C GPIO to HS */ + GPIO_SET_HS(B, 6); + GPIO_SET_HS(B, 7); + GPIO_SET_HS(F, 1); + GPIO_SET_HS(F, 0); + GPIO_SET_HS(A, 8); + GPIO_SET_HS(B, 4); + GPIO_SET_HS(C, 6); + GPIO_SET_HS(C, 7); +} + +static void board_init(void) +{ +} +DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); + diff --git a/board/stm32f446e-eval/board.h b/board/stm32f446e-eval/board.h new file mode 100644 index 0000000000..24735a2dc7 --- /dev/null +++ b/board/stm32f446e-eval/board.h @@ -0,0 +1,54 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* STM32F446E-Eval board configuration */ + +#ifndef __CROS_EC_BOARD_H +#define __CROS_EC_BOARD_H + +/* Use external clock */ +#define CONFIG_STM32_CLOCK_HSE_HZ 8000000 + +/* Optional features */ +#undef CONFIG_WATCHDOG_HELP +#undef CONFIG_LID_SWITCH +#define CONFIG_BOARD_POST_GPIO_INIT + +/* Enable console recasting of GPIO type. */ +#define CONFIG_CMD_GPIO_EXTENDED + +/* The UART console is on USART1 (PA9/PA10) */ +#undef CONFIG_UART_CONSOLE +#define CONFIG_UART_CONSOLE 1 +#undef CONFIG_UART_TX_BUF_SIZE +#define CONFIG_UART_TX_BUF_SIZE 4096 +#define CONFIG_UART_TX_REQ_CH 4 +#define CONFIG_UART_RX_REQ_CH 4 + +/* This is not actually an EC so disable some features. */ +#undef CONFIG_WATCHDOG_HELP +#undef CONFIG_LID_SWITCH +#undef CONFIG_WATCHDOG + +/* Optional features */ +#define CONFIG_STM_HWTIMER32 +#define CONFIG_DMA_HELP + +/* + * Allow dangerous commands all the time, since we don't have a write protect + * switch. + */ +#define CONFIG_SYSTEM_UNLOCKED + +#ifndef __ASSEMBLER__ +#undef CONFIG_FLASH + +/* Timer selection */ +#define TIM_CLOCK32 5 + +#include "gpio_signal.h" + +#endif /* !__ASSEMBLER__ */ +#endif /* __CROS_EC_BOARD_H */ diff --git a/board/stm32f446e-eval/build.mk b/board/stm32f446e-eval/build.mk new file mode 100644 index 0000000000..6b06f2bb8f --- /dev/null +++ b/board/stm32f446e-eval/build.mk @@ -0,0 +1,12 @@ +# -*- makefile -*- +# Copyright 2016 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Board specific files build + +CHIP:=stm32 +CHIP_FAMILY:=stm32f4 +CHIP_VARIANT:=stm32f446 + +board-y=board.o diff --git a/board/stm32f446e-eval/ec.tasklist b/board/stm32f446e-eval/ec.tasklist new file mode 100644 index 0000000000..c4605514e5 --- /dev/null +++ b/board/stm32f446e-eval/ec.tasklist @@ -0,0 +1,21 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** + * List of enabled tasks in the priority order + * + * The first one has the lowest priority. + * + * For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and + * TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries, + * where : + * 'n' in the name of the task + * 'r' in the main routine of the task + * 'd' in an opaque parameter passed to the routine at startup + * 's' is the stack size in bytes; must be a multiple of 8 + */ +#define CONFIG_TASK_LIST \ + TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \ + TASK_ALWAYS(CONSOLE, console_task, NULL, VENTI_TASK_STACK_SIZE) diff --git a/board/stm32f446e-eval/gpio.inc b/board/stm32f446e-eval/gpio.inc new file mode 100644 index 0000000000..3d1753d43b --- /dev/null +++ b/board/stm32f446e-eval/gpio.inc @@ -0,0 +1,62 @@ +/* -*- mode:c -*- + * + * Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Declare symbolic names for all the GPIOs that we care about. + * Note: Those with interrupt handlers must be declared first. */ + +/* Outputs */ +GPIO(PD11, PIN(D, 11), GPIO_OUT_HIGH) + +GPIO(I2C1_SCL, PIN(B, 8), GPIO_INPUT) +GPIO(I2C1_SDA, PIN(B, 9), GPIO_INPUT) +GPIO(FMPI2C_SCL, PIN(C, 6), GPIO_INPUT) +GPIO(FMPI2C_SDA, PIN(C, 7), GPIO_INPUT) + +/* USART3 TX/RX */ +GPIO(MCU_UART1_TX, PIN(A, 9), GPIO_INPUT) +GPIO(MCU_UART1_RX, PIN(A, 10), GPIO_INPUT) +GPIO(MCU_UART3_TX, PIN(C, 10), GPIO_INPUT) +GPIO(MCU_UART3_RX, PIN(C, 11), GPIO_INPUT) + +GPIO(USB_FS_DM, PIN(A, 11), GPIO_INPUT) +GPIO(USB_FS_DP, PIN(A, 12), GPIO_INPUT) + + +GPIO(USB_HS_ULPI_NXT, PIN(C, 3), GPIO_INPUT) +GPIO(USB_HS_ULPI_DIR, PIN(C, 2), GPIO_INPUT) +GPIO(USB_HS_ULPI_STP, PIN(C, 0), GPIO_INPUT) +GPIO(USB_HS_ULPI_CK, PIN(A, 5), GPIO_INPUT) + +GPIO(USB_HS_ULPI_D7, PIN(B, 5), GPIO_INPUT) +GPIO(USB_HS_ULPI_D6, PIN(B,13), GPIO_INPUT) +GPIO(USB_HS_ULPI_D5, PIN(B,12), GPIO_INPUT) +GPIO(USB_HS_ULPI_D4, PIN(B, 2), GPIO_INPUT) +GPIO(USB_HS_ULPI_D3, PIN(B,10), GPIO_INPUT) +GPIO(USB_HS_ULPI_D2, PIN(B, 1), GPIO_INPUT) +GPIO(USB_HS_ULPI_D1, PIN(B, 0), GPIO_INPUT) +GPIO(USB_HS_ULPI_D0, PIN(A, 3), GPIO_INPUT) + + + +/* Unimplemented signals since this is a dev board */ +UNIMPLEMENTED(ENTERING_RW) +UNIMPLEMENTED(WP_L) + +ALTERNATE(PIN_MASK(A, 0x0600), 7, MODULE_UART, 0) /* USART1: PA9/PA10 - Console */ +ALTERNATE(PIN_MASK(C, 0x0C00), 7, MODULE_USART, 0) /* USART3: PC10/PC11 - NOT Console */ +ALTERNATE(PIN_MASK(A, 0x0100), 0, MODULE_MCO, 0) /* MCO1: PA8 */ +ALTERNATE(PIN_MASK(C, 0x0200), 0, MODULE_MCO, 0) /* MCO2: PC9 */ + +ALTERNATE(PIN_MASK(B, 0x0300), 4, MODULE_I2C, GPIO_ODR_HIGH | GPIO_PULL_UP) /* I2C1: PB8-9 */ +ALTERNATE(PIN_MASK(C, 0x00c0), 4, MODULE_I2C, GPIO_ODR_HIGH | GPIO_PULL_UP) /* FMPI2C MASTER:PC6/7 */ + +ALTERNATE(PIN_MASK(A, 0x1800), 10, MODULE_USB, 0) /* DWC USB OTG: PA11/12 */ + +/* OTG HS */ +ALTERNATE(PIN_MASK(A, 0x0028), 10, MODULE_USB, 0) /* DWC USB OTG HS */ +ALTERNATE(PIN_MASK(B, 0x3427), 10, MODULE_USB, 0) /* DWC USB OTG HS */ +ALTERNATE(PIN_MASK(C, 0x000d), 10, MODULE_USB, 0) /* DWC USB OTG HS */ diff --git a/chip/npcx/peci.c b/chip/npcx/peci.c index cb3df354e6..4cb926ef18 100644 --- a/chip/npcx/peci.c +++ b/chip/npcx/peci.c @@ -28,8 +28,6 @@ /* PECI Time-out */ #define PECI_DONE_TIMEOUT_US (10*MSEC) -/* Task Event for PECI */ -#define TASK_EVENT_PECI_DONE TASK_EVENT_CUSTOM(1<<26) #define NULL_PENDING_TASK_ID 0xFFFFFFFF #define PECI_MAX_FIFO_SIZE 16 diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk index 9d76c03885..d145db5473 100644 --- a/chip/stm32/build.mk +++ b/chip/stm32/build.mk @@ -11,7 +11,7 @@ ifeq ($(CHIP_FAMILY),stm32f0) CORE:=cortex-m0 # Force ARMv6-M ISA used by the Cortex-M0 CFLAGS_CPU+=-march=armv6-m -mcpu=cortex-m0 -else ifeq ($(CHIP_FAMILY),$(filter $(CHIP_FAMILY),stm32f3 stm32l4)) +else ifeq ($(CHIP_FAMILY),$(filter $(CHIP_FAMILY),stm32f3 stm32l4 stm32f4)) # STM32F3xx and STM32L4xx sub-family has a Cortex-M4 ARM core CORE:=cortex-m # Allow the full Cortex-M4 instruction set @@ -25,10 +25,14 @@ endif # Select between 16-bit and 32-bit timer for clock source TIMER_TYPE=$(if $(CONFIG_STM_HWTIMER32),32,) +DMA_TYPE=$(if $(CHIP_FAMILY_STM32F4),-stm32f4,) -chip-y=dma.o +chip-$(CONFIG_DMA)+=dma$(DMA_TYPE).o chip-$(CONFIG_COMMON_RUNTIME)+=system.o chip-y+=jtag-$(CHIP_FAMILY).o clock-$(CHIP_FAMILY).o +ifeq ($(CHIP_FAMILY),$(filter $(CHIP_FAMILY),stm32f0 stm32f3 stm32f4)) +chip-y+=clock-f.o +endif chip-$(CONFIG_SPI)+=spi.o chip-$(CONFIG_SPI_MASTER)+=spi_master.o chip-$(CONFIG_COMMON_GPIO)+=gpio.o gpio-$(CHIP_FAMILY).o diff --git a/chip/stm32/clock-f.c b/chip/stm32/clock-f.c new file mode 100644 index 0000000000..02773dc678 --- /dev/null +++ b/chip/stm32/clock-f.c @@ -0,0 +1,209 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Clocks and power management settings */ + +#include "chipset.h" +#include "clock.h" +#include "clock-f.h" +#include "common.h" +#include "console.h" +#include "cpu.h" +#include "hooks.h" +#include "hwtimer.h" +#include "registers.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_CLOCK, outstr) +#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args) + + +/* Convert between RTC regs in BCD and seconds */ +uint32_t rtc_to_sec(uint32_t rtc) +{ + uint32_t sec; + + /* convert the hours field */ + sec = (((rtc & 0x300000) >> 20) * 10 + ((rtc & 0xf0000) >> 16)) * 3600; + /* convert the minutes field */ + sec += (((rtc & 0x7000) >> 12) * 10 + ((rtc & 0xf00) >> 8)) * 60; + /* convert the seconds field */ + sec += ((rtc & 0x70) >> 4) * 10 + (rtc & 0xf); + + return sec; +} +uint32_t sec_to_rtc(uint32_t sec) +{ + uint32_t rtc; + + /* convert the hours field */ + rtc = ((sec / 36000) << 20) | (((sec / 3600) % 10) << 16); + /* convert the minutes field */ + rtc |= (((sec % 3600) / 600) << 12) | (((sec % 600) / 60) << 8); + /* convert the seconds field */ + rtc |= (((sec % 60) / 10) << 4) | (sec % 10); + + return rtc; +} + +/* Return time diff between two rtc readings */ +int32_t get_rtc_diff(uint32_t rtc0, uint32_t rtc0ss, + uint32_t rtc1, uint32_t rtc1ss) +{ + int32_t diff; + + /* Note: this only looks at the diff mod 10 seconds */ + diff = ((rtc1 & 0xf) * SECOND + + rtcss_to_us(rtc1ss)) - + ((rtc0 & 0xf) * SECOND + + rtcss_to_us(rtc0ss)); + + return (diff < 0) ? (diff + 10*SECOND) : diff; +} + +void rtc_read(uint32_t *rtc, uint32_t *rtcss) +{ + /* Read current time synchronously */ + do { + *rtc = STM32_RTC_TR; + /* + * RTC_SSR must be read twice with identical values because + * glitches may occur for reads close to the RTCCLK edge. + */ + do { + *rtcss = STM32_RTC_SSR; + } while (*rtcss != STM32_RTC_SSR); + } while (*rtc != STM32_RTC_TR); +} + +void set_rtc_alarm(uint32_t delay_s, uint32_t delay_us, + uint32_t *rtc, uint32_t *rtcss) +{ + uint32_t alarm_sec, alarm_us; + + /* Alarm must be within 1 day (86400 seconds) */ + ASSERT((delay_s + delay_us / SECOND) < 86400); + + rtc_unlock_regs(); + + /* Make sure alarm is disabled */ + STM32_RTC_CR &= ~STM32_RTC_CR_ALRAE; + while (!(STM32_RTC_ISR & STM32_RTC_ISR_ALRAWF)) + ; + STM32_RTC_ISR &= ~STM32_RTC_ISR_ALRAF; + + rtc_read(rtc, rtcss); + + /* Calculate alarm time */ + alarm_sec = rtc_to_sec(*rtc) + delay_s; + alarm_us = rtcss_to_us(*rtcss) + delay_us; + alarm_sec = alarm_sec + alarm_us / SECOND; + alarm_us = alarm_us % 1000000; + /* + * If seconds is greater than 1 day, subtract by 1 day to deal with + * 24-hour rollover. + */ + if (alarm_sec >= 86400) + alarm_sec -= 86400; + + /* Set alarm time */ + STM32_RTC_ALRMAR = sec_to_rtc(alarm_sec); + STM32_RTC_ALRMASSR = us_to_rtcss(alarm_us); + /* Check for match on hours, minutes, seconds, and subsecond */ + STM32_RTC_ALRMAR |= 0xc0000000; + STM32_RTC_ALRMASSR |= 0x0f000000; + + /* Enable alarm and alarm interrupt */ + STM32_EXTI_PR = EXTI_RTC_ALR_EVENT; + STM32_EXTI_IMR |= EXTI_RTC_ALR_EVENT; + STM32_RTC_CR |= STM32_RTC_CR_ALRAE; + + rtc_lock_regs(); +} + +void reset_rtc_alarm(uint32_t *rtc, uint32_t *rtcss) +{ + rtc_unlock_regs(); + + /* Disable alarm */ + STM32_RTC_CR &= ~STM32_RTC_CR_ALRAE; + STM32_RTC_ISR &= ~STM32_RTC_ISR_ALRAF; + + /* Disable RTC alarm interrupt */ + STM32_EXTI_IMR &= ~EXTI_RTC_ALR_EVENT; + STM32_EXTI_PR = EXTI_RTC_ALR_EVENT; + + /* Read current time */ + rtc_read(rtc, rtcss); + + rtc_lock_regs(); +} + +void __rtc_alarm_irq(void) +{ + uint32_t rtc, rtcss; + + reset_rtc_alarm(&rtc, &rtcss); +} +DECLARE_IRQ(STM32_IRQ_RTC_ALARM, __rtc_alarm_irq, 1); + +void clock_init(void) +{ + /* + * The initial state : + * SYSCLK from HSI (=8MHz), no divider on AHB, APB1, APB2 + * PLL unlocked, RTC enabled on LSE + */ + + /* + * put 1 Wait-State for flash access to ensure proper reads at 48Mhz + * and enable prefetch buffer. + */ + /* Enable data and instruction cache. */ + STM32_FLASH_ACR = STM32_FLASH_ACR_LATENCY | STM32_FLASH_ACR_PRFTEN; + + config_hispeed_clock(); + + rtc_init(); +} + +/*****************************************************************************/ +/* Console commands */ + +#ifdef CONFIG_CMD_RTC_ALARM +static int command_rtc_alarm_test(int argc, char **argv) +{ + int s = 1, us = 0; + uint32_t rtc, rtcss; + char *e; + + ccprintf("Setting RTC alarm\n"); + + if (argc > 1) { + s = strtoi(argv[1], &e, 10); + if (*e) + return EC_ERROR_PARAM1; + + } + if (argc > 2) { + us = strtoi(argv[2], &e, 10); + if (*e) + return EC_ERROR_PARAM2; + + } + + set_rtc_alarm(s, us, &rtc, &rtcss); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(rtc_alarm, command_rtc_alarm_test, + "[seconds [microseconds]]", + "Test alarm", + NULL); +#endif /* CONFIG_CMD_RTC_ALARM */ + diff --git a/chip/stm32/clock-f.h b/chip/stm32/clock-f.h new file mode 100644 index 0000000000..187bda916d --- /dev/null +++ b/chip/stm32/clock-f.h @@ -0,0 +1,70 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Clocks and power management settings */ + +#ifndef __CROS_EC_CLOCK_F_H +#define __CROS_EC_CLOCK_F_H + +#include "chipset.h" +#include "clock.h" +#include "common.h" +#include "console.h" +#include "cpu.h" +#include "hooks.h" +#include "hwtimer.h" +#include "registers.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* Lock and unlock RTC write access */ +static inline void rtc_lock_regs(void) +{ + STM32_RTC_WPR = 0xff; +} +static inline void rtc_unlock_regs(void) +{ + STM32_RTC_WPR = 0xca; + STM32_RTC_WPR = 0x53; +} + +/* Convert between RTC regs in BCD and seconds */ +uint32_t rtc_to_sec(uint32_t rtc); + +/* Convert between seconds and RTC regs */ +uint32_t sec_to_rtc(uint32_t sec); + +/* Calculate microseconds from rtc clocks. */ +int32_t rtcss_to_us(uint32_t rtcss); + +/* Calculate rtc clocks from microseconds. */ +uint32_t us_to_rtcss(int32_t us); + +/* Return time diff between two rtc readings */ +int32_t get_rtc_diff(uint32_t rtc0, uint32_t rtc0ss, + uint32_t rtc1, uint32_t rtc1ss); + +/* Read RTC values */ +void rtc_read(uint32_t *rtc, uint32_t *rtcss); + +/* Set RTC wakeup */ +void set_rtc_alarm(uint32_t delay_s, uint32_t delay_us, + uint32_t *rtc, uint32_t *rtcss); + +/* Clear RTC wakeup */ +void reset_rtc_alarm(uint32_t *rtc, uint32_t *rtcss); + +/* RTC init */ +void rtc_init(void); + +/* Init clock blocks and finctionality */ +void clock_init(void); + +/* Init high speed clock config */ +void config_hispeed_clock(void); + +#endif /* __CROS_EC_CLOCK_F_H */ diff --git a/chip/stm32/clock-stm32f0.c b/chip/stm32/clock-stm32f0.c index a6d297bcb7..98c39694f2 100644 --- a/chip/stm32/clock-stm32f0.c +++ b/chip/stm32/clock-stm32f0.c @@ -7,6 +7,7 @@ #include "chipset.h" #include "clock.h" +#include "clock-f.h" #include "common.h" #include "console.h" #include "cpu.h" @@ -74,147 +75,19 @@ static int dsleep_recovery_margin_us = 1000000; #define RTC_PREDIV_A 1 #define US_PER_RTC_TICK (1000000 / RTC_FREQ) -/* Lock and unlock RTC write access */ -static inline void rtc_lock_regs(void) -{ - STM32_RTC_WPR = 0xff; -} -static inline void rtc_unlock_regs(void) -{ - STM32_RTC_WPR = 0xca; - STM32_RTC_WPR = 0x53; -} - -/* Convert between RTC regs in BCD and seconds */ -static inline uint32_t rtc_to_sec(uint32_t rtc) -{ - uint32_t sec; - - /* convert the hours field */ - sec = (((rtc & 0x300000) >> 20) * 10 + ((rtc & 0xf0000) >> 16)) * 3600; - /* convert the minutes field */ - sec += (((rtc & 0x7000) >> 12) * 10 + ((rtc & 0xf00) >> 8)) * 60; - /* convert the seconds field */ - sec += ((rtc & 0x70) >> 4) * 10 + (rtc & 0xf); - - return sec; -} -static inline uint32_t sec_to_rtc(uint32_t sec) -{ - uint32_t rtc; - - /* convert the hours field */ - rtc = ((sec / 36000) << 20) | (((sec / 3600) % 10) << 16); - /* convert the minutes field */ - rtc |= (((sec % 3600) / 600) << 12) | (((sec % 600) / 60) << 8); - /* convert the seconds field */ - rtc |= (((sec % 60) / 10) << 4) | (sec % 10); - - return rtc; -} - -/* Return time diff between two rtc readings */ -int32_t get_rtc_diff(uint32_t rtc0, uint32_t rtc0ss, - uint32_t rtc1, uint32_t rtc1ss) -{ - int32_t diff; - - /* Note: this only looks at the diff mod 10 seconds */ - diff = ((rtc1 & 0xf) * SECOND + - (RTC_PREDIV_S - rtc1ss) * US_PER_RTC_TICK) - - ((rtc0 & 0xf) * SECOND + - (RTC_PREDIV_S - rtc0ss) * US_PER_RTC_TICK); - - return (diff < 0) ? (diff + 10*SECOND) : diff; -} -static inline void rtc_read(uint32_t *rtc, uint32_t *rtcss) +int32_t rtcss_to_us(uint32_t rtcss) { - /* Read current time synchronously */ - do { - *rtc = STM32_RTC_TR; - /* - * RTC_SSR must be read twice with identical values because - * glitches may occur for reads close to the RTCCLK edge. - */ - do { - *rtcss = STM32_RTC_SSR; - } while (*rtcss != STM32_RTC_SSR); - } while (*rtc != STM32_RTC_TR); -} - -void set_rtc_alarm(uint32_t delay_s, uint32_t delay_us, - uint32_t *rtc, uint32_t *rtcss) -{ - uint32_t alarm_sec, alarm_us; - - /* Alarm must be within 1 day (86400 seconds) */ - ASSERT((delay_s + delay_us / SECOND) < 86400); - - rtc_unlock_regs(); - - /* Make sure alarm is disabled */ - STM32_RTC_CR &= ~STM32_RTC_CR_ALRAE; - while (!(STM32_RTC_ISR & STM32_RTC_ISR_ALRAWF)) - ; - STM32_RTC_ISR &= ~STM32_RTC_ISR_ALRAF; - - rtc_read(rtc, rtcss); - - /* Calculate alarm time */ - alarm_sec = rtc_to_sec(*rtc) + delay_s; - alarm_us = (RTC_PREDIV_S - *rtcss) * US_PER_RTC_TICK + delay_us; - alarm_sec = alarm_sec + alarm_us / SECOND; - alarm_us = alarm_us % 1000000; - /* - * If seconds is greater than 1 day, subtract by 1 day to deal with - * 24-hour rollover. - */ - if (alarm_sec >= 86400) - alarm_sec -= 86400; - - /* Set alarm time */ - STM32_RTC_ALRMAR = sec_to_rtc(alarm_sec); - STM32_RTC_ALRMASSR = RTC_PREDIV_S - (alarm_us / US_PER_RTC_TICK); - /* Check for match on hours, minutes, seconds, and subsecond */ - STM32_RTC_ALRMAR |= 0xc0000000; - STM32_RTC_ALRMASSR |= 0x0f000000; - - /* Enable alarm and alarm interrupt */ - STM32_EXTI_PR = EXTI_RTC_ALR_EVENT; - STM32_EXTI_IMR |= EXTI_RTC_ALR_EVENT; - STM32_RTC_CR |= STM32_RTC_CR_ALRAE; - - rtc_lock_regs(); + return ((RTC_PREDIV_S - rtcss) * US_PER_RTC_TICK); } -void reset_rtc_alarm(uint32_t *rtc, uint32_t *rtcss) +uint32_t us_to_rtcss(int32_t us) { - rtc_unlock_regs(); - - /* Disable alarm */ - STM32_RTC_CR &= ~STM32_RTC_CR_ALRAE; - STM32_RTC_ISR &= ~STM32_RTC_ISR_ALRAF; - - /* Disable RTC alarm interrupt */ - STM32_EXTI_IMR &= ~EXTI_RTC_ALR_EVENT; - STM32_EXTI_PR = EXTI_RTC_ALR_EVENT; - - /* Read current time */ - rtc_read(rtc, rtcss); - - rtc_lock_regs(); + return (RTC_PREDIV_S - (us / US_PER_RTC_TICK)); } -void __rtc_alarm_irq(void) -{ - uint32_t rtc, rtcss; - - reset_rtc_alarm(&rtc, &rtcss); -} -DECLARE_IRQ(STM32_IRQ_RTC_ALARM, __rtc_alarm_irq, 1); -static void config_hispeed_clock(void) +void config_hispeed_clock(void) { #ifdef CHIP_FAMILY_STM32F3 /* Ensure that HSE is ON */ @@ -517,58 +390,6 @@ void rtc_init(void) rtc_lock_regs(); } -void clock_init(void) -{ - /* - * The initial state : - * SYSCLK from HSI (=8MHz), no divider on AHB, APB1, APB2 - * PLL unlocked, RTC enabled on LSE - */ - - /* - * put 1 Wait-State for flash access to ensure proper reads at 48Mhz - * and enable prefetch buffer. - */ - STM32_FLASH_ACR = STM32_FLASH_ACR_LATENCY | STM32_FLASH_ACR_PRFTEN; - - config_hispeed_clock(); - - rtc_init(); -} - -/*****************************************************************************/ -/* Console commands */ - -#ifdef CONFIG_CMD_RTC_ALARM -static int command_rtc_alarm_test(int argc, char **argv) -{ - int s = 1, us = 0; - uint32_t rtc, rtcss; - char *e; - - ccprintf("Setting RTC alarm\n"); - - if (argc > 1) { - s = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - - } - if (argc > 2) { - us = strtoi(argv[2], &e, 10); - if (*e) - return EC_ERROR_PARAM2; - - } - - set_rtc_alarm(s, us, &rtc, &rtcss); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(rtc_alarm, command_rtc_alarm_test, - "[seconds [microseconds]]", - "Test alarm", - NULL); -#endif /* CONFIG_CMD_RTC_ALARM */ #if defined(CONFIG_LOW_POWER_IDLE) && defined(CONFIG_COMMON_RUNTIME) #ifdef CONFIG_CMD_IDLE_STATS @@ -595,4 +416,3 @@ DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats, NULL); #endif /* CONFIG_CMD_IDLE_STATS */ #endif - diff --git a/chip/stm32/clock-stm32f4.c b/chip/stm32/clock-stm32f4.c new file mode 100644 index 0000000000..975effd564 --- /dev/null +++ b/chip/stm32/clock-stm32f4.c @@ -0,0 +1,254 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Clocks and power management settings */ + +#include "chipset.h" +#include "clock.h" +#include "clock-f.h" +#include "common.h" +#include "console.h" +#include "cpu.h" +#include "hooks.h" +#include "hwtimer.h" +#include "registers.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_CLOCK, outstr) +#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args) + +#ifdef CONFIG_STM32_CLOCK_HSE_HZ +#define RTC_PREDIV_A 39 +#define RTC_FREQ ((STM32F4_RTC_REQ) / (RTC_PREDIV_A + 1)) /* Hz */ +#else +/* LSI clock is 40kHz-ish */ +#define RTC_PREDIV_A 1 +#define RTC_FREQ (40000 / (RTC_PREDIV_A + 1)) /* Hz */ +#endif +#define RTC_PREDIV_S (RTC_FREQ - 1) +#define US_PER_RTC_TICK (1000000 / RTC_FREQ) + +int32_t rtcss_to_us(uint32_t rtcss) +{ + return ((RTC_PREDIV_S - rtcss) * US_PER_RTC_TICK); +} + +uint32_t us_to_rtcss(int32_t us) +{ + return (RTC_PREDIV_S - (us / US_PER_RTC_TICK)); +} + +static void wait_for_ready(volatile uint32_t *cr_reg, + uint32_t enable, uint32_t ready) +{ + /* Ensure that clock source is ON */ + if (!(*cr_reg & ready)) { + /* Enable clock */ + *cr_reg |= enable; + /* Wait for ready */ + while (!(*cr_reg & ready)) + ; + } +} + +void config_hispeed_clock(void) +{ +#ifdef CONFIG_STM32_CLOCK_HSE_HZ + int srcclock = CONFIG_STM32_CLOCK_HSE_HZ; + int clk_check_mask = STM32_RCC_CR_HSERDY; + int clk_enable_mask = STM32_RCC_CR_HSEON; +#else + int srcclock = STM32F4_HSI_CLOCK; + int clk_check_mask = STM32_RCC_CR_HSIRDY; + int clk_enable_mask = STM32_RCC_CR_HSION; +#endif + int plldiv, pllinputclock; + int pllmult, vcoclock; + int systemdivq, systemclock; + int usbdiv; + int i2sdiv; + + int ahbpre, apb1pre, apb2pre; + int rtcdiv = 0; + + /* If PLL is the clock source, PLL has already been set up. */ + if ((STM32_RCC_CFGR & STM32_RCC_CFGR_SWS_MASK) == + STM32_RCC_CFGR_SWS_PLL) + return; + + /* Ensure that HSE/HSI is ON */ + wait_for_ready(&(STM32_RCC_CR), clk_enable_mask, clk_check_mask); + + /* PLL input must be between 1-2MHz, near 2 */ + /* Valid values 2-63 */ + plldiv = (srcclock + STM32F4_PLL_REQ - 1) / STM32F4_PLL_REQ; + pllinputclock = srcclock / plldiv; + + /* PLL output clock: Must be 100-432MHz */ + /* Valid values 50-432, we'll get 336MHz */ + pllmult = (STM32F4_VCO_CLOCK + (pllinputclock / 2)) / pllinputclock; + vcoclock = pllinputclock * pllmult; + + /* CPU/System clock: Below 180MHz */ + /* We'll do 84MHz */ + systemclock = vcoclock / 4; + systemdivq = 1; + /* USB clock = 48MHz exactly */ + usbdiv = (vcoclock + (STM32F4_USB_REQ / 2)) / STM32F4_USB_REQ; + /* SYSTEM/I2S: same system clock */ + i2sdiv = (vcoclock + (systemclock / 2)) / systemclock; + + /* All IO clocks at 42MHz */ + /* AHB Prescalar */ + ahbpre = 0x8; /* AHB = system clock / 2*/ + /* NOTE: If apbXpre is not 0, timers are x2 clocked. RM0390 Fig. 13 */ + apb1pre = 0; /* APB1 = AHB */ + apb2pre = 0; /* APB2 = AHB */ + +#ifdef CONFIG_STM32_CLOCK_HSE_HZ + /* RTC clock = 1MHz */ + rtcdiv = (CONFIG_STM32_CLOCK_HSE_HZ + (STM32F4_RTC_REQ / 2)) + / STM32F4_RTC_REQ; +#endif + /* Switch SYSCLK to PLL, setup prescalars. + * EC codebase doesn't understand multiple clock domains + * so we enforce a clock config that keeps AHB = APB1 = APB2 + * allowing ec codebase assumptions about consistent clock + * rates to remain true. + * + * NOTE: Sweetberry requires MCO2 <- HSE @ 24MHz + * MCO outputs are selected here but are not changeable later. + * A CONFIG may be needed if other boards have different MCO + * requirements. + */ + STM32_RCC_CFGR = + (2 << 30) | /* MCO2 <- HSE */ + (0 << 27) | /* MCO2 div / 4 */ + (6 << 24) | /* MCO1 div / 4 */ + (3 << 21) | /* MCO1 <- PLL */ + CFGR_RTCPRE(rtcdiv) | + CFGR_PPRE2(apb2pre) | + CFGR_PPRE1(apb1pre) | + CFGR_HPRE(ahbpre) | + STM32_RCC_CFGR_SW_PLL; + + /* Set up PLL */ + STM32_RCC_PLLCFGR = + PLLCFGR_PLLM(plldiv) | + PLLCFGR_PLLN(pllmult) | + PLLCFGR_PLLP(systemdivq) | +#if defined(CONFIG_STM32_CLOCK_HSE_HZ) + PLLCFGR_PLLSRC_HSE | +#else + PLLCFGR_PLLSRC_HSI | +#endif + PLLCFGR_PLLQ(usbdiv) | + PLLCFGR_PLLR(i2sdiv); + + wait_for_ready(&(STM32_RCC_CR), + STM32_RCC_CR_PLLON, STM32_RCC_CR_PLLRDY); + + /* Wait until the PLL is the clock source */ + if ((STM32_RCC_CFGR & STM32_RCC_CFGR_SWS_MASK) == + STM32_RCC_CFGR_SWS_PLL) + ; + + /* Setup RTC Clock input */ + STM32_RCC_BDCR |= STM32_RCC_BDCR_BDRST; +#ifdef CONFIG_STM32_CLOCK_HSE_HZ + STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BCDR_RTCSEL(BDCR_SRC_HSE); +#else + /* Ensure that LSI is ON */ + wait_for_ready(&(STM32_RCC_CSR), + STM32_RCC_CSR_LSION, STM32_RCC_CSR_LSIRDY); + + STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BCDR_RTCSEL(BDCR_SRC_LSI); +#endif +} + +int clock_get_freq(void) +{ + return STM32F4_IO_CLOCK; +} + +void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles) +{ + volatile uint32_t dummy __attribute__((unused)); + + if (bus == BUS_AHB) { + while (cycles--) + dummy = STM32_DMA_GET_ISR(0); + } else { /* APB */ + while (cycles--) + dummy = STM32_USART_BRR(STM32_USART1_BASE); + } +} + +void clock_enable_module(enum module_id module, int enable) +{ + if (module == MODULE_USB) { + if (enable) { + STM32_RCC_AHB2ENR |= STM32_RCC_AHB2ENR_OTGFSEN; + STM32_RCC_AHB1ENR |= STM32_RCC_AHB1ENR_OTGHSEN | + STM32_RCC_AHB1ENR_OTGHSULPIEN; + } else { + STM32_RCC_AHB2ENR &= ~STM32_RCC_AHB2ENR_OTGFSEN; + STM32_RCC_AHB1ENR &= ~STM32_RCC_AHB1ENR_OTGHSEN & + ~STM32_RCC_AHB1ENR_OTGHSULPIEN; + } + return; + } else if (module == MODULE_I2C) { + if (enable) { + /* Enable clocks to I2C modules if necessary */ + STM32_RCC_APB1ENR |= + STM32_RCC_I2C1EN | STM32_RCC_I2C2EN + | STM32_RCC_I2C3EN | STM32_RCC_FMPI2C4EN; + STM32_RCC_DCKCFGR2 = + (STM32_RCC_DCKCFGR2 & ~DCKCFGR2_FMPI2C1SEL_MASK) + | DCKCFGR2_FMPI2C1SEL(FMPI2C1SEL_APB); + } else { + STM32_RCC_APB1ENR &= + ~(STM32_RCC_I2C1EN | STM32_RCC_I2C2EN | + STM32_RCC_I2C3EN | STM32_RCC_FMPI2C4EN); + } + return; + } + + CPRINTS("Module %d is not supported for clock %s\n", + module, enable ? "enable" : "disable"); +} + +void rtc_init(void) +{ + rtc_unlock_regs(); + + /* Enter RTC initialize mode */ + STM32_RTC_ISR |= STM32_RTC_ISR_INIT; + while (!(STM32_RTC_ISR & STM32_RTC_ISR_INITF)) + ; + + /* Set clock prescalars: Needs two separate writes. */ + STM32_RTC_PRER = + (STM32_RTC_PRER & ~STM32_RTC_PRER_S_MASK) | RTC_PREDIV_S; + STM32_RTC_PRER = + (STM32_RTC_PRER & ~STM32_RTC_PRER_A_MASK) + | (RTC_PREDIV_A << 16); + + /* Start RTC timer */ + STM32_RTC_ISR &= ~STM32_RTC_ISR_INIT; + while (STM32_RTC_ISR & STM32_RTC_ISR_INITF) + ; + + /* Enable RTC alarm interrupt */ + STM32_RTC_CR |= STM32_RTC_CR_ALRAIE | STM32_RTC_CR_BYPSHAD; + STM32_EXTI_RTSR |= EXTI_RTC_ALR_EVENT; + task_enable_irq(STM32_IRQ_RTC_ALARM); + + rtc_lock_regs(); +} diff --git a/chip/stm32/config-stm32f446.h b/chip/stm32/config-stm32f446.h new file mode 100644 index 0000000000..33b44b71a3 --- /dev/null +++ b/chip/stm32/config-stm32f446.h @@ -0,0 +1,63 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Memory mapping */ +/* Flash physical size is: (512 * 1024) + * We are limiting the ec.bin size to 128k to reduce flashing time. + */ +#define CONFIG_FLASH_SIZE (128 * 1024) +#define CONFIG_FLASH_BANK_SIZE (16 * 1024) + +/* + * 8 "erase" sectors : 16KB/16KB/16KB/16KB/64KB/128KB/128KB/128KB + * We won't use CONFIG_FLASH_ERASE_SIZE, it will be programmatically + * set in flash-stm32f4.c. However it must be set or the common flash + * code won't build. So we'll set it here. + */ +#define CONFIG_FLASH_ERASE_SIZE (16 * 1024) + +/* minimum write size for 3.3V. 1 for 1.8V */ +#define FLASH_WRITE_SIZE_1800 0x0001 +#define FLASH_WS_DIV_1800 16000000 +#define FLASH_WRITE_SIZE_3300 0x0004 +#define FLASH_WS_DIV_3300 30000000 +#define FLASH_WRITE_SIZE 0x0004 + +#define CONFIG_FLASH_WRITE_SIZE FLASH_WRITE_SIZE + +/* No page mode on STM32F, so no benefit to larger write sizes */ +#define CONFIG_FLASH_WRITE_IDEAL_SIZE FLASH_WRITE_SIZE + +#define CONFIG_RAM_BASE 0x20000000 +#define CONFIG_RAM_SIZE 0x00020000 + +#define CONFIG_RO_MEM_OFF 0 +#define CONFIG_RO_SIZE (48 * 1024) +#define CONFIG_RW_MEM_OFF (64 * 1024) +#define CONFIG_RW_SIZE (64 * 1024) + +#define CONFIG_RO_STORAGE_OFF 0 +#define CONFIG_RW_STORAGE_OFF 0 + +#define CONFIG_EC_PROTECTED_STORAGE_OFF 0 +#define CONFIG_EC_PROTECTED_STORAGE_SIZE CONFIG_RW_MEM_OFF +#define CONFIG_EC_WRITABLE_STORAGE_OFF CONFIG_RW_MEM_OFF +#define CONFIG_EC_WRITABLE_STORAGE_SIZE \ + (CONFIG_FLASH_SIZE - CONFIG_EC_WRITABLE_STORAGE_OFF) + +#define CONFIG_WP_STORAGE_OFF CONFIG_EC_PROTECTED_STORAGE_OFF +#define CONFIG_WP_STORAGE_SIZE CONFIG_EC_PROTECTED_STORAGE_SIZE + +/* PSTATE lives in one of the smaller blocks. */ +#define CONFIG_FLASH_PSTATE +#define CONFIG_FW_PSTATE_SIZE (16 * 1024) +#define CONFIG_FW_PSTATE_OFF (CONFIG_RO_SIZE) + +#undef I2C_PORT_COUNT +#define I2C_PORT_COUNT 4 + + +/* Number of IRQ vectors on the NVIC */ +#define CONFIG_IRQ_COUNT 97 diff --git a/chip/stm32/config_chip.h b/chip/stm32/config_chip.h index 04041828af..b87d14931c 100644 --- a/chip/stm32/config_chip.h +++ b/chip/stm32/config_chip.h @@ -23,12 +23,17 @@ #define CHIP_VARIANT_STM32F03X #endif +/* Number of I2C ports, can be overridden in variant */ +#define I2C_PORT_COUNT 2 + #if defined(CHIP_VARIANT_STM32L476) #include "config-stm32l476.h" #elif defined(CHIP_VARIANT_STM32L15X) #include "config-stm32l15x.h" #elif defined(CHIP_VARIANT_STM32L100) #include "config-stm32l100.h" +#elif defined(CHIP_VARIANT_STM32F446) +#include "config-stm32f446.h" #elif defined(CHIP_VARIANT_STM32F373) #include "config-stm32f373.h" #elif defined(CHIP_VARIANT_STM32F09X) @@ -56,8 +61,10 @@ /* Program is run directly from storage */ #define CONFIG_MAPPED_STORAGE_BASE CONFIG_PROGRAM_MEMORY_BASE +#if !defined(CHIP_VARIANT_STM32F446) /* Compute the rest of the flash params from these */ #include "config_std_internal_flash.h" +#endif /* System stack size */ #if defined(CHIP_VARIANT_STM32F05X) @@ -85,9 +92,6 @@ #define HOOK_TICK_INTERVAL_MS 500 #define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC) -/* Number of I2C ports */ -#define I2C_PORT_COUNT 2 - /* * Use a timer to print a watchdog warning event before the actual watchdog * timer fires. This is needed on STM32, where the independent watchdog has no diff --git a/chip/stm32/dma-stm32f4.c b/chip/stm32/dma-stm32f4.c new file mode 100644 index 0000000000..135df53b1a --- /dev/null +++ b/chip/stm32/dma-stm32f4.c @@ -0,0 +1,308 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "common.h" +#include "console.h" +#include "dma.h" +#include "hooks.h" +#include "registers.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_DMA, outstr) +#define CPRINTF(format, args...) cprintf(CC_DMA, format, ## args) + +stm32_dma_regs_t *STM32_DMA_REGS[] = { STM32_DMA1_REGS, STM32_DMA2_REGS }; + +/* Callback data to use when IRQ fires */ +static struct { + void (*cb)(void *); /* Callback function to call */ + void *cb_data; /* Callback data for callback function */ +} dma_irq[STM32_DMAS_TOTAL_COUNT]; + +/** + * Return the IRQ for the DMA stream + * + * @param stream stream number + * @return IRQ for the stream + */ +static int dma_get_irq(enum dma_channel stream) +{ + if (stream < STM32_DMA1_STREAM6) + return STM32_IRQ_DMA1_STREAM0 + stream; + if (stream == STM32_DMA1_STREAM7) + return STM32_IRQ_DMA1_STREAM7; + if (stream < STM32_DMA2_STREAM5) + return STM32_IRQ_DMA2_STREAM0 + stream - STM32_DMA2_STREAM0; + else + return STM32_IRQ_DMA2_STREAM5 + stream - STM32_DMA2_STREAM5; +} + +stm32_dma_regs_t *dma_get_ctrl(enum dma_channel stream) +{ + return STM32_DMA_REGS[stream / STM32_DMAS_COUNT]; +} + +stm32_dma_stream_t *dma_get_channel(enum dma_channel stream) +{ + stm32_dma_regs_t *dma = dma_get_ctrl(stream); + + return &dma->stream[stream % STM32_DMAS_COUNT]; +} + +void dma_disable(enum dma_channel ch) +{ + stm32_dma_stream_t *stream = dma_get_channel(ch); + + if (stream->scr & STM32_DMA_CCR_EN) { + stream->scr &= ~STM32_DMA_CCR_EN; + while (stream->scr & STM32_DMA_CCR_EN) + ; + } +} + +void dma_disable_all(void) +{ + int ch; + + for (ch = 0; ch < STM32_DMAS_TOTAL_COUNT; ch++) + dma_disable(ch); +} + +/** + * Prepare a stream for use and start it + * + * @param stream stream to read + * @param count Number of bytes to transfer + * @param periph Pointer to peripheral data register + * @param memory Pointer to memory address for receive/transmit + * @param flags DMA flags for the control register. + */ +static void prepare_stream(enum dma_channel stream, unsigned count, + void *periph, void *memory, unsigned flags) +{ + stm32_dma_stream_t *dma_stream = dma_get_channel(stream); + uint32_t ccr = STM32_DMA_CCR_PL_VERY_HIGH; + + dma_disable(stream); + dma_clear_isr(stream); + + /* Following the order in DocID026448 Rev 1 (RM0383) p181 */ + dma_stream->spar = (uint32_t)periph; + dma_stream->sm0ar = (uint32_t)memory; + dma_stream->sndtr = count; + dma_stream->scr = ccr; + ccr |= flags & STM32_DMA_CCR_CHANNEL_MASK; + dma_stream->scr = ccr; + dma_stream->sfcr &= ~STM32_DMA_SFCR_DMDIS; + ccr |= flags; + dma_stream->scr = ccr; +} + +void dma_go(stm32_dma_stream_t *stream) +{ + /* Flush data in write buffer so that DMA can get the lastest data */ + asm volatile("dsb;"); + + /* Fire it up */ + stream->scr |= STM32_DMA_CCR_EN; +} + +void dma_prepare_tx(const struct dma_option *option, unsigned count, + const void *memory) +{ + /* + * Cast away const for memory pointer; this is ok because we know + * we're preparing the stream for transmit. + */ + prepare_stream(option->channel, count, option->periph, (void *)memory, + STM32_DMA_CCR_MINC | STM32_DMA_CCR_DIR_M2P | + option->flags); +} + +void dma_start_rx(const struct dma_option *option, unsigned count, + void *memory) +{ + stm32_dma_stream_t *stream = dma_get_channel(option->channel); + + prepare_stream(option->channel, count, option->periph, memory, + STM32_DMA_CCR_MINC | STM32_DMA_CCR_DIR_P2M | + option->flags); + dma_go(stream); +} + +int dma_bytes_done(stm32_dma_stream_t *stream, int orig_count) +{ + if (!(stream->scr & STM32_DMA_CCR_EN)) + return 0; + return orig_count - stream->sndtr; +} + +#ifdef CONFIG_DMA_HELP +void dma_dump(enum dma_channel stream) +{ + stm32_dma_stream_t *dma_stream = dma_get_channel(stream); + + CPRINTF("scr=%x, sndtr=%x, spar=%x, sm0ar=%x, sfcr=%x\n", + dma_stream->scr, dma_stream->sndtr, dma_stream->spar, + dma_stream->sm0ar, dma_stream->sfcr); + CPRINTF("stream %d, isr=%x, ifcr=%x\n", + stream, + STM32_DMA_GET_ISR(stream), + STM32_DMA_GET_IFCR(stream)); +} + +void dma_check(enum dma_channel stream, char *buf) +{ + stm32_dma_stream_t *dma_stream = dma_get_channel(stream); + int count; + int i; + + count = dma_stream->sndtr; + CPRINTF("c=%d\n", count); + udelay(100 * MSEC); + CPRINTF("c=%d\n", dma_stream->sndtr); + for (i = 0; i < count; i++) + CPRINTF("%02x ", buf[i]); + udelay(100 * MSEC); + CPRINTF("c=%d\n", dma_stream->sndtr); + for (i = 0; i < count; i++) + CPRINTF("%02x ", buf[i]); +} + +/* Run a check of memory-to-memory DMA */ +void dma_test(enum dma_channel stream) +{ + stm32_dma_stream_t *dma_stream = dma_get_channel(stream); + uint32_t ctrl; + char periph[32], memory[32]; + unsigned count = sizeof(periph); + int i; + + memset(memory, '\0', sizeof(memory)); + for (i = 0; i < count; i++) + periph[i] = 10 + i; + + dma_clear_isr(stream); + /* Following the order in Doc ID 15965 Rev 5 p194 */ + dma_stream->spar = (uint32_t)periph; + dma_stream->sm0ar = (uint32_t)memory; + dma_stream->sndtr = count; + dma_stream->sfcr &= ~STM32_DMA_SFCR_DMDIS; + ctrl = STM32_DMA_CCR_PL_MEDIUM; + dma_stream->scr = ctrl; + + ctrl |= STM32_DMA_CCR_MINC; + ctrl |= STM32_DMA_CCR_DIR_M2M; + ctrl |= STM32_DMA_CCR_PINC; + + dma_stream->scr = ctrl; + dma_dump(stream); + dma_stream->scr = ctrl | STM32_DMA_CCR_EN; + + for (i = 0; i < count; i++) + CPRINTF("%d/%d ", periph[i], memory[i]); + CPRINTF("\ncount=%d\n", dma_stream->sndtr); + dma_dump(stream); +} +#endif /* CONFIG_DMA_HELP */ + +void dma_init(void) +{ + STM32_RCC_AHB1ENR |= STM32_RCC_HB1_DMA1 | STM32_RCC_HB1_DMA2; +} + +int dma_wait(enum dma_channel stream) +{ + timestamp_t deadline; + + deadline.val = get_time().val + DMA_TRANSFER_TIMEOUT_US; + while ((STM32_DMA_GET_ISR(stream) & STM32_DMA_TCIF) == 0) { + if (deadline.val <= get_time().val) + return EC_ERROR_TIMEOUT; + + udelay(DMA_POLLING_INTERVAL_US); + } + return EC_SUCCESS; +} + +static inline void _dma_wake_callback(void *cb_data) +{ + task_id_t id = (task_id_t)(int)cb_data; + + if (id != TASK_ID_INVALID) + task_set_event(id, TASK_EVENT_DMA_TC, 0); +} + +void dma_enable_tc_interrupt(enum dma_channel stream) +{ + dma_enable_tc_interrupt_callback(stream, _dma_wake_callback, + (void *)(int)task_get_current()); +} + +void dma_enable_tc_interrupt_callback(enum dma_channel stream, + void (*callback)(void *), + void *callback_data) +{ + stm32_dma_stream_t *dma_stream = dma_get_channel(stream); + + dma_irq[stream].cb = callback; + dma_irq[stream].cb_data = callback_data; + + dma_stream->scr |= STM32_DMA_CCR_TCIE; + task_enable_irq(dma_get_irq(stream)); +} + +void dma_disable_tc_interrupt(enum dma_channel stream) +{ + stm32_dma_stream_t *dma_stream = dma_get_channel(stream); + + dma_stream->scr &= ~STM32_DMA_CCR_TCIE; + task_disable_irq(dma_get_irq(stream)); + + dma_irq[stream].cb = NULL; + dma_irq[stream].cb_data = NULL; +} + +void dma_clear_isr(enum dma_channel stream) +{ + STM32_DMA_SET_IFCR(stream, STM32_DMA_ALL); +} + +#ifdef CONFIG_DMA_DEFAULT_HANDLERS +#define STM32_DMA_IDX(dma, x) CONCAT4(STM32_DMA, dma, _STREAM, x) +#define STM32_DMA_FCT(dma, x) CONCAT4(dma_, dma, _event_interrupt_stream_, x) +#define DECLARE_DMA_IRQ(dma, x) \ + void STM32_DMA_FCT(dma, x)(void) \ + { \ + dma_clear_isr(STM32_DMA_IDX(dma, x)); \ + if (dma_irq[STM32_DMA_IDX(dma, x)].cb != NULL) \ + (*dma_irq[STM32_DMA_IDX(dma, x)].cb) \ + (dma_irq[STM32_DMA_IDX(dma, x)].cb_data); \ + } \ + DECLARE_IRQ(CONCAT4(STM32_IRQ_DMA, dma, _STREAM, x), \ + STM32_DMA_FCT(dma, x), 1); + +DECLARE_DMA_IRQ(1, 0); +DECLARE_DMA_IRQ(1, 1); +DECLARE_DMA_IRQ(1, 2); +DECLARE_DMA_IRQ(1, 3); +DECLARE_DMA_IRQ(1, 4); +DECLARE_DMA_IRQ(1, 5); +DECLARE_DMA_IRQ(1, 6); +DECLARE_DMA_IRQ(1, 7); +DECLARE_DMA_IRQ(2, 0); +DECLARE_DMA_IRQ(2, 1); +DECLARE_DMA_IRQ(2, 2); +DECLARE_DMA_IRQ(2, 3); +DECLARE_DMA_IRQ(2, 4); +DECLARE_DMA_IRQ(2, 5); +DECLARE_DMA_IRQ(2, 6); +DECLARE_DMA_IRQ(2, 7); + +#endif /* CONFIG_DMA_DEFAULT_HANDLERS */ + diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c index a3cc6d6de4..74bc0bd957 100644 --- a/chip/stm32/dma.c +++ b/chip/stm32/dma.c @@ -73,6 +73,20 @@ void dma_select_channel(enum dma_channel channel, unsigned char stream) val = STM32_DMA_CSELR(channel) & ~(mask << ch * shift); STM32_DMA_CSELR(channel) = val | (stream << ch * shift); } +#elif defined(CHIP_FAMILY_STM32F4) +void dma_select_channel(enum dma_channel channel, unsigned char stream) +{ + stm32_dma_chan_t *chan = dma_get_channel(channel); + uint32_t val; + + ASSERT(channel < STM32_DMAC_COUNT); + ASSERT(stream < STM32_DMA_MAX_STREAMS); + + /* Set stream input for channel */ + val = chan->ccr & + ~(STM32_DMA_CCR_CHMASK << STM32_DMA_CCR_CHOFF); + chan->ccr = val | (stream << STM32_DMA_CCR_CHOFF); +} #endif void dma_disable(enum dma_channel channel) @@ -230,7 +244,7 @@ void dma_test(enum dma_channel channel) void dma_init(void) { -#ifdef CHIP_FAMILY_STM32L4 +#if defined(CHIP_FAMILY_STM32L4) || defined(CHIP_FAMILY_STM32F4) STM32_RCC_AHB1ENR |= STM32_RCC_AHB1ENR_DMA1EN|STM32_RCC_AHB1ENR_DMA2EN; #else STM32_RCC_AHBENR |= STM32_RCC_HB_DMA1; @@ -244,6 +258,19 @@ void dma_init(void) int dma_wait(enum dma_channel channel) { +#if defined(CHIP_FAMILY_STM32F4) + timestamp_t deadline; + + deadline.val = get_time().val + DMA_TRANSFER_TIMEOUT_US; + + /* Wait for TCIF completion */ + while ((STM32_DMA_GET_ISR(channel) & STM32_DMA_TCIF) == 0) { + if (deadline.val <= get_time().val) + return EC_ERROR_TIMEOUT; + + udelay(DMA_POLLING_INTERVAL_US); + } +#else stm32_dma_regs_t *dma = STM32_DMA_REGS(channel); const uint32_t mask = STM32_DMA_ISR_TCIF(channel); timestamp_t deadline; @@ -255,6 +282,7 @@ int dma_wait(enum dma_channel channel) udelay(DMA_POLLING_INTERVAL_US); } +#endif return EC_SUCCESS; } @@ -297,9 +325,13 @@ void dma_disable_tc_interrupt(enum dma_channel channel) void dma_clear_isr(enum dma_channel channel) { +#if defined(CHIP_FAMILY_STM32F4) + STM32_DMA_SET_IFCR(channel, STM32_DMA_ALL); +#else stm32_dma_regs_t *dma = STM32_DMA_REGS(channel); dma->ifcr |= STM32_DMA_ISR_ALL(channel); +#endif } #ifdef CONFIG_DMA_DEFAULT_HANDLERS diff --git a/chip/stm32/flash-f.c b/chip/stm32/flash-f.c index c57f072fc2..09a52ded2e 100644 --- a/chip/stm32/flash-f.c +++ b/chip/stm32/flash-f.c @@ -7,6 +7,7 @@ #include "battery.h" #include "console.h" +#include "clock.h" #include "flash.h" #include "hooks.h" #include "registers.h" @@ -25,8 +26,6 @@ /* Flash page programming timeout. This is 2x the datasheet max. */ #define FLASH_TIMEOUT_US 16000 -#define FLASH_TIMEOUT_LOOP \ - (FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP) /* Flash unlocking keys */ #define KEY1 0x45670123 @@ -44,9 +43,15 @@ static int write_optb(int byte, uint8_t value); +static inline int calculate_flash_timeout(void) +{ + return (FLASH_TIMEOUT_US * + (clock_get_freq() / SECOND) / CYCLE_PER_FLASH_LOOP); +} + static int wait_busy(void) { - int timeout = FLASH_TIMEOUT_LOOP; + int timeout = calculate_flash_timeout(); while (STM32_FLASH_SR & (1 << 0) && timeout-- > 0) udelay(CYCLE_PER_FLASH_LOOP); return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT; @@ -207,6 +212,7 @@ int flash_physical_write(int offset, int size, const char *data) { uint16_t *address = (uint16_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset); int res = EC_SUCCESS; + int timeout = calculate_flash_timeout(); int i; if (unlock(PRG_LOCK) != EC_SUCCESS) { @@ -228,7 +234,7 @@ int flash_physical_write(int offset, int size, const char *data) watchdog_reload(); /* wait to be ready */ - for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); + for (i = 0; (STM32_FLASH_SR & 1) && (i < timeout); i++) ; @@ -237,7 +243,7 @@ int flash_physical_write(int offset, int size, const char *data) data += 2; /* Wait for writes to complete */ - for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); + for (i = 0; (STM32_FLASH_SR & 1) && (i < timeout); i++) ; diff --git a/chip/stm32/flash-stm32f4.c b/chip/stm32/flash-stm32f4.c new file mode 100644 index 0000000000..48815d6956 --- /dev/null +++ b/chip/stm32/flash-stm32f4.c @@ -0,0 +1,384 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Flash memory module for stm32f4 */ + +#include "clock.h" +#include "compile_time_macros.h" +#include "console.h" +#include "common.h" +#include "flash.h" +#include "hooks.h" +#include "registers.h" +#include "system.h" +#include "panic.h" +#include "watchdog.h" + + +#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args) + +/* + * Approximate number of CPU cycles per iteration of the loop when polling + * the flash status + */ +#define CYCLE_PER_FLASH_LOOP 10 + +/* Flash page programming timeout. This is 2x the datasheet max. */ +#define FLASH_TIMEOUT_US 16000 + +static inline int calculate_flash_timeout(void) +{ + return (FLASH_TIMEOUT_US * + (clock_get_freq() / SECOND) / CYCLE_PER_FLASH_LOOP); +} + + +/* Flag indicating whether we have locked down entire flash */ +static int entire_flash_locked; + +#define FLASH_SYSJUMP_TAG 0x5750 /* "WP" - Write Protect */ +#define FLASH_HOOK_VERSION 1 +/* The previous write protect state before sys jump */ +struct flash_wp_state { + int entire_flash_locked; +}; + +/*****************************************************************************/ +/* Physical layer APIs */ + +/* Flash unlocking keys */ +#define PRG_LOCK 0 +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +static int unlock(void) +{ + /* + * We may have already locked the flash module and get a bus fault + * in the attempt to unlock. Need to disable bus fault handler now. + */ + ignore_bus_fault(1); + + /* unlock CR if needed */ + if (STM32_FLASH_CR & FLASH_CR_LOCK) { + STM32_FLASH_KEYR = KEY1; + STM32_FLASH_KEYR = KEY2; + } + + /* Re-enable bus fault handler */ + ignore_bus_fault(0); + + return (STM32_FLASH_CR & FLASH_CR_LOCK) ? + EC_ERROR_UNKNOWN : EC_SUCCESS; +} + +static void lock(void) +{ + STM32_FLASH_CR = FLASH_CR_LOCK; +} + + +int flash_physical_get_protect(int block) +{ + /* TODO: not sure if write protect can be implemented like this. */ + return 0; +} + +uint32_t flash_physical_get_protect_flags(void) +{ + return entire_flash_locked ? EC_FLASH_PROTECT_ALL_NOW : 0; +} + +int flash_physical_protect_now(int all) +{ + if (all) { + /* + * Lock by writing a wrong key to FLASH_KEYR. This triggers a + * bus fault, so we need to disable bus fault handler while + * doing this. + * + * This incorrect key fault causes the flash to become + * permanenlty locked until reset, a correct keyring write + * will not unlock it. In this way we can implement system + * write protect. + */ + ignore_bus_fault(1); + STM32_FLASH_KEYR = 0xffffffff; + ignore_bus_fault(0); + + entire_flash_locked = 1; + + /* Check if lock happened */ + if (STM32_FLASH_CR & FLASH_CR_LOCK) + return EC_SUCCESS; + } + + /* No way to protect just the RO flash until next boot */ + return EC_ERROR_INVAL; +} + +uint32_t flash_physical_get_valid_flags(void) +{ + return EC_FLASH_PROTECT_RO_AT_BOOT | + EC_FLASH_PROTECT_RO_NOW | + EC_FLASH_PROTECT_ALL_NOW; +} + +uint32_t flash_physical_get_writable_flags(uint32_t cur_flags) +{ + uint32_t ret = 0; + + /* If RO protection isn't enabled, its at-boot state can be changed. */ + if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW)) + ret |= EC_FLASH_PROTECT_RO_AT_BOOT; + + /* + * If entire flash isn't protected at this boot, it can be enabled if + * the WP GPIO is asserted. + */ + if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) && + (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED)) + ret |= EC_FLASH_PROTECT_ALL_NOW; + + return ret; +} + +int flash_physical_restore_state(void) +{ + uint32_t reset_flags = system_get_reset_flags(); + int version, size; + const struct flash_wp_state *prev; + + /* + * If we have already jumped between images, an earlier image could + * have applied write protection. Nothing additional needs to be done. + */ + if (reset_flags & RESET_FLAG_SYSJUMP) { + prev = (const struct flash_wp_state *)system_get_jump_tag( + FLASH_SYSJUMP_TAG, &version, &size); + if (prev && version == FLASH_HOOK_VERSION && + size == sizeof(*prev)) + entire_flash_locked = prev->entire_flash_locked; + return 1; + } + + return 0; +} + +static int flash_idle(void) +{ + timestamp_t deadline; + + deadline.val = get_time().val + FLASH_TIMEOUT_US; + /* Wait for flash op to complete. + * This function is used for both reads and writes, so + * we need a long timeout, but a relatively short poll interval. + */ + while ((STM32_FLASH_SR & FLASH_SR_BUSY) && + (get_time().val < deadline.val)) { + usleep(1); + } + + if (STM32_FLASH_SR & FLASH_SR_BUSY) + return EC_ERROR_TIMEOUT; + + return EC_SUCCESS; +} + +static void clear_flash_errors(void) +{ + /* Clear previous error status */ + STM32_FLASH_SR = FLASH_SR_ERR_MASK; +} + +/*****************************************************************************/ +/* Physical layer APIs */ + +int flash_physical_protect_at_boot(enum flash_wp_range range) +{ + return EC_SUCCESS; +} + +int flash_physical_write(int offset, int size, const char *data) +{ + uint32_t *address = (uint32_t *)(CONFIG_MAPPED_STORAGE_BASE + offset); + int res = EC_SUCCESS; + + if (unlock() != EC_SUCCESS) { + res = EC_ERROR_UNKNOWN; + goto exit_wr; + } + + /* Wait for busy to clear */ + res = flash_idle(); + if (res) + goto exit_wr; + clear_flash_errors(); + + /* set PG bit */ + STM32_FLASH_CR &= ~FLASH_CR_PSIZE_MASK; + STM32_FLASH_CR |= FLASH_CR_PSIZE(FLASH_CR_PSIZE_32); + STM32_FLASH_CR |= FLASH_CR_PG; + + for (; size > 0; size -= sizeof(uint32_t)) { + /* + * Reload the watchdog timer to avoid watchdog reset when doing + * long writing with interrupt disabled. + */ + watchdog_reload(); + + res = flash_idle(); + if (res) + goto exit_wr; + + /* write the word */ + *address = data[0] + (data[1] << 8) + + (data[2] << 16) + (data[3] << 24); + + address++; + data += sizeof(uint32_t); + + res = flash_idle(); + if (res) + goto exit_wr; + + if (STM32_FLASH_SR & FLASH_SR_BUSY) { + res = EC_ERROR_TIMEOUT; + goto exit_wr; + } + + /* Check for error conditions - erase failed, voltage error, + * protection error. + */ + if (STM32_FLASH_SR & FLASH_SR_ERR_MASK) { + res = EC_ERROR_UNKNOWN; + goto exit_wr; + } + } + +exit_wr: + /* Disable PG bit */ + STM32_FLASH_CR &= ~FLASH_CR_PG; + + lock(); + + return res; +} + + + +/* "@Internal Flash /0x08000000/04*016Kg,01*064Kg,03*128Kg" */ +struct flash_sector { + int base; + int size; +}; +static const struct flash_sector sectors[] = { + {(0 * 1024), (16 * 1024)}, + {(16 * 1024), (16 * 1024)}, + {(32 * 1024), (16 * 1024)}, + {(48 * 1024), (16 * 1024)}, + {(64 * 1024), (64 * 1024)}, + {(128 * 1024), (128 * 1024)}, + {(256 * 1024), (128 * 1024)}, + {(384 * 1024), (128 * 1024)} +}; +static const int num_sectors = ARRAY_SIZE(sectors); + +int flash_physical_erase(int offset, int size) +{ + int res = EC_SUCCESS; + int start_sector; + int end_sector; + + /* Check that offset/size align with sectors. */ + for (start_sector = 0; start_sector < num_sectors; start_sector++) + if (offset == sectors[start_sector].base) + break; + for (end_sector = start_sector; end_sector < num_sectors; end_sector++) + if ((offset + size) == + (sectors[end_sector].base + sectors[end_sector].size)) + break; + + /* We can only erase on sector boundaries. */ + if ((start_sector >= num_sectors) || (end_sector >= num_sectors)) + return EC_ERROR_PARAM1; + + if (unlock() != EC_SUCCESS) + return EC_ERROR_UNKNOWN; + + res = flash_idle(); + if (res) + goto exit_er; + + clear_flash_errors(); + + for (; start_sector <= end_sector; start_sector++) { + /* Do nothing if already erased */ + if (flash_is_erased(sectors[start_sector].base, + sectors[start_sector].size)) + continue; + + res = flash_idle(); + if (res) + goto exit_er; + + /* set Sector Erase bit and select sector */ + STM32_FLASH_CR = (STM32_FLASH_CR & ~FLASH_CR_SNB_MASK) | + FLASH_CR_SER | FLASH_CR_SNB(start_sector); + + /* set STRT bit : start erase */ + STM32_FLASH_CR |= FLASH_CR_STRT; + + /* + * Reload the watchdog timer to avoid watchdog reset during a + * long erase operation. + */ + watchdog_reload(); + + /* Wait for erase to complete, this will be awhile */ + res = flash_idle(); + if (res) + goto exit_er; + /* + * Check for error conditions - erase failed, voltage error, + * protection error + */ + if (STM32_FLASH_SR & FLASH_SR_ERR_MASK) { + res = EC_ERROR_UNKNOWN; + goto exit_er; + } + } + +exit_er: + /* reset PER bit */ + STM32_FLASH_CR &= ~FLASH_CR_SER; + + lock(); + + return res; +} + +/*****************************************************************************/ +/* High-level APIs */ + +int flash_pre_init(void) +{ + return EC_SUCCESS; +} + +/*****************************************************************************/ +/* Hooks */ + +static void flash_preserve_state(void) +{ + struct flash_wp_state state; + + state.entire_flash_locked = entire_flash_locked; + + system_add_jump_tag(FLASH_SYSJUMP_TAG, FLASH_HOOK_VERSION, + sizeof(state), &state); +} +DECLARE_HOOK(HOOK_SYSJUMP, flash_preserve_state, HOOK_PRIO_DEFAULT); + diff --git a/chip/stm32/gpio-stm32f4.c b/chip/stm32/gpio-stm32f4.c new file mode 100644 index 0000000000..e456a1920a --- /dev/null +++ b/chip/stm32/gpio-stm32f4.c @@ -0,0 +1,26 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* GPIO module for Chrome EC */ + +#include "clock.h" +#include "common.h" +#include "registers.h" + +void gpio_enable_clocks(void) +{ + /* + * Enable all GPIOs clocks + * + * TODO(crosbug.com/p/23770): only enable the banks we need to, + * and support disabling some of them in low-power idle. + */ + STM32_RCC_AHB1ENR |= STM32_RCC_AHB1ENR_GPIOMASK; + + /* Delay 1 AHB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_AHB, 1); +} + +#include "gpio-f0-l.c" diff --git a/chip/stm32/gpio.c b/chip/stm32/gpio.c index 3a5f6265c2..a2ea8fad94 100644 --- a/chip/stm32/gpio.c +++ b/chip/stm32/gpio.c @@ -27,7 +27,7 @@ void gpio_pre_init(void) int i; /* Required to configure external IRQ lines (SYSCFG_EXTICRn) */ - STM32_RCC_APB2ENR |= 1 << 0; + STM32_RCC_APB2ENR |= STM32_RCC_SYSCFGEN; /* Delay 1 APB clock cycle after the clock is enabled */ clock_wait_bus_cycles(BUS_APB, 1); diff --git a/chip/stm32/jtag-stm32f4.c b/chip/stm32/jtag-stm32f4.c new file mode 100644 index 0000000000..fb6431214d --- /dev/null +++ b/chip/stm32/jtag-stm32f4.c @@ -0,0 +1,17 @@ +/* Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +/* Settings to enable JTAG debugging */ + +#include "jtag.h" +#include "registers.h" + +void jtag_pre_init(void) +{ + /* + * Stop all timers we might use (TIM1-8) and watchdogs when + * the JTAG stops the CPU. + */ + /* TODO(nsanders): Implement this if someone needs jtag. */ +} diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 9007b45134..f49b91b26a 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -121,6 +121,8 @@ #define STM32_IRQ_TIM14 45 /* STM32F373 only */ #define STM32_IRQ_TIM5 50 /* STM32F373 */ #define STM32_IRQ_SPI3 51 /* STM32F373 */ +#define STM32_IRQ_USART4 52 /* STM32F446 only */ +#define STM32_IRQ_USART5 53 /* STM32F446 only */ #define STM32_IRQ_TIM6_DAC 54 /* STM32F373 */ #define STM32_IRQ_TIM7 55 /* STM32F373 */ #define STM32_IRQ_DMA2_CHANNEL1 56 /* STM32F373 */ @@ -136,6 +138,9 @@ #define STM32_IRQ_DMA2_CHANNEL7 69 /* STM32L4 only */ #define STM32_IRQ_LPUART 70 /* STM32L4 only */ #define STM32_IRQ_USART9 70 /* STM32L4 only */ +#define STM32_IRQ_USART6 71 /* STM32F446 only */ +#define STM32_IRQ_I2C3_EV 72 /* STM32F446 only */ +#define STM32_IRQ_I2C3_ER 73 /* STM32F446 only */ #define STM32_IRQ_USB_WAKEUP 76 /* STM32F373 only */ #define STM32_IRQ_TIM19 78 /* STM32F373 only */ #define STM32_IRQ_FPU 81 /* STM32F373 only */ @@ -149,16 +154,57 @@ /* aliases for easier code sharing */ #define STM32_IRQ_I2C1 STM32_IRQ_I2C1_EV #define STM32_IRQ_I2C2 STM32_IRQ_I2C2_EV +#define STM32_IRQ_I2C3 STM32_IRQ_I2C3_EV #endif /* !CHIP_FAMILY_STM32F0 */ +#ifdef CHIP_FAMILY_STM32F4 +/* + * STM32F4 introduces a concept of DMA stream to allow + * fine allocation of a stream to a channel. + */ +#define STM32_IRQ_DMA1_STREAM0 11 +#define STM32_IRQ_DMA1_STREAM1 12 +#define STM32_IRQ_DMA1_STREAM2 13 +#define STM32_IRQ_DMA1_STREAM3 14 +#define STM32_IRQ_DMA1_STREAM4 15 +#define STM32_IRQ_DMA1_STREAM5 16 +#define STM32_IRQ_DMA1_STREAM6 17 +#define STM32_IRQ_DMA1_STREAM7 47 +#define STM32_IRQ_DMA2_STREAM0 56 +#define STM32_IRQ_DMA2_STREAM1 57 +#define STM32_IRQ_DMA2_STREAM2 58 +#define STM32_IRQ_DMA2_STREAM3 59 +#define STM32_IRQ_DMA2_STREAM4 60 +#define STM32_IRQ_DMA2_STREAM5 68 +#define STM32_IRQ_DMA2_STREAM6 69 +#define STM32_IRQ_DMA2_STREAM7 70 + +#define STM32_IRQ_OTG_HS_WKUP 76 +#define STM32_IRQ_OTG_HS_EP1_IN 75 +#define STM32_IRQ_OTG_HS_EP1_OUT 74 +#define STM32_IRQ_OTG_HS 77 +#define STM32_IRQ_OTG_FS 67 +#define STM32_IRQ_OTG_FS_WKUP 42 + +#endif + #ifndef __ASSEMBLER__ /* --- USART --- */ +#if defined(CHIP_FAMILY_STM32F4) +#define STM32_USART1_BASE 0x40011000 +#define STM32_USART2_BASE 0x40004400 +#define STM32_USART3_BASE 0x40004800 +#define STM32_USART4_BASE 0x40004c00 +#define STM32_USART5_BASE 0x40005000 +#define STM32_USART6_BASE 0x40011400 +#else #define STM32_USART1_BASE 0x40013800 #define STM32_USART2_BASE 0x40004400 #define STM32_USART3_BASE 0x40004800 #define STM32_USART4_BASE 0x40004c00 #define STM32_USART9_BASE 0x40008000 /* LPUART */ +#endif #define STM32_USART_BASE(n) CONCAT3(STM32_USART, n, _BASE) #define STM32_USART_REG(base, offset) REG32((base) + (offset)) @@ -218,6 +264,7 @@ #define STM32_USART_CR1_OVER8 (1 << 15) /* STM32L only */ #define STM32_USART_CR2(base) STM32_USART_REG(base, 0x10) #define STM32_USART_CR3(base) STM32_USART_REG(base, 0x14) +#define STM32_USART_CR3_EIE (1 << 0) #define STM32_USART_CR3_DMAR (1 << 6) #define STM32_USART_CR3_DMAT (1 << 7) #define STM32_USART_CR3_ONEBIT (1 << 11) /* STM32L only */ @@ -403,6 +450,28 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define GPIO_ALT_FE 0xE #define GPIO_ALT_FF 0xF +#elif defined(CHIP_FAMILY_STM32F4) + +#define STM32_GPIOA_BASE 0x40020000 +#define STM32_GPIOB_BASE 0x40020400 +#define STM32_GPIOC_BASE 0x40020800 +#define STM32_GPIOD_BASE 0x40020C00 +#define STM32_GPIOE_BASE 0x40021000 +#define STM32_GPIOF_BASE 0x40021400 +#define STM32_GPIOG_BASE 0x40021800 +#define STM32_GPIOH_BASE 0x40021C00 + +#define STM32_GPIO_MODER(b) REG32((b) + 0x00) +#define STM32_GPIO_OTYPER(b) REG16((b) + 0x04) +#define STM32_GPIO_OSPEEDR(b) REG32((b) + 0x08) +#define STM32_GPIO_PUPDR(b) REG32((b) + 0x0C) +#define STM32_GPIO_IDR(b) REG16((b) + 0x10) +#define STM32_GPIO_ODR(b) REG16((b) + 0x14) +#define STM32_GPIO_BSRR(b) REG32((b) + 0x18) +#define STM32_GPIO_LCKR(b) REG32((b) + 0x1C) +#define STM32_GPIO_AFRL(b) REG32((b) + 0x20) +#define STM32_GPIO_AFRH(b) REG32((b) + 0x24) + #else #error Unsupported chip variant #endif @@ -410,9 +479,13 @@ typedef volatile struct timer_ctlr timer_ctlr_t; /* --- I2C --- */ #define STM32_I2C1_BASE 0x40005400 #define STM32_I2C2_BASE 0x40005800 +#define STM32_I2C3_BASE 0x40005C00 +#define STM32_I2C4_BASE 0x40006000 #define STM32_I2C1_PORT 0 #define STM32_I2C2_PORT 1 +#define STM32_I2C3_PORT 2 +#define STM32_FMPI2C4_PORT 3 #define stm32_i2c_reg(port, offset) \ ((uint16_t *)((STM32_I2C1_BASE + ((port) * 0x400)) + (offset))) @@ -477,6 +550,8 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_I2C_CR1_POS (1 << 11) #define STM32_I2C_CR1_SWRST (1 << 15) #define STM32_I2C_CR2(n) REG16(stm32_i2c_reg(n, 0x04)) +#define STM32_I2C_CR2_LAST (1 << 12) +#define STM32_I2C_CR2_DMAEN (1 << 11) #define STM32_I2C_OAR1(n) REG16(stm32_i2c_reg(n, 0x08)) #define STM32_I2C_OAR2(n) REG16(stm32_i2c_reg(n, 0x0C)) #define STM32_I2C_DR(n) REG16(stm32_i2c_reg(n, 0x10)) @@ -494,9 +569,58 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_I2C_SR2_BUSY (1 << 1) #define STM32_I2C_CCR(n) REG16(stm32_i2c_reg(n, 0x1C)) +#define STM32_I2C_CCR_DUTY (1 << 14) +#define STM32_I2C_CCR_FM (1 << 15) #define STM32_I2C_TRISE(n) REG16(stm32_i2c_reg(n, 0x20)) #endif /* !CHIP_FAMILY_STM32F0 && !CHIP_FAMILY_STM32F3 */ + +#if defined(CHIP_FAMILY_STM32F4) +#define STM32_FMPI2C_CR1(n) REG32(stm32_i2c_reg(n, 0x00)) +#define FMPI2C_CR1_PE (1 << 0) +#define FMPI2C_CR1_TXDMAEN (1 << 14) +#define FMPI2C_CR1_RXDMAEN (1 << 15) +#define STM32_FMPI2C_CR2(n) REG32(stm32_i2c_reg(n, 0x04)) +#define FMPI2C_CR2_RD_WRN (1 << 10) +#define FMPI2C_READ 1 +#define FMPI2C_WRITE 0 +#define FMPI2C_CR2_START (1 << 13) +#define FMPI2C_CR2_STOP (1 << 14) +#define FMPI2C_CR2_NACK (1 << 15) +#define FMPI2C_CR2_RELOAD (1 << 24) +#define FMPI2C_CR2_AUTOEND (1 << 25) +#define FMPI2C_CR2_SADD(addr) ((addr) & 0x3ff) +#define FMPI2C_CR2_SADD_MASK FMPI2C_CR2_SADD(0x3ff) +#define FMPI2C_CR2_SIZE(size) (((size) & 0xff) << 16) +#define FMPI2C_CR2_SIZE_MASK FMPI2C_CR2_SIZE(0xf) +#define STM32_FMPI2C_OAR1(n) REG32(stm32_i2c_reg(n, 0x08)) +#define STM32_FMPI2C_OAR2(n) REG32(stm32_i2c_reg(n, 0x0C)) +#define STM32_FMPI2C_TIMINGR(n) REG32(stm32_i2c_reg(n, 0x10)) +#define TIMINGR_THE_RIGHT_VALUE 0xC0000E12 +#define FMPI2C_TIMINGR_PRESC(val) (((val) & 0xf) << 28) +#define FMPI2C_TIMINGR_SCLDEL(val) (((val) & 0xf) << 20) +#define FMPI2C_TIMINGR_SDADEL(val) (((val) & 0xf) << 16) +#define FMPI2C_TIMINGR_SCLH(val) (((val) & 0xff) << 8) +#define FMPI2C_TIMINGR_SCLL(val) (((val) & 0xff) << 0) +#define STM32_FMPI2C_TIMEOUTR(n) REG32(stm32_i2c_reg(n, 0x14)) + +#define STM32_FMPI2C_ISR(n) REG32(stm32_i2c_reg(n, 0x18)) +#define FMPI2C_ISR_TXE (1 << 0) +#define FMPI2C_ISR_TXIS (1 << 1) +#define FMPI2C_ISR_RXNE (1 << 2) +#define FMPI2C_ISR_ADDR (1 << 3) +#define FMPI2C_ISR_NACKF (1 << 4) +#define FMPI2C_ISR_STOPF (1 << 5) +#define FMPI2C_ISR_BERR (1 << 8) +#define FMPI2C_ISR_ARLO (1 << 9) +#define FMPI2C_ISR_BUSY (1 << 15) +#define STM32_FMPI2C_ICR(n) REG32(stm32_i2c_reg(n, 0x1C)) + +#define STM32_FMPI2C_PECR(n) REG32(stm32_i2c_reg(n, 0x20)) +#define STM32_FMPI2C_RXDR(n) REG32(stm32_i2c_reg(n, 0x24)) +#define STM32_FMPI2C_TXDR(n) REG32(stm32_i2c_reg(n, 0x28)) +#endif + /* --- Power / Reset / Clocks --- */ #define STM32_PWR_BASE 0x40007000 @@ -551,7 +675,11 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_RCC_APB1RSTR REG32(STM32_RCC_BASE + 0x18) #define STM32_RCC_AHBENR REG32(STM32_RCC_BASE + 0x1C) #define STM32_RCC_APB2ENR REG32(STM32_RCC_BASE + 0x20) +#define STM32_RCC_SYSCFGEN (1 << 0) + #define STM32_RCC_APB1ENR REG32(STM32_RCC_BASE + 0x24) +#define STM32_RCC_PWREN (1 << 28) + #define STM32_RCC_AHBLPENR REG32(STM32_RCC_BASE + 0x28) #define STM32_RCC_APB2LPENR REG32(STM32_RCC_BASE + 0x2C) #define STM32_RCC_APB1LPENR REG32(STM32_RCC_BASE + 0x30) @@ -624,10 +752,13 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_RCC_AHB2ENR_GPIOMASK (0xff << 0) #define STM32_RCC_APB1ENR REG32(STM32_RCC_BASE + 0x58) +#define STM32_RCC_PWREN (1 << 28) + #define STM32_RCC_APB1ENR2 REG32(STM32_RCC_BASE + 0x5C) #define STM32_RCC_APB1ENR2_LPUART1EN (1 << 0) #define STM32_RCC_APB2ENR REG32(STM32_RCC_BASE + 0x60) +#define STM32_RCC_SYSCFGEN (1 << 0) #define STM32_RCC_CCIPR REG32(STM32_RCC_BASE + 0x88) #define STM32_RCC_CCIPR_PCLK 0 @@ -659,7 +790,11 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_RCC_APB1RSTR REG32(STM32_RCC_BASE + 0x10) #define STM32_RCC_AHBENR REG32(STM32_RCC_BASE + 0x14) #define STM32_RCC_APB2ENR REG32(STM32_RCC_BASE + 0x18) +#define STM32_RCC_SYSCFGEN (1 << 0) + #define STM32_RCC_APB1ENR REG32(STM32_RCC_BASE + 0x1c) +#define STM32_RCC_PWREN (1 << 28) + #define STM32_RCC_BDCR REG32(STM32_RCC_BASE + 0x20) #define STM32_RCC_CSR REG32(STM32_RCC_BASE + 0x24) /* STM32F373 */ @@ -690,6 +825,142 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_SYSCFG_EXTICR(n) REG32(STM32_SYSCFG_BASE + 8 + 4 * (n)) #define STM32_SYSCFG_CFGR2 REG32(STM32_SYSCFG_BASE + 0x18) +#elif defined(CHIP_FAMILY_STM32F4) +#define STM32_RCC_BASE 0x40023800 + +#define STM32_RCC_CR REG32(STM32_RCC_BASE + 0x00) +#define STM32_RCC_CR_HSION (1 << 0) +#define STM32_RCC_CR_HSIRDY (1 << 1) +#define STM32_RCC_CR_HSEON (1 << 16) +#define STM32_RCC_CR_HSERDY (1 << 17) +#define STM32_RCC_CR_PLLON (1 << 24) +#define STM32_RCC_CR_PLLRDY (1 << 25) + +/* Required or recommended clocks for stm32f446 */ +#define STM32F4_PLL_REQ 2000000 +#define STM32F4_RTC_REQ 1000000 +#define STM32F4_IO_CLOCK 42000000 +#define STM32F4_USB_REQ 48000000 +#define STM32F4_VCO_CLOCK 336000000 +#define STM32F4_HSI_CLOCK 16000000 +#define STM32F4_LSI_CLOCK 32000 + +#define STM32_RCC_PLLCFGR REG32(STM32_RCC_BASE + 0x04) +/* PLL Division factor */ +#define PLLCFGR_PLLM_OFF 0 +#define PLLCFGR_PLLM(val) (((val) & 0x1f) << PLLCFGR_PLLM_OFF) +/* PLL Multiplication factor */ +#define PLLCFGR_PLLN_OFF 6 +#define PLLCFGR_PLLN(val) (((val) & 0x1ff) << PLLCFGR_PLLN_OFF) +/* Main CPU Clock */ +#define PLLCFGR_PLLP_OFF 16 +#define PLLCFGR_PLLP(val) (((val) & 0x3) << PLLCFGR_PLLP_OFF) + +#define PLLCFGR_PLLSRC_HSI (0 << 22) +#define PLLCFGR_PLLSRC_HSE (1 << 22) +/* USB OTG FS: Must equal 48MHz */ +#define PLLCFGR_PLLQ_OFF 24 +#define PLLCFGR_PLLQ(val) (((val) & 0xf) << PLLCFGR_PLLQ_OFF) +/* SYSTEM */ +#define PLLCFGR_PLLR_OFF 28 +#define PLLCFGR_PLLR(val) (((val) & 0x7) << PLLCFGR_PLLR_OFF) + +#define STM32_RCC_CFGR REG32(STM32_RCC_BASE + 0x08) +#define STM32_RCC_CFGR_SW_HSI (0 << 0) +#define STM32_RCC_CFGR_SW_HSE (1 << 0) +#define STM32_RCC_CFGR_SW_PLL (2 << 0) +#define STM32_RCC_CFGR_SW_PLL_R (3 << 0) +#define STM32_RCC_CFGR_SW_MASK (3 << 0) +#define STM32_RCC_CFGR_SWS_HSI (0 << 2) +#define STM32_RCC_CFGR_SWS_HSE (1 << 2) +#define STM32_RCC_CFGR_SWS_PLL (2 << 2) +#define STM32_RCC_CFGR_SWS_PLL_R (3 << 2) +#define STM32_RCC_CFGR_SWS_MASK (3 << 2) +/* AHB Prescalar: nonlinear values, look up in RM0390 */ +#define CFGR_HPRE_OFF 4 +#define CFGR_HPRE(val) (((val) & 0xf) << CFGR_HPRE_OFF) +/* APB1 Low Speed Prescalar < 45MHz */ +#define CFGR_PPRE1_OFF 10 +#define CFGR_PPRE1(val) (((val) & 0x7) << CFGR_PPRE1_OFF) +/* APB2 High Speed Prescalar < 90MHz */ +#define CFGR_PPRE2_OFF 13 +#define CFGR_PPRE2(val) (((val) & 0x7) << CFGR_PPRE2_OFF) +/* RTC CLock: Must equal 1MHz */ +#define CFGR_RTCPRE_OFF 16 +#define CFGR_RTCPRE(val) (((val) & 0x1f) << CFGR_RTCPRE_OFF) + +#define STM32_RCC_CIR REG32(STM32_RCC_BASE + 0x0C) +#define STM32_RCC_AHB1RSTR REG32(STM32_RCC_BASE + 0x10) +#define RCC_AHB1RSTR_OTGHSRST (1 << 29) + +#define STM32_RCC_AHB2RSTR REG32(STM32_RCC_BASE + 0x14) +#define STM32_RCC_AHB3RSTR REG32(STM32_RCC_BASE + 0x18) + +#define STM32_RCC_APB1RSTR REG32(STM32_RCC_BASE + 0x20) +#define STM32_RCC_APB2RSTR REG32(STM32_RCC_BASE + 0x24) + +#define STM32_RCC_AHB1ENR REG32(STM32_RCC_BASE + 0x30) +#define STM32_RCC_AHB1ENR_GPIOMASK (0xff << 0) +#define STM32_RCC_AHB1ENR_BKPSRAMEN (1 << 18) +#define STM32_RCC_AHB1ENR_DMA1EN (1 << 21) +#define STM32_RCC_AHB1ENR_DMA2EN (1 << 22) +/* TODO(nsanders): normalize naming.*/ +#define STM32_RCC_HB1_DMA1 (1 << 21) +#define STM32_RCC_HB1_DMA2 (1 << 22) +#define STM32_RCC_AHB1ENR_OTGHSEN (1 << 29) +#define STM32_RCC_AHB1ENR_OTGHSULPIEN (1 << 30) + +#define STM32_RCC_AHB2ENR REG32(STM32_RCC_BASE + 0x34) +#define STM32_RCC_AHB2ENR_OTGFSEN (1 << 7) +#define STM32_RCC_AHB3ENR REG32(STM32_RCC_BASE + 0x38) + +#define STM32_RCC_APB1ENR REG32(STM32_RCC_BASE + 0x40) +#define STM32_RCC_PWREN (1 << 28) +#define STM32_RCC_I2C1EN (1 << 21) +#define STM32_RCC_I2C2EN (1 << 22) +#define STM32_RCC_I2C3EN (1 << 23) +#define STM32_RCC_FMPI2C4EN (1 << 24) + +#define STM32_RCC_APB2ENR REG32(STM32_RCC_BASE + 0x44) + +#define STM32_RCC_PB2_USART6 (1 << 5) +#define STM32_RCC_SYSCFGEN (1 << 14) + +#define STM32_RCC_AHB1LPENR REG32(STM32_RCC_BASE + 0x50) +#define STM32_RCC_AHB2LPENR REG32(STM32_RCC_BASE + 0x54) +#define STM32_RCC_AHB3LPENR REG32(STM32_RCC_BASE + 0x58) +#define STM32_RCC_APB1LPENR REG32(STM32_RCC_BASE + 0x60) +#define STM32_RCC_APB2LPENR REG32(STM32_RCC_BASE + 0x64) + +#define STM32_RCC_BDCR REG32(STM32_RCC_BASE + 0x70) +#define STM32_RCC_BDCR_BDRST (1 << 16) +#define STM32_RCC_BDCR_RTCEN (1 << 15) +#define BCDR_RTCSEL(source) (((source) & 0x3) << 8) +#define BDCR_SRC_HSE 0x3 +#define BDCR_SRC_LSI 0x2 +#define STM32_RCC_CSR REG32(STM32_RCC_BASE + 0x74) +#define STM32_RCC_CSR_LSION (1 << 0) +#define STM32_RCC_CSR_LSIRDY (1 << 1) + +#define STM32_RCC_HB_DMA1 (1 << 24) +#define STM32_RCC_PB2_TIM9 (1 << 2) +#define STM32_RCC_PB2_TIM10 (1 << 3) +#define STM32_RCC_PB2_TIM11 (1 << 4) +#define STM32_RCC_PB1_USB (1 << 23) + +#define STM32_RCC_DCKCFGR2 REG32(STM32_RCC_BASE + 0x94) +#define DCKCFGR2_FMPI2C1SEL(val) (((val) & 0x3) << 22) +#define DCKCFGR2_FMPI2C1SEL_MASK (0x3 << 22) +#define FMPI2C1SEL_APB 0x0 + +#define STM32_SYSCFG_BASE 0x40013800 + +#define STM32_SYSCFG_MEMRMP REG32(STM32_SYSCFG_BASE + 0x00) +#define STM32_SYSCFG_PMC REG32(STM32_SYSCFG_BASE + 0x04) +#define STM32_SYSCFG_EXTICR(n) REG32(STM32_SYSCFG_BASE + 8 + 4 * (n)) +#define STM32_SYSCFG_CMPCR REG32(STM32_SYSCFG_BASE + 0x20) +#define STM32_SYSCFG_CFGR REG32(STM32_SYSCFG_BASE + 0x2C) + #else #error Unsupported chip variant #endif @@ -711,7 +982,11 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_RCC_PB1_USART4 (1 << 19) #define STM32_RCC_PB1_USART5 (1 << 20) #define STM32_RCC_PB2_SPI1 (1 << 12) +#if defined(CHIP_FAMILY_STM32F4) +#define STM32_RCC_PB2_USART1 (1 << 4) +#else #define STM32_RCC_PB2_USART1 (1 << 14) +#endif /* --- Watchdogs --- */ @@ -740,7 +1015,8 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_RTC_BASE 0x40002800 #if defined(CHIP_FAMILY_STM32L) || defined(CHIP_FAMILY_STM32F0) || \ - defined(CHIP_FAMILY_STM32F3) || defined(CHIP_FAMILY_STM32L4) + defined(CHIP_FAMILY_STM32F3) || defined(CHIP_FAMILY_STM32L4) || \ + defined(CHIP_FAMILY_STM32F4) #define STM32_RTC_TR REG32(STM32_RTC_BASE + 0x00) #define STM32_RTC_DR REG32(STM32_RTC_BASE + 0x04) #define STM32_RTC_CR REG32(STM32_RTC_BASE + 0x08) @@ -754,6 +1030,8 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_RTC_ISR_INIT (1 << 7) #define STM32_RTC_ISR_ALRAF (1 << 8) #define STM32_RTC_PRER REG32(STM32_RTC_BASE + 0x10) +#define STM32_RTC_PRER_A_MASK (0x7f << 16) +#define STM32_RTC_PRER_S_MASK (0x7fff << 0) #define STM32_RTC_WUTR REG32(STM32_RTC_BASE + 0x14) #define STM32_RTC_CALIBR REG32(STM32_RTC_BASE + 0x18) #define STM32_RTC_ALRMAR REG32(STM32_RTC_BASE + 0x1C) @@ -915,12 +1193,53 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_OPTB_COMPL_SHIFT 8 +#elif defined(CHIP_FAMILY_STM32F4) +#define STM32_FLASH_REGS_BASE 0x40023c00 + +#define STM32_FLASH_ACR REG32(STM32_FLASH_REGS_BASE + 0x00) +#define STM32_FLASH_ACR_LATENCY (1 << 0) +#define STM32_FLASH_ACR_PRFTEN (1 << 8) +#define STM32_FLASH_ACR_ICEN (1 << 9) +#define STM32_FLASH_ACR_DCEN (1 << 10) +#define STM32_FLASH_KEYR REG32(STM32_FLASH_REGS_BASE + 0x04) +#define STM32_FLASH_OPTKEYR REG32(STM32_FLASH_REGS_BASE + 0x08) +#define STM32_FLASH_SR REG32(STM32_FLASH_REGS_BASE + 0x0c) +#define FLASH_SR_BUSY (1 << 16) +#define FLASH_SR_ERR_MASK (0x1f3) +#define STM32_FLASH_CR REG32(STM32_FLASH_REGS_BASE + 0x10) +#define FLASH_CR_PG (1 << 0) +#define FLASH_CR_SER (1 << 1) +#define FLASH_CR_STRT (1 << 16) +#define FLASH_CR_LOCK (1 << 31) +#define FLASH_CR_PSIZE(size) (((size) & 0x3) << 8) +#define FLASH_CR_PSIZE_16 (1) +#define FLASH_CR_PSIZE_32 (2) +#define FLASH_CR_PSIZE_MASK FLASH_CR_PSIZE(0x3) +#define FLASH_CR_SNB(sec) (((sec) & 0xf) << 3) +#define FLASH_CR_SNB_MASK FLASH_CR_SNB(0xf) + +#define STM32_FLASH_OPTCR REG32(STM32_FLASH_REGS_BASE + 0x14) + +#define STM32_OPTB_BASE 0x1FFFC000 + +#define STM32_OPTB_RDP_OFF 0x00 +#define STM32_OPTB_USER_OFF 0x02 +#define STM32_OPTB_WRP_OFF(n) (0x08 + (n&3) * 2) +#define STM32_OPTB_WRP01 0x08 +#define STM32_OPTB_WRP23 0x0c + +#define STM32_OPTB_COMPL_SHIFT 8 + #else #error Unsupported chip variant #endif /* --- External Interrupts --- */ +#if defined(CHIP_FAMILY_STM32F4) +#define STM32_EXTI_BASE 0x40013C00 +#else #define STM32_EXTI_BASE 0x40010400 +#endif #define STM32_EXTI_IMR REG32(STM32_EXTI_BASE + 0x00) #define STM32_EXTI_EMR REG32(STM32_EXTI_BASE + 0x04) @@ -929,15 +1248,21 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_EXTI_SWIER REG32(STM32_EXTI_BASE + 0x10) #define STM32_EXTI_PR REG32(STM32_EXTI_BASE + 0x14) -#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3) +#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3) || \ + defined(CHIP_FAMILY_STM32F4) #define EXTI_RTC_ALR_EVENT (1 << 17) #endif /* --- ADC --- */ +#if defined(CHIP_FAMILY_STM32F4) +#define STM32_ADC1_BASE 0x40012000 +#define STM32_ADC_BASE 0x40012300 +#else #define STM32_ADC1_BASE 0x40012400 #define STM32_ADC_BASE 0x40012700 /* STM32L15X only */ +#endif -#if defined(CHIP_VARIANT_STM32F373) +#if defined(CHIP_VARIANT_STM32F373) || defined(CHIP_FAMILY_STM32F4) #define STM32_ADC_SR REG32(STM32_ADC1_BASE + 0x00) #define STM32_ADC_CR1 REG32(STM32_ADC1_BASE + 0x04) #define STM32_ADC_CR2 REG32(STM32_ADC1_BASE + 0x08) @@ -1241,10 +1566,107 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; defined(CHIP_FAMILY_STM32L4) #define STM32_DMA1_BASE 0x40020000 #define STM32_DMA2_BASE 0x40020400 +#elif defined(CHIP_FAMILY_STM32F4) +#define STM32_DMA1_BASE 0x40026000 +#define STM32_DMA2_BASE 0x40026400 #else #error Unsupported chip variant #endif + +#if defined(CHIP_FAMILY_STM32F4) + +/* + * Available DMA streams, numbered from 0. + * + * Named channel to respect older interface, but a stream can serve + * any channels, as long as they are in the same DMA controller. + * + * Stream 0 - 7 are managed by controller DMA1, 8 - 15 DMA2. + */ +enum dma_channel { + /* Channel numbers */ + STM32_DMA1_STREAM0 = 0, + STM32_DMA1_STREAM1 = 1, + STM32_DMA1_STREAM2 = 2, + STM32_DMA1_STREAM3 = 3, + STM32_DMA1_STREAM4 = 4, + STM32_DMA1_STREAM5 = 5, + STM32_DMA1_STREAM6 = 6, + STM32_DMA1_STREAM7 = 7, + STM32_DMAS_COUNT = 8, + STM32_DMA2_STREAM0 = 8, + STM32_DMA2_STREAM1 = 9, + STM32_DMA2_STREAM2 = 10, + STM32_DMA2_STREAM3 = 11, + STM32_DMA2_STREAM4 = 12, + STM32_DMA2_STREAM5 = 13, + STM32_DMA2_STREAM6 = 14, + STM32_DMA2_STREAM7 = 15, + + STM32_DMAS_USART1_TX = STM32_DMA2_STREAM7, + STM32_DMAS_USART1_RX = STM32_DMA2_STREAM5, + /* Legacy naming for uart.c */ + STM32_DMAC_USART1_TX = STM32_DMAS_USART1_TX, + STM32_DMAC_USART1_RX = STM32_DMAS_USART1_RX, + + STM32_DMAC_I2C1_TX = STM32_DMA1_STREAM6, + STM32_DMAC_I2C1_RX = STM32_DMA1_STREAM0, + + STM32_DMAC_I2C2_TX = STM32_DMA1_STREAM7, + STM32_DMAC_I2C2_RX = STM32_DMA1_STREAM3, + + STM32_DMAC_I2C3_TX = STM32_DMA1_STREAM4, + STM32_DMAC_I2C3_RX = STM32_DMA1_STREAM1, + + STM32_DMAC_FMPI2C4_TX = STM32_DMA1_STREAM5, + STM32_DMAC_FMPI2C4_RX = STM32_DMA1_STREAM2, + +}; + +#define STM32_REQ_USART1_TX 4 +#define STM32_REQ_USART1_RX 4 + +#define STM32_REQ_USART2_TX 4 +#define STM32_REQ_USART2_RX 4 + +#define STM32_I2C1_TX_REQ_CH 1 +#define STM32_I2C1_RX_REQ_CH 1 + +#define STM32_I2C2_TX_REQ_CH 7 +#define STM32_I2C2_RX_REQ_CH 7 + +#define STM32_I2C3_TX_REQ_CH 3 +#define STM32_I2C3_RX_REQ_CH 1 + +#define STM32_FMPI2C4_TX_REQ_CH 2 +#define STM32_FMPI2C4_RX_REQ_CH 2 + +#define STM32_DMAS_TOTAL_COUNT 16 + +/* Registers for a single stream of a DMA controller */ +struct stm32_dma_stream { + uint32_t scr; /* Control */ + uint32_t sndtr; /* Number of data to transfer */ + uint32_t spar; /* Peripheral address */ + uint32_t sm0ar; /* Memory address 0 */ + uint32_t sm1ar; /* address 1 for double buffer */ + uint32_t sfcr; /* FIFO control */ +}; + +/* Always use stm32_dma_stream_t so volatile keyword is included! */ +typedef volatile struct stm32_dma_stream stm32_dma_stream_t; + +/* Common code and header file must use this */ +typedef stm32_dma_stream_t dma_chan_t; +struct stm32_dma_regs { + uint32_t isr[2]; + uint32_t ifcr[2]; + stm32_dma_stream_t stream[STM32_DMAS_COUNT]; +}; + +#else /* CHIP_FAMILY_STM32F4 */ + /* * Available DMA channels, numbered from 0. * @@ -1338,12 +1760,93 @@ struct stm32_dma_regs { uint32_t ifcr; stm32_dma_chan_t chan[STM32_DMAC_COUNT]; }; +#endif /* CHIP_FAMILY_STM32F4 */ /* Always use stm32_dma_regs_t so volatile keyword is included! */ typedef volatile struct stm32_dma_regs stm32_dma_regs_t; #define STM32_DMA1_REGS ((stm32_dma_regs_t *)STM32_DMA1_BASE) + + +#if defined(CHIP_FAMILY_STM32F4) +#define STM32_DMA2_REGS ((stm32_dma_regs_t *)STM32_DMA2_BASE) + +#define STM32_DMA_REGS(channel) \ + ((channel) < STM32_DMAS_COUNT ? STM32_DMA1_REGS : STM32_DMA2_REGS) + +#define STM32_DMA_CCR_EN (1 << 0) +#define STM32_DMA_CCR_DMEIE (1 << 1) +#define STM32_DMA_CCR_TEIE (1 << 2) +#define STM32_DMA_CCR_HTIE (1 << 3) +#define STM32_DMA_CCR_TCIE (1 << 4) +#define STM32_DMA_CCR_PFCTRL (1 << 5) +#define STM32_DMA_CCR_DIR_P2M (0 << 6) +#define STM32_DMA_CCR_DIR_M2P (1 << 6) +#define STM32_DMA_CCR_DIR_M2M (2 << 6) +#define STM32_DMA_CCR_CIRC (1 << 8) +#define STM32_DMA_CCR_PINC (1 << 9) +#define STM32_DMA_CCR_MINC (1 << 10) +#define STM32_DMA_CCR_PSIZE_8_BIT (0 << 11) +#define STM32_DMA_CCR_PSIZE_16_BIT (1 << 11) +#define STM32_DMA_CCR_PSIZE_32_BIT (2 << 11) +#define STM32_DMA_CCR_MSIZE_8_BIT (0 << 13) +#define STM32_DMA_CCR_MSIZE_16_BIT (1 << 13) +#define STM32_DMA_CCR_MSIZE_32_BIT (2 << 13) +#define STM32_DMA_CCR_PINCOS (1 << 15) +#define STM32_DMA_CCR_PL_LOW (0 << 16) +#define STM32_DMA_CCR_PL_MEDIUM (1 << 16) +#define STM32_DMA_CCR_PL_HIGH (2 << 16) +#define STM32_DMA_CCR_PL_VERY_HIGH (3 << 16) +#define STM32_DMA_CCR_DBM (1 << 18) +#define STM32_DMA_CCR_CT (1 << 19) +#define STM32_DMA_CCR_PBURST(b_len) ((((b_len) - 4) / 4) << 21) +#define STM32_DMA_CCR_MBURST(b_len) ((((b_len) - 4) / 4) << 21) +#define STM32_DMA_CCR_CHANNEL_MASK (0x7 << 25) +#define STM32_DMA_CCR_CHANNEL(channel) ((channel) << 25) +#define STM32_DMA_CCR_RSVD_MASK (0xF0100000) + + +#define STM32_DMA_SFCR_DMDIS (1 << 2) +#define STM32_DMA_SFCR_FTH(level) (((level) - 1) << 0) + + +#define STM32_DMA_CH_LOCAL(channel) ((channel) % STM32_DMAS_COUNT) +#define STM32_DMA_CH_LH(channel) \ + ((STM32_DMA_CH_LOCAL(channel) < 4) ? 0 : 1) +#define STM32_DMA_CH_OFFSET(channel) \ + (((STM32_DMA_CH_LOCAL(channel) % 4) * 6) + \ + (((STM32_DMA_CH_LOCAL(channel) % 4) >= 2) ? 4 : 0)) +#define STM32_DMA_CH_GETBITS(channel, val) \ + (((val) >> STM32_DMA_CH_OFFSET(channel)) & 0x3f) +#define STM32_DMA_GET_IFCR(channel) \ + (STM32_DMA_CH_GETBITS(channel, \ + STM32_DMA_REGS(channel)->ifcr[STM32_DMA_CH_LH(channel)])) +#define STM32_DMA_GET_ISR(channel) \ + (STM32_DMA_CH_GETBITS(channel, \ + STM32_DMA_REGS(channel)->ifcr[STM32_DMA_CH_LH(channel)])) + +#define STM32_DMA_SET_IFCR(channel, val) \ + (STM32_DMA_REGS(channel)->ifcr[STM32_DMA_CH_LH(channel)] = \ + (STM32_DMA_REGS(channel)->ifcr[STM32_DMA_CH_LH(channel)] & \ + ~(0x3f << STM32_DMA_CH_OFFSET(channel))) | \ + (((val) & 0x3f) << STM32_DMA_CH_OFFSET(channel))) +#define STM32_DMA_SET_ISR(channel, val) \ + (STM32_DMA_REGS(channel)->isr[STM32_DMA_CH_LH(channel)] = \ + (STM32_DMA_REGS(channel)->isr[STM32_DMA_CH_LH(channel)] & \ + ~(0x3f << STM32_DMA_CH_OFFSET(channel))) | \ + (((val) & 0x3f) << STM32_DMA_CH_OFFSET(channel))) + +#define STM32_DMA_FEIF (1 << 0) +#define STM32_DMA_DMEIF (1 << 2) +#define STM32_DMA_TEIF (1 << 3) +#define STM32_DMA_HTIF (1 << 4) +#define STM32_DMA_TCIF (1 << 5) +#define STM32_DMA_ALL 0x3d + +#else /* !CHIP_FAMILY_STM32F4 */ +#define STM32_DMA_CCR_CHANNEL(channel) (0) + #if defined(CHIP_FAMILY_STM32F3) || defined(CHIP_FAMILY_STM32L4) #define STM32_DMA2_REGS ((stm32_dma_regs_t *)STM32_DMA2_BASE) #define STM32_DMA_REGS(channel) \ @@ -1356,14 +1859,39 @@ typedef volatile struct stm32_dma_regs stm32_dma_regs_t; #endif /* Bits for DMA controller regs (isr and ifcr) */ +#define STM32_DMA_CH_OFFSET(channel) (4 * ((channel) % STM32_DMAC_PER_CTLR)) #define STM32_DMA_ISR_MASK(channel, mask) \ - ((mask) << (4 * ((channel) % STM32_DMAC_PER_CTLR))) + ((mask) << STM32_DMA_CH_OFFSET(channel)) #define STM32_DMA_ISR_GIF(channel) STM32_DMA_ISR_MASK(channel, 1 << 0) #define STM32_DMA_ISR_TCIF(channel) STM32_DMA_ISR_MASK(channel, 1 << 1) #define STM32_DMA_ISR_HTIF(channel) STM32_DMA_ISR_MASK(channel, 1 << 2) #define STM32_DMA_ISR_TEIF(channel) STM32_DMA_ISR_MASK(channel, 1 << 3) #define STM32_DMA_ISR_ALL(channel) STM32_DMA_ISR_MASK(channel, 0x0f) +#define STM32_DMA_GIF (1 << 0) +#define STM32_DMA_TCIF (1 << 1) +#define STM32_DMA_HTIF (1 << 2) +#define STM32_DMA_TEIF (1 << 3) +#define STM32_DMA_ALL 0xf + +#define STM32_DMA_GET_ISR(channel) \ + ((STM32_DMA_REGS(channel)->isr >> STM32_DMA_CH_OFFSET(channel)) \ + & STM32_DMA_ALL) +#define STM32_DMA_SET_ISR(channel, val) \ + (STM32_DMA_REGS(channel)->isr = \ + ((STM32_DMA_REGS(channel)->isr & \ + ~(STM32_DMA_ALL << STM32_DMA_CH_OFFSET(channel))) | \ + (((val) & STM32_DMA_ALL) << STM32_DMA_CH_OFFSET(channel)))) +#define STM32_DMA_GET_IFCR(channel) \ + ((STM32_DMA_REGS(channel)->ifcr >> STM32_DMA_CH_OFFSET(channel)) \ + & STM32_DMA_ALL) +#define STM32_DMA_SET_IFCR(channel, val) \ + (STM32_DMA_REGS(channel)->ifcr = \ + ((STM32_DMA_REGS(channel)->ifcr & \ + ~(STM32_DMA_ALL << STM32_DMA_CH_OFFSET(channel))) | \ + (((val) & STM32_DMA_ALL) << STM32_DMA_CH_OFFSET(channel)))) + + /* Bits for DMA channel regs */ #define STM32_DMA_CCR_EN (1 << 0) #define STM32_DMA_CCR_TCIE (1 << 1) @@ -1384,6 +1912,7 @@ typedef volatile struct stm32_dma_regs stm32_dma_regs_t; #define STM32_DMA_CCR_PL_HIGH (2 << 12) #define STM32_DMA_CCR_PL_VERY_HIGH (3 << 12) #define STM32_DMA_CCR_MEM2MEM (1 << 14) +#endif /* !CHIP_FAMILY_STM32F4 */ /* --- CRC --- */ #define STM32_CRC_BASE 0x40023000 diff --git a/chip/stm32/system.c b/chip/stm32/system.c index e906234f19..ea8c91390d 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -186,9 +186,14 @@ void system_pre_init(void) #endif /* enable clock on Power module */ - STM32_RCC_APB1ENR |= 1 << 28; + STM32_RCC_APB1ENR |= STM32_RCC_PWREN; +#if defined(CHIP_FAMILY_STM32F4) + /* enable backup registers */ + STM32_RCC_AHB1ENR |= STM32_RCC_AHB1ENR_BKPSRAMEN; +#else /* enable backup registers */ STM32_RCC_APB1ENR |= 1 << 27; +#endif /* Delay 1 APB clock cycle after the clock is enabled */ clock_wait_bus_cycles(BUS_APB, 1); /* Enable access to RCC CSR register and RTC backup registers */ @@ -212,7 +217,7 @@ void system_pre_init(void) STM32_RCC_CSR = (STM32_RCC_CSR & ~0x00C30000) | 0x00420000; } #elif defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3) || \ - defined(CHIP_FAMILY_STM32L4) + defined(CHIP_FAMILY_STM32L4) || defined(CHIP_FAMILY_STM32F4) if ((STM32_RCC_BDCR & 0x00018300) != 0x00008200) { /* the RTC settings are bad, we need to reset it */ STM32_RCC_BDCR |= 0x00010000; @@ -404,5 +409,8 @@ int system_is_reboot_warm(void) #elif defined(CHIP_FAMILY_STM32L4) return ((STM32_RCC_AHB2ENR & STM32_RCC_AHB2ENR_GPIOMASK) == STM32_RCC_AHB2ENR_GPIOMASK); +#elif defined(CHIP_FAMILY_STM32F4) + return ((STM32_RCC_AHB1ENR & STM32_RCC_AHB1ENR_GPIOMASK) + == STM32_RCC_AHB1ENR_GPIOMASK); #endif } diff --git a/chip/stm32/uart.c b/chip/stm32/uart.c index 8fbb6a3436..a1edaa6692 100644 --- a/chip/stm32/uart.c +++ b/chip/stm32/uart.c @@ -32,6 +32,9 @@ static const struct dma_option dma_tx_option = { CONFIG_UART_TX_DMA_CH, (void *)&STM32_USART_TDR(UARTN_BASE), STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT +#ifdef CHIP_FAMILY_STM32F4 + | STM32_DMA_CCR_CHANNEL(CONFIG_UART_TX_REQ_CH) +#endif }; #else @@ -47,6 +50,9 @@ static const struct dma_option dma_tx_option = { static const struct dma_option dma_rx_option = { CONFIG_UART_RX_DMA_CH, (void *)&STM32_USART_RDR(UARTN_BASE), STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT | +#ifdef CHIP_FAMILY_STM32F4 + STM32_DMA_CCR_CHANNEL(CONFIG_UART_RX_REQ_CH) | +#endif STM32_DMA_CCR_CIRC }; @@ -167,7 +173,11 @@ void uart_interrupt(void) STM32_USART_CR1(UARTN_BASE) &= ~STM32_USART_CR1_TCIE; enable_sleep(SLEEP_MASK_UART); } +#if defined(CHIP_FAMILY_STM32F4) + STM32_USART_SR(UARTN_BASE) &= ~STM32_USART_SR_TC; +#else STM32_USART_ICR(UARTN_BASE) |= STM32_USART_SR_TC; +#endif if (!(STM32_USART_SR(UARTN_BASE) & ~STM32_USART_SR_TC)) return; } @@ -234,7 +244,8 @@ static void uart_freq_change(void) #endif #if defined(CHIP_FAMILY_STM32L) || defined(CHIP_FAMILY_STM32F0) || \ - defined(CHIP_FAMILY_STM32F3) || defined(CHIP_FAMILY_STM32L4) + defined(CHIP_FAMILY_STM32F3) || defined(CHIP_FAMILY_STM32L4) || \ + defined(CHIP_FAMILY_STM32F4) if (div / 16 > 0) { /* * CPU clock is high enough to support x16 oversampling. @@ -279,6 +290,8 @@ void uart_init(void) /* Enable USART clock */ #if (UARTN == 1) STM32_RCC_APB2ENR |= STM32_RCC_PB2_USART1; +#elif (UARTN == 6) + STM32_RCC_APB2ENR |= STM32_RCC_PB2_USART6; #elif (UARTN == 9) STM32_RCC_APB1ENR2 |= STM32_RCC_APB1ENR2_LPUART1EN; #else @@ -340,7 +353,7 @@ void uart_init(void) STM32_USART_CR1(UARTN_BASE) |= STM32_USART_CR1_RXNEIE; #endif -#ifdef CHIP_FAMILY_STM32L +#if defined(CHIP_FAMILY_STM32L) || defined(CHIP_FAMILY_STM32F4) /* Use single-bit sampling */ STM32_USART_CR3(UARTN_BASE) |= STM32_USART_CR3_ONEBIT; #endif diff --git a/include/config.h b/include/config.h index 64ecab1eff..5f5f90adea 100644 --- a/include/config.h +++ b/include/config.h @@ -524,6 +524,9 @@ */ #undef CONFIG_CLOCK_CRYSTAL +/* Indicate if a clock source is connected to stm32f4's "HSE" specific input */ +#undef CONFIG_STM32_CLOCK_HSE_HZ + /*****************************************************************************/ /* PMIC config */ @@ -1870,6 +1873,11 @@ /* The DMA peripheral request signal for UART TX. STM32 only. */ #undef CONFIG_UART_TX_DMA_PH +/* The DMA channel mapping config for stm32f4. */ +#undef CONFIG_UART_TX_REQ_CH +#undef CONFIG_UART_RX_REQ_CH + + /*****************************************************************************/ /* USB PD config */ diff --git a/include/module_id.h b/include/module_id.h index 72849afa4d..dc4fff1191 100644 --- a/include/module_id.h +++ b/include/module_id.h @@ -49,6 +49,7 @@ enum module_id { MODULE_USB_PORT_POWER, /* 35 */ MODULE_USB_SWITCH, MODULE_VBOOT, + MODULE_MCO, /* Module count; not an actual module */ MODULE_COUNT diff --git a/include/task.h b/include/task.h index a1b133b986..e177bae546 100644 --- a/include/task.h +++ b/include/task.h @@ -13,13 +13,26 @@ /* Task event bitmasks */ /* Tasks may use the bits in TASK_EVENT_CUSTOM for their own events */ -#define TASK_EVENT_CUSTOM(x) (x & 0x03ffffff) +#define TASK_EVENT_CUSTOM(x) (x & 0x0007ffff) + +/* npcx peci event */ +#define TASK_EVENT_PECI_DONE (1 << 19) + +/* I2C tx/rx interrupt handler completion event. */ +#define TASK_EVENT_I2C_COMPLETION(port) \ + (1 << ((port) + 20)) +#define TASK_EVENT_I2C_IDLE (TASK_EVENT_I2C_COMPLETION(0)) +#define TASK_EVENT_MAX_I2C 6 +#ifdef I2C_PORT_COUNT +#if (I2C_PORT_COUNT > TASK_EVENT_MAX_I2C) +#error "Too many i2c ports for i2c events" +#endif +#endif + /* DMA transmit complete event */ #define TASK_EVENT_DMA_TC (1 << 26) /* ADC interrupt handler event */ #define TASK_EVENT_ADC_DONE (1 << 27) -/* I2C interrupt handler event */ -#define TASK_EVENT_I2C_IDLE (1 << 28) /* task_wake() called on task */ #define TASK_EVENT_WAKE (1 << 29) /* Mutex unlocking */ diff --git a/util/flash_ec b/util/flash_ec index d70f5f791f..58e373e02d 100755 --- a/util/flash_ec +++ b/util/flash_ec @@ -88,6 +88,7 @@ BOARDS_STM32_DFU=( discovery servo_v4 servo_micro + stm32f446e-eval ) BOARDS_NPCX_5M5G_JTAG=( |