summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap/am33xx_bbu_spi_mlo.c
blob: 7d2ef1f0f2257d31566a493c837275da275c45bc (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
/*
 * am33xx_bbu_spi_mlo.c - am35xx and am33xx specific MLO
 *	update handler for SPI NOR flash
 *
 * Copyright (c) 2013 Sharavn kumar <shravan.k@phytec.in>, Phytec
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <common.h>
#include <malloc.h>
#include <bbu.h>
#include <fs.h>
#include <fcntl.h>
#include <linux/stat.h>
#include <mach/bbu.h>

/*
 * AM35xx, AM33xx chips use big endian MLO for SPI NOR flash
 * This handler converting MLO to big endian and write to SPI NOR
 */
static int spi_nor_mlo_handler(struct bbu_handler *handler,
					struct bbu_data *data)
{
	int dstfd = 0;
	int ret = 0;
	uint32_t readbuf;
	int size = data->len;
	const void *image = data->image;
	const uint32_t *header;
	int swap = 0;
	struct stat s;

	header = data->image;

	if (header[5] == 0x43485345 || header[10] == 0x62617265) {
		swap = 0;
	} else if (header[5] == 0x45534843 || header[10] == 0x65726142) {
		swap = 1;
	} else {
		if (!bbu_force(data, "Not a MLO image"))
			return -EINVAL;
	}

	ret = stat(data->devicefile, &s);
	if (ret) {
		printf("could not open %s: %s", data->devicefile, errno_str());
		return ret;
	}

	if (size > s.st_size) {
		printf("Image too big, need %d, have %lld\n", size, s.st_size);
		return -ENOSPC;
	}

	ret = bbu_confirm(data);
	if (ret != 0)
		return ret;

	dstfd = open(data->devicefile, O_WRONLY);
	if (dstfd < 0) {
		printf("could not open %s: %s", data->devicefile, errno_str());
		ret = dstfd;
		goto out;
	}

	ret = erase(dstfd, ERASE_SIZE_ALL, 0);
	if (ret < 0) {
		printf("could not erase %s: %s", data->devicefile, errno_str());
		goto out1;
	}

	for (; size >= 0; size -= 4) {
		memcpy((char *)&readbuf, image, 4);

		if (swap)
			readbuf = cpu_to_be32(readbuf);
		ret = write(dstfd, &readbuf, 4);
		if (ret < 0) {
			perror("write");
			goto out1;
		}

		image = image + 4;
	}

	ret = 0;
out1:
	close(dstfd);
out:
	return ret;
}

/*
 * Register a am33xx MLO update handler for SPI NOR
 */
int am33xx_bbu_spi_nor_mlo_register_handler(const char *name, char *devicefile)
{
	struct bbu_handler *handler;
	int ret;

	handler = xzalloc(sizeof(*handler));
	handler->devicefile = devicefile;
	handler->name = name;
	handler->handler = spi_nor_mlo_handler;

	ret = bbu_register_handler(handler);

	if (ret)
		free(handler);

	return ret;
}