xref: /rk3399_rockchip-uboot/drivers/misc/fsl_iim.c (revision 0f67e09e9ef354ae2d282091adb3dc531f2aef7d)
1*0f67e09eSBenoît Thébaudeau /*
2*0f67e09eSBenoît Thébaudeau  * (C) Copyright 2009-2013 ADVANSEE
3*0f67e09eSBenoît Thébaudeau  * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
4*0f67e09eSBenoît Thébaudeau  *
5*0f67e09eSBenoît Thébaudeau  * Based on the mpc512x iim code:
6*0f67e09eSBenoît Thébaudeau  * Copyright 2008 Silicon Turnkey Express, Inc.
7*0f67e09eSBenoît Thébaudeau  * Martha Marx <mmarx@silicontkx.com>
8*0f67e09eSBenoît Thébaudeau  *
9*0f67e09eSBenoît Thébaudeau  * See file CREDITS for list of people who contributed to this
10*0f67e09eSBenoît Thébaudeau  * project.
11*0f67e09eSBenoît Thébaudeau  *
12*0f67e09eSBenoît Thébaudeau  * This program is free software; you can redistribute it and/or
13*0f67e09eSBenoît Thébaudeau  * modify it under the terms of the GNU General Public License as
14*0f67e09eSBenoît Thébaudeau  * published by the Free Software Foundation; either version 2 of
15*0f67e09eSBenoît Thébaudeau  * the License, or (at your option) any later version.
16*0f67e09eSBenoît Thébaudeau  *
17*0f67e09eSBenoît Thébaudeau  * This program is distributed in the hope that it will be useful,
18*0f67e09eSBenoît Thébaudeau  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19*0f67e09eSBenoît Thébaudeau  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20*0f67e09eSBenoît Thébaudeau  * GNU General Public License for more details.
21*0f67e09eSBenoît Thébaudeau  *
22*0f67e09eSBenoît Thébaudeau  * You should have received a copy of the GNU General Public License
23*0f67e09eSBenoît Thébaudeau  * along with this program; if not, write to the Free Software
24*0f67e09eSBenoît Thébaudeau  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25*0f67e09eSBenoît Thébaudeau  * MA 02111-1307 USA
26*0f67e09eSBenoît Thébaudeau  */
27*0f67e09eSBenoît Thébaudeau 
28*0f67e09eSBenoît Thébaudeau #include <common.h>
29*0f67e09eSBenoît Thébaudeau #include <fuse.h>
30*0f67e09eSBenoît Thébaudeau #include <asm/errno.h>
31*0f67e09eSBenoît Thébaudeau #include <asm/io.h>
32*0f67e09eSBenoît Thébaudeau #ifndef CONFIG_MPC512X
33*0f67e09eSBenoît Thébaudeau #include <asm/arch/imx-regs.h>
34*0f67e09eSBenoît Thébaudeau #endif
35*0f67e09eSBenoît Thébaudeau 
36*0f67e09eSBenoît Thébaudeau /* FSL IIM-specific constants */
37*0f67e09eSBenoît Thébaudeau #define STAT_BUSY		0x80
38*0f67e09eSBenoît Thébaudeau #define STAT_PRGD		0x02
39*0f67e09eSBenoît Thébaudeau #define STAT_SNSD		0x01
40*0f67e09eSBenoît Thébaudeau 
41*0f67e09eSBenoît Thébaudeau #define STATM_PRGD_M		0x02
42*0f67e09eSBenoît Thébaudeau #define STATM_SNSD_M		0x01
43*0f67e09eSBenoît Thébaudeau 
44*0f67e09eSBenoît Thébaudeau #define ERR_PRGE		0x80
45*0f67e09eSBenoît Thébaudeau #define ERR_WPE			0x40
46*0f67e09eSBenoît Thébaudeau #define ERR_OPE			0x20
47*0f67e09eSBenoît Thébaudeau #define ERR_RPE			0x10
48*0f67e09eSBenoît Thébaudeau #define ERR_WLRE		0x08
49*0f67e09eSBenoît Thébaudeau #define ERR_SNSE		0x04
50*0f67e09eSBenoît Thébaudeau #define ERR_PARITYE		0x02
51*0f67e09eSBenoît Thébaudeau 
52*0f67e09eSBenoît Thébaudeau #define EMASK_PRGE_M		0x80
53*0f67e09eSBenoît Thébaudeau #define EMASK_WPE_M		0x40
54*0f67e09eSBenoît Thébaudeau #define EMASK_OPE_M		0x20
55*0f67e09eSBenoît Thébaudeau #define EMASK_RPE_M		0x10
56*0f67e09eSBenoît Thébaudeau #define EMASK_WLRE_M		0x08
57*0f67e09eSBenoît Thébaudeau #define EMASK_SNSE_M		0x04
58*0f67e09eSBenoît Thébaudeau #define EMASK_PARITYE_M		0x02
59*0f67e09eSBenoît Thébaudeau 
60*0f67e09eSBenoît Thébaudeau #define FCTL_DPC		0x80
61*0f67e09eSBenoît Thébaudeau #define FCTL_PRG_LENGTH_MASK	0x70
62*0f67e09eSBenoît Thébaudeau #define FCTL_ESNS_N		0x08
63*0f67e09eSBenoît Thébaudeau #define FCTL_ESNS_0		0x04
64*0f67e09eSBenoît Thébaudeau #define FCTL_ESNS_1		0x02
65*0f67e09eSBenoît Thébaudeau #define FCTL_PRG		0x01
66*0f67e09eSBenoît Thébaudeau 
67*0f67e09eSBenoît Thébaudeau #define UA_A_BANK_MASK		0x38
68*0f67e09eSBenoît Thébaudeau #define UA_A_ROWH_MASK		0x07
69*0f67e09eSBenoît Thébaudeau 
70*0f67e09eSBenoît Thébaudeau #define LA_A_ROWL_MASK		0xf8
71*0f67e09eSBenoît Thébaudeau #define LA_A_BIT_MASK		0x07
72*0f67e09eSBenoît Thébaudeau 
73*0f67e09eSBenoît Thébaudeau #define PREV_PROD_REV_MASK	0xf8
74*0f67e09eSBenoît Thébaudeau #define PREV_PROD_VT_MASK	0x07
75*0f67e09eSBenoît Thébaudeau 
76*0f67e09eSBenoît Thébaudeau /* Select the correct accessors depending on endianness */
77*0f67e09eSBenoît Thébaudeau #if __BYTE_ORDER == __LITTLE_ENDIAN
78*0f67e09eSBenoît Thébaudeau #define iim_read32		in_le32
79*0f67e09eSBenoît Thébaudeau #define iim_write32		out_le32
80*0f67e09eSBenoît Thébaudeau #define iim_clrsetbits32	clrsetbits_le32
81*0f67e09eSBenoît Thébaudeau #define iim_clrbits32		clrbits_le32
82*0f67e09eSBenoît Thébaudeau #define iim_setbits32		setbits_le32
83*0f67e09eSBenoît Thébaudeau #elif __BYTE_ORDER == __BIG_ENDIAN
84*0f67e09eSBenoît Thébaudeau #define iim_read32		in_be32
85*0f67e09eSBenoît Thébaudeau #define iim_write32		out_be32
86*0f67e09eSBenoît Thébaudeau #define iim_clrsetbits32	clrsetbits_be32
87*0f67e09eSBenoît Thébaudeau #define iim_clrbits32		clrbits_be32
88*0f67e09eSBenoît Thébaudeau #define iim_setbits32		setbits_be32
89*0f67e09eSBenoît Thébaudeau #else
90*0f67e09eSBenoît Thébaudeau #error Endianess is not defined: please fix to continue
91*0f67e09eSBenoît Thébaudeau #endif
92*0f67e09eSBenoît Thébaudeau 
93*0f67e09eSBenoît Thébaudeau /* IIM control registers */
94*0f67e09eSBenoît Thébaudeau struct fsl_iim {
95*0f67e09eSBenoît Thébaudeau 	u32 stat;
96*0f67e09eSBenoît Thébaudeau 	u32 statm;
97*0f67e09eSBenoît Thébaudeau 	u32 err;
98*0f67e09eSBenoît Thébaudeau 	u32 emask;
99*0f67e09eSBenoît Thébaudeau 	u32 fctl;
100*0f67e09eSBenoît Thébaudeau 	u32 ua;
101*0f67e09eSBenoît Thébaudeau 	u32 la;
102*0f67e09eSBenoît Thébaudeau 	u32 sdat;
103*0f67e09eSBenoît Thébaudeau 	u32 prev;
104*0f67e09eSBenoît Thébaudeau 	u32 srev;
105*0f67e09eSBenoît Thébaudeau 	u32 prg_p;
106*0f67e09eSBenoît Thébaudeau 	u32 scs[0x1f5];
107*0f67e09eSBenoît Thébaudeau 	struct {
108*0f67e09eSBenoît Thébaudeau 		u32 word[0x100];
109*0f67e09eSBenoît Thébaudeau 	} bank[8];
110*0f67e09eSBenoît Thébaudeau };
111*0f67e09eSBenoît Thébaudeau 
112*0f67e09eSBenoît Thébaudeau static int prepare_access(struct fsl_iim **regs, u32 bank, u32 word, int assert,
113*0f67e09eSBenoît Thébaudeau 				const char *caller)
114*0f67e09eSBenoît Thébaudeau {
115*0f67e09eSBenoît Thébaudeau 	*regs = (struct fsl_iim *)IIM_BASE_ADDR;
116*0f67e09eSBenoît Thébaudeau 
117*0f67e09eSBenoît Thébaudeau 	if (bank >= ARRAY_SIZE((*regs)->bank) ||
118*0f67e09eSBenoît Thébaudeau 			word >= ARRAY_SIZE((*regs)->bank[0].word) ||
119*0f67e09eSBenoît Thébaudeau 			!assert) {
120*0f67e09eSBenoît Thébaudeau 		printf("fsl_iim %s(): Invalid argument\n", caller);
121*0f67e09eSBenoît Thébaudeau 		return -EINVAL;
122*0f67e09eSBenoît Thébaudeau 	}
123*0f67e09eSBenoît Thébaudeau 
124*0f67e09eSBenoît Thébaudeau 	return 0;
125*0f67e09eSBenoît Thébaudeau }
126*0f67e09eSBenoît Thébaudeau 
127*0f67e09eSBenoît Thébaudeau static void clear_status(struct fsl_iim *regs)
128*0f67e09eSBenoît Thébaudeau {
129*0f67e09eSBenoît Thébaudeau 	iim_setbits32(&regs->stat, 0);
130*0f67e09eSBenoît Thébaudeau 	iim_setbits32(&regs->err, 0);
131*0f67e09eSBenoît Thébaudeau }
132*0f67e09eSBenoît Thébaudeau 
133*0f67e09eSBenoît Thébaudeau static void finish_access(struct fsl_iim *regs, u32 *stat, u32 *err)
134*0f67e09eSBenoît Thébaudeau {
135*0f67e09eSBenoît Thébaudeau 	*stat = iim_read32(&regs->stat);
136*0f67e09eSBenoît Thébaudeau 	*err = iim_read32(&regs->err);
137*0f67e09eSBenoît Thébaudeau 	clear_status(regs);
138*0f67e09eSBenoît Thébaudeau }
139*0f67e09eSBenoît Thébaudeau 
140*0f67e09eSBenoît Thébaudeau static int prepare_read(struct fsl_iim **regs, u32 bank, u32 word, u32 *val,
141*0f67e09eSBenoît Thébaudeau 			const char *caller)
142*0f67e09eSBenoît Thébaudeau {
143*0f67e09eSBenoît Thébaudeau 	int ret;
144*0f67e09eSBenoît Thébaudeau 
145*0f67e09eSBenoît Thébaudeau 	ret = prepare_access(regs, bank, word, val != NULL, caller);
146*0f67e09eSBenoît Thébaudeau 	if (ret)
147*0f67e09eSBenoît Thébaudeau 		return ret;
148*0f67e09eSBenoît Thébaudeau 
149*0f67e09eSBenoît Thébaudeau 	clear_status(*regs);
150*0f67e09eSBenoît Thébaudeau 
151*0f67e09eSBenoît Thébaudeau 	return 0;
152*0f67e09eSBenoît Thébaudeau }
153*0f67e09eSBenoît Thébaudeau 
154*0f67e09eSBenoît Thébaudeau int fuse_read(u32 bank, u32 word, u32 *val)
155*0f67e09eSBenoît Thébaudeau {
156*0f67e09eSBenoît Thébaudeau 	struct fsl_iim *regs;
157*0f67e09eSBenoît Thébaudeau 	u32 stat, err;
158*0f67e09eSBenoît Thébaudeau 	int ret;
159*0f67e09eSBenoît Thébaudeau 
160*0f67e09eSBenoît Thébaudeau 	ret = prepare_read(&regs, bank, word, val, __func__);
161*0f67e09eSBenoît Thébaudeau 	if (ret)
162*0f67e09eSBenoît Thébaudeau 		return ret;
163*0f67e09eSBenoît Thébaudeau 
164*0f67e09eSBenoît Thébaudeau 	*val = iim_read32(&regs->bank[bank].word[word]);
165*0f67e09eSBenoît Thébaudeau 	finish_access(regs, &stat, &err);
166*0f67e09eSBenoît Thébaudeau 
167*0f67e09eSBenoît Thébaudeau 	if (err & ERR_RPE) {
168*0f67e09eSBenoît Thébaudeau 		puts("fsl_iim fuse_read(): Read protect error\n");
169*0f67e09eSBenoît Thébaudeau 		return -EIO;
170*0f67e09eSBenoît Thébaudeau 	}
171*0f67e09eSBenoît Thébaudeau 
172*0f67e09eSBenoît Thébaudeau 	return 0;
173*0f67e09eSBenoît Thébaudeau }
174*0f67e09eSBenoît Thébaudeau 
175*0f67e09eSBenoît Thébaudeau static void direct_access(struct fsl_iim *regs, u32 bank, u32 word, u32 bit,
176*0f67e09eSBenoît Thébaudeau 				u32 fctl, u32 *stat, u32 *err)
177*0f67e09eSBenoît Thébaudeau {
178*0f67e09eSBenoît Thébaudeau 	iim_write32(&regs->ua, bank << 3 | word >> 5);
179*0f67e09eSBenoît Thébaudeau 	iim_write32(&regs->la, (word << 3 | bit) & 0xff);
180*0f67e09eSBenoît Thébaudeau 	if (fctl == FCTL_PRG)
181*0f67e09eSBenoît Thébaudeau 		iim_write32(&regs->prg_p, 0xaa);
182*0f67e09eSBenoît Thébaudeau 	iim_setbits32(&regs->fctl, fctl);
183*0f67e09eSBenoît Thébaudeau 	while (iim_read32(&regs->stat) & STAT_BUSY)
184*0f67e09eSBenoît Thébaudeau 		udelay(20);
185*0f67e09eSBenoît Thébaudeau 	finish_access(regs, stat, err);
186*0f67e09eSBenoît Thébaudeau }
187*0f67e09eSBenoît Thébaudeau 
188*0f67e09eSBenoît Thébaudeau int fuse_sense(u32 bank, u32 word, u32 *val)
189*0f67e09eSBenoît Thébaudeau {
190*0f67e09eSBenoît Thébaudeau 	struct fsl_iim *regs;
191*0f67e09eSBenoît Thébaudeau 	u32 stat, err;
192*0f67e09eSBenoît Thébaudeau 	int ret;
193*0f67e09eSBenoît Thébaudeau 
194*0f67e09eSBenoît Thébaudeau 	ret = prepare_read(&regs, bank, word, val, __func__);
195*0f67e09eSBenoît Thébaudeau 	if (ret)
196*0f67e09eSBenoît Thébaudeau 		return ret;
197*0f67e09eSBenoît Thébaudeau 
198*0f67e09eSBenoît Thébaudeau 	direct_access(regs, bank, word, 0, FCTL_ESNS_N, &stat, &err);
199*0f67e09eSBenoît Thébaudeau 
200*0f67e09eSBenoît Thébaudeau 	if (err & ERR_SNSE) {
201*0f67e09eSBenoît Thébaudeau 		puts("fsl_iim fuse_sense(): Explicit sense cycle error\n");
202*0f67e09eSBenoît Thébaudeau 		return -EIO;
203*0f67e09eSBenoît Thébaudeau 	}
204*0f67e09eSBenoît Thébaudeau 
205*0f67e09eSBenoît Thébaudeau 	if (!(stat & STAT_SNSD)) {
206*0f67e09eSBenoît Thébaudeau 		puts("fsl_iim fuse_sense(): Explicit sense cycle did not complete\n");
207*0f67e09eSBenoît Thébaudeau 		return -EIO;
208*0f67e09eSBenoît Thébaudeau 	}
209*0f67e09eSBenoît Thébaudeau 
210*0f67e09eSBenoît Thébaudeau 	*val = iim_read32(&regs->sdat);
211*0f67e09eSBenoît Thébaudeau 	return 0;
212*0f67e09eSBenoît Thébaudeau }
213*0f67e09eSBenoît Thébaudeau 
214*0f67e09eSBenoît Thébaudeau static int prog_bit(struct fsl_iim *regs, u32 bank, u32 word, u32 bit)
215*0f67e09eSBenoît Thébaudeau {
216*0f67e09eSBenoît Thébaudeau 	u32 stat, err;
217*0f67e09eSBenoît Thébaudeau 
218*0f67e09eSBenoît Thébaudeau 	clear_status(regs);
219*0f67e09eSBenoît Thébaudeau 	direct_access(regs, bank, word, bit, FCTL_PRG, &stat, &err);
220*0f67e09eSBenoît Thébaudeau 	iim_write32(&regs->prg_p, 0x00);
221*0f67e09eSBenoît Thébaudeau 
222*0f67e09eSBenoît Thébaudeau 	if (err & ERR_PRGE) {
223*0f67e09eSBenoît Thébaudeau 		puts("fsl_iim fuse_prog(): Program error\n");
224*0f67e09eSBenoît Thébaudeau 		return -EIO;
225*0f67e09eSBenoît Thébaudeau 	}
226*0f67e09eSBenoît Thébaudeau 
227*0f67e09eSBenoît Thébaudeau 	if (err & ERR_WPE) {
228*0f67e09eSBenoît Thébaudeau 		puts("fsl_iim fuse_prog(): Write protect error\n");
229*0f67e09eSBenoît Thébaudeau 		return -EIO;
230*0f67e09eSBenoît Thébaudeau 	}
231*0f67e09eSBenoît Thébaudeau 
232*0f67e09eSBenoît Thébaudeau 	if (!(stat & STAT_PRGD)) {
233*0f67e09eSBenoît Thébaudeau 		puts("fsl_iim fuse_prog(): Program did not complete\n");
234*0f67e09eSBenoît Thébaudeau 		return -EIO;
235*0f67e09eSBenoît Thébaudeau 	}
236*0f67e09eSBenoît Thébaudeau 
237*0f67e09eSBenoît Thébaudeau 	return 0;
238*0f67e09eSBenoît Thébaudeau }
239*0f67e09eSBenoît Thébaudeau 
240*0f67e09eSBenoît Thébaudeau static int prepare_write(struct fsl_iim **regs, u32 bank, u32 word, u32 val,
241*0f67e09eSBenoît Thébaudeau 				const char *caller)
242*0f67e09eSBenoît Thébaudeau {
243*0f67e09eSBenoît Thébaudeau 	return prepare_access(regs, bank, word, !(val & ~0xff), caller);
244*0f67e09eSBenoît Thébaudeau }
245*0f67e09eSBenoît Thébaudeau 
246*0f67e09eSBenoît Thébaudeau int fuse_prog(u32 bank, u32 word, u32 val)
247*0f67e09eSBenoît Thébaudeau {
248*0f67e09eSBenoît Thébaudeau 	struct fsl_iim *regs;
249*0f67e09eSBenoît Thébaudeau 	u32 bit;
250*0f67e09eSBenoît Thébaudeau 	int ret;
251*0f67e09eSBenoît Thébaudeau 
252*0f67e09eSBenoît Thébaudeau 	ret = prepare_write(&regs, bank, word, val, __func__);
253*0f67e09eSBenoît Thébaudeau 	if (ret)
254*0f67e09eSBenoît Thébaudeau 		return ret;
255*0f67e09eSBenoît Thébaudeau 
256*0f67e09eSBenoît Thébaudeau 	for (bit = 0; val; bit++, val >>= 1)
257*0f67e09eSBenoît Thébaudeau 		if (val & 0x01) {
258*0f67e09eSBenoît Thébaudeau 			ret = prog_bit(regs, bank, word, bit);
259*0f67e09eSBenoît Thébaudeau 			if (ret)
260*0f67e09eSBenoît Thébaudeau 				return ret;
261*0f67e09eSBenoît Thébaudeau 		}
262*0f67e09eSBenoît Thébaudeau 
263*0f67e09eSBenoît Thébaudeau 	return 0;
264*0f67e09eSBenoît Thébaudeau }
265*0f67e09eSBenoît Thébaudeau 
266*0f67e09eSBenoît Thébaudeau int fuse_override(u32 bank, u32 word, u32 val)
267*0f67e09eSBenoît Thébaudeau {
268*0f67e09eSBenoît Thébaudeau 	struct fsl_iim *regs;
269*0f67e09eSBenoît Thébaudeau 	u32 stat, err;
270*0f67e09eSBenoît Thébaudeau 	int ret;
271*0f67e09eSBenoît Thébaudeau 
272*0f67e09eSBenoît Thébaudeau 	ret = prepare_write(&regs, bank, word, val, __func__);
273*0f67e09eSBenoît Thébaudeau 	if (ret)
274*0f67e09eSBenoît Thébaudeau 		return ret;
275*0f67e09eSBenoît Thébaudeau 
276*0f67e09eSBenoît Thébaudeau 	clear_status(regs);
277*0f67e09eSBenoît Thébaudeau 	iim_write32(&regs->bank[bank].word[word], val);
278*0f67e09eSBenoît Thébaudeau 	finish_access(regs, &stat, &err);
279*0f67e09eSBenoît Thébaudeau 
280*0f67e09eSBenoît Thébaudeau 	if (err & ERR_OPE) {
281*0f67e09eSBenoît Thébaudeau 		puts("fsl_iim fuse_override(): Override protect error\n");
282*0f67e09eSBenoît Thébaudeau 		return -EIO;
283*0f67e09eSBenoît Thébaudeau 	}
284*0f67e09eSBenoît Thébaudeau 
285*0f67e09eSBenoît Thébaudeau 	return 0;
286*0f67e09eSBenoît Thébaudeau }
287