summaryrefslogtreecommitdiff
path: root/chip/g/loader/rom_flash.c
blob: eec0bc4733b4308e09585ab596c8822ad4c9a9ce (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
/* Copyright 2015 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 "debug_printf.h"
#include "setup.h"
#include "rom_flash.h"

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;
}

/* 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;
}

/* 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_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;
}