1 // SPDX-License-Identifier: GPL-2.0+
3 * Software partition device (UCLASS_PARTITION)
5 * Copyright (c) 2021 Linaro Limited
6 * Author: AKASHI Takahiro
9 #define LOG_CATEGORY UCLASS_PARTITION
17 #include <dm/device-internal.h>
20 int part_create_block_devices(struct udevice *blk_dev)
23 struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
24 struct disk_partition info;
25 struct disk_part *part_data;
30 if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled())
33 if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
36 /* Add devices for each partition */
37 for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
38 if (part_get_info(desc, part, &info))
40 snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
43 ret = device_bind_driver(blk_dev, "blk_partition",
44 strdup(devname), &dev);
48 part_data = dev_get_uclass_plat(dev);
49 part_data->partnum = part;
50 part_data->gpt_part_info = info;
53 ret = device_probe(dev);
55 debug("Can't probe\n");
62 debug("%s: %d partitions found in %s\n", __func__, count,
68 static ulong part_blk_read(struct udevice *dev, lbaint_t start,
69 lbaint_t blkcnt, void *buffer)
71 struct udevice *parent;
72 struct disk_part *part;
73 const struct blk_ops *ops;
75 parent = dev_get_parent(dev);
76 ops = blk_get_ops(parent);
80 part = dev_get_uclass_plat(dev);
81 if (start >= part->gpt_part_info.size)
84 if ((start + blkcnt) > part->gpt_part_info.size)
85 blkcnt = part->gpt_part_info.size - start;
86 start += part->gpt_part_info.start;
88 return ops->read(parent, start, blkcnt, buffer);
91 static ulong part_blk_write(struct udevice *dev, lbaint_t start,
92 lbaint_t blkcnt, const void *buffer)
94 struct udevice *parent;
95 struct disk_part *part;
96 const struct blk_ops *ops;
98 parent = dev_get_parent(dev);
99 ops = blk_get_ops(parent);
103 part = dev_get_uclass_plat(dev);
104 if (start >= part->gpt_part_info.size)
107 if ((start + blkcnt) > part->gpt_part_info.size)
108 blkcnt = part->gpt_part_info.size - start;
109 start += part->gpt_part_info.start;
111 return ops->write(parent, start, blkcnt, buffer);
114 static ulong part_blk_erase(struct udevice *dev, lbaint_t start,
117 struct udevice *parent;
118 struct disk_part *part;
119 const struct blk_ops *ops;
121 parent = dev_get_parent(dev);
122 ops = blk_get_ops(parent);
126 part = dev_get_uclass_plat(dev);
127 if (start >= part->gpt_part_info.size)
130 if ((start + blkcnt) > part->gpt_part_info.size)
131 blkcnt = part->gpt_part_info.size - start;
132 start += part->gpt_part_info.start;
134 return ops->erase(parent, start, blkcnt);
137 static const struct blk_ops blk_part_ops = {
138 .read = part_blk_read,
139 .write = part_blk_write,
140 .erase = part_blk_erase,
143 U_BOOT_DRIVER(blk_partition) = {
144 .name = "blk_partition",
145 .id = UCLASS_PARTITION,
146 .ops = &blk_part_ops,
152 static struct blk_desc *dev_get_blk(struct udevice *dev)
154 struct blk_desc *desc;
156 switch (device_get_uclass_id(dev)) {
158 * We won't support UCLASS_BLK with dev_* interfaces.
160 case UCLASS_PARTITION:
161 desc = dev_get_uclass_plat(dev_get_parent(dev));
171 unsigned long disk_blk_read(struct udevice *dev, lbaint_t start,
172 lbaint_t blkcnt, void *buffer)
174 struct blk_desc *desc;
175 const struct blk_ops *ops;
176 struct disk_part *part;
177 lbaint_t start_in_disk;
180 desc = dev_get_blk(dev);
184 ops = blk_get_ops(dev);
188 start_in_disk = start;
189 if (device_get_uclass_id(dev) == UCLASS_PARTITION) {
190 part = dev_get_uclass_plat(dev);
191 start_in_disk += part->gpt_part_info.start;
194 if (blkcache_read(desc->uclass_id, desc->devnum, start_in_disk, blkcnt,
195 desc->blksz, buffer))
197 blks_read = ops->read(dev, start, blkcnt, buffer);
198 if (blks_read == blkcnt)
199 blkcache_fill(desc->uclass_id, desc->devnum, start_in_disk,
200 blkcnt, desc->blksz, buffer);
205 unsigned long disk_blk_write(struct udevice *dev, lbaint_t start,
206 lbaint_t blkcnt, const void *buffer)
208 struct blk_desc *desc;
209 const struct blk_ops *ops;
211 desc = dev_get_blk(dev);
215 ops = blk_get_ops(dev);
219 blkcache_invalidate(desc->uclass_id, desc->devnum);
221 return ops->write(dev, start, blkcnt, buffer);
224 unsigned long disk_blk_erase(struct udevice *dev, lbaint_t start,
227 struct blk_desc *desc;
228 const struct blk_ops *ops;
230 desc = dev_get_blk(dev);
234 ops = blk_get_ops(dev);
238 blkcache_invalidate(desc->uclass_id, desc->devnum);
240 return ops->erase(dev, start, blkcnt);
243 UCLASS_DRIVER(partition) = {
244 .id = UCLASS_PARTITION,
245 .per_device_plat_auto = sizeof(struct disk_part),