diff options
-rw-r--r-- | board/pit/board.c | 17 | ||||
-rw-r--r-- | board/pit/board.h | 18 | ||||
-rw-r--r-- | chip/stm32/gpio-stm32l15x.c | 6 | ||||
-rw-r--r-- | chip/stm32/registers.h | 27 | ||||
-rw-r--r-- | chip/stm32/spi.c | 80 |
5 files changed, 69 insertions, 79 deletions
diff --git a/board/pit/board.c b/board/pit/board.c index a8bdf5e930..29ded9de1d 100644 --- a/board/pit/board.c +++ b/board/pit/board.c @@ -28,6 +28,8 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"CHARGER_INT", GPIO_C, (1<<6), GPIO_INT_RISING, pmu_irq_handler}, {"LID_OPEN", GPIO_C, (1<<13), GPIO_INT_BOTH, lid_interrupt}, {"SUSPEND_L", GPIO_C, (1<<7), GPIO_INT_BOTH, gaia_suspend_event}, + {"SPI1_NSS", GPIO_A, (1<<4), GPIO_INT_BOTH | GPIO_PULL_UP, + spi_event}, {"KB_IN00", GPIO_C, (1<<8), GPIO_KB_INPUT, keyboard_raw_gpio_interrupt}, {"KB_IN01", GPIO_C, (1<<9), GPIO_KB_INPUT, @@ -65,7 +67,6 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"PMIC_RESET", GPIO_A, (1<<15), GPIO_OUT_LOW, NULL}, #ifndef CONFIG_SPI {"SPI1_MISO", GPIO_A, (1<<6), GPIO_OUT_HIGH, NULL}, - {"SPI1_NSS", GPIO_A, (1<<4), GPIO_PULL_UP, NULL}, #endif {"KB_OUT00", GPIO_B, (1<<0), GPIO_KB_OUTPUT, NULL}, {"KB_OUT01", GPIO_B, (1<<8), GPIO_KB_OUTPUT, NULL}, @@ -102,14 +103,14 @@ void board_config_post_gpio_init(void) gpio_set_alternate_function(GPIO_B, (1 << 3), GPIO_ALT_TIM2); #ifdef CONFIG_SPI - /* SPI1 on pins PA4-7 (alt. function push-pull, 10MHz) */ - val = STM32_GPIO_CRL(GPIO_A) & ~0xffff0000; - val |= 0x99990000; - STM32_GPIO_CRL(GPIO_A) = val; - - gpio_set_flags(GPIO_SPI1_NSS, GPIO_INT_BOTH); + /* SPI1 on pins PA4-7 */ + gpio_set_alternate_function(GPIO_A, + (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7), + GPIO_ALT_SPI); + /* 10 MHz pin speed */ + STM32_GPIO_OSPEEDR(GPIO_A) = (STM32_GPIO_OSPEEDR(GPIO_A) & ~0xff00) | + 0xaa00; #endif - } #ifdef CONFIG_PMU_BOARD_INIT diff --git a/board/pit/board.h b/board/pit/board.h index 1009ef490a..84347c3ca4 100644 --- a/board/pit/board.h +++ b/board/pit/board.h @@ -39,16 +39,14 @@ #define CONFIG_PMU_HARD_RESET #define CONFIG_PMU_TPS65090 #define CONFIG_SMART_BATTERY - +#define CONFIG_SPI #ifdef PORT_TO_PIT /* TODO(rspangler): enable these features when they compile */ #define CONFIG_LOW_POWER_IDLE -#define CONFIG_SPI #define CONFIG_WATCHDOG_HELP #endif - #ifndef __ASSEMBLER__ /* By default, enable all console messages except keyboard */ @@ -57,7 +55,17 @@ /* Keyboard output port list */ #define KB_OUT_PORT_LIST GPIO_A, GPIO_B, GPIO_C -/* Charging */ +/* + * Charging. + * + * "HOST" means the port where the EC is the master, which has the battery, + * charger and PMU. + * + * "SLAVE" means the port where the EC is the slave, which has the AP (host + * processor). + * + * TODO: In this context, "host" is badly overloaded and confusing. + */ #define I2C_PORT_HOST 0 #define I2C_PORT_BATTERY I2C_PORT_HOST #define I2C_PORT_CHARGER I2C_PORT_HOST @@ -77,6 +85,7 @@ enum gpio_signal { GPIO_CHARGER_INT, GPIO_LID_OPEN, GPIO_SUSPEND_L, + GPIO_SPI1_NSS, /* Keyboard inputs */ GPIO_KB_IN00, GPIO_KB_IN01, @@ -107,7 +116,6 @@ enum gpio_signal { GPIO_PMIC_RESET, #ifndef CONFIG_SPI GPIO_SPI1_MISO, - GPIO_SPI1_NSS, #endif GPIO_KB_OUT00, GPIO_KB_OUT01, diff --git a/chip/stm32/gpio-stm32l15x.c b/chip/stm32/gpio-stm32l15x.c index 7b17cd363c..016161c5c2 100644 --- a/chip/stm32/gpio-stm32l15x.c +++ b/chip/stm32/gpio-stm32l15x.c @@ -178,6 +178,12 @@ test_mockable int gpio_get_level(enum gpio_signal signal) gpio_list[signal].mask); } +uint16_t *gpio_get_level_reg(enum gpio_signal signal, uint32_t *mask) +{ + *mask = gpio_list[signal].mask; + return (uint16_t *)&STM32_GPIO_IDR(gpio_list[signal].port); +} + void gpio_set_level(enum gpio_signal signal, int value) { STM32_GPIO_BSRR(gpio_list[signal].port) = diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 3155407200..cb02973399 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -193,6 +193,8 @@ struct timer_ctlr { unsigned or; }; +/* Must be volatile, or compiler optimizes out repeated accesses */ +typedef volatile struct timer_ctlr timer_ctlr_t; /* --- GPIO --- */ @@ -437,29 +439,24 @@ struct timer_ctlr { #define STM32_SPI2_PORT 1 /* The SPI controller registers */ -struct spi_ctlr { - unsigned ctrl1; - unsigned ctrl2; +struct stm32_spi_regs { + uint16_t ctrl1; + uint16_t _pad0; + uint16_t ctrl2; + uint16_t _pad1; unsigned stat; - unsigned data; + uint16_t data; + uint16_t _pad2; unsigned crcp; unsigned rxcrc; unsigned txcrc; unsigned i2scfgr; /* STM32F10x only */ unsigned i2spr; /* STM32F10x only */ }; +/* Must be volatile, or compiler optimizes out repeated accesses */ +typedef volatile struct stm32_spi_regs stm32_spi_regs_t; -/* - * TODO(vpalatin): - * For whatever reason, our toolchain is substandard and generate a - * function every time you are using this inline function. - * - * That's why I have not used inline stuff in the registers definition. - */ -#define stm32_spi_addr(port) \ - ((struct spi_ctlr *)(port == 0 ? STM32_SPI1_BASE : STM32_SPI2_BASE)) -#define stm32_spi_port(addr) \ - ((addr) == STM32_SPI1_BASE ? 0 : 1) +#define STM32_SPI1_REGS ((stm32_spi_regs_t *)STM32_SPI1_BASE) /* --- Debug --- */ diff --git a/chip/stm32/spi.c b/chip/stm32/spi.c index bf57b0b361..79a08a9e68 100644 --- a/chip/stm32/spi.c +++ b/chip/stm32/spi.c @@ -23,18 +23,14 @@ #define CPRINTF(format, args...) cprintf(CC_SPI, format, ## args) /* DMA channel option */ -static const struct dma_option dma_tx_option[2] = { - {DMA_SPI1_TX, (void *)&stm32_spi_addr(STM32_SPI1_PORT)->data, - DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, - {DMA_SPI2_TX, (void *)&stm32_spi_addr(STM32_SPI2_PORT)->data, - DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, +static const struct dma_option dma_tx_option = { + DMAC_SPI1_TX, (void *)&STM32_SPI1_REGS->data, + DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD }; -static const struct dma_option dma_rx_option[2] = { - {DMA_SPI1_RX, (void *)&stm32_spi_addr(STM32_SPI1_PORT)->data, - DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, - {DMA_SPI2_RX, (void *)&stm32_spi_addr(STM32_SPI2_PORT)->data, - DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, +static const struct dma_option dma_rx_option = { + DMAC_SPI1_RX, (void *)&STM32_SPI1_REGS->data, + DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD }; /* Status register flags that we use */ @@ -155,14 +151,13 @@ static int wait_for_bytes(struct dma_channel *rxdma, int needed, * We keep an eye on the NSS line - if this goes high then the transaction is * over so there is no point in trying to send the reply. * - * @param spi SPI controller to send data on * @param txdma TX DMA channel to send on * @param status Status result to send * @param msg_ptr Message payload to send, which normally starts * SPI_MSG_HEADER_LEN bytes into out_msg * @param msg_len Number of message bytes to send */ -static void reply(struct spi_ctlr *spi, struct dma_channel *txdma, +static void reply(struct dma_channel *txdma, enum ec_status status, char *msg_ptr, int msg_len) { char *msg; @@ -194,7 +189,7 @@ static void reply(struct spi_ctlr *spi, struct dma_channel *txdma, /* Add the checksum and get ready to send */ msg[msg_len - 2] = sum & 0xff; msg[msg_len - 1] = SPI_MSG_PREAMBLE_BYTE; - dma_prepare_tx(dma_tx_option[stm32_spi_port(spi)], msg_len, msg); + dma_prepare_tx(&dma_tx_option, msg_len, msg); /* Kick off the DMA to send the data */ dma_go(txdma); @@ -206,23 +201,22 @@ static void reply(struct spi_ctlr *spi, struct dma_channel *txdma, * Set up our RX DMA and disable our TX DMA. Set up the data output so that * we will send preamble bytes. */ -static void setup_for_transaction(struct spi_ctlr *spi) +static void setup_for_transaction(void) { - int dmac; + stm32_spi_regs_t *spi = STM32_SPI1_REGS; + int dmac __attribute__((unused)); /* We are no longer actively processing a transaction */ active = 0; /* write 0xfd which will be our default output value */ - REG16(&spi->data) = 0xfd; - dma_disable(DMA_CHANNEL_FOR_SPI_TX(spi)); + spi->data = 0xfd; + dma_disable(DMAC_SPI1_TX); *in_msg = 0xff; /* read a byte in case there is one, and the rx dma gets it */ - dmac = REG16(&spi->data); - dmac = DMA_CHANNEL_FOR_SPI_RX(spi); - dma_start_rx(dma_rx_option[stm32_spi_port(spi)], - sizeof(in_msg), in_msg); + dmac = spi->data; + dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg); } /** @@ -234,7 +228,6 @@ static void setup_for_transaction(struct spi_ctlr *spi) */ static void spi_send_response(struct host_cmd_handler_args *args) { - struct spi_ctlr *spi; enum ec_status result = args->result; struct dma_channel *txdma; @@ -242,7 +235,6 @@ static void spi_send_response(struct host_cmd_handler_args *args) if (!active) return; - spi = (struct spi_ctlr *)stm32_spi_addr(SPI_PORT_HOST); if (args->response_size > EC_HOST_PARAM_SIZE) result = EC_RES_INVALID_RESPONSE; @@ -251,8 +243,8 @@ static void spi_send_response(struct host_cmd_handler_args *args) ASSERT(args->response == out_msg + SPI_MSG_HEADER_LEN); /* Transmit the reply */ - txdma = dma_get_channel(DMA_CHANNEL_FOR_SPI_TX(spi)); - reply(spi, txdma, result, args->response, args->response_size); + txdma = dma_get_channel(DMAC_SPI1_TX); + reply(txdma, result, args->response, args->response_size); } /** @@ -266,28 +258,26 @@ static void spi_send_response(struct host_cmd_handler_args *args) void spi_event(enum gpio_signal signal) { struct dma_channel *rxdma; - struct spi_ctlr *spi; uint16_t *nss_reg; uint32_t nss_mask; - spi = (struct spi_ctlr *)stm32_spi_addr(SPI_PORT_HOST); - /* * If NSS is rising, we have finished the transaction, so prepare * for the next. */ nss_reg = gpio_get_level_reg(GPIO_SPI1_NSS, &nss_mask); if (REG16(nss_reg) & nss_mask) { - setup_for_transaction(spi); + setup_for_transaction(); return; } + /* Otherwise, NSS is low and we're now inside a transaction */ active = 1; - rxdma = dma_get_channel(DMA_CHANNEL_FOR_SPI_RX(spi)); + rxdma = dma_get_channel(DMAC_SPI1_RX); /* Wait for version, command, length bytes */ if (wait_for_bytes(rxdma, 3, nss_reg, nss_mask)) { - setup_for_transaction(spi); + setup_for_transaction(); return; } @@ -306,7 +296,7 @@ void spi_event(enum gpio_signal signal) /* Wait for parameters */ if (wait_for_bytes(rxdma, 3 + args.params_size, nss_reg, nss_mask)) { - setup_for_transaction(spi); + setup_for_transaction(); return; } @@ -322,33 +312,21 @@ void spi_event(enum gpio_signal signal) host_command_received(&args); } -static int spi_init(void) +static void spi_init(void) { - struct spi_ctlr *spi; + stm32_spi_regs_t *spi = STM32_SPI1_REGS; - /* Enable clocks to SPI module */ + /* Enable clocks to SPI1 module */ STM32_RCC_APB2ENR |= 1 << 12; - /** - * SPI1 - * PA7: SPI1_MOSI - * PA6: SPI1_MISO - * PA5: SPI1_SCK - * PA4: SPI1_NSS - * - * 8-bit data, master mode, full-duplex, clock is fpclk / 2 - */ - spi = (struct spi_ctlr *)stm32_spi_addr(SPI_PORT_HOST); - /* Enable rx DMA and get ready to receive our first transaction */ - REG16(&spi->ctrl2) = CR2_RXDMAEN | CR2_TXDMAEN; + spi->ctrl2 = CR2_RXDMAEN | CR2_TXDMAEN; - /* enable the SPI peripheral */ - REG16(&spi->ctrl1) |= CR1_SPE; + /* Enable the SPI peripheral */ + spi->ctrl1 |= CR1_SPE; - setup_for_transaction(spi); + setup_for_transaction(); gpio_enable_interrupt(GPIO_SPI1_NSS); - return EC_SUCCESS; } DECLARE_HOOK(HOOK_INIT, spi_init, HOOK_PRIO_DEFAULT); |