1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
13 #include <spi_flash.h>
14 #include <jffs2/load_kernel.h>
15 #include <linux/mtd/mtd.h>
17 static int dfu_get_medium_size_sf(struct dfu_entity
*dfu
, u64
*size
)
19 *size
= dfu
->data
.sf
.size
;
24 static int dfu_read_medium_sf(struct dfu_entity
*dfu
, u64 offset
, void *buf
,
27 return spi_flash_read(dfu
->data
.sf
.dev
, dfu
->data
.sf
.start
+ offset
,
31 static u64
find_sector(struct dfu_entity
*dfu
, u64 start
, u64 offset
)
33 return (lldiv((start
+ offset
), dfu
->data
.sf
.dev
->sector_size
)) *
34 dfu
->data
.sf
.dev
->sector_size
;
37 static int dfu_write_medium_sf(struct dfu_entity
*dfu
,
38 u64 offset
, void *buf
, long *len
)
42 ret
= spi_flash_erase(dfu
->data
.sf
.dev
,
43 find_sector(dfu
, dfu
->data
.sf
.start
, offset
),
44 dfu
->data
.sf
.dev
->sector_size
);
48 ret
= spi_flash_write(dfu
->data
.sf
.dev
, dfu
->data
.sf
.start
+ offset
,
56 static int dfu_flush_medium_sf(struct dfu_entity
*dfu
)
60 if (!CONFIG_IS_ENABLED(DFU_SF_PART
) || !dfu
->data
.sf
.ubi
)
63 /* in case of ubi partition, erase rest of the partition */
64 off
= find_sector(dfu
, dfu
->data
.sf
.start
, dfu
->offset
);
65 /* last write ended with unaligned length jump to next */
66 if (off
!= dfu
->data
.sf
.start
+ dfu
->offset
)
67 off
+= dfu
->data
.sf
.dev
->sector_size
;
68 length
= dfu
->data
.sf
.start
+ dfu
->data
.sf
.size
- off
;
70 return spi_flash_erase(dfu
->data
.sf
.dev
, off
, length
);
75 static unsigned int dfu_polltimeout_sf(struct dfu_entity
*dfu
)
78 * Currently, Poll Timeout != 0 is only needed on nand
79 * ubi partition, as sectors which are not used need
82 if (CONFIG_IS_ENABLED(DFU_SF_PART
) && dfu
->data
.sf
.ubi
)
83 return DFU_MANIFEST_POLL_TIMEOUT
;
85 return DFU_DEFAULT_POLL_TIMEOUT
;
88 static void dfu_free_entity_sf(struct dfu_entity
*dfu
)
90 spi_flash_free(dfu
->data
.sf
.dev
);
93 static struct spi_flash
*parse_dev(char *devstr
)
97 unsigned int speed
= CONFIG_SF_DEFAULT_SPEED
;
98 unsigned int mode
= CONFIG_SF_DEFAULT_MODE
;
100 struct spi_flash
*dev
;
102 s
= strsep(&devstr
, ":");
103 if (!s
|| !*s
|| (bus
= simple_strtoul(s
, &endp
, 0), *endp
)) {
104 printf("Invalid SPI bus %s\n", s
);
108 s
= strsep(&devstr
, ":");
109 if (!s
|| !*s
|| (cs
= simple_strtoul(s
, &endp
, 0), *endp
)) {
110 printf("Invalid SPI chip-select %s\n", s
);
114 s
= strsep(&devstr
, ":");
116 speed
= simple_strtoul(s
, &endp
, 0);
117 if (*endp
|| !speed
) {
118 printf("Invalid SPI speed %s\n", s
);
123 s
= strsep(&devstr
, ":");
125 mode
= simple_strtoul(s
, &endp
, 0);
126 if (*endp
|| mode
> 3) {
127 printf("Invalid SPI mode %s\n", s
);
132 dev
= spi_flash_probe(bus
, cs
, speed
, mode
);
134 printf("Failed to create SPI flash at %d:%d:%d:%d\n",
135 bus
, cs
, speed
, mode
);
142 int dfu_fill_entity_sf(struct dfu_entity
*dfu
, char *devstr
, char *s
)
145 char *devstr_bkup
= strdup(devstr
);
147 dfu
->data
.sf
.dev
= parse_dev(devstr_bkup
);
149 if (!dfu
->data
.sf
.dev
)
152 dfu
->dev_type
= DFU_DEV_SF
;
153 dfu
->max_buf_size
= dfu
->data
.sf
.dev
->sector_size
;
155 st
= strsep(&s
, " ");
156 if (!strcmp(st
, "raw")) {
157 dfu
->layout
= DFU_RAW_ADDR
;
158 dfu
->data
.sf
.start
= simple_strtoul(s
, &s
, 16);
160 dfu
->data
.sf
.size
= simple_strtoul(s
, &s
, 16);
161 } else if (CONFIG_IS_ENABLED(DFU_SF_PART
) &&
162 (!strcmp(st
, "part") || !strcmp(st
, "partubi"))) {
164 struct mtd_device
*mtd_dev
;
166 struct part_info
*pi
;
169 dfu
->layout
= DFU_RAW_ADDR
;
171 dev
= simple_strtoul(s
, &s
, 10);
173 part
= simple_strtoul(s
, &s
, 10);
175 sprintf(mtd_id
, "%s%d,%d", "nor", dev
, part
- 1);
176 printf("using id '%s'\n", mtd_id
);
180 ret
= find_dev_and_part(mtd_id
, &mtd_dev
, &part_num
, &pi
);
182 printf("Could not locate '%s'\n", mtd_id
);
185 dfu
->data
.sf
.start
= pi
->offset
;
186 dfu
->data
.sf
.size
= pi
->size
;
187 if (!strcmp(st
, "partubi"))
188 dfu
->data
.sf
.ubi
= 1;
190 printf("%s: Memory layout (%s) not supported!\n", __func__
, st
);
191 spi_flash_free(dfu
->data
.sf
.dev
);
195 dfu
->get_medium_size
= dfu_get_medium_size_sf
;
196 dfu
->read_medium
= dfu_read_medium_sf
;
197 dfu
->write_medium
= dfu_write_medium_sf
;
198 dfu
->flush_medium
= dfu_flush_medium_sf
;
199 dfu
->poll_timeout
= dfu_polltimeout_sf
;
200 dfu
->free_entity
= dfu_free_entity_sf
;