]>
Commit | Line | Data |
---|---|---|
6f12ebf6 SW |
1 | /* |
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <malloc.h> | |
9 | #include <errno.h> | |
10 | #include <div64.h> | |
11 | #include <dfu.h> | |
843c9e87 | 12 | #include <spi.h> |
6f12ebf6 SW |
13 | #include <spi_flash.h> |
14 | ||
15970d87 | 15 | static int dfu_get_medium_size_sf(struct dfu_entity *dfu, u64 *size) |
6f12ebf6 | 16 | { |
4de51201 PD |
17 | *size = dfu->data.sf.size; |
18 | ||
19 | return 0; | |
6f12ebf6 SW |
20 | } |
21 | ||
22 | static int dfu_read_medium_sf(struct dfu_entity *dfu, u64 offset, void *buf, | |
23 | long *len) | |
24 | { | |
e5f00f01 PE |
25 | return spi_flash_read(dfu->data.sf.dev, dfu->data.sf.start + offset, |
26 | *len, buf); | |
6f12ebf6 SW |
27 | } |
28 | ||
2727f3bf FE |
29 | static u64 find_sector(struct dfu_entity *dfu, u64 start, u64 offset) |
30 | { | |
31 | return (lldiv((start + offset), dfu->data.sf.dev->sector_size)) * | |
32 | dfu->data.sf.dev->sector_size; | |
33 | } | |
34 | ||
6f12ebf6 SW |
35 | static int dfu_write_medium_sf(struct dfu_entity *dfu, |
36 | u64 offset, void *buf, long *len) | |
37 | { | |
38 | int ret; | |
39 | ||
2727f3bf FE |
40 | ret = spi_flash_erase(dfu->data.sf.dev, |
41 | find_sector(dfu, dfu->data.sf.start, offset), | |
f4c92582 | 42 | dfu->data.sf.dev->sector_size); |
6f12ebf6 SW |
43 | if (ret) |
44 | return ret; | |
45 | ||
2727f3bf FE |
46 | ret = spi_flash_write(dfu->data.sf.dev, dfu->data.sf.start + offset, |
47 | *len, buf); | |
6f12ebf6 SW |
48 | if (ret) |
49 | return ret; | |
50 | ||
51 | return 0; | |
52 | } | |
53 | ||
54 | static int dfu_flush_medium_sf(struct dfu_entity *dfu) | |
55 | { | |
56 | return 0; | |
57 | } | |
58 | ||
59 | static unsigned int dfu_polltimeout_sf(struct dfu_entity *dfu) | |
60 | { | |
61 | return DFU_DEFAULT_POLL_TIMEOUT; | |
62 | } | |
63 | ||
64 | static void dfu_free_entity_sf(struct dfu_entity *dfu) | |
65 | { | |
66 | spi_flash_free(dfu->data.sf.dev); | |
67 | } | |
68 | ||
69 | static struct spi_flash *parse_dev(char *devstr) | |
70 | { | |
71 | unsigned int bus; | |
72 | unsigned int cs; | |
73 | unsigned int speed = CONFIG_SF_DEFAULT_SPEED; | |
74 | unsigned int mode = CONFIG_SF_DEFAULT_MODE; | |
75 | char *s, *endp; | |
76 | struct spi_flash *dev; | |
77 | ||
78 | s = strsep(&devstr, ":"); | |
79 | if (!s || !*s || (bus = simple_strtoul(s, &endp, 0), *endp)) { | |
80 | printf("Invalid SPI bus %s\n", s); | |
81 | return NULL; | |
82 | } | |
83 | ||
84 | s = strsep(&devstr, ":"); | |
85 | if (!s || !*s || (cs = simple_strtoul(s, &endp, 0), *endp)) { | |
86 | printf("Invalid SPI chip-select %s\n", s); | |
87 | return NULL; | |
88 | } | |
89 | ||
90 | s = strsep(&devstr, ":"); | |
91 | if (s && *s) { | |
92 | speed = simple_strtoul(s, &endp, 0); | |
93 | if (*endp || !speed) { | |
94 | printf("Invalid SPI speed %s\n", s); | |
95 | return NULL; | |
96 | } | |
97 | } | |
98 | ||
99 | s = strsep(&devstr, ":"); | |
100 | if (s && *s) { | |
101 | mode = simple_strtoul(s, &endp, 0); | |
102 | if (*endp || mode > 3) { | |
103 | printf("Invalid SPI mode %s\n", s); | |
104 | return NULL; | |
105 | } | |
106 | } | |
107 | ||
108 | dev = spi_flash_probe(bus, cs, speed, mode); | |
109 | if (!dev) { | |
110 | printf("Failed to create SPI flash at %d:%d:%d:%d\n", | |
111 | bus, cs, speed, mode); | |
112 | return NULL; | |
113 | } | |
114 | ||
115 | return dev; | |
116 | } | |
117 | ||
118 | int dfu_fill_entity_sf(struct dfu_entity *dfu, char *devstr, char *s) | |
119 | { | |
120 | char *st; | |
30e3ea4c | 121 | char *devstr_bkup = strdup(devstr); |
6f12ebf6 | 122 | |
30e3ea4c V |
123 | dfu->data.sf.dev = parse_dev(devstr_bkup); |
124 | free(devstr_bkup); | |
6f12ebf6 SW |
125 | if (!dfu->data.sf.dev) |
126 | return -ENODEV; | |
127 | ||
128 | dfu->dev_type = DFU_DEV_SF; | |
129 | dfu->max_buf_size = dfu->data.sf.dev->sector_size; | |
130 | ||
131 | st = strsep(&s, " "); | |
132 | if (!strcmp(st, "raw")) { | |
133 | dfu->layout = DFU_RAW_ADDR; | |
134 | dfu->data.sf.start = simple_strtoul(s, &s, 16); | |
135 | s++; | |
136 | dfu->data.sf.size = simple_strtoul(s, &s, 16); | |
137 | } else { | |
138 | printf("%s: Memory layout (%s) not supported!\n", __func__, st); | |
139 | spi_flash_free(dfu->data.sf.dev); | |
140 | return -1; | |
141 | } | |
142 | ||
143 | dfu->get_medium_size = dfu_get_medium_size_sf; | |
144 | dfu->read_medium = dfu_read_medium_sf; | |
145 | dfu->write_medium = dfu_write_medium_sf; | |
146 | dfu->flush_medium = dfu_flush_medium_sf; | |
147 | dfu->poll_timeout = dfu_polltimeout_sf; | |
148 | dfu->free_entity = dfu_free_entity_sf; | |
149 | ||
150 | /* initial state */ | |
151 | dfu->inited = 0; | |
152 | ||
153 | return 0; | |
154 | } |