summaryrefslogtreecommitdiffstats
path: root/src/soc/mediatek/mt8192/i2c.c
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/mt8192/i2c.c
parent9ef72ca7db807a7ae2e7d78144773940dd688a78 (diff)
downloadcoreboot-cd83bf8874b13639bbd0b9e3b1270a5771d5e5bc.tar.gz
coreboot-cd83bf8874b13639bbd0b9e3b1270a5771d5e5bc.tar.bz2
coreboot-cd83bf8874b13639bbd0b9e3b1270a5771d5e5bc.zip
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/mt8192/i2c.c')
-rw-r--r--src/soc/mediatek/mt8192/i2c.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/soc/mediatek/mt8192/i2c.c b/src/soc/mediatek/mt8192/i2c.c
new file mode 100644
index 000000000000..e38cbb617de1
--- /dev/null
+++ b/src/soc/mediatek/mt8192/i2c.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <assert.h>
+#include <device/mmio.h>
+#include <soc/pll.h>
+#include <soc/i2c.h>
+#include <soc/gpio.h>
+
+#define I2C_CLK_HZ (UNIVPLL_HZ / 20)
+struct mtk_i2c mtk_i2c_bus_controller[] = {
+ [0] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x250000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [1] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x70000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x80),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [2] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x71000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x100),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [3] = {
+ .i2c_regs = (void *)(I2C_BASE),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x280),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [4] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x72000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x300),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [5] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x150000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x480),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [6] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x251000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x500),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [7] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x50000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x580),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [8] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x51000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x700),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+ [9] = {
+ .i2c_regs = (void *)(I2C_BASE + 0x52000),
+ .i2c_dma_regs = (void *)(I2C_DMA_BASE + 0x880),
+ .mt_i2c_flag = I2C_APDMA_ASYNC,
+ },
+};
+
+#define I2C_BUS_NUMBER ARRAY_SIZE(mtk_i2c_bus_controller)
+
+struct pad_func {
+ gpio_t gpio;
+ u8 func;
+};
+
+#define PAD_FUNC(name, func) {GPIO(name), PAD_##name##_FUNC_##func}
+
+static const struct pad_func i2c_funcs[I2C_BUS_NUMBER][2] = {
+ [0] = {
+ PAD_FUNC(SDA0, SDA0),
+ PAD_FUNC(SCL0, SCL0),
+ },
+ [1] = {
+ PAD_FUNC(SDA1, SDA1),
+ PAD_FUNC(SCL1, SCL1),
+ },
+ [2] = {
+ PAD_FUNC(SDA2, SDA2),
+ PAD_FUNC(SCL2, SCL2),
+ },
+ [3] = {
+ PAD_FUNC(SDA3, SDA3),
+ PAD_FUNC(SCL3, SCL3),
+ },
+ [4] = {
+ PAD_FUNC(SDA4, SDA4),
+ PAD_FUNC(SCL4, SCL4),
+ },
+ [5] = {
+ PAD_FUNC(SDA5, SDA5),
+ PAD_FUNC(SCL5, SCL5),
+ },
+ [6] = {
+ PAD_FUNC(SDA6, SDA6),
+ PAD_FUNC(SCL6, SCL6),
+ },
+ [7] = {
+ PAD_FUNC(SDA7, SDA7),
+ PAD_FUNC(SCL7, SCL7),
+ },
+ [8] = {
+ PAD_FUNC(SDA8, SDA8),
+ PAD_FUNC(SCL8, SCL8),
+ },
+ [9] = {
+ PAD_FUNC(SDA9, SDA9),
+ PAD_FUNC(SCL9, SCL9),
+ },
+};
+
+static void mtk_i2c_set_gpio_pinmux(uint8_t bus)
+{
+ assert(bus < I2C_BUS_NUMBER);
+
+ const struct pad_func *ptr = i2c_funcs[bus];
+ for (size_t i = 0; i < 2; i++) {
+ gpio_set_mode(ptr[i].gpio, ptr[i].func);
+ gpio_set_pull(ptr[i].gpio, GPIO_PULL_ENABLE, GPIO_PULL_UP);
+ }
+}
+
+static void mtk_i2c_speed_init(uint8_t bus)
+{
+ uint8_t step_div;
+ const uint8_t clock_div = 5;
+ const uint8_t sample_div = 1;
+ uint32_t i2c_freq;
+
+ assert(bus < I2C_BUS_NUMBER);
+
+ /* Calculate i2c frequency */
+ step_div = DIV_ROUND_UP(I2C_CLK_HZ,
+ (400 * KHz * sample_div * 2) * clock_div);
+ i2c_freq = I2C_CLK_HZ / (step_div * sample_div * 2 * clock_div);
+ assert(sample_div < 8 && step_div < 64 && i2c_freq <= 400 * KHz &&
+ i2c_freq >= 380 * KHz);
+
+ /* Init i2c bus timing register */
+ write32(&mtk_i2c_bus_controller[bus].i2c_regs->timing,
+ (sample_div - 1) << 8 | (step_div - 1));
+ write32(&mtk_i2c_bus_controller[bus].i2c_regs->ltiming,
+ (sample_div - 1) << 6 | (step_div - 1));
+
+ /* Init i2c bus clock_div register */
+ write32(&mtk_i2c_bus_controller[bus].i2c_regs->clock_div,
+ clock_div - 1);
+}
+
+void mtk_i2c_bus_init(uint8_t bus)
+{
+ mtk_i2c_speed_init(bus);
+ mtk_i2c_set_gpio_pinmux(bus);
+}