summaryrefslogtreecommitdiff
path: root/chip/npcx/i2c.c
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2016-01-15 11:17:43 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-01-20 20:36:53 -0800
commitebd29d455793d048daadc2dcfef7e26edee9d46b (patch)
tree2a5052c13cd2c9bfe3460e75cec449ab44c2ee71 /chip/npcx/i2c.c
parent17ffa6b1abdec63015054623226a09c60c38a1ee (diff)
downloadchrome-ec-ebd29d455793d048daadc2dcfef7e26edee9d46b.tar.gz
nuc: Adjust core clock from 16/12 MHz to 15/13 MHz.
We found the deviation of 115200 UART baud-rate is too large when core clock is 16 or 12MHz. It causes failure during FAFT since sometime EC could not receive correct commands to proceed test. We adjusted core clock from 16/12 to 15/13 to reduce the deviation of 115200. Both of them have run FAFT and stress tests for weeks and no UART issues were found. Since the lowest source clock of i2c is 6.5MHz, we modified tSCLL, tSCLH and hold time directly for better i2c timing when freq is 400K. And if freq is 100K, we introduced normal mode to handle it. Modified sources: 1. clock.c: Adjust core clock from 16/12 MHz to 15/13 MHz. 2. clock_chip.h: Set target core clock as 15 MHz. 3. uart.c: Add baud-rate support for 15/13 MHz. 4. register.h: Add new register definitions of SMBus. 5. i2c.c: Modified tSCLL, tSCLH and hold time directly for better i2c timing. BUG=chrome-os-partner:34346 TEST=make buildall -j; test nuvoton IC specific drivers BRANCH=none Change-Id: Ie5d22e87875c064b49338046c99a178f8fadf32b Signed-off-by: Mulin Chao <mlchao@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/322320 Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'chip/npcx/i2c.c')
-rw-r--r--chip/npcx/i2c.c85
1 files changed, 71 insertions, 14 deletions
diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c
index d4513af7e0..ef31160a04 100644
--- a/chip/npcx/i2c.c
+++ b/chip/npcx/i2c.c
@@ -658,7 +658,7 @@ static void i2c_freq_changed(void)
for (i = 0; i < i2c_ports_used; i++) {
int bus_freq = i2c_ports[i].kbps;
int ctrl = i2c_port_to_controller(i2c_ports[i].port);
- int scl_time;
+ int scl_freq;
/* SMB0/1 use core clock & SMB2/3 use apb2 clock */
if (ctrl < 2)
@@ -666,21 +666,78 @@ static void i2c_freq_changed(void)
else
freq = clock_get_apb2_freq();
- /* use Fast Mode */
- SET_BIT(NPCX_SMBCTL3(ctrl) , NPCX_SMBCTL3_400K);
-
/*
- * Set SCLLT/SCLHT:
- * tSCLL = 2 * SCLLT7-0 * tCLK
- * tSCLH = 2 * SCLHT7-0 * tCLK
- * (tSCLL+tSCLH) = 4 * SCLH(L)T * tCLK if tSCLL == tSCLH
- * SCLH(L)T = T(SCL)/4/T(CLK) = FREQ(CLK)/4/FREQ(SCL)
+ * Set SCL frequency by formula:
+ * tSCL = 4 * SCLFRQ * tCLK
+ * fSCL = fCLK / (4*SCLFRQ)
+ * SCLFRQ = fSCL/(4*fSCL)
*/
- scl_time = (freq/1000) / (bus_freq * 4); /* bus_freq is KHz */
-
- /* set SCL High/Low time */
- NPCX_SMBSCLLT(ctrl) = scl_time;
- NPCX_SMBSCLHT(ctrl) = scl_time;
+ scl_freq = (freq/1000) / (bus_freq*4); /* bus_freq is KHz */
+
+ /* Normal mode if i2c freq is under 100kHz */
+ if (bus_freq <= 100) {
+ /* Set divider value of SCL */
+ SET_FIELD(NPCX_SMBCTL2(ctrl), NPCX_SMBCTL2_SCLFRQ7_FIELD
+ , (scl_freq & 0x7F));
+ SET_FIELD(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_SCLFRQ2_FIELD
+ , (scl_freq >> 7));
+ } else {
+ /* use Fast Mode */
+ SET_BIT(NPCX_SMBCTL3(ctrl) , NPCX_SMBCTL3_400K);
+#if (OSC_CLK > 15000000)
+ /*
+ * Set SCLLT/SCLHT:
+ * tSCLL = 2 * SCLLT7-0 * tCLK
+ * tSCLH = 2 * SCLHT7-0 * tCLK
+ * (tSCLL+tSCLH) = 4 * SCLH(L)T * tCLK if tSCLL == tSCLH
+ * SCLH(L)T = tSCL/(4*tCLK) = fCLK/(4*fSCL)
+ * The same formula as SCLFRQ
+ */
+ NPCX_SMBSCLLT(ctrl) = scl_freq;
+ NPCX_SMBSCLHT(ctrl) = scl_freq;
+#else
+ /*
+ * Set SCLH(L)T and hold-time directly for best i2c
+ * timing condition if core clock is low. Please refer
+ * Section 7.5.9 "SMBus Timing - Fast Mode" for detail.
+ */
+ if (bus_freq == 400) {
+ if (freq == 15000000) {
+ NPCX_SMBSCLLT(ctrl) = 12;
+ NPCX_SMBSCLHT(ctrl) = 9;
+ SET_FIELD(NPCX_SMBCTL4(ctrl),
+ NPCX_SMBCTL4_HLDT_FIELD, 7);
+ } else if (freq == 15000000/2) {
+ NPCX_SMBSCLLT(ctrl) = 7;
+ NPCX_SMBSCLHT(ctrl) = 5;
+ SET_FIELD(NPCX_SMBCTL4(ctrl),
+ NPCX_SMBCTL4_HLDT_FIELD, 7);
+ } else if (freq == 13000000) {
+ NPCX_SMBSCLLT(ctrl) = 11;
+ NPCX_SMBSCLHT(ctrl) = 8;
+ SET_FIELD(NPCX_SMBCTL4(ctrl),
+ NPCX_SMBCTL4_HLDT_FIELD, 7);
+ } else if (freq == 13000000/2) {
+ NPCX_SMBSCLLT(ctrl) = 7;
+ NPCX_SMBSCLHT(ctrl) = 4;
+ SET_FIELD(NPCX_SMBCTL4(ctrl),
+ NPCX_SMBCTL4_HLDT_FIELD, 7);
+ } else {
+ /* Set value from formula */
+ NPCX_SMBSCLLT(ctrl) = scl_freq;
+ NPCX_SMBSCLHT(ctrl) = scl_freq;
+ cprints(CC_I2C, "Warning: Not ",
+ "optimized timing for i2c %d", ctrl);
+ }
+ } else {
+ /* Set value from formula */
+ NPCX_SMBSCLLT(ctrl) = scl_freq;
+ NPCX_SMBSCLHT(ctrl) = scl_freq;
+ cprints(CC_I2C, "Warning: I2c %d don't support",
+ " over 400kHz if src clock is low.", ctrl);
+ }
+#endif
+ }
}
}
DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT);