1 /*
2 * Copyright (C) (C) Copyright 2016-2017 Rockchip Electronics Co., Ltd
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7 #include <common.h>
8 #include <asm/arch/vendor.h>
9 #include <dm.h>
10 #include <dm/device-internal.h>
11 #include <dm/lists.h>
12 #include <dm/root.h>
13 #include "rknand.h"
14
rknand_get_blk_desc(struct rknand_dev * ndev)15 struct blk_desc *rknand_get_blk_desc(struct rknand_dev *ndev)
16 {
17 struct blk_desc *desc;
18 struct udevice *dev;
19
20 device_find_first_child(ndev->dev, &dev);
21 if (!dev)
22 return NULL;
23 desc = dev_get_uclass_platdata(dev);
24
25 return desc;
26 }
27
rknand_bread(struct udevice * udev,lbaint_t start,lbaint_t blkcnt,void * dst)28 ulong rknand_bread(struct udevice *udev, lbaint_t start,
29 lbaint_t blkcnt, void *dst)
30 {
31 struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
32 struct rknand_dev *ndev = dev_get_priv(udev->parent);
33 int err;
34
35 if (blkcnt == 0)
36 return 0;
37
38 if ((start + blkcnt) > block_dev->lba)
39 return 0;
40
41 if (ndev->read == NULL)
42 return 0;
43
44 err = ndev->read(0, (u32)start, (u32)blkcnt, dst);
45 if (err)
46 return err;
47
48 return blkcnt;
49 }
50
rknand_bwrite(struct udevice * udev,lbaint_t start,lbaint_t blkcnt,const void * src)51 ulong rknand_bwrite(struct udevice *udev, lbaint_t start,
52 lbaint_t blkcnt, const void *src)
53 {
54 struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
55 struct rknand_dev *ndev = dev_get_priv(udev->parent);
56 int err;
57
58 if (blkcnt == 0)
59 return 0;
60
61 if ((start + blkcnt) > block_dev->lba)
62 return 0;
63
64 if (ndev->write == NULL)
65 return 0;
66
67 err = ndev->write(0, (u32)start, (u32)blkcnt, src);
68 if (err)
69 return err;
70
71 return blkcnt;
72 }
73
rknand_berase(struct udevice * udev,lbaint_t start,lbaint_t blkcnt)74 ulong rknand_berase(struct udevice *udev, lbaint_t start,
75 lbaint_t blkcnt)
76 {
77 struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
78 struct rknand_dev *ndev = dev_get_priv(udev->parent);
79 int err;
80
81 if (blkcnt == 0)
82 return 0;
83
84 if ((start + blkcnt) > block_dev->lba)
85 return 0;
86
87 if (ndev->erase == NULL)
88 return 0;
89
90 err = ndev->erase(0, (u32)start, (u32)blkcnt);
91 if (err)
92 return err;
93
94 return blkcnt;
95 }
96
rkftl_nand_vendor_read(struct blk_desc * dev_desc,u32 index,u32 n_sec,void * p_data)97 int rkftl_nand_vendor_read(struct blk_desc *dev_desc,
98 u32 index,
99 u32 n_sec,
100 void *p_data)
101 {
102 int ret;
103
104 ret = ftl_vendor_read(index, n_sec, p_data);
105 if (!ret)
106 return n_sec;
107 else
108 return -EIO;
109 }
110
rkftl_nand_vendor_write(struct blk_desc * dev_desc,u32 index,u32 n_sec,void * p_data)111 int rkftl_nand_vendor_write(struct blk_desc *dev_desc,
112 u32 index,
113 u32 n_sec,
114 void *p_data)
115 {
116 int ret;
117
118 ret = ftl_vendor_write(index, n_sec, p_data);
119 if (!ret)
120 return n_sec;
121 else
122 return -EIO;
123 }
124
rknand_scan_namespace(void)125 int rknand_scan_namespace(void)
126 {
127 struct uclass *uc;
128 struct udevice *dev;
129 int ret;
130
131 ret = uclass_get(UCLASS_RKNAND, &uc);
132 if (ret)
133 return ret;
134
135 uclass_foreach_dev(dev, uc) {
136 debug("%s %d %p\n", __func__, __LINE__, dev);
137 ret = device_probe(dev);
138 if (ret)
139 return ret;
140 }
141
142 return 0;
143 }
144
rknand_blk_bind(struct udevice * udev)145 static int rknand_blk_bind(struct udevice *udev)
146 {
147 struct udevice *bdev;
148 int ret;
149
150 ret = blk_create_devicef(udev, "rknand_blk", "blk",
151 IF_TYPE_RKNAND,
152 0, 512, 0, &bdev);
153 if (ret) {
154 debug("Cannot create block device\n");
155 return ret;
156 }
157
158 return 0;
159 }
160
rknand_blk_probe(struct udevice * udev)161 static int rknand_blk_probe(struct udevice *udev)
162 {
163 struct rknand_dev *ndev = dev_get_priv(udev->parent);
164 struct blk_desc *desc = dev_get_uclass_platdata(udev);
165
166 debug("%s %d %p ndev = %p %p\n", __func__, __LINE__,
167 udev, ndev, udev->parent);
168 ndev->dev = udev;
169 desc->if_type = IF_TYPE_RKNAND;
170 desc->lba = ndev->density;
171 desc->log2blksz = 9;
172 desc->blksz = 512;
173 desc->bdev = udev;
174 desc->devnum = 0;
175 sprintf(desc->vendor, "0x%.4x", 0x2207);
176 memcpy(desc->product, "rknand", sizeof("rknand"));
177 memcpy(desc->revision, "V1.00", sizeof("V1.00"));
178 part_init(desc);
179 return 0;
180 }
181
rockchip_nand_probe(struct udevice * udev)182 static int rockchip_nand_probe(struct udevice *udev)
183 {
184 int ret;
185 struct rknand_dev *ndev = dev_get_priv(udev);
186
187 ndev->ioaddr = dev_read_addr_ptr(udev);
188 ret = rk_ftl_init(ndev->ioaddr);
189 if (!ret) {
190 ndev->density = ftl_get_density(0);
191 ndev->read = ftl_read;
192 ndev->write = ftl_write;
193 ndev->erase = ftl_discard;
194 #ifndef CONFIG_SPL_BUILD
195 #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
196 flash_vendor_dev_ops_register(rkftl_nand_vendor_read,
197 rkftl_nand_vendor_write);
198 #endif
199 #endif
200 }
201
202 return ret;
203 }
204
205 static const struct blk_ops rknand_blk_ops = {
206 .read = rknand_bread,
207 .write = rknand_bwrite,
208 .erase = rknand_berase,
209 };
210
211 static const struct udevice_id rockchip_nand_ids[] = {
212 { .compatible = "rockchip,rk-nandc" },
213 { }
214 };
215
216 U_BOOT_DRIVER(rknand_blk) = {
217 .name = "rknand_blk",
218 .id = UCLASS_BLK,
219 .ops = &rknand_blk_ops,
220 .probe = rknand_blk_probe,
221 };
222
223 UCLASS_DRIVER(rknand) = {
224 .id = UCLASS_RKNAND,
225 .name = "rknand",
226 .flags = DM_UC_FLAG_SEQ_ALIAS,
227 .per_device_auto_alloc_size = sizeof(struct rknand_uclass_priv),
228 };
229
230 U_BOOT_DRIVER(rknand) = {
231 .name = "rknand",
232 .id = UCLASS_RKNAND,
233 .of_match = rockchip_nand_ids,
234 .bind = rknand_blk_bind,
235 .probe = rockchip_nand_probe,
236 .priv_auto_alloc_size = sizeof(struct rknand_dev),
237 };
238
239