summaryrefslogtreecommitdiff
path: root/src/soc/mediatek/common
diff options
context:
space:
mode:
authorQii Wang <qii.wang@mediatek.com>2020-11-20 17:36:07 +0800
committerHung-Te Lin <hungte@chromium.org>2020-12-14 03:55:13 +0000
commitcd83bf8874b13639bbd0b9e3b1270a5771d5e5bc (patch)
tree6a620a74dd402e61530de3aeb2876e656af9bb50 /src/soc/mediatek/common
parent9ef72ca7db807a7ae2e7d78144773940dd688a78 (diff)
soc/mediatek/mt8192: add i2c driver support
Add I2C controller for MT8192, and revise the common I2C driver to support I2C controller running in APDMA async mode. In that case we have to initiate a different handshake protocol and reset I2C differently. BUG=b:155715435 TEST=Asurada boots up to shell Signed-off-by: Qii Wang <qii.wang@mediatek.com> Change-Id: I13835e00eb674a93aa5496a9870d1e601e263368 Reviewed-on: https://review.coreboot.org/c/coreboot/+/47800 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Diffstat (limited to 'src/soc/mediatek/common')
-rw-r--r--src/soc/mediatek/common/i2c.c51
-rw-r--r--src/soc/mediatek/common/include/soc/i2c_common.h19
2 files changed, 57 insertions, 13 deletions
diff --git a/src/soc/mediatek/common/i2c.c b/src/soc/mediatek/common/i2c.c
index 87925ba169..3c54b17738 100644
--- a/src/soc/mediatek/common/i2c.c
+++ b/src/soc/mediatek/common/i2c.c
@@ -10,14 +10,34 @@
#include <soc/i2c.h>
#include <device/i2c_simple.h>
-static inline void i2c_dma_reset(struct mt_i2c_dma_regs *dma_regs)
+static inline void i2c_hw_reset(uint8_t bus)
{
- write32(&dma_regs->dma_rst, 0x1);
- udelay(50);
- write32(&dma_regs->dma_rst, 0x2);
- udelay(50);
- write32(&dma_regs->dma_rst, 0x0);
- udelay(50);
+ struct mt_i2c_regs *regs;
+ struct mt_i2c_dma_regs *dma_regs;
+
+ regs = mtk_i2c_bus_controller[bus].i2c_regs;
+ dma_regs = mtk_i2c_bus_controller[bus].i2c_dma_regs;
+
+ if (mtk_i2c_bus_controller[bus].mt_i2c_flag == I2C_APDMA_ASYNC) {
+ write32(&dma_regs->dma_rst, I2C_DMA_WARM_RST);
+ udelay(10);
+ write32(&dma_regs->dma_rst, I2C_DMA_CLR_FLAG);
+ udelay(10);
+ write32(&dma_regs->dma_rst,
+ I2C_DMA_HARD_RST | I2C_DMA_HANDSHAKE_RST);
+ write32(&regs->softreset, I2C_SOFT_RST | I2C_HANDSHAKE_RST);
+ udelay(10);
+ write32(&dma_regs->dma_rst, I2C_DMA_CLR_FLAG);
+ write32(&regs->softreset, I2C_CLR_FLAG);
+ } else {
+ write32(&regs->softreset, I2C_SOFT_RST);
+ write32(&dma_regs->dma_rst, I2C_DMA_WARM_RST);
+ udelay(50);
+ write32(&dma_regs->dma_rst, I2C_DMA_HARD_RST);
+ udelay(50);
+ write32(&dma_regs->dma_rst, I2C_DMA_CLR_FLAG);
+ udelay(50);
+ }
}
static inline void mtk_i2c_dump_info(struct mt_i2c_regs *regs)
@@ -47,6 +67,7 @@ static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg,
{
uint32_t ret_code = I2C_OK;
uint16_t status;
+ uint16_t dma_sync = 0;
uint32_t time_out_val = 0;
uint8_t addr;
uint32_t write_len = 0;
@@ -62,6 +83,12 @@ static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg,
addr = seg[0].slave;
+ if (mtk_i2c_bus_controller[bus].mt_i2c_flag == I2C_APDMA_ASYNC) {
+ dma_sync = I2C_DMA_SKIP_CONFIG | I2C_DMA_ASYNC_MODE;
+ if (mode == I2C_WRITE_READ_MODE)
+ dma_sync |= I2C_DMA_DIR_CHANGE;
+ }
+
switch (mode) {
case I2C_WRITE_MODE:
assert(seg[0].len > 0 && seg[0].len <= 255);
@@ -113,7 +140,7 @@ static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg,
write32(&regs->slave_addr, addr << 1);
/* Prepare buffer data to start transfer */
- write32(&dma_regs->dma_con, I2C_DMA_CON_TX);
+ write32(&dma_regs->dma_con, I2C_DMA_CON_TX | dma_sync);
write32(&dma_regs->dma_tx_mem_addr, (uintptr_t)_dma_coherent);
write32(&dma_regs->dma_tx_len, write_len);
break;
@@ -132,7 +159,7 @@ static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg,
write32(&regs->slave_addr, (addr << 1 | 0x1));
/* Prepare buffer data to start transfer */
- write32(&dma_regs->dma_con, I2C_DMA_CON_RX);
+ write32(&dma_regs->dma_con, I2C_DMA_CON_RX | dma_sync);
write32(&dma_regs->dma_rx_mem_addr, (uintptr_t)_dma_coherent);
write32(&dma_regs->dma_rx_len, read_len);
break;
@@ -154,7 +181,7 @@ static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg,
write32(&regs->slave_addr, addr << 1);
/* Prepare buffer data to start transfer */
- write32(&dma_regs->dma_con, I2C_DMA_CLR_FLAG);
+ write32(&dma_regs->dma_con, I2C_DMA_CLR_FLAG | dma_sync);
write32(&dma_regs->dma_tx_mem_addr, (uintptr_t)_dma_coherent);
write32(&dma_regs->dma_tx_len, write_len);
write32(&dma_regs->dma_rx_mem_addr, (uintptr_t)_dma_coherent);
@@ -206,9 +233,7 @@ static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg,
I2C_TRANSAC_COMP);
/* reset the i2c controller for next i2c transfer. */
- write32(&regs->softreset, 0x1);
-
- i2c_dma_reset(dma_regs);
+ i2c_hw_reset(bus);
return ret_code;
}
diff --git a/src/soc/mediatek/common/include/soc/i2c_common.h b/src/soc/mediatek/common/include/soc/i2c_common.h
index 0100e261cd..d2da27ef4c 100644
--- a/src/soc/mediatek/common/include/soc/i2c_common.h
+++ b/src/soc/mediatek/common/include/soc/i2c_common.h
@@ -38,6 +38,12 @@ enum {
I2C_DMA_INT_FLAG_NONE = 0x0,
I2C_DMA_CLR_FLAG = 0x0,
I2C_DMA_FLUSH_FLAG = 0x1,
+ I2C_DMA_ASYNC_MODE = 0x0004,
+ I2C_DMA_SKIP_CONFIG = 0x0010,
+ I2C_DMA_DIR_CHANGE = 0x0200,
+ I2C_DMA_WARM_RST = 0x1,
+ I2C_DMA_HARD_RST = 0x2,
+ I2C_DMA_HANDSHAKE_RST = 0x4,
};
enum {
@@ -46,6 +52,11 @@ enum {
I2C_CONTROL_MASK = (0x3f << 1)
};
+enum {
+ I2C_APDMA_NOASYNC = 0,
+ I2C_APDMA_ASYNC = 1,
+};
+
/* Register mask */
enum {
I2C_HS_NACKERR = (1 << 2),
@@ -53,6 +64,13 @@ enum {
I2C_TRANSAC_COMP = (1 << 0),
};
+/* reset bits */
+enum {
+ I2C_CLR_FLAG = 0x0,
+ I2C_SOFT_RST = 0x1,
+ I2C_HANDSHAKE_RST = 0x20,
+};
+
/* i2c control bits */
enum {
ASYNC_MODE = (1 << 9),
@@ -80,6 +98,7 @@ enum {
struct mtk_i2c {
struct mt_i2c_regs *i2c_regs;
struct mt_i2c_dma_regs *i2c_dma_regs;
+ uint32_t mt_i2c_flag;
};
extern struct mtk_i2c mtk_i2c_bus_controller[];