diff options
-rw-r--r-- | chip/g/ite_flash.c | 127 | ||||
-rw-r--r-- | chip/g/ite_sync.S | 122 | ||||
-rw-r--r-- | chip/g/ite_sync.h | 36 |
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 |