1 // SPDX-License-Identifier: GPL-2.0
2
3 /* Copyright (c) 2018 Rockchip Electronics Co. Ltd. */
4
5 #include <linux/kernel.h>
6 #include <linux/mtd/cfi.h>
7 #include <linux/mtd/mtd.h>
8 #include <linux/mtd/partitions.h>
9 #include <linux/slab.h>
10 #include <linux/string.h>
11
12 #include "rkflash_blk.h"
13 #include "rkflash_debug.h"
14
15 struct snor_mtd_dev {
16 struct SFNOR_DEV *snor;
17 struct mutex *lock; /* to lock this object */
18 struct mtd_info mtd;
19 u8 *dma_buf;
20 };
21
22 static struct mtd_partition nor_parts[MAX_PART_COUNT];
23
24 #define SFC_NOR_MTD_DMA_MAX 8192
25
mtd_to_priv(struct mtd_info * ptr_mtd)26 static inline struct snor_mtd_dev *mtd_to_priv(struct mtd_info *ptr_mtd)
27 {
28 return (struct snor_mtd_dev *)((char *)ptr_mtd -
29 offsetof(struct snor_mtd_dev, mtd));
30 }
31
sfc_erase_mtd(struct mtd_info * mtd,struct erase_info * instr)32 static int sfc_erase_mtd(struct mtd_info *mtd, struct erase_info *instr)
33 {
34 int ret;
35 struct snor_mtd_dev *p_dev = mtd_to_priv(mtd);
36 u32 addr, len;
37 u32 rem;
38
39 addr = instr->addr;
40 len = instr->len;
41 rkflash_print_dio("%s addr= %x len= %x\n",
42 __func__, addr, len);
43
44 if ((addr + len) > mtd->size)
45 return -EINVAL;
46
47 div_u64_rem(instr->len, mtd->erasesize, &rem);
48 if (rem)
49 return -EINVAL;
50
51 mutex_lock(p_dev->lock);
52
53 if (len == p_dev->mtd.size) {
54 ret = snor_erase(p_dev->snor, 0, ERASE_CHIP);
55 if (ret) {
56 rkflash_print_error("snor_erase CHIP 0x%x ret=%d\n",
57 addr, ret);
58 instr->fail_addr = addr;
59 mutex_unlock(p_dev->lock);
60 return -EIO;
61 }
62 } else {
63 while (len > 0) {
64 ret = snor_erase(p_dev->snor, addr, ERASE_BLOCK64K);
65 if (ret) {
66 rkflash_print_error("snor_erase 0x%x ret=%d\n",
67 addr, ret);
68 instr->fail_addr = addr;
69 mutex_unlock(p_dev->lock);
70 return -EIO;
71 }
72 addr += mtd->erasesize;
73 len -= mtd->erasesize;
74 }
75 }
76
77 mutex_unlock(p_dev->lock);
78
79 return 0;
80 }
81
sfc_write_mtd(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf)82 static int sfc_write_mtd(struct mtd_info *mtd, loff_t to, size_t len,
83 size_t *retlen, const u_char *buf)
84 {
85 int status;
86 u32 addr, size, chunk, padding;
87 u32 page_align;
88 struct snor_mtd_dev *p_dev = mtd_to_priv(mtd);
89
90 rkflash_print_dio("%s addr= %llx len= %x\n", __func__, to, (u32)len);
91 if ((to + len) > mtd->size)
92 return -EINVAL;
93
94 mutex_lock(p_dev->lock);
95
96 addr = to;
97 size = len;
98
99 while (size > 0) {
100 page_align = addr & (NOR_PAGE_SIZE - 1);
101 chunk = size;
102 if (chunk > (NOR_PAGE_SIZE - page_align))
103 chunk = NOR_PAGE_SIZE - page_align;
104 memcpy(p_dev->dma_buf, buf, chunk);
105 padding = 0;
106 if (chunk < NOR_PAGE_SIZE) {
107 /* 4 bytes algin */
108 padding = ((chunk + 3) & 0xFFFC) - chunk;
109 memset(p_dev->dma_buf + chunk, 0xFF, padding);
110 }
111 status = snor_prog_page(p_dev->snor, addr, p_dev->dma_buf,
112 chunk + padding);
113 if (status != SFC_OK) {
114 rkflash_print_error("snor_prog_page %x ret= %d\n",
115 addr, status);
116 *retlen = len - size;
117 mutex_unlock(p_dev->lock);
118 return status;
119 }
120
121 size -= chunk;
122 addr += chunk;
123 buf += chunk;
124 }
125 *retlen = len;
126 mutex_unlock(p_dev->lock);
127
128 return 0;
129 }
130
sfc_read_mtd(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,u_char * buf)131 static int sfc_read_mtd(struct mtd_info *mtd, loff_t from, size_t len,
132 size_t *retlen, u_char *buf)
133 {
134 u32 addr, size, chunk;
135 u8 *p_buf = (u8 *)buf;
136 int ret = SFC_OK;
137 struct snor_mtd_dev *p_dev = mtd_to_priv(mtd);
138
139 rkflash_print_dio("%s addr= %llx len= %x\n", __func__, from, (u32)len);
140 if ((from + len) > mtd->size)
141 return -EINVAL;
142
143 mutex_lock(p_dev->lock);
144
145 addr = from;
146 size = len;
147
148 while (size > 0) {
149 chunk = (size < SFC_NOR_MTD_DMA_MAX) ? size : SFC_NOR_MTD_DMA_MAX;
150 ret = snor_read_data(p_dev->snor, addr, p_dev->dma_buf, chunk);
151 if (ret != SFC_OK) {
152 rkflash_print_error("snor_read_data %x ret=%d\n", addr, ret);
153 *retlen = len - size;
154 mutex_unlock(p_dev->lock);
155 return ret;
156 }
157 memcpy(p_buf, p_dev->dma_buf, chunk);
158 size -= chunk;
159 addr += chunk;
160 p_buf += chunk;
161 }
162
163 *retlen = len;
164 mutex_unlock(p_dev->lock);
165 return 0;
166 }
167
168 /*
169 * if not support rk_partition and partition is confirmed, you can define
170 * strust def_nor_part by adding new partition like following example:
171 * {"u-boot", 0x1000 * 512, 0x2000 * 512},
172 * Note.
173 * 1. New partition format {name. size, offset}
174 * 2. Unit:Byte
175 * 3. Last partition 'size' can be set 0xFFFFFFFFF to fully user left space.
176 */
177 struct mtd_partition def_nor_part[] = {};
178
sfc_nor_mtd_init(struct SFNOR_DEV * p_dev,struct mutex * lock)179 int sfc_nor_mtd_init(struct SFNOR_DEV *p_dev, struct mutex *lock)
180 {
181 int ret, i, part_num = 0;
182 int capacity;
183 struct STRUCT_PART_INFO *g_part; /* size 2KB */
184 struct snor_mtd_dev *priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL);
185
186 if (!priv_dev) {
187 rkflash_print_error("%s %d alloc failed\n", __func__, __LINE__);
188 return -ENOMEM;
189 }
190
191 priv_dev->snor = p_dev;
192 capacity = p_dev->capacity;
193 priv_dev->mtd.name = "sfc_nor";
194 priv_dev->mtd.type = MTD_NORFLASH;
195 priv_dev->mtd.writesize = 1;
196 priv_dev->mtd.flags = MTD_CAP_NORFLASH;
197 /* see snor_write */
198 priv_dev->mtd.size = (u64)capacity << 9;
199 priv_dev->mtd._erase = sfc_erase_mtd;
200 priv_dev->mtd._read = sfc_read_mtd;
201 priv_dev->mtd._write = sfc_write_mtd;
202 priv_dev->mtd.erasesize = p_dev->blk_size << 9;
203 priv_dev->mtd.writebufsize = NOR_PAGE_SIZE;
204 priv_dev->lock = lock;
205 priv_dev->dma_buf = (u8 *)__get_free_pages(GFP_KERNEL | GFP_DMA32, get_order(SFC_NOR_MTD_DMA_MAX));
206 if (!priv_dev->dma_buf) {
207 rkflash_print_error("%s %d alloc failed\n", __func__, __LINE__);
208 ret = -ENOMEM;
209 goto error_out;
210 }
211
212 g_part = kmalloc(sizeof(*g_part), GFP_KERNEL);
213 if (!g_part) {
214 ret = -ENOMEM;
215 goto error_out;
216 }
217 part_num = 0;
218 if (snor_read(p_dev, 0, 4, g_part) == 4) {
219 if (g_part->hdr.ui_fw_tag == RK_PARTITION_TAG) {
220 part_num = g_part->hdr.ui_part_entry_count;
221 for (i = 0; i < part_num; i++) {
222 nor_parts[i].name =
223 kstrdup(g_part->part[i].sz_name,
224 GFP_KERNEL);
225 if (g_part->part[i].ui_pt_sz == 0xFFFFFFFF)
226 g_part->part[i].ui_pt_sz = capacity -
227 g_part->part[i].ui_pt_off;
228 nor_parts[i].offset =
229 (u64)g_part->part[i].ui_pt_off << 9;
230 nor_parts[i].size =
231 (u64)g_part->part[i].ui_pt_sz << 9;
232 nor_parts[i].mask_flags = 0;
233 }
234 } else {
235 part_num = ARRAY_SIZE(def_nor_part);
236 for (i = 0; i < part_num; i++) {
237 nor_parts[i].name =
238 kstrdup(def_nor_part[i].name,
239 GFP_KERNEL);
240 if (def_nor_part[i].size == 0xFFFFFFFF)
241 def_nor_part[i].size = (capacity << 9) -
242 def_nor_part[i].offset;
243 nor_parts[i].offset =
244 def_nor_part[i].offset;
245 nor_parts[i].size =
246 def_nor_part[i].size;
247 nor_parts[i].mask_flags = 0;
248 }
249 }
250 }
251 kfree(g_part);
252 ret = mtd_device_register(&priv_dev->mtd, nor_parts, part_num);
253 if (ret) {
254 pr_err("%s register mtd fail %d\n", __func__, ret);
255 } else {
256 pr_info("%s register mtd succuss\n", __func__);
257
258 return 0;
259 }
260
261 free_pages((unsigned long)priv_dev->dma_buf, get_order(SFC_NOR_MTD_DMA_MAX));
262 error_out:
263 kfree(priv_dev);
264
265 return ret;
266 }
267