diff options
-rw-r--r-- | chip/g/config_chip.h | 2 | ||||
-rw-r--r-- | chip/g/init_chip.h | 1 | ||||
-rw-r--r-- | chip/g/jitter.c | 162 | ||||
-rw-r--r-- | chip/g/usb.c | 6 |
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; |