/** Configure the data transmission format * * @param mode Clock polarity and phase mode (0 - 3) * */ static void sps_configure(enum sps_mode mode, enum spi_clock_mode clk_mode) { /* Disable All Interrupts */ GREG32(SPS, ICTRL) = 0; GWRITE_FIELD(SPS, CTRL, MODE, mode); GWRITE_FIELD(SPS, CTRL, IDLE_LVL, 0); GWRITE_FIELD(SPS, CTRL, CPHA, clk_mode & 1); GWRITE_FIELD(SPS, CTRL, CPOL, (clk_mode >> 1) & 1); GWRITE_FIELD(SPS, CTRL, TXBITOR, 1); /* MSB first */ GWRITE_FIELD(SPS, CTRL, RXBITOR, 1); /* MSB first */ /* xfer 0xff when tx fifo is empty */ GREG32(SPS, DUMMY_WORD) = GC_SPS_DUMMY_WORD_DEFAULT; /* [5,4,3] [2,1,0] * RX{DIS, EN, RST} TX{DIS, EN, RST} */ GREG32(SPS, FIFO_CTRL) = 0x9; /* wait for reset to self clear. */ while (GREG32(SPS, FIFO_CTRL) & 9) ; /* Do not enable TX FIFO until we have something to send. */ GWRITE_FIELD(SPS, FIFO_CTRL, RXFIFO_EN, 1); GREG32(SPS, RXFIFO_THRESHOLD) = 8; GWRITE_FIELD(SPS, ICTRL, RXFIFO_LVL, 1); /* Use CS_DEASSERT to retrieve all remaining bytes from RX FIFO. */ GWRITE_FIELD(SPS, ISTATE_CLR, CS_DEASSERT, 1); GWRITE_FIELD(SPS, ICTRL, CS_DEASSERT, 1); }
static void usb_load_serialno(void) { char devid_str[20]; snprintf(devid_str, 20, "%08X-%08X", GREG32(FUSE, DEV_ID0), GREG32(FUSE, DEV_ID1)); usb_set_serial(devid_str); }
static void init_timers(void) { /* Cancel low speed timers that may have * been initialized prior to soft reset. */ GREG32(TIMELS, TIMER0_CONTROL) = 0; GREG32(TIMELS, TIMER0_LOAD) = 0; GREG32(TIMELS, TIMER1_CONTROL) = 0; GREG32(TIMELS, TIMER1_LOAD) = 0; }
void flash_info_write_enable(void) { /* Enable R/W access to INFO. */ GREG32(GLOBALSEC, FLASH_REGION3_BASE_ADDR) = FLASH_INFO_MEMORY_BASE + FLASH_INFO_MANUFACTURE_STATE_OFFSET; GREG32(GLOBALSEC, FLASH_REGION3_SIZE) = FLASH_INFO_MANUFACTURE_STATE_SIZE - 1; GREG32(GLOBALSEC, FLASH_REGION3_CTRL) = GC_GLOBALSEC_FLASH_REGION3_CTRL_EN_MASK | GC_GLOBALSEC_FLASH_REGION3_CTRL_WR_EN_MASK | GC_GLOBALSEC_FLASH_REGION3_CTRL_RD_EN_MASK; }
/* 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: 0x%02x", __func__, coarseTrimValue); if (coarseTrimValue > 0x00) GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM) = coarseTrimValue - 1; GREG32(XO, DXO_INT_STATE) = GC_XO_DXO_INT_STATE_SLOW_CALIB_UNDERRUN_MASK; }
static void sps_cs_deassert_interrupt(uint32_t port) { /* Make sure the receive FIFO is drained. */ sps_rx_interrupt(port, 1); GWRITE_FIELD(SPS, ISTATE_CLR, CS_DEASSERT, 1); GWRITE_FIELD(SPS, FIFO_CTRL, TXFIFO_EN, 0); /* * And transmit FIFO is emptied, so the next transaction doesn't start * by clocking out any bytes left over from this one. */ GREG32(SPS, TXFIFO_WPTR) = GREG32(SPS, TXFIFO_RPTR); }
/* Initialize board. */ static void board_init(void) { init_pmu(); init_timers(); init_interrupts(); init_trng(); init_runlevel(PERMISSION_MEDIUM); /* TODO(crosbug.com/p/49959): For now, leave flash WP unlocked */ GREG32(RBOX, EC_WP_L) = 1; /* Indication that firmware is running, for debug purposes. */ GREG32(PMU, PWRDN_SCRATCH16) = 0xCAFECAFE; }
void unlockFlashForRW(void) { uint32_t text_end = ((uint32_t)(&__ro_end) + (uint32_t)(&__data_end) - (uint32_t)(&__data_start) + CONFIG_FLASH_BANK_SIZE) & ~(CONFIG_FLASH_BANK_SIZE - 1); GREG32(GLOBALSEC, FLASH_REGION1_BASE_ADDR) = text_end; GREG32(GLOBALSEC, FLASH_REGION1_SIZE) = CONFIG_FLASH_SIZE - text_end - 1; GWRITE_FIELD(GLOBALSEC, FLASH_REGION1_CTRL, EN, 1); GWRITE_FIELD(GLOBALSEC, FLASH_REGION1_CTRL, RD_EN, 1); GWRITE_FIELD(GLOBALSEC, FLASH_REGION1_CTRL, WR_EN, 0); }
/* Verify the flash controller is awake. */ static int _check_flash_is_awake(void) { int retval; GREG32(FLASH, FSH_TRANS) = 0xFFFFFFFF; retval = GREG32(FLASH, FSH_TRANS); GREG32(FLASH, FSH_TRANS) = 0x0; if (retval == 0) { debug_printf("ERROR:FLASH Controller seems unresponsive. "); debug_printf("Did you make sure to run 'reseth'?\n"); return E_FL_NOT_AWAKE; } return 0; }
int flash_info_read(uint32_t offset, uint32_t *dst) { int retval; /* Make sure flash controller is awake. */ retval = _check_flash_is_awake(); if (retval) return retval; GWRITE_FIELD(FLASH, FSH_TRANS, OFFSET, offset); GWRITE_FIELD(FLASH, FSH_TRANS, MAINB, 1); GWRITE_FIELD(FLASH, FSH_TRANS, SIZE, 1); retval = _flash_cmd(1, FSH_OP_READ); if (retval) return retval; if (_flash_error()) return E_FL_ERROR; if (!retval) *dst = GREG32(FLASH, FSH_DOUT_VAL1); return retval; }
static void init_pmu(void) { /* This boot sequence may be a result of previous soft reset, * in which case the PMU low power sequence register needs to * be reset. */ GREG32(PMU, LOW_POWER_DIS) = 0; }
/* 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); unsigned max; CPRINTS("%s: 0x%02x", __func__, coarseTrimValue); if (GREAD_FIELD(XO, CLK_TIMER_CALIB_TRIM_CTRL, MAX_TRIM_SEL)) max = 0x1f; else max = 0xff; if (coarseTrimValue < max) GREG32(XO, CLK_TIMER_RC_COARSE_ATE_TRIM) = coarseTrimValue + 1; GREG32(XO, DXO_INT_STATE) = GC_XO_DXO_INT_STATE_SLOW_CALIB_OVERFLOW_MASK; }
static int _flash_error(void) { int retval = GREG32(FLASH, FSH_ERROR); if (!retval) return 0; debug_printf("Register FLASH_FSH_ERROR is not zero (found %x).\n"); debug_printf("Will read again to verify FSH_ERROR was cleared "); debug_printf("and then continue...\n", retval); retval = GREG32(FLASH, FSH_ERROR); if (retval) { debug_printf("ERROR: Read to FLASH_FSH_ERROR (%x) "); debug_printf("did not clear it\n", retval); } return retval; }
void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest) { int i; const int digest_len = (mode == SHA1_MODE) ? SHA_DIGEST_SIZE : SHA256_DIGEST_SIZE; /* Stop LIVESTREAM mode. */ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; /* Wait for SHA DONE interrupt. */ while (!GREG32(KEYMGR, SHA_ITOP)) ; /* Read out final digest. */ for (i = 0; i < digest_len / 4; ++i) *digest++ = GR_KEYMGR_SHA_HASH(i); dcrypto_release_sha_hw(); }
void checkBuildVersion(void) { uint32_t last_sync = GREG32(SWDP, P4_LAST_SYNC); if (last_sync == GC_SWDP_P4_LAST_SYNC_DEFAULT) return; debug_printf("compiled for %u, not willing to run on %u\n", GC_SWDP_P4_LAST_SYNC_DEFAULT, last_sync); halt(); }
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 * 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); unsigned skiphigh = (trim48 << 4) + (delta * 6); unsigned setting = trimfast << 4; unsigned stepx16; unsigned bankval; int bank; if (highsec) stepx16 = 0xff - trimfast; else stepx16 = 2 * (trim48 - trimfast); for (bank = 0; bank < 16; bank++) { /* saturate at 0xff */ bankval = (setting > 0xfff) ? 0xff : (setting >> 4); GR_XO_JTR_JITTERY_TRIM_BANK(bank) = bankval; setting += stepx16; if ((setting > skiplow) && (setting < skiphigh)) setting = skiphigh; } GWRITE_FIELD(XO, CLK_JTR_TRIM_CTRL, RC_COARSE_TRIM_SRC, 2); GWRITE_FIELD(XO, CLK_JTR_TRIM_CTRL, RC_INITIAL_TRIM_PERIOD, 100); GWRITE_FIELD(XO, CLK_JTR_TRIM_CTRL, RC_TRIM_EN, 1); GREG32(XO, CLK_JTR_JITTERY_TRIM_EN) = 1; GREG32(XO, CLK_JTR_SYNC_CONTENTS) = 0; /* Writing any value locks things until the next hard reboot */ GREG32(XO, CFG_WR_EN) = 0; GREG32(XO, JTR_CTRL_EN) = 0; }
void dcrypto_sha_init(enum sha_mode mode) { int val; /* Stop LIVESTREAM mode, in case final() was not called. */ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; /* Clear interrupt status. */ GREG32(KEYMGR, SHA_ITOP) = 0; /* Enable streaming mode. */ val = GC_KEYMGR_SHA_CFG_EN_LIVESTREAM_MASK; /* Enable SHA DONE interrupt. */ val |= GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK; /* Select SHA mode. */ if (mode == SHA1_MODE) val |= GC_KEYMGR_SHA_CFG_EN_SHA1_MASK; GREG32(KEYMGR, SHA_CFG_EN) = val; /* Start SHA engine. */ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK; }
/* Send cmd to flash controller. */ static int _flash_cmd(uint32_t fidx, uint32_t cmd) { int cnt, retval; /* Activate controller. */ GREG32(FLASH, FSH_PE_EN) = FSH_OP_ENABLE; GREG32_ADDR(FLASH, FSH_PE_CONTROL0)[fidx] = cmd; /* wait on FSH_PE_EN (means the operation started) */ cnt = 500; /* TODO(mschilder): pick sane value. */ do { retval = GREG32(FLASH, FSH_PE_EN); } while (retval && cnt--); if (retval) { debug_printf("ERROR: FLASH_FSH_PE_EN never went to 0, is "); debug_printf("0x%x after timeout\n", retval); return E_FL_TIMEOUT; } /* * wait 100us before checking FSH_PE_CONTROL (means the operation * ended) */ cnt = 1000000; do { retval = GREG32_ADDR(FLASH, FSH_PE_CONTROL0)[fidx]; } while (retval && --cnt); if (retval) { debug_printf ("ERROR: FLASH_FSH_PE_CONTROL%d is 0x%x after timeout\n", fidx, retval); GREG32_ADDR(FLASH, FSH_PE_CONTROL0)[fidx] = 0; return E_FL_TIMEOUT; } return 0; }
int flash_physical_info_read_word(int byte_offset, uint32_t *dst) { int ret; if (byte_offset % CONFIG_FLASH_WRITE_SIZE) return EC_ERROR_INVAL; ret = do_flash_op(OP_READ_BLOCK, 1, byte_offset, 1); if (ret != EC_SUCCESS) return ret; *dst = GREG32(FLASH, FSH_DOUT_VAL1); return EC_SUCCESS; }
void dcrypto_sha_update(struct HASH_CTX *unused, const void *data, uint32_t n) { const uint8_t *bp = (const uint8_t *) data; const uint32_t *wp; /* Feed unaligned start bytes. */ while (n != 0 && ((uint32_t)bp & 3)) { GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++; n -= 1; } /* Feed groups of aligned words. */ wp = (uint32_t *)bp; while (n >= 8*4) { GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; n -= 8*4; } /* Feed individual aligned words. */ while (n >= 4) { GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; n -= 4; } /* Feed remaing bytes. */ bp = (uint8_t *) wp; while (n != 0) { GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++; n -= 1; } }
void sps_tx_status(uint8_t byte) { GREG32(SPS, DUMMY_WORD) = byte; }
void usb_init(void) { int i, resume; /* USB is in use */ disable_sleep(SLEEP_MASK_USB_DEVICE); /* * Resuming from a deep sleep is a lot like a cold boot, but there are * few things that we need to do slightly differently. However, we ONLY * do them if we're really resuming due to a USB wakeup. If we're woken * for some other reason, we just do a normal USB reset. The host * doesn't mind. */ resume = ((system_get_reset_flags() & RESET_FLAG_USB_RESUME) && (GR_USB_GINTSTS & GC_USB_GINTSTS_WKUPINT_MASK)); /* TODO(crosbug.com/p/46813): Clean this up. Do only what's needed, and * use meaningful constants instead of magic numbers. */ GREG32(GLOBALSEC, DDMA0_REGION0_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DDMA0_REGION1_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DDMA0_REGION2_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DDMA0_REGION3_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION0_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION1_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION2_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION3_CTRL) = 0xffffffff; /* Enable clocks */ clock_enable_module(MODULE_USB, 1); /* TODO(crbug.com/496888): set up pinmux */ gpio_config_module(MODULE_USB, 1); /* Make sure interrupts are disabled */ GR_USB_GINTMSK = 0; GR_USB_DAINTMSK = 0; GR_USB_DIEPMSK = 0; GR_USB_DOEPMSK = 0; /* Select the correct PHY */ usb_select_phy(which_phy); /* Full-Speed Serial PHY */ GR_USB_GUSBCFG = GUSBCFG_PHYSEL_FS | GUSBCFG_FSINTF_6PIN | GUSBCFG_TOUTCAL(7) /* FIXME: Magic number! 14 is for 15MHz! Use 9 for 30MHz */ | GUSBCFG_USBTRDTIM(14); if (!resume) /* Don't reset on resume, because some preserved internal state * will be lost and there's no way to restore it. */ usb_softreset(); GR_USB_GUSBCFG = GUSBCFG_PHYSEL_FS | GUSBCFG_FSINTF_6PIN | GUSBCFG_TOUTCAL(7) /* FIXME: Magic number! 14 is for 15MHz! Use 9 for 30MHz */ | GUSBCFG_USBTRDTIM(14); /* Global + DMA configuration */ /* TODO: What about the AHB Burst Length Field? It's 0 now. */ GR_USB_GAHBCFG = GAHBCFG_DMA_EN | GAHBCFG_GLB_INTR_EN | GAHBCFG_NP_TXF_EMP_LVL; /* Be in disconnected state until we are ready */ if (!resume) usb_disconnect(); if (resume) /* DEVADDR is preserved in the USB module during deep sleep, * but it doesn't show up in USB_DCFG on resume. If we don't * restore it manually too, it doesn't work. */ GR_USB_DCFG = GREG32(PMU, PWRDN_SCRATCH18); else /* Init: USB2 FS, Scatter/Gather DMA, DEVADDR = 0x00 */ GR_USB_DCFG |= DCFG_DEVSPD_FS48 | DCFG_DESCDMA; /* If we've restored a nonzero device address, update our state. */ if (GR_USB_DCFG & GC_USB_DCFG_DEVADDR_MASK) { /* Caution: We only have one config TODAY, so there's no real * difference between DS_CONFIGURED and DS_ADDRESS. */ device_state = DS_CONFIGURED; configuration_value = 1; } else { device_state = DS_DEFAULT; configuration_value = 0; } /* Now that DCFG.DesDMA is accurate, prepare the FIFOs */ setup_data_fifos(); /* If resuming, reinitialize the endpoints now. For a cold boot we'll * do this as part of handling the host-driven reset. */ if (resume) usb_init_endpoints(); /* Clear any pending interrupts */ for (i = 0; i < 16; i++) { GR_USB_DIEPINT(i) = 0xffffffff; GR_USB_DOEPINT(i) = 0xffffffff; } GR_USB_GINTSTS = 0xFFFFFFFF; /* Unmask some endpoint interrupt causes */ GR_USB_DIEPMSK = DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK; GR_USB_DOEPMSK = DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK | DOEPMSK_SETUPMSK; /* Enable interrupt handlers */ task_enable_irq(GC_IRQNUM_USB0_USBINTR); /* Allow USB interrupts to come in */ GR_USB_GINTMSK = /* NAK bits that must be cleared by the DCTL register */ GINTMSK(GOUTNAKEFF) | GINTMSK(GINNAKEFF) | /* Initialization events */ GINTMSK(USBRST) | GINTMSK(ENUMDONE) | /* Endpoint activity, cleared by the DOEPINT/DIEPINT regs */ GINTMSK(OEPINT) | GINTMSK(IEPINT) | /* Reset detected while suspended. Need to wake up. */ GINTMSK(RESETDET) | /* TODO: Do we need this? */ /* Idle, Suspend detected. Should go to sleep. */ GINTMSK(ERLYSUSP) | GINTMSK(USBSUSP) | /* Watch for first SOF */ GINTMSK(SOF); /* Device registers have been setup */ GR_USB_DCTL |= DCTL_PWRONPRGDONE; udelay(10); GR_USB_DCTL &= ~DCTL_PWRONPRGDONE; /* Clear global NAKs */ GR_USB_DCTL |= DCTL_CGOUTNAK | DCTL_CGNPINNAK; #ifndef CONFIG_USB_INHIBIT_CONNECT /* Indicate our presence to the USB host */ if (!resume) usb_connect(); #endif }
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; }
void flash_info_write_disable(void) { GREG32(GLOBALSEC, FLASH_REGION3_CTRL) = 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); }