Nitheesh Sekar has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/32546
Change subject: qcom: Add i2c driver ......................................................................
qcom: Add i2c driver
Add i2c driver in coreboot.
Change-Id: I3d39d0325718fc5dd60da42eb2b87dcc4429bfc2 Signed-off-by: Prudhvi Yarlagadda pyarlaga@codeaurora.org Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org --- M src/soc/qualcomm/qcs405/Makefile.inc A src/soc/qualcomm/qcs405/blsp.c A src/soc/qualcomm/qcs405/i2c.c A src/soc/qualcomm/qcs405/qup.c 4 files changed, 866 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/46/32546/1
diff --git a/src/soc/qualcomm/qcs405/Makefile.inc b/src/soc/qualcomm/qcs405/Makefile.inc index c64e5bc..0ebfcae 100644 --- a/src/soc/qualcomm/qcs405/Makefile.inc +++ b/src/soc/qualcomm/qcs405/Makefile.inc @@ -8,6 +8,9 @@ bootblock-y += mmu.c bootblock-y += gpio.c bootblock-y += clock.c +bootblock-y += i2c.c +bootblock-y += qup.c +bootblock-y += blsp.c bootblock-$(CONFIG_DRIVERS_UART) += uart.c
################################################################################ @@ -15,6 +18,9 @@ verstage-y += spi.c verstage-y += gpio.c verstage-y += clock.c +verstage-y += i2c.c +verstage-y += qup.c +verstage-y += blsp.c verstage-$(CONFIG_DRIVERS_UART) += uart.c
################################################################################ @@ -25,6 +31,9 @@ romstage-y += clock.c romstage-y += usb.c romstage-$(CONFIG_DRIVERS_UART) += uart.c +romstage-y += i2c.c +romstage-y += qup.c +romstage-y += blsp.c
################################################################################ ramstage-y += soc.c @@ -33,6 +42,9 @@ ramstage-y += cbmem.c ramstage-y += gpio.c ramstage-y += clock.c +ramstage-y += i2c.c +ramstage-y += qup.c +ramstage-y += blsp.c ramstage-y += usb.c ramstage-$(CONFIG_DRIVERS_UART) += uart.c
diff --git a/src/soc/qualcomm/qcs405/blsp.c b/src/soc/qualcomm/qcs405/blsp.c new file mode 100644 index 0000000..eb27ce2 --- /dev/null +++ b/src/soc/qualcomm/qcs405/blsp.c @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2016, 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <device/mmio.h> +#include <soc/blsp.h> +#include <soc/gpio.h> +#include <soc/iomap.h> +#include <soc/clock.h> + +blsp_return_t blsp_i2c_init(blsp_qup_id_t id) +{ + void *base = blsp_qup_base(id); + + if (!base) + return BLSP_ID_ERROR; + + clock_configure_i2c(19200000); + clock_enable_i2c(); + + switch (id) { + case BLSP_QUP_ID_1: + gpio_configure + (GPIO(24), 2, GPIO_PULL_UP, GPIO_2MA, GPIO_OUTPUT); + gpio_configure + (GPIO(25), 2, GPIO_PULL_UP, GPIO_2MA, GPIO_OUTPUT); + break; + default: + return 1; + } + + /* Configure Mini core to I2C core */ + clrsetbits_le32(base, BLSP_MINI_CORE_MASK, BLSP_MINI_CORE_I2C); + + return BLSP_SUCCESS; +} diff --git a/src/soc/qualcomm/qcs405/i2c.c b/src/soc/qualcomm/qcs405/i2c.c new file mode 100644 index 0000000..4e5f215 --- /dev/null +++ b/src/soc/qualcomm/qcs405/i2c.c @@ -0,0 +1,181 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015, 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <console/console.h> +#include <delay.h> +#include <device/i2c_simple.h> +#include <stdlib.h> +#include <string.h> +#include <soc/blsp.h> +#include <soc/qup.h> +#include <soc/gpio.h> + +static qup_config_t blsp1_qup0_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static qup_config_t blsp1_qup1_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static qup_config_t blsp1_qup2_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static qup_config_t blsp1_qup3_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static int i2c_read(uint32_t gsbi_id, uint8_t slave, + uint8_t *data, int data_len) +{ + qup_data_t obj; + qup_return_t qup_ret = 0; + + memset(&obj, 0, sizeof(obj)); + obj.protocol = QUP_MINICORE_I2C_MASTER; + obj.p.iic.addr = slave; + obj.p.iic.data_len = data_len; + obj.p.iic.data = data; + qup_ret = qup_recv_data(gsbi_id, &obj); + + if (QUP_SUCCESS != qup_ret) + return 1; + else + return 0; +} + +static int i2c_write(uint32_t gsbi_id, uint8_t slave, + uint8_t *data, int data_len, uint8_t stop_seq) +{ + qup_data_t obj; + qup_return_t qup_ret = 0; + + memset(&obj, 0, sizeof(obj)); + obj.protocol = QUP_MINICORE_I2C_MASTER; + obj.p.iic.addr = slave; + obj.p.iic.data_len = data_len; + obj.p.iic.data = data; + qup_ret = qup_send_data(gsbi_id, &obj, stop_seq); + + if (QUP_SUCCESS != qup_ret) + return 1; + else + return 0; +} + +static int i2c_init(blsp_qup_id_t id) +{ + qup_config_t *qup_config; + + switch (id) { + case BLSP_QUP_ID_0: + qup_config = &blsp1_qup0_config; + break; + case BLSP_QUP_ID_1: + qup_config = &blsp1_qup1_config; + break; + case BLSP_QUP_ID_2: + qup_config = &blsp1_qup2_config; + break; + case BLSP_QUP_ID_3: + qup_config = &blsp1_qup3_config; + break; + default: + printk(BIOS_ERR, "QUP configuration not defined for BLSP%d.\n", + id); + return 1; + } + + if (qup_config->initialized) + return 0; + + if (blsp_i2c_init(id)) { + printk(BIOS_ERR, "failed to initialize blsp\n"); + return 1; + } + + if (qup_init(id, qup_config)) { + printk(BIOS_ERR, "failed to initialize qup\n"); + return 1; + } + + if (qup_reset_i2c_master_status(id)) { + printk(BIOS_ERR, "failed to reset i2c master status\n"); + return 1; + } + + qup_config->initialized = 1; + return 0; +} + +int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, + int seg_count) +{ + struct i2c_msg *seg = segments; + int ret = 0; + + if (i2c_init(bus)) + return 1; + + while (!ret && seg_count--) { + if (seg->flags & I2C_M_RD) + ret = i2c_read(bus, seg->slave, seg->buf, seg->len); + else + ret = i2c_write(bus, seg->slave, seg->buf, seg->len, + (seg_count ? 0 : 1)); + seg++; + } + + if (ret) { + qup_set_state(bus, QUP_STATE_RESET); + return 1; + } + + return 0; +} diff --git a/src/soc/qualcomm/qcs405/qup.c b/src/soc/qualcomm/qcs405/qup.c new file mode 100644 index 0000000..e2aab06 --- /dev/null +++ b/src/soc/qualcomm/qcs405/qup.c @@ -0,0 +1,610 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015, 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <device/mmio.h> +#include <console/console.h> +#include <delay.h> +#include <soc/gpio.h> +#include <soc/iomap.h> +#include <stdlib.h> +#include <soc/qup.h> + +#define TIMEOUT_CNT 100 + +#define QUP_ADDR(id, reg) (blsp_qup_base(id) + (reg)) + +#define QUP_DEBUG 0 + +#define QUPDBG BIOS_ERR, "\t-> " + +#if QUP_DEBUG +#define qup_write32(a, v) do { \ + write32(a, v); \ + printk(QUPDBG "%s(%d): write32(0x%p, 0x%x)\n", \ + __func__, __LINE__, a, v); \ +} while (0) +#else +#define qup_write32 write32 +#endif + +struct i2c_clk_div_fld { + u32 clk_freq_out; + u8 fs_div; + u8 ht_div; +}; + +static struct i2c_clk_div_fld i2c_clk_div_map[] = { + {100000, 124, 62}, + {400000, 28, 14}, + {1000000, 8, 5}, +}; + +static void i2c_set_mstr_clk_ctl(unsigned id, unsigned hz) +{ + int i; + struct i2c_clk_div_fld *itr = i2c_clk_div_map; + u8 fs_div = 0; + u8 ht_div = 0; + u32 mstr_clk_ctl; + + for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { + if (hz == itr->clk_freq_out) { + if (!fs_div) + fs_div = itr->fs_div; + if (!ht_div) + ht_div = itr->ht_div; + break; + } + } + + /* format values in clk-ctl cache */ + mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); + + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CLK_CTL), mstr_clk_ctl); +} + + +static qup_return_t qup_i2c_master_status(blsp_qup_id_t id) +{ + uint32_t reg_val = read32(QUP_ADDR(id, QUP_I2C_MASTER_STATUS)); + + if (read32(QUP_ADDR(id, QUP_ERROR_FLAGS))) + return QUP_ERR_XFER_FAIL; + +#if QUP_DEBUG + printk(QUPDBG "%s: 0x%x\n", __func__, reg_val); +#endif + + if (reg_val & QUP_I2C_INVALID_READ_ADDR) + return QUP_ERR_I2C_INVALID_SLAVE_ADDR; + if (reg_val & QUP_I2C_FAILED_MASK) + return QUP_ERR_I2C_FAILED; + if (reg_val & QUP_I2C_ARB_LOST) + return QUP_ERR_I2C_ARB_LOST; + if (reg_val & QUP_I2C_BUS_ERROR) + return QUP_ERR_I2C_BUS_ERROR; + if (reg_val & QUP_I2C_INVALID_WRITE) + return QUP_ERR_I2C_INVALID_WRITE; + if (reg_val & QUP_I2C_PACKET_NACK) + return QUP_ERR_I2C_NACK; + if (reg_val & QUP_I2C_INVALID_TAG) + return QUP_ERR_I2C_INVALID_TAG; + + return QUP_SUCCESS; +} + +static int check_bit_state(uint32_t *reg, int wait_for) +{ + unsigned int count = TIMEOUT_CNT; + + while ((read32(reg) & (QUP_STATE_VALID_MASK | QUP_STATE_MASK)) != + (QUP_STATE_VALID | wait_for)) { + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +/* + * Check whether GSBIn_QUP State is valid + */ +static qup_return_t qup_wait_for_state(blsp_qup_id_t id, unsigned wait_for) +{ + return check_bit_state(QUP_ADDR(id, QUP_STATE), wait_for); +} + +qup_return_t qup_reset_i2c_master_status(blsp_qup_id_t id) +{ + /* + * The I2C_STATUS is a status register. + * Writing any value clears the status bits. + */ + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_STATUS), 0); + return QUP_SUCCESS; +} + +static qup_return_t qup_reset_master_status(blsp_qup_id_t id) +{ + qup_write32(QUP_ADDR(id, QUP_ERROR_FLAGS), 0x3C); + qup_write32(QUP_ADDR(id, QUP_ERROR_FLAGS_EN), 0x3C); + qup_reset_i2c_master_status(id); + return QUP_SUCCESS; +} + +static qup_return_t qup_fifo_wait_for(blsp_qup_id_t id, uint32_t status) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned int count = TIMEOUT_CNT; + + while (!(read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status)) { + ret = qup_i2c_master_status(id); + if (ret) + return ret; + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +static qup_return_t qup_fifo_wait_while(blsp_qup_id_t id, uint32_t status) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned int count = TIMEOUT_CNT; + + while (read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status) { + ret = qup_i2c_master_status(id); + if (ret) + return ret; + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +static inline uint32_t qup_i2c_create_output_tag(int stop, u8 data) +{ + uint32_t tag; + + if (stop) + tag = QUP_I2C_STOP_SEQ | QUP_I2C_DATA(data); + else + tag = QUP_I2C_DATA_SEQ | QUP_I2C_DATA(data); + + return tag; +} + +static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + qup_write32(QUP_ADDR(id, QUP_OPERATIONAL), OUTPUT_SERVICE_FLAG); + + mdelay(4); /* TPM seems to need this */ + + ret = qup_fifo_wait_while(id, OUTPUT_FIFO_NOT_EMPTY); + if (ret) + return ret; + + ret = qup_i2c_master_status(id); + + if (ret) + printk(BIOS_DEBUG, "%s: error\n", __func__); + + return ret; +} + +static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t addr = p_tx_obj->p.iic.addr; + uint8_t *data_ptr = p_tx_obj->p.iic.data; + unsigned data_len = p_tx_obj->p.iic.data_len; + unsigned idx = 0; + uint32_t tag, *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + + qup_reset_master_status(id); + + qup_write32(QUP_ADDR(id, QUP_MX_OUTPUT_COUNT), data_len + 1); + + qup_set_state(id, QUP_STATE_RUN); + + /* + * Since UNPACK enable is set in io mode register, populate 2 tags + * for each fifo register. + * + * Create the first tag as follows, with the start tag and first byte + * of the data to be written + * +--------+--------+--------+--------+ + * | STOP / | data | START | ADDR | + * |DATA tag| byte | tag | << 1 | + * +--------+--------+--------+--------+ + * rest will be created in the following while loop. + */ + tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq, + data_ptr[idx]); + tag = ((tag << 16) & 0xffff0000) | + (QUP_I2C_START_SEQ | QUP_I2C_ADDR(addr)); + data_len--; + idx++; + + qup_write32(fifo, tag); + + while (data_len) { + + tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq, + data_ptr[idx]); + data_len--; + idx++; + + if (data_len) { + tag |= qup_i2c_create_output_tag( + data_len == 1 && stop_seq, + data_ptr[idx]) << 16; + data_len--; + idx++; + } + + qup_write32(fifo, tag); + + ret = qup_i2c_write_fifo_flush(id); + + if (ret) { + printk(QUPDBG "%s: error\n", __func__); + return ret; + } + } + + ret = qup_i2c_write_fifo_flush(id); + + qup_set_state(id, QUP_STATE_RESET); + + return ret; +} + +static qup_return_t qup_i2c_write(blsp_qup_id_t id, uint8_t mode, + qup_data_t *p_tx_obj, uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + switch (mode) { + case QUP_MODE_FIFO: + case QUP_MODE_BLOCK: + ret = qup_i2c_write_fifo(id, p_tx_obj, stop_seq); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + + if (ret) { + qup_set_state(id, QUP_STATE_RESET); + printk(QUPDBG "%s() failed (%d)\n", __func__, ret); + } + + return ret; +} + +static int qup_i2c_parse_tag(uint32_t data, uint8_t *data_ptr, uint32_t len) +{ + int i, idx = 0; + int max = (len > 2) ? 2 : len; + + for (i = 0; i < max; i++) { + switch (QUP_I2C_MI_TAG(data)) { + case QUP_I2C_MIDATA_SEQ: + data_ptr[idx] = QUP_I2C_DATA(data); + idx++; + break; + case QUP_I2C_MISTOP_SEQ: + data_ptr[idx] = QUP_I2C_DATA(data); + idx++; + return idx; + default: + printk(QUPDBG "%s: Unexpected tag (0x%x)\n", __func__, + QUP_I2C_MI_TAG(data)); + return -1; + } + + data = (data >> 16); + } + + return idx; +} + +static qup_return_t qup_i2c_read_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t addr = p_tx_obj->p.iic.addr; + uint8_t *data_ptr = p_tx_obj->p.iic.data; + unsigned data_len = p_tx_obj->p.iic.data_len; + unsigned idx = 0; + uint32_t *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + + qup_reset_master_status(id); + + qup_write32(QUP_ADDR(id, QUP_IO_MODES), + QUP_UNPACK_EN | QUP_PACK_EN | + ((QUP_MODE_BLOCK & QUP_MODE_MASK) << + QUP_OUTPUT_MODE_SHFT) | + ((QUP_MODE_BLOCK & QUP_MODE_MASK) << + QUP_INPUT_MODE_SHFT)); + + qup_write32(QUP_ADDR(id, QUP_MX_INPUT_COUNT), data_len); + + qup_set_state(id, QUP_STATE_RUN); + + qup_write32(fifo, (QUP_I2C_START_SEQ | + (QUP_I2C_ADDR(addr) | QUP_I2C_SLAVE_READ)) | + ((QUP_I2C_RECV_SEQ | data_len) << 16)); + + ret = qup_i2c_write_fifo_flush(id); + if (ret) { + printk(QUPDBG "%s: OUTPUT_FIFO_NOT_EMPTY\n", __func__); + return ret; + } + + ret = qup_fifo_wait_for(id, INPUT_SERVICE_FLAG); + if (ret) { + printk(QUPDBG "%s: INPUT_SERVICE_FLAG\n", __func__); + return ret; + } + + fifo = QUP_ADDR(id, QUP_INPUT_FIFO); + + while (data_len) { + uint32_t data; + int count; + + data = read32(fifo); + mdelay(1); + + count = qup_i2c_parse_tag(data, data_ptr + idx, data_len); + + if (count < 0) { + printk(QUPDBG "%s: Cannot parse tag 0x%x\n", + __func__, data); + qup_set_state(id, QUP_STATE_PAUSE); + + return QUP_ERR_I2C_INVALID_TAG; + } + + idx += count; + data_len -= count; + + qup_write32(QUP_ADDR(id, QUP_OPERATIONAL), INPUT_SERVICE_FLAG); + } + + p_tx_obj->p.iic.data_len = idx; + + qup_write32(QUP_ADDR(id, QUP_MX_READ_COUNT), 0); + + qup_set_state(id, QUP_STATE_RESET); + + return QUP_SUCCESS; +} + +static qup_return_t qup_i2c_read(blsp_qup_id_t id, uint8_t mode, + qup_data_t *p_tx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + qup_set_state(id, QUP_STATE_RESET); + + switch (mode) { + case QUP_MODE_FIFO: + case QUP_MODE_BLOCK: + ret = qup_i2c_read_fifo(id, p_tx_obj); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + + if (ret) { + qup_set_state(id, QUP_STATE_RESET); + printk(QUPDBG "%s() failed (%d)\n", __func__, ret); + } + + return ret; +} + +qup_return_t qup_init(blsp_qup_id_t id, const qup_config_t *config_ptr) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint32_t reg_val; + + /* Reset the QUP core.*/ + qup_write32(QUP_ADDR(id, QUP_SW_RESET), 0x1); + + /* Wait till the reset takes effect */ + ret = qup_wait_for_state(id, QUP_STATE_RESET); + if (ret) + goto bailout; + + /* Reset the config */ + qup_write32(QUP_ADDR(id, QUP_CONFIG), 0); + + /* Program the config register */ + /* Set N value */ + reg_val = 0x0F; + /* Set protocol */ + switch (config_ptr->protocol) { + case QUP_MINICORE_I2C_MASTER: + reg_val |= ((config_ptr->protocol & + QUP_MINI_CORE_PROTO_MASK) << + QUP_MINI_CORE_PROTO_SHFT); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + goto bailout; + } + reg_val |= QUP_APP_CLK_ON_EN | QUP_CORE_CLK_ON_EN; + qup_write32(QUP_ADDR(id, QUP_CONFIG), reg_val); + + /* Choose version 1 tag */ + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CONFIG), 0); + + /* Reset i2c clk cntl register */ + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CLK_CTL), 0); + + /* Set QUP IO Mode */ + switch (config_ptr->mode) { + case QUP_MODE_FIFO: + case QUP_MODE_BLOCK: + reg_val = QUP_UNPACK_EN | QUP_PACK_EN | + ((config_ptr->mode & QUP_MODE_MASK) << + QUP_OUTPUT_MODE_SHFT) | + ((config_ptr->mode & QUP_MODE_MASK) << + QUP_INPUT_MODE_SHFT); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + goto bailout; + } + qup_write32(QUP_ADDR(id, QUP_IO_MODES), reg_val); + + /*Set i2c clk cntl*/ + i2c_set_mstr_clk_ctl(id, 400000); + + qup_set_state(id, QUP_STATE_RESET); +bailout: + if (ret) + printk(QUPDBG "failed to init qup (%d)\n", ret); + + return ret; +} + +qup_return_t qup_set_state(blsp_qup_id_t id, uint32_t state) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned curr_state = read32(QUP_ADDR(id, QUP_STATE)); + + if ((state >= QUP_STATE_RESET && state <= QUP_STATE_PAUSE) + && (curr_state & QUP_STATE_VALID_MASK)) { + /* + * For PAUSE_STATE to RESET_STATE transition, + * two writes of 10[binary]) are required for the + * transition to complete. + */ + if (QUP_STATE_PAUSE == curr_state && QUP_STATE_RESET == state) { + qup_write32(QUP_ADDR(id, QUP_STATE), 0x2); + qup_write32(QUP_ADDR(id, QUP_STATE), 0x2); + } else { + qup_write32(QUP_ADDR(id, QUP_STATE), state); + } + ret = qup_wait_for_state(id, state); + } + + return ret; +} + +static qup_return_t qup_i2c_send_data(blsp_qup_id_t id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t mode = (read32(QUP_ADDR(id, QUP_IO_MODES)) >> + QUP_OUTPUT_MODE_SHFT) & QUP_MODE_MASK; + + ret = qup_i2c_write(id, mode, p_tx_obj, stop_seq); + if (QUP_DEBUG) { + int i; + + printk(BIOS_DEBUG, "i2c tx bus %d device %2.2x:", + id, p_tx_obj->p.iic.addr); + for (i = 0; i < p_tx_obj->p.iic.data_len; i++) + printk(BIOS_DEBUG, " %2.2x", p_tx_obj->p.iic.data[i]); + printk(BIOS_DEBUG, "\n"); + } + + return ret; +} + +qup_return_t qup_send_data(blsp_qup_id_t id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + if (p_tx_obj->protocol == ((read32(QUP_ADDR(id, QUP_CONFIG)) >> + QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) { + switch (p_tx_obj->protocol) { + case QUP_MINICORE_I2C_MASTER: + ret = qup_i2c_send_data(id, p_tx_obj, stop_seq); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + } + + return ret; +} + +static qup_return_t qup_i2c_recv_data(blsp_qup_id_t id, qup_data_t *p_rx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t mode = (read32(QUP_ADDR(id, QUP_IO_MODES)) >> + QUP_INPUT_MODE_SHFT) & QUP_MODE_MASK; + + ret = qup_i2c_read(id, mode, p_rx_obj); + if (QUP_DEBUG) { + int i; + + printk(BIOS_DEBUG, "i2c rxed on bus %d device %2.2x:", + id, p_rx_obj->p.iic.addr); + for (i = 0; i < p_rx_obj->p.iic.data_len; i++) + printk(BIOS_DEBUG, " %2.2x", p_rx_obj->p.iic.data[i]); + printk(BIOS_DEBUG, "\n"); + } + + return ret; +} + +qup_return_t qup_recv_data(blsp_qup_id_t id, qup_data_t *p_rx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + if (p_rx_obj->protocol == ((read32(QUP_ADDR(id, QUP_CONFIG)) >> + QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) { + switch (p_rx_obj->protocol) { + case QUP_MINICORE_I2C_MASTER: + ret = qup_i2c_recv_data(id, p_rx_obj); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + } + + return ret; +}
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 1:
(64 comments)
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@49 PS1, Line 49: case BLSP_QUP_ID_1: code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@49 PS1, Line 49: case BLSP_QUP_ID_1: please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@54 PS1, Line 54: break; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@54 PS1, Line 54: break; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@55 PS1, Line 55: default: code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@56 PS1, Line 56: return 1; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@56 PS1, Line 56: return 1; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@57 PS1, Line 57: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/blsp.c@57 PS1, Line 57: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/i2c.c File src/soc/qualcomm/qcs405/i2c.c:
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/i2c.c@87 PS1, Line 87: if (QUP_SUCCESS != qup_ret) Comparisons should place the constant on the right side of the test
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/i2c.c@106 PS1, Line 106: if (QUP_SUCCESS != qup_ret) Comparisons should place the constant on the right side of the test
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/i2c.c@157 PS1, Line 157: int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c File src/soc/qualcomm/qcs405/qup.c:
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@59 PS1, Line 59: u32 clk_freq_out; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@59 PS1, Line 59: u32 clk_freq_out; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@60 PS1, Line 60: u8 fs_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@60 PS1, Line 60: u8 fs_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@61 PS1, Line 61: u8 ht_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@61 PS1, Line 61: u8 ht_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@65 PS1, Line 65: {100000, 124, 62}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@65 PS1, Line 65: {100000, 124, 62}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@66 PS1, Line 66: {400000, 28, 14}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@66 PS1, Line 66: {400000, 28, 14}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@67 PS1, Line 67: {1000000, 8, 5}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@67 PS1, Line 67: {1000000, 8, 5}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@70 PS1, Line 70: static void i2c_set_mstr_clk_ctl(unsigned id, unsigned hz) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@70 PS1, Line 70: static void i2c_set_mstr_clk_ctl(unsigned id, unsigned hz) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@72 PS1, Line 72: int i; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@72 PS1, Line 72: int i; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@73 PS1, Line 73: struct i2c_clk_div_fld *itr = i2c_clk_div_map; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@73 PS1, Line 73: struct i2c_clk_div_fld *itr = i2c_clk_div_map; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@74 PS1, Line 74: u8 fs_div = 0; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@74 PS1, Line 74: u8 fs_div = 0; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@75 PS1, Line 75: u8 ht_div = 0; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@75 PS1, Line 75: u8 ht_div = 0; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@76 PS1, Line 76: u32 mstr_clk_ctl; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@76 PS1, Line 76: u32 mstr_clk_ctl; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@78 PS1, Line 78: for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@78 PS1, Line 78: for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@79 PS1, Line 79: if (hz == itr->clk_freq_out) { code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@79 PS1, Line 79: if (hz == itr->clk_freq_out) { please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@80 PS1, Line 80: if (!fs_div) code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@80 PS1, Line 80: if (!fs_div) please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@81 PS1, Line 81: fs_div = itr->fs_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@81 PS1, Line 81: fs_div = itr->fs_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@82 PS1, Line 82: if (!ht_div) code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@82 PS1, Line 82: if (!ht_div) please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@83 PS1, Line 83: ht_div = itr->ht_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@83 PS1, Line 83: ht_div = itr->ht_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@84 PS1, Line 84: break; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@84 PS1, Line 84: break; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@85 PS1, Line 85: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@85 PS1, Line 85: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@86 PS1, Line 86: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@86 PS1, Line 86: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@88 PS1, Line 88: /* format values in clk-ctl cache */ code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@89 PS1, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@89 PS1, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@89 PS1, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); need consistent spacing around '|' (ctx:WxV)
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@141 PS1, Line 141: static qup_return_t qup_wait_for_state(blsp_qup_id_t id, unsigned wait_for) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@236 PS1, Line 236: unsigned data_len = p_tx_obj->p.iic.data_len; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@237 PS1, Line 237: unsigned idx = 0; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@353 PS1, Line 353: unsigned data_len = p_tx_obj->p.iic.data_len; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@354 PS1, Line 354: unsigned idx = 0; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/1/src/soc/qualcomm/qcs405/qup.c@513 PS1, Line 513: unsigned curr_state = read32(QUP_ADDR(id, QUP_STATE)); Prefer 'unsigned int' to bare use of 'unsigned'
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32546
to look at the new patch set (#2).
Change subject: qcom: Add i2c driver ......................................................................
qcom: Add i2c driver
Add i2c driver in coreboot.
Change-Id: I3d39d0325718fc5dd60da42eb2b87dcc4429bfc2 Signed-off-by: Prudhvi Yarlagadda pyarlaga@codeaurora.org Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org --- M src/soc/qualcomm/qcs405/Makefile.inc A src/soc/qualcomm/qcs405/blsp.c A src/soc/qualcomm/qcs405/i2c.c A src/soc/qualcomm/qcs405/qup.c 4 files changed, 865 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/46/32546/2
Paul Menzel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 2:
Did you write this driver from scratch (what data sheet?) or copy it from somewhere?
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32546
to look at the new patch set (#3).
Change subject: qcom: Add i2c driver ......................................................................
qcom: Add i2c driver
Add i2c driver in coreboot.
Change-Id: I3d39d0325718fc5dd60da42eb2b87dcc4429bfc2 Signed-off-by: Prudhvi Yarlagadda pyarlaga@codeaurora.org Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org --- M src/soc/qualcomm/qcs405/Makefile.inc A src/soc/qualcomm/qcs405/blsp.c A src/soc/qualcomm/qcs405/i2c.c A src/soc/qualcomm/qcs405/qup.c 4 files changed, 866 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/46/32546/3
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 3:
(64 comments)
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@49 PS3, Line 49: case BLSP_QUP_ID_1: code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@49 PS3, Line 49: case BLSP_QUP_ID_1: please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@54 PS3, Line 54: break; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@54 PS3, Line 54: break; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@55 PS3, Line 55: default: code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@56 PS3, Line 56: return 1; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@56 PS3, Line 56: return 1; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@57 PS3, Line 57: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/blsp.c@57 PS3, Line 57: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/i2c.c File src/soc/qualcomm/qcs405/i2c.c:
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/i2c.c@87 PS3, Line 87: if (QUP_SUCCESS != qup_ret) Comparisons should place the constant on the right side of the test
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/i2c.c@106 PS3, Line 106: if (QUP_SUCCESS != qup_ret) Comparisons should place the constant on the right side of the test
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/i2c.c@157 PS3, Line 157: int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c File src/soc/qualcomm/qcs405/qup.c:
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@59 PS3, Line 59: u32 clk_freq_out; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@59 PS3, Line 59: u32 clk_freq_out; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@60 PS3, Line 60: u8 fs_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@60 PS3, Line 60: u8 fs_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@61 PS3, Line 61: u8 ht_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@61 PS3, Line 61: u8 ht_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@65 PS3, Line 65: {100000, 124, 62}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@65 PS3, Line 65: {100000, 124, 62}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@66 PS3, Line 66: {400000, 28, 14}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@66 PS3, Line 66: {400000, 28, 14}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@67 PS3, Line 67: {1000000, 8, 5}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@67 PS3, Line 67: {1000000, 8, 5}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@70 PS3, Line 70: static void i2c_set_mstr_clk_ctl(unsigned id, unsigned hz) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@70 PS3, Line 70: static void i2c_set_mstr_clk_ctl(unsigned id, unsigned hz) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@72 PS3, Line 72: int i; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@72 PS3, Line 72: int i; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@73 PS3, Line 73: struct i2c_clk_div_fld *itr = i2c_clk_div_map; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@73 PS3, Line 73: struct i2c_clk_div_fld *itr = i2c_clk_div_map; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@74 PS3, Line 74: u8 fs_div = 0; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@74 PS3, Line 74: u8 fs_div = 0; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@75 PS3, Line 75: u8 ht_div = 0; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@75 PS3, Line 75: u8 ht_div = 0; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@76 PS3, Line 76: u32 mstr_clk_ctl; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@76 PS3, Line 76: u32 mstr_clk_ctl; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@78 PS3, Line 78: for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@78 PS3, Line 78: for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@79 PS3, Line 79: if (hz == itr->clk_freq_out) { code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@79 PS3, Line 79: if (hz == itr->clk_freq_out) { please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@80 PS3, Line 80: if (!fs_div) code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@80 PS3, Line 80: if (!fs_div) please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@81 PS3, Line 81: fs_div = itr->fs_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@81 PS3, Line 81: fs_div = itr->fs_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@82 PS3, Line 82: if (!ht_div) code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@82 PS3, Line 82: if (!ht_div) please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@83 PS3, Line 83: ht_div = itr->ht_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@83 PS3, Line 83: ht_div = itr->ht_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@84 PS3, Line 84: break; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@84 PS3, Line 84: break; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@85 PS3, Line 85: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@85 PS3, Line 85: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@86 PS3, Line 86: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@86 PS3, Line 86: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@88 PS3, Line 88: /* format values in clk-ctl cache */ code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@89 PS3, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@89 PS3, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@89 PS3, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); need consistent spacing around '|' (ctx:WxV)
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@141 PS3, Line 141: static qup_return_t qup_wait_for_state(blsp_qup_id_t id, unsigned wait_for) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@236 PS3, Line 236: unsigned data_len = p_tx_obj->p.iic.data_len; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@237 PS3, Line 237: unsigned idx = 0; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@353 PS3, Line 353: unsigned data_len = p_tx_obj->p.iic.data_len; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@354 PS3, Line 354: unsigned idx = 0; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/3/src/soc/qualcomm/qcs405/qup.c@513 PS3, Line 513: unsigned curr_state = read32(QUP_ADDR(id, QUP_STATE)); Prefer 'unsigned int' to bare use of 'unsigned'
Prudhvi Yarlagadda has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 3:
Patch Set 2:
Did you write this driver from scratch (what data sheet?) or copy it from somewhere?
This driver is already present in ipq4xx and we ported here for qcs405.
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32546
to look at the new patch set (#4).
Change subject: qcom: Add i2c driver ......................................................................
qcom: Add i2c driver
Add i2c driver in coreboot.
Change-Id: I3d39d0325718fc5dd60da42eb2b87dcc4429bfc2 Signed-off-by: Prudhvi Yarlagadda pyarlaga@codeaurora.org Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org --- M src/soc/qualcomm/qcs405/Makefile.inc A src/soc/qualcomm/qcs405/blsp.c A src/soc/qualcomm/qcs405/i2c.c A src/soc/qualcomm/qcs405/qup.c 4 files changed, 866 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/46/32546/4
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 4:
(64 comments)
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@49 PS4, Line 49: case BLSP_QUP_ID_1: code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@49 PS4, Line 49: case BLSP_QUP_ID_1: please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@54 PS4, Line 54: break; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@54 PS4, Line 54: break; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@55 PS4, Line 55: default: code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@56 PS4, Line 56: return 1; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@56 PS4, Line 56: return 1; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@57 PS4, Line 57: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/blsp.c@57 PS4, Line 57: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/i2c.c File src/soc/qualcomm/qcs405/i2c.c:
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/i2c.c@87 PS4, Line 87: if (QUP_SUCCESS != qup_ret) Comparisons should place the constant on the right side of the test
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/i2c.c@106 PS4, Line 106: if (QUP_SUCCESS != qup_ret) Comparisons should place the constant on the right side of the test
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/i2c.c@157 PS4, Line 157: int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c File src/soc/qualcomm/qcs405/qup.c:
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@59 PS4, Line 59: u32 clk_freq_out; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@59 PS4, Line 59: u32 clk_freq_out; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@60 PS4, Line 60: u8 fs_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@60 PS4, Line 60: u8 fs_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@61 PS4, Line 61: u8 ht_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@61 PS4, Line 61: u8 ht_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@65 PS4, Line 65: {100000, 124, 62}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@65 PS4, Line 65: {100000, 124, 62}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@66 PS4, Line 66: {400000, 28, 14}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@66 PS4, Line 66: {400000, 28, 14}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@67 PS4, Line 67: {1000000, 8, 5}, code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@67 PS4, Line 67: {1000000, 8, 5}, please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@70 PS4, Line 70: static void i2c_set_mstr_clk_ctl(unsigned id, unsigned hz) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@70 PS4, Line 70: static void i2c_set_mstr_clk_ctl(unsigned id, unsigned hz) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@72 PS4, Line 72: int i; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@72 PS4, Line 72: int i; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@73 PS4, Line 73: struct i2c_clk_div_fld *itr = i2c_clk_div_map; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@73 PS4, Line 73: struct i2c_clk_div_fld *itr = i2c_clk_div_map; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@74 PS4, Line 74: u8 fs_div = 0; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@74 PS4, Line 74: u8 fs_div = 0; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@75 PS4, Line 75: u8 ht_div = 0; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@75 PS4, Line 75: u8 ht_div = 0; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@76 PS4, Line 76: u32 mstr_clk_ctl; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@76 PS4, Line 76: u32 mstr_clk_ctl; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@78 PS4, Line 78: for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@78 PS4, Line 78: for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@79 PS4, Line 79: if (hz == itr->clk_freq_out) { code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@79 PS4, Line 79: if (hz == itr->clk_freq_out) { please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@80 PS4, Line 80: if (!fs_div) code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@80 PS4, Line 80: if (!fs_div) please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@81 PS4, Line 81: fs_div = itr->fs_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@81 PS4, Line 81: fs_div = itr->fs_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@82 PS4, Line 82: if (!ht_div) code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@82 PS4, Line 82: if (!ht_div) please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@83 PS4, Line 83: ht_div = itr->ht_div; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@83 PS4, Line 83: ht_div = itr->ht_div; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@84 PS4, Line 84: break; code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@84 PS4, Line 84: break; please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@85 PS4, Line 85: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@85 PS4, Line 85: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@86 PS4, Line 86: } code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@86 PS4, Line 86: } please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@88 PS4, Line 88: /* format values in clk-ctl cache */ code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@89 PS4, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); code indent should use tabs where possible
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@89 PS4, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); please, no spaces at the start of a line
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@89 PS4, Line 89: mstr_clk_ctl = ((ht_div & 0xff) << 16) |(fs_div & 0xff); need consistent spacing around '|' (ctx:WxV)
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@141 PS4, Line 141: static qup_return_t qup_wait_for_state(blsp_qup_id_t id, unsigned wait_for) Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@236 PS4, Line 236: unsigned data_len = p_tx_obj->p.iic.data_len; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@237 PS4, Line 237: unsigned idx = 0; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@353 PS4, Line 353: unsigned data_len = p_tx_obj->p.iic.data_len; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@354 PS4, Line 354: unsigned idx = 0; Prefer 'unsigned int' to bare use of 'unsigned'
https://review.coreboot.org/#/c/32546/4/src/soc/qualcomm/qcs405/qup.c@513 PS4, Line 513: unsigned curr_state = read32(QUP_ADDR(id, QUP_STATE)); Prefer 'unsigned int' to bare use of 'unsigned'
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32546
to look at the new patch set (#5).
Change subject: qcom: Add i2c driver ......................................................................
qcom: Add i2c driver
Add i2c driver in coreboot.
Change-Id: I3d39d0325718fc5dd60da42eb2b87dcc4429bfc2 Signed-off-by: Prudhvi Yarlagadda pyarlaga@codeaurora.org Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org --- M src/soc/qualcomm/qcs405/Makefile.inc A src/soc/qualcomm/qcs405/blsp.c A src/soc/qualcomm/qcs405/i2c.c A src/soc/qualcomm/qcs405/qup.c 4 files changed, 865 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/46/32546/5
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 5: Code-Review+1
(1 comment)
a nit more than anything, but please resolve the 1 -> BLSP_ID_ERROR thing
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@56 PS5, Line 56: 1 BLSP_ID_ERROR, but what's the point of bailing out _here_ (after enabling i2c halfway)?
Prudhvi Yarlagadda has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@45 PS5, Line 45: clock_configure_i2c(19200000); Hi Patrick, Please let us know if the clock_configure_i2c API should take BLSP_QUP instance also as a parameter?
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@56 PS5, Line 56: 1
BLSP_ID_ERROR, but what's the point of bailing out _here_ (after enabling i2c halfway)?
Hi Patrick, Please let me know if my understanding to resolve this comment is correct. We need to check the BLSP_QUP_ID at the beginning of this API and return BLSP_ID_ERROR from there instead of checking the id after enabling the clocks.
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@45 PS5, Line 45: clock_configure_i2c(19200000);
Hi Patrick, […]
I'd rather remove that value altogether, given how this function can only configure that one block.
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@56 PS5, Line 56: 1
Hi Patrick, […]
That seems to make more sense to me, yes. Or, as mentioned earlier, remove "id" completely?
Prudhvi Yarlagadda has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@45 PS5, Line 45: clock_configure_i2c(19200000);
I'd rather remove that value altogether, given how this function can only configure that one block.
I understand this wrt the fix use case of one i2c instance. Are you confirming that there won't be any further change wrt usecase ? In that case we can remove this block and let us know where that change will happen ? Clock driver ?
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@56 PS5, Line 56: 1
That seems to make more sense to me, yes. […]
Ok we will add the check for id at the beginning of the API. "id" is needed for porting of this driver to future chips where number of i2c use cases can be more than one.
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c File src/soc/qualcomm/qcs405/blsp.c:
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@45 PS5, Line 45: clock_configure_i2c(19200000);
I understand this wrt the fix use case of one i2c instance. […]
Don't think there will be on mistral, but I'd hope we can reuse the work we're doing here :-) clock_configure_i2c was defined in a CL that is already merged, so you'll have to edit the existing implementation. Feel free to do that to pass along the BLSP_QUP.
https://review.coreboot.org/#/c/32546/5/src/soc/qualcomm/qcs405/blsp.c@56 PS5, Line 56: 1
Ok we will add the check for id at the beginning of the API. […]
Makes sense. Let's keep the id argument, but test earlier (before half of the configuration is done) if it's valid for the current code.
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32546
to look at the new patch set (#6).
Change subject: qcom: Add i2c driver ......................................................................
qcom: Add i2c driver
Add i2c driver in coreboot.
Change-Id: I3d39d0325718fc5dd60da42eb2b87dcc4429bfc2 Signed-off-by: Prudhvi Yarlagadda pyarlaga@codeaurora.org Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org --- M src/soc/qualcomm/qcs405/Makefile.inc A src/soc/qualcomm/qcs405/blsp.c A src/soc/qualcomm/qcs405/i2c.c A src/soc/qualcomm/qcs405/qup.c 4 files changed, 867 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/46/32546/6
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
Patch Set 6: Code-Review+2
Patrick Georgi has submitted this change and it was merged. ( https://review.coreboot.org/c/coreboot/+/32546 )
Change subject: qcom: Add i2c driver ......................................................................
qcom: Add i2c driver
Add i2c driver in coreboot.
Change-Id: I3d39d0325718fc5dd60da42eb2b87dcc4429bfc2 Signed-off-by: Prudhvi Yarlagadda pyarlaga@codeaurora.org Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/32546 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Patrick Georgi pgeorgi@google.com --- M src/soc/qualcomm/qcs405/Makefile.inc A src/soc/qualcomm/qcs405/blsp.c A src/soc/qualcomm/qcs405/i2c.c A src/soc/qualcomm/qcs405/qup.c 4 files changed, 867 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Patrick Georgi: Looks good to me, approved
diff --git a/src/soc/qualcomm/qcs405/Makefile.inc b/src/soc/qualcomm/qcs405/Makefile.inc index c64e5bc..0ebfcae 100644 --- a/src/soc/qualcomm/qcs405/Makefile.inc +++ b/src/soc/qualcomm/qcs405/Makefile.inc @@ -8,6 +8,9 @@ bootblock-y += mmu.c bootblock-y += gpio.c bootblock-y += clock.c +bootblock-y += i2c.c +bootblock-y += qup.c +bootblock-y += blsp.c bootblock-$(CONFIG_DRIVERS_UART) += uart.c
################################################################################ @@ -15,6 +18,9 @@ verstage-y += spi.c verstage-y += gpio.c verstage-y += clock.c +verstage-y += i2c.c +verstage-y += qup.c +verstage-y += blsp.c verstage-$(CONFIG_DRIVERS_UART) += uart.c
################################################################################ @@ -25,6 +31,9 @@ romstage-y += clock.c romstage-y += usb.c romstage-$(CONFIG_DRIVERS_UART) += uart.c +romstage-y += i2c.c +romstage-y += qup.c +romstage-y += blsp.c
################################################################################ ramstage-y += soc.c @@ -33,6 +42,9 @@ ramstage-y += cbmem.c ramstage-y += gpio.c ramstage-y += clock.c +ramstage-y += i2c.c +ramstage-y += qup.c +ramstage-y += blsp.c ramstage-y += usb.c ramstage-$(CONFIG_DRIVERS_UART) += uart.c
diff --git a/src/soc/qualcomm/qcs405/blsp.c b/src/soc/qualcomm/qcs405/blsp.c new file mode 100644 index 0000000..f185ea3 --- /dev/null +++ b/src/soc/qualcomm/qcs405/blsp.c @@ -0,0 +1,65 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2016, 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <device/mmio.h> +#include <soc/blsp.h> +#include <soc/gpio.h> +#include <soc/iomap.h> +#include <soc/clock.h> + +blsp_return_t blsp_i2c_init(blsp_qup_id_t id) +{ + void *base; + + switch (id) { + case BLSP_QUP_ID_1: + gpio_configure + (GPIO(24), 2, GPIO_PULL_UP, GPIO_2MA, GPIO_OUTPUT); + gpio_configure + (GPIO(25), 2, GPIO_PULL_UP, GPIO_2MA, GPIO_OUTPUT); + break; + default: + return BLSP_ID_ERROR; + } + + clock_configure_i2c(19200000); + clock_enable_i2c(); + + base = blsp_qup_base(id); + + if (!base) + return BLSP_ID_ERROR; + + /* Configure Mini core to I2C core */ + clrsetbits_le32(base, BLSP_MINI_CORE_MASK, BLSP_MINI_CORE_I2C); + + return BLSP_SUCCESS; +} diff --git a/src/soc/qualcomm/qcs405/i2c.c b/src/soc/qualcomm/qcs405/i2c.c new file mode 100644 index 0000000..94f8e0d --- /dev/null +++ b/src/soc/qualcomm/qcs405/i2c.c @@ -0,0 +1,181 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015, 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <console/console.h> +#include <delay.h> +#include <device/i2c_simple.h> +#include <stdlib.h> +#include <string.h> +#include <soc/blsp.h> +#include <soc/qup.h> +#include <soc/gpio.h> + +static qup_config_t blsp1_qup0_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static qup_config_t blsp1_qup1_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static qup_config_t blsp1_qup2_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static qup_config_t blsp1_qup3_config = { + QUP_MINICORE_I2C_MASTER, + 400000, + 19200000, + QUP_MODE_BLOCK, + 0 +}; + +static int i2c_read(uint32_t gsbi_id, uint8_t slave, + uint8_t *data, int data_len) +{ + qup_data_t obj; + qup_return_t qup_ret = 0; + + memset(&obj, 0, sizeof(obj)); + obj.protocol = QUP_MINICORE_I2C_MASTER; + obj.p.iic.addr = slave; + obj.p.iic.data_len = data_len; + obj.p.iic.data = data; + qup_ret = qup_recv_data(gsbi_id, &obj); + + if (qup_ret != QUP_SUCCESS) + return 1; + else + return 0; +} + +static int i2c_write(uint32_t gsbi_id, uint8_t slave, + uint8_t *data, int data_len, uint8_t stop_seq) +{ + qup_data_t obj; + qup_return_t qup_ret = 0; + + memset(&obj, 0, sizeof(obj)); + obj.protocol = QUP_MINICORE_I2C_MASTER; + obj.p.iic.addr = slave; + obj.p.iic.data_len = data_len; + obj.p.iic.data = data; + qup_ret = qup_send_data(gsbi_id, &obj, stop_seq); + + if (qup_ret != QUP_SUCCESS) + return 1; + else + return 0; +} + +static int i2c_init(blsp_qup_id_t id) +{ + qup_config_t *qup_config; + + switch (id) { + case BLSP_QUP_ID_0: + qup_config = &blsp1_qup0_config; + break; + case BLSP_QUP_ID_1: + qup_config = &blsp1_qup1_config; + break; + case BLSP_QUP_ID_2: + qup_config = &blsp1_qup2_config; + break; + case BLSP_QUP_ID_3: + qup_config = &blsp1_qup3_config; + break; + default: + printk(BIOS_ERR, "QUP configuration not defined for BLSP%d.\n", + id); + return 1; + } + + if (qup_config->initialized) + return 0; + + if (blsp_i2c_init(id)) { + printk(BIOS_ERR, "failed to initialize blsp\n"); + return 1; + } + + if (qup_init(id, qup_config)) { + printk(BIOS_ERR, "failed to initialize qup\n"); + return 1; + } + + if (qup_reset_i2c_master_status(id)) { + printk(BIOS_ERR, "failed to reset i2c master status\n"); + return 1; + } + + qup_config->initialized = 1; + return 0; +} + +int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, + int seg_count) +{ + struct i2c_msg *seg = segments; + int ret = 0; + + if (i2c_init(bus)) + return 1; + + while (!ret && seg_count--) { + if (seg->flags & I2C_M_RD) + ret = i2c_read(bus, seg->slave, seg->buf, seg->len); + else + ret = i2c_write(bus, seg->slave, seg->buf, seg->len, + (seg_count ? 0 : 1)); + seg++; + } + + if (ret) { + qup_set_state(bus, QUP_STATE_RESET); + return 1; + } + + return 0; +} diff --git a/src/soc/qualcomm/qcs405/qup.c b/src/soc/qualcomm/qcs405/qup.c new file mode 100644 index 0000000..cff5241 --- /dev/null +++ b/src/soc/qualcomm/qcs405/qup.c @@ -0,0 +1,609 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 - 2015, 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <device/mmio.h> +#include <console/console.h> +#include <delay.h> +#include <soc/gpio.h> +#include <soc/iomap.h> +#include <stdlib.h> +#include <soc/qup.h> + +#define TIMEOUT_CNT 100 + +#define QUP_ADDR(id, reg) (blsp_qup_base(id) + (reg)) + +#define QUP_DEBUG 0 + +#define QUPDBG BIOS_ERR, "\t-> " + +#if QUP_DEBUG +#define qup_write32(a, v) do { \ + write32(a, v); \ + printk(QUPDBG "%s(%d): write32(0x%p, 0x%x)\n", \ + __func__, __LINE__, a, v); \ +} while (0) +#else +#define qup_write32 write32 +#endif + +struct i2c_clk_div_fld { + u32 clk_freq_out; + u8 fs_div; + u8 ht_div; +}; + +static struct i2c_clk_div_fld i2c_clk_div_map[] = { + {100000, 124, 62}, + {400000, 28, 14}, + {1000000, 8, 5}, +}; + +static void i2c_set_mstr_clk_ctl(unsigned int id, unsigned int hz) +{ + int i; + struct i2c_clk_div_fld *itr = i2c_clk_div_map; + u8 fs_div = 0; + u8 ht_div = 0; + u32 mstr_clk_ctl; + + for (i = 0; i < ARRAY_SIZE(i2c_clk_div_map); ++i, ++itr) { + if (hz == itr->clk_freq_out) { + if (!fs_div) + fs_div = itr->fs_div; + if (!ht_div) + ht_div = itr->ht_div; + break; + } + } + + /* format values in clk-ctl cache */ + mstr_clk_ctl = ((ht_div & 0xff) << 16) | (fs_div & 0xff); + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CLK_CTL), mstr_clk_ctl); +} + + +static qup_return_t qup_i2c_master_status(blsp_qup_id_t id) +{ + uint32_t reg_val = read32(QUP_ADDR(id, QUP_I2C_MASTER_STATUS)); + + if (read32(QUP_ADDR(id, QUP_ERROR_FLAGS))) + return QUP_ERR_XFER_FAIL; + +#if QUP_DEBUG + printk(QUPDBG "%s: 0x%x\n", __func__, reg_val); +#endif + + if (reg_val & QUP_I2C_INVALID_READ_ADDR) + return QUP_ERR_I2C_INVALID_SLAVE_ADDR; + if (reg_val & QUP_I2C_FAILED_MASK) + return QUP_ERR_I2C_FAILED; + if (reg_val & QUP_I2C_ARB_LOST) + return QUP_ERR_I2C_ARB_LOST; + if (reg_val & QUP_I2C_BUS_ERROR) + return QUP_ERR_I2C_BUS_ERROR; + if (reg_val & QUP_I2C_INVALID_WRITE) + return QUP_ERR_I2C_INVALID_WRITE; + if (reg_val & QUP_I2C_PACKET_NACK) + return QUP_ERR_I2C_NACK; + if (reg_val & QUP_I2C_INVALID_TAG) + return QUP_ERR_I2C_INVALID_TAG; + + return QUP_SUCCESS; +} + +static int check_bit_state(uint32_t *reg, int wait_for) +{ + unsigned int count = TIMEOUT_CNT; + + while ((read32(reg) & (QUP_STATE_VALID_MASK | QUP_STATE_MASK)) != + (QUP_STATE_VALID | wait_for)) { + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +/* + * Check whether GSBIn_QUP State is valid + */ +static qup_return_t qup_wait_for_state(blsp_qup_id_t id, unsigned int wait_for) +{ + return check_bit_state(QUP_ADDR(id, QUP_STATE), wait_for); +} + +qup_return_t qup_reset_i2c_master_status(blsp_qup_id_t id) +{ + /* + * The I2C_STATUS is a status register. + * Writing any value clears the status bits. + */ + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_STATUS), 0); + return QUP_SUCCESS; +} + +static qup_return_t qup_reset_master_status(blsp_qup_id_t id) +{ + qup_write32(QUP_ADDR(id, QUP_ERROR_FLAGS), 0x3C); + qup_write32(QUP_ADDR(id, QUP_ERROR_FLAGS_EN), 0x3C); + qup_reset_i2c_master_status(id); + return QUP_SUCCESS; +} + +static qup_return_t qup_fifo_wait_for(blsp_qup_id_t id, uint32_t status) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned int count = TIMEOUT_CNT; + + while (!(read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status)) { + ret = qup_i2c_master_status(id); + if (ret) + return ret; + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +static qup_return_t qup_fifo_wait_while(blsp_qup_id_t id, uint32_t status) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned int count = TIMEOUT_CNT; + + while (read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status) { + ret = qup_i2c_master_status(id); + if (ret) + return ret; + if (count == 0) + return QUP_ERR_TIMEOUT; + count--; + } + + return QUP_SUCCESS; +} + +static inline uint32_t qup_i2c_create_output_tag(int stop, u8 data) +{ + uint32_t tag; + + if (stop) + tag = QUP_I2C_STOP_SEQ | QUP_I2C_DATA(data); + else + tag = QUP_I2C_DATA_SEQ | QUP_I2C_DATA(data); + + return tag; +} + +static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + qup_write32(QUP_ADDR(id, QUP_OPERATIONAL), OUTPUT_SERVICE_FLAG); + + mdelay(4); /* TPM seems to need this */ + + ret = qup_fifo_wait_while(id, OUTPUT_FIFO_NOT_EMPTY); + if (ret) + return ret; + + ret = qup_i2c_master_status(id); + + if (ret) + printk(BIOS_DEBUG, "%s: error\n", __func__); + + return ret; +} + +static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t addr = p_tx_obj->p.iic.addr; + uint8_t *data_ptr = p_tx_obj->p.iic.data; + unsigned int data_len = p_tx_obj->p.iic.data_len; + unsigned int idx = 0; + uint32_t tag, *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + + qup_reset_master_status(id); + + qup_write32(QUP_ADDR(id, QUP_MX_OUTPUT_COUNT), data_len + 1); + + qup_set_state(id, QUP_STATE_RUN); + + /* + * Since UNPACK enable is set in io mode register, populate 2 tags + * for each fifo register. + * + * Create the first tag as follows, with the start tag and first byte + * of the data to be written + * +--------+--------+--------+--------+ + * | STOP / | data | START | ADDR | + * |DATA tag| byte | tag | << 1 | + * +--------+--------+--------+--------+ + * rest will be created in the following while loop. + */ + tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq, + data_ptr[idx]); + tag = ((tag << 16) & 0xffff0000) | + (QUP_I2C_START_SEQ | QUP_I2C_ADDR(addr)); + data_len--; + idx++; + + qup_write32(fifo, tag); + + while (data_len) { + + tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq, + data_ptr[idx]); + data_len--; + idx++; + + if (data_len) { + tag |= qup_i2c_create_output_tag( + data_len == 1 && stop_seq, + data_ptr[idx]) << 16; + data_len--; + idx++; + } + + qup_write32(fifo, tag); + + ret = qup_i2c_write_fifo_flush(id); + + if (ret) { + printk(QUPDBG "%s: error\n", __func__); + return ret; + } + } + + ret = qup_i2c_write_fifo_flush(id); + + qup_set_state(id, QUP_STATE_RESET); + + return ret; +} + +static qup_return_t qup_i2c_write(blsp_qup_id_t id, uint8_t mode, + qup_data_t *p_tx_obj, uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + switch (mode) { + case QUP_MODE_FIFO: + case QUP_MODE_BLOCK: + ret = qup_i2c_write_fifo(id, p_tx_obj, stop_seq); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + + if (ret) { + qup_set_state(id, QUP_STATE_RESET); + printk(QUPDBG "%s() failed (%d)\n", __func__, ret); + } + + return ret; +} + +static int qup_i2c_parse_tag(uint32_t data, uint8_t *data_ptr, uint32_t len) +{ + int i, idx = 0; + int max = (len > 2) ? 2 : len; + + for (i = 0; i < max; i++) { + switch (QUP_I2C_MI_TAG(data)) { + case QUP_I2C_MIDATA_SEQ: + data_ptr[idx] = QUP_I2C_DATA(data); + idx++; + break; + case QUP_I2C_MISTOP_SEQ: + data_ptr[idx] = QUP_I2C_DATA(data); + idx++; + return idx; + default: + printk(QUPDBG "%s: Unexpected tag (0x%x)\n", __func__, + QUP_I2C_MI_TAG(data)); + return -1; + } + + data = (data >> 16); + } + + return idx; +} + +static qup_return_t qup_i2c_read_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t addr = p_tx_obj->p.iic.addr; + uint8_t *data_ptr = p_tx_obj->p.iic.data; + unsigned int data_len = p_tx_obj->p.iic.data_len; + unsigned int idx = 0; + uint32_t *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO); + + qup_reset_master_status(id); + + qup_write32(QUP_ADDR(id, QUP_IO_MODES), + QUP_UNPACK_EN | QUP_PACK_EN | + ((QUP_MODE_BLOCK & QUP_MODE_MASK) << + QUP_OUTPUT_MODE_SHFT) | + ((QUP_MODE_BLOCK & QUP_MODE_MASK) << + QUP_INPUT_MODE_SHFT)); + + qup_write32(QUP_ADDR(id, QUP_MX_INPUT_COUNT), data_len); + + qup_set_state(id, QUP_STATE_RUN); + + qup_write32(fifo, (QUP_I2C_START_SEQ | + (QUP_I2C_ADDR(addr) | QUP_I2C_SLAVE_READ)) | + ((QUP_I2C_RECV_SEQ | data_len) << 16)); + + ret = qup_i2c_write_fifo_flush(id); + if (ret) { + printk(QUPDBG "%s: OUTPUT_FIFO_NOT_EMPTY\n", __func__); + return ret; + } + + ret = qup_fifo_wait_for(id, INPUT_SERVICE_FLAG); + if (ret) { + printk(QUPDBG "%s: INPUT_SERVICE_FLAG\n", __func__); + return ret; + } + + fifo = QUP_ADDR(id, QUP_INPUT_FIFO); + + while (data_len) { + uint32_t data; + int count; + + data = read32(fifo); + mdelay(1); + + count = qup_i2c_parse_tag(data, data_ptr + idx, data_len); + + if (count < 0) { + printk(QUPDBG "%s: Cannot parse tag 0x%x\n", + __func__, data); + qup_set_state(id, QUP_STATE_PAUSE); + + return QUP_ERR_I2C_INVALID_TAG; + } + + idx += count; + data_len -= count; + + qup_write32(QUP_ADDR(id, QUP_OPERATIONAL), INPUT_SERVICE_FLAG); + } + + p_tx_obj->p.iic.data_len = idx; + + qup_write32(QUP_ADDR(id, QUP_MX_READ_COUNT), 0); + + qup_set_state(id, QUP_STATE_RESET); + + return QUP_SUCCESS; +} + +static qup_return_t qup_i2c_read(blsp_qup_id_t id, uint8_t mode, + qup_data_t *p_tx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + qup_set_state(id, QUP_STATE_RESET); + + switch (mode) { + case QUP_MODE_FIFO: + case QUP_MODE_BLOCK: + ret = qup_i2c_read_fifo(id, p_tx_obj); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + + if (ret) { + qup_set_state(id, QUP_STATE_RESET); + printk(QUPDBG "%s() failed (%d)\n", __func__, ret); + } + + return ret; +} + +qup_return_t qup_init(blsp_qup_id_t id, const qup_config_t *config_ptr) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint32_t reg_val; + + /* Reset the QUP core.*/ + qup_write32(QUP_ADDR(id, QUP_SW_RESET), 0x1); + + /* Wait till the reset takes effect */ + ret = qup_wait_for_state(id, QUP_STATE_RESET); + if (ret) + goto bailout; + + /* Reset the config */ + qup_write32(QUP_ADDR(id, QUP_CONFIG), 0); + + /* Program the config register */ + /* Set N value */ + reg_val = 0x0F; + /* Set protocol */ + switch (config_ptr->protocol) { + case QUP_MINICORE_I2C_MASTER: + reg_val |= ((config_ptr->protocol & + QUP_MINI_CORE_PROTO_MASK) << + QUP_MINI_CORE_PROTO_SHFT); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + goto bailout; + } + reg_val |= QUP_APP_CLK_ON_EN | QUP_CORE_CLK_ON_EN; + qup_write32(QUP_ADDR(id, QUP_CONFIG), reg_val); + + /* Choose version 1 tag */ + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CONFIG), 0); + + /* Reset i2c clk cntl register */ + qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CLK_CTL), 0); + + /* Set QUP IO Mode */ + switch (config_ptr->mode) { + case QUP_MODE_FIFO: + case QUP_MODE_BLOCK: + reg_val = QUP_UNPACK_EN | QUP_PACK_EN | + ((config_ptr->mode & QUP_MODE_MASK) << + QUP_OUTPUT_MODE_SHFT) | + ((config_ptr->mode & QUP_MODE_MASK) << + QUP_INPUT_MODE_SHFT); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + goto bailout; + } + qup_write32(QUP_ADDR(id, QUP_IO_MODES), reg_val); + + /*Set i2c clk cntl*/ + i2c_set_mstr_clk_ctl(id, 400000); + + qup_set_state(id, QUP_STATE_RESET); +bailout: + if (ret) + printk(QUPDBG "failed to init qup (%d)\n", ret); + + return ret; +} + +qup_return_t qup_set_state(blsp_qup_id_t id, uint32_t state) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + unsigned int curr_state = read32(QUP_ADDR(id, QUP_STATE)); + + if ((state <= QUP_STATE_PAUSE) + && (curr_state & QUP_STATE_VALID_MASK)) { + /* + * For PAUSE_STATE to RESET_STATE transition, + * two writes of 10[binary]) are required for the + * transition to complete. + */ + if (curr_state == QUP_STATE_PAUSE && state == QUP_STATE_RESET) { + qup_write32(QUP_ADDR(id, QUP_STATE), 0x2); + qup_write32(QUP_ADDR(id, QUP_STATE), 0x2); + } else { + qup_write32(QUP_ADDR(id, QUP_STATE), state); + } + ret = qup_wait_for_state(id, state); + } + + return ret; +} + +static qup_return_t qup_i2c_send_data(blsp_qup_id_t id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t mode = (read32(QUP_ADDR(id, QUP_IO_MODES)) >> + QUP_OUTPUT_MODE_SHFT) & QUP_MODE_MASK; + + ret = qup_i2c_write(id, mode, p_tx_obj, stop_seq); + if (QUP_DEBUG) { + int i; + + printk(BIOS_DEBUG, "i2c tx bus %d device %2.2x:", + id, p_tx_obj->p.iic.addr); + for (i = 0; i < p_tx_obj->p.iic.data_len; i++) + printk(BIOS_DEBUG, " %2.2x", p_tx_obj->p.iic.data[i]); + printk(BIOS_DEBUG, "\n"); + } + + return ret; +} + +qup_return_t qup_send_data(blsp_qup_id_t id, qup_data_t *p_tx_obj, + uint8_t stop_seq) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + if (p_tx_obj->protocol == ((read32(QUP_ADDR(id, QUP_CONFIG)) >> + QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) { + switch (p_tx_obj->protocol) { + case QUP_MINICORE_I2C_MASTER: + ret = qup_i2c_send_data(id, p_tx_obj, stop_seq); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + } + + return ret; +} + +static qup_return_t qup_i2c_recv_data(blsp_qup_id_t id, qup_data_t *p_rx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + uint8_t mode = (read32(QUP_ADDR(id, QUP_IO_MODES)) >> + QUP_INPUT_MODE_SHFT) & QUP_MODE_MASK; + + ret = qup_i2c_read(id, mode, p_rx_obj); + if (QUP_DEBUG) { + int i; + + printk(BIOS_DEBUG, "i2c rxed on bus %d device %2.2x:", + id, p_rx_obj->p.iic.addr); + for (i = 0; i < p_rx_obj->p.iic.data_len; i++) + printk(BIOS_DEBUG, " %2.2x", p_rx_obj->p.iic.data[i]); + printk(BIOS_DEBUG, "\n"); + } + + return ret; +} + +qup_return_t qup_recv_data(blsp_qup_id_t id, qup_data_t *p_rx_obj) +{ + qup_return_t ret = QUP_ERR_UNDEFINED; + + if (p_rx_obj->protocol == ((read32(QUP_ADDR(id, QUP_CONFIG)) >> + QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) { + switch (p_rx_obj->protocol) { + case QUP_MINICORE_I2C_MASTER: + ret = qup_i2c_recv_data(id, p_rx_obj); + break; + default: + ret = QUP_ERR_UNSUPPORTED; + } + } + + return ret; +}