/* Copyright (c) 2014 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. */ /* Hardware initialization and common functions */ #include "adc.h" #include "adc_chip.h" #include "common.h" #include "cpu.h" #include "registers.h" #include "task.h" #include "timer.h" #include "util.h" #include "watchdog.h" static void system_init(void) { /* Enable access to RCC CSR register and RTC backup registers */ STM32_PWR_CR |= 1 << 8; /* switch on LSI */ STM32_RCC_CSR |= 1 << 0; /* Wait for LSI to be ready */ while (!(STM32_RCC_CSR & (1 << 1))) ; /* re-configure RTC if needed */ if ((STM32_RCC_BDCR & 0x00018300) != 0x00008200) { /* the RTC settings are bad, we need to reset it */ STM32_RCC_BDCR |= 0x00010000; /* Enable RTC and use LSI as clock source */ STM32_RCC_BDCR = (STM32_RCC_BDCR & ~0x00018300) | 0x00008200; } } static void power_init(void) { /* enable SYSCFG, COMP, ADC, SPI1, USART1 */ STM32_RCC_APB2ENR = 0x00005201; /* enable TIM2, TIM3, TIM14, PWR */ STM32_RCC_APB1ENR = 0x10000103; /* enable DMA, SRAM, CRC, GPA, GPB, GPF */ STM32_RCC_AHBENR = 0x460045; } /* GPIO setting helpers */ #define OUT(n) (1 << ((n) * 2)) #define AF(n) (2 << ((n) * 2)) #define ANALOG(n) (3 << ((n) * 2)) #define HIGH(n) (1 << (n)) #define ODR(n) (1 << (n)) #define HISPEED(n) (3 << ((n) * 2)) #define AFx(n, x) (x << (((n) % 8) * 4)) static void pins_init(void) { /* Pin usage: * PA0 (OUT - GPIO) : Wakeup on Vnc / Threshold * PA1 (ANALOG - ADC_IN1) : CC sense * PA2 (ANALOG - ADC_IN2) : Current sense * PA3 (ANALOG - ADC_IN3) : Voltage sense * PA4 (OUT - OD GPIO) : PD TX enable * PA5 (AF0 - SPI1_SCK) : TX clock in * PA6 (AF0 - SPI1_MISO) : PD TX * PA7 (AF5 - TIM3_CH2) : PD RX * PA9 (AF1 - UART1_TX) : [DEBUG] UART TX * PA10 (AF1 - UART1_RX) : [DEBUG] UART RX * PA13 (OUT - GPIO) : voltage select[0] * PA14 (OUT - GPIO) : voltage select[1] * PB1 (AF0 - TIM14_CH1) : TX clock out * PF0 (OUT - GPIO) : LM5050 FET driver off * PF1 (OUT - GPIO) : discharge FET */ /* * Clear power control/status register to disable wakeup * pin A0, so that we can change it to an output. */ STM32_PWR_CSR = 0; STM32_PWR_CR |= 0xc; STM32_GPIO_ODR(GPIO_A) = HIGH(0) | HIGH(4); STM32_GPIO_AFRL(GPIO_A) = AFx(7, 1); STM32_GPIO_AFRH(GPIO_A) = AFx(9, 1) | AFx(10, 1); STM32_GPIO_OTYPER(GPIO_A) = ODR(4); STM32_GPIO_OSPEEDR(GPIO_A) = HISPEED(5) | HISPEED(6) | HISPEED(7); STM32_GPIO_MODER(GPIO_A) = OUT(0) | ANALOG(1) | ANALOG(2) | ANALOG(3) | OUT(4) | AF(5) /*| AF(6)*/ | AF(7) | AF(9) | AF(10) | OUT(13) | OUT(14); /* set PF0 / PF1 as output */ STM32_GPIO_ODR(GPIO_F) = 0; STM32_GPIO_MODER(GPIO_F) = OUT(0) | OUT(1); STM32_GPIO_OTYPER(GPIO_F) = 0; /* Set PB1 as AF0 (TIM14_CH1) */ STM32_GPIO_OSPEEDR(GPIO_B) = HISPEED(1); STM32_GPIO_MODER(GPIO_B) = AF(1); } static void adc_init(void) { /* Only do the calibration if the ADC is off */ if (!(STM32_ADC_CR & 1)) { /* ADC calibration */ STM32_ADC_CR = STM32_ADC_CR_ADCAL; /* set ADCAL = 1, ADC off */ /* wait for the end of calibration */ while (STM32_ADC_CR & STM32_ADC_CR_ADCAL) ; } /* Single conversion, right aligned, 12-bit */ STM32_ADC_CFGR1 = 1 << 12; /* (1 << 15) => AUTOOFF */; /* clock is ADCCLK (ADEN must be off when writing this reg) */ STM32_ADC_CFGR2 = 0; /* Sampling time : 71.5 ADC clock cycles, about 5us */ STM32_ADC_SMPR = 6; /* * ADC enable (note: takes 4 ADC clocks between end of calibration * and setting ADEN). */ STM32_ADC_CR = STM32_ADC_CR_ADEN; while (!(STM32_ADC_ISR & STM32_ADC_ISR_ADRDY)) STM32_ADC_CR = STM32_ADC_CR_ADEN; /* Disable interrupts */ STM32_ADC_IER = 0; /* Analog watchdog IRQ */ task_enable_irq(STM32_IRQ_ADC_COMP); } static void uart_init(void) { /* set baudrate */ STM32_USART_BRR(UARTN_BASE) = DIV_ROUND_NEAREST(CPU_CLOCK, CONFIG_UART_BAUD_RATE); /* UART enabled, 8 Data bits, oversampling x16, no parity */ STM32_USART_CR1(UARTN_BASE) = STM32_USART_CR1_UE | STM32_USART_CR1_TE | STM32_USART_CR1_RE; /* 1 stop bit, no fancy stuff */ STM32_USART_CR2(UARTN_BASE) = 0x0000; /* DMA disabled, special modes disabled, error interrupt disabled */ STM32_USART_CR3(UARTN_BASE) = 0x0000; } static void timers_init(void) { /* TIM2 is a 32-bit free running counter with 1Mhz frequency */ STM32_TIM_CR2(2) = 0x0000; STM32_TIM32_ARR(2) = 0xFFFFFFFF; STM32_TIM_PSC(2) = CPU_CLOCK / 1000000 - 1; STM32_TIM_EGR(2) = 0x0001; /* Reload the pre-scaler */ STM32_TIM_CR1(2) = 1; STM32_TIM32_CNT(2) = 0x00000000; STM32_TIM_SR(2) = 0; /* Clear pending interrupts */ STM32_TIM_DIER(2) = 1; /* Overflow interrupt */ task_enable_irq(STM32_IRQ_TIM2); } static void irq_init(void) { /* clear all pending interrupts */ CPU_NVIC_UNPEND(0) = 0xffffffff; /* enable global interrupts */ asm("cpsie i"); } extern void runtime_init(void); void hardware_init(void) { uint32_t raw_cause = STM32_RCC_CSR; uint32_t pwr_status = STM32_PWR_CSR; power_init(); /* Clear the hardware reset cause by setting the RMVF bit */ STM32_RCC_CSR |= 1 << 24; /* Clear SBF in PWR_CSR */ STM32_PWR_CR |= 1 << 3; /* * WORKAROUND: as we cannot de-activate the watchdog during * long hibernation, we are woken-up once by the watchdog and * go back to hibernate if we detect that condition, without * watchdog initialized this time. * The RTC deadline (if any) is already set. */ if ((pwr_status & 0x2) && (raw_cause & 0x60000000)) __enter_hibernate(0, 0); system_init(); runtime_init(); /* sets clock */ pins_init(); uart_init(); timers_init(); watchdog_init(); adc_init(); irq_init(); } static int watchdog_ain_id, watchdog_ain_high, watchdog_ain_low; static int adc_enable_last_watchdog(void) { return adc_enable_watchdog(watchdog_ain_id, watchdog_ain_high, watchdog_ain_low); } static inline int adc_watchdog_enabled(void) { return STM32_ADC_CFGR1 & (1 << 23); } int adc_read_channel(enum adc_channel ch) { int value; int watchdog_enabled = adc_watchdog_enabled(); if (watchdog_enabled) adc_disable_watchdog(); /* Select channel to convert */ STM32_ADC_CHSELR = 1 << ch; /* Clear flags */ STM32_ADC_ISR = 0x8e; /* Start conversion */ STM32_ADC_CR |= 1 << 2; /* ADSTART */ /* Wait for end of conversion */ while (!(STM32_ADC_ISR & (1 << 2))) ; /* read converted value */ value = STM32_ADC_DR; if (watchdog_enabled) adc_enable_last_watchdog(); return value; } int adc_enable_watchdog(int ch, int high, int low) { /* store last watchdog setup */ watchdog_ain_id = ch; watchdog_ain_high = high; watchdog_ain_low = low; /* Set thresholds */ STM32_ADC_TR = ((high & 0xfff) << 16) | (low & 0xfff); /* Select channel to convert */ STM32_ADC_CHSELR = 1 << ch; /* Clear flags */ STM32_ADC_ISR = 0x8e; /* Set Watchdog enable bit on a single channel / continuous mode */ STM32_ADC_CFGR1 = (ch << 26) | (1 << 23) | (1 << 22) | (1 << 13) | (1 << 12); /* Enable watchdog interrupt */ STM32_ADC_IER = 1 << 7; /* Start continuous conversion */ STM32_ADC_CR |= 1 << 2; /* ADSTART */ return EC_SUCCESS; } int adc_disable_watchdog(void) { /* Stop on-going conversion */ STM32_ADC_CR |= 1 << 4; /* ADSTP */ /* Wait for conversion to stop */ while (STM32_ADC_CR & (1 << 4)) ; /* CONT=0 -> continuous mode off / Clear Watchdog enable */ STM32_ADC_CFGR1 = 1 << 12; /* Disable interrupt */ STM32_ADC_IER = 0; /* Clear flags */ STM32_ADC_ISR = 0x8e; return EC_SUCCESS; } /* ---- flash handling ---- */ /* * 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 #define FLASH_TIMEOUT_LOOP \ (FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP) /* Flash unlocking keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB /* Lock bits for FLASH_CR register */ #define PG (1<<0) #define PER (1<<1) #define OPTPG (1<<4) #define OPTER (1<<5) #define STRT (1<<6) #define CR_LOCK (1<<7) #define OPTWRE (1<<9) 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 i; if ((uint32_t)address > CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_SIZE) return EC_ERROR_INVAL; /* unlock CR if needed */ if (STM32_FLASH_CR & CR_LOCK) { STM32_FLASH_KEYR = KEY1; STM32_FLASH_KEYR = KEY2; } /* Clear previous error status */ STM32_FLASH_SR = 0x34; /* set the ProGram bit */ STM32_FLASH_CR |= PG; for (; size > 0; size -= sizeof(uint16_t)) { /* wait to be ready */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; /* write the half word */ *address++ = data[0] + (data[1] << 8); data += 2; /* Wait for writes to complete */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; if (i == FLASH_TIMEOUT_LOOP) { res = EC_ERROR_TIMEOUT; goto exit_wr; } /* Check for error conditions - erase failed, voltage error, * protection error */ if (STM32_FLASH_SR & 0x14) { res = EC_ERROR_UNKNOWN; goto exit_wr; } } exit_wr: STM32_FLASH_CR &= ~PG; STM32_FLASH_CR = CR_LOCK; return res; } int flash_physical_erase(int offset, int size) { int res = EC_SUCCESS; /* unlock CR if needed */ if (STM32_FLASH_CR & CR_LOCK) { STM32_FLASH_KEYR = KEY1; STM32_FLASH_KEYR = KEY2; } /* Clear previous error status */ STM32_FLASH_SR = 0x34; /* set PER bit */ STM32_FLASH_CR |= PER; for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, offset += CONFIG_FLASH_ERASE_SIZE) { int i; /* select page to erase */ STM32_FLASH_AR = CONFIG_PROGRAM_MEMORY_BASE + offset; /* set STRT bit : start erase */ STM32_FLASH_CR |= STRT; /* Wait for erase to complete */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; if (i == FLASH_TIMEOUT_LOOP) { res = EC_ERROR_TIMEOUT; goto exit_er; } /* * Check for error conditions - erase failed, voltage error, * protection error */ if (STM32_FLASH_SR & 0x14) { res = EC_ERROR_UNKNOWN; goto exit_er; } } exit_er: STM32_FLASH_CR &= ~PER; STM32_FLASH_CR = CR_LOCK; return res; } static void unlock_erase_optb(void) { int i; /* Clear previous error status */ STM32_FLASH_SR = 0x34; /* wait to be ready */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; /* Unlock the option bytes access */ if (STM32_FLASH_CR & CR_LOCK) { STM32_FLASH_KEYR = KEY1; STM32_FLASH_KEYR = KEY2; } if (!(STM32_FLASH_CR & OPTWRE)) { STM32_FLASH_OPTKEYR = KEY1; STM32_FLASH_OPTKEYR = KEY2; } /* Must be set in 2 separate lines. */ STM32_FLASH_CR |= OPTER; STM32_FLASH_CR |= STRT; /* wait to be ready */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; /* reset erasing bits */ STM32_FLASH_CR = OPTWRE; } static void write_optb(int byte, uint8_t value) { volatile int16_t *hword = (uint16_t *)(STM32_OPTB_BASE + byte); int i; /* Clear previous error status */ STM32_FLASH_SR = 0x34; /* set OPTPG bit */ STM32_FLASH_CR |= OPTPG; *hword = ((~value) << STM32_OPTB_COMPL_SHIFT) | value; /* reset OPTPG bit */ STM32_FLASH_CR = OPTWRE; /* wait to be ready */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; } void flash_physical_permanent_protect(void) { unlock_erase_optb(); /* protect the 16KB RO partition against write/erase in WRP0 */ write_optb(8, 0xF0); /* Set RDP to level 1 to prevent disabling the protection */ write_optb(0, 0x11); /* Reset by using OBL_LAUNCH to take changes into account */ asm volatile("cpsid i"); STM32_FLASH_CR |= FLASH_CR_OBL_LAUNCH; /* Spin and wait for reboot; should never return */ while (1) ; } int flash_physical_is_permanently_protected(void) { /* if RDP is still at level 0, the flash protection is not in place */ return (STM32_FLASH_OBR & STM32_FLASH_OBR_RDP_MASK) && /* the low 16KB (RO partition) are write-protected */ !(STM32_FLASH_WRPR & 0xF); }