summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2016-07-26 13:17:09 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-08-17 16:19:07 -0700
commit6fcd163da5169bfca36ab8c15cfd9d0624acae19 (patch)
treecc1e3cd999fa3df95547356e8160fd966aa26bc3
parent6fad4f8588242cd6202e1177e145073c6aff6b7a (diff)
downloadchrome-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.c58
-rw-r--r--board/stm32f446e-eval/board.h54
-rw-r--r--board/stm32f446e-eval/build.mk12
-rw-r--r--board/stm32f446e-eval/ec.tasklist21
-rw-r--r--board/stm32f446e-eval/gpio.inc62
-rw-r--r--chip/npcx/peci.c2
-rw-r--r--chip/stm32/build.mk8
-rw-r--r--chip/stm32/clock-f.c209
-rw-r--r--chip/stm32/clock-f.h70
-rw-r--r--chip/stm32/clock-stm32f0.c192
-rw-r--r--chip/stm32/clock-stm32f4.c254
-rw-r--r--chip/stm32/config-stm32f446.h63
-rw-r--r--chip/stm32/config_chip.h10
-rw-r--r--chip/stm32/dma-stm32f4.c308
-rw-r--r--chip/stm32/dma.c34
-rw-r--r--chip/stm32/flash-f.c16
-rw-r--r--chip/stm32/flash-stm32f4.c384
-rw-r--r--chip/stm32/gpio-stm32f4.c26
-rw-r--r--chip/stm32/gpio.c2
-rw-r--r--chip/stm32/jtag-stm32f4.c17
-rw-r--r--chip/stm32/registers.h537
-rw-r--r--chip/stm32/system.c12
-rw-r--r--chip/stm32/uart.c17
-rw-r--r--include/config.h8
-rw-r--r--include/module_id.h1
-rw-r--r--include/task.h19
-rwxr-xr-xutil/flash_ec1
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=(