Add initial support for cr50 SoC

The serial console works. Nothing else is implemented yet.

BUG=none
BRANCH=ToT
TEST=make buildall -j

To build,

  make BOARD=cr50 hex

Testing the result requires a development board. I have one. It
works with HW revision m3.dist_20140918_094011

Change-Id: I718d93572d315d13e96ef6f296c3c2796e928e66
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/226268
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Bill Richardson
2014-10-07 13:18:19 -07:00
committed by chrome-internal-fetch
parent 327bfe2e58
commit 86c7e2e90a
17 changed files with 1036 additions and 0 deletions

View File

@@ -41,6 +41,7 @@ cmd_flat_to_obj = $(CC) -T $(out)/firmware_image.lds -nostdlib $(CPPFLAGS) \
-Wl,--build-id=none -o $@ $<
cmd_elf_to_flat = $(OBJCOPY) -O binary $^ $@
cmd_elf_to_dis = $(OBJDUMP) -D $< > $@
cmd_elf_to_hex = $(OBJCOPY) -O ihex $^ $@
cmd_elf = $(LD) $(objs) $(LDFLAGS) -o $@ -T $< -Map $(out)/$*.map
cmd_exe = $(CC) $(objs) $(HOST_TEST_LDFLAGS) -o $@
cmd_c_to_o = $(CC) $(CFLAGS) -MMD -MF $@.d -c $< -o $@
@@ -81,6 +82,9 @@ proj-%:
dis-y = $(out)/$(PROJECT).RO.dis $(out)/$(PROJECT).RW.dis
dis: $(dis-y)
hex-y = $(out)/$(PROJECT).RO.hex $(out)/$(PROJECT).RW.hex
hex: $(hex-y)
utils: $(build-utils) $(host-utils)
# On board test binaries
@@ -157,6 +161,9 @@ $(out)/%.dis: $(out)/%.elf
$(out)/%.flat: $(out)/%.elf
$(call quiet,elf_to_flat,OBJCOPY)
$(out)/%.hex: $(out)/%.elf
$(call quiet,elf_to_hex,OBJCOPY)
$(out)/%.elf: $(out)/%.lds $(objs)
$(call quiet,elf,LD )

1
board/cr50/Makefile Symbolic link
View File

@@ -0,0 +1 @@
../../Makefile

20
board/cr50/board.c Normal file
View File

@@ -0,0 +1,20 @@
/* Copyright (c) 2014 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 "common.h"
#include "gpio.h"
#include "hooks.h"
#include "task.h"
#include "util.h"
#include "gpio_list.h"
/* Initialize board. */
static void board_init(void)
{
/* TODO(crosbug.com/p/33432): Try enabling this */
/* gpio_enable_interrupt(GPIO_CAMO0_BREACH_INT); */
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);

34
board/cr50/board.h Normal file
View File

@@ -0,0 +1,34 @@
/* Copyright (c) 2014 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.
*/
#ifndef __BOARD_H
#define __BOARD_H
/* Features that we don't want just yet */
#undef CONFIG_CMD_LID_ANGLE
#undef CONFIG_CMD_POWERINDEBUG
#undef CONFIG_DMA_DEFAULT_HANDLERS
#undef CONFIG_FLASH
#undef CONFIG_FMAP
#undef CONFIG_HIBERNATE
#undef CONFIG_LID_SWITCH
#undef CONFIG_WATCHDOG
/* How do I identify nonexistant GPIOs? */
#define DUMMY_GPIO_BANK -1
/*
* Allow dangerous commands all the time, since we don't have a write protect
* switch.
*/
#define CONFIG_SYSTEM_UNLOCKED
#ifndef __ASSEMBLER__
#include "gpio_signal.h"
#endif /* !__ASSEMBLER__ */
#endif /* __BOARD_H */

10
board/cr50/build.mk Normal file
View File

@@ -0,0 +1,10 @@
# -*- makefile -*-
# Copyright (c) 2014 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.
#
# Board specific files build
CHIP:=g
board-y=board.o

21
board/cr50/ec.tasklist Normal file
View File

@@ -0,0 +1,21 @@
/* Copyright (c) 2014 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.
*/
/**
* List of enabled tasks in the priority order
*
* The first one has the lowest priority.
*
* For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
* TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
* where :
* 'n' in the name of the task
* 'r' in the main routine of the task
* 'd' in an opaque parameter passed to the routine at startup
* 's' is the stack size in bytes; must be a multiple of 8
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)

16
board/cr50/gpio.inc Normal file
View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) 2014 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.
*/
/* Inputs with interrupt handlers are first for efficiency */
/* TODO(crosbug.com/p/33432): try enabling this */
/* GPIO(CAMO0_BREACH_INT, A, 0, GPIO_INT_BOTH, button_event) */
/* Outputs */
/* Unimplemented signals which we need to emulate for now */
UNIMPLEMENTED(ENTERING_RW)
/* Alternate functions */

11
chip/g/build.mk Normal file
View File

@@ -0,0 +1,11 @@
# -*- makefile -*-
# Copyright (c) 2014 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.
#
CORE:=cortex-m
CFLAGS_CPU+=-march=armv7-m -mcpu=cortex-m3
# Required chip modules
chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o

331
chip/g/clock.c Normal file
View File

@@ -0,0 +1,331 @@
/* Copyright (c) 2014 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 "clock.h"
#include "registers.h"
/* Clock initialization taken from some example code */
#define RESOLUTION 12
#define LOAD_VAL (0x1 << 11)
#define MAX_TRIM (7*16)
static void switch_osc_to_xtl(void);
static void clock_on_xo0(void)
{
/* turn on xo0 clock */
/* don't know which control word it might be in */
#ifdef G_PMU_PERICLKSET0_DXO0_LSB
G_PMU_PERICLKSET0 = (1 << G_PMU_PERICLKSET0_DXO0_LSB);
#endif
#ifdef G_PMU_PERICLKSET1_DXO0_LSB
G_PMU_PERICLKSET1 = (1 << G_PMU_PERICLKSET1_DXO0_LSB);
#endif
}
/* Converts an integer setting to the RC trim code format (7, 4-bit values) */
static unsigned val_to_trim_code(unsigned val)
{
unsigned base = val / 7;
unsigned mod = val % 7;
unsigned code = 0x0;
int digit;
/* Increasing count from right to left */
for (digit = 0; digit < 7; digit++) {
/* Check for mod */
if (digit <= mod)
code |= ((base & 0xF) << 4 * digit);
else
code |= (((base - 1) & 0xF) << 4 * digit);
}
return code;
}
static unsigned calib_rc_trim(void)
{
unsigned size, iter;
signed mid;
signed diff;
/* Switch to crystal for calibration. This should work since we are
* technically on an uncalibrated RC trim clock. */
switch_osc_to_xtl();
clock_on_xo0();
/* Clear the HOLD signal on dxo */
G_XO_OSC_CLRHOLD = G_XO_OSC_CLRHOLD_RC_TRIM_MASK;
/* Reset RC calibration counters */
G_XO_OSC_RC_CAL_RSTB = 0x0;
G_XO_OSC_RC_CAL_RSTB = 0x1;
/* Write the LOAD val */
G_XO_OSC_RC_CAL_LOAD = LOAD_VAL;
/* Begin binary search */
mid = 0;
size = MAX_TRIM / 2;
for (iter = 0; iter <= 7; iter++) {
/* Set the trim value */
G_XO_OSC_RC = val_to_trim_code(mid) << G_XO_OSC_RC_TRIM_LSB;
/* Do a calibration */
G_XO_OSC_RC_CAL_START = 0x1;
/* NOTE: There is a small race condition because of the delay
* in dregfile. The start doesn't actually appear for 2 clock
* cycles after the write. So, poll until done goes low. */
while (G_XO_OSC_RC_CAL_DONE)
;
/* Wait until it's done */
while (!G_XO_OSC_RC_CAL_DONE)
;
/* Check the counter value */
diff = LOAD_VAL - G_XO_OSC_RC_CAL_COUNT;
/* Test to see whether we are still outside of our desired
* resolution */
if ((diff < -RESOLUTION) || (diff > RESOLUTION))
mid = (diff > 0) ? (mid - size / 2) : (mid + size / 2);
size = (size + 1) >> 1; /* round up before division */
}
/* Set the final trim value */
G_XO_OSC_RC = (val_to_trim_code(mid) << G_XO_OSC_RC_TRIM_LSB) |
(0x1 << G_XO_OSC_RC_EN_LSB);
/* Set the HOLD signal on dxo */
G_XO_OSC_SETHOLD = G_XO_OSC_SETHOLD_RC_TRIM_MASK;
/* Switch back to the RC trim now that we are calibrated */
G_PMU_OSC_HOLD_CLR = 0x1; /* make sure the hold signal is clear */
G_PMU_OSC_SELECT = G_PMU_OSC_SELECT_RC_TRIM;
/* Make sure the hold signal is set for future power downs */
G_PMU_OSC_HOLD_SET = 0x1;
return mid;
}
static void switch_osc_to_rc_trim(void)
{
unsigned trimmed;
unsigned saved_trim, fuse_trim, default_trim;
unsigned trim_code;
/* check which clock we are running on */
unsigned osc_sel = G_PMU_OSC_SELECT_STAT;
if (osc_sel == G_PMU_OSC_SELECT_RC_TRIM) {
/* already using the rc_trim so nothing to do here */
/* make sure the hold signal is set for future power downs */
G_PMU_OSC_HOLD_SET = 0x1;
return;
}
/* Turn on DXO clock so we can write in the trim code in */
clock_on_xo0();
/* disable the RC_TRIM Clock */
REG_WRITE_MASK(G_PMU_OSC_CTRL,
G_PMU_OSC_CTRL_RC_TRIM_READYB_MASK, 0x1,
G_PMU_OSC_CTRL_RC_TRIM_READYB_LSB);
/* power up the clock if not already powered up */
G_PMU_CLRDIS = 1 << G_PMU_SETDIS_RC_TRIM_LSB;
/* Try to find the trim code */
saved_trim = G_XO_OSC_RC_STATUS;
fuse_trim = G_PMU_FUSE_RD_RC_OSC_26MHZ;
default_trim = G_XO_OSC_RC;
/* Check for the trim code in the always-on domain before looking at
* the fuse */
if (saved_trim & G_XO_OSC_RC_STATUS_EN_MASK) {
trim_code = (saved_trim & G_XO_OSC_RC_STATUS_TRIM_MASK)
>> G_XO_OSC_RC_STATUS_TRIM_LSB;
trimmed = 1;
} else if (fuse_trim & G_PMU_FUSE_RD_RC_OSC_26MHZ_EN_MASK) {
trim_code = (fuse_trim & G_PMU_FUSE_RD_RC_OSC_26MHZ_TRIM_MASK)
>> G_PMU_FUSE_RD_RC_OSC_26MHZ_TRIM_LSB;
trimmed = 1;
} else {
trim_code = (default_trim & G_XO_OSC_RC_TRIM_MASK)
>> G_XO_OSC_RC_TRIM_LSB;
trimmed = 0;
}
/* Write the trim code to dxo */
if (trimmed) {
/* clear the hold signal */
G_XO_OSC_CLRHOLD = 1 << G_XO_OSC_CLRHOLD_RC_TRIM_LSB;
G_XO_OSC_RC = (trim_code << G_XO_OSC_RC_TRIM_LSB) | /* write */
((trimmed & 0x1) << G_XO_OSC_RC_EN_LSB); /* enable */
/* set the hold signal */
G_XO_OSC_SETHOLD = 1 << G_XO_OSC_SETHOLD_RC_TRIM_LSB;
}
/* enable the RC_TRIM Clock */
REG_WRITE_MASK(G_PMU_OSC_CTRL, G_PMU_OSC_CTRL_RC_TRIM_READYB_MASK,
0x0, G_PMU_OSC_CTRL_RC_TRIM_READYB_LSB);
/* Switch the select signal */
G_PMU_OSC_HOLD_CLR = 0x1; /* make sure the hold signal is clear */
G_PMU_OSC_SELECT = G_PMU_OSC_SELECT_RC_TRIM;
/* make sure the hold signal is set for future power downs */
G_PMU_OSC_HOLD_SET = 0x1;
/* If we didn't find a valid trim code, then we need to calibrate */
if (!trimmed)
calib_rc_trim();
/* We saved the trim code and went back to the RC trim inside
* calib_rc_trim */
}
static void switch_osc_to_xtl(void)
{
unsigned int saved_trim, fuse_trim, trim_code, final_trim;
unsigned int fsm_status, max_trim;
unsigned int fsm_done;
/* check which clock we are running on */
unsigned int osc_sel = G_PMU_OSC_SELECT_STAT;
if (osc_sel == G_PMU_OSC_SELECT_XTL) {
/* already using the crystal so nothing to do here */
/* make sure the hold signal is set for future power downs */
G_PMU_OSC_HOLD_SET = 0x1;
return;
}
if (osc_sel == G_PMU_OSC_SELECT_RC)
/* RC untrimmed clock. We must go through the trimmed clock
* first to avoid glitching */
switch_osc_to_rc_trim();
/* disable the XTL Clock */
REG_WRITE_MASK(G_PMU_OSC_CTRL, G_PMU_OSC_CTRL_XTL_READYB_MASK,
0x1, G_PMU_OSC_CTRL_XTL_READYB_LSB);
/* power up the clock if not already powered up */
G_PMU_CLRDIS = 1 << G_PMU_SETDIS_XTL_LSB;
/* Try to find the trim code */
trim_code = 0;
saved_trim = G_XO_OSC_XTL_TRIM_STAT;
fuse_trim = G_PMU_FUSE_RD_XTL_OSC_26MHZ;
/* Check for the trim code in the always-on domain before looking at
* the fuse */
if (saved_trim & G_XO_OSC_XTL_TRIM_STAT_EN_MASK) {
/* nothing to do */
/* trim_code = (saved_trim & G_XO_OSC_XTL_TRIM_STAT_CODE_MASK)
>> G_XO_OSC_XTL_TRIM_STAT_CODE_LSB; */
/* print_trickbox_message("XTL TRIM CODE FOUND IN 3P3"); */
} else if (fuse_trim & G_PMU_FUSE_RD_XTL_OSC_26MHZ_EN_MASK) {
/* push the fuse trim code as the saved trim code */
/* print_trickbox_message("XTL TRIM CODE FOUND IN FUSE"); */
trim_code = (fuse_trim & G_PMU_FUSE_RD_XTL_OSC_26MHZ_TRIM_MASK)
>> G_PMU_FUSE_RD_XTL_OSC_26MHZ_TRIM_LSB;
/* make sure the hold signal is clear */
G_XO_OSC_CLRHOLD = 0x1 << G_XO_OSC_CLRHOLD_XTL_LSB;
G_XO_OSC_XTL_TRIM =
(trim_code << G_XO_OSC_XTL_TRIM_CODE_LSB) |
(0x1 << G_XO_OSC_XTL_TRIM_EN_LSB);
} else
/* print_trickbox_message("XTL TRIM CODE NOT FOUND"); */
;
/* Run the crystal FSM to calibrate the crystal trim */
fsm_done = G_XO_OSC_XTL_FSM;
if (fsm_done & G_XO_OSC_XTL_FSM_DONE_MASK) {
/* If FSM done is high, it means we already ran it so let's not
* run it again */
/* DO NOTHING */
} else {
G_XO_OSC_XTL_FSM_EN = 0x0; /* reset FSM */
G_XO_OSC_XTL_FSM_EN = G_XO_OSC_XTL_FSM_EN_KEY;
while (!(fsm_done & G_XO_OSC_XTL_FSM_DONE_MASK))
fsm_done = G_XO_OSC_XTL_FSM;
}
/* Check the status and final trim value */
max_trim = (G_XO_OSC_XTL_FSM_CFG & G_XO_OSC_XTL_FSM_CFG_TRIM_MAX_MASK)
>> G_XO_OSC_XTL_FSM_CFG_TRIM_MAX_LSB;
final_trim = (fsm_done & G_XO_OSC_XTL_FSM_TRIM_MASK)
>> G_XO_OSC_XTL_FSM_TRIM_LSB;
fsm_status = (fsm_done & G_XO_OSC_XTL_FSM_STATUS_MASK)
>> G_XO_OSC_XTL_FSM_STATUS_LSB;
/* Check status bit and trim value */
if (fsm_status) {
if (final_trim >= max_trim)
/* print_trickbox_error("ERROR: XTL FSM status was
high, but final XTL trim is greater than or equal to
max trim"); */
;
} else {
if (final_trim != max_trim)
/* print_trickbox_error("ERROR: XTL FSM status was low,
but final XTL trim does not equal max trim"); */
;
}
/* save the trim for future powerups */
/* make sure the hold signal is clear (may have already been cleared) */
G_XO_OSC_CLRHOLD = 0x1 << G_XO_OSC_CLRHOLD_XTL_LSB;
G_XO_OSC_XTL_TRIM =
(final_trim << G_XO_OSC_XTL_TRIM_CODE_LSB) |
(0x1 << G_XO_OSC_XTL_TRIM_EN_LSB);
/* make sure the hold signal is set for future power downs */
G_XO_OSC_SETHOLD = 0x1 << G_XO_OSC_SETHOLD_XTL_LSB;
/* enable the XTL Clock */
REG_WRITE_MASK(G_PMU_OSC_CTRL, G_PMU_OSC_CTRL_XTL_READYB_MASK,
0x0, G_PMU_OSC_CTRL_XTL_READYB_LSB);
/* Switch the select signal */
G_PMU_OSC_HOLD_CLR = 0x1; /* make sure the hold signal is clear */
G_PMU_OSC_SELECT = G_PMU_OSC_SELECT_XTL;
/* make sure the hold signal is set for future power downs */
G_PMU_OSC_HOLD_SET = 0x1;
}
void clock_init(void)
{
/*
* TODO(crosbug.com/p/33432): The following comment was in the example
* code, but the function that's called doesn't match what it says.
* Investigate further.
*/
/* Switch to crystal clock since RC clock not accurate enough */
switch_osc_to_rc_trim();
}
void clock_enable_module(enum module_id module, int enable)
{
if (module != MODULE_UART)
return;
/* don't know which control word it might be in */
#ifdef G_PMU_PERICLKSET0_DUART0_LSB
REG_WRITE_MASK(G_PMU_PERICLKSET0,
1 << G_PMU_PERICLKSET0_DUART0_LSB, enable,
G_PMU_PERICLKSET0_DUART0_LSB);
#endif
#ifdef G_PMU_PERICLKSET1_DUART0_LSB
REG_WRITE_MASK(G_PMU_PERICLKSET1,
1 << G_PMU_PERICLKSET1_DUART0_LSB, enable,
G_PMU_PERICLKSET0_DUART1_LSB);
#endif
}

50
chip/g/config_chip.h Normal file
View File

@@ -0,0 +1,50 @@
/* Copyright (c) 2014 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.
*/
#ifndef __CROS_EC_CONFIG_CHIP_H
#define __CROS_EC_CONFIG_CHIP_H
#include "core/cortex-m/config_core.h"
/* Number of IRQ vectors on the NVIC */
#define CONFIG_IRQ_COUNT 93
/* Describe the RAM layout */
#define CONFIG_RAM_BASE 0x10000
#define CONFIG_RAM_SIZE 0x8000
/* Describe the flash layout */
#define CONFIG_FLASH_BASE 0x40000
#define CONFIG_FLASH_PHYSICAL_SIZE (512 * 1024)
/* flash chip specifics */
/* TODO(crosbug.com/p/33432): These are probably wrong. Don't use them yet. */
#define CONFIG_FLASH_BANK_SIZE 0x00000800 /* protect bank size */
#define CONFIG_FLASH_ERASE_SIZE 0x00000400 /* erase bank size */
#define CONFIG_FLASH_WRITE_SIZE 0x00000004 /* minimum write size */
/* Size of one firmware image in flash */
#define CONFIG_FW_IMAGE_SIZE (128 * 1024)
/* Compute the rest of the flash params from these */
#include "config_std_flash.h"
/* Interval between HOOK_TICK notifications */
#define HOOK_TICK_INTERVAL_MS 500
#define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC)
/* System stack size */
#define CONFIG_STACK_SIZE 1024
/* Idle task stack size */
#define IDLE_TASK_STACK_SIZE 256
/* Default task stack size */
#define TASK_STACK_SIZE 488
/* Larger task stack size, for hook task */
#define LARGER_TASK_STACK_SIZE 640
/* Maximum number of deferrable functions */
#define DEFERRABLE_MAX_COUNT 8
#endif /* __CROS_EC_CONFIG_CHIP_H */

42
chip/g/config_std_flash.h Normal file
View File

@@ -0,0 +1,42 @@
/* Copyright (c) 2014 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.
*/
#ifndef __CROS_EC_CONFIG_STD_FLASH_H
#define __CROS_EC_CONFIG_STD_FLASH_H
/* RO firmware must start at beginning of flash */
#define CONFIG_FW_RO_OFF 0
/*
* The EC uses the one bank of flash to emulate a SPI-like write protect
* register with persistent state.
*/
#define CONFIG_FW_PSTATE_SIZE CONFIG_FLASH_BANK_SIZE
#ifdef CONFIG_PSTATE_AT_END
/* PSTATE is at end of flash */
#define CONFIG_FW_RO_SIZE CONFIG_FW_IMAGE_SIZE
#define CONFIG_FW_PSTATE_OFF (CONFIG_FLASH_PHYSICAL_SIZE \
- CONFIG_FW_PSTATE_SIZE)
/* Don't claim PSTATE is part of flash */
#define CONFIG_FLASH_SIZE CONFIG_FW_PSTATE_OFF
#else
/* PSTATE immediately follows RO, in the first half of flash */
#define CONFIG_FW_RO_SIZE (CONFIG_FW_IMAGE_SIZE \
- CONFIG_FW_PSTATE_SIZE)
#define CONFIG_FW_PSTATE_OFF CONFIG_FW_RO_SIZE
#define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE
#endif
/* Either way, RW firmware is one firmware image offset from the start */
#define CONFIG_FW_RW_OFF CONFIG_FW_IMAGE_SIZE
#define CONFIG_FW_RW_SIZE CONFIG_FW_IMAGE_SIZE
/* TODO(crosbug.com/p/23796): why 2 sets of configs with the same numbers? */
#define CONFIG_FW_WP_RO_OFF CONFIG_FW_RO_OFF
#define CONFIG_FW_WP_RO_SIZE CONFIG_FW_RO_SIZE
#endif /* __CROS_EC_CONFIG_STD_FLASH_H */

28
chip/g/gpio.c Normal file
View File

@@ -0,0 +1,28 @@
/* Copyright (c) 2014 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 "common.h"
#include "gpio.h"
#include "hooks.h"
/* TODO(crosbug.com/p/33432): We don't have any GPIOs defined yet! */
test_mockable int gpio_get_level(enum gpio_signal signal)
{
return 0;
}
void gpio_set_level(enum gpio_signal signal, int value)
{
}
void gpio_pre_init(void)
{
}
static void gpio_init(void)
{
}
DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT);

24
chip/g/hwtimer.c Normal file
View File

@@ -0,0 +1,24 @@
/* Copyright (c) 2014 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 "common.h"
#include "hwtimer.h"
/* TODO(crosbug.com/p/33432): Implement these functions */
uint32_t __hw_clock_event_get(void)
{
return 0;
}
uint32_t __hw_clock_source_read(void)
{
return 0;
}
int __hw_clock_source_init(uint32_t start_t)
{
return 0;
}

9
chip/g/jtag.c Normal file
View File

@@ -0,0 +1,9 @@
/* Copyright (c) 2014 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.
*/
void jtag_pre_init(void)
{
/* I don't think we need this to do anything */
}

219
chip/g/registers.h Normal file
View File

@@ -0,0 +1,219 @@
/* Copyright (c) 2014 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.
*/
#ifndef __CROS_EC_REGISTERS_H
#define __CROS_EC_REGISTERS_H
#include "common.h"
/* Replace masked bits with val << lsb */
#define REG_WRITE_MASK(reg, mask, val, lsb) \
reg = ((reg & ~mask) | ((val << lsb) & mask))
/* Revision */
#define G_REVISION_STR "A1"
#define G_PINMUX_BASE_ADDR 0x40060000
#define G_PINMUX_DIOA0_SEL REG32(G_PINMUX_BASE_ADDR + 0x0028)
#define G_PINMUX_DIOA0_CTL REG32(G_PINMUX_BASE_ADDR + 0x002c)
#define G_PINMUX_DIOA1_CTL REG32(G_PINMUX_BASE_ADDR + 0x0034)
#define G_PINMUX_UART0_RX_SEL REG32(G_PINMUX_BASE_ADDR + 0x02a8)
#define G_PINMUX_DIOA0_CTL_IE_LSB 0x2
#define G_PINMUX_DIOA0_CTL_IE_MASK 0x4
#define G_PINMUX_DIOA1_CTL_IE_LSB 0x2
#define G_PINMUX_DIOA1_CTL_IE_MASK 0x4
#define G_PINMUX_DIOA1_SEL 0x7
#define G_PINMUX_UART0_TX_SEL 0x40
#define G_PMU_BASE_ADDR 0x40000000
#define G_PMU_CLRDIS REG32(G_PMU_BASE_ADDR + 0x0018)
#define G_PMU_OSC_HOLD_SET REG32(G_PMU_BASE_ADDR + 0x0080)
#define G_PMU_OSC_HOLD_CLR REG32(G_PMU_BASE_ADDR + 0x0084)
#define G_PMU_OSC_SELECT REG32(G_PMU_BASE_ADDR + 0x0088)
#define G_PMU_OSC_SELECT_STAT REG32(G_PMU_BASE_ADDR + 0x008c)
#define G_PMU_OSC_CTRL REG32(G_PMU_BASE_ADDR + 0x0090)
#define G_PMU_PERICLKSET0 REG32(G_PMU_BASE_ADDR + 0x009c)
#define G_PMU_FUSE_RD_RC_OSC_26MHZ REG32(G_PMU_BASE_ADDR + 0x011c)
#define G_PMU_FUSE_RD_XTL_OSC_26MHZ REG32(G_PMU_BASE_ADDR + 0x0124)
#define G_PMU_FUSE_RD_RC_OSC_26MHZ_EN_MASK 0x10000000
#define G_PMU_FUSE_RD_RC_OSC_26MHZ_TRIM_LSB 0x0
#define G_PMU_FUSE_RD_RC_OSC_26MHZ_TRIM_MASK 0xfffffff
#define G_PMU_FUSE_RD_XTL_OSC_26MHZ_EN_MASK 0x10
#define G_PMU_FUSE_RD_XTL_OSC_26MHZ_TRIM_LSB 0x0
#define G_PMU_FUSE_RD_XTL_OSC_26MHZ_TRIM_MASK 0xf
#define G_PMU_OSC_CTRL_RC_TRIM_READYB_LSB 0x1
#define G_PMU_OSC_CTRL_RC_TRIM_READYB_MASK 0x2
#define G_PMU_OSC_CTRL_XTL_READYB_LSB 0x0
#define G_PMU_OSC_CTRL_XTL_READYB_MASK 0x1
#define G_PMU_OSC_SELECT_RC 0x3
#define G_PMU_OSC_SELECT_RC_TRIM 0x2
#define G_PMU_OSC_SELECT_XTL 0x0
#define G_PMU_PERICLKSET0_DXO0_LSB 0x18
#define G_PMU_PERICLKSET0_DUART0_LSB 0x14
#define G_PMU_SETDIS_RC_TRIM_LSB 0xf
#define G_PMU_SETDIS_XTL_LSB 0xe
/* More than one UART */
#define G_UART0_BASE_ADDR 0x40540000
#define G_UART1_BASE_ADDR 0x40550000
#define G_UART2_BASE_ADDR 0x40560000
#define G_UART_BASE_ADDR_SEP 0x00010000
static inline int g_uart_addr(int ch, int offset)
{
return offset + G_UART0_BASE_ADDR + G_UART_BASE_ADDR_SEP * ch;
}
#define G_UARTREG(ch, offset) REG32(g_uart_addr(ch, offset))
#define G_UART_RDATA(ch) G_UARTREG(ch, 0x0000)
#define G_UART_WDATA(ch) G_UARTREG(ch, 0x0004)
#define G_UART_NCO(ch) G_UARTREG(ch, 0x0008)
#define G_UART_CTRL(ch) G_UARTREG(ch, 0x000c)
#define G_UART_ICTRL(ch) G_UARTREG(ch, 0x0010)
#define G_UART_STATE(ch) G_UARTREG(ch, 0x0014)
#define G_UART_ISTATECLR(ch) G_UARTREG(ch, 0x0020)
#define G_UART_FIFO(ch) G_UARTREG(ch, 0x0024)
#define G_UART_RFIFO(ch) G_UARTREG(ch, 0x0028)
#define G_XO0_BASE_ADDR 0x40420000
#define G_XO_OSC_RC_CAL_RSTB REG32(G_XO0_BASE_ADDR + 0x0014)
#define G_XO_OSC_RC_CAL_LOAD REG32(G_XO0_BASE_ADDR + 0x0018)
#define G_XO_OSC_RC_CAL_START REG32(G_XO0_BASE_ADDR + 0x001c)
#define G_XO_OSC_RC_CAL_DONE REG32(G_XO0_BASE_ADDR + 0x0020)
#define G_XO_OSC_RC_CAL_COUNT REG32(G_XO0_BASE_ADDR + 0x0024)
#define G_XO_OSC_RC REG32(G_XO0_BASE_ADDR + 0x0028)
#define G_XO_OSC_RC_STATUS REG32(G_XO0_BASE_ADDR + 0x002c)
#define G_XO_OSC_XTL_TRIM REG32(G_XO0_BASE_ADDR + 0x0048)
#define G_XO_OSC_XTL_TRIM_STAT REG32(G_XO0_BASE_ADDR + 0x004c)
#define G_XO_OSC_XTL_FSM_EN REG32(G_XO0_BASE_ADDR + 0x0050)
#define G_XO_OSC_XTL_FSM REG32(G_XO0_BASE_ADDR + 0x0054)
#define G_XO_OSC_XTL_FSM_CFG REG32(G_XO0_BASE_ADDR + 0x0058)
#define G_XO_OSC_SETHOLD REG32(G_XO0_BASE_ADDR + 0x005c)
#define G_XO_OSC_CLRHOLD REG32(G_XO0_BASE_ADDR + 0x0060)
#define G_XO_OSC_CLRHOLD_RC_TRIM_LSB 0x0
#define G_XO_OSC_CLRHOLD_RC_TRIM_MASK 0x1
#define G_XO_OSC_CLRHOLD_XTL_LSB 0x1
#define G_XO_OSC_RC_EN_LSB 0x1c
#define G_XO_OSC_RC_STATUS_EN_MASK 0x10000000
#define G_XO_OSC_RC_STATUS_TRIM_LSB 0x0
#define G_XO_OSC_RC_STATUS_TRIM_MASK 0xfffffff
#define G_XO_OSC_RC_TRIM_LSB 0x0
#define G_XO_OSC_RC_TRIM_MASK 0xfffffff
#define G_XO_OSC_SETHOLD_RC_TRIM_LSB 0x0
#define G_XO_OSC_SETHOLD_RC_TRIM_MASK 0x1
#define G_XO_OSC_SETHOLD_XTL_LSB 0x1
#define G_XO_OSC_XTL_FSM_CFG_TRIM_MAX_LSB 0x0
#define G_XO_OSC_XTL_FSM_CFG_TRIM_MAX_MASK 0xf
#define G_XO_OSC_XTL_FSM_DONE_MASK 0x1
#define G_XO_OSC_XTL_FSM_EN_KEY 0x60221413
#define G_XO_OSC_XTL_FSM_STATUS_LSB 0x5
#define G_XO_OSC_XTL_FSM_STATUS_MASK 0x20
#define G_XO_OSC_XTL_FSM_TRIM_LSB 0x1
#define G_XO_OSC_XTL_FSM_TRIM_MASK 0x1e
#define G_XO_OSC_XTL_TRIM_CODE_LSB 0x0
#define G_XO_OSC_XTL_TRIM_EN_LSB 0x4
#define G_XO_OSC_XTL_TRIM_STAT_EN_MASK 0x10
/* Interrupts */
#define G_IRQNUM_CAMO0_BREACH_INT 0
#define G_IRQNUM_FLASH0_EDONEINT 1
#define G_IRQNUM_FLASH0_PDONEINT 2
#define G_IRQNUM_GPIO0_GPIOCOMBINT 3
#define G_IRQNUM_GPIO0_GPIO0INT 4
#define G_IRQNUM_GPIO0_GPIO1INT 5
#define G_IRQNUM_GPIO0_GPIO2INT 6
#define G_IRQNUM_GPIO0_GPIO3INT 7
#define G_IRQNUM_GPIO0_GPIO4INT 8
#define G_IRQNUM_GPIO0_GPIO5INT 9
#define G_IRQNUM_GPIO0_GPIO6INT 10
#define G_IRQNUM_GPIO0_GPIO7INT 11
#define G_IRQNUM_GPIO0_GPIO8INT 12
#define G_IRQNUM_GPIO0_GPIO9INT 13
#define G_IRQNUM_GPIO0_GPIO10INT 14
#define G_IRQNUM_GPIO0_GPIO11INT 15
#define G_IRQNUM_GPIO0_GPIO12INT 16
#define G_IRQNUM_GPIO0_GPIO13INT 17
#define G_IRQNUM_GPIO0_GPIO14INT 18
#define G_IRQNUM_GPIO0_GPIO15INT 19
#define G_IRQNUM_GPIO1_GPIOCOMBINT 20
#define G_IRQNUM_GPIO1_GPIO0INT 21
#define G_IRQNUM_GPIO1_GPIO1INT 22
#define G_IRQNUM_GPIO1_GPIO2INT 23
#define G_IRQNUM_GPIO1_GPIO3INT 24
#define G_IRQNUM_GPIO1_GPIO4INT 25
#define G_IRQNUM_GPIO1_GPIO5INT 26
#define G_IRQNUM_GPIO1_GPIO6INT 27
#define G_IRQNUM_GPIO1_GPIO7INT 28
#define G_IRQNUM_GPIO1_GPIO8INT 29
#define G_IRQNUM_GPIO1_GPIO9INT 30
#define G_IRQNUM_GPIO1_GPIO10INT 31
#define G_IRQNUM_GPIO1_GPIO11INT 32
#define G_IRQNUM_GPIO1_GPIO12INT 33
#define G_IRQNUM_GPIO1_GPIO13INT 34
#define G_IRQNUM_GPIO1_GPIO14INT 35
#define G_IRQNUM_GPIO1_GPIO15INT 36
#define G_IRQNUM_I2C0_I2CINT 37
#define G_IRQNUM_I2C1_I2CINT 38
#define G_IRQNUM_PMU_PMUINT 39
#define G_IRQNUM_SHA0_DSHA_INT 40
#define G_IRQNUM_SPI0_SPITXINT 41
#define G_IRQNUM_SPS0_CS_ASSERT_INTR 42
#define G_IRQNUM_SPS0_CS_DEASSERT_INTR 43
#define G_IRQNUM_SPS0_REGION0_BUF_LVL 44
#define G_IRQNUM_SPS0_REGION1_BUF_LVL 45
#define G_IRQNUM_SPS0_REGION2_BUF_LVL 46
#define G_IRQNUM_SPS0_REGION3_BUF_LVL 47
#define G_IRQNUM_SPS0_ROM_CMD_END 48
#define G_IRQNUM_SPS0_ROM_CMD_START 49
#define G_IRQNUM_SPS0_RXFIFO_LVL_INTR 50
#define G_IRQNUM_SPS0_RXFIFO_OVERFLOW_INTR 51
#define G_IRQNUM_SPS0_SPSCTRLINT0 52
#define G_IRQNUM_SPS0_SPSCTRLINT1 53
#define G_IRQNUM_SPS0_SPSCTRLINT2 54
#define G_IRQNUM_SPS0_SPSCTRLINT3 55
#define G_IRQNUM_SPS0_SPSCTRLINT4 56
#define G_IRQNUM_SPS0_SPSCTRLINT5 57
#define G_IRQNUM_SPS0_SPSCTRLINT6 58
#define G_IRQNUM_SPS0_SPSCTRLINT7 59
#define G_IRQNUM_SPS0_TXFIFO_EMPTY_INTR 60
#define G_IRQNUM_SPS0_TXFIFO_FULL_INTR 61
#define G_IRQNUM_SPS0_TXFIFO_LVL_INTR 62
#define G_IRQNUM_TIMEHS0_TIMINTC 63
#define G_IRQNUM_TIMEHS0_TIMINT1 64
#define G_IRQNUM_TIMEHS0_TIMINT2 65
#define G_IRQNUM_TIMEHS1_TIMINTC 66
#define G_IRQNUM_TIMEHS1_TIMINT1 67
#define G_IRQNUM_TIMEHS1_TIMINT2 68
#define G_IRQNUM_TIMELS0_TIMINT0 69
#define G_IRQNUM_TIMELS0_TIMINT1 70
#define G_IRQNUM_UART0_RXBINT 71
#define G_IRQNUM_UART0_RXFINT 72
#define G_IRQNUM_UART0_RXINT 73
#define G_IRQNUM_UART0_RXOVINT 74
#define G_IRQNUM_UART0_RXTOINT 75
#define G_IRQNUM_UART0_TXINT 76
#define G_IRQNUM_UART0_TXOVINT 77
#define G_IRQNUM_UART1_RXBINT 78
#define G_IRQNUM_UART1_RXFINT 79
#define G_IRQNUM_UART1_RXINT 80
#define G_IRQNUM_UART1_RXOVINT 81
#define G_IRQNUM_UART1_RXTOINT 82
#define G_IRQNUM_UART1_TXINT 83
#define G_IRQNUM_UART1_TXOVINT 84
#define G_IRQNUM_UART2_RXBINT 85
#define G_IRQNUM_UART2_RXFINT 86
#define G_IRQNUM_UART2_RXINT 87
#define G_IRQNUM_UART2_RXOVINT 88
#define G_IRQNUM_UART2_RXTOINT 89
#define G_IRQNUM_UART2_TXINT 90
#define G_IRQNUM_UART2_TXOVINT 91
#define G_IRQNUM_WATCHDOG0_WDOGINT 92
#endif /* __CROS_EC_REGISTERS_H */

45
chip/g/system.c Normal file
View File

@@ -0,0 +1,45 @@
/* Copyright (c) 2014 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 "system.h"
#include "registers.h"
void system_pre_init(void)
{
}
/* TODO(crosbug.com/p/33432): How do we force a reset? */
void system_reset(int flags)
{
}
const char *system_get_chip_vendor(void)
{
return "g";
}
const char *system_get_chip_name(void)
{
return "cr50";
}
const char *system_get_chip_revision(void)
{
return G_REVISION_STR;
}
/* TODO(crosbug.com/p/33432): Where can we store stuff persistently? */
int system_get_vbnvcontext(uint8_t *block)
{
return 0;
}
int system_set_vbnvcontext(const uint8_t *block)
{
return 0;
}

168
chip/g/uart.c Normal file
View File

@@ -0,0 +1,168 @@
/* Copyright (c) 2014 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 "clock.h"
#include "common.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "uart.h"
#include "util.h"
static int done_uart_init_yet;
int uart_init_done(void)
{
return done_uart_init_yet;
}
void uart_tx_start(void)
{
/* If interrupt is already enabled, nothing to do */
if (G_UART_ICTRL(0) & 0x01)
return;
/* Do not allow deep sleep while transmit in progress */
disable_sleep(SLEEP_MASK_UART);
/*
* Re-enable the transmit interrupt, then forcibly trigger the
* interrupt. This works around a hardware problem with the
* UART where the FIFO only triggers the interrupt when its
* threshold is _crossed_, not just met.
*/
/* TODO(crosbug.com/p/33432): Do we need this hack here? Find out. */
REG_WRITE_MASK(G_UART_ICTRL(0), 0x01, 0x01, 0);
task_trigger_irq(G_IRQNUM_UART0_TXINT);
}
void uart_tx_stop(void)
{
/* Disable the TX interrupt */
REG_WRITE_MASK(G_UART_ICTRL(0), 0x01, 0x00, 0);
/* Re-allow deep sleep */
enable_sleep(SLEEP_MASK_UART);
}
int uart_tx_in_progress(void)
{
/* Transmit is in progress if the TX idle bit is not set */
return !(G_UART_STATE(0) & 0x20);
}
void uart_tx_flush(void)
{
/* Wait until TX FIFO is idle. */
while (uart_tx_in_progress())
;
}
int uart_tx_ready(void)
{
/* True if the TX buffer is not completely full */
return !(G_UART_STATE(0) & 0x01);
}
int uart_rx_available(void)
{
/* True if the RX buffer is not completely empty. */
/* TODO(crosbug.com/p/33432): Ask Scott for a single bit for this. */
return G_UART_RFIFO(0) & 0x0fc0;
}
void uart_write_char(char c)
{
/* Wait for space in transmit FIFO. */
while (!uart_tx_ready())
;
G_UART_WDATA(0) = c;
}
int uart_read_char(void)
{
return G_UART_RDATA(0);
}
void uart_disable_interrupt(void)
{
task_disable_irq(G_IRQNUM_UART0_TXINT);
task_disable_irq(G_IRQNUM_UART0_RXINT);
}
void uart_enable_interrupt(void)
{
task_enable_irq(G_IRQNUM_UART0_TXINT);
task_enable_irq(G_IRQNUM_UART0_RXINT);
}
/**
* Interrupt handlers for UART0
*/
void uart_ec_tx_interrupt(void)
{
/* Clear transmit interrupt status */
G_UART_ISTATECLR(0) = 0x01;
/* Fill output FIFO */
uart_process_output();
}
DECLARE_IRQ(G_IRQNUM_UART0_TXINT, uart_ec_tx_interrupt, 1);
void uart_ec_rx_interrupt(void)
{
/* Clear receive interrupt status */
G_UART_ISTATECLR(0) = 0x02;
/* Read input FIFO until empty */
uart_process_input();
}
DECLARE_IRQ(G_IRQNUM_UART0_RXINT, uart_ec_rx_interrupt, 1);
/* Constants for setting baud rate */
#define PCLK_FREQ 26000000
#define DEFAULT_UART_FREQ 1000000
#define UART_NCO_WIDTH 16
void uart_init(void)
{
long long setting = (16 * (1 << UART_NCO_WIDTH) *
(long long)CONFIG_UART_BAUD_RATE / PCLK_FREQ);
/* turn on uart clock */
clock_enable_module(MODULE_UART, 1);
/* set up pinmux */
G_PINMUX_DIOA0_SEL = G_PINMUX_UART0_TX_SEL;
G_PINMUX_UART0_RX_SEL = G_PINMUX_DIOA1_SEL;
/* IE must be set to 1 to work as a digital pad (for any direction) */
/* turn on input driver (IE field) */
REG_WRITE_MASK(G_PINMUX_DIOA0_CTL, G_PINMUX_DIOA0_CTL_IE_MASK,
1, G_PINMUX_DIOA0_CTL_IE_LSB);
/* turn on input driver (IE field) */
REG_WRITE_MASK(G_PINMUX_DIOA1_CTL, G_PINMUX_DIOA1_CTL_IE_MASK,
1, G_PINMUX_DIOA1_CTL_IE_LSB);
/* set frequency */
G_UART_NCO(0) = setting;
/* Interrupt when RX fifo has anything, when TX fifo <= half empty */
/* Also reset (clear) both FIFOs */
G_UART_FIFO(0) = 0x63;
/* TX enable, RX enable, HW flow control disabled, no loopback */
G_UART_CTRL(0) = 0x03;
/* enable RX interrupts in block */
/* Note: doesn't do anything unless turned on in NVIC */
G_UART_ICTRL(0) = 0x02;
/* Enable interrupts for UART0 only */
uart_enable_interrupt();
done_uart_init_yet = 1;
}