u-boot/arch/powerpc/cpu/mpc512x/iim.c
Stefan Roese a47a12becf Move arch/ppc to arch/powerpc
As discussed on the list, move "arch/ppc" to "arch/powerpc" to
better match the Linux directory structure.

Please note that this patch also changes the "ppc" target in
MAKEALL to "powerpc" to match this new infrastructure. But "ppc"
is kept as an alias for now, to not break compatibility with
scripts using this name.

Signed-off-by: Stefan Roese <sr@denx.de>
Acked-by: Wolfgang Denk <wd@denx.de>
Acked-by: Detlev Zundel <dzu@denx.de>
Acked-by: Kim Phillips <kim.phillips@freescale.com>
Cc: Peter Tyser <ptyser@xes-inc.com>
Cc: Anatolij Gustschin <agust@denx.de>
2010-04-21 23:42:38 +02:00

394 lines
10 KiB
C

/*
* Copyright 2008 Silicon Turnkey Express, Inc.
* Martha Marx <mmarx@silicontkx.com>
*
* ADS5121 IIM (Fusebox) Interface
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <command.h>
#include <asm/io.h>
#ifdef CONFIG_CMD_FUSE
DECLARE_GLOBAL_DATA_PTR;
static char cur_bank = '1';
char *iim_err_msg(u32 err)
{
static char *IIM_errs[] = {
"Parity Error in cache",
"Explicit Sense Cycle Error",
"Write to Locked Register Error",
"Read Protect Error",
"Override Protect Error",
"Write Protect Error"};
int i;
if (!err)
return "";
for (i = 1; i < 8; i++)
if (err & (1 << i))
printf("IIM - %s\n", IIM_errs[i-1]);
return "";
}
int in_range(int n, int min, int max, char *err, char *usg)
{
if (n > max || n < min) {
printf(err);
printf("Usage:\n%s\n", usg);
return 0;
}
return 1;
}
int ads5121_fuse_read(int bank, int fstart, int num)
{
iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
u32 *iim_fb, dummy;
int f, ctr;
out_be32(&iim->err, in_be32(&iim->err));
if (bank == 0)
iim_fb = (u32 *)&(iim->fbac0);
else
iim_fb = (u32 *)&(iim->fbac1);
/* try a read to see if Read Protect is set */
dummy = in_be32(&iim_fb[0]);
if (in_be32(&iim->err) & IIM_ERR_RPE) {
printf("\tRead protect fuse is set\n");
out_be32(&iim->err, IIM_ERR_RPE);
return 0;
}
printf("Reading Bank %d cache\n", bank);
for (f = fstart, ctr = 0; num > 0; ctr++, num--, f++) {
if (ctr % 4 == 0)
printf("F%2d:", f);
printf("\t%#04x", (u8)(iim_fb[f]));
if (ctr % 4 == 3)
printf("\n");
}
if (ctr % 4 != 0)
printf("\n");
}
int ads5121_fuse_override(int bank, int f, u8 val)
{
iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
u32 *iim_fb;
u32 iim_stat;
int i;
out_be32(&iim->err, in_be32(&iim->err));
if (bank == 0)
iim_fb = (u32 *)&(iim->fbac0);
else
iim_fb = (u32 *)&(iim->fbac1);
/* try a read to see if Read Protect is set */
iim_stat = in_be32(&iim_fb[0]);
if (in_be32(&iim->err) & IIM_ERR_RPE) {
printf("Read protect fuse is set on bank %d;"
"Override protect may also be set\n", bank);
printf("An attempt will be made to override\n");
out_be32(&iim->err, IIM_ERR_RPE);
}
if (iim_stat & IIM_FBAC_FBOP) {
printf("Override protect fuse is set on bank %d\n", bank);
return 1;
}
if (f > IIM_FMAX) /* reset the entire bank */
for (i = 0; i < IIM_FMAX + 1; i++)
out_be32(&iim_fb[i], 0);
else
out_be32(&iim_fb[f], val);
return 0;
}
int ads5121_fuse_prog(cmd_tbl_t *cmdtp, int bank, char *fuseno_bitno)
{
iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
int f, i, bitno;
u32 stat, err;
f = simple_strtol(fuseno_bitno, NULL, 10);
if (f == 0 && fuseno_bitno[0] != '0')
f = -1;
if (!in_range(f, 0, IIM_FMAX,
"<frow> must be between 0-31\n\n", cmdtp->usage))
return 1;
bitno = -1;
for (i = 0; i < 6; i++) {
if (fuseno_bitno[i] == '_') {
bitno = simple_strtol(&(fuseno_bitno[i+1]), NULL, 10);
if (bitno == 0 && fuseno_bitno[i+1] != '0')
bitno = -1;
break;
}
}
if (!in_range(bitno, 0, 7, "Bit number ranges from 0-7\n"
"Example of <frow_bitno>: \"18_4\" sets bit 4 of row 18\n",
cmdtp->usage))
return 1;
out_be32(&iim->err, in_be32(&iim->err));
out_be32(&iim->prg_p, IIM_PRG_P_SET);
out_be32(&iim->ua, IIM_SET_UA(bank, f));
out_be32(&iim->la, IIM_SET_LA(f, bitno));
#ifdef DEBUG
printf("Programming disabled with DEBUG defined \n");
printf(""Set up to pro
printf("iim.ua = %x; iim.la = %x\n", iim->ua, iim->la);
#else
out_be32(&iim->fctl, IIM_FCTL_PROG_PULSE | IIM_FCTL_PROG);
do
udelay(20);
while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY);
out_be32(&iim->prg_p, 0);
err = in_be32(&iim->err);
if (stat & IIM_STAT_PRGD) {
if (!(err & (IIM_ERR_WPE | IIM_ERR_WPE))) {
printf("Fuse is successfully set");
if (err)
printf(" - however there are other errors");
printf("\n");
}
iim->stat = 0;
}
if (err) {
iim_err_msg(err);
out_be32(&iim->err, in_be32(&iim->err));
}
#endif
}
int ads5121_fuse_sense(int bank, int fstart, int num)
{
iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
u32 iim_fbac;
u32 stat, err, err_hold = 0;
int f, ctr;
out_be32(&iim->err, in_be32(&iim->err));
if (bank == 0)
iim_fbac = in_be32(&iim->fbac0);
else
iim_fbac = in_be32(&iim->fbac1);
if (iim_fbac & IIM_FBAC_FBESP) {
printf("\tSense Protect disallows this operation\n");
out_be32(&iim->err, IIM_FBAC_FBESP);
return 1;
}
err = in_be32(&iim->err);
if (err) {
iim_err_msg(err);
err_hold |= err;
}
if (err & IIM_ERR_RPE)
printf("\tRead protect fuse is set; "
"Sense Protect may be set but will be attempted\n");
if (err)
out_be32(&iim->err, err);
printf("Sensing fuse(s) on Bank %d\n", bank);
for (f = fstart, ctr = 0; num > 0; ctr++, f++, num--) {
out_be32(&iim->ua, IIM_SET_UA(bank, f));
out_be32(&iim->la, IIM_SET_LA(f, 0));
out_be32(&iim->fctl, IIM_FCTL_ESNS_N);
do
udelay(20);
while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY);
err = in_be32(&iim->err);
if (err & IIM_ERR_SNSE) {
iim_err_msg(err);
out_be32(&iim->err, IIM_ERR_SNSE);
return 1;
}
if (stat & IIM_STAT_SNSD) {
out_be32(&iim->stat, 0);
if (ctr % 4 == 0)
printf("F%2d:", f);
printf("\t%#04x", (u8)iim->sdat);
if (ctr % 4 == 3)
printf("\n");
}
if (err) {
err_hold |= err;
out_be32(&iim->err, err);
}
}
if (ctr % 4 != 0)
printf("\n");
if (err_hold)
iim_err_msg(err_hold);
return 0;
}
int ads5121_fuse_stat(int bank)
{
iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim;
u32 iim_fbac;
u32 err;
out_be32(&iim->err, in_be32(&iim->err));
if (bank == 0)
iim_fbac = in_be32(&iim->fbac0);
else
iim_fbac = in_be32(&iim->fbac1);
err = in_be32(&iim->err);
if (err)
iim_err_msg(err);
if (err & IIM_ERR_RPE || iim_fbac & IIM_FBAC_FBRP) {
if (iim_fbac == 0)
printf("Since protection settings can't be read - "
"try sensing fuse row 0;\n");
return 0;
}
if (iim_fbac & IIM_PROTECTION)
printf("Protection Fuses Bank %d = %#04x:\n", bank, iim_fbac);
else if (!(err & IIM_ERR_RPE))
printf("No Protection fuses are set\n");
if (iim_fbac & IIM_FBAC_FBWP)
printf("\tWrite Protect fuse is set\n");
if (iim_fbac & IIM_FBAC_FBOP)
printf("\tOverride Protect fuse is set\n");
if (iim_fbac & IIM_FBAC_FBESP)
printf("\tSense Protect Fuse is set\n");
out_be32(&iim->err, in_be32(&iim->err));
return 0;
}
int do_ads5121_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int frow, n, v, bank;
if (cur_bank == '0')
bank = 0;
else
bank = 1;
switch (argc) {
case 0:
case 1:
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
case 2:
if (strncmp(argv[1], "stat", 4) == 0)
return ads5121_fuse_stat(bank);
if (strncmp(argv[1], "read", 4) == 0)
return ads5121_fuse_read(bank, 0, IIM_FMAX + 1);
if (strncmp(argv[1], "sense", 5) == 0)
return ads5121_fuse_sense(bank, 0, IIM_FMAX + 1);
if (strncmp(argv[1], "ovride", 6) == 0)
return ads5121_fuse_override(bank, IIM_FMAX + 1, 0);
if (strncmp(argv[1], "bank", 4) == 0) {
printf("Active Fuse Bank is %c\n", cur_bank);
return 0;
}
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
case 3:
if (strncmp(argv[1], "bank", 4) == 0) {
if (argv[2][0] == '0')
cur_bank = '0';
else if (argv[2][0] == '1')
cur_bank = '1';
else {
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
}
printf("Setting Active Fuse Bank to %c\n", cur_bank);
return 0;
}
if (strncmp(argv[1], "prog", 4) == 0)
return ads5121_fuse_prog(cmdtp, bank, argv[2]);
frow = (int)simple_strtol(argv[2], NULL, 10);
if (frow == 0 && argv[2][0] != '0')
frow = -1;
if (!in_range(frow, 0, IIM_FMAX,
"<frow> must be between 0-31\n\n", cmdtp->usage))
return 1;
if (strncmp(argv[1], "read", 4) == 0)
return ads5121_fuse_read(bank, frow, 1);
if (strncmp(argv[1], "ovride", 6) == 0)
return ads5121_fuse_override(bank, frow, 0);
if (strncmp(argv[1], "sense", 5) == 0)
return ads5121_fuse_sense(bank, frow, 1);
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
case 4:
frow = (int)simple_strtol(argv[2], NULL, 10);
if (frow == 0 && argv[2][0] != '0')
frow = -1;
if (!in_range(frow, 0, IIM_FMAX,
"<frow> must be between 0-31\n\n", cmdtp->usage))
return 1;
if (strncmp(argv[1], "read", 4) == 0) {
n = (int)simple_strtol(argv[3], NULL, 10);
if (!in_range(frow + n, frow + 1, IIM_FMAX + 1,
"<frow>+<n> must be between 1-32\n\n",
cmdtp->usage))
return 1;
return ads5121_fuse_read(bank, frow, n);
}
if (strncmp(argv[1], "ovride", 6) == 0) {
v = (int)simple_strtol(argv[3], NULL, 10);
return ads5121_fuse_override(bank, frow, v);
}
if (strncmp(argv[1], "sense", 5) == 0) {
n = (int)simple_strtol(argv[3], NULL, 10);
if (!in_range(frow + n, frow + 1, IIM_FMAX + 1,
"<frow>+<n> must be between 1-32\n\n",
cmdtp->usage))
return 1;
return ads5121_fuse_sense(bank, frow, n);
}
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
default: /* at least 5 args */
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
}
}
U_BOOT_CMD(
fuse, CONFIG_SYS_MAXARGS, 0, do_ads5121_fuse,
" - Read, Sense, Override or Program Fuses\n",
"bank <n> - sets active Fuse Bank to 0 or 1\n"
" no args shows current active bank\n"
"fuse stat - print active fuse bank's protection status\n"
"fuse read [<frow> [<n>]] - print <n> fuse rows starting at <frow>\n"
" no args to print entire bank's fuses\n"
"fuse ovride [<frow> [<v>]]- override fuses at <frow> with <v>\n"
" no <v> defaults to 0 for the row\n"
" no args resets entire bank to 0\n"
" NOTE - settings persist until hard reset\n"
"fuse sense [<frow>] - senses current fuse at <frow>\n"
" no args for entire bank\n"
"fuse prog <frow_bit> - program fuse at row <frow>, bit <_bit>\n"
" <frow> is 0-31, <bit> is 0-7; eg. 13_2 \n"
" WARNING - this is permanent"
);
#endif /* CONFIG_CMD_FUSE */