summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/g/ite_flash.c127
-rw-r--r--chip/g/ite_sync.S122
-rw-r--r--chip/g/ite_sync.h36
3 files changed, 285 insertions, 0 deletions
diff --git a/chip/g/ite_flash.c b/chip/g/ite_flash.c
new file mode 100644
index 0000000000..b805e09e6a
--- /dev/null
+++ b/chip/g/ite_flash.c
@@ -0,0 +1,127 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "ccd_config.h"
+#include "config.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "init_chip.h"
+#include "ite_sync.h"
+#include "registers.h"
+#include "scratch_reg1.h"
+#include "system.h"
+#include "timer.h"
+#include "usb_i2c.h"
+
+#define ITE_SYNC_TIME (50 * MSEC)
+#define ITE_PERIOD_TIME 5 /* This is 200 kHz */
+#define TIMEUS_CLK_FREQ 24 /* units: MHz */
+#define HALF_PERIOD_TICKS 8
+
+/* Register controlling CPU clock mode among other things. */
+#define PROC_CONTROL_REGISTER 0x4009A6D0
+
+void generate_ite_sync(void)
+{
+ uint16_t *gpio_addr;
+ uint32_t cycle_count;
+ uint16_t both_zero;
+ uint16_t both_one;
+ uint16_t one_zero;
+ uint16_t zero_one;
+ uint32_t saved_setting;
+
+ /* Let's pulse EC reset while preparing to sync up. */
+ assert_ec_rst();
+ msleep(1);
+ deassert_ec_rst();
+ msleep(5);
+
+ /*
+ * Values to write to set SCL and SDA to various combinations of 0 and
+ * 1 to be able to generate two necessary waveforms.
+ */
+ both_zero = 0;
+ one_zero = 1 << 13;
+ zero_one = 1 << 12;
+ both_one = one_zero | zero_one;
+
+ /* Address of the mask byte register to use to set both pins. */
+ gpio_addr = (uint16_t *) (GC_GPIO0_BASE_ADDR +
+ GC_GPIO_MASKHIGHBYTE_800_OFFSET +
+ (both_one >> 8) * 4);
+
+ /*
+ * Let's take over the i2c master pins. Connect pads DIOB0(aka i2c
+ * scl) to gpio0.12 and DIOB1(aka sda) to gpio0.13. I2c master
+ * controller is disconnected from the pads.
+ */
+ REG32(GBASE(PINMUX) + GOFFSET(PINMUX, DIOB0_SEL)) =
+ GC_PINMUX_GPIO0_GPIO12_SEL;
+ REG32(GBASE(PINMUX) + GOFFSET(PINMUX, DIOB1_SEL)) =
+ GC_PINMUX_GPIO0_GPIO13_SEL;
+
+ gpio_set_flags(GPIO_I2C_SCL_INA, GPIO_OUTPUT | GPIO_HIGH);
+ gpio_set_flags(GPIO_I2C_SDA_INA, GPIO_OUTPUT | GPIO_HIGH);
+
+ cycle_count = 2 * ITE_SYNC_TIME / ITE_PERIOD_TIME;
+
+ interrupt_disable();
+
+ init_jittery_clock_locking_optional(1, 0, 0);
+
+ saved_setting = REG32(0x4009A6D0);
+ REG32(0x4009A6D0) = 0;
+
+ /* Call assembler function to generate ITE SYNC sequence. */
+ ite_sync(gpio_addr, both_zero, one_zero, zero_one, both_one,
+ HALF_PERIOD_TICKS, HALF_PERIOD_TICKS * cycle_count);
+
+ REG32(0x4009A6D0) = saved_setting;
+
+ interrupt_enable();
+
+ /*
+ * Restore I2C configuration, re-attach i2c master controller to the
+ * pads.
+ */
+ REG32(GBASE(PINMUX) + GOFFSET(PINMUX, DIOB0_SEL)) =
+ GC_PINMUX_I2C0_SCL_SEL;
+ REG32(GBASE(PINMUX) + GOFFSET(PINMUX, DIOB1_SEL)) =
+ GC_PINMUX_I2C0_SDA_SEL;
+}
+
+/*
+ * Callback invoked by usb_i2c bridge when a write to a special I2C address is
+ * requested.
+ */
+#define CROS_CMD_ITE_SYNC 0
+static int ite_sync_preparer(void *data_in, size_t in_size,
+ void *data_out, size_t out_size)
+{
+
+ if (in_size != 1)
+ return USB_I2C_WRITE_COUNT_INVALID;
+
+ if (*((uint8_t *)data_in) != CROS_CMD_ITE_SYNC)
+ return USB_I2C_UNSUPPORTED_COMMAND;
+
+ if (!ccd_is_cap_enabled(CCD_CAP_EC_FLASH))
+ return USB_I2C_DISABLED;
+
+ board_start_ite_sync();
+
+ return 0;
+}
+
+static void register_ite_sync(void)
+{
+ usb_i2c_register_cros_cmd_handler(ite_sync_preparer);
+}
+
+DECLARE_HOOK(HOOK_INIT, register_ite_sync, HOOK_PRIO_DEFAULT);
diff --git a/chip/g/ite_sync.S b/chip/g/ite_sync.S
new file mode 100644
index 0000000000..0c3d303dd2
--- /dev/null
+++ b/chip/g/ite_sync.S
@@ -0,0 +1,122 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+.text
+
+.syntax unified
+.code 16
+
+.global ite_sync
+.thumb_func
+
+/*
+ * The logic shown by the following C code is implemented in assembly below.
+ *
+ * Two square wave sequences are generated, one oscillating twice as fast as
+ * the other. The ite_sync_clock() function implements tick counter. The higher
+ * frequency sequence's half period time takes 'half_period_ticks' cycles of
+ * the ite_sync_clock() inner loop. So, to generate two sequences, one half
+ * the frequency of the other four half cycles are required.
+ *
+ * Two GPIOs used as who outputs of the two clocks. Luckily both GPIOs can be
+ * controlled by the same SOC register, the input values of 'both_zero',
+ * 'one_zero', 'zero_one', and 'both_one' are the values to be written
+ * into the register to set the two GPIOs to the respecitve values.
+ *
+
+static uint32_t tick; # Free running tick counter, runs from
+ # 0 to 'total_ticks_required'
+static uint32_t next_tick; # Deadline for the next half period
+static uint32_t half_period_ticks; # Number of ticks per half period.
+
+static void ite_sync_clock(void)
+{
+ while (tick++ < next_tick)
+ ;
+ next_tick += half_period_ticks ;
+}
+
+void ite_sync(volatile uint16_t *gpio_addr, uint16_t both_zero,
+ uint16_t one_zero, uint16_t zero_one, uint16_t both_one,
+ uint32_t half_period, uint32_t total_ticks_required)
+{
+ uint32_t tick = 0;
+ uint32_t next_tick = half_period_ticks = half_period;
+
+ while (tick < total_ticks_required) {
+ ite_sync_clock() ;
+ *gpio_addr = both_zero;
+
+ ite_sync_clock() ;
+ *gpio_addr = one_zero;
+
+ ite_sync_clock() ;
+ *gpio_addr = zero_one;
+
+ ite_sync_clock() ;
+ *gpio_addr = both_one;
+ }
+}
+*/
+
+.thumb_func
+ite_sync_clock:
+ @ ip tick
+ @ r7 next_tick
+ @ r5 half_period_ticks
+ add ip, ip, #1
+ cmp ip, r7
+ bcc ite_sync_clock
+ add r7, r7, r5
+ mov r8, r8 @ a few NOOPs to fine tune the period.
+ mov r8, r8
+ bx lr
+
+.thumb_func
+.global ite_sync
+ite_sync:
+ @ vvvvvv passed in registers: vvvvv
+ @ r0 gpio_addr
+ @ r1 both_zero
+ @ r2 one_zero
+ @ r3 zero_one
+ @ vvvvvv passed on the stack, moved to registers: vvvvv
+ @ r4 both_one
+ @ r5 half_period
+ @ r6 total_ticks_required
+ @ vvvvvv local variables: vvvvv
+ @ r7 next_tick
+ @ ip tick
+
+ push {r4, r5, r6, r7, lr}
+
+ ldr r4, [sp, #20] @ both one
+ ldr r5, [sp, #24] @ half_period_ticks
+ ldr r6, [sp, #28] @ total_ticks_required
+
+ mov ip, #0 @ tick counter
+ mov r7, r5 @ next tick
+
+sync_loop:
+ bl ite_sync_clock
+ strh r1, [r0] @ both_zero
+ add ip, ip, 1 @ cycle counter increment
+
+ bl ite_sync_clock
+ strh r2, [r0] @ one_zero
+ mov r8, r8
+
+ bl ite_sync_clock
+ strh r3, [r0] @ zero_one
+ mov r8, r8
+
+ bl ite_sync_clock
+ strh r4, [r0] @ both_one
+
+ cmp ip, r6
+ bcc sync_loop
+
+ pop {r4, r5, r6, r7, pc}
+
diff --git a/chip/g/ite_sync.h b/chip/g/ite_sync.h
new file mode 100644
index 0000000000..c25dc57bc4
--- /dev/null
+++ b/chip/g/ite_sync.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CHIP_G_ITE_SYNC_H
+#define __CHIP_G_ITE_SYNC_H
+
+#include "util.h"
+
+/*
+ * Assembler function to generates ITE EC sync sequence, which requires two
+ * lines generating phase locked 200 KHz and 100 KHz clocks. This is achieved
+ * by directly togging two GPIOs.
+ *
+ * gpio_addr: address of the register to write to drive the GPIOs
+ * both_zero:
+ * one_zero:
+ * zero_one:
+ * both_one: values to write at gpio_addr to set the tow lines to these
+ * stattes
+ * half_period_ticks: number of interations of the tight loop to last for half
+ * the period of the higher frequency
+ * total_ticks_required: total ticks required to generate the sequence of the
+ * necessary duration.
+ */
+void ite_sync(volatile uint16_t *gpio_addr, uint16_t both_zero,
+ uint16_t one_zero, uint16_t zero_one, uint16_t both_one,
+ uint32_t half_period_ticks, uint32_t total_ticks_required);
+
+
+/* Generate ITE SYNC sequence on the I2C interface controlling the EC. */
+void generate_ite_sync(void);
+
+#endif