summaryrefslogtreecommitdiff
path: root/zephyr/shim/chip/npcx/system_external_storage.c
blob: d3b2d2636210bed5d1948ff057fbef8eaa4e99ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/* Copyright 2021 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "clock_chip.h"
#include "common.h"
#include "rom_chip.h"
#include "system.h"
#include "system_chip.h"

#include <zephyr/devicetree.h>
#include <zephyr/drivers/syscon.h>

/* TODO (b:179900857) Make this implementation not npcx specific. */

static const struct device *mdc_dev = DEVICE_DT_GET(DT_NODELABEL(mdc));

/*
 * b/218820985: The FWCTL register reset to 0xFF on multiple reads.
 * Read the register once, and then cache all writes to this register
 *
 * TODO: if this is a chip bug, this should be managed by the syscon driver
 * upstream.
 */
static uint32_t fwctrl_cached = 0xFFFFFFFF;

#ifdef CONFIG_SOC_SERIES_NPCX7
#define NPCX_FWCTRL 0x007
#define NPCX_FWCTRL_RO_REGION 0
#define NPCX_FWCTRL_FW_SLOT 1
#elif defined(CONFIG_SOC_SERIES_NPCX9)
#define NPCX_FWCTRL 0x009
#define NPCX_FWCTRL_RO_REGION 6
#define NPCX_FWCTRL_FW_SLOT 7
#else
#error "Unsupported NPCX SoC series."
#endif

static uint32_t read_fwctrl(void)
{
	/* On first entry, read the value and cache it. */
	if (fwctrl_cached == 0xFFFFFFFF) {
		syscon_read_reg(mdc_dev, NPCX_FWCTRL, &fwctrl_cached);
	}

	return fwctrl_cached;
}

static void write_fwctrl(uint32_t fwctrl)
{
	syscon_write_reg(mdc_dev, NPCX_FWCTRL, fwctrl);
	fwctrl_cached = fwctrl;
}

void system_jump_to_booter(void)
{
	enum API_RETURN_STATUS_T status __attribute__((unused));
	static uint32_t flash_offset;
	static uint32_t flash_used;
	static uint32_t addr_entry;

	/*
	 * Get memory offset and size for RO/RW regions.
	 * Both of them need 16-bytes alignment since GDMA burst mode.
	 */
	switch (system_get_shrspi_image_copy()) {
	case EC_IMAGE_RW:
		flash_offset =
			CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_STORAGE_OFF;
		flash_used = CONFIG_RW_SIZE;
		break;
#ifdef CONFIG_RW_B
	case EC_IMAGE_RW_B:
		flash_offset = CONFIG_EC_WRITABLE_STORAGE_OFF +
			       CONFIG_RW_B_STORAGE_OFF;
		flash_used = CONFIG_RW_SIZE;
		break;
#endif
	case EC_IMAGE_RO:
	default: /* Jump to RO by default */
		flash_offset =
			CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF;
		flash_used = CONFIG_RO_SIZE;
		break;
	}

	/* Make sure the reset vector is inside the destination image */
	addr_entry =
		*(uintptr_t *)(flash_offset + CONFIG_MAPPED_STORAGE_BASE + 4);

	/*
	 * Speed up FW download time by increasing clock freq of EC. It will
	 * restore to default in clock_init() later.
	 */
	clock_turbo();

	/*
	 * npcx9 Rev.1 has the problem for download_from_flash API.
	 * Workwaroud it by executing the system_download_from_flash function
	 * in the suspend RAM like npcx5.
	 * TODO: Removing npcx9 when Rev.2 is available.
	 */
	/* Bypass for GMDA issue of ROM api utilities */
#if defined(CONFIG_SOC_SERIES_NPCX5) || \
	defined(CONFIG_PLATFORM_EC_WORKAROUND_FLASH_DOWNLOAD_API)
	system_download_from_flash(flash_offset, /* The offset of the data in
						    spi flash */
				   CONFIG_PROGRAM_MEMORY_BASE, /* RAM Addr of
								  downloaded
								  data */
				   flash_used, /* Number of bytes to download */
				   addr_entry /* jump to this address after
						 download */
	);
#else
	download_from_flash(flash_offset, /* The offset of the data in spi flash
					   */
			    CONFIG_PROGRAM_MEMORY_BASE, /* RAM Addr of
							   downloaded data */
			    flash_used, /* Number of bytes to download      */
			    SIGN_NO_CHECK, /* Need CRC check or not */
			    addr_entry, /* jump to this address after download
					 */
			    &status /* Status fo download */
	);
#endif
}

uint32_t system_get_lfw_address()
{
	/*
	 * In A3 version, we don't use little FW anymore
	 * We provide the alternative function in ROM
	 */
	uint32_t jump_addr = (uint32_t)system_jump_to_booter;
	return jump_addr;
}

enum ec_image system_get_shrspi_image_copy(void)
{
	uint32_t fwctrl;

	fwctrl = read_fwctrl();

	if (IS_BIT_SET(fwctrl, NPCX_FWCTRL_RO_REGION)) {
		/* RO image */
#ifdef CHIP_HAS_RO_B
		if (!IS_BIT_SET(fwctrl, NPCX_FWCTRL_FW_SLOT))
			return EC_IMAGE_RO_B;
#endif
		return EC_IMAGE_RO;
	} else {
#ifdef CONFIG_RW_B
		/* RW image */
		if (!IS_BIT_SET(fwctrl, NPCX_FWCTRL_FW_SLOT))
			/* Slot A */
			return EC_IMAGE_RW_B;
#endif
		return EC_IMAGE_RW;
	}
}

void system_set_image_copy(enum ec_image copy)
{
	uint32_t fwctrl;

	fwctrl = read_fwctrl();
	switch (copy) {
	case EC_IMAGE_RW:
		CLEAR_BIT(fwctrl, NPCX_FWCTRL_RO_REGION);
		SET_BIT(fwctrl, NPCX_FWCTRL_FW_SLOT);
		break;
#ifdef CONFIG_RW_B
	case EC_IMAGE_RW_B:
		CLEAR_BIT(fwctrl, NPCX_FWCTRL_RO_REGION);
		CLEAR_BIT(fwctrl, NPCX_FWCTRL_FW_SLOT);
		break;
#endif
	default:
		/* Fall through to EC_IMAGE_RO */
	case EC_IMAGE_RO:
		SET_BIT(fwctrl, NPCX_FWCTRL_RO_REGION);
		SET_BIT(fwctrl, NPCX_FWCTRL_FW_SLOT);
		break;
	}

	write_fwctrl(fwctrl);
}