/* * This file is part of the coreboot project. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 #include #include #include #include #define TIMEOUT_CNT 100000 //TODO: refactor the following array to iomap driver. static unsigned int gsbi_qup_base[] = { (unsigned int)GSBI_QUP1_BASE, (unsigned int)GSBI_QUP2_BASE, (unsigned int)GSBI_QUP3_BASE, (unsigned int)GSBI_QUP4_BASE, (unsigned int)GSBI_QUP5_BASE, (unsigned int)GSBI_QUP6_BASE, (unsigned int)GSBI_QUP7_BASE, }; #define QUP_ADDR(gsbi_num, reg) ((void *)((gsbi_qup_base[gsbi_num-1]) + (reg))) static qup_return_t qup_i2c_master_status(gsbi_id_t gsbi_id) { uint32_t reg_val = read32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_STATUS)); if (read32(QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS))) return QUP_ERR_XFER_FAIL; 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--; udelay(1); } return QUP_SUCCESS; } /* * Check whether GSBIn_QUP State is valid */ static qup_return_t qup_wait_for_state(gsbi_id_t gsbi_id, unsigned int wait_for) { return check_bit_state(QUP_ADDR(gsbi_id, QUP_STATE), wait_for); } qup_return_t qup_reset_i2c_master_status(gsbi_id_t gsbi_id) { /* * Writing a one clears the status bits. * Bit31-25, Bit1 and Bit0 are reserved. */ //TODO: Define each status bit. OR all status bits in a single macro. write32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_STATUS), 0x3FFFFFC); return QUP_SUCCESS; } static qup_return_t qup_reset_master_status(gsbi_id_t gsbi_id) { write32(QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS), 0x7C); write32(QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS_EN), 0x7C); qup_reset_i2c_master_status(gsbi_id); return QUP_SUCCESS; } static qup_return_t qup_fifo_wait_for(gsbi_id_t gsbi_id, uint32_t status) { qup_return_t ret = QUP_ERR_UNDEFINED; unsigned int count = TIMEOUT_CNT; while (!(read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & status)) { ret = qup_i2c_master_status(gsbi_id); if (ret) return ret; if (count == 0) return QUP_ERR_TIMEOUT; count--; } return QUP_SUCCESS; } static qup_return_t qup_fifo_wait_while(gsbi_id_t gsbi_id, uint32_t status) { qup_return_t ret = QUP_ERR_UNDEFINED; unsigned int count = TIMEOUT_CNT; while (read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & status) { ret = qup_i2c_master_status(gsbi_id); if (ret) return ret; if (count == 0) return QUP_ERR_TIMEOUT; count--; } return QUP_SUCCESS; } static qup_return_t qup_i2c_write_fifo(gsbi_id_t gsbi_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; qup_reset_master_status(gsbi_id); qup_set_state(gsbi_id, QUP_STATE_RUN); write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), (QUP_I2C_START_SEQ | QUP_I2C_ADDR(addr))); while (data_len) { if (data_len == 1 && stop_seq) { write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), QUP_I2C_STOP_SEQ | QUP_I2C_DATA(data_ptr[idx])); } else { write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), QUP_I2C_DATA_SEQ | QUP_I2C_DATA(data_ptr[idx])); } data_len--; idx++; if (data_len) { ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_FULL); if (ret) return ret; } /* Hardware sets the OUTPUT_SERVICE_FLAG flag to 1 when OUTPUT_FIFO_NOT_EMPTY flag in the QUP_OPERATIONAL register changes from 1 to 0, indicating that software can write more data to the output FIFO. Software should set OUTPUT_SERVICE_FLAG to 1 to clear it to 0, which means that software knows to return to fill the output FIFO with data. */ if (read32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) & OUTPUT_SERVICE_FLAG) { write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), OUTPUT_SERVICE_FLAG); } } ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY); if (ret) return ret; qup_set_state(gsbi_id, QUP_STATE_PAUSE); return qup_i2c_master_status(gsbi_id); } static qup_return_t qup_i2c_write(gsbi_id_t gsbi_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: ret = qup_i2c_write_fifo(gsbi_id, p_tx_obj, stop_seq); break; default: ret = QUP_ERR_UNSUPPORTED; } if (ret) { qup_set_state(gsbi_id, QUP_STATE_RESET); printk(BIOS_ERR, "%s() failed (%d)\n", __func__, ret); } return ret; } static qup_return_t qup_i2c_read_fifo(gsbi_id_t gsbi_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; qup_reset_master_status(gsbi_id); qup_set_state(gsbi_id, QUP_STATE_RUN); write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), QUP_I2C_START_SEQ | (QUP_I2C_ADDR(addr) | QUP_I2C_SLAVE_READ)); write32(QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO), QUP_I2C_RECV_SEQ | data_len); ret = qup_fifo_wait_while(gsbi_id, OUTPUT_FIFO_NOT_EMPTY); if (ret) return ret; write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), OUTPUT_SERVICE_FLAG); while (data_len) { uint32_t data; ret = qup_fifo_wait_for(gsbi_id, INPUT_SERVICE_FLAG); if (ret) return ret; data = read32(QUP_ADDR(gsbi_id, QUP_INPUT_FIFO)); /* * Process tag and corresponding data value. For I2C master * mini-core, data in FIFO is composed of 16 bits and is divided * into an 8-bit tag for the upper bits and 8-bit data for the * lower bits. The 8-bit tag indicates whether the byte is the * last byte, or if a bus error happened during the receipt of * the byte. */ if ((QUP_I2C_MI_TAG(data)) == QUP_I2C_MIDATA_SEQ) { /* Tag: MIDATA = Master input data.*/ data_ptr[idx] = QUP_I2C_DATA(data); idx++; data_len--; write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), INPUT_SERVICE_FLAG); } else if (QUP_I2C_MI_TAG(data) == QUP_I2C_MISTOP_SEQ) { /* Tag: MISTOP: Last byte of master input. */ data_ptr[idx] = QUP_I2C_DATA(data); idx++; data_len--; break; } else { /* Tag: MINACK: Invalid master input data.*/ break; } } write32(QUP_ADDR(gsbi_id, QUP_OPERATIONAL), INPUT_SERVICE_FLAG); p_tx_obj->p.iic.data_len = idx; qup_set_state(gsbi_id, QUP_STATE_PAUSE); return QUP_SUCCESS; } static qup_return_t qup_i2c_read(gsbi_id_t gsbi_id, uint8_t mode, qup_data_t *p_tx_obj) { qup_return_t ret = QUP_ERR_UNDEFINED; switch (mode) { case QUP_MODE_FIFO: ret = qup_i2c_read_fifo(gsbi_id, p_tx_obj); break; default: ret = QUP_ERR_UNSUPPORTED; } if (ret) { qup_set_state(gsbi_id, QUP_STATE_RESET); printk(BIOS_ERR, "%s() failed (%d)\n", __func__, ret); } return ret; } qup_return_t qup_init(gsbi_id_t gsbi_id, const qup_config_t *config_ptr) { qup_return_t ret = QUP_ERR_UNDEFINED; uint32_t reg_val; /* Reset the QUP core.*/ write32(QUP_ADDR(gsbi_id, QUP_SW_RESET), 0x1); /*Wait till the reset takes effect */ ret = qup_wait_for_state(gsbi_id, QUP_STATE_RESET); if (ret) goto bailout; /* Reset the config */ write32(QUP_ADDR(gsbi_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; } write32(QUP_ADDR(gsbi_id, QUP_CONFIG), reg_val); /*Reset i2c clk cntl register*/ write32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_CLK_CTL), 0); /*Set QUP IO Mode*/ switch (config_ptr->mode) { case QUP_MODE_FIFO: reg_val = QUP_OUTPUT_BIT_SHIFT_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; } write32(QUP_ADDR(gsbi_id, QUP_IO_MODES), reg_val); /*Set i2c clk cntl*/ reg_val = (QUP_DIVIDER_MIN_VAL << QUP_HS_DIVIDER_SHFT); reg_val |= ((((config_ptr->src_frequency / config_ptr->clk_frequency) / 2) - QUP_DIVIDER_MIN_VAL) & QUP_FS_DIVIDER_MASK); write32(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_CLK_CTL), reg_val); bailout: if (ret) printk(BIOS_ERR, "failed to init qup (%d)\n", ret); return ret; } qup_return_t qup_set_state(gsbi_id_t gsbi_id, uint32_t state) { qup_return_t ret = QUP_ERR_UNDEFINED; unsigned int curr_state = read32(QUP_ADDR(gsbi_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 (QUP_STATE_PAUSE == curr_state && QUP_STATE_RESET == state) { write32(QUP_ADDR(gsbi_id, QUP_STATE), 0x2); write32(QUP_ADDR(gsbi_id, QUP_STATE), 0x2); } else { write32(QUP_ADDR(gsbi_id, QUP_STATE), state); } ret = qup_wait_for_state(gsbi_id, state); } return ret; } static qup_return_t qup_i2c_send_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj, uint8_t stop_seq) { qup_return_t ret = QUP_ERR_UNDEFINED; uint8_t mode = (read32(QUP_ADDR(gsbi_id, QUP_IO_MODES)) >> QUP_OUTPUT_MODE_SHFT) & QUP_MODE_MASK; ret = qup_i2c_write(gsbi_id, mode, p_tx_obj, stop_seq); if (0) { int i; printk(BIOS_DEBUG, "i2c tx bus %d device %2.2x:", gsbi_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(gsbi_id_t gsbi_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(gsbi_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(gsbi_id, p_tx_obj, stop_seq); break; default: ret = QUP_ERR_UNSUPPORTED; } } return ret; } static qup_return_t qup_i2c_recv_data(gsbi_id_t gsbi_id, qup_data_t *p_rx_obj) { qup_return_t ret = QUP_ERR_UNDEFINED; uint8_t mode = (read32(QUP_ADDR(gsbi_id, QUP_IO_MODES)) >> QUP_INPUT_MODE_SHFT) & QUP_MODE_MASK; ret = qup_i2c_read(gsbi_id, mode, p_rx_obj); if (0) { int i; printk(BIOS_DEBUG, "i2c rxed on bus %d device %2.2x:", gsbi_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(gsbi_id_t gsbi_id, qup_data_t *p_rx_obj) { qup_return_t ret = QUP_ERR_UNDEFINED; if (p_rx_obj->protocol == ((read32(QUP_ADDR(gsbi_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(gsbi_id, p_rx_obj); break; default: ret = QUP_ERR_UNSUPPORTED; } } return ret; }