<p>Patrick Rudolph has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/23751">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">soc/cavium: Add twsi<br><br>Add TWSI.<br>Ported from BDK uboot tree.<br><br>Change-Id: I9f85d024b3ffd0a0c4376a8880d14db9e3570d79<br>Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com><br>---<br>M src/soc/cavium/cn81xx/Makefile.inc<br>A src/soc/cavium/cn81xx/twsi.c<br>M src/soc/cavium/common/Makefile.inc<br>D src/soc/cavium/common/i2c.c<br>A src/soc/cavium/common/include/soc/twsi.h<br>A src/soc/cavium/common/twsi.c<br>6 files changed, 764 insertions(+), 331 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/51/23751/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/soc/cavium/cn81xx/Makefile.inc b/src/soc/cavium/cn81xx/Makefile.inc</span><br><span>index d2bd94b..fbba930 100644</span><br><span>--- a/src/soc/cavium/cn81xx/Makefile.inc</span><br><span>+++ b/src/soc/cavium/cn81xx/Makefile.inc</span><br><span>@@ -28,12 +28,15 @@</span><br><span> bootblock-y += bootblock.c</span><br><span> bootblock-y += clock.c</span><br><span> #bootblock-y += gpio.c</span><br><span style="color: hsl(120, 100%, 40%);">+bootblock-y += twsi.c</span><br><span> bootblock-y += l2c.c</span><br><span> bootblock-y += mmu_operations.c</span><br><span> #bootblock-y += sdram.c</span><br><span> bootblock-y += timer.c</span><br><span> bootblock-y += ../common/wdt.c</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+romstage-y += twsi.c</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> romstage-y += sdram.c</span><br><span> romstage-y += ../common/bdk/libdram/libdram.c</span><br><span> romstage-y += ../common/bdk/libbdk-arch/bdk-csr.c</span><br><span>@@ -98,6 +101,7 @@</span><br><span> ramstage-y += ../common/cbmem.c</span><br><span> ramstage-y += sdram.c</span><br><span> ramstage-y += spi.c</span><br><span style="color: hsl(120, 100%, 40%);">+ramstage-y += twsi.c</span><br><span> ramstage-$(CONFIG_DRIVERS_UART) += uart.c</span><br><span> ##ramstage-y += clock.c</span><br><span> #ramstage-y += ../common/gpio.c</span><br><span>diff --git a/src/soc/cavium/cn81xx/twsi.c b/src/soc/cavium/cn81xx/twsi.c</span><br><span>new file mode 100644</span><br><span>index 0000000..a87de79</span><br><span>--- /dev/null</span><br><span>+++ b/src/soc/cavium/cn81xx/twsi.c</span><br><span>@@ -0,0 +1,20 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright 2018-present  Facebook, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stddef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <soc/twsi.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *const twsi_bus[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ (void *const)0x87E0D0000000ULL,</span><br><span style="color: hsl(120, 100%, 40%);">+       (void *const)0x87E0D1000000ULL,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void *twsi_get_baseaddr(const size_t bus)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   assert (bus < ARRAY_SIZE(twsi_bus));</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bus >= ARRAY_SIZE(twsi_bus))</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return twsi_bus[bus];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/soc/cavium/common/Makefile.inc b/src/soc/cavium/common/Makefile.inc</span><br><span>index 2ed9a5e..6777dfc 100644</span><br><span>--- a/src/soc/cavium/common/Makefile.inc</span><br><span>+++ b/src/soc/cavium/common/Makefile.inc</span><br><span>@@ -16,5 +16,15 @@</span><br><span> ifeq ($(CONFIG_SOC_CAVIUM_COMMON),y)</span><br><span> </span><br><span> bootblock-$(CONFIG_BOOTBLOCK_CUSTOM) += bootblock.c</span><br><span style="color: hsl(120, 100%, 40%);">+bootblock-y += twsi.c</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+romstage-y += twsi.c</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ramstage-y += twsi.c</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+CPPFLAGS_common += -Isrc/soc/cavium/common/include</span><br><span> </span><br><span> endif</span><br><span>diff --git a/src/soc/cavium/common/i2c.c b/src/soc/cavium/common/i2c.c</span><br><span>deleted file mode 100644</span><br><span>index 6c1bdfa..0000000</span><br><span>--- a/src/soc/cavium/common/i2c.c</span><br><span>+++ /dev/null</span><br><span>@@ -1,331 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-/*</span><br><span style="color: hsl(0, 100%, 40%);">- * This file is part of the coreboot project.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * Copyright 2017-present Facebook, Inc.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(0, 100%, 40%);">- * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(0, 100%, 40%);">- * the Free Software Foundation; version 2 of the License.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(0, 100%, 40%);">- * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(0, 100%, 40%);">- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">- * GNU General Public License for more details.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* FIXME: scaffolding based on rk3399 */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <arch/io.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <assert.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <cbfs.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <console/console.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <delay.h></span><br><span style="color: hsl(0, 100%, 40%);">-//#include <device/i2c_simple.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <soc/addressmap.h></span><br><span style="color: hsl(0, 100%, 40%);">-//#include <soc/grf.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <soc/soc.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <soc/i2c.h></span><br><span style="color: hsl(0, 100%, 40%);">-//#include <soc/clock.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <stdlib.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <string.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#define RETRY_COUNT      3</span><br><span style="color: hsl(0, 100%, 40%);">-/* 100000us = 100ms */</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_TIMEOUT_US   100000</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_BUS_MAX       6</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_NOACK      2</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_TIMEOUT    3</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#define i2c_info(x...) do {if (0) printk(BIOS_DEBUG, x); } while (0)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">-struct rk_i2c_regs {</span><br><span style="color: hsl(0, 100%, 40%);">-  u32 i2c_con;</span><br><span style="color: hsl(0, 100%, 40%);">-    u32 i2c_clkdiv;</span><br><span style="color: hsl(0, 100%, 40%);">- u32 i2c_mrxaddr;</span><br><span style="color: hsl(0, 100%, 40%);">-        u32 i2c_mrxraddr;</span><br><span style="color: hsl(0, 100%, 40%);">-       u32 i2c_mtxcnt;</span><br><span style="color: hsl(0, 100%, 40%);">- u32 i2c_mrxcnt;</span><br><span style="color: hsl(0, 100%, 40%);">- u32 i2c_ien;</span><br><span style="color: hsl(0, 100%, 40%);">-    u32 i2c_ipd;</span><br><span style="color: hsl(0, 100%, 40%);">-    u32 i2c_fcnt;</span><br><span style="color: hsl(0, 100%, 40%);">-   u32 reserved0[(0x100 - 0x24) / 4];</span><br><span style="color: hsl(0, 100%, 40%);">-      u32 txdata[8];</span><br><span style="color: hsl(0, 100%, 40%);">-  u32 reserved1[(0x200 - 0x120) / 4];</span><br><span style="color: hsl(0, 100%, 40%);">-     u32 rxdata[8];</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static const uintptr_t i2c_bus[] = IC_BASES;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Con register bits. */</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_ACT2NAK                 (1<<6)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_NAK                             (1<<5)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_STOP                            (1<<4)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_START                   (1<<3)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_MODE_TX                 (0<<1)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_MODE_TRX                (1<<1)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_MODE_RX                 (2<<1)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_EN                              (1<<0)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_8BIT    (1<<24)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_16BIT  (3<<24)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_24BIT  (7<<24)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Mtxcnt register bits. */</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_CNT(cnt)            ((cnt) & 0x3F)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_NAKRCVI   (1<<6)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_STOPI   (1<<5)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_STARTI  (1<<4)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_MBRFI   (1<<3)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_MBTFI   (1<<2)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_BRFI    (1<<1)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_BTFI    (1<<0)</span><br><span style="color: hsl(0, 100%, 40%);">-#define I2C_CLEANI  0x7F</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int i2c_send_start(struct cavium_i2c_regs *reg_addr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  /* FIXME: stub */</span><br><span style="color: hsl(0, 100%, 40%);">-       printk(BIOS_ERR, "%s: implement this.\n", __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- int res = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    int timeout = I2C_TIMEOUT_US;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   i2c_info("I2c Start::Send Start bit\n");</span><br><span style="color: hsl(0, 100%, 40%);">-      write32(&reg_addr->i2c_ipd, I2C_CLEANI);</span><br><span style="color: hsl(0, 100%, 40%);">- write32(&reg_addr->i2c_con, I2C_EN | I2C_START);</span><br><span style="color: hsl(0, 100%, 40%);">- while (timeout--) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (read32(&reg_addr->i2c_ipd) & I2C_STARTI)</span><br><span style="color: hsl(0, 100%, 40%);">-                 break;</span><br><span style="color: hsl(0, 100%, 40%);">-          udelay(1);</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (timeout <= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-          printk(BIOS_ERR, "I2C Start::Send Start Bit Timeout\n");</span><br><span style="color: hsl(0, 100%, 40%);">-              res = I2C_TIMEOUT;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return res;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int i2c_send_stop(struct cavium_i2c_regs *reg_addr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   /* FIXME: stub */</span><br><span style="color: hsl(0, 100%, 40%);">-       printk(BIOS_ERR, "%s: implement this.\n", __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- int res = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    int timeout = I2C_TIMEOUT_US;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   i2c_info("I2c Stop::Send Stop bit\n");</span><br><span style="color: hsl(0, 100%, 40%);">-        write32(&reg_addr->i2c_ipd, I2C_CLEANI);</span><br><span style="color: hsl(0, 100%, 40%);">- write32(&reg_addr->i2c_con, I2C_EN | I2C_STOP);</span><br><span style="color: hsl(0, 100%, 40%);">-  while (timeout--) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (read32(&reg_addr->i2c_ipd) & I2C_STOPI)</span><br><span style="color: hsl(0, 100%, 40%);">-                  break;</span><br><span style="color: hsl(0, 100%, 40%);">-          udelay(1);</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       write32(&reg_addr->i2c_con, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (timeout <= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-          printk(BIOS_ERR, "I2C Stop::Send Stop Bit Timeout\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                res = I2C_TIMEOUT;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return res;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int i2c_read(struct cavium_i2c_regs *reg_addr, struct i2c_msg segment)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        /* FIXME: stub */</span><br><span style="color: hsl(0, 100%, 40%);">-       printk(BIOS_ERR, "%s: implement this.\n", __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- int res = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t *data = segment.buf;</span><br><span style="color: hsl(0, 100%, 40%);">-    int timeout = I2C_TIMEOUT_US;</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned int bytes_remaining = segment.len;</span><br><span style="color: hsl(0, 100%, 40%);">-     unsigned int bytes_transferred = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     unsigned int words_transferred = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     unsigned int rxdata = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-        unsigned int con = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned int i, j;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      write32(&reg_addr->i2c_mrxaddr, I2C_8BIT | segment.slave << 1 | 1);</span><br><span style="color: hsl(0, 100%, 40%);">-        write32(&reg_addr->i2c_mrxraddr, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-     con = I2C_MODE_TRX | I2C_EN | I2C_ACT2NAK;</span><br><span style="color: hsl(0, 100%, 40%);">-      while (bytes_remaining) {</span><br><span style="color: hsl(0, 100%, 40%);">-               bytes_transferred = MIN(bytes_remaining, 32);</span><br><span style="color: hsl(0, 100%, 40%);">-           bytes_remaining -= bytes_transferred;</span><br><span style="color: hsl(0, 100%, 40%);">-           if (!bytes_remaining)</span><br><span style="color: hsl(0, 100%, 40%);">-                   con |= I2C_EN | I2C_NAK;</span><br><span style="color: hsl(0, 100%, 40%);">-                words_transferred = ALIGN_UP(bytes_transferred, 4) / 4;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         write32(&reg_addr->i2c_ipd, I2C_CLEANI);</span><br><span style="color: hsl(0, 100%, 40%);">-         write32(&reg_addr->i2c_con, con);</span><br><span style="color: hsl(0, 100%, 40%);">-                write32(&reg_addr->i2c_mrxcnt, bytes_transferred);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               timeout = I2C_TIMEOUT_US;</span><br><span style="color: hsl(0, 100%, 40%);">-               while (timeout--) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (read32(&reg_addr->i2c_ipd) & I2C_NAKRCVI) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              write32(&reg_addr->i2c_mrxcnt, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                               write32(&reg_addr->i2c_con, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                          return I2C_NOACK;</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (read32(&reg_addr->i2c_ipd) & I2C_MBRFI)</span><br><span style="color: hsl(0, 100%, 40%);">-                          break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  udelay(1);</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (timeout <= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  printk(BIOS_ERR, "I2C Read::Recv Data Timeout\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                    write32(&reg_addr->i2c_mrxcnt, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                       write32(&reg_addr->i2c_con, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                  return I2C_TIMEOUT;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               for (i = 0; i < words_transferred; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    rxdata = read32(&reg_addr->rxdata[i]);</span><br><span style="color: hsl(0, 100%, 40%);">-                   i2c_info("I2c Read::RXDATA[%d] = 0x%x\n", i, rxdata);</span><br><span style="color: hsl(0, 100%, 40%);">-                 for (j = 0; j < 4; j++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            if ((i * 4 + j) == bytes_transferred)</span><br><span style="color: hsl(0, 100%, 40%);">-                                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-                          *data++ = (rxdata >> (j * 8)) & 0xff;</span><br><span style="color: hsl(0, 100%, 40%);">-                 }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               con = I2C_MODE_RX | I2C_EN | I2C_ACT2NAK;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-       return res;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int i2c_write(struct rk_i2c_regs *reg_addr, struct i2c_msg segment)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   /* FIXME: stub */</span><br><span style="color: hsl(0, 100%, 40%);">-       printk(BIOS_ERR, "%s: implement this.\n", __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- int res = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t *data = segment.buf;</span><br><span style="color: hsl(0, 100%, 40%);">-    int timeout = I2C_TIMEOUT_US;</span><br><span style="color: hsl(0, 100%, 40%);">-   int bytes_remaining = segment.len + 1;</span><br><span style="color: hsl(0, 100%, 40%);">-  int bytes_transferred = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-      int words_transferred = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-      unsigned int i;</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int j = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-     u32 txdata = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- txdata |= (segment.slave << 1);</span><br><span style="color: hsl(0, 100%, 40%);">-   while (bytes_remaining) {</span><br><span style="color: hsl(0, 100%, 40%);">-               bytes_transferred = MIN(bytes_remaining, 32);</span><br><span style="color: hsl(0, 100%, 40%);">-           words_transferred = ALIGN_UP(bytes_transferred, 4) / 4;</span><br><span style="color: hsl(0, 100%, 40%);">-         for (i = 0; i < words_transferred; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    do {</span><br><span style="color: hsl(0, 100%, 40%);">-                            if ((i * 4 + j) == bytes_transferred)</span><br><span style="color: hsl(0, 100%, 40%);">-                                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-                          txdata |= (*data++) << (j * 8);</span><br><span style="color: hsl(0, 100%, 40%);">-                   } while (++j < 4);</span><br><span style="color: hsl(0, 100%, 40%);">-                   write32(&reg_addr->txdata[i], txdata);</span><br><span style="color: hsl(0, 100%, 40%);">-                   j = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                  i2c_info("I2c Write::TXDATA[%d] = 0x%x\n", i, txdata);</span><br><span style="color: hsl(0, 100%, 40%);">-                        txdata = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               write32(&reg_addr->i2c_ipd, I2C_CLEANI);</span><br><span style="color: hsl(0, 100%, 40%);">-         write32(&reg_addr->i2c_con,</span><br><span style="color: hsl(0, 100%, 40%);">-                      I2C_EN | I2C_MODE_TX | I2C_ACT2NAK);</span><br><span style="color: hsl(0, 100%, 40%);">-            write32(&reg_addr->i2c_mtxcnt, bytes_transferred);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               timeout = I2C_TIMEOUT_US;</span><br><span style="color: hsl(0, 100%, 40%);">-               while (timeout--) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (read32(&reg_addr->i2c_ipd) & I2C_NAKRCVI) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              write32(&reg_addr->i2c_mtxcnt, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                               write32(&reg_addr->i2c_con, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                          return I2C_NOACK;</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (read32(&reg_addr->i2c_ipd) & I2C_MBTFI)</span><br><span style="color: hsl(0, 100%, 40%);">-                          break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  udelay(1);</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (timeout <= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  printk(BIOS_ERR, "I2C Write::Send Data Timeout\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                   write32(&reg_addr->i2c_mtxcnt, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                       write32(&reg_addr->i2c_con, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                  return I2C_TIMEOUT;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               bytes_remaining -= bytes_transferred;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-       return res;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int i2c_do_xfer(void *reg_addr, struct i2c_msg segment)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       /* FIXME: stub */</span><br><span style="color: hsl(0, 100%, 40%);">-       printk(BIOS_ERR, "%s: implement this.\n", __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- int res = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (i2c_send_start(reg_addr))</span><br><span style="color: hsl(0, 100%, 40%);">-           return I2C_TIMEOUT;</span><br><span style="color: hsl(0, 100%, 40%);">-     if (segment.flags & I2C_M_RD)</span><br><span style="color: hsl(0, 100%, 40%);">-               res = i2c_read(reg_addr, segment);</span><br><span style="color: hsl(0, 100%, 40%);">-      else</span><br><span style="color: hsl(0, 100%, 40%);">-            res = i2c_write(reg_addr, segment);</span><br><span style="color: hsl(0, 100%, 40%);">-     return i2c_send_stop(reg_addr) || res;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,</span><br><span style="color: hsl(0, 100%, 40%);">-                    int seg_count)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       /* FIXME: stub */</span><br><span style="color: hsl(0, 100%, 40%);">-       printk(BIOS_ERR, "%s: implement this.\n", __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- int i;</span><br><span style="color: hsl(0, 100%, 40%);">-  int res = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct rk_i2c_regs *regs = (struct rk_i2c_regs *)(i2c_bus[bus]);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct i2c_msg *seg = segments;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- for (i = 0; i < seg_count; i++, seg++) {</span><br><span style="color: hsl(0, 100%, 40%);">-             res = i2c_do_xfer(regs, *seg);</span><br><span style="color: hsl(0, 100%, 40%);">-          if (res)</span><br><span style="color: hsl(0, 100%, 40%);">-                        break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-       return res;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void i2c_init(unsigned int bus, unsigned int hz)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     /* FIXME: stub */</span><br><span style="color: hsl(0, 100%, 40%);">-       printk(BIOS_ERR, "%s: implement this.\n", __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-  return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int clk_div;</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned int divl;</span><br><span style="color: hsl(0, 100%, 40%);">-      unsigned int divh;</span><br><span style="color: hsl(0, 100%, 40%);">-      unsigned int i2c_src_clk;</span><br><span style="color: hsl(0, 100%, 40%);">-       unsigned int i2c_clk;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct rk_i2c_regs *regs = (struct rk_i2c_regs *)(i2c_bus[bus]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        i2c_src_clk = rkclk_i2c_clock_for_bus(bus);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* SCL Divisor = 8*(CLKDIVL + 1 + CLKDIVH + 1)</span><br><span style="color: hsl(0, 100%, 40%);">-     SCL = PCLK / SCLK Divisor */</span><br><span style="color: hsl(0, 100%, 40%);">- clk_div = div_round_up(i2c_src_clk, hz * 8);</span><br><span style="color: hsl(0, 100%, 40%);">-    divh = clk_div * 3 / 7 - 1;</span><br><span style="color: hsl(0, 100%, 40%);">-     divl = clk_div - divh - 2;</span><br><span style="color: hsl(0, 100%, 40%);">-      i2c_clk = i2c_src_clk / (8 * (divl + 1 + divh + 1));</span><br><span style="color: hsl(0, 100%, 40%);">-    printk(BIOS_DEBUG, "I2C bus %u: %uHz (divh = %u, divl = %u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              bus, i2c_clk, divh, divl);</span><br><span style="color: hsl(0, 100%, 40%);">-       assert((divh < 65536) && (divl < 65536) && hz - i2c_clk < 15*KHz);</span><br><span style="color: hsl(0, 100%, 40%);">-     write32(&regs->i2c_clkdiv, (divh << 16) | (divl << 0));</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span>diff --git a/src/soc/cavium/common/include/soc/twsi.h b/src/soc/cavium/common/include/soc/twsi.h</span><br><span>new file mode 100644</span><br><span>index 0000000..a9f23ad</span><br><span>--- /dev/null</span><br><span>+++ b/src/soc/cavium/common/include/soc/twsi.h</span><br><span>@@ -0,0 +1,14 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright 2018-present  Facebook, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier:    GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <types.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <device/i2c.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef __SOC_CAVIUM_CN81XX_INCLUDE_SOC_TWSI_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define __SOC_CAVIUM_CN81XX_INCLUDE_SOC_TWSI_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int twsi_init(unsigned int bus, enum i2c_speed hz);</span><br><span style="color: hsl(120, 100%, 40%);">+void *twsi_get_baseaddr(const size_t bus);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>diff --git a/src/soc/cavium/common/twsi.c b/src/soc/cavium/common/twsi.c</span><br><span>new file mode 100644</span><br><span>index 0000000..e2ea838</span><br><span>--- /dev/null</span><br><span>+++ b/src/soc/cavium/common/twsi.c</span><br><span>@@ -0,0 +1,716 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright 2016          Cavium, Inc. <support@cavium.com></span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright 2018-present  Facebook, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier:       GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <console/console.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <soc/twsi.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <device/i2c.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <device/i2c_simple.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <delay.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arch/io.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define RST_BOOT    ((void *const)0x87e006001600ll)</span><br><span style="color: hsl(120, 100%, 40%);">+#define PLL_REF_CLK    50000000        /* 50 MHz */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TWSI_THP                24</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TWSI_SW_TWSI              0x1000</span><br><span style="color: hsl(120, 100%, 40%);">+#define TWSI_TWSI_SW            0x1008</span><br><span style="color: hsl(120, 100%, 40%);">+#define TWSI_INT                0x1010</span><br><span style="color: hsl(120, 100%, 40%);">+#define TWSI_SW_TWSI_EXT        0x1018</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+union rst_boot {</span><br><span style="color: hsl(120, 100%, 40%);">+    u64 u;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              u64 rboot_pin:1;</span><br><span style="color: hsl(120, 100%, 40%);">+              u64 rboot:1;</span><br><span style="color: hsl(120, 100%, 40%);">+          u64 lboot:10;</span><br><span style="color: hsl(120, 100%, 40%);">+         u64 lboot_ext23:6;</span><br><span style="color: hsl(120, 100%, 40%);">+            u64 lboot_ext45:6;</span><br><span style="color: hsl(120, 100%, 40%);">+            u64 reserved_24_29:6;</span><br><span style="color: hsl(120, 100%, 40%);">+         u64 lboot_oci:3;</span><br><span style="color: hsl(120, 100%, 40%);">+              u64 pnr_mul:6;</span><br><span style="color: hsl(120, 100%, 40%);">+                u64 reserved_39_39:1;</span><br><span style="color: hsl(120, 100%, 40%);">+         u64 c_mul:7;</span><br><span style="color: hsl(120, 100%, 40%);">+          u64 reserved_47_54:8;</span><br><span style="color: hsl(120, 100%, 40%);">+         u64 dis_scan:1;</span><br><span style="color: hsl(120, 100%, 40%);">+               u64 dis_huk:1;</span><br><span style="color: hsl(120, 100%, 40%);">+                u64 vrm_err:1;</span><br><span style="color: hsl(120, 100%, 40%);">+                u64 jt_tstmode:1;</span><br><span style="color: hsl(120, 100%, 40%);">+             u64 ckill_ppdis:1;</span><br><span style="color: hsl(120, 100%, 40%);">+            u64 trusted_mode:1;</span><br><span style="color: hsl(120, 100%, 40%);">+           u64 ejtagdis:1;</span><br><span style="color: hsl(120, 100%, 40%);">+               u64 jtcsrdis:1;</span><br><span style="color: hsl(120, 100%, 40%);">+               u64 chipkill:1;</span><br><span style="color: hsl(120, 100%, 40%);">+       } s;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+union twsx_sw_twsi {</span><br><span style="color: hsl(120, 100%, 40%);">+      u64 u;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              u64 data:32;</span><br><span style="color: hsl(120, 100%, 40%);">+          u64 eop_ia:3;</span><br><span style="color: hsl(120, 100%, 40%);">+         u64 ia:5;</span><br><span style="color: hsl(120, 100%, 40%);">+             u64 addr:10;</span><br><span style="color: hsl(120, 100%, 40%);">+          u64 scr:2;</span><br><span style="color: hsl(120, 100%, 40%);">+            u64 size:3;</span><br><span style="color: hsl(120, 100%, 40%);">+           u64 sovr:1;</span><br><span style="color: hsl(120, 100%, 40%);">+           u64 r:1;</span><br><span style="color: hsl(120, 100%, 40%);">+              u64 op:4;</span><br><span style="color: hsl(120, 100%, 40%);">+             u64 eia:1;</span><br><span style="color: hsl(120, 100%, 40%);">+            u64 slonly:1;</span><br><span style="color: hsl(120, 100%, 40%);">+         u64 v:1;</span><br><span style="color: hsl(120, 100%, 40%);">+      } s;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+union twsx_sw_twsi_ext {</span><br><span style="color: hsl(120, 100%, 40%);">+  u64 u;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              u64     data:32;</span><br><span style="color: hsl(120, 100%, 40%);">+              u64     ia:8;</span><br><span style="color: hsl(120, 100%, 40%);">+         u64     :24;</span><br><span style="color: hsl(120, 100%, 40%);">+  } s;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+union twsx_int {</span><br><span style="color: hsl(120, 100%, 40%);">+  u64 u;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              u64     st_int:1;       /** TWSX_SW_TWSI register update int */</span><br><span style="color: hsl(120, 100%, 40%);">+               u64     ts_int:1;       /** TWSX_TWSI_SW register update int */</span><br><span style="color: hsl(120, 100%, 40%);">+               u64     core_int:1;     /** TWSI core interrupt, ignored for HLC */</span><br><span style="color: hsl(120, 100%, 40%);">+           u64     :5;             /** Reserved */</span><br><span style="color: hsl(120, 100%, 40%);">+               u64     sda_ovr:1;      /** SDA testing override */</span><br><span style="color: hsl(120, 100%, 40%);">+           u64     scl_ovr:1;      /** SCL testing override */</span><br><span style="color: hsl(120, 100%, 40%);">+           u64     sda:1;          /** SDA signal */</span><br><span style="color: hsl(120, 100%, 40%);">+             u64     scl:1;          /** SCL signal */</span><br><span style="color: hsl(120, 100%, 40%);">+             u64     :52;            /** Reserved */</span><br><span style="color: hsl(120, 100%, 40%);">+       } s;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+    TWSI_OP_WRITE   = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+  TWSI_OP_READ    = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+    TWSI_EOP_SLAVE_ADDR = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      TWSI_EOP_CLK_CTL = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+ TWSI_SW_EOP_IA   = 6,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_SLAVEADD     = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+        TWSI_DATA         = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+        TWSI_CTL          = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+        TWSI_CLKCTL       = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+        TWSI_STAT         = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+        TWSI_SLAVEADD_EXT = 4,</span><br><span style="color: hsl(120, 100%, 40%);">+        TWSI_RST          = 7,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+  TWSI_CTL_AAK    = (1 << 2),</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_CTL_IFLG   = (1 << 3),</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_CTL_STP    = (1 << 4),</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_CTL_STA    = (1 << 5),</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_CTL_ENAB   = (1 << 6),</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_CTL_CE     = (1 << 7),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Bus error */</span><br><span style="color: hsl(120, 100%, 40%);">+      TWSI_STAT_BUS_ERROR             = 0x00,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Start condition transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+    TWSI_STAT_START                 = 0x08,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Repeat start condition transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_STAT_RSTART                = 0x10,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Address + write bit transmitted, ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+  TWSI_STAT_TXADDR_ACK            = 0x18,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Address + write bit transmitted, /ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+ TWSI_STAT_TXADDR_NAK            = 0x20,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte transmitted in master mode, ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_STAT_TXDATA_ACK            = 0x28,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte transmitted in master mode, ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_STAT_TXDATA_NAK            = 0x30,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Arbitration lost in address or data byte */</span><br><span style="color: hsl(120, 100%, 40%);">+       TWSI_STAT_TX_ARB_LOST           = 0x38,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Address + read bit transmitted, ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_STAT_RXADDR_ACK            = 0x40,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Address + read bit transmitted, /ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+  TWSI_STAT_RXADDR_NAK            = 0x48,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte received in master mode, ACK transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_STAT_RXDATA_ACK_SENT       = 0x50,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte received, NACK transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_STAT_RXDATA_NAK_SENT       = 0x58,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Slave address received, sent ACK */</span><br><span style="color: hsl(120, 100%, 40%);">+       TWSI_STAT_SLAVE_RXADDR_ACK      = 0x60,</span><br><span style="color: hsl(120, 100%, 40%);">+       /**</span><br><span style="color: hsl(120, 100%, 40%);">+    * Arbitration lost in address as master, slave address + write bit</span><br><span style="color: hsl(120, 100%, 40%);">+    * received, ACK transmitted</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_STAT_TX_ACK_ARB_LOST       = 0x68,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** General call address received, ACK transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+ TWSI_STAT_RX_GEN_ADDR_ACK       = 0x70,</span><br><span style="color: hsl(120, 100%, 40%);">+       /**</span><br><span style="color: hsl(120, 100%, 40%);">+    * Arbitration lost in address as master, general call address</span><br><span style="color: hsl(120, 100%, 40%);">+         * received, ACK transmitted</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_STAT_RX_GEN_ADDR_ARB_LOST  = 0x78,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte received after slave address received, ACK transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+       TWSI_STAT_SLAVE_RXDATA_ACK      = 0x80,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte received after slave address received, /ACK transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+      TWSI_STAT_SLAVE_RXDATA_NAK      = 0x88,</span><br><span style="color: hsl(120, 100%, 40%);">+       /**</span><br><span style="color: hsl(120, 100%, 40%);">+    * Data byte received after general call address received, ACK</span><br><span style="color: hsl(120, 100%, 40%);">+         * transmitted</span><br><span style="color: hsl(120, 100%, 40%);">+         */</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_STAT_GEN_RXADDR_ACK        = 0x90,</span><br><span style="color: hsl(120, 100%, 40%);">+       /**</span><br><span style="color: hsl(120, 100%, 40%);">+    * Data byte received after general call address received, /ACK</span><br><span style="color: hsl(120, 100%, 40%);">+        * transmitted</span><br><span style="color: hsl(120, 100%, 40%);">+         */</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_STAT_GEN_RXADDR_NAK        = 0x98,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** STOP or repeated START condition received in slave mode */</span><br><span style="color: hsl(120, 100%, 40%);">+        TWSI_STAT_STOP_MULTI_START      = 0xA0,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Slave address + read bit received, ACK transmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_STAT_SLAVE_RXADDR2_ACK     = 0xA8,</span><br><span style="color: hsl(120, 100%, 40%);">+       /**</span><br><span style="color: hsl(120, 100%, 40%);">+    * Arbitration lost in address as master, slave address + read bit</span><br><span style="color: hsl(120, 100%, 40%);">+     * received, ACK transmitted</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   TWSI_STAT_RXDATA_ACK_ARB_LOST   = 0xB0,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte transmitted in slave mode, ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+      TWSI_STAT_SLAVE_TXDATA_ACK      = 0xB8,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Data byte transmitted in slave mode, /ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_STAT_SLAVE_TXDATA_NAK      = 0xC0,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Last byte transmitted in slave mode, ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+      TWSI_STAT_SLAVE_TXDATA_END_ACK  = 0xC8,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Second address byte + write bit transmitted, ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+      TWSI_STAT_TXADDR2DATA_ACK       = 0xD0,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Second address byte + write bit transmitted, /ACK received */</span><br><span style="color: hsl(120, 100%, 40%);">+     TWSI_STAT_TXADDR2DATA_NAK       = 0xD8,</span><br><span style="color: hsl(120, 100%, 40%);">+       /** No relevant status information */</span><br><span style="color: hsl(120, 100%, 40%);">+ TWSI_STAT_IDLE          = 0xF8</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Returns true if we lost arbitration</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param        code            status code</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param  final_read      true if this is the final read operation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return        true if arbitration has been lost, false if it hasn't been lost.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_i2c_lost_arb(u8 code, int final_read)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (code) {</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Arbitration lost */</span><br><span style="color: hsl(120, 100%, 40%);">+        case TWSI_STAT_TX_ARB_LOST:</span><br><span style="color: hsl(120, 100%, 40%);">+   case TWSI_STAT_TX_ACK_ARB_LOST:</span><br><span style="color: hsl(120, 100%, 40%);">+       case TWSI_STAT_RX_GEN_ADDR_ARB_LOST:</span><br><span style="color: hsl(120, 100%, 40%);">+  case TWSI_STAT_RXDATA_ACK_ARB_LOST:</span><br><span style="color: hsl(120, 100%, 40%);">+           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Being addressed as slave, should back off and listen */</span><br><span style="color: hsl(120, 100%, 40%);">+    case TWSI_STAT_SLAVE_RXADDR_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+      case TWSI_STAT_RX_GEN_ADDR_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+       case TWSI_STAT_GEN_RXADDR_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+        case TWSI_STAT_GEN_RXADDR_NAK:</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Core busy as slave */</span><br><span style="color: hsl(120, 100%, 40%);">+      case TWSI_STAT_SLAVE_RXDATA_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+      case TWSI_STAT_SLAVE_RXDATA_NAK:</span><br><span style="color: hsl(120, 100%, 40%);">+      case TWSI_STAT_STOP_MULTI_START:</span><br><span style="color: hsl(120, 100%, 40%);">+      case TWSI_STAT_SLAVE_RXADDR2_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+     case TWSI_STAT_SLAVE_TXDATA_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+      case TWSI_STAT_SLAVE_TXDATA_NAK:</span><br><span style="color: hsl(120, 100%, 40%);">+      case TWSI_STAT_SLAVE_TXDATA_END_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+          return  -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Ack allowed on pre-terminal bytes only */</span><br><span style="color: hsl(120, 100%, 40%);">+  case TWSI_STAT_RXDATA_ACK_SENT:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!final_read)</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* NAK allowed on terminal byte only */</span><br><span style="color: hsl(120, 100%, 40%);">+       case TWSI_STAT_RXDATA_NAK_SENT:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!final_read)</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  case TWSI_STAT_TXDATA_NAK:</span><br><span style="color: hsl(120, 100%, 40%);">+    case TWSI_STAT_TXADDR_NAK:</span><br><span style="color: hsl(120, 100%, 40%);">+    case TWSI_STAT_RXADDR_NAK:</span><br><span style="color: hsl(120, 100%, 40%);">+    case TWSI_STAT_TXADDR2DATA_NAK:</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define RST_BOOT_PNR_MUL(Val)  ((Val >> 33) & 0x1F)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Writes to the MIO_TWS(0..5)_SW_TWSI register</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param    baseaddr        Base address of i2c registers</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param        sw_twsi         value to write</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return  0 for success, otherwise error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static u64 twsi_write_sw(void *baseaddr, union twsx_sw_twsi sw_twsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned long timeout = 500000;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     sw_twsi.s.r = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      sw_twsi.s.v = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printk(BIOS_SPEW, "%s(%p, 0x%llx)\n", __func__, baseaddr, sw_twsi.u);</span><br><span style="color: hsl(120, 100%, 40%);">+       write64(baseaddr + TWSI_SW_TWSI, sw_twsi.u);</span><br><span style="color: hsl(120, 100%, 40%);">+  do {</span><br><span style="color: hsl(120, 100%, 40%);">+          sw_twsi.u = read64(baseaddr + TWSI_SW_TWSI);</span><br><span style="color: hsl(120, 100%, 40%);">+          timeout--;</span><br><span style="color: hsl(120, 100%, 40%);">+    } while (sw_twsi.s.v != 0 && timeout > 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (sw_twsi.s.v)</span><br><span style="color: hsl(120, 100%, 40%);">+              printk(BIOS_ERR, "%s: timed out\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+      return sw_twsi.u;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Reads the MIO_TWS(0..5)_SW_TWSI register</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param baseaddr        Base address of i2c registers</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param        sw_twsi         value for eia and op, etc. to read</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return      value of the register</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static u64 twsi_read_sw(void *baseaddr, union twsx_sw_twsi sw_twsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned long timeout = 500000;</span><br><span style="color: hsl(120, 100%, 40%);">+       sw_twsi.s.r = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      sw_twsi.s.v = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printk(BIOS_SPEW, "%s(%p, 0x%llx)\n", __func__, baseaddr, sw_twsi.u);</span><br><span style="color: hsl(120, 100%, 40%);">+       write64(baseaddr + TWSI_SW_TWSI, sw_twsi.u);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        do {</span><br><span style="color: hsl(120, 100%, 40%);">+          sw_twsi.u = read64(baseaddr + TWSI_SW_TWSI);</span><br><span style="color: hsl(120, 100%, 40%);">+          timeout--;</span><br><span style="color: hsl(120, 100%, 40%);">+    } while (sw_twsi.s.v != 0 && timeout > 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (sw_twsi.s.v)</span><br><span style="color: hsl(120, 100%, 40%);">+              printk(BIOS_ERR, "%s: Error writing 0x%llx\n", __func__,</span><br><span style="color: hsl(120, 100%, 40%);">+                   sw_twsi.u);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  printk(BIOS_SPEW, "%s: Returning 0x%llx\n", __func__, sw_twsi.u);</span><br><span style="color: hsl(120, 100%, 40%);">+   return sw_twsi.u;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Write control register</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param   baseaddr        Base address for i2c registers</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param       data            data to write</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void twsi_write_ctl(void *baseaddr, const u8 data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      union twsx_sw_twsi twsi_sw;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printk(BIOS_SPEW, "%s(%p, 0x%x)\n", __func__, baseaddr, data);</span><br><span style="color: hsl(120, 100%, 40%);">+      twsi_sw.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      twsi_sw.s.op = TWSI_SW_EOP_IA;</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_sw.s.eop_ia = TWSI_CTL;</span><br><span style="color: hsl(120, 100%, 40%);">+  twsi_sw.s.data  = data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     twsi_write_sw(baseaddr, twsi_sw);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Reads the TWSI Control Register</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param[in]      baseaddr        Base address for i2c</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return    8-bit TWSI control register</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static u32 twsi_read_ctl(void *baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ union twsx_sw_twsi sw_twsi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ sw_twsi.u  = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       sw_twsi.s.op  = TWSI_SW_EOP_IA;</span><br><span style="color: hsl(120, 100%, 40%);">+       sw_twsi.s.eop_ia = TWSI_CTL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        sw_twsi.u = twsi_read_sw(baseaddr, sw_twsi);</span><br><span style="color: hsl(120, 100%, 40%);">+  printk(BIOS_SPEW, "%s(%p): 0x%x\n", __func__, baseaddr, sw_twsi.s.data);</span><br><span style="color: hsl(120, 100%, 40%);">+    return sw_twsi.s.data;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Read i2c status register</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param    baseaddr        Base address of i2c registers</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return   value of status register</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static u8 twsi_read_status(void *baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  union twsx_sw_twsi twsi_sw;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ twsi_sw.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_sw.s.op = TWSI_SW_EOP_IA;</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_sw.s.eop_ia = TWSI_STAT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return twsi_read_sw(baseaddr, twsi_sw);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Waits for an i2c operation to complete</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param     baseaddr        Base address of registers</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return       0 for success, 1 if timeout</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_wait(void *baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned long timeout = 500000;</span><br><span style="color: hsl(120, 100%, 40%);">+       u8 twsi_ctl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        printk(BIOS_SPEW, "%s(%p)\n", __func__, baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+  do {</span><br><span style="color: hsl(120, 100%, 40%);">+          twsi_ctl = twsi_read_ctl(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+           twsi_ctl &= TWSI_CTL_IFLG;</span><br><span style="color: hsl(120, 100%, 40%);">+                timeout--;</span><br><span style="color: hsl(120, 100%, 40%);">+    } while (!twsi_ctl && timeout > 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      printk(BIOS_SPEW, "  return: %u\n", !twsi_ctl);</span><br><span style="color: hsl(120, 100%, 40%);">+     return !twsi_ctl;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sends an i2c stop condition</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param      baseaddr        register base address</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return   0 for success, -1 if error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_stop(void *baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      u8 stat;</span><br><span style="color: hsl(120, 100%, 40%);">+      twsi_write_ctl(baseaddr, TWSI_CTL_STP | TWSI_CTL_ENAB);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     stat = twsi_read_status(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (stat != TWSI_STAT_IDLE) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "%s: Bad status on bus@%p\n", __func__,</span><br><span style="color: hsl(120, 100%, 40%);">+                   baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Manually clear the I2C bus and send a stop</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void twsi_unblock(void *baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        union twsx_int  int_reg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    int_reg.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < 9; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          int_reg.s.scl_ovr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                write64(baseaddr + TWSI_INT, int_reg.u);</span><br><span style="color: hsl(120, 100%, 40%);">+              udelay(5);</span><br><span style="color: hsl(120, 100%, 40%);">+            int_reg.s.scl_ovr = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                write64(baseaddr + TWSI_INT, int_reg.u);</span><br><span style="color: hsl(120, 100%, 40%);">+              udelay(5);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     int_reg.s.sda_ovr = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        write64(baseaddr + TWSI_INT, int_reg.u);</span><br><span style="color: hsl(120, 100%, 40%);">+      udelay(5);</span><br><span style="color: hsl(120, 100%, 40%);">+    int_reg.s.scl_ovr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        write64(baseaddr + TWSI_INT, int_reg.u);</span><br><span style="color: hsl(120, 100%, 40%);">+      udelay(5);</span><br><span style="color: hsl(120, 100%, 40%);">+    int_reg.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        write64(baseaddr + TWSI_INT, int_reg.u);</span><br><span style="color: hsl(120, 100%, 40%);">+      udelay(5);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Unsticks the i2c bus</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param    baseaddr        base address of registers</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_start_unstick(void *baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      twsi_stop(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_unblock(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Sends an i2c start condition</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param     baseaddr        base address of registers</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return       0 for success, otherwise error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_start(void *baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int result;</span><br><span style="color: hsl(120, 100%, 40%);">+   u8 stat;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printk(BIOS_SPEW, "%s(%p)\n", __func__, baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+  twsi_write_ctl(baseaddr, TWSI_CTL_STA | TWSI_CTL_ENAB);</span><br><span style="color: hsl(120, 100%, 40%);">+       result = twsi_wait(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+         stat = twsi_read_status(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+            printk(BIOS_SPEW, "%s: result: 0x%x, status: 0x%x\n", __func__,</span><br><span style="color: hsl(120, 100%, 40%);">+                   result, stat);</span><br><span style="color: hsl(120, 100%, 40%);">+          switch (stat) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case TWSI_STAT_START:</span><br><span style="color: hsl(120, 100%, 40%);">+         case TWSI_STAT_RSTART:</span><br><span style="color: hsl(120, 100%, 40%);">+                        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             case TWSI_STAT_RXADDR_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+            default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      return twsi_start_unstick(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     printk(BIOS_SPEW, "%s: success\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Writes data to the i2c bus</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param       baseraddr       register base address</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param        slave_addr      address of slave to write to</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param buffer          Pointer to buffer to write</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param   length          Number of bytes in buffer to write</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return      0 for success, otherwise error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_write_data(void *baseaddr, const u8 slave_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                     const u8 *buffer, const unsigned int length)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    union twsx_sw_twsi twsi_sw;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int curr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int result;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printk(BIOS_DEBUG, "%s(%p, 0x%x, %p, 0x%x)\n", __func__, baseaddr,</span><br><span style="color: hsl(120, 100%, 40%);">+         slave_addr, buffer, length);</span><br><span style="color: hsl(120, 100%, 40%);">+   result = twsi_start(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "%s: Could not start BUS transaction\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   result = twsi_wait(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "%s: wait failed\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+            return result;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   twsi_sw.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_sw.s.op = TWSI_SW_EOP_IA;</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_sw.s.eop_ia = TWSI_DATA;</span><br><span style="color: hsl(120, 100%, 40%);">+ twsi_sw.s.data = (u32) (slave_addr << 1) | TWSI_OP_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     twsi_write_sw(baseaddr, twsi_sw);</span><br><span style="color: hsl(120, 100%, 40%);">+     twsi_write_ctl(baseaddr, TWSI_CTL_ENAB);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printk(BIOS_DEBUG, "%s: Waiting\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+      result = twsi_wait(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "%s: Timed out writing slave address 0x%x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    __func__, slave_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return result;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     result = twsi_read_status(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if ((result = twsi_read_status(baseaddr)) != TWSI_STAT_TXADDR_ACK) {</span><br><span style="color: hsl(120, 100%, 40%);">+          twsi_stop(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return twsi_i2c_lost_arb(result, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   while (curr < length) {</span><br><span style="color: hsl(120, 100%, 40%);">+            twsi_sw.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                twsi_sw.s.op = TWSI_SW_EOP_IA;</span><br><span style="color: hsl(120, 100%, 40%);">+                twsi_sw.s.eop_ia = TWSI_DATA;</span><br><span style="color: hsl(120, 100%, 40%);">+         twsi_sw.s.data = buffer[curr++];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            twsi_write_sw(baseaddr, twsi_sw);</span><br><span style="color: hsl(120, 100%, 40%);">+             twsi_write_ctl(baseaddr, TWSI_CTL_ENAB);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            result = twsi_wait(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 printk(BIOS_ERR, "%s: Timed out writing data to 0x%x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          __func__, slave_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+                  return result;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printk(BIOS_DEBUG, "%s: Stopping\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+     return twsi_stop(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Performs a read transaction on the i2c bus</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param     baseaddr        Base address of twsi registers</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param       slave_addr      i2c bus address to read from</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param buffer          buffer to read into</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param  length          number of bytes to read</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return 0 for success, otherwise error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_read_data(void *baseaddr, const u8 slave_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                     u8 *buffer, const unsigned int length)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   union twsx_sw_twsi twsi_sw;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int curr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int result;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printk(BIOS_DEBUG, "%s(%p, 0x%x, %p, %u)\n", __func__, baseaddr,</span><br><span style="color: hsl(120, 100%, 40%);">+           slave_addr, buffer, length);</span><br><span style="color: hsl(120, 100%, 40%);">+   result = twsi_start(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "%s: start failed\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+           return result;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   result = twsi_wait(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "%s: wait failed\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+            return result;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   twsi_sw.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_sw.s.op = TWSI_SW_EOP_IA;</span><br><span style="color: hsl(120, 100%, 40%);">+        twsi_sw.s.eop_ia = TWSI_DATA;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       twsi_sw.s.data  = (u32) (slave_addr << 1) | TWSI_OP_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     twsi_write_sw(baseaddr, twsi_sw);</span><br><span style="color: hsl(120, 100%, 40%);">+     twsi_write_ctl(baseaddr, TWSI_CTL_ENAB);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    result = twsi_wait(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "%s: waiting for sending addr failed\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+                return result;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   result = twsi_read_status(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (result != TWSI_STAT_RXADDR_ACK) {</span><br><span style="color: hsl(120, 100%, 40%);">+         twsi_stop(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return twsi_i2c_lost_arb(result, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   while (curr < length) {</span><br><span style="color: hsl(120, 100%, 40%);">+            twsi_write_ctl(baseaddr, TWSI_CTL_ENAB |</span><br><span style="color: hsl(120, 100%, 40%);">+                              ((curr < length - 1) ? TWSI_CTL_AAK : 0));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               result = twsi_wait(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 printk(BIOS_ERR, "%s: waiting for data failed\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return result;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           twsi_sw.u = twsi_read_sw(baseaddr, twsi_sw);</span><br><span style="color: hsl(120, 100%, 40%);">+          buffer[curr++] = twsi_sw.s.data;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   twsi_stop(baseaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int twsi_set_speed(void *baseaddr, const unsigned int speed)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int io_clock_hz;</span><br><span style="color: hsl(120, 100%, 40%);">+      int n_div;</span><br><span style="color: hsl(120, 100%, 40%);">+    int m_div;</span><br><span style="color: hsl(120, 100%, 40%);">+    union twsx_sw_twsi sw_twsi;</span><br><span style="color: hsl(120, 100%, 40%);">+   union rst_boot rst_boot;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printk(BIOS_DEBUG, "%s(%p, %u)\n", __func__, baseaddr, speed);</span><br><span style="color: hsl(120, 100%, 40%);">+      rst_boot.u = read64(RST_BOOT);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      io_clock_hz = rst_boot.s.pnr_mul * PLL_REF_CLK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Set the TWSI clock to a conservative TWSI_BUS_FREQ.  Compute the</span><br><span style="color: hsl(120, 100%, 40%);">+    * clocks M divider based on the SCLK.</span><br><span style="color: hsl(120, 100%, 40%);">+         * TWSI freq = (core freq) / (20 x (M+1) x (thp+1) x 2^N)</span><br><span style="color: hsl(120, 100%, 40%);">+      * M = ((core freq) / (20 x (TWSI freq) x (thp+1) x 2^N)) - 1</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   for (n_div = 0; n_div < 8; n_div++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              m_div = io_clock_hz / (20 * speed * (TWSI_THP + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+          m_div /= 1 << n_div;</span><br><span style="color: hsl(120, 100%, 40%);">+            m_div -= 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (m_div < 16)</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (m_div >= 16)</span><br><span style="color: hsl(120, 100%, 40%);">+           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  sw_twsi.u = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        sw_twsi.s.v = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      sw_twsi.s.op = 0x6;     /* See EOP field */</span><br><span style="color: hsl(120, 100%, 40%);">+   sw_twsi.s.r = 0;        /* Select CLKCTL when R = 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+        sw_twsi.s.eop_ia = 3;   /* R=0 selects CLKCTL, R=1 selects STAT */</span><br><span style="color: hsl(120, 100%, 40%);">+    sw_twsi.s.data = ((m_div & 0xf) << 3) | ((n_div & 0x7) << 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   twsi_write_sw(baseaddr, sw_twsi);</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int twsi_init(unsigned int bus, enum i2c_speed hz)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ void *baseaddr = twsi_get_baseaddr(bus);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (twsi_set_speed(baseaddr, hz) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Enable TWSI, HLC disable, STOP, NAK */</span><br><span style="color: hsl(120, 100%, 40%);">+     twsi_write_ctl(baseaddr, TWSI_CTL_ENAB);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,</span><br><span style="color: hsl(120, 100%, 40%);">+                       int seg_count)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int result;</span><br><span style="color: hsl(120, 100%, 40%);">+   void *baseaddr = twsi_get_baseaddr(bus);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!baseaddr)</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  printk(BIOS_SPEW, "%s: %d messages\n", __func__, seg_count);</span><br><span style="color: hsl(120, 100%, 40%);">+        for (; seg_count > 0; seg_count--, segments++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (segments->flags & I2C_M_RD) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      result = twsi_read_data(baseaddr, segments->slave,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         segments->buf, segments->len);</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      result = twsi_write_data(baseaddr, segments->slave,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 segments->buf, segments->len);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (result) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 printk(BIOS_ERR, "%s: error transmitting data\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://review.coreboot.org/23751">change 23751</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/23751"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I9f85d024b3ffd0a0c4376a8880d14db9e3570d79 </div>
<div style="display:none"> Gerrit-Change-Number: 23751 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Patrick Rudolph <patrick.rudolph@9elements.com> </div>