summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/g/config_chip.h2
-rw-r--r--chip/g/init_chip.h1
-rw-r--r--chip/g/jitter.c162
-rw-r--r--chip/g/usb.c6
4 files changed, 167 insertions, 4 deletions
diff --git a/chip/g/config_chip.h b/chip/g/config_chip.h
index 938f3fdb1b..1f67678d71 100644
--- a/chip/g/config_chip.h
+++ b/chip/g/config_chip.h
@@ -65,7 +65,7 @@
#define PCLK_FREQ (24 * 1000 * 1000)
/* Number of IRQ vectors on the NVIC */
-#define CONFIG_IRQ_COUNT (GC_INTERRUPTS_COUNT - 16)
+#define CONFIG_IRQ_COUNT (GC_INTERRUPTS_COUNT - 15)
#undef CONFIG_RW_MEM_OFF
#undef CONFIG_RW_SIZE
diff --git a/chip/g/init_chip.h b/chip/g/init_chip.h
index 60d156e533..090ac7b730 100644
--- a/chip/g/init_chip.h
+++ b/chip/g/init_chip.h
@@ -7,5 +7,6 @@
#define __CROS_EC_INIT_CHIP_H
void init_jittery_clock(int highsec);
+void init_sof_clock(void);
#endif /* __CROS_EC_INIT_CHIP_H */
diff --git a/chip/g/jitter.c b/chip/g/jitter.c
index db1859b0d4..b864bf6db9 100644
--- a/chip/g/jitter.c
+++ b/chip/g/jitter.c
@@ -7,13 +7,16 @@
#include "console.h"
#include "init_chip.h"
#include "registers.h"
+#include "task.h"
+
+#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
void init_jittery_clock(int highsec)
{
unsigned trimfast = GR_FUSE(RC_JTR_OSC60_CC_TRIM);
unsigned trim48 = GR_FUSE(RC_JTR_OSC48_CC_TRIM);
unsigned delta = (trim48 - trimfast);
- /* for metastability reasons, avoid clk_jtr ~= clk_timer, make
+ /* For metastability reasons, avoid clk_jtr ~= clk_timer, make
* a keepout region around 24MHz of about 0.75MHz, about 3/16 of the
* the delta from trimfast and trim48 */
unsigned skiplow = (trim48 << 4) - (delta * 6);
@@ -49,3 +52,160 @@ void init_jittery_clock(int highsec)
GREG32(XO, CFG_WR_EN) = 0;
GREG32(XO, JTR_CTRL_EN) = 0;
}
+
+void init_sof_clock(void)
+{
+ /* Copy fuse value into software registers, both coarse and fine */
+ unsigned coarseTrimVal = GR_FUSE(RC_TIMER_OSC48_CC_TRIM);
+ unsigned fineTrimVal = GR_FUSE(RC_TIMER_OSC48_FC_TRIM);
+
+ /* We think SOF toggle happens once every mS, or ~24000 clock ticks */
+ unsigned targetCnt = PCLK_FREQ / 1000;
+
+ /* The possible operations of a particular calibration bucket */
+ unsigned binaryDnOp = 0x1 | 0x1 << 4;
+ unsigned binaryUpOp = 0x1 | 0x0 << 4;
+ unsigned subOp = 0x3 | 0x1 << 4;
+ unsigned addOp = 0x2 | 0x1 << 4;
+ unsigned nop = 0;
+
+ GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM) = coarseTrimVal;
+ GREG32(XO, CLK_TIMER_RC_FINE_ATE_TRIM) = fineTrimVal;
+
+ /* Coarse trim values come from software */
+ GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_COARSE_TRIM_SRC, 0);
+
+ /* enable error interrupts
+ * This enables underrun and overflow interrupts */
+ GREG32(XO, DXO_INT_ENABLE) = 0xC;
+
+ /* Setup SOF calibration buckets and associated operations */
+ GREG32(XO, CLK_TIMER_SLOW_CALIB0) = targetCnt * 70 / 100;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB1) = targetCnt * 80 / 100;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB2) = targetCnt * 90 / 100;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB3) =
+ targetCnt * (1000000 - 1250) / 1000000;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB4) = targetCnt;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB5) =
+ targetCnt * (1000000 + 1250) / 1000000;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB6) = targetCnt * 110 / 100;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB7) = targetCnt * 120 / 100;
+
+ /* This is a work-around for the screwy SOF */
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL0) = nop;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL1) = binaryDnOp;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL2) = binaryDnOp;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL3) = subOp;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL4) = nop;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL5) = nop;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL6) = addOp;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL7) = binaryUpOp;
+ GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL8) = binaryUpOp;
+
+ /* Set the calibration mode */
+ GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, ENABLE_FAST, 0);
+ GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, ENABLE_SLOW, 1);
+ GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, SLOW_MODE_SEL, 0); /* SOF */
+ GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, MAX_TRIM_SEL, 1);
+ /* Don't stop when a NOP operation is seen, keep on calibrating */
+ GWRITE_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, STOP_ON_NOP, 0);
+
+ /* Set source of trim codes:
+ * coarse trim comes from software
+ * fine trim comes from calibration engine */
+ GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_COARSE_TRIM_SRC, 0);
+ GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_FINE_TRIM_SRC, 1);
+
+ /* Enable dynamic trim */
+ GWRITE_FIELD(XO, CLK_TIMER_TRIM_CTRL, RC_TRIM_EN, 1);
+
+ /* Sync everything! */
+ GREG32(XO, CLK_TIMER_SYNC_CONTENTS) = 1;
+
+ /* Enable interrupts */
+ task_enable_irq(GC_IRQNUM_XO0_SLOW_CALIB_UNDERRUN_INT);
+ task_enable_irq(GC_IRQNUM_XO0_SLOW_CALIB_OVERFLOW_INT);
+}
+
+/* When the calibration under runs, it means the fine trim code
+ * has reached 0, but the clock is still too slow. Thus,
+ * software must reduce the coarse trim code by 1 */
+static void timer_sof_calibration_underrun_int(void)
+{
+ unsigned coarseTrimValue = GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM);
+
+ CPRINTS("%s: coarseTrimValue 0x%02x", __func__, coarseTrimValue);
+ GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM) = coarseTrimValue + 1;
+
+ GREG32(XO, DXO_INT_STATE) =
+ GC_XO_DXO_INT_STATE_SLOW_CALIB_UNDERRUN_MASK;
+}
+DECLARE_IRQ(GC_IRQNUM_XO0_SLOW_CALIB_UNDERRUN_INT,
+ timer_sof_calibration_underrun_int, 1);
+
+/* When the calibration overflows, it means the fine trim code
+ * has reached 0x1F, but the clock is still too fast. Thus,
+ * software must increase the coarse trim code by 1 */
+static void timer_sof_calibration_overflow_int(void)
+{
+ unsigned coarseTrimValue = GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM);
+
+ CPRINTS("%s: coarseTrimValue 0x%02x", __func__, coarseTrimValue);
+ GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM) = coarseTrimValue - 1;
+
+ GREG32(XO, DXO_INT_STATE) =
+ GC_XO_DXO_INT_STATE_SLOW_CALIB_OVERFLOW_MASK;
+}
+DECLARE_IRQ(GC_IRQNUM_XO0_SLOW_CALIB_OVERFLOW_INT,
+ timer_sof_calibration_overflow_int, 1);
+
+#ifdef DEBUG_ME
+static int command_sof(int argc, char **argv)
+{
+ ccprintf("FUSE_RC_TIMER_OSC48_CC_TRIM) 0x%08x\n",
+ GR_FUSE(RC_TIMER_OSC48_CC_TRIM));
+ ccprintf("FUSE_RC_TIMER_OSC48_FC_TRIM) 0x%08x\n",
+ GR_FUSE(RC_TIMER_OSC48_FC_TRIM));
+
+ ccprintf("CLK_TIMER_RC_COARSE_ATE_TRIM 0x%08x\n",
+ GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM));
+ ccprintf("CLK_TIMER_RC_FINE_ATE_TRIM 0x%08x\n",
+ GREG32(XO, CLK_TIMER_RC_FINE_ATE_TRIM));
+
+ ccprintf("CLK_TIMER_TRIM_CTRL 0x%08x\n",
+ GREG32(XO, CLK_TIMER_TRIM_CTRL));
+
+ ccprintf("CLK_TIMER_CALIB_TRIM_CTRL 0x%08x\n",
+ GREG32(XO, CLK_TIMER_CALIB_TRIM_CTRL));
+
+ ccprintf("DXO_INT_ENABLE 0x%08x\n",
+ GREG32(XO, DXO_INT_ENABLE));
+
+ ccprintf("CLK_TIMER_SLOW_CALIB\n");
+ ccprintf(" 0: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB0));
+ ccprintf(" 1: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB1));
+ ccprintf(" 2: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB2));
+ ccprintf(" 3: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB3));
+ ccprintf(" 4: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB4));
+ ccprintf(" 5: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB5));
+ ccprintf(" 6: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB6));
+ ccprintf(" 7: 0x%04x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB7));
+
+ ccprintf("CLK_TIMER_SLOW_CALIB_CTRL\n");
+ ccprintf(" 0: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL0));
+ ccprintf(" 1: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL1));
+ ccprintf(" 2: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL2));
+ ccprintf(" 3: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL3));
+ ccprintf(" 4: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL4));
+ ccprintf(" 5: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL5));
+ ccprintf(" 6: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL6));
+ ccprintf(" 7: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL7));
+ ccprintf(" 8: 0x%02x\n", GREG32(XO, CLK_TIMER_SLOW_CALIB_CTRL8));
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(sof, command_sof,
+ "",
+ "Display the SoF clock stuff",
+ NULL);
+#endif /* DEBUG_ME */
diff --git a/chip/g/usb.c b/chip/g/usb.c
index b5e036d60b..d47912dd02 100644
--- a/chip/g/usb.c
+++ b/chip/g/usb.c
@@ -9,6 +9,7 @@
#include "console.h"
#include "gpio.h"
#include "hooks.h"
+#include "init_chip.h"
#include "link_defs.h"
#include "registers.h"
#include "system.h"
@@ -1073,6 +1074,9 @@ static void usb_reset(void)
/* Reinitialize all the endpoints */
usb_init_endpoints();
+
+ /* Init the clock calibrator */
+ init_sof_clock();
}
static void usb_resetdet(void)
@@ -1188,14 +1192,12 @@ static void usb_softreset(void)
void usb_connect(void)
{
- CPRINTS("%s", __func__);
print_later("usb_connect()", 0, 0, 0, 0, 0);
GR_USB_DCTL &= ~DCTL_SFTDISCON;
}
void usb_disconnect(void)
{
- CPRINTS("%s", __func__);
print_later("usb_disconnect()", 0, 0, 0, 0, 0);
GR_USB_DCTL |= DCTL_SFTDISCON;