stm32mp1: Add PMIC support
authorYann Gautier <yann.gautier@st.com>
Mon, 16 Jul 2018 15:55:07 +0000 (17:55 +0200)
committerYann Gautier <yann.gautier@st.com>
Tue, 24 Jul 2018 15:15:13 +0000 (17:15 +0200)
If a PMIC companion chip is present on board, it has to be configured
for regulators supplies.
This check is done with board DT configuration.

Signed-off-by: Yann Gautier <yann.gautier@st.com>
Signed-off-by: Pascal Paillet <p.paillet@st.com>
drivers/st/pmic/stm32_i2c.c [new file with mode: 0644]
drivers/st/pmic/stm32mp1_pmic.c [new file with mode: 0644]
drivers/st/pmic/stpmu1.c [new file with mode: 0644]
include/drivers/st/stm32_i2c.h [new file with mode: 0644]
include/drivers/st/stm32mp1_pmic.h [new file with mode: 0644]
include/drivers/st/stpmu1.h [new file with mode: 0644]
plat/st/stm32mp1/bl2_plat_setup.c
plat/st/stm32mp1/platform.mk

diff --git a/drivers/st/pmic/stm32_i2c.c b/drivers/st/pmic/stm32_i2c.c
new file mode 100644 (file)
index 0000000..0980139
--- /dev/null
@@ -0,0 +1,851 @@
+/*
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mmio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stm32_i2c.h>
+
+/* STM32 I2C registers offsets */
+#define I2C_CR1                        0x00U
+#define I2C_CR2                        0x04U
+#define I2C_OAR1               0x08U
+#define I2C_OAR2               0x0CU
+#define I2C_TIMINGR            0x10U
+#define I2C_TIMEOUTR           0x14U
+#define I2C_ISR                        0x18U
+#define I2C_ICR                        0x1CU
+#define I2C_PECR               0x20U
+#define I2C_RXDR               0x24U
+#define I2C_TXDR               0x28U
+
+#define MAX_DELAY              0xFFFFFFFFU
+
+/* I2C TIMING clear register Mask */
+#define TIMING_CLEAR_MASK      0xF0FFFFFFU
+/* Timeout 25 ms */
+#define I2C_TIMEOUT_BUSY       25U
+
+#define MAX_NBYTE_SIZE         255U
+
+static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
+                                   uint16_t dev_addr, uint16_t mem_addr,
+                                   uint16_t mem_add_size, uint32_t timeout,
+                                   uint32_t tick_start);
+static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                                  uint16_t mem_addr, uint16_t mem_add_size,
+                                  uint32_t timeout, uint32_t tick_start);
+
+/* Private functions to handle flags during polling transfer */
+static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
+                        uint8_t awaited_value, uint32_t timeout,
+                        uint32_t tick_start);
+static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout,
+                        uint32_t tick_start);
+static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout,
+                        uint32_t tick_start);
+static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout,
+                         uint32_t tick_start);
+
+/* Private function to flush TXDR register */
+static void i2c_flush_txdr(struct i2c_handle_s *hi2c);
+
+/* Private function to start, restart or stop a transfer */
+static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                               uint16_t size, uint32_t i2c_mode,
+                               uint32_t request);
+
+/*
+ * @brief  Initialize the I2C device.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_init(struct i2c_handle_s *hi2c)
+{
+       if (hi2c == NULL) {
+               return -ENOENT;
+       }
+
+       if (hi2c->i2c_state == I2C_STATE_RESET) {
+               hi2c->lock = 0;
+       }
+
+       hi2c->i2c_state = I2C_STATE_BUSY;
+
+       /* Disable the selected I2C peripheral */
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+       /* Configure I2Cx: Frequency range */
+       mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR,
+                     hi2c->i2c_init.timing & TIMING_CLEAR_MASK);
+
+       /* Disable Own Address1 before set the Own Address1 configuration */
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN);
+
+       /* Configure I2Cx: Own Address1 and ack own address1 mode */
+       if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
+               mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
+                             I2C_OAR1_OA1EN | hi2c->i2c_init.own_address1);
+       } else { /* I2C_ADDRESSINGMODE_10BIT */
+               mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
+                             I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE |
+                             hi2c->i2c_init.own_address1);
+       }
+
+       /* Configure I2Cx: Addressing Master mode */
+       if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_10BIT) {
+               mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10);
+       }
+
+       /*
+        * Enable the AUTOEND by default, and enable NACK
+        * (should be disable only during Slave process)
+        */
+       mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
+                       I2C_CR2_AUTOEND | I2C_CR2_NACK);
+
+       /* Disable Own Address2 before set the Own Address2 configuration */
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE);
+
+       /* Configure I2Cx: Dual mode and Own Address2 */
+       mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2,
+                     hi2c->i2c_init.dual_address_mode |
+                     hi2c->i2c_init.own_address2 |
+                     (hi2c->i2c_init.own_address2_masks << 8));
+
+       /* Configure I2Cx: Generalcall and NoStretch mode */
+       mmio_write_32(hi2c->i2c_base_addr + I2C_CR1,
+                     hi2c->i2c_init.general_call_mode |
+                     hi2c->i2c_init.no_stretch_mode);
+
+       /* Enable the selected I2C peripheral */
+       mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+       hi2c->i2c_err = I2C_ERROR_NONE;
+       hi2c->i2c_state = I2C_STATE_READY;
+       hi2c->i2c_mode = I2C_MODE_NONE;
+
+       return 0;
+}
+
+/*
+ * @brief  Write an amount of data in blocking mode to a specific memory address
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: size of internal memory address
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout: timeout duration
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                       uint16_t mem_addr, uint16_t mem_add_size,
+                       uint8_t *p_data, uint16_t size, uint32_t timeout)
+{
+       uint32_t tickstart;
+
+       if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+               return -EBUSY;
+       }
+
+       if ((p_data == NULL) || (size == 0U)) {
+               return -EINVAL;
+       }
+
+       hi2c->lock = 1;
+
+       tickstart = (uint32_t)read_cntpct_el0();
+
+       if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY,
+                         tickstart) != 0) {
+               return -EIO;
+       }
+
+       hi2c->i2c_state     = I2C_STATE_BUSY_TX;
+       hi2c->i2c_mode      = I2C_MODE_MEM;
+       hi2c->i2c_err = I2C_ERROR_NONE;
+
+       hi2c->p_buff  = p_data;
+       hi2c->xfer_count = size;
+
+       /* Send Slave Address and Memory Address */
+       if (i2c_request_memory_write(hi2c, dev_addr, mem_addr, mem_add_size,
+                                    timeout, tickstart) != 0) {
+               hi2c->lock = 0;
+               return -EIO;
+       }
+
+       /*
+        * Set NBYTES to write and reload
+        * if hi2c->xfer_count > MAX_NBYTE_SIZE
+        */
+       if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
+               hi2c->xfer_size = MAX_NBYTE_SIZE;
+               i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
+                                   I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
+       } else {
+               hi2c->xfer_size = hi2c->xfer_count;
+               i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
+                                   I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
+       }
+
+       do {
+               if (i2c_wait_txis(hi2c, timeout, tickstart) != 0) {
+                       return -EIO;
+               }
+
+               mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *hi2c->p_buff);
+               hi2c->p_buff++;
+               hi2c->xfer_count--;
+               hi2c->xfer_size--;
+
+               if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) {
+                       /* Wait until TCR flag is set */
+                       if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout,
+                                         tickstart) != 0) {
+                               return -EIO;
+               }
+
+                       if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
+                               hi2c->xfer_size = MAX_NBYTE_SIZE;
+                               i2c_transfer_config(hi2c, dev_addr,
+                                                   hi2c->xfer_size,
+                                                   I2C_RELOAD_MODE,
+                                                   I2C_NO_STARTSTOP);
+                       } else {
+                               hi2c->xfer_size = hi2c->xfer_count;
+                               i2c_transfer_config(hi2c, dev_addr,
+                                                   hi2c->xfer_size,
+                                                   I2C_AUTOEND_MODE,
+                                                   I2C_NO_STARTSTOP);
+                       }
+               }
+
+       } while (hi2c->xfer_count > 0U);
+
+       /*
+        * No need to Check TC flag, with AUTOEND mode the stop
+        * is automatically generated.
+        * Wait until STOPF flag is reset.
+        */
+       if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) {
+               return -EIO;
+       }
+
+       mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
+
+       hi2c->i2c_state = I2C_STATE_READY;
+       hi2c->i2c_mode  = I2C_MODE_NONE;
+
+       hi2c->lock = 0;
+
+       return 0;
+}
+
+/*
+ * @brief  Read an amount of data in blocking mode from a specific memory
+ *        address
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: size of internal memory address
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout: timeout duration
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                      uint16_t mem_addr, uint16_t mem_add_size,
+                      uint8_t *p_data, uint16_t size, uint32_t timeout)
+{
+       uint32_t tickstart;
+
+       if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+               return -EBUSY;
+       }
+
+       if ((p_data == NULL) || (size == 0U)) {
+               return  -EINVAL;
+       }
+
+       hi2c->lock = 1;
+
+       tickstart = (uint32_t)read_cntpct_el0();
+
+       if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY,
+                         tickstart) != 0) {
+               return -EIO;
+       }
+
+       hi2c->i2c_state     = I2C_STATE_BUSY_RX;
+       hi2c->i2c_mode      = I2C_MODE_MEM;
+       hi2c->i2c_err = I2C_ERROR_NONE;
+
+       hi2c->p_buff  = p_data;
+       hi2c->xfer_count = size;
+
+       /* Send Slave Address and Memory Address */
+       if (i2c_request_memory_read(hi2c, dev_addr, mem_addr, mem_add_size,
+                                   timeout, tickstart) != 0) {
+               hi2c->lock = 0;
+               return -EIO;
+       }
+
+       /*
+        * Send Slave Address.
+        * Set NBYTES to write and reload if hi2c->xfer_count > MAX_NBYTE_SIZE
+        * and generate RESTART.
+        */
+       if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
+               hi2c->xfer_size = MAX_NBYTE_SIZE;
+               i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
+                                   I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
+       } else {
+               hi2c->xfer_size = hi2c->xfer_count;
+               i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
+                                   I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
+       }
+
+       do {
+               if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout,
+                                 tickstart) != 0) {
+                       return -EIO;
+               }
+
+               *hi2c->p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR);
+               hi2c->p_buff++;
+               hi2c->xfer_size--;
+               hi2c->xfer_count--;
+
+               if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) {
+                       if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout,
+                                         tickstart) != 0) {
+                               return -EIO;
+                       }
+
+                       if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
+                               hi2c->xfer_size = MAX_NBYTE_SIZE;
+                               i2c_transfer_config(hi2c, dev_addr,
+                                                   hi2c->xfer_size,
+                                                   I2C_RELOAD_MODE,
+                                                   I2C_NO_STARTSTOP);
+                       } else {
+                               hi2c->xfer_size = hi2c->xfer_count;
+                               i2c_transfer_config(hi2c, dev_addr,
+                                                   hi2c->xfer_size,
+                                                   I2C_AUTOEND_MODE,
+                                                   I2C_NO_STARTSTOP);
+                       }
+               }
+       } while (hi2c->xfer_count > 0U);
+
+       /*
+        * No need to Check TC flag, with AUTOEND mode the stop
+        * is automatically generated
+        * Wait until STOPF flag is reset
+        */
+       if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) {
+               return -EIO;
+       }
+
+       mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
+
+       hi2c->i2c_state = I2C_STATE_READY;
+       hi2c->i2c_mode  = I2C_MODE_NONE;
+
+       hi2c->lock = 0;
+
+       return 0;
+}
+
+/*
+ * @brief  Checks if target device is ready for communication.
+ * @note   This function is used with Memory devices
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  trials: Number of trials
+ * @param  timeout: timeout duration
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
+                             uint16_t dev_addr, uint32_t trials,
+                             uint32_t timeout)
+{
+       uint32_t i2c_trials = 0U;
+
+       if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+               return -EBUSY;
+       }
+
+       if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) !=
+           0U) {
+               return -EBUSY;
+       }
+
+       hi2c->lock = 1;
+
+       hi2c->i2c_state = I2C_STATE_BUSY;
+       hi2c->i2c_err = I2C_ERROR_NONE;
+
+       do {
+               uint32_t tickstart;
+
+               /* Generate Start */
+               if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
+                       mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
+                                     (((uint32_t)dev_addr & I2C_CR2_SADD) |
+                                      I2C_CR2_START | I2C_CR2_AUTOEND) &
+                                      ~I2C_CR2_RD_WRN);
+               } else {
+                       mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
+                                     (((uint32_t)dev_addr & I2C_CR2_SADD) |
+                                      I2C_CR2_START | I2C_CR2_ADD10) &
+                                     ~I2C_CR2_RD_WRN);
+               }
+
+               /*
+                * No need to Check TC flag, with AUTOEND mode the stop
+                * is automatically generated
+                * Wait until STOPF flag is set or a NACK flag is set
+                */
+               tickstart = (uint32_t)read_cntpct_el0();
+               while (((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+                        (I2C_FLAG_STOPF | I2C_FLAG_AF)) == 0U) &&
+                      (hi2c->i2c_state != I2C_STATE_TIMEOUT)) {
+                       if (timeout != MAX_DELAY) {
+                               if ((((uint32_t)read_cntpct_el0() - tickstart) >
+                                    timeout) || (timeout == 0U)) {
+                                       hi2c->i2c_state = I2C_STATE_READY;
+
+                                       hi2c->i2c_err |=
+                                               I2C_ERROR_TIMEOUT;
+
+                                       hi2c->lock = 0;
+
+                                       return -EIO;
+                               }
+                       }
+               }
+
+               /* Check if the NACKF flag has not been set */
+               if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+                    I2C_FLAG_AF) == 0U) {
+                       if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout,
+                                         tickstart) != 0) {
+                               return -EIO;
+                       }
+
+                       mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
+                                     I2C_FLAG_STOPF);
+
+                       hi2c->i2c_state = I2C_STATE_READY;
+
+                       hi2c->lock = 0;
+
+                       return 0;
+               }
+
+               if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout,
+                                 tickstart) != 0) {
+                       return -EIO;
+               }
+
+               mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
+
+               mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+               if (i2c_trials == trials) {
+                       mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
+                                       I2C_CR2_STOP);
+
+                       if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout,
+                                         tickstart) != 0) {
+                               return -EIO;
+                       }
+
+                       mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
+                                     I2C_FLAG_STOPF);
+               }
+
+               i2c_trials++;
+       } while (i2c_trials < trials);
+
+       hi2c->i2c_state = I2C_STATE_READY;
+
+       hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
+
+       hi2c->lock = 0;
+
+       return -EIO;
+}
+
+/*
+ * @brief  Master sends target device address followed by internal memory
+ *        address for write request.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: size of internal memory address
+ * @param  timeout: timeout duration
+ * @param  tick_start Tick start value
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
+                                   uint16_t dev_addr, uint16_t mem_addr,
+                                   uint16_t mem_add_size, uint32_t timeout,
+                                   uint32_t tick_start)
+{
+       i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE,
+                           I2C_GENERATE_START_WRITE);
+
+       if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
+               return -EIO;
+       }
+
+       if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
+               /* Send Memory Address */
+               mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+                            (uint8_t)(mem_addr & 0x00FFU));
+       } else {
+               /* Send MSB of Memory Address */
+               mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+                            (uint8_t)((mem_addr & 0xFF00U) >> 8));
+
+               /* Wait until TXIS flag is set */
+               if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
+                       return -EIO;
+               }
+
+               /* Send LSB of Memory Address */
+               mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+                            (uint8_t)(mem_addr & 0x00FFU));
+       }
+
+       if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, tick_start) !=
+           0) {
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * @brief  Master sends target device address followed by internal memory
+ *        address for read request.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: size of internal memory address
+ * @param  timeout: timeout duration
+ * @param  tick_start Tick start value
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                                  uint16_t mem_addr, uint16_t mem_add_size,
+                                  uint32_t timeout, uint32_t tick_start)
+{
+       i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE,
+                           I2C_GENERATE_START_WRITE);
+
+       if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
+               return -EIO;
+       }
+
+       if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
+               /* Send Memory Address */
+               mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+                            (uint8_t)(mem_addr & 0x00FFU));
+       } else {
+               /* Send MSB of Memory Address */
+               mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+                            (uint8_t)((mem_addr & 0xFF00U) >> 8));
+
+               /* Wait until TXIS flag is set */
+               if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
+                       return -EIO;
+               }
+
+               /* Send LSB of Memory Address */
+               mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+                            (uint8_t)(mem_addr & 0x00FFU));
+       }
+
+       if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout, tick_start) != 0) {
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * @brief  I2C Tx data register flush process.
+ * @param  hi2c: I2C handle.
+ * @retval None
+ */
+static void i2c_flush_txdr(struct i2c_handle_s *hi2c)
+{
+       /*
+        * If a pending TXIS flag is set,
+        * write a dummy data in TXDR to clear it.
+        */
+       if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) !=
+           0U) {
+               mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0);
+       }
+
+       /* Flush TX register if not empty */
+       if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) ==
+           0U) {
+               mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR,
+                               I2C_FLAG_TXE);
+       }
+}
+
+/*
+ * @brief  This function handles I2C Communication timeout.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  flag: Specifies the I2C flag to check.
+ * @param  awaited_value: The awaited bit value for the flag (0 or 1).
+ * @param  timeout: timeout duration
+ * @param  tick_start: Tick start value
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
+                        uint8_t awaited_value, uint32_t timeout,
+                        uint32_t tick_start)
+{
+       uint8_t flag_check;
+
+       do {
+               flag_check = ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+                              flag) == flag) ? 1U : 0U;
+
+               if (timeout != MAX_DELAY) {
+                       if ((((uint32_t)read_cntpct_el0() - tick_start) >
+                            timeout) || (timeout == 0U)) {
+                               hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
+                               hi2c->i2c_state = I2C_STATE_READY;
+                               hi2c->i2c_mode = I2C_MODE_NONE;
+
+                               hi2c->lock = 0;
+                               return -EIO;
+                       }
+               }
+       } while (flag_check == awaited_value);
+
+       return 0;
+}
+
+/*
+ * @brief  This function handles I2C Communication timeout for specific usage
+ *        of TXIS flag.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  timeout: timeout duration
+ * @param  tick_start: Tick start value
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout,
+                        uint32_t tick_start)
+{
+       while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+               I2C_FLAG_TXIS) == 0U) {
+               if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) {
+                       return -EIO;
+               }
+
+               if (timeout != MAX_DELAY) {
+                       if ((((uint32_t)read_cntpct_el0() - tick_start) >
+                            timeout) || (timeout == 0U)) {
+                               hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
+                               hi2c->i2c_state = I2C_STATE_READY;
+                               hi2c->i2c_mode = I2C_MODE_NONE;
+
+                               hi2c->lock = 0;
+
+                               return -EIO;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * @brief  This function handles I2C Communication timeout for specific
+ *        usage of STOP flag.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  timeout: timeout duration
+ * @param  tick_start: Tick start value
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout,
+                        uint32_t tick_start)
+{
+       while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+                I2C_FLAG_STOPF) == 0U) {
+               if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) {
+                       return -EIO;
+               }
+
+               if ((((uint32_t)read_cntpct_el0() - tick_start) > timeout) ||
+                   (timeout == 0U)) {
+                       hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
+                       hi2c->i2c_state = I2C_STATE_READY;
+                       hi2c->i2c_mode = I2C_MODE_NONE;
+
+                       hi2c->lock = 0;
+
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * @brief  This function handles Acknowledge failed detection during
+ *        an I2C Communication.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  timeout: timeout duration
+ * @param  tick_start: Tick start value
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout,
+                         uint32_t tick_start)
+{
+       if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) {
+               return 0;
+       }
+
+       /*
+        * Wait until STOP Flag is reset.
+        * AutoEnd should be initiate after AF.
+        */
+       while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+               I2C_FLAG_STOPF) == 0U) {
+               if (timeout != MAX_DELAY) {
+                       if ((((uint32_t)read_cntpct_el0() - tick_start) >
+                            timeout) || (timeout == 0U)) {
+                               hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
+                               hi2c->i2c_state = I2C_STATE_READY;
+                               hi2c->i2c_mode = I2C_MODE_NONE;
+
+                               hi2c->lock = 0;
+
+                               return -EIO;
+                       }
+               }
+       }
+
+       mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
+
+       mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+       i2c_flush_txdr(hi2c);
+
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
+
+       hi2c->i2c_err |= I2C_ERROR_AF;
+       hi2c->i2c_state = I2C_STATE_READY;
+       hi2c->i2c_mode = I2C_MODE_NONE;
+
+       hi2c->lock = 0;
+
+       return -EIO;
+}
+
+/*
+ * @brief  Handles I2Cx communication when starting transfer or during transfer
+ *        (TC or TCR flag are set).
+ * @param  hi2c: I2C handle.
+ * @param  dev_addr: Specifies the slave address to be programmed.
+ * @param  size: Specifies the number of bytes to be programmed.
+ *   This parameter must be a value between 0 and 255.
+ * @param  i2c_mode: New state of the I2C START condition generation.
+ *   This parameter can be one of the following values:
+ *     @arg @ref I2C_RELOAD_MODE: Enable Reload mode .
+ *     @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode.
+ *     @arg @ref I2C_SOFTEND_MODE: Enable Software end mode.
+ * @param  request: New state of the I2C START condition generation.
+ *   This parameter can be one of the following values:
+ *     @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition.
+ *     @arg @ref I2C_GENERATE_STOP: Generate stop condition
+ *                                  (size should be set to 0).
+ *     @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request.
+ *     @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request.
+ * @retval None
+ */
+static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                               uint16_t size, uint32_t i2c_mode,
+                               uint32_t request)
+{
+       uint32_t clr_value, set_value;
+
+       clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD |
+                    I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) |
+               (I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET)));
+
+       set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) |
+               (((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) |
+               i2c_mode | request;
+
+       mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value);
+}
+
+/*
+ * @brief  Configure I2C Analog noise filter.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2Cx peripheral
+ * @param  analog_filter: New state of the Analog filter.
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c,
+                                  uint32_t analog_filter)
+{
+       if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+               return -EBUSY;
+       }
+
+       hi2c->lock = 1;
+
+       hi2c->i2c_state = I2C_STATE_BUSY;
+
+       /* Disable the selected I2C peripheral */
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+       /* Reset I2Cx ANOFF bit */
+       mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF);
+
+       /* Set analog filter bit*/
+       mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter);
+
+       /* Enable the selected I2C peripheral */
+       mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+       hi2c->i2c_state = I2C_STATE_READY;
+
+       hi2c->lock = 0;
+
+       return 0;
+}
diff --git a/drivers/st/pmic/stm32mp1_pmic.c b/drivers/st/pmic/stm32mp1_pmic.c
new file mode 100644 (file)
index 0000000..958de08
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <mmio.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <stdbool.h>
+#include <stm32_gpio.h>
+#include <stm32mp1_clk.h>
+#include <stm32mp1_dt.h>
+#include <stm32mp1_pmic.h>
+#include <stpmu1.h>
+#include <utils_def.h>
+
+/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */
+#define I2C_TIMING                     0x10D07DB5
+
+#define I2C_TIMEOUT                    0xFFFFF
+
+#define MASK_RESET_BUCK3               BIT(2)
+
+#define STPMU1_LDO12356_OUTPUT_MASK    (uint8_t)(GENMASK(6, 2))
+#define STPMU1_LDO12356_OUTPUT_SHIFT   2
+#define STPMU1_LDO3_MODE               (uint8_t)(BIT(7))
+#define STPMU1_LDO3_DDR_SEL            31U
+#define STPMU1_LDO3_1800000            (9U << STPMU1_LDO12356_OUTPUT_SHIFT)
+
+#define STPMU1_BUCK_OUTPUT_SHIFT       2
+#define STPMU1_BUCK3_1V8               (39U << STPMU1_BUCK_OUTPUT_SHIFT)
+
+#define STPMU1_DEFAULT_START_UP_DELAY_MS       1
+
+static struct i2c_handle_s i2c_handle;
+static uint32_t pmic_i2c_addr;
+
+static int dt_get_pmic_node(void *fdt)
+{
+       return fdt_node_offset_by_compatible(fdt, -1, "st,stpmu1");
+}
+
+bool dt_check_pmic(void)
+{
+       int node;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return false;
+       }
+
+       node = dt_get_pmic_node(fdt);
+       if (node < 0) {
+               VERBOSE("%s: No PMIC node found in DT\n", __func__);
+               return false;
+       }
+
+       return fdt_check_status(node);
+}
+
+static int dt_pmic_i2c_config(struct dt_node_info *i2c_info)
+{
+       int pmic_node, i2c_node;
+       void *fdt;
+       const fdt32_t *cuint;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return -ENOENT;
+       }
+
+       pmic_node = dt_get_pmic_node(fdt);
+       if (pmic_node < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
+       if (cuint == NULL) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
+       if (pmic_i2c_addr > UINT16_MAX) {
+               return -EINVAL;
+       }
+
+       i2c_node = fdt_parent_offset(fdt, pmic_node);
+       if (i2c_node < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       dt_fill_device_info(i2c_info, i2c_node);
+       if (i2c_info->base == 0U) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       return dt_set_pinctrl_config(i2c_node);
+}
+
+int dt_pmic_enable_boot_on_regulators(void)
+{
+       int pmic_node, regulators_node, regulator_node;
+       void *fdt;
+
+       if (fdt_get_address(&fdt) == 0) {
+               return -ENOENT;
+       }
+
+       pmic_node = dt_get_pmic_node(fdt);
+       if (pmic_node < 0) {
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
+
+       fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
+               const fdt32_t *cuint;
+               const char *node_name;
+               uint16_t voltage;
+
+               if (fdt_getprop(fdt, regulator_node, "regulator-boot-on",
+                               NULL) == NULL) {
+                       continue;
+               }
+
+               cuint = fdt_getprop(fdt, regulator_node,
+                                   "regulator-min-microvolt", NULL);
+               if (cuint == NULL) {
+                       continue;
+               }
+
+               /* DT uses microvolts, whereas driver awaits millivolts */
+               voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+               node_name = fdt_get_name(fdt, regulator_node, NULL);
+
+               if (stpmu1_is_regulator_enabled(node_name) == 0U) {
+                       int status;
+
+                       status = stpmu1_regulator_voltage_set(node_name,
+                                                             voltage);
+                       if (status != 0) {
+                               return status;
+                       }
+
+                       status = stpmu1_regulator_enable(node_name);
+                       if (status != 0) {
+                               return status;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void initialize_pmic_i2c(void)
+{
+       int ret;
+       struct dt_node_info i2c_info;
+
+       if (dt_pmic_i2c_config(&i2c_info) != 0) {
+               ERROR("I2C configuration failed\n");
+               panic();
+       }
+
+       if (stm32mp1_clk_enable((uint32_t)i2c_info.clock) < 0) {
+               ERROR("I2C clock enable failed\n");
+               panic();
+       }
+
+       /* Initialize PMIC I2C */
+       i2c_handle.i2c_base_addr                = i2c_info.base;
+       i2c_handle.i2c_init.timing              = I2C_TIMING;
+       i2c_handle.i2c_init.own_address1        = pmic_i2c_addr;
+       i2c_handle.i2c_init.addressing_mode     = I2C_ADDRESSINGMODE_7BIT;
+       i2c_handle.i2c_init.dual_address_mode   = I2C_DUALADDRESS_DISABLE;
+       i2c_handle.i2c_init.own_address2        = 0;
+       i2c_handle.i2c_init.own_address2_masks  = I2C_OAR2_OA2NOMASK;
+       i2c_handle.i2c_init.general_call_mode   = I2C_GENERALCALL_DISABLE;
+       i2c_handle.i2c_init.no_stretch_mode     = I2C_NOSTRETCH_DISABLE;
+
+       ret = stm32_i2c_init(&i2c_handle);
+       if (ret != 0) {
+               ERROR("Cannot initialize I2C %x (%d)\n",
+                     i2c_handle.i2c_base_addr, ret);
+               panic();
+       }
+
+       ret = stm32_i2c_config_analog_filter(&i2c_handle,
+                                            I2C_ANALOGFILTER_ENABLE);
+       if (ret != 0) {
+               ERROR("Cannot initialize I2C analog filter (%d)\n", ret);
+               panic();
+       }
+
+       ret = stm32_i2c_is_device_ready(&i2c_handle, (uint16_t)pmic_i2c_addr, 1,
+                                       I2C_TIMEOUT);
+       if (ret != 0) {
+               ERROR("I2C device not ready (%d)\n", ret);
+               panic();
+       }
+
+       stpmu1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr);
+}
+
+void initialize_pmic(void)
+{
+       int status;
+       uint8_t read_val;
+
+       initialize_pmic_i2c();
+
+       status = stpmu1_register_read(VERSION_STATUS_REG, &read_val);
+       if (status != 0) {
+               panic();
+       }
+
+       INFO("PMIC version = 0x%x\n", read_val);
+
+       /* Keep VDD on during the reset cycle */
+       status = stpmu1_register_update(MASK_RESET_BUCK_REG,
+                                       MASK_RESET_BUCK3,
+                                       MASK_RESET_BUCK3);
+       if (status != 0) {
+               panic();
+       }
+}
+
+int pmic_ddr_power_init(enum ddr_type ddr_type)
+{
+       bool buck3_at_1v8 = false;
+       uint8_t read_val;
+       int status;
+
+       switch (ddr_type) {
+       case STM32MP_DDR3:
+               /* Set LDO3 to sync mode */
+               status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val);
+               if (status != 0) {
+                       return status;
+               }
+
+               read_val &= ~STPMU1_LDO3_MODE;
+               read_val &= ~STPMU1_LDO12356_OUTPUT_MASK;
+               read_val |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT;
+
+               status = stpmu1_register_write(LDO3_CONTROL_REG, read_val);
+               if (status != 0) {
+                       return status;
+               }
+
+               status = stpmu1_regulator_voltage_set("buck2", 1350);
+               if (status != 0) {
+                       return status;
+               }
+
+               status = stpmu1_regulator_enable("buck2");
+               if (status != 0) {
+                       return status;
+               }
+
+               mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+               status = stpmu1_regulator_enable("vref_ddr");
+               if (status != 0) {
+                       return status;
+               }
+
+               mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+               status = stpmu1_regulator_enable("ldo3");
+               if (status != 0) {
+                       return status;
+               }
+
+               mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+               break;
+
+       case STM32MP_LPDDR2:
+               /*
+                * Set LDO3 to 1.8V
+                * Set LDO3 to bypass mode if BUCK3 = 1.8V
+                * Set LDO3 to normal mode if BUCK3 != 1.8V
+                */
+               status = stpmu1_register_read(BUCK3_CONTROL_REG, &read_val);
+               if (status != 0) {
+                       return status;
+               }
+
+               if ((read_val & STPMU1_BUCK3_1V8) == STPMU1_BUCK3_1V8) {
+                       buck3_at_1v8 = true;
+               }
+
+               status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val);
+               if (status != 0) {
+                       return status;
+               }
+
+               read_val &= ~STPMU1_LDO3_MODE;
+               read_val &= ~STPMU1_LDO12356_OUTPUT_MASK;
+               read_val |= STPMU1_LDO3_1800000;
+               if (buck3_at_1v8) {
+                       read_val |= STPMU1_LDO3_MODE;
+               }
+
+               status = stpmu1_register_write(LDO3_CONTROL_REG, read_val);
+               if (status != 0) {
+                       return status;
+               }
+
+               status = stpmu1_regulator_voltage_set("buck2", 1200);
+               if (status != 0) {
+                       return status;
+               }
+
+               status = stpmu1_regulator_enable("ldo3");
+               if (status != 0) {
+                       return status;
+               }
+
+               mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+               status = stpmu1_regulator_enable("buck2");
+               if (status != 0) {
+                       return status;
+               }
+
+               mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+               status = stpmu1_regulator_enable("vref_ddr");
+               if (status != 0) {
+                       return status;
+               }
+
+               mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+               break;
+
+       default:
+               break;
+       };
+
+       return 0;
+}
diff --git a/drivers/st/pmic/stpmu1.c b/drivers/st/pmic/stpmu1.c
new file mode 100644 (file)
index 0000000..5951899
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <platform.h>
+#include <stpmu1.h>
+#include <string.h>
+
+struct regul_struct {
+       const char *dt_node_name;
+       const uint16_t *voltage_table;
+       uint8_t voltage_table_size;
+       uint8_t control_reg;
+       uint8_t low_power_reg;
+};
+
+static struct i2c_handle_s *stpmu_i2c_handle;
+static uint16_t stpmu_i2c_addr;
+
+/* Voltage tables in mV */
+static const uint16_t buck1_voltage_table[] = {
+       600,
+       625,
+       650,
+       675,
+       700,
+       725,
+       750,
+       775,
+       800,
+       825,
+       850,
+       875,
+       900,
+       925,
+       950,
+       975,
+       1000,
+       1025,
+       1050,
+       1075,
+       1100,
+       1125,
+       1150,
+       1175,
+       1200,
+       1225,
+       1250,
+       1275,
+       1300,
+       1325,
+       1350,
+       1350,
+};
+
+static const uint16_t buck2_voltage_table[] = {
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1050,
+       1050,
+       1100,
+       1100,
+       1150,
+       1150,
+       1200,
+       1200,
+       1250,
+       1250,
+       1300,
+       1300,
+       1350,
+       1350,
+       1400,
+       1400,
+       1450,
+       1450,
+       1500,
+};
+
+static const uint16_t buck3_voltage_table[] = {
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1000,
+       1100,
+       1100,
+       1100,
+       1100,
+       1200,
+       1200,
+       1200,
+       1200,
+       1300,
+       1300,
+       1300,
+       1300,
+       1400,
+       1400,
+       1400,
+       1400,
+       1500,
+       1600,
+       1700,
+       1800,
+       1900,
+       2000,
+       2100,
+       2200,
+       2300,
+       2400,
+       2500,
+       2600,
+       2700,
+       2800,
+       2900,
+       3000,
+       3100,
+       3200,
+       3300,
+       3400,
+};
+
+static const uint16_t buck4_voltage_table[] = {
+       600,
+       625,
+       650,
+       675,
+       700,
+       725,
+       750,
+       775,
+       800,
+       825,
+       850,
+       875,
+       900,
+       925,
+       950,
+       975,
+       1000,
+       1025,
+       1050,
+       1075,
+       1100,
+       1125,
+       1150,
+       1175,
+       1200,
+       1225,
+       1250,
+       1275,
+       1300,
+       1300,
+       1350,
+       1350,
+       1400,
+       1400,
+       1450,
+       1450,
+       1500,
+       1600,
+       1700,
+       1800,
+       1900,
+       2000,
+       2100,
+       2200,
+       2300,
+       2400,
+       2500,
+       2600,
+       2700,
+       2800,
+       2900,
+       3000,
+       3100,
+       3200,
+       3300,
+       3400,
+       3500,
+       3600,
+       3700,
+       3800,
+       3900,
+};
+
+static const uint16_t ldo1_voltage_table[] = {
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1800,
+       1900,
+       2000,
+       2100,
+       2200,
+       2300,
+       2400,
+       2500,
+       2600,
+       2700,
+       2800,
+       2900,
+       3000,
+       3100,
+       3200,
+       3300,
+};
+
+static const uint16_t ldo2_voltage_table[] = {
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1800,
+       1900,
+       2000,
+       2100,
+       2200,
+       2300,
+       2400,
+       2500,
+       2600,
+       2700,
+       2800,
+       2900,
+       3000,
+       3100,
+       3200,
+       3300,
+};
+
+static const uint16_t ldo3_voltage_table[] = {
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1800,
+       1900,
+       2000,
+       2100,
+       2200,
+       2300,
+       2400,
+       2500,
+       2600,
+       2700,
+       2800,
+       2900,
+       3000,
+       3100,
+       3200,
+       3300,
+       3300,
+       3300,
+       3300,
+       3300,
+       3300,
+       3300,
+       0xFFFF, /* VREFDDR */
+};
+
+static const uint16_t ldo5_voltage_table[] = {
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1700,
+       1800,
+       1900,
+       2000,
+       2100,
+       2200,
+       2300,
+       2400,
+       2500,
+       2600,
+       2700,
+       2800,
+       2900,
+       3000,
+       3100,
+       3200,
+       3300,
+       3400,
+       3500,
+       3600,
+       3700,
+       3800,
+       3900,
+};
+
+static const uint16_t ldo6_voltage_table[] = {
+       900,
+       1000,
+       1100,
+       1200,
+       1300,
+       1400,
+       1500,
+       1600,
+       1700,
+       1800,
+       1900,
+       2000,
+       2100,
+       2200,
+       2300,
+       2400,
+       2500,
+       2600,
+       2700,
+       2800,
+       2900,
+       3000,
+       3100,
+       3200,
+       3300,
+};
+
+static const uint16_t ldo4_voltage_table[] = {
+       3300,
+};
+
+static const uint16_t vref_ddr_voltage_table[] = {
+       3300,
+};
+
+/* Table of Regulators in PMIC SoC */
+static const struct regul_struct regulators_table[] = {
+       {
+               .dt_node_name   = "buck1",
+               .voltage_table  = buck1_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(buck1_voltage_table),
+               .control_reg    = BUCK1_CONTROL_REG,
+               .low_power_reg  = BUCK1_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "buck2",
+               .voltage_table  = buck2_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
+               .control_reg    = BUCK2_CONTROL_REG,
+               .low_power_reg  = BUCK2_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "buck3",
+               .voltage_table  = buck3_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
+               .control_reg    = BUCK3_CONTROL_REG,
+               .low_power_reg  = BUCK3_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "buck4",
+               .voltage_table  = buck4_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
+               .control_reg    = BUCK4_CONTROL_REG,
+               .low_power_reg  = BUCK4_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "ldo1",
+               .voltage_table  = ldo1_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
+               .control_reg    = LDO1_CONTROL_REG,
+               .low_power_reg  = LDO1_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "ldo2",
+               .voltage_table  = ldo2_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
+               .control_reg    = LDO2_CONTROL_REG,
+               .low_power_reg  = LDO2_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "ldo3",
+               .voltage_table  = ldo3_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
+               .control_reg    = LDO3_CONTROL_REG,
+               .low_power_reg  = LDO3_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "ldo4",
+               .voltage_table  = ldo4_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
+               .control_reg    = LDO4_CONTROL_REG,
+               .low_power_reg  = LDO4_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "ldo5",
+               .voltage_table  = ldo5_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
+               .control_reg    = LDO5_CONTROL_REG,
+               .low_power_reg  = LDO5_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "ldo6",
+               .voltage_table  = ldo6_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
+               .control_reg    = LDO6_CONTROL_REG,
+               .low_power_reg  = LDO6_PWRCTRL_REG,
+       },
+       {
+               .dt_node_name   = "vref_ddr",
+               .voltage_table  = vref_ddr_voltage_table,
+               .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
+               .control_reg    = VREF_DDR_CONTROL_REG,
+               .low_power_reg  = VREF_DDR_PWRCTRL_REG,
+       },
+};
+
+#define MAX_REGUL  ARRAY_SIZE(regulators_table)
+
+static const struct regul_struct *stpmu1_get_regulator_data(const char *name)
+{
+       uint8_t i;
+
+       for (i = 0 ; i < MAX_REGUL ; i++) {
+               if (strncmp(name, regulators_table[i].dt_node_name,
+                           strlen(regulators_table[i].dt_node_name)) == 0) {
+                       return &regulators_table[i];
+               }
+       }
+
+       /* Regulator not found */
+       panic();
+       return NULL;
+}
+
+static uint8_t stpmu1_voltage_find_index(const char *name,
+                                        uint16_t millivolts)
+{
+       const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+       uint8_t i;
+
+       for (i = 0 ; i < regul->voltage_table_size ; i++) {
+               if (regul->voltage_table[i] == millivolts) {
+                       return i;
+               }
+       }
+
+       /* Voltage not found */
+       panic();
+
+       return 0;
+}
+
+int stpmu1_switch_off(void)
+{
+       return stpmu1_register_update(MAIN_CONTROL_REG, 1,
+                                     SOFTWARE_SWITCH_OFF_ENABLED);
+}
+
+int stpmu1_regulator_enable(const char *name)
+{
+       const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+
+       return stpmu1_register_update(regul->control_reg, BIT(0), BIT(0));
+}
+
+int stpmu1_regulator_disable(const char *name)
+{
+       const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+
+       return stpmu1_register_update(regul->control_reg, 0, BIT(0));
+}
+
+uint8_t stpmu1_is_regulator_enabled(const char *name)
+{
+       uint8_t val;
+       const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+
+       if (stpmu1_register_read(regul->control_reg, &val) != 0) {
+               panic();
+       }
+
+       return (val & 0x1U);
+}
+
+int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts)
+{
+       uint8_t voltage_index = stpmu1_voltage_find_index(name, millivolts);
+       const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+
+       return stpmu1_register_update(regul->control_reg, voltage_index << 2,
+                                     0xFC);
+}
+
+int stpmu1_register_read(uint8_t register_id,  uint8_t *value)
+{
+       return stm32_i2c_mem_read(stpmu_i2c_handle, stpmu_i2c_addr,
+                                   (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT,
+                                   value, 1, 100000);
+}
+
+int stpmu1_register_write(uint8_t register_id, uint8_t value)
+{
+       int status;
+
+       status = stm32_i2c_mem_write(stpmu_i2c_handle, stpmu_i2c_addr,
+                                    (uint16_t)register_id,
+                                    I2C_MEMADD_SIZE_8BIT, &value, 1, 100000);
+
+       if (status != 0) {
+               return status;
+       }
+
+       if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) {
+               uint8_t readval;
+
+               status = stpmu1_register_read(register_id, &readval);
+               if (status != 0) {
+                       return status;
+               }
+
+               if (readval != value) {
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask)
+{
+       int status;
+       uint8_t val;
+
+       status = stpmu1_register_read(register_id, &val);
+       if (status != 0) {
+               return status;
+       }
+
+       /* Clear bits to update */
+       val &= ~mask;
+
+       /* Update appropriate bits*/
+       val |= (value & mask);
+
+       /* Send new value on I2C Bus */
+       return stpmu1_register_write(register_id, val);
+}
+
+void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr)
+{
+       stpmu_i2c_handle = i2c_handle;
+       stpmu_i2c_addr = i2c_addr;
+}
diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h
new file mode 100644 (file)
index 0000000..29b9d34
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __STM32MP1_I2C_H
+#define __STM32MP1_I2C_H
+
+#include <stdint.h>
+#include <utils_def.h>
+
+/* Bit definition for I2C_CR1 register */
+#define I2C_CR1_PE                     BIT(0)
+#define I2C_CR1_TXIE                   BIT(1)
+#define I2C_CR1_RXIE                   BIT(2)
+#define I2C_CR1_ADDRIE                 BIT(3)
+#define I2C_CR1_NACKIE                 BIT(4)
+#define I2C_CR1_STOPIE                 BIT(5)
+#define I2C_CR1_TCIE                   BIT(6)
+#define I2C_CR1_ERRIE                  BIT(7)
+#define I2C_CR1_DNF                    GENMASK(11, 8)
+#define I2C_CR1_ANFOFF                 BIT(12)
+#define I2C_CR1_SWRST                  BIT(13)
+#define I2C_CR1_TXDMAEN                        BIT(14)
+#define I2C_CR1_RXDMAEN                        BIT(15)
+#define I2C_CR1_SBC                    BIT(16)
+#define I2C_CR1_NOSTRETCH              BIT(17)
+#define I2C_CR1_WUPEN                  BIT(18)
+#define I2C_CR1_GCEN                   BIT(19)
+#define I2C_CR1_SMBHEN                 BIT(22)
+#define I2C_CR1_SMBDEN                 BIT(21)
+#define I2C_CR1_ALERTEN                        BIT(22)
+#define I2C_CR1_PECEN                  BIT(23)
+
+/* Bit definition for I2C_CR2 register */
+#define I2C_CR2_SADD                   GENMASK(9, 0)
+#define I2C_CR2_RD_WRN                 BIT(10)
+#define I2C_CR2_RD_WRN_OFFSET          10U
+#define I2C_CR2_ADD10                  BIT(11)
+#define I2C_CR2_HEAD10R                        BIT(12)
+#define I2C_CR2_START                  BIT(13)
+#define I2C_CR2_STOP                   BIT(14)
+#define I2C_CR2_NACK                   BIT(15)
+#define I2C_CR2_NBYTES                 GENMASK(23, 16)
+#define I2C_CR2_NBYTES_OFFSET          16U
+#define I2C_CR2_RELOAD                 BIT(24)
+#define I2C_CR2_AUTOEND                        BIT(25)
+#define I2C_CR2_PECBYTE                        BIT(26)
+
+/* Bit definition for I2C_OAR1 register */
+#define I2C_OAR1_OA1                   GENMASK(9, 0)
+#define I2C_OAR1_OA1MODE               BIT(10)
+#define I2C_OAR1_OA1EN                 BIT(15)
+
+/* Bit definition for I2C_OAR2 register */
+#define I2C_OAR2_OA2                   GENMASK(7, 1)
+#define I2C_OAR2_OA2MSK                        GENMASK(10, 8)
+#define I2C_OAR2_OA2NOMASK             0
+#define I2C_OAR2_OA2MASK01             BIT(8)
+#define I2C_OAR2_OA2MASK02             BIT(9)
+#define I2C_OAR2_OA2MASK03             GENMASK(9, 8)
+#define I2C_OAR2_OA2MASK04             BIT(10)
+#define I2C_OAR2_OA2MASK05             (BIT(8) | BIT(10))
+#define I2C_OAR2_OA2MASK06             (BIT(9) | BIT(10))
+#define I2C_OAR2_OA2MASK07             GENMASK(10, 8)
+#define I2C_OAR2_OA2EN                 BIT(15)
+
+/* Bit definition for I2C_TIMINGR register */
+#define I2C_TIMINGR_SCLL               GENMASK(7, 0)
+#define I2C_TIMINGR_SCLH               GENMASK(15, 8)
+#define I2C_TIMINGR_SDADEL             GENMASK(19, 16)
+#define I2C_TIMINGR_SCLDEL             GENMASK(23, 20)
+#define I2C_TIMINGR_PRESC              GENMASK(31, 28)
+
+/* Bit definition for I2C_TIMEOUTR register */
+#define I2C_TIMEOUTR_TIMEOUTA          GENMASK(11, 0)
+#define I2C_TIMEOUTR_TIDLE             BIT(12)
+#define I2C_TIMEOUTR_TIMOUTEN          BIT(15)
+#define I2C_TIMEOUTR_TIMEOUTB          GENMASK(27, 16)
+#define I2C_TIMEOUTR_TEXTEN            BIT(31)
+
+/* Bit definition for I2C_ISR register */
+#define I2C_ISR_TXE                    BIT(0)
+#define I2C_ISR_TXIS                   BIT(1)
+#define I2C_ISR_RXNE                   BIT(2)
+#define I2C_ISR_ADDR                   BIT(3)
+#define I2C_ISR_NACKF                  BIT(4)
+#define I2C_ISR_STOPF                  BIT(5)
+#define I2C_ISR_TC                     BIT(6)
+#define I2C_ISR_TCR                    BIT(7)
+#define I2C_ISR_BERR                   BIT(8)
+#define I2C_ISR_ARLO                   BIT(9)
+#define I2C_ISR_OVR                    BIT(10)
+#define I2C_ISR_PECERR                 BIT(11)
+#define I2C_ISR_TIMEOUT                        BIT(12)
+#define I2C_ISR_ALERT                  BIT(13)
+#define I2C_ISR_BUSY                   BIT(15)
+#define I2C_ISR_DIR                    BIT(16)
+#define I2C_ISR_ADDCODE                        GENMASK(23, 17)
+
+/* Bit definition for I2C_ICR register */
+#define I2C_ICR_ADDRCF                 BIT(3)
+#define I2C_ICR_NACKCF                 BIT(4)
+#define I2C_ICR_STOPCF                 BIT(5)
+#define I2C_ICR_BERRCF                 BIT(8)
+#define I2C_ICR_ARLOCF                 BIT(9)
+#define I2C_ICR_OVRCF                  BIT(10)
+#define I2C_ICR_PECCF                  BIT(11)
+#define I2C_ICR_TIMOUTCF               BIT(12)
+#define I2C_ICR_ALERTCF                        BIT(13)
+
+struct stm32_i2c_init_s {
+       uint32_t timing;           /* Specifies the I2C_TIMINGR_register value
+                                   * This parameter is calculated by referring
+                                   * to I2C initialization section in Reference
+                                   * manual.
+                                   */
+
+       uint32_t own_address1;     /* Specifies the first device own address.
+                                   * This parameter can be a 7-bit or 10-bit
+                                   * address.
+                                   */
+
+       uint32_t addressing_mode;  /* Specifies if 7-bit or 10-bit addressing
+                                   * mode is selected.
+                                   * This parameter can be a value of @ref
+                                   * I2C_ADDRESSING_MODE.
+                                   */
+
+       uint32_t dual_address_mode; /* Specifies if dual addressing mode is
+                                    * selected.
+                                    * This parameter can be a value of @ref
+                                    * I2C_DUAL_ADDRESSING_MODE.
+                                    */
+
+       uint32_t own_address2;     /* Specifies the second device own address
+                                   * if dual addressing mode is selected.
+                                   * This parameter can be a 7-bit address.
+                                   */
+
+       uint32_t own_address2_masks; /* Specifies the acknowledge mask address
+                                     * second device own address if dual
+                                     * addressing mode is selected.
+                                     * This parameter can be a value of @ref
+                                     * I2C_OWN_ADDRESS2_MASKS.
+                                     */
+
+       uint32_t general_call_mode; /* Specifies if general call mode is
+                                    * selected.
+                                    * This parameter can be a value of @ref
+                                    * I2C_GENERAL_CALL_ADDRESSING_MODE.
+                                    */
+
+       uint32_t no_stretch_mode;  /* Specifies if nostretch mode is
+                                   * selected.
+                                   * This parameter can be a value of @ref
+                                   * I2C_NOSTRETCH_MODE.
+                                   */
+
+};
+
+enum i2c_state_e {
+       I2C_STATE_RESET          = 0x00U,   /* Peripheral is not yet
+                                            * initialized.
+                                            */
+       I2C_STATE_READY          = 0x20U,   /* Peripheral Initialized
+                                            * and ready for use.
+                                            */
+       I2C_STATE_BUSY           = 0x24U,   /* An internal process is
+                                            * ongoing.
+                                            */
+       I2C_STATE_BUSY_TX        = 0x21U,   /* Data Transmission process
+                                            * is ongoing.
+                                            */
+       I2C_STATE_BUSY_RX        = 0x22U,   /* Data Reception process
+                                            * is ongoing.
+                                            */
+       I2C_STATE_LISTEN         = 0x28U,   /* Address Listen Mode is
+                                            * ongoing.
+                                            */
+       I2C_STATE_BUSY_TX_LISTEN = 0x29U,   /* Address Listen Mode
+                                            * and Data Transmission
+                                            * process is ongoing.
+                                            */
+       I2C_STATE_BUSY_RX_LISTEN = 0x2AU,   /* Address Listen Mode
+                                            * and Data Reception
+                                            * process is ongoing.
+                                            */
+       I2C_STATE_ABORT          = 0x60U,   /* Abort user request ongoing. */
+       I2C_STATE_TIMEOUT        = 0xA0U,   /* Timeout state. */
+       I2C_STATE_ERROR          = 0xE0U    /* Error. */
+
+};
+
+enum i2c_mode_e {
+       I2C_MODE_NONE   = 0x00U,   /* No I2C communication on going.       */
+       I2C_MODE_MASTER = 0x10U,   /* I2C communication is in Master Mode. */
+       I2C_MODE_SLAVE  = 0x20U,   /* I2C communication is in Slave Mode.  */
+       I2C_MODE_MEM    = 0x40U    /* I2C communication is in Memory Mode. */
+
+};
+
+#define I2C_ERROR_NONE         0x00000000U     /* No error              */
+#define I2C_ERROR_BERR         0x00000001U     /* BERR error            */
+#define I2C_ERROR_ARLO         0x00000002U     /* ARLO error            */
+#define I2C_ERROR_AF           0x00000004U     /* ACKF error            */
+#define I2C_ERROR_OVR          0x00000008U     /* OVR error             */
+#define I2C_ERROR_DMA          0x00000010U     /* DMA transfer error    */
+#define I2C_ERROR_TIMEOUT      0x00000020U     /* Timeout error         */
+#define I2C_ERROR_SIZE         0x00000040U     /* Size Management error */
+
+struct i2c_handle_s {
+       uint32_t i2c_base_addr;                 /* Registers base address */
+
+       struct stm32_i2c_init_s i2c_init;       /* Communication parameters */
+
+       uint8_t *p_buff;                        /* Pointer to transfer buffer */
+
+       uint16_t xfer_size;                     /* Transfer size */
+
+       uint16_t xfer_count;                    /* Transfer counter */
+
+       uint32_t prev_state;                    /* Communication previous
+                                                * state
+                                                */
+
+       uint8_t lock;                           /* Locking object */
+
+       enum i2c_state_e i2c_state;             /* Communication state */
+
+       enum i2c_mode_e i2c_mode;               /* Communication mode */
+
+       uint32_t i2c_err;                       /* Error code */
+};
+
+#define I2C_ADDRESSINGMODE_7BIT                0x00000001U
+#define I2C_ADDRESSINGMODE_10BIT       0x00000002U
+
+#define I2C_DUALADDRESS_DISABLE                0x00000000U
+#define I2C_DUALADDRESS_ENABLE         I2C_OAR2_OA2EN
+
+#define I2C_GENERALCALL_DISABLE                0x00000000U
+#define I2C_GENERALCALL_ENABLE         I2C_CR1_GCEN
+
+#define I2C_NOSTRETCH_DISABLE          0x00000000U
+#define I2C_NOSTRETCH_ENABLE           I2C_CR1_NOSTRETCH
+
+#define I2C_MEMADD_SIZE_8BIT           0x00000001U
+#define I2C_MEMADD_SIZE_16BIT          0x00000002U
+
+#define  I2C_RELOAD_MODE               I2C_CR2_RELOAD
+#define  I2C_AUTOEND_MODE              I2C_CR2_AUTOEND
+#define  I2C_SOFTEND_MODE              0x00000000U
+
+#define  I2C_NO_STARTSTOP              0x00000000U
+#define  I2C_GENERATE_STOP             (BIT(31) | I2C_CR2_STOP)
+#define  I2C_GENERATE_START_READ       (BIT(31) | I2C_CR2_START | \
+                                        I2C_CR2_RD_WRN)
+#define  I2C_GENERATE_START_WRITE      (BIT(31) | I2C_CR2_START)
+
+#define I2C_FLAG_TXE                   I2C_ISR_TXE
+#define I2C_FLAG_TXIS                  I2C_ISR_TXIS
+#define I2C_FLAG_RXNE                  I2C_ISR_RXNE
+#define I2C_FLAG_ADDR                  I2C_ISR_ADDR
+#define I2C_FLAG_AF                    I2C_ISR_NACKF
+#define I2C_FLAG_STOPF                 I2C_ISR_STOPF
+#define I2C_FLAG_TC                    I2C_ISR_TC
+#define I2C_FLAG_TCR                   I2C_ISR_TCR
+#define I2C_FLAG_BERR                  I2C_ISR_BERR
+#define I2C_FLAG_ARLO                  I2C_ISR_ARLO
+#define I2C_FLAG_OVR                   I2C_ISR_OVR
+#define I2C_FLAG_PECERR                        I2C_ISR_PECERR
+#define I2C_FLAG_TIMEOUT               I2C_ISR_TIMEOUT
+#define I2C_FLAG_ALERT                 I2C_ISR_ALERT
+#define I2C_FLAG_BUSY                  I2C_ISR_BUSY
+#define I2C_FLAG_DIR                   I2C_ISR_DIR
+
+#define I2C_RESET_CR2                  (I2C_CR2_SADD | I2C_CR2_HEAD10R | \
+                                        I2C_CR2_NBYTES | I2C_CR2_RELOAD  | \
+                                        I2C_CR2_RD_WRN)
+
+#define I2C_ANALOGFILTER_ENABLE                ((uint32_t)0x00000000U)
+#define I2C_ANALOGFILTER_DISABLE       I2C_CR1_ANFOFF
+
+int stm32_i2c_init(struct i2c_handle_s *hi2c);
+
+int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                       uint16_t mem_addr, uint16_t mem_add_size,
+                       uint8_t *p_data, uint16_t size, uint32_t timeout);
+int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                      uint16_t mem_addr, uint16_t mem_add_size,
+                      uint8_t *p_data, uint16_t size, uint32_t timeout);
+int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+                             uint32_t trials, uint32_t timeout);
+
+int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c,
+                                  uint32_t analog_filter);
+
+#endif /* __STM32MP1_I2C_H */
diff --git a/include/drivers/st/stm32mp1_pmic.h b/include/drivers/st/stm32mp1_pmic.h
new file mode 100644 (file)
index 0000000..5d94b40
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __STM32MP1_PMIC_H__
+#define __STM32MP1_PMIC_H__
+
+#include <stdbool.h>
+
+bool dt_check_pmic(void);
+int dt_pmic_enable_boot_on_regulators(void);
+void initialize_pmic_i2c(void);
+void initialize_pmic(void);
+int pmic_ddr_power_init(enum ddr_type ddr_type);
+
+#endif /* __STM32MP1_PMIC_H__ */
diff --git a/include/drivers/st/stpmu1.h b/include/drivers/st/stpmu1.h
new file mode 100644 (file)
index 0000000..1b93ab2
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef __STPMU1_H__
+#define __STPMU1_H__
+
+#include <stm32_i2c.h>
+#include <utils_def.h>
+
+#define TURN_ON_REG                    0x1U
+#define TURN_OFF_REG                   0x2U
+#define ICC_LDO_TURN_OFF_REG           0x3U
+#define ICC_BUCK_TURN_OFF_REG          0x4U
+#define RESET_STATUS_REG               0x5U
+#define VERSION_STATUS_REG             0x6U
+#define MAIN_CONTROL_REG               0x10U
+#define PADS_PULL_REG                  0x11U
+#define BUCK_PULL_DOWN_REG             0x12U
+#define LDO14_PULL_DOWN_REG            0x13U
+#define LDO56_PULL_DOWN_REG            0x14U
+#define VIN_CONTROL_REG                        0x15U
+#define PONKEY_TIMER_REG               0x16U
+#define MASK_RANK_BUCK_REG             0x17U
+#define MASK_RESET_BUCK_REG            0x18U
+#define MASK_RANK_LDO_REG              0x19U
+#define MASK_RESET_LDO_REG             0x1AU
+#define WATCHDOG_CONTROL_REG           0x1BU
+#define WATCHDOG_TIMER_REG             0x1CU
+#define BUCK_ICC_TURNOFF_REG           0x1DU
+#define LDO_ICC_TURNOFF_REG            0x1EU
+#define BUCK_APM_CONTROL_REG           0x1FU
+#define BUCK1_CONTROL_REG              0x20U
+#define BUCK2_CONTROL_REG              0x21U
+#define BUCK3_CONTROL_REG              0x22U
+#define BUCK4_CONTROL_REG              0x23U
+#define VREF_DDR_CONTROL_REG           0x24U
+#define LDO1_CONTROL_REG               0x25U
+#define LDO2_CONTROL_REG               0x26U
+#define LDO3_CONTROL_REG               0x27U
+#define LDO4_CONTROL_REG               0x28U
+#define LDO5_CONTROL_REG               0x29U
+#define LDO6_CONTROL_REG               0x2AU
+#define BUCK1_PWRCTRL_REG              0x30U
+#define BUCK2_PWRCTRL_REG              0x31U
+#define BUCK3_PWRCTRL_REG              0x32U
+#define BUCK4_PWRCTRL_REG              0x33U
+#define VREF_DDR_PWRCTRL_REG           0x34U
+#define LDO1_PWRCTRL_REG               0x35U
+#define LDO2_PWRCTRL_REG               0x36U
+#define LDO3_PWRCTRL_REG               0x37U
+#define LDO4_PWRCTRL_REG               0x38U
+#define LDO5_PWRCTRL_REG               0x39U
+#define LDO6_PWRCTRL_REG               0x3AU
+#define FREQUENCY_SPREADING_REG                0x3BU
+#define USB_CONTROL_REG                        0x40U
+#define ITLATCH1_REG                   0x50U
+#define ITLATCH2_REG                   0x51U
+#define ITLATCH3_REG                   0x52U
+#define ITLATCH4_REG                   0x53U
+#define ITSETLATCH1_REG                        0x60U
+#define ITSETLATCH2_REG                        0x61U
+#define ITSETLATCH3_REG                        0x62U
+#define ITSETLATCH4_REG                        0x63U
+#define ITCLEARLATCH1_REG              0x70U
+#define ITCLEARLATCH2_REG              0x71U
+#define ITCLEARLATCH3_REG              0x72U
+#define ITCLEARLATCH4_REG              0x73U
+#define ITMASK1_REG                    0x80U
+#define ITMASK2_REG                    0x81U
+#define ITMASK3_REG                    0x82U
+#define ITMASK4_REG                    0x83U
+#define ITSETMASK1_REG                 0x90U
+#define ITSETMASK2_REG                 0x91U
+#define ITSETMASK3_REG                 0x92U
+#define ITSETMASK4_REG                 0x93U
+#define ITCLEARMASK1_REG               0xA0U
+#define ITCLEARMASK2_REG               0xA1U
+#define ITCLEARMASK3_REG               0xA2U
+#define ITCLEARMASK4_REG               0xA3U
+#define ITSOURCE1_REG                  0xB0U
+#define ITSOURCE2_REG                  0xB1U
+#define ITSOURCE3_REG                  0xB2U
+#define ITSOURCE4_REG                  0xB3U
+#define LDO_VOLTAGE_MASK               0x7CU
+#define BUCK_VOLTAGE_MASK              0xFCU
+#define LDO_BUCK_VOLTAGE_SHIFT         2
+#define LDO_ENABLE_MASK                        0x01U
+#define BUCK_ENABLE_MASK               0x01U
+#define BUCK_HPLP_ENABLE_MASK          0x02U
+#define LDO_HPLP_ENABLE_MASK           0x02U
+#define LDO_BUCK_HPLP_SHIFT            1
+#define LDO_BUCK_RANK_MASK             0x01U
+#define LDO_BUCK_RESET_MASK            0x01U
+#define LDO_BUCK_PULL_DOWN_MASK                0x03U
+
+/* Main PMIC Control Register (MAIN_CONTROL_REG) */
+#define ICC_EVENT_ENABLED              BIT(4)
+#define PWRCTRL_POLARITY_HIGH          BIT(3)
+#define PWRCTRL_PIN_VALID              BIT(2)
+#define RESTART_REQUEST_ENABLED                BIT(1)
+#define SOFTWARE_SWITCH_OFF_ENABLED    BIT(0)
+
+/* Main PMIC PADS Control Register (PADS_PULL_REG) */
+#define WAKEUP_DETECTOR_DISABLED       BIT(4)
+#define PWRCTRL_PD_ACTIVE              BIT(3)
+#define PWRCTRL_PU_ACTIVE              BIT(2)
+#define WAKEUP_PD_ACTIVE               BIT(1)
+#define PONKEY_PU_ACTIVE               BIT(0)
+
+/* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */
+#define SWIN_DETECTOR_ENABLED          BIT(7)
+#define SWOUT_DETECTOR_ENABLED          BIT(6)
+#define VINLOW_HYST_MASK               0x3
+#define VINLOW_HYST_SHIFT              4
+#define VINLOW_THRESHOLD_MASK          0x7
+#define VINLOW_THRESHOLD_SHIFT         1
+#define VINLOW_ENABLED                 0x01
+#define VINLOW_CTRL_REG_MASK           0xFF
+
+/* USB Control Register */
+#define BOOST_OVP_DISABLED             BIT(7)
+#define VBUS_OTG_DETECTION_DISABLED    BIT(6)
+#define OCP_LIMIT_HIGH                 BIT(3)
+#define SWIN_SWOUT_ENABLED             BIT(2)
+#define USBSW_OTG_SWITCH_ENABLED       BIT(1)
+
+int stpmu1_switch_off(void);
+int stpmu1_register_read(uint8_t register_id, uint8_t *value);
+int stpmu1_register_write(uint8_t register_id, uint8_t value);
+int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask);
+int stpmu1_regulator_enable(const char *name);
+int stpmu1_regulator_disable(const char *name);
+uint8_t stpmu1_is_regulator_enabled(const char *name);
+int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts);
+void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr);
+
+#endif /* __STPMU1_H__ */
index 97abdc4774d9ac269c4f3be1487b46e97838988e..84484e13ffaf5d24beb8b403002bdcbfa79f5602 100644 (file)
@@ -18,6 +18,7 @@
 #include <platform_def.h>
 #include <stm32mp1_clk.h>
 #include <stm32mp1_dt.h>
+#include <stm32mp1_pmic.h>
 #include <stm32mp1_private.h>
 #include <stm32mp1_context.h>
 #include <stm32mp1_pwr.h>
@@ -34,6 +35,10 @@ void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1,
 
 void bl2_platform_setup(void)
 {
+       if (dt_check_pmic()) {
+               initialize_pmic();
+       }
+
        INFO("BL2 runs SP_MIN setup\n");
 }
 
index 9c97f726ee2d90a40942124571cac98fe762f25c..bd74d0f9fe0d7632da2aaa7599331a5a3b34ee54 100644 (file)
@@ -42,6 +42,9 @@ PLAT_BL_COMMON_SOURCES        +=      ${LIBFDT_SRCS}                                          \
                                drivers/st/clk/stm32mp1_clk.c                           \
                                drivers/st/clk/stm32mp1_clkfunc.c                       \
                                drivers/st/gpio/stm32_gpio.c                            \
+                               drivers/st/pmic/stm32_i2c.c                             \
+                               drivers/st/pmic/stm32mp1_pmic.c                         \
+                               drivers/st/pmic/stpmu1.c                                \
                                drivers/st/reset/stm32mp1_reset.c                       \
                                plat/st/stm32mp1/stm32mp1_context.c                     \
                                plat/st/stm32mp1/stm32mp1_dt.c                          \