Commit 0f67e09e9ef354ae2d282091adb3dc531f2aef7d
Committed by
Stefano Babic
1 parent
ccca7dfd02
Exists in
master
and in
53 other branches
Add fsl_iim driver
Add a fsl_iim driver common to i.MX and MPC. Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
Showing 7 changed files with 340 additions and 0 deletions Side-by-side Diff
arch/arm/include/asm/arch-mx25/imx-regs.h
... | ... | @@ -253,6 +253,7 @@ |
253 | 253 | #define IMX_PWM1_BASE (0x53FE0000) |
254 | 254 | #define IMX_RTIC_BASE (0x53FEC000) |
255 | 255 | #define IMX_IIM_BASE (0x53FF0000) |
256 | +#define IIM_BASE_ADDR IMX_IIM_BASE | |
256 | 257 | #define IMX_USB_BASE (0x53FF4000) |
257 | 258 | #define IMX_USB_PORT_OFFSET 0x200 |
258 | 259 | #define IMX_CSI_BASE (0x53FF8000) |
arch/arm/include/asm/arch-mx27/imx-regs.h
... | ... | @@ -222,6 +222,7 @@ |
222 | 222 | #define IMX_PLL_BASE (0x27000 + IMX_IO_BASE) |
223 | 223 | #define IMX_SYSTEM_CTL_BASE (0x27800 + IMX_IO_BASE) |
224 | 224 | #define IMX_IIM_BASE (0x28000 + IMX_IO_BASE) |
225 | +#define IIM_BASE_ADDR IMX_IIM_BASE | |
225 | 226 | #define IMX_FEC_BASE (0x2b000 + IMX_IO_BASE) |
226 | 227 | |
227 | 228 | #define IMX_ESD_BASE (0xD8001000) |
arch/arm/include/asm/arch-mx31/imx-regs.h
arch/powerpc/include/asm/immap_512x.h
doc/README.fsl_iim
1 | +Driver implementing the fuse API for Freescale's IC Identification Module (IIM) | |
2 | + | |
3 | +This IP can be found on the following SoCs: | |
4 | + - MPC512x, | |
5 | + - i.MX25, | |
6 | + - i.MX27, | |
7 | + - i.MX31, | |
8 | + - i.MX35, | |
9 | + - i.MX51, | |
10 | + - i.MX53. | |
11 | + | |
12 | +The section numbers in this file refer to the i.MX25 Reference Manual. | |
13 | + | |
14 | +A fuse word contains 8 fuse bit slots, as explained in 30.4.2.2.1. | |
15 | + | |
16 | +A bank contains 256 fuse word slots, as shown by the memory map in 30.3.1. | |
17 | + | |
18 | +Some fuse bit or word slots may not have the corresponding fuses actually | |
19 | +implemented in the fusebox. | |
20 | + | |
21 | +See the README files of the SoCs using this driver in order to know the | |
22 | +conventions used by U-Boot to store some specific data in the fuses, e.g. MAC | |
23 | +addresses. | |
24 | + | |
25 | +Fuse operations: | |
26 | + | |
27 | + Read | |
28 | + Read operations are implemented as read accesses to the shadow registers, | |
29 | + using "Word y of Bank x" from the register summary in 30.3.2. This is | |
30 | + explained in detail in 30.4.5.1. | |
31 | + | |
32 | + Sense | |
33 | + Sense operations are implemented as explained in 30.4.5.2. | |
34 | + | |
35 | + Program | |
36 | + Program operations are implemented as explained in 30.4.5.3. Following | |
37 | + this operation, the shadow registers are reloaded by the hardware (not | |
38 | + immediately, but this does not make any difference for a user reading | |
39 | + these registers). | |
40 | + | |
41 | + Override | |
42 | + Override operations are implemented as write accesses to the shadow | |
43 | + registers, as explained in 30.4.5.4. | |
44 | + | |
45 | +Configuration: | |
46 | + | |
47 | + CONFIG_FSL_IIM | |
48 | + Define this to enable the fsl_iim driver. |
drivers/misc/Makefile
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | COBJS-$(CONFIG_ALI152X) += ali512x.o |
29 | 29 | COBJS-$(CONFIG_DS4510) += ds4510.o |
30 | 30 | COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o |
31 | +COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o | |
31 | 32 | COBJS-$(CONFIG_GPIO_LED) += gpio_led.o |
32 | 33 | COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o |
33 | 34 | COBJS-$(CONFIG_NS87308) += ns87308.o |
drivers/misc/fsl_iim.c
1 | +/* | |
2 | + * (C) Copyright 2009-2013 ADVANSEE | |
3 | + * Benoît Thébaudeau <benoit.thebaudeau@advansee.com> | |
4 | + * | |
5 | + * Based on the mpc512x iim code: | |
6 | + * Copyright 2008 Silicon Turnkey Express, Inc. | |
7 | + * Martha Marx <mmarx@silicontkx.com> | |
8 | + * | |
9 | + * See file CREDITS for list of people who contributed to this | |
10 | + * project. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or | |
13 | + * modify it under the terms of the GNU General Public License as | |
14 | + * published by the Free Software Foundation; either version 2 of | |
15 | + * the License, or (at your option) any later version. | |
16 | + * | |
17 | + * This program is distributed in the hope that it will be useful, | |
18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | + * GNU General Public License for more details. | |
21 | + * | |
22 | + * You should have received a copy of the GNU General Public License | |
23 | + * along with this program; if not, write to the Free Software | |
24 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | + * MA 02111-1307 USA | |
26 | + */ | |
27 | + | |
28 | +#include <common.h> | |
29 | +#include <fuse.h> | |
30 | +#include <asm/errno.h> | |
31 | +#include <asm/io.h> | |
32 | +#ifndef CONFIG_MPC512X | |
33 | +#include <asm/arch/imx-regs.h> | |
34 | +#endif | |
35 | + | |
36 | +/* FSL IIM-specific constants */ | |
37 | +#define STAT_BUSY 0x80 | |
38 | +#define STAT_PRGD 0x02 | |
39 | +#define STAT_SNSD 0x01 | |
40 | + | |
41 | +#define STATM_PRGD_M 0x02 | |
42 | +#define STATM_SNSD_M 0x01 | |
43 | + | |
44 | +#define ERR_PRGE 0x80 | |
45 | +#define ERR_WPE 0x40 | |
46 | +#define ERR_OPE 0x20 | |
47 | +#define ERR_RPE 0x10 | |
48 | +#define ERR_WLRE 0x08 | |
49 | +#define ERR_SNSE 0x04 | |
50 | +#define ERR_PARITYE 0x02 | |
51 | + | |
52 | +#define EMASK_PRGE_M 0x80 | |
53 | +#define EMASK_WPE_M 0x40 | |
54 | +#define EMASK_OPE_M 0x20 | |
55 | +#define EMASK_RPE_M 0x10 | |
56 | +#define EMASK_WLRE_M 0x08 | |
57 | +#define EMASK_SNSE_M 0x04 | |
58 | +#define EMASK_PARITYE_M 0x02 | |
59 | + | |
60 | +#define FCTL_DPC 0x80 | |
61 | +#define FCTL_PRG_LENGTH_MASK 0x70 | |
62 | +#define FCTL_ESNS_N 0x08 | |
63 | +#define FCTL_ESNS_0 0x04 | |
64 | +#define FCTL_ESNS_1 0x02 | |
65 | +#define FCTL_PRG 0x01 | |
66 | + | |
67 | +#define UA_A_BANK_MASK 0x38 | |
68 | +#define UA_A_ROWH_MASK 0x07 | |
69 | + | |
70 | +#define LA_A_ROWL_MASK 0xf8 | |
71 | +#define LA_A_BIT_MASK 0x07 | |
72 | + | |
73 | +#define PREV_PROD_REV_MASK 0xf8 | |
74 | +#define PREV_PROD_VT_MASK 0x07 | |
75 | + | |
76 | +/* Select the correct accessors depending on endianness */ | |
77 | +#if __BYTE_ORDER == __LITTLE_ENDIAN | |
78 | +#define iim_read32 in_le32 | |
79 | +#define iim_write32 out_le32 | |
80 | +#define iim_clrsetbits32 clrsetbits_le32 | |
81 | +#define iim_clrbits32 clrbits_le32 | |
82 | +#define iim_setbits32 setbits_le32 | |
83 | +#elif __BYTE_ORDER == __BIG_ENDIAN | |
84 | +#define iim_read32 in_be32 | |
85 | +#define iim_write32 out_be32 | |
86 | +#define iim_clrsetbits32 clrsetbits_be32 | |
87 | +#define iim_clrbits32 clrbits_be32 | |
88 | +#define iim_setbits32 setbits_be32 | |
89 | +#else | |
90 | +#error Endianess is not defined: please fix to continue | |
91 | +#endif | |
92 | + | |
93 | +/* IIM control registers */ | |
94 | +struct fsl_iim { | |
95 | + u32 stat; | |
96 | + u32 statm; | |
97 | + u32 err; | |
98 | + u32 emask; | |
99 | + u32 fctl; | |
100 | + u32 ua; | |
101 | + u32 la; | |
102 | + u32 sdat; | |
103 | + u32 prev; | |
104 | + u32 srev; | |
105 | + u32 prg_p; | |
106 | + u32 scs[0x1f5]; | |
107 | + struct { | |
108 | + u32 word[0x100]; | |
109 | + } bank[8]; | |
110 | +}; | |
111 | + | |
112 | +static int prepare_access(struct fsl_iim **regs, u32 bank, u32 word, int assert, | |
113 | + const char *caller) | |
114 | +{ | |
115 | + *regs = (struct fsl_iim *)IIM_BASE_ADDR; | |
116 | + | |
117 | + if (bank >= ARRAY_SIZE((*regs)->bank) || | |
118 | + word >= ARRAY_SIZE((*regs)->bank[0].word) || | |
119 | + !assert) { | |
120 | + printf("fsl_iim %s(): Invalid argument\n", caller); | |
121 | + return -EINVAL; | |
122 | + } | |
123 | + | |
124 | + return 0; | |
125 | +} | |
126 | + | |
127 | +static void clear_status(struct fsl_iim *regs) | |
128 | +{ | |
129 | + iim_setbits32(®s->stat, 0); | |
130 | + iim_setbits32(®s->err, 0); | |
131 | +} | |
132 | + | |
133 | +static void finish_access(struct fsl_iim *regs, u32 *stat, u32 *err) | |
134 | +{ | |
135 | + *stat = iim_read32(®s->stat); | |
136 | + *err = iim_read32(®s->err); | |
137 | + clear_status(regs); | |
138 | +} | |
139 | + | |
140 | +static int prepare_read(struct fsl_iim **regs, u32 bank, u32 word, u32 *val, | |
141 | + const char *caller) | |
142 | +{ | |
143 | + int ret; | |
144 | + | |
145 | + ret = prepare_access(regs, bank, word, val != NULL, caller); | |
146 | + if (ret) | |
147 | + return ret; | |
148 | + | |
149 | + clear_status(*regs); | |
150 | + | |
151 | + return 0; | |
152 | +} | |
153 | + | |
154 | +int fuse_read(u32 bank, u32 word, u32 *val) | |
155 | +{ | |
156 | + struct fsl_iim *regs; | |
157 | + u32 stat, err; | |
158 | + int ret; | |
159 | + | |
160 | + ret = prepare_read(®s, bank, word, val, __func__); | |
161 | + if (ret) | |
162 | + return ret; | |
163 | + | |
164 | + *val = iim_read32(®s->bank[bank].word[word]); | |
165 | + finish_access(regs, &stat, &err); | |
166 | + | |
167 | + if (err & ERR_RPE) { | |
168 | + puts("fsl_iim fuse_read(): Read protect error\n"); | |
169 | + return -EIO; | |
170 | + } | |
171 | + | |
172 | + return 0; | |
173 | +} | |
174 | + | |
175 | +static void direct_access(struct fsl_iim *regs, u32 bank, u32 word, u32 bit, | |
176 | + u32 fctl, u32 *stat, u32 *err) | |
177 | +{ | |
178 | + iim_write32(®s->ua, bank << 3 | word >> 5); | |
179 | + iim_write32(®s->la, (word << 3 | bit) & 0xff); | |
180 | + if (fctl == FCTL_PRG) | |
181 | + iim_write32(®s->prg_p, 0xaa); | |
182 | + iim_setbits32(®s->fctl, fctl); | |
183 | + while (iim_read32(®s->stat) & STAT_BUSY) | |
184 | + udelay(20); | |
185 | + finish_access(regs, stat, err); | |
186 | +} | |
187 | + | |
188 | +int fuse_sense(u32 bank, u32 word, u32 *val) | |
189 | +{ | |
190 | + struct fsl_iim *regs; | |
191 | + u32 stat, err; | |
192 | + int ret; | |
193 | + | |
194 | + ret = prepare_read(®s, bank, word, val, __func__); | |
195 | + if (ret) | |
196 | + return ret; | |
197 | + | |
198 | + direct_access(regs, bank, word, 0, FCTL_ESNS_N, &stat, &err); | |
199 | + | |
200 | + if (err & ERR_SNSE) { | |
201 | + puts("fsl_iim fuse_sense(): Explicit sense cycle error\n"); | |
202 | + return -EIO; | |
203 | + } | |
204 | + | |
205 | + if (!(stat & STAT_SNSD)) { | |
206 | + puts("fsl_iim fuse_sense(): Explicit sense cycle did not complete\n"); | |
207 | + return -EIO; | |
208 | + } | |
209 | + | |
210 | + *val = iim_read32(®s->sdat); | |
211 | + return 0; | |
212 | +} | |
213 | + | |
214 | +static int prog_bit(struct fsl_iim *regs, u32 bank, u32 word, u32 bit) | |
215 | +{ | |
216 | + u32 stat, err; | |
217 | + | |
218 | + clear_status(regs); | |
219 | + direct_access(regs, bank, word, bit, FCTL_PRG, &stat, &err); | |
220 | + iim_write32(®s->prg_p, 0x00); | |
221 | + | |
222 | + if (err & ERR_PRGE) { | |
223 | + puts("fsl_iim fuse_prog(): Program error\n"); | |
224 | + return -EIO; | |
225 | + } | |
226 | + | |
227 | + if (err & ERR_WPE) { | |
228 | + puts("fsl_iim fuse_prog(): Write protect error\n"); | |
229 | + return -EIO; | |
230 | + } | |
231 | + | |
232 | + if (!(stat & STAT_PRGD)) { | |
233 | + puts("fsl_iim fuse_prog(): Program did not complete\n"); | |
234 | + return -EIO; | |
235 | + } | |
236 | + | |
237 | + return 0; | |
238 | +} | |
239 | + | |
240 | +static int prepare_write(struct fsl_iim **regs, u32 bank, u32 word, u32 val, | |
241 | + const char *caller) | |
242 | +{ | |
243 | + return prepare_access(regs, bank, word, !(val & ~0xff), caller); | |
244 | +} | |
245 | + | |
246 | +int fuse_prog(u32 bank, u32 word, u32 val) | |
247 | +{ | |
248 | + struct fsl_iim *regs; | |
249 | + u32 bit; | |
250 | + int ret; | |
251 | + | |
252 | + ret = prepare_write(®s, bank, word, val, __func__); | |
253 | + if (ret) | |
254 | + return ret; | |
255 | + | |
256 | + for (bit = 0; val; bit++, val >>= 1) | |
257 | + if (val & 0x01) { | |
258 | + ret = prog_bit(regs, bank, word, bit); | |
259 | + if (ret) | |
260 | + return ret; | |
261 | + } | |
262 | + | |
263 | + return 0; | |
264 | +} | |
265 | + | |
266 | +int fuse_override(u32 bank, u32 word, u32 val) | |
267 | +{ | |
268 | + struct fsl_iim *regs; | |
269 | + u32 stat, err; | |
270 | + int ret; | |
271 | + | |
272 | + ret = prepare_write(®s, bank, word, val, __func__); | |
273 | + if (ret) | |
274 | + return ret; | |
275 | + | |
276 | + clear_status(regs); | |
277 | + iim_write32(®s->bank[bank].word[word], val); | |
278 | + finish_access(regs, &stat, &err); | |
279 | + | |
280 | + if (err & ERR_OPE) { | |
281 | + puts("fsl_iim fuse_override(): Override protect error\n"); | |
282 | + return -EIO; | |
283 | + } | |
284 | + | |
285 | + return 0; | |
286 | +} |