blob: 617db226a2480e069286ab462a2c85e1c4473829 [file] [log] [blame]
Simon Glasscceee552016-02-29 15:25:55 -07001/*
2 * Copyright (C) 2016 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
9#include <blk.h>
10#include <dm.h>
11#include <dm/device-internal.h>
12#include <dm/lists.h>
13
14int blk_first_device(int if_type, struct udevice **devp)
15{
16 struct blk_desc *desc;
17 int ret;
18
19 ret = uclass_first_device(UCLASS_BLK, devp);
20 if (ret)
21 return ret;
22 if (!*devp)
23 return -ENODEV;
24 do {
25 desc = dev_get_uclass_platdata(*devp);
26 if (desc->if_type == if_type)
27 return 0;
28 ret = uclass_next_device(devp);
29 if (ret)
30 return ret;
31 } while (*devp);
32
33 return -ENODEV;
34}
35
36int blk_next_device(struct udevice **devp)
37{
38 struct blk_desc *desc;
39 int ret, if_type;
40
41 desc = dev_get_uclass_platdata(*devp);
42 if_type = desc->if_type;
43 do {
44 ret = uclass_next_device(devp);
45 if (ret)
46 return ret;
47 if (!*devp)
48 return -ENODEV;
49 desc = dev_get_uclass_platdata(*devp);
50 if (desc->if_type == if_type)
51 return 0;
52 } while (1);
53}
54
55int blk_get_device(int if_type, int devnum, struct udevice **devp)
56{
57 struct uclass *uc;
58 struct udevice *dev;
59 int ret;
60
61 ret = uclass_get(UCLASS_BLK, &uc);
62 if (ret)
63 return ret;
64 uclass_foreach_dev(dev, uc) {
65 struct blk_desc *desc = dev_get_uclass_platdata(dev);
66
67 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
68 if_type, devnum, dev->name, desc->if_type, desc->devnum);
69 if (desc->if_type == if_type && desc->devnum == devnum) {
70 *devp = dev;
71 return device_probe(dev);
72 }
73 }
74
75 return -ENODEV;
76}
77
78unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
79 lbaint_t blkcnt, void *buffer)
80{
81 struct udevice *dev = block_dev->bdev;
82 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -070083 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -070084
85 if (!ops->read)
86 return -ENOSYS;
87
Eric Nelsonfaf4f052016-03-28 10:05:44 -070088 if (blkcache_read(block_dev->if_type, block_dev->devnum,
89 start, blkcnt, block_dev->blksz, buffer))
90 return blkcnt;
91 blks_read = ops->read(dev, start, blkcnt, buffer);
92 if (blks_read == blkcnt)
93 blkcache_fill(block_dev->if_type, block_dev->devnum,
94 start, blkcnt, block_dev->blksz, buffer);
95
96 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -070097}
98
99unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
100 lbaint_t blkcnt, const void *buffer)
101{
102 struct udevice *dev = block_dev->bdev;
103 const struct blk_ops *ops = blk_get_ops(dev);
104
105 if (!ops->write)
106 return -ENOSYS;
107
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700108 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700109 return ops->write(dev, start, blkcnt, buffer);
110}
111
112unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
113 lbaint_t blkcnt)
114{
115 struct udevice *dev = block_dev->bdev;
116 const struct blk_ops *ops = blk_get_ops(dev);
117
118 if (!ops->erase)
119 return -ENOSYS;
120
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700121 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700122 return ops->erase(dev, start, blkcnt);
123}
124
125int blk_prepare_device(struct udevice *dev)
126{
127 struct blk_desc *desc = dev_get_uclass_platdata(dev);
128
129 part_init(desc);
130
131 return 0;
132}
133
134int blk_create_device(struct udevice *parent, const char *drv_name,
135 const char *name, int if_type, int devnum, int blksz,
136 lbaint_t size, struct udevice **devp)
137{
138 struct blk_desc *desc;
139 struct udevice *dev;
140 int ret;
141
142 ret = device_bind_driver(parent, drv_name, name, &dev);
143 if (ret)
144 return ret;
145 desc = dev_get_uclass_platdata(dev);
146 desc->if_type = if_type;
147 desc->blksz = blksz;
148 desc->lba = size / blksz;
149 desc->part_type = PART_TYPE_UNKNOWN;
150 desc->bdev = dev;
151 desc->devnum = devnum;
152 *devp = dev;
153
154 return 0;
155}
156
157int blk_unbind_all(int if_type)
158{
159 struct uclass *uc;
160 struct udevice *dev, *next;
161 int ret;
162
163 ret = uclass_get(UCLASS_BLK, &uc);
164 if (ret)
165 return ret;
166 uclass_foreach_dev_safe(dev, next, uc) {
167 struct blk_desc *desc = dev_get_uclass_platdata(dev);
168
169 if (desc->if_type == if_type) {
170 ret = device_remove(dev);
171 if (ret)
172 return ret;
173 ret = device_unbind(dev);
174 if (ret)
175 return ret;
176 }
177 }
178
179 return 0;
180}
181
182UCLASS_DRIVER(blk) = {
183 .id = UCLASS_BLK,
184 .name = "blk",
185 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
186};