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