1441217e3SZhaoyifeng /*
2441217e3SZhaoyifeng * Copyright (C) (C) Copyright 2016-2017 Rockchip Electronics Co., Ltd
3441217e3SZhaoyifeng *
4441217e3SZhaoyifeng * SPDX-License-Identifier: GPL-2.0+
5441217e3SZhaoyifeng */
6441217e3SZhaoyifeng
7441217e3SZhaoyifeng #include <common.h>
8a4399586SYifeng Zhao #include <asm/arch/vendor.h>
9441217e3SZhaoyifeng #include <dm.h>
10441217e3SZhaoyifeng #include <dm/device-internal.h>
11441217e3SZhaoyifeng #include <dm/lists.h>
12441217e3SZhaoyifeng #include <dm/root.h>
13441217e3SZhaoyifeng #include "rknand.h"
14441217e3SZhaoyifeng
rknand_get_blk_desc(struct rknand_dev * ndev)15441217e3SZhaoyifeng struct blk_desc *rknand_get_blk_desc(struct rknand_dev *ndev)
16441217e3SZhaoyifeng {
17441217e3SZhaoyifeng struct blk_desc *desc;
18441217e3SZhaoyifeng struct udevice *dev;
19441217e3SZhaoyifeng
20441217e3SZhaoyifeng device_find_first_child(ndev->dev, &dev);
21441217e3SZhaoyifeng if (!dev)
22441217e3SZhaoyifeng return NULL;
23441217e3SZhaoyifeng desc = dev_get_uclass_platdata(dev);
24441217e3SZhaoyifeng
25441217e3SZhaoyifeng return desc;
26441217e3SZhaoyifeng }
27441217e3SZhaoyifeng
rknand_bread(struct udevice * udev,lbaint_t start,lbaint_t blkcnt,void * dst)28441217e3SZhaoyifeng ulong rknand_bread(struct udevice *udev, lbaint_t start,
29441217e3SZhaoyifeng lbaint_t blkcnt, void *dst)
30441217e3SZhaoyifeng {
31441217e3SZhaoyifeng struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
32441217e3SZhaoyifeng struct rknand_dev *ndev = dev_get_priv(udev->parent);
33441217e3SZhaoyifeng int err;
34441217e3SZhaoyifeng
35441217e3SZhaoyifeng if (blkcnt == 0)
36441217e3SZhaoyifeng return 0;
37441217e3SZhaoyifeng
38441217e3SZhaoyifeng if ((start + blkcnt) > block_dev->lba)
39441217e3SZhaoyifeng return 0;
40441217e3SZhaoyifeng
41441217e3SZhaoyifeng if (ndev->read == NULL)
42441217e3SZhaoyifeng return 0;
43441217e3SZhaoyifeng
44441217e3SZhaoyifeng err = ndev->read(0, (u32)start, (u32)blkcnt, dst);
45441217e3SZhaoyifeng if (err)
46441217e3SZhaoyifeng return err;
47441217e3SZhaoyifeng
48441217e3SZhaoyifeng return blkcnt;
49441217e3SZhaoyifeng }
50441217e3SZhaoyifeng
rknand_bwrite(struct udevice * udev,lbaint_t start,lbaint_t blkcnt,const void * src)51441217e3SZhaoyifeng ulong rknand_bwrite(struct udevice *udev, lbaint_t start,
52441217e3SZhaoyifeng lbaint_t blkcnt, const void *src)
53441217e3SZhaoyifeng {
54441217e3SZhaoyifeng struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
55441217e3SZhaoyifeng struct rknand_dev *ndev = dev_get_priv(udev->parent);
56441217e3SZhaoyifeng int err;
57441217e3SZhaoyifeng
58441217e3SZhaoyifeng if (blkcnt == 0)
59441217e3SZhaoyifeng return 0;
60441217e3SZhaoyifeng
61441217e3SZhaoyifeng if ((start + blkcnt) > block_dev->lba)
62441217e3SZhaoyifeng return 0;
63441217e3SZhaoyifeng
64441217e3SZhaoyifeng if (ndev->write == NULL)
65441217e3SZhaoyifeng return 0;
66441217e3SZhaoyifeng
67441217e3SZhaoyifeng err = ndev->write(0, (u32)start, (u32)blkcnt, src);
68441217e3SZhaoyifeng if (err)
69441217e3SZhaoyifeng return err;
70441217e3SZhaoyifeng
71441217e3SZhaoyifeng return blkcnt;
72441217e3SZhaoyifeng }
73441217e3SZhaoyifeng
rknand_berase(struct udevice * udev,lbaint_t start,lbaint_t blkcnt)74441217e3SZhaoyifeng ulong rknand_berase(struct udevice *udev, lbaint_t start,
75441217e3SZhaoyifeng lbaint_t blkcnt)
76441217e3SZhaoyifeng {
77441217e3SZhaoyifeng struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
78441217e3SZhaoyifeng struct rknand_dev *ndev = dev_get_priv(udev->parent);
79441217e3SZhaoyifeng int err;
80441217e3SZhaoyifeng
81441217e3SZhaoyifeng if (blkcnt == 0)
82441217e3SZhaoyifeng return 0;
83441217e3SZhaoyifeng
84441217e3SZhaoyifeng if ((start + blkcnt) > block_dev->lba)
85441217e3SZhaoyifeng return 0;
86441217e3SZhaoyifeng
87441217e3SZhaoyifeng if (ndev->erase == NULL)
88441217e3SZhaoyifeng return 0;
89441217e3SZhaoyifeng
90441217e3SZhaoyifeng err = ndev->erase(0, (u32)start, (u32)blkcnt);
91441217e3SZhaoyifeng if (err)
92441217e3SZhaoyifeng return err;
93441217e3SZhaoyifeng
94441217e3SZhaoyifeng return blkcnt;
95441217e3SZhaoyifeng }
96441217e3SZhaoyifeng
rkftl_nand_vendor_read(struct blk_desc * dev_desc,u32 index,u32 n_sec,void * p_data)97a4399586SYifeng Zhao int rkftl_nand_vendor_read(struct blk_desc *dev_desc,
98a4399586SYifeng Zhao u32 index,
99a4399586SYifeng Zhao u32 n_sec,
100a4399586SYifeng Zhao void *p_data)
101a4399586SYifeng Zhao {
102a4399586SYifeng Zhao int ret;
103a4399586SYifeng Zhao
104a4399586SYifeng Zhao ret = ftl_vendor_read(index, n_sec, p_data);
105a4399586SYifeng Zhao if (!ret)
106a4399586SYifeng Zhao return n_sec;
107a4399586SYifeng Zhao else
108a4399586SYifeng Zhao return -EIO;
109a4399586SYifeng Zhao }
110a4399586SYifeng Zhao
rkftl_nand_vendor_write(struct blk_desc * dev_desc,u32 index,u32 n_sec,void * p_data)111a4399586SYifeng Zhao int rkftl_nand_vendor_write(struct blk_desc *dev_desc,
112a4399586SYifeng Zhao u32 index,
113a4399586SYifeng Zhao u32 n_sec,
114a4399586SYifeng Zhao void *p_data)
115a4399586SYifeng Zhao {
116a4399586SYifeng Zhao int ret;
117a4399586SYifeng Zhao
118a4399586SYifeng Zhao ret = ftl_vendor_write(index, n_sec, p_data);
119a4399586SYifeng Zhao if (!ret)
120a4399586SYifeng Zhao return n_sec;
121a4399586SYifeng Zhao else
122a4399586SYifeng Zhao return -EIO;
123a4399586SYifeng Zhao }
124a4399586SYifeng Zhao
rknand_scan_namespace(void)125441217e3SZhaoyifeng int rknand_scan_namespace(void)
126441217e3SZhaoyifeng {
127441217e3SZhaoyifeng struct uclass *uc;
128441217e3SZhaoyifeng struct udevice *dev;
129441217e3SZhaoyifeng int ret;
130441217e3SZhaoyifeng
131441217e3SZhaoyifeng ret = uclass_get(UCLASS_RKNAND, &uc);
132441217e3SZhaoyifeng if (ret)
133441217e3SZhaoyifeng return ret;
134441217e3SZhaoyifeng
135441217e3SZhaoyifeng uclass_foreach_dev(dev, uc) {
136441217e3SZhaoyifeng debug("%s %d %p\n", __func__, __LINE__, dev);
137441217e3SZhaoyifeng ret = device_probe(dev);
138441217e3SZhaoyifeng if (ret)
139441217e3SZhaoyifeng return ret;
140441217e3SZhaoyifeng }
141441217e3SZhaoyifeng
142441217e3SZhaoyifeng return 0;
143441217e3SZhaoyifeng }
144441217e3SZhaoyifeng
rknand_blk_bind(struct udevice * udev)145441217e3SZhaoyifeng static int rknand_blk_bind(struct udevice *udev)
146441217e3SZhaoyifeng {
147441217e3SZhaoyifeng struct udevice *bdev;
148441217e3SZhaoyifeng int ret;
149441217e3SZhaoyifeng
150441217e3SZhaoyifeng ret = blk_create_devicef(udev, "rknand_blk", "blk",
151441217e3SZhaoyifeng IF_TYPE_RKNAND,
152441217e3SZhaoyifeng 0, 512, 0, &bdev);
153441217e3SZhaoyifeng if (ret) {
154441217e3SZhaoyifeng debug("Cannot create block device\n");
155441217e3SZhaoyifeng return ret;
156441217e3SZhaoyifeng }
157441217e3SZhaoyifeng
158441217e3SZhaoyifeng return 0;
159441217e3SZhaoyifeng }
160441217e3SZhaoyifeng
rknand_blk_probe(struct udevice * udev)161441217e3SZhaoyifeng static int rknand_blk_probe(struct udevice *udev)
162441217e3SZhaoyifeng {
163441217e3SZhaoyifeng struct rknand_dev *ndev = dev_get_priv(udev->parent);
164441217e3SZhaoyifeng struct blk_desc *desc = dev_get_uclass_platdata(udev);
165441217e3SZhaoyifeng
166441217e3SZhaoyifeng debug("%s %d %p ndev = %p %p\n", __func__, __LINE__,
167441217e3SZhaoyifeng udev, ndev, udev->parent);
168441217e3SZhaoyifeng ndev->dev = udev;
169441217e3SZhaoyifeng desc->if_type = IF_TYPE_RKNAND;
170441217e3SZhaoyifeng desc->lba = ndev->density;
171441217e3SZhaoyifeng desc->log2blksz = 9;
172441217e3SZhaoyifeng desc->blksz = 512;
173441217e3SZhaoyifeng desc->bdev = udev;
174441217e3SZhaoyifeng desc->devnum = 0;
175441217e3SZhaoyifeng sprintf(desc->vendor, "0x%.4x", 0x2207);
176441217e3SZhaoyifeng memcpy(desc->product, "rknand", sizeof("rknand"));
177441217e3SZhaoyifeng memcpy(desc->revision, "V1.00", sizeof("V1.00"));
1789ea7f399SZhaoyifeng part_init(desc);
179441217e3SZhaoyifeng return 0;
180441217e3SZhaoyifeng }
181441217e3SZhaoyifeng
rockchip_nand_probe(struct udevice * udev)182441217e3SZhaoyifeng static int rockchip_nand_probe(struct udevice *udev)
183441217e3SZhaoyifeng {
184441217e3SZhaoyifeng int ret;
185441217e3SZhaoyifeng struct rknand_dev *ndev = dev_get_priv(udev);
186441217e3SZhaoyifeng
187c4238552SZhaoyifeng ndev->ioaddr = dev_read_addr_ptr(udev);
188441217e3SZhaoyifeng ret = rk_ftl_init(ndev->ioaddr);
189441217e3SZhaoyifeng if (!ret) {
190441217e3SZhaoyifeng ndev->density = ftl_get_density(0);
191441217e3SZhaoyifeng ndev->read = ftl_read;
192441217e3SZhaoyifeng ndev->write = ftl_write;
193441217e3SZhaoyifeng ndev->erase = ftl_discard;
194*e18e7090SYifeng Zhao #ifndef CONFIG_SPL_BUILD
195a4399586SYifeng Zhao #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
196a4399586SYifeng Zhao flash_vendor_dev_ops_register(rkftl_nand_vendor_read,
197a4399586SYifeng Zhao rkftl_nand_vendor_write);
198a4399586SYifeng Zhao #endif
199*e18e7090SYifeng Zhao #endif
200441217e3SZhaoyifeng }
201441217e3SZhaoyifeng
202441217e3SZhaoyifeng return ret;
203441217e3SZhaoyifeng }
204441217e3SZhaoyifeng
205441217e3SZhaoyifeng static const struct blk_ops rknand_blk_ops = {
206441217e3SZhaoyifeng .read = rknand_bread,
207441217e3SZhaoyifeng .write = rknand_bwrite,
208441217e3SZhaoyifeng .erase = rknand_berase,
209441217e3SZhaoyifeng };
210441217e3SZhaoyifeng
211441217e3SZhaoyifeng static const struct udevice_id rockchip_nand_ids[] = {
212441217e3SZhaoyifeng { .compatible = "rockchip,rk-nandc" },
213441217e3SZhaoyifeng { }
214441217e3SZhaoyifeng };
215441217e3SZhaoyifeng
216441217e3SZhaoyifeng U_BOOT_DRIVER(rknand_blk) = {
217441217e3SZhaoyifeng .name = "rknand_blk",
218441217e3SZhaoyifeng .id = UCLASS_BLK,
219441217e3SZhaoyifeng .ops = &rknand_blk_ops,
220441217e3SZhaoyifeng .probe = rknand_blk_probe,
221441217e3SZhaoyifeng };
222441217e3SZhaoyifeng
223441217e3SZhaoyifeng UCLASS_DRIVER(rknand) = {
224441217e3SZhaoyifeng .id = UCLASS_RKNAND,
225441217e3SZhaoyifeng .name = "rknand",
226441217e3SZhaoyifeng .flags = DM_UC_FLAG_SEQ_ALIAS,
227441217e3SZhaoyifeng .per_device_auto_alloc_size = sizeof(struct rknand_uclass_priv),
228441217e3SZhaoyifeng };
229441217e3SZhaoyifeng
230441217e3SZhaoyifeng U_BOOT_DRIVER(rknand) = {
231441217e3SZhaoyifeng .name = "rknand",
232441217e3SZhaoyifeng .id = UCLASS_RKNAND,
233441217e3SZhaoyifeng .of_match = rockchip_nand_ids,
234441217e3SZhaoyifeng .bind = rknand_blk_bind,
235441217e3SZhaoyifeng .probe = rockchip_nand_probe,
236441217e3SZhaoyifeng .priv_auto_alloc_size = sizeof(struct rknand_dev),
237441217e3SZhaoyifeng };
238441217e3SZhaoyifeng
239