blob: 49df2a6f8965695bffe052d64f09f81dbedd4457 [file] [log] [blame]
Simon Glass09d71aa2016-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);
83
84 if (!ops->read)
85 return -ENOSYS;
86
87 return ops->read(dev, start, blkcnt, buffer);
88}
89
90unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
91 lbaint_t blkcnt, const void *buffer)
92{
93 struct udevice *dev = block_dev->bdev;
94 const struct blk_ops *ops = blk_get_ops(dev);
95
96 if (!ops->write)
97 return -ENOSYS;
98
99 return ops->write(dev, start, blkcnt, buffer);
100}
101
102unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
103 lbaint_t blkcnt)
104{
105 struct udevice *dev = block_dev->bdev;
106 const struct blk_ops *ops = blk_get_ops(dev);
107
108 if (!ops->erase)
109 return -ENOSYS;
110
111 return ops->erase(dev, start, blkcnt);
112}
113
114int blk_prepare_device(struct udevice *dev)
115{
116 struct blk_desc *desc = dev_get_uclass_platdata(dev);
117
118 part_init(desc);
119
120 return 0;
121}
122
123int blk_create_device(struct udevice *parent, const char *drv_name,
124 const char *name, int if_type, int devnum, int blksz,
125 lbaint_t size, struct udevice **devp)
126{
127 struct blk_desc *desc;
128 struct udevice *dev;
129 int ret;
130
131 ret = device_bind_driver(parent, drv_name, name, &dev);
132 if (ret)
133 return ret;
134 desc = dev_get_uclass_platdata(dev);
135 desc->if_type = if_type;
136 desc->blksz = blksz;
137 desc->lba = size / blksz;
138 desc->part_type = PART_TYPE_UNKNOWN;
139 desc->bdev = dev;
140 desc->devnum = devnum;
141 *devp = dev;
142
143 return 0;
144}
145
146int blk_unbind_all(int if_type)
147{
148 struct uclass *uc;
149 struct udevice *dev, *next;
150 int ret;
151
152 ret = uclass_get(UCLASS_BLK, &uc);
153 if (ret)
154 return ret;
155 uclass_foreach_dev_safe(dev, next, uc) {
156 struct blk_desc *desc = dev_get_uclass_platdata(dev);
157
158 if (desc->if_type == if_type) {
159 ret = device_remove(dev);
160 if (ret)
161 return ret;
162 ret = device_unbind(dev);
163 if (ret)
164 return ret;
165 }
166 }
167
168 return 0;
169}
170
171UCLASS_DRIVER(blk) = {
172 .id = UCLASS_BLK,
173 .name = "blk",
174 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
175};