1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
/* 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 = BIT(13);
zero_one = BIT(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 controller pins. Connect pads DIOB0(aka i2c
* scl) to gpio0.12 and DIOB1(aka sda) to gpio0.13. I2c 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 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);
|