xref: /rk3399_rockchip-uboot/drivers/rknand/rknand.c (revision e18e7090245c4c26ad498bd5505736b324a15463)
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