summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-12-17 16:53:07 +0100
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-12-17 16:53:07 +0100
commitcb5473205206c7f14cbb1e747f28ec75b48826e2 (patch)
tree8f4808d60917100b18a10b05230f7638a0a9bbcc /drivers
parentbaf449fc5ff96f071bb0e3789fd3265f6d4fd9a0 (diff)
parent92c78a3bbcb2ce508b4bf1c4a1e0940406a024bb (diff)
downloadu-boot-imx-cb5473205206c7f14cbb1e747f28ec75b48826e2.zip
u-boot-imx-cb5473205206c7f14cbb1e747f28ec75b48826e2.tar.gz
u-boot-imx-cb5473205206c7f14cbb1e747f28ec75b48826e2.tar.bz2
Merge branch 'fixes' into cleanups
Conflicts: board/atmel/atngw100/atngw100.c board/atmel/atstk1000/atstk1000.c cpu/at32ap/at32ap700x/gpio.c include/asm-avr32/arch-at32ap700x/clk.h include/configs/atngw100.h include/configs/atstk1002.h include/configs/atstk1003.h include/configs/atstk1004.h include/configs/atstk1006.h include/configs/favr-32-ezkit.h include/configs/hammerhead.h include/configs/mimc200.h
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bios_emulator/Makefile3
-rw-r--r--drivers/bios_emulator/atibios.c5
-rw-r--r--drivers/bios_emulator/besys.c4
-rw-r--r--drivers/bios_emulator/bios.c4
-rw-r--r--drivers/bios_emulator/biosemu.c4
-rw-r--r--drivers/bios_emulator/x86emu/debug.c11
-rw-r--r--drivers/bios_emulator/x86emu/decode.c5
-rw-r--r--drivers/bios_emulator/x86emu/ops.c5
-rw-r--r--drivers/bios_emulator/x86emu/ops2.c5
-rw-r--r--drivers/bios_emulator/x86emu/prim_ops.c5
-rw-r--r--drivers/bios_emulator/x86emu/sys.c5
-rw-r--r--drivers/block/ahci.c2
-rw-r--r--drivers/block/ata_piix.c30
-rw-r--r--drivers/block/ata_piix.h2
-rw-r--r--drivers/block/fsl_sata.c16
-rw-r--r--drivers/block/sata_sil3114.c4
-rw-r--r--drivers/block/sil680.c28
-rw-r--r--drivers/block/sym53c8xx.c6
-rw-r--r--drivers/block/systemace.c28
-rw-r--r--drivers/fpga/ACEX1K.c362
-rw-r--r--drivers/fpga/Makefile58
-rw-r--r--drivers/fpga/altera.c283
-rw-r--r--drivers/fpga/cyclon2.c301
-rw-r--r--drivers/fpga/fpga.c335
-rw-r--r--drivers/fpga/spartan2.c663
-rw-r--r--drivers/fpga/spartan3.c668
-rw-r--r--drivers/fpga/stratixII.c231
-rw-r--r--drivers/fpga/virtex2.c554
-rw-r--r--drivers/fpga/xilinx.c307
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/adm1021.c4
-rw-r--r--drivers/hwmon/ds1621.c9
-rw-r--r--drivers/hwmon/ds1775.c6
-rw-r--r--drivers/hwmon/lm63.c174
-rw-r--r--drivers/hwmon/lm73.c4
-rw-r--r--drivers/hwmon/lm75.c238
-rw-r--r--drivers/hwmon/lm81.c6
-rw-r--r--drivers/i2c/fsl_i2c.c41
-rw-r--r--drivers/i2c/mxc_i2c.c8
-rw-r--r--drivers/i2c/omap1510_i2c.c6
-rw-r--r--drivers/i2c/omap24xx_i2c.c137
-rw-r--r--drivers/i2c/soft_i2c.c131
-rw-r--r--drivers/i2c/tsi108_i2c.c20
-rw-r--r--drivers/input/i8042.c6
-rw-r--r--drivers/input/keyboard.c4
-rw-r--r--drivers/input/ps2ser.c12
-rw-r--r--drivers/misc/fsl_law.c7
-rw-r--r--drivers/misc/ns87308.c72
-rw-r--r--drivers/mmc/atmel_mci.c22
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/cfi_flash.c206
-rw-r--r--drivers/mtd/cfi_mtd.c202
-rw-r--r--drivers/mtd/dataflash.c39
-rw-r--r--drivers/mtd/jedec_flash.c8
-rw-r--r--drivers/mtd/mtdcore.c144
-rw-r--r--drivers/mtd/mtdpart.c540
-rw-r--r--drivers/mtd/mw_eeprom.c2
-rw-r--r--drivers/mtd/nand/diskonchip.c43
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c92
-rw-r--r--drivers/mtd/nand/nand.c18
-rw-r--r--drivers/mtd/nand/nand_base.c141
-rw-r--r--drivers/mtd/nand/nand_bbt.c2
-rw-r--r--drivers/mtd/nand/nand_ecc.c7
-rw-r--r--drivers/mtd/nand/nand_ids.c3
-rw-r--r--drivers/mtd/nand/nand_util.c42
-rw-r--r--drivers/mtd/nand/s3c64xx.c12
-rw-r--r--drivers/mtd/nand_legacy/nand_legacy.c12
-rw-r--r--drivers/mtd/onenand/onenand_base.c2
-rw-r--r--drivers/mtd/onenand/onenand_uboot.c2
-rw-r--r--drivers/mtd/spi/Makefile1
-rw-r--r--drivers/mtd/spi/spi_flash.c5
-rw-r--r--drivers/mtd/spi/spi_flash_internal.h7
-rw-r--r--drivers/mtd/spi/stmicro.c356
-rw-r--r--drivers/mtd/ubi/Makefile51
-rw-r--r--drivers/mtd/ubi/build.c1188
-rw-r--r--drivers/mtd/ubi/crc32.c518
-rw-r--r--drivers/mtd/ubi/crc32defs.h32
-rw-r--r--drivers/mtd/ubi/crc32table.h136
-rw-r--r--drivers/mtd/ubi/debug.c192
-rw-r--r--drivers/mtd/ubi/debug.h152
-rw-r--r--drivers/mtd/ubi/eba.c1256
-rw-r--r--drivers/mtd/ubi/io.c1274
-rw-r--r--drivers/mtd/ubi/kapi.c638
-rw-r--r--drivers/mtd/ubi/misc.c106
-rw-r--r--drivers/mtd/ubi/scan.c1360
-rw-r--r--drivers/mtd/ubi/scan.h165
-rw-r--r--drivers/mtd/ubi/ubi-media.h372
-rw-r--r--drivers/mtd/ubi/ubi.h641
-rw-r--r--drivers/mtd/ubi/upd.c441
-rw-r--r--drivers/mtd/ubi/vmt.c862
-rw-r--r--drivers/mtd/ubi/vtbl.c837
-rw-r--r--drivers/mtd/ubi/wl.c1670
-rw-r--r--drivers/net/4xx_enet.c2126
-rw-r--r--drivers/net/Makefile12
-rw-r--r--drivers/net/ax88180.c727
-rw-r--r--drivers/net/ax88180.h412
-rw-r--r--drivers/net/ax88796.c2
-rw-r--r--drivers/net/bcm570x.c14
-rw-r--r--drivers/net/bfin_mac.c3
-rw-r--r--drivers/net/cs8900.c6
-rw-r--r--drivers/net/dc2114x.c1
-rw-r--r--drivers/net/dm9000x.c2
-rw-r--r--drivers/net/e1000.c2
-rw-r--r--drivers/net/e1000.h1
-rw-r--r--drivers/net/eepro100.c33
-rw-r--r--drivers/net/fsl_mcdmafec.c60
-rw-r--r--drivers/net/greth.c1
-rw-r--r--drivers/net/inca-ip_sw.c3
-rw-r--r--drivers/net/lan91c96.c2
-rw-r--r--drivers/net/macb.c45
-rw-r--r--drivers/net/mcffec.c81
-rw-r--r--drivers/net/mcfmii.c321
-rw-r--r--drivers/net/mpc512x_fec.c3
-rw-r--r--drivers/net/mpc5xxx_fec.c1
-rw-r--r--drivers/net/natsemi.c3
-rw-r--r--drivers/net/ne2000.c719
-rw-r--r--drivers/net/ne2000_base.c757
-rw-r--r--drivers/net/ne2000_base.h36
-rw-r--r--drivers/net/netarm_eth.c4
-rw-r--r--drivers/net/ns7520_eth.c4
-rw-r--r--drivers/net/ns8382x.c3
-rw-r--r--drivers/net/ns9750_eth.c4
-rw-r--r--drivers/net/pcnet.c1
-rw-r--r--drivers/net/phy/miiphybb.c6
-rw-r--r--drivers/net/plb2800_eth.c5
-rw-r--r--drivers/net/rtl8139.c3
-rw-r--r--drivers/net/rtl8169.c1
-rw-r--r--drivers/net/sk98lin/h/skdrv1st.h2
-rw-r--r--drivers/net/sk98lin/h/skgehw.h6
-rw-r--r--drivers/net/sk98lin/skgeinit.c4
-rw-r--r--drivers/net/sk98lin/u-boot_compat.h2
-rw-r--r--drivers/net/sk98lin/uboot_drv.c1
-rw-r--r--drivers/net/smc91111.c2
-rw-r--r--drivers/net/smc911x.c9
-rw-r--r--drivers/net/tigon3.c2
-rw-r--r--drivers/net/tsec.c259
-rw-r--r--drivers/net/tsec.h579
-rw-r--r--drivers/net/tsi108_eth.c3
-rw-r--r--drivers/net/uli526x.c1
-rw-r--r--drivers/net/vsc7385.c12
-rw-r--r--drivers/net/xilinx_emaclite.c4
-rw-r--r--drivers/pci/fsl_pci_init.c162
-rw-r--r--drivers/pci/pci.c39
-rw-r--r--drivers/pci/pci_auto.c96
-rw-r--r--drivers/pci/pci_sh7751.c28
-rw-r--r--drivers/pci/pci_sh7780.c15
-rw-r--r--drivers/pci/tsi108_pci.c38
-rw-r--r--drivers/pci/w83c553f.c4
-rw-r--r--drivers/pcmcia/i82365.c12
-rw-r--r--drivers/pcmcia/marubun_pcmcia.c32
-rw-r--r--drivers/pcmcia/mpc8xx_pcmcia.c32
-rw-r--r--drivers/pcmcia/pxa_pcmcia.c12
-rw-r--r--drivers/pcmcia/ti_pci1410a.c14
-rw-r--r--drivers/pcmcia/tqm8xx_pcmcia.c26
-rw-r--r--drivers/qe/uec.c159
-rw-r--r--drivers/qe/uec.h1
-rw-r--r--drivers/qe/uec_phy.c103
-rw-r--r--drivers/qe/uec_phy.h8
-rw-r--r--drivers/rtc/Makefile6
-rw-r--r--drivers/rtc/bfin_rtc.c25
-rw-r--r--drivers/rtc/ds12887.c4
-rw-r--r--drivers/rtc/ds1302.c5
-rw-r--r--drivers/rtc/ds1306.c22
-rw-r--r--drivers/rtc/ds1307.c14
-rw-r--r--drivers/rtc/ds1337.c12
-rw-r--r--drivers/rtc/ds1374.c22
-rw-r--r--drivers/rtc/ds1556.c6
-rw-r--r--drivers/rtc/ds164x.c6
-rw-r--r--drivers/rtc/ds174x.c6
-rw-r--r--drivers/rtc/ds3231.c8
-rw-r--r--drivers/rtc/isl1208.c8
-rw-r--r--drivers/rtc/m41t11.c52
-rw-r--r--drivers/rtc/m41t60.c24
-rw-r--r--drivers/rtc/m41t62.c12
-rw-r--r--drivers/rtc/m48t35ax.c8
-rw-r--r--drivers/rtc/max6900.c12
-rw-r--r--drivers/rtc/mc13783-rtc.c14
-rw-r--r--drivers/rtc/mc146818.c11
-rw-r--r--drivers/rtc/mcfrtc.c12
-rw-r--r--drivers/rtc/mk48t59.c4
-rw-r--r--drivers/rtc/mpc5xxx.c8
-rw-r--r--drivers/rtc/mpc8xx.c8
-rw-r--r--drivers/rtc/pcf8563.c8
-rw-r--r--[-rwxr-xr-x]drivers/rtc/pl031.c14
-rw-r--r--drivers/rtc/rs5c372.c25
-rw-r--r--drivers/rtc/rx8025.c20
-rw-r--r--drivers/rtc/s3c24x0_rtc.c4
-rw-r--r--drivers/rtc/x1205.c8
-rw-r--r--drivers/serial/Makefile7
-rw-r--r--drivers/serial/mcfuart.c10
-rw-r--r--drivers/serial/ns16550.c4
-rw-r--r--drivers/serial/serial.c42
-rw-r--r--drivers/serial/serial_pl011.c161
-rw-r--r--drivers/serial/serial_pl01x.c (renamed from drivers/serial/serial_pl010.c)88
-rw-r--r--drivers/serial/serial_pl01x.h (renamed from drivers/serial/serial_pl011.h)0
-rw-r--r--drivers/serial/serial_sh.c4
-rw-r--r--drivers/serial/usbtty.c6
-rw-r--r--drivers/serial/usbtty.h31
-rwxr-xr-xdrivers/serial/vcth.c121
-rw-r--r--drivers/spi/mpc8xxx_spi.c4
-rw-r--r--drivers/spi/soft_spi.c10
-rw-r--r--drivers/usb/Makefile19
-rw-r--r--drivers/usb/isp116x-hcd.c8
-rw-r--r--drivers/usb/r8a66597-hcd.c6
-rw-r--r--drivers/usb/sl811_usb.c7
-rw-r--r--drivers/usb/usb_ohci.c1037
-rw-r--r--drivers/usb/usb_ohci.h44
-rw-r--r--drivers/usb/usbdcore_ep0.c4
-rw-r--r--drivers/usb/usbdcore_mpc8xx.c26
-rw-r--r--drivers/usb/usbdcore_omap1510.c8
-rw-r--r--drivers/video/ati_radeon_fb.c6
-rw-r--r--drivers/video/atmel_lcdfb.c6
-rw-r--r--drivers/video/cfb_console.c36
-rw-r--r--drivers/video/ct69000.c2
-rw-r--r--drivers/video/mb862xx.c3
-rw-r--r--drivers/video/smiLynxEM.c6
-rw-r--r--drivers/video/videomodes.c2
-rw-r--r--drivers/video/videomodes.h4
218 files changed, 24358 insertions, 3434 deletions
diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile
index 90c64da..c73da97 100644
--- a/drivers/bios_emulator/Makefile
+++ b/drivers/bios_emulator/Makefile
@@ -6,7 +6,7 @@ X86DIR = x86emu
$(shell mkdir -p $(obj)$(X86DIR))
-COBJS = atibios.o biosemu.o besys.o bios.o \
+COBJS-$(CONFIG_BIOSEMU) = atibios.o biosemu.o besys.o bios.o \
$(X86DIR)/decode.o \
$(X86DIR)/ops2.o \
$(X86DIR)/ops.o \
@@ -14,6 +14,7 @@ COBJS = atibios.o biosemu.o besys.o bios.o \
$(X86DIR)/sys.o \
$(X86DIR)/debug.o
+COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
index 5779f99..d950b18 100644
--- a/drivers/bios_emulator/atibios.c
+++ b/drivers/bios_emulator/atibios.c
@@ -46,9 +46,6 @@
* BIOS in u-boot.
****************************************************************************/
#include <common.h>
-
-#ifdef CONFIG_BIOSEMU
-
#include "biosemui.h"
#include <malloc.h>
@@ -336,5 +333,3 @@ int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp)
*pVGAInfo = VGAInfo;
return true;
}
-
-#endif
diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c
index cb1b0c1..cbc5062 100644
--- a/drivers/bios_emulator/besys.c
+++ b/drivers/bios_emulator/besys.c
@@ -48,9 +48,6 @@
****************************************************************************/
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "biosemui.h"
/*------------------------- Global Variables ------------------------------*/
@@ -721,4 +718,3 @@ void X86API BE_outl(X86EMU_pioAddr port, u32 val)
#endif
LOG_outpd(port, val);
}
-#endif
diff --git a/drivers/bios_emulator/bios.c b/drivers/bios_emulator/bios.c
index d41511c..edda276 100644
--- a/drivers/bios_emulator/bios.c
+++ b/drivers/bios_emulator/bios.c
@@ -42,9 +42,6 @@
****************************************************************************/
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "biosemui.h"
/*----------------------------- Implementation ----------------------------*/
@@ -323,4 +320,3 @@ void _BE_bios_init(u32 * intrTab)
bios_intr_tab[0x6D] = int10;
X86EMU_setupIntrFuncs(bios_intr_tab);
}
-#endif
diff --git a/drivers/bios_emulator/biosemu.c b/drivers/bios_emulator/biosemu.c
index decdb79..d0c6521 100644
--- a/drivers/bios_emulator/biosemu.c
+++ b/drivers/bios_emulator/biosemu.c
@@ -47,9 +47,6 @@
#include <malloc.h>
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "biosemui.h"
BE_sysEnv _BE_env = {{0}};
@@ -372,4 +369,3 @@ int X86API BE_int86x(int intno, RMREGS * in, RMREGS * out, RMSREGS * sregs)
sregs->gs = M.x86.R_GS;
return out->x.ax;
}
-#endif
diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c
index 5cbcc95..241acf3 100644
--- a/drivers/bios_emulator/x86emu/debug.c
+++ b/drivers/bios_emulator/x86emu/debug.c
@@ -39,9 +39,6 @@
#include <stdarg.h>
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "x86emu/x86emui.h"
/*----------------------------- Implementation ----------------------------*/
@@ -50,7 +47,7 @@
static void print_encoded_bytes(u16 s, u16 o);
static void print_decoded_instruction(void);
-static int parse_line(char *s, int *ps, int *n);
+static int x86emu_parse_line(char *s, int *ps, int *n);
/* should look something like debug's output. */
void X86EMU_trace_regs(void)
@@ -257,7 +254,7 @@ void x86emu_single_step(void)
offset = M.x86.saved_ip;
while (!done) {
printk("-");
- cmd = parse_line(s, ps, &ntok);
+ cmd = x86emu_parse_line(s, ps, &ntok);
switch (cmd) {
case 'u':
disassemble_forward(M.x86.saved_cs, (u16) offset, 10);
@@ -331,7 +328,7 @@ int X86EMU_trace_off(void)
return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F);
}
-static int parse_line(char *s, int *ps, int *n)
+static int x86emu_parse_line(char *s, int *ps, int *n)
{
int cmd;
@@ -463,5 +460,3 @@ void x86emu_dump_xregs(void)
printk("NC ");
printk("\n");
}
-
-#endif
diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c
index 7a9a1dd..a782b81 100644
--- a/drivers/bios_emulator/x86emu/decode.c
+++ b/drivers/bios_emulator/x86emu/decode.c
@@ -37,9 +37,6 @@
*
****************************************************************************/
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "x86emu/x86emui.h"
/*----------------------------- Implementation ----------------------------*/
@@ -1145,5 +1142,3 @@ unsigned decode_rmXX_address(int mod, int rm)
return decode_rm01_address(rm);
return decode_rm10_address(rm);
}
-
-#endif
diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c
index 10f2757..d63c99f 100644
--- a/drivers/bios_emulator/x86emu/ops.c
+++ b/drivers/bios_emulator/x86emu/ops.c
@@ -76,9 +76,6 @@
****************************************************************************/
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "x86emu/x86emui.h"
/*----------------------------- Implementation ----------------------------*/
@@ -5434,5 +5431,3 @@ void (*x86emu_optab[256])(u8) __attribute__ ((section(GOT2_TYPE))) =
/* 0xfe */ x86emuOp_opcFE_byte_RM,
/* 0xff */ x86emuOp_opcFF_word_RM,
};
-
-#endif
diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c
index d90d366..51e20e1 100644
--- a/drivers/bios_emulator/x86emu/ops2.c
+++ b/drivers/bios_emulator/x86emu/ops2.c
@@ -45,9 +45,6 @@
****************************************************************************/
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "x86emu/x86emui.h"
/*----------------------------- Implementation ----------------------------*/
@@ -1772,5 +1769,3 @@ void (*x86emu_optab2[256])(u8) __attribute__((section(GOT2_TYPE))) =
/* 0xfe */ x86emuOp2_illegal_op,
/* 0xff */ x86emuOp2_illegal_op,
};
-
-#endif
diff --git a/drivers/bios_emulator/x86emu/prim_ops.c b/drivers/bios_emulator/x86emu/prim_ops.c
index 2a254a4..7553087 100644
--- a/drivers/bios_emulator/x86emu/prim_ops.c
+++ b/drivers/bios_emulator/x86emu/prim_ops.c
@@ -100,9 +100,6 @@
#include <common.h>
#define PRIM_OPS_NO_REDEFINE_ASM
-
-#if defined(CONFIG_BIOSEMU)
-
#include "x86emu/x86emui.h"
/*------------------------- Global Variables ------------------------------*/
@@ -2448,5 +2445,3 @@ DB( if (CHECK_SP_ACCESS())
M.x86.R_SP += 4;
return res;
}
-
-#endif
diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c
index dd44ff1..21f9730 100644
--- a/drivers/bios_emulator/x86emu/sys.c
+++ b/drivers/bios_emulator/x86emu/sys.c
@@ -40,9 +40,6 @@
****************************************************************************/
#include <common.h>
-
-#if defined(CONFIG_BIOSEMU)
-
#include "x86emu/x86emui.h"
/*------------------------- Global Variables ------------------------------*/
@@ -324,5 +321,3 @@ void X86EMU_prepareForInt(int num)
M.x86.R_IP = mem_access_word(num * 4);
M.x86.intr = 0;
}
-
-#endif
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 52fd108..2445e8c 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -676,7 +676,7 @@ void scsi_low_level_init(int busdevfunc)
linkmap = probe_ent->link_port_map;
- for (i = 0; i < CFG_SCSI_MAX_SCSI_ID; i++) {
+ for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
if (((linkmap >> i) & 0x01)) {
if (ahci_port_start((u8) i)) {
printf("Can not start port %d\n", i);
diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c
index 4c26b36..ec37687 100644
--- a/drivers/block/ata_piix.c
+++ b/drivers/block/ata_piix.c
@@ -35,7 +35,7 @@
#include <ide.h>
#include <ata.h>
-extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
extern int curr_device;
#define DEBUG_SATA 0 /*For debug prints set DEBUG_SATA to 1 */
@@ -173,10 +173,10 @@ init_sata (int dev)
iobase4 | ATA_PCI_CTL_OFS;
port[1].ioaddr.bmdma_addr = iobase5 + 0x8;
- for (i = 0; i < CFG_SATA_MAXBUS; i++)
+ for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++)
sata_port (&port[i].ioaddr);
- for (i = 0; i < CFG_SATA_MAXBUS; i++) {
+ for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) {
if (!(sata_bus_probe (i))) {
port[i].port_state = 0;
printf ("SATA#%d port is not present \n", i);
@@ -190,15 +190,15 @@ init_sata (int dev)
}
}
- for (i = 0; i < CFG_SATA_MAXBUS; i++) {
+ for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) {
u8 j, devno;
if (port[i].port_state == 0)
continue;
- for (j = 0; j < CFG_SATA_DEVS_PER_BUS; j++) {
+ for (j = 0; j < CONFIG_SYS_SATA_DEVS_PER_BUS; j++) {
sata_identify (i, j);
set_Feature_cmd (i, j);
- devno = i * CFG_SATA_DEVS_PER_BUS + j;
+ devno = i * CONFIG_SYS_SATA_DEVS_PER_BUS + j;
if ((sata_dev_desc[devno].lba > 0) &&
(sata_dev_desc[devno].blksz > 0)) {
dev_print (&sata_dev_desc[devno]);
@@ -206,7 +206,7 @@ init_sata (int dev)
init_part (&sata_dev_desc[devno]);
if (curr_device < 0)
curr_device =
- i * CFG_SATA_DEVS_PER_BUS + j;
+ i * CONFIG_SYS_SATA_DEVS_PER_BUS + j;
}
}
}
@@ -271,7 +271,7 @@ sata_bus_softreset (int num)
port[num].dev_mask = 0;
- for (i = 0; i < CFG_SATA_DEVS_PER_BUS; i++) {
+ for (i = 0; i < CONFIG_SYS_SATA_DEVS_PER_BUS; i++) {
if (!(sata_devchk (&port[num].ioaddr, i))) {
PRINTF ("dev_chk failed for dev#%d\n", i);
} else {
@@ -328,7 +328,7 @@ sata_bus_softreset (int num)
void
sata_identify (int num, int dev)
{
- u8 cmd = 0, status = 0, devno = num * CFG_SATA_DEVS_PER_BUS + dev;
+ u8 cmd = 0, status = 0, devno = num * CONFIG_SYS_SATA_DEVS_PER_BUS + dev;
u16 iobuf[ATA_SECT_SIZE];
u64 n_sectors = 0;
u8 mask = 0;
@@ -564,10 +564,10 @@ sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff)
}
#endif
/*Port Number */
- num = device / CFG_SATA_DEVS_PER_BUS;
+ num = device / CONFIG_SYS_SATA_DEVS_PER_BUS;
/*dev on the port */
- if (device >= CFG_SATA_DEVS_PER_BUS)
- dev = device - CFG_SATA_DEVS_PER_BUS;
+ if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS)
+ dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS;
else
dev = device;
@@ -671,10 +671,10 @@ sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff)
}
#endif
/*Port Number */
- num = device / CFG_SATA_DEVS_PER_BUS;
+ num = device / CONFIG_SYS_SATA_DEVS_PER_BUS;
/*dev on the Port */
- if (device >= CFG_SATA_DEVS_PER_BUS)
- dev = device - CFG_SATA_DEVS_PER_BUS;
+ if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS)
+ dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS;
else
dev = device;
diff --git a/drivers/block/ata_piix.h b/drivers/block/ata_piix.h
index f9f0194..11885af 100644
--- a/drivers/block/ata_piix.h
+++ b/drivers/block/ata_piix.h
@@ -88,7 +88,7 @@ int init_sata (int dev);
#endif
#ifdef DRV_DECL /*Defines Driver Specific variables */
-struct sata_port port[CFG_SATA_MAXBUS];
+struct sata_port port[CONFIG_SYS_SATA_MAXBUS];
#endif
#endif /* __ATA_PIIX_H__ */
diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c
index 55f593a..2009d1e 100644
--- a/drivers/block/fsl_sata.c
+++ b/drivers/block/fsl_sata.c
@@ -26,23 +26,23 @@
#include <fis.h>
#include "fsl_sata.h"
-extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
-#ifndef CFG_SATA1_FLAGS
- #define CFG_SATA1_FLAGS FLAGS_DMA
+#ifndef CONFIG_SYS_SATA1_FLAGS
+ #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA
#endif
-#ifndef CFG_SATA2_FLAGS
- #define CFG_SATA2_FLAGS FLAGS_DMA
+#ifndef CONFIG_SYS_SATA2_FLAGS
+ #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA
#endif
static struct fsl_sata_info fsl_sata_info[] = {
#ifdef CONFIG_SATA1
- {CFG_SATA1, CFG_SATA1_FLAGS},
+ {CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS},
#else
{0, 0},
#endif
#ifdef CONFIG_SATA2
- {CFG_SATA2, CFG_SATA2_FLAGS},
+ {CONFIG_SYS_SATA2, CONFIG_SYS_SATA2_FLAGS},
#else
{0, 0},
#endif
@@ -123,7 +123,7 @@ int init_sata(int dev)
int i;
fsl_sata_t *sata;
- if (dev < 0 || dev > (CFG_SATA_MAX_DEVICE - 1)) {
+ if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
printf("the sata index %d is out of ranges\n\r", dev);
return -1;
}
diff --git a/drivers/block/sata_sil3114.c b/drivers/block/sata_sil3114.c
index 8399737..351cf99 100644
--- a/drivers/block/sata_sil3114.c
+++ b/drivers/block/sata_sil3114.c
@@ -48,9 +48,9 @@ static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus);
static void msleep (int count);
static u32 iobase[6] = { 0, 0, 0, 0, 0, 0}; /* PCI BAR registers for device */
-extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
-static struct sata_port port[CFG_SATA_MAX_DEVICE];
+static struct sata_port port[CONFIG_SYS_SATA_MAX_DEVICE];
static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words)
{
diff --git a/drivers/block/sil680.c b/drivers/block/sil680.c
index 052c3d3..e21fb9b 100644
--- a/drivers/block/sil680.c
+++ b/drivers/block/sil680.c
@@ -32,25 +32,25 @@
* #define CONFIG_PCI_PNP
* NOTE it may also be necessary to define this if the default of 8 is
* incorrect for the target board (e.g. the sequoia board requires 0).
- * #define CFG_PCI_CACHE_LINE_SIZE 0
+ * #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 0
*
* #define CONFIG_CMD_IDE
* #undef CONFIG_IDE_8xx_DIRECT
* #undef CONFIG_IDE_LED
* #undef CONFIG_IDE_RESET
* #define CONFIG_IDE_PREINIT
- * #define CFG_IDE_MAXBUS 2 - modify to suit
- * #define CFG_IDE_MAXDEVICE (CFG_IDE_MAXBUS*2) - modify to suit
- * #define CFG_ATA_BASE_ADDR 0
- * #define CFG_ATA_IDE0_OFFSET 0
- * #define CFG_ATA_IDE1_OFFSET 0
- * #define CFG_ATA_DATA_OFFSET 0
- * #define CFG_ATA_REG_OFFSET 0
- * #define CFG_ATA_ALT_OFFSET 0x0004
+ * #define CONFIG_SYS_IDE_MAXBUS 2 - modify to suit
+ * #define CONFIG_SYS_IDE_MAXDEVICE (CONFIG_SYS_IDE_MAXBUS*2) - modify to suit
+ * #define CONFIG_SYS_ATA_BASE_ADDR 0
+ * #define CONFIG_SYS_ATA_IDE0_OFFSET 0
+ * #define CONFIG_SYS_ATA_IDE1_OFFSET 0
+ * #define CONFIG_SYS_ATA_DATA_OFFSET 0
+ * #define CONFIG_SYS_ATA_REG_OFFSET 0
+ * #define CONFIG_SYS_ATA_ALT_OFFSET 0x0004
*
* The mapping for PCI IO-space.
* NOTE this is the value for the sequoia board. Modify to suit.
- * #define CFG_PCI0_IO_SPACE 0xE8000000
+ * #define CONFIG_SYS_PCI0_IO_SPACE 0xE8000000
*/
#include <common.h>
@@ -58,7 +58,7 @@
#include <ide.h>
#include <pci.h>
-extern ulong ide_bus_offset[CFG_IDE_MAXBUS];
+extern ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];
int ide_preinit (void)
{
@@ -67,7 +67,7 @@ int ide_preinit (void)
int l;
status = 1;
- for (l = 0; l < CFG_IDE_MAXBUS; l++) {
+ for (l = 0; l < CONFIG_SYS_IDE_MAXBUS; l++) {
ide_bus_offset[l] = -ATA_STATUS;
}
devbusfn = pci_find_device (0x1095, 0x0680, 0);
@@ -77,11 +77,11 @@ int ide_preinit (void)
pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0,
(u32 *) &ide_bus_offset[0]);
ide_bus_offset[0] &= 0xfffffff8;
- ide_bus_offset[0] += CFG_PCI0_IO_SPACE;
+ ide_bus_offset[0] += CONFIG_SYS_PCI0_IO_SPACE;
pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_2,
(u32 *) &ide_bus_offset[1]);
ide_bus_offset[1] &= 0xfffffff8;
- ide_bus_offset[1] += CFG_PCI0_IO_SPACE;
+ ide_bus_offset[1] += CONFIG_SYS_PCI0_IO_SPACE;
/* init various things - taken from the Linux driver */
/* set PIO mode */
pci_write_config_byte(devbusfn, 0x80, 0x00);
diff --git a/drivers/block/sym53c8xx.c b/drivers/block/sym53c8xx.c
index 44e998b..8094b41 100644
--- a/drivers/block/sym53c8xx.c
+++ b/drivers/block/sym53c8xx.c
@@ -426,7 +426,7 @@ void scsi_bus_reset(void)
{
unsigned char t;
int i;
- int end = CFG_SCSI_SPIN_UP_TIME*1000;
+ int end = CONFIG_SYS_SCSI_SPIN_UP_TIME*1000;
t=scsi_read_byte(SCNTL1);
scsi_write_byte(SCNTL1,(t | CRST));
@@ -836,10 +836,10 @@ void scsi_chip_init(void)
scsi_write_byte(SCNTL0,0xC0); /* full arbitration no start, no message, parity disabled, master */
scsi_write_byte(SCNTL1,0x00);
scsi_write_byte(SCNTL2,0x00);
-#ifndef CFG_SCSI_SYM53C8XX_CCF /* config value for none 40 mhz clocks */
+#ifndef CONFIG_SYS_SCSI_SYM53C8XX_CCF /* config value for none 40 MHz clocks */
scsi_write_byte(SCNTL3,0x13); /* synchronous clock 40/4=10MHz, asynchronous 40MHz */
#else
- scsi_write_byte(SCNTL3,CFG_SCSI_SYM53C8XX_CCF); /* config value for none 40 mhz clocks */
+ scsi_write_byte(SCNTL3,CONFIG_SYS_SCSI_SYM53C8XX_CCF); /* config value for none 40 MHz clocks */
#endif
scsi_write_byte(SCID,0x47); /* ID=7, enable reselection */
scsi_write_byte(SXFER,0x00); /* synchronous transfer period 10MHz, asynchronous */
diff --git a/drivers/block/systemace.c b/drivers/block/systemace.c
index dfaab52..e8dff0a 100644
--- a/drivers/block/systemace.c
+++ b/drivers/block/systemace.c
@@ -20,7 +20,7 @@
/*
* The Xilinx SystemACE chip support is activated by defining
- * CONFIG_SYSTEMACE to turn on support, and CFG_SYSTEMACE_BASE
+ * CONFIG_SYSTEMACE to turn on support, and CONFIG_SYS_SYSTEMACE_BASE
* to set the base address of the device. This code currently
* assumes that the chip is connected via a byte-wide bus.
*
@@ -47,25 +47,25 @@
/*
* The ace_readw and writew functions read/write 16bit words, but the
* offset value is the BYTE offset as most used in the Xilinx
- * datasheet for the SystemACE chip. The CFG_SYSTEMACE_BASE is defined
+ * datasheet for the SystemACE chip. The CONFIG_SYS_SYSTEMACE_BASE is defined
* to be the base address for the chip, usually in the local
* peripheral bus.
*/
-#if (CFG_SYSTEMACE_WIDTH == 8)
+#if (CONFIG_SYS_SYSTEMACE_WIDTH == 8)
#if !defined(__BIG_ENDIAN)
-#define ace_readw(off) ((readb(CFG_SYSTEMACE_BASE+off)<<8) | \
- (readb(CFG_SYSTEMACE_BASE+off+1)))
-#define ace_writew(val, off) {writeb(val>>8, CFG_SYSTEMACE_BASE+off); \
- writeb(val, CFG_SYSTEMACE_BASE+off+1);}
+#define ace_readw(off) ((readb(CONFIG_SYS_SYSTEMACE_BASE+off)<<8) | \
+ (readb(CONFIG_SYS_SYSTEMACE_BASE+off+1)))
+#define ace_writew(val, off) {writeb(val>>8, CONFIG_SYS_SYSTEMACE_BASE+off); \
+ writeb(val, CONFIG_SYS_SYSTEMACE_BASE+off+1);}
#else
-#define ace_readw(off) ((readb(CFG_SYSTEMACE_BASE+off)) | \
- (readb(CFG_SYSTEMACE_BASE+off+1)<<8))
-#define ace_writew(val, off) {writeb(val, CFG_SYSTEMACE_BASE+off); \
- writeb(val>>8, CFG_SYSTEMACE_BASE+off+1);}
+#define ace_readw(off) ((readb(CONFIG_SYS_SYSTEMACE_BASE+off)) | \
+ (readb(CONFIG_SYS_SYSTEMACE_BASE+off+1)<<8))
+#define ace_writew(val, off) {writeb(val, CONFIG_SYS_SYSTEMACE_BASE+off); \
+ writeb(val>>8, CONFIG_SYS_SYSTEMACE_BASE+off+1);}
#endif
#else
-#define ace_readw(off) (in16(CFG_SYSTEMACE_BASE+off))
-#define ace_writew(val, off) (out16(CFG_SYSTEMACE_BASE+off,val))
+#define ace_readw(off) (in16(CONFIG_SYS_SYSTEMACE_BASE+off))
+#define ace_writew(val, off) (out16(CONFIG_SYS_SYSTEMACE_BASE+off,val))
#endif
/* */
@@ -120,7 +120,7 @@ block_dev_desc_t *systemace_get_dev(int dev)
/*
* Ensure the correct bus mode (8/16 bits) gets enabled
*/
- ace_writew(CFG_SYSTEMACE_WIDTH == 8 ? 0 : 0x0001, 0);
+ ace_writew(CONFIG_SYS_SYSTEMACE_WIDTH == 8 ? 0 : 0x0001, 0);
init_part(&systemace_dev);
diff --git a/drivers/fpga/ACEX1K.c b/drivers/fpga/ACEX1K.c
new file mode 100644
index 0000000..3f79677
--- /dev/null
+++ b/drivers/fpga/ACEX1K.c
@@ -0,0 +1,362 @@
+/*
+ * (C) Copyright 2003
+ * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de
+ *
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * 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> /* core U-Boot definitions */
+#include <ACEX1K.h> /* ACEX device family */
+
+/* Define FPGA_DEBUG to get debug printf's */
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CONFIG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CONFIG_FPGA_DELAY
+#define CONFIG_FPGA_DELAY()
+#endif
+
+#ifndef CONFIG_SYS_FPGA_WAIT
+#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/10 /* 100 ms */
+#endif
+
+static int ACEX1K_ps_load( Altera_desc *desc, void *buf, size_t bsize );
+static int ACEX1K_ps_dump( Altera_desc *desc, void *buf, size_t bsize );
+/* static int ACEX1K_ps_info( Altera_desc *desc ); */
+static int ACEX1K_ps_reloc( Altera_desc *desc, ulong reloc_offset );
+
+/* ------------------------------------------------------------------------- */
+/* ACEX1K Generic Implementation */
+int ACEX1K_load (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ PRINTF ("%s: Launching Passive Serial Loader\n", __FUNCTION__);
+ ret_val = ACEX1K_ps_load (desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int ACEX1K_dump (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ PRINTF ("%s: Launching Passive Serial Dump\n", __FUNCTION__);
+ ret_val = ACEX1K_ps_dump (desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int ACEX1K_info( Altera_desc *desc )
+{
+ return FPGA_SUCCESS;
+}
+
+
+int ACEX1K_reloc (Altera_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (desc->family != Altera_ACEX1K) {
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ return FPGA_FAIL;
+ } else
+ switch (desc->iface) {
+ case passive_serial:
+ ret_val = ACEX1K_ps_reloc (desc, reloc_offset);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* ACEX1K Passive Serial Generic Implementation */
+
+static int ACEX1K_ps_load (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Altera_ACEX1K_Passive_Serial_fns *fn = desc->iface_fns;
+ int i;
+
+ PRINTF ("%s: start with interface functions @ 0x%p\n",
+ __FUNCTION__, fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ PRINTF ("%s: Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "config:\t0x%p\n"
+ "status:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "data:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ __FUNCTION__, &fn, fn, fn->config, fn->status,
+ fn->clk, fn->data, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->config) (TRUE, TRUE, cookie); /* Assert nCONFIG */
+
+ udelay(2); /* T_cfg > 2us */
+
+ /* nSTATUS should be asserted now */
+ (*fn->done) (cookie);
+ if ( !(*fn->status) (cookie) ) {
+ puts ("** nSTATUS is not asserted.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+
+ (*fn->config) (FALSE, TRUE, cookie); /* Deassert nCONFIG */
+ udelay(2); /* T_cf2st1 < 4us */
+
+ /* Wait for nSTATUS to be released (i.e. deasserted) */
+ ts = get_timer (0); /* get current time */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for STATUS to go high.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ (*fn->done) (cookie);
+ } while ((*fn->status) (cookie));
+
+ /* Get ready for the burn */
+ CONFIG_FPGA_DELAY ();
+
+ /* Load the data */
+ while (bytecount < bsize) {
+ unsigned char val=0;
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+ if (ctrlc ()) {
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#endif
+ /* Altera detects an error if INIT goes low (active)
+ while DONE is low (inactive) */
+#if 0 /* not yet implemented */
+ if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
+ puts ("** CRC error during FPGA load.\n");
+ (*fn->abort) (cookie);
+ return (FPGA_FAIL);
+ }
+#endif
+ val = data [bytecount ++ ];
+ i = 8;
+ do {
+ /* Deassert the clock */
+ (*fn->clk) (FALSE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ /* Write data */
+ (*fn->data) ( (val & 0x01), TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ /* Assert the clock */
+ (*fn->clk) (TRUE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ val >>= 1;
+ i --;
+ } while (i > 0);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CONFIG_FPGA_DELAY ();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc (' '); /* terminate the dotted line */
+#endif
+
+ /*
+ * Checking FPGA's CONF_DONE signal - correctly booted ?
+ */
+
+ if ( ! (*fn->done) (cookie) ) {
+ puts ("** Booting failed! CONF_DONE is still deasserted.\n");
+ (*fn->abort) (cookie);
+ return (FPGA_FAIL);
+ }
+
+ /*
+ * "DCLK must be clocked an additional 10 times fpr ACEX 1K..."
+ */
+
+ for (i = 0; i < 12; i++) {
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ }
+
+ ret_val = FPGA_SUCCESS;
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS) {
+ puts ("Done.\n");
+ }
+ else {
+ puts ("Fail.\n");
+ }
+#endif
+ (*fn->post) (cookie);
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int ACEX1K_ps_dump (Altera_desc * desc, void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf ("%s: Passive Serial Dumping is unavailable\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+static int ACEX1K_ps_reloc (Altera_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Altera_ACEX1K_Passive_Serial_fns *fn_r, *fn =
+ (Altera_ACEX1K_Passive_Serial_fns *) (desc->iface_fns);
+
+ if (fn) {
+ ulong addr;
+
+ /* Get the relocated table address */
+ addr = (ulong) fn + reloc_offset;
+ fn_r = (Altera_ACEX1K_Passive_Serial_fns *) addr;
+
+ if (!fn_r->relocated) {
+
+ if (memcmp (fn_r, fn,
+ sizeof (Altera_ACEX1K_Passive_Serial_fns))
+ == 0) {
+ /* good copy of the table, fix the descriptor pointer */
+ desc->iface_fns = fn_r;
+ } else {
+ PRINTF ("%s: Invalid function table at 0x%p\n",
+ __FUNCTION__, fn_r);
+ return FPGA_FAIL;
+ }
+
+ PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
+ desc);
+
+ addr = (ulong) (fn->pre) + reloc_offset;
+ fn_r->pre = (Altera_pre_fn) addr;
+
+ addr = (ulong) (fn->config) + reloc_offset;
+ fn_r->config = (Altera_config_fn) addr;
+
+ addr = (ulong) (fn->status) + reloc_offset;
+ fn_r->status = (Altera_status_fn) addr;
+
+ addr = (ulong) (fn->done) + reloc_offset;
+ fn_r->done = (Altera_done_fn) addr;
+
+ addr = (ulong) (fn->clk) + reloc_offset;
+ fn_r->clk = (Altera_clk_fn) addr;
+
+ addr = (ulong) (fn->data) + reloc_offset;
+ fn_r->data = (Altera_data_fn) addr;
+
+ addr = (ulong) (fn->abort) + reloc_offset;
+ fn_r->abort = (Altera_abort_fn) addr;
+
+ addr = (ulong) (fn->post) + reloc_offset;
+ fn_r->post = (Altera_post_fn) addr;
+
+ fn_r->relocated = TRUE;
+
+ } else {
+ /* this table has already been moved */
+ /* XXX - should check to see if the descriptor is correct */
+ desc->iface_fns = fn_r;
+ }
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+
+}
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
new file mode 100644
index 0000000..52d8e24
--- /dev/null
+++ b/drivers/fpga/Makefile
@@ -0,0 +1,58 @@
+#
+# (C) Copyright 2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB := $(obj)libfpga.a
+
+ifdef CONFIG_FPGA
+COBJS-y += fpga.o
+COBJS-$(CONFIG_FPGA_SPARTAN2) += spartan2.o
+COBJS-$(CONFIG_FPGA_SPARTAN3) += spartan3.o
+COBJS-$(CONFIG_FPGA_VIRTEX2) += virtex2.o
+COBJS-$(CONFIG_FPGA_XILINX) += xilinx.o
+ifdef CONFIG_FPGA_ALTERA
+COBJS-y += altera.o
+COBJS-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
+COBJS-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
+COBJS-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
+endif
+endif
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c
new file mode 100644
index 0000000..09dc0b2
--- /dev/null
+++ b/drivers/fpga/altera.c
@@ -0,0 +1,283 @@
+/*
+ * (C) Copyright 2003
+ * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de
+ *
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * 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
+ *
+ */
+
+/*
+ * Altera FPGA support
+ */
+#include <common.h>
+#include <ACEX1K.h>
+#include <stratixII.h>
+
+/* Define FPGA_DEBUG to get debug printf's */
+/* #define FPGA_DEBUG */
+
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Local Static Functions */
+static int altera_validate (Altera_desc * desc, const char *fn);
+
+/* ------------------------------------------------------------------------- */
+int altera_load( Altera_desc *desc, void *buf, size_t bsize )
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (!altera_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ } else {
+ switch (desc->family) {
+ case Altera_ACEX1K:
+ case Altera_CYC2:
+#if defined(CONFIG_FPGA_ACEX1K)
+ PRINTF ("%s: Launching the ACEX1K Loader...\n",
+ __FUNCTION__);
+ ret_val = ACEX1K_load (desc, buf, bsize);
+#elif defined(CONFIG_FPGA_CYCLON2)
+ PRINTF ("%s: Launching the CYCLON II Loader...\n",
+ __FUNCTION__);
+ ret_val = CYC2_load (desc, buf, bsize);
+#else
+ printf ("%s: No support for ACEX1K devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+
+#if defined(CONFIG_FPGA_STRATIX_II)
+ case Altera_StratixII:
+ PRINTF ("%s: Launching the Stratix II Loader...\n",
+ __FUNCTION__);
+ ret_val = StratixII_load (desc, buf, bsize);
+ break;
+#endif
+ default:
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ }
+ }
+
+ return ret_val;
+}
+
+int altera_dump( Altera_desc *desc, void *buf, size_t bsize )
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (!altera_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ } else {
+ switch (desc->family) {
+ case Altera_ACEX1K:
+#if defined(CONFIG_FPGA_ACEX)
+ PRINTF ("%s: Launching the ACEX1K Reader...\n",
+ __FUNCTION__);
+ ret_val = ACEX1K_dump (desc, buf, bsize);
+#else
+ printf ("%s: No support for ACEX1K devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+
+#if defined(CONFIG_FPGA_STRATIX_II)
+ case Altera_StratixII:
+ PRINTF ("%s: Launching the Stratix II Reader...\n",
+ __FUNCTION__);
+ ret_val = StratixII_dump (desc, buf, bsize);
+ break;
+#endif
+ default:
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ }
+ }
+
+ return ret_val;
+}
+
+int altera_info( Altera_desc *desc )
+{
+ int ret_val = FPGA_FAIL;
+
+ if (altera_validate (desc, (char *)__FUNCTION__)) {
+ printf ("Family: \t");
+ switch (desc->family) {
+ case Altera_ACEX1K:
+ printf ("ACEX1K\n");
+ break;
+ case Altera_CYC2:
+ printf ("CYCLON II\n");
+ break;
+ case Altera_StratixII:
+ printf ("Stratix II\n");
+ break;
+ /* Add new family types here */
+ default:
+ printf ("Unknown family type, %d\n", desc->family);
+ }
+
+ printf ("Interface type:\t");
+ switch (desc->iface) {
+ case passive_serial:
+ printf ("Passive Serial (PS)\n");
+ break;
+ case passive_parallel_synchronous:
+ printf ("Passive Parallel Synchronous (PPS)\n");
+ break;
+ case passive_parallel_asynchronous:
+ printf ("Passive Parallel Asynchronous (PPA)\n");
+ break;
+ case passive_serial_asynchronous:
+ printf ("Passive Serial Asynchronous (PSA)\n");
+ break;
+ case altera_jtag_mode: /* Not used */
+ printf ("JTAG Mode\n");
+ break;
+ case fast_passive_parallel:
+ printf ("Fast Passive Parallel (FPP)\n");
+ break;
+ case fast_passive_parallel_security:
+ printf
+ ("Fast Passive Parallel with Security (FPPS) \n");
+ break;
+ /* Add new interface types here */
+ default:
+ printf ("Unsupported interface type, %d\n", desc->iface);
+ }
+
+ printf ("Device Size: \t%d bytes\n"
+ "Cookie: \t0x%x (%d)\n",
+ desc->size, desc->cookie, desc->cookie);
+
+ if (desc->iface_fns) {
+ printf ("Device Function Table @ 0x%p\n", desc->iface_fns);
+ switch (desc->family) {
+ case Altera_ACEX1K:
+ case Altera_CYC2:
+#if defined(CONFIG_FPGA_ACEX1K)
+ ACEX1K_info (desc);
+#elif defined(CONFIG_FPGA_CYCLON2)
+ CYC2_info (desc);
+#else
+ /* just in case */
+ printf ("%s: No support for ACEX1K devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+#if defined(CONFIG_FPGA_STRATIX_II)
+ case Altera_StratixII:
+ StratixII_info (desc);
+ break;
+#endif
+ /* Add new family types here */
+ default:
+ /* we don't need a message here - we give one up above */
+ break;
+ }
+ } else {
+ printf ("No Device Function Table.\n");
+ }
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+int altera_reloc( Altera_desc *desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (!altera_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ } else {
+ switch (desc->family) {
+ case Altera_ACEX1K:
+#if defined(CONFIG_FPGA_ACEX1K)
+ ret_val = ACEX1K_reloc (desc, reloc_offset);
+#else
+ printf ("%s: No support for ACEX devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+#if defined(CONFIG_FPGA_STRATIX_II)
+ case Altera_StratixII:
+ ret_val = StratixII_reloc (desc, reloc_offset);
+ break;
+#endif
+ case Altera_CYC2:
+#if defined(CONFIG_FPGA_CYCLON2)
+ ret_val = CYC2_reloc (desc, reloc_offset);
+#else
+ printf ("%s: No support for CYCLON II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ /* Add new family types here */
+ default:
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ }
+ }
+
+ return ret_val;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int altera_validate (Altera_desc * desc, const char *fn)
+{
+ int ret_val = FALSE;
+
+ if (desc) {
+ if ((desc->family > min_altera_type) &&
+ (desc->family < max_altera_type)) {
+ if ((desc->iface > min_altera_iface_type) &&
+ (desc->iface < max_altera_iface_type)) {
+ if (desc->size) {
+ ret_val = TRUE;
+ } else {
+ printf ("%s: NULL part size\n", fn);
+ }
+ } else {
+ printf ("%s: Invalid Interface type, %d\n",
+ fn, desc->iface);
+ }
+ } else {
+ printf ("%s: Invalid family type, %d\n", fn, desc->family);
+ }
+ } else {
+ printf ("%s: NULL descriptor!\n", fn);
+ }
+
+ return ret_val;
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/drivers/fpga/cyclon2.c b/drivers/fpga/cyclon2.c
new file mode 100644
index 0000000..3ed64b2
--- /dev/null
+++ b/drivers/fpga/cyclon2.c
@@ -0,0 +1,301 @@
+/*
+ * (C) Copyright 2006
+ * Heiko Schocher, hs@denx.de
+ * Based on ACE1XK.c
+ *
+ * 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> /* core U-Boot definitions */
+#include <altera.h>
+#include <ACEX1K.h> /* ACEX device family */
+
+/* Define FPGA_DEBUG to get debug printf's */
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CONFIG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CONFIG_FPGA_DELAY
+#define CONFIG_FPGA_DELAY()
+#endif
+
+#ifndef CONFIG_SYS_FPGA_WAIT
+#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/10 /* 100 ms */
+#endif
+
+static int CYC2_ps_load( Altera_desc *desc, void *buf, size_t bsize );
+static int CYC2_ps_dump( Altera_desc *desc, void *buf, size_t bsize );
+/* static int CYC2_ps_info( Altera_desc *desc ); */
+static int CYC2_ps_reloc( Altera_desc *desc, ulong reloc_offset );
+
+/* ------------------------------------------------------------------------- */
+/* CYCLON2 Generic Implementation */
+int CYC2_load (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ PRINTF ("%s: Launching Passive Serial Loader\n", __FUNCTION__);
+ ret_val = CYC2_ps_load (desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int CYC2_dump (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ PRINTF ("%s: Launching Passive Serial Dump\n", __FUNCTION__);
+ ret_val = CYC2_ps_dump (desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int CYC2_info( Altera_desc *desc )
+{
+ return FPGA_SUCCESS;
+}
+
+int CYC2_reloc (Altera_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (desc->family != Altera_CYC2) {
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ return FPGA_FAIL;
+ } else
+ switch (desc->iface) {
+ case passive_serial:
+ ret_val = CYC2_ps_reloc (desc, reloc_offset);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+/* ------------------------------------------------------------------------- */
+/* CYCLON2 Passive Serial Generic Implementation */
+static int CYC2_ps_load (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Altera_CYC2_Passive_Serial_fns *fn = desc->iface_fns;
+ int ret = 0;
+
+ PRINTF ("%s: start with interface functions @ 0x%p\n",
+ __FUNCTION__, fn);
+
+ if (fn) {
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ PRINTF ("%s: Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "config:\t0x%p\n"
+ "status:\t0x%p\n"
+ "write:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ __FUNCTION__, &fn, fn, fn->config, fn->status,
+ fn->write, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->config) (TRUE, TRUE, cookie); /* Assert nCONFIG */
+
+ udelay(2); /* T_cfg > 2us */
+
+ /* Wait for nSTATUS to be asserted */
+ ts = get_timer (0); /* get current time */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for STATUS to go high.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->status) (cookie));
+
+ /* Get ready for the burn */
+ CONFIG_FPGA_DELAY ();
+
+ ret = (*fn->write) (buf, bsize, TRUE, cookie);
+ if (ret) {
+ puts ("** Write failed.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts(" OK? ...");
+#endif
+
+ CONFIG_FPGA_DELAY ();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc (' '); /* terminate the dotted line */
+#endif
+
+ /*
+ * Checking FPGA's CONF_DONE signal - correctly booted ?
+ */
+
+ if ( ! (*fn->done) (cookie) ) {
+ puts ("** Booting failed! CONF_DONE is still deasserted.\n");
+ (*fn->abort) (cookie);
+ return (FPGA_FAIL);
+ }
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts(" OK\n");
+#endif
+
+ ret_val = FPGA_SUCCESS;
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS) {
+ puts ("Done.\n");
+ }
+ else {
+ puts ("Fail.\n");
+ }
+#endif
+ (*fn->post) (cookie);
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int CYC2_ps_dump (Altera_desc * desc, void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf ("%s: Passive Serial Dumping is unavailable\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+static int CYC2_ps_reloc (Altera_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Altera_CYC2_Passive_Serial_fns *fn_r, *fn =
+ (Altera_CYC2_Passive_Serial_fns *) (desc->iface_fns);
+
+ if (fn) {
+ ulong addr;
+
+ /* Get the relocated table address */
+ addr = (ulong) fn + reloc_offset;
+ fn_r = (Altera_CYC2_Passive_Serial_fns *) addr;
+
+ if (!fn_r->relocated) {
+
+ if (memcmp (fn_r, fn,
+ sizeof (Altera_CYC2_Passive_Serial_fns))
+ == 0) {
+ /* good copy of the table, fix the descriptor pointer */
+ desc->iface_fns = fn_r;
+ } else {
+ PRINTF ("%s: Invalid function table at 0x%p\n",
+ __FUNCTION__, fn_r);
+ return FPGA_FAIL;
+ }
+
+ PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
+ desc);
+
+ addr = (ulong) (fn->pre) + reloc_offset;
+ fn_r->pre = (Altera_pre_fn) addr;
+
+ addr = (ulong) (fn->config) + reloc_offset;
+ fn_r->config = (Altera_config_fn) addr;
+
+ addr = (ulong) (fn->status) + reloc_offset;
+ fn_r->status = (Altera_status_fn) addr;
+
+ addr = (ulong) (fn->done) + reloc_offset;
+ fn_r->done = (Altera_done_fn) addr;
+
+ addr = (ulong) (fn->write) + reloc_offset;
+ fn_r->write = (Altera_write_fn) addr;
+
+ addr = (ulong) (fn->abort) + reloc_offset;
+ fn_r->abort = (Altera_abort_fn) addr;
+
+ addr = (ulong) (fn->post) + reloc_offset;
+ fn_r->post = (Altera_post_fn) addr;
+
+ fn_r->relocated = TRUE;
+
+ } else {
+ /* this table has already been moved */
+ /* XXX - should check to see if the descriptor is correct */
+ desc->iface_fns = fn_r;
+ }
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
new file mode 100644
index 0000000..67a6c30
--- /dev/null
+++ b/drivers/fpga/fpga.c
@@ -0,0 +1,335 @@
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * 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
+ *
+ */
+
+/*
+ * Generic FPGA support
+ */
+#include <common.h> /* core U-Boot definitions */
+#include <xilinx.h> /* xilinx specific definitions */
+#include <altera.h> /* altera specific definitions */
+
+#if 0
+#define FPGA_DEBUG /* define FPGA_DEBUG to get debug messages */
+#endif
+
+/* Local definitions */
+#ifndef CONFIG_MAX_FPGA_DEVICES
+#define CONFIG_MAX_FPGA_DEVICES 5
+#endif
+
+/* Enable/Disable debug console messages */
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Local static data */
+static ulong relocation_offset = 0;
+static int next_desc = FPGA_INVALID_DEVICE;
+static fpga_desc desc_table[CONFIG_MAX_FPGA_DEVICES];
+
+/* Local static functions */
+static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_get_desc( int devnum );
+static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_validate( int devnum, void *buf,
+ size_t bsize, char *fn );
+static int fpga_dev_info( int devnum );
+
+
+/* ------------------------------------------------------------------------- */
+
+/* fpga_no_sup
+ * 'no support' message function
+ */
+static void fpga_no_sup( char *fn, char *msg )
+{
+ if ( fn && msg ) {
+ printf( "%s: No support for %s.\n", fn, msg);
+ } else if ( msg ) {
+ printf( "No support for %s.\n", msg);
+ } else {
+ printf( "No FPGA suport!\n");
+ }
+}
+
+
+/* fpga_get_desc
+ * map a device number to a descriptor
+ */
+static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_get_desc( int devnum )
+{
+ fpga_desc *desc = (fpga_desc * )NULL;
+
+ if (( devnum >= 0 ) && (devnum < next_desc )) {
+ desc = &desc_table[devnum];
+ PRINTF( "%s: found fpga descriptor #%d @ 0x%p\n",
+ __FUNCTION__, devnum, desc );
+ }
+
+ return desc;
+}
+
+
+/* fpga_validate
+ * generic parameter checking code
+ */
+static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_validate( int devnum, void *buf,
+ size_t bsize, char *fn )
+{
+ fpga_desc * desc = fpga_get_desc( devnum );
+
+ if ( !desc ) {
+ printf( "%s: Invalid device number %d\n", fn, devnum );
+ }
+
+ if ( !buf ) {
+ printf( "%s: Null buffer.\n", fn );
+ return (fpga_desc * const)NULL;
+ }
+ return desc;
+}
+
+
+/* fpga_dev_info
+ * generic multiplexing code
+ */
+static int fpga_dev_info( int devnum )
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ const fpga_desc * const desc = fpga_get_desc( devnum );
+
+ if ( desc ) {
+ PRINTF( "%s: Device Descriptor @ 0x%p\n",
+ __FUNCTION__, desc->devdesc );
+
+ switch ( desc->devtype ) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ printf( "Xilinx Device\nDescriptor @ 0x%p\n", desc );
+ ret_val = xilinx_info( desc->devdesc );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" );
+#endif
+ break;
+ case fpga_altera:
+#if defined(CONFIG_FPGA_ALTERA)
+ printf( "Altera Device\nDescriptor @ 0x%p\n", desc );
+ ret_val = altera_info( desc->devdesc );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Altera devices" );
+#endif
+ break;
+ default:
+ printf( "%s: Invalid or unsupported device type %d\n",
+ __FUNCTION__, desc->devtype );
+ }
+ } else {
+ printf( "%s: Invalid device number %d\n",
+ __FUNCTION__, devnum );
+ }
+
+ return ret_val;
+}
+
+
+/* fpga_reloc
+ * generic multiplexing code
+ */
+int fpga_reloc( fpga_type devtype, void *desc, ulong reloc_off )
+{
+ int ret_val = FPGA_FAIL;
+
+ PRINTF( "%s: Relocating Device of type %d @ 0x%p with offset %lx\n",
+ __FUNCTION__, devtype, desc, reloc_off );
+
+ switch ( devtype ) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_reloc( desc, reloc_off );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" );
+#endif
+ break;
+ case fpga_altera:
+#if defined(CONFIG_FPGA_ALTERA)
+ ret_val = altera_reloc( desc, reloc_off );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Altera devices" );
+#endif
+ break;
+ default:
+ printf( "%s: Invalid or unsupported device type %d\n",
+ __FUNCTION__, devtype );
+ }
+
+ return ret_val;
+}
+
+/* ------------------------------------------------------------------------- */
+/* fgpa_init is usually called from misc_init_r() and MUST be called
+ * before any of the other fpga functions are used.
+ */
+void fpga_init( ulong reloc_off )
+{
+ relocation_offset = reloc_off;
+ next_desc = 0;
+ memset( desc_table, 0, sizeof(desc_table));
+
+ PRINTF( "%s: CONFIG_FPGA = 0x%x\n", __FUNCTION__, CONFIG_FPGA );
+}
+
+/* fpga_count
+ * Basic interface function to get the current number of devices available.
+ */
+int fpga_count( void )
+{
+ return next_desc;
+}
+
+/* fpga_add
+ * Attempts to relocate the device/board specific interface code
+ * to the proper RAM locations and adds the device descriptor to
+ * the device table.
+ */
+int fpga_add( fpga_type devtype, void *desc )
+{
+ int devnum = FPGA_INVALID_DEVICE;
+
+ if ( next_desc < 0 ) {
+ printf( "%s: FPGA support not initialized!\n", __FUNCTION__ );
+ } else if (( devtype > fpga_min_type ) && ( devtype < fpga_undefined )) {
+ if ( desc ) {
+ if ( next_desc < CONFIG_MAX_FPGA_DEVICES ) {
+ if ( fpga_reloc( devtype, desc, relocation_offset )
+ == FPGA_SUCCESS ) {
+ devnum = next_desc;
+ desc_table[next_desc].devtype = devtype;
+ desc_table[next_desc++].devdesc = desc;
+ } else {
+ printf( "%s: Unable to relocate device interface table!\n",
+ __FUNCTION__ );
+ }
+ } else {
+ printf( "%s: Exceeded Max FPGA device count\n", __FUNCTION__ );
+ }
+ } else {
+ printf( "%s: NULL device descriptor\n", __FUNCTION__ );
+ }
+ } else {
+ printf( "%s: Unsupported FPGA type %d\n", __FUNCTION__, devtype );
+ }
+
+ return devnum;
+}
+
+/*
+ * Generic multiplexing code
+ */
+int fpga_load( int devnum, void *buf, size_t bsize )
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ fpga_desc * desc = fpga_validate( devnum, buf, bsize, (char *)__FUNCTION__ );
+
+ if ( desc ) {
+ switch ( desc->devtype ) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_load( desc->devdesc, buf, bsize );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" );
+#endif
+ break;
+ case fpga_altera:
+#if defined(CONFIG_FPGA_ALTERA)
+ ret_val = altera_load( desc->devdesc, buf, bsize );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Altera devices" );
+#endif
+ break;
+ default:
+ printf( "%s: Invalid or unsupported device type %d\n",
+ __FUNCTION__, desc->devtype );
+ }
+ }
+
+ return ret_val;
+}
+
+/* fpga_dump
+ * generic multiplexing code
+ */
+int fpga_dump( int devnum, void *buf, size_t bsize )
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ fpga_desc * desc = fpga_validate( devnum, buf, bsize, (char *)__FUNCTION__ );
+
+ if ( desc ) {
+ switch ( desc->devtype ) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_dump( desc->devdesc, buf, bsize );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" );
+#endif
+ break;
+ case fpga_altera:
+#if defined(CONFIG_FPGA_ALTERA)
+ ret_val = altera_dump( desc->devdesc, buf, bsize );
+#else
+ fpga_no_sup( (char *)__FUNCTION__, "Altera devices" );
+#endif
+ break;
+ default:
+ printf( "%s: Invalid or unsupported device type %d\n",
+ __FUNCTION__, desc->devtype );
+ }
+ }
+
+ return ret_val;
+}
+
+
+/* fpga_info
+ * front end to fpga_dev_info. If devnum is invalid, report on all
+ * available devices.
+ */
+int fpga_info( int devnum )
+{
+ if ( devnum == FPGA_INVALID_DEVICE ) {
+ if ( next_desc > 0 ) {
+ int dev;
+
+ for ( dev = 0; dev < next_desc; dev++ ) {
+ fpga_dev_info( dev );
+ }
+ return FPGA_SUCCESS;
+ } else {
+ printf( "%s: No FPGA devices available.\n", __FUNCTION__ );
+ return FPGA_FAIL;
+ }
+ }
+ else return fpga_dev_info( devnum );
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c
new file mode 100644
index 0000000..f5ba7fc
--- /dev/null
+++ b/drivers/fpga/spartan2.c
@@ -0,0 +1,663 @@
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * 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> /* core U-Boot definitions */
+#include <spartan2.h> /* Spartan-II device family */
+
+/* Define FPGA_DEBUG to get debug printf's */
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#undef CONFIG_SYS_FPGA_CHECK_BUSY
+#undef CONFIG_SYS_FPGA_PROG_FEEDBACK
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CONFIG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CONFIG_FPGA_DELAY
+#define CONFIG_FPGA_DELAY()
+#endif
+
+#ifndef CONFIG_SYS_FPGA_WAIT
+#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
+#endif
+
+static int Spartan2_sp_load( Xilinx_desc *desc, void *buf, size_t bsize );
+static int Spartan2_sp_dump( Xilinx_desc *desc, void *buf, size_t bsize );
+/* static int Spartan2_sp_info( Xilinx_desc *desc ); */
+static int Spartan2_sp_reloc( Xilinx_desc *desc, ulong reloc_offset );
+
+static int Spartan2_ss_load( Xilinx_desc *desc, void *buf, size_t bsize );
+static int Spartan2_ss_dump( Xilinx_desc *desc, void *buf, size_t bsize );
+/* static int Spartan2_ss_info( Xilinx_desc *desc ); */
+static int Spartan2_ss_reloc( Xilinx_desc *desc, ulong reloc_offset );
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Generic Implementation */
+int Spartan2_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__);
+ ret_val = Spartan2_ss_load (desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__);
+ ret_val = Spartan2_sp_load (desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int Spartan2_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__);
+ ret_val = Spartan2_ss_dump (desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__);
+ ret_val = Spartan2_sp_dump (desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int Spartan2_info( Xilinx_desc *desc )
+{
+ return FPGA_SUCCESS;
+}
+
+
+int Spartan2_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (desc->family != Xilinx_Spartan2) {
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ return FPGA_FAIL;
+ } else
+ switch (desc->iface) {
+ case slave_serial:
+ ret_val = Spartan2_ss_reloc (desc, reloc_offset);
+ break;
+
+ case slave_parallel:
+ ret_val = Spartan2_sp_reloc (desc, reloc_offset);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Slave Parallel Generic Implementation */
+
+static int Spartan2_sp_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan2_Slave_Parallel_fns *fn = desc->iface_fns;
+
+ PRINTF ("%s: start with interface functions @ 0x%p\n",
+ __FUNCTION__, fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ PRINTF ("%s: Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pre: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "err:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "cs:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "read data:\t0x%p\n"
+ "write data:\t0x%p\n"
+ "busy:\t0x%p\n"
+ "abort:\t0x%p\n",
+ "post:\t0x%p\n\n",
+ __FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
+ fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
+ fn->abort, fn->post);
+
+ /*
+ * This code is designed to emulate the "Express Style"
+ * Continuous Data Loading in Slave Parallel Mode for
+ * the Spartan-II Family.
+ */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (TRUE, TRUE, cookie); /* Assert the program, commit */
+
+ /* Get ready for the burn */
+ CONFIG_FPGA_DELAY ();
+ (*fn->pgm) (FALSE, TRUE, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT and BUSY to go high */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie) && (*fn->busy) (cookie));
+
+ (*fn->wr) (TRUE, TRUE, cookie); /* Assert write, commit */
+ (*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ /* Load the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+ /* XXX - Check the error bit? */
+
+ (*fn->wdata) (data[bytecount++], TRUE, cookie); /* write the data */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
+ ts = get_timer (0); /* get current time */
+ while ((*fn->busy) (cookie)) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for BUSY to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->cs) (FALSE, TRUE, cookie); /* Deassert the chip select */
+ (*fn->wr) (FALSE, TRUE, cookie); /* Deassert the write pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ while ((*fn->done) (cookie) == FPGA_FAIL) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+
+ if (ret_val == FPGA_SUCCESS) {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts ("Done.\n");
+#endif
+ }
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post) {
+ (*fn->post) (cookie);
+ }
+
+ else {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts ("Fail.\n");
+#endif
+ }
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int Spartan2_sp_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan2_Slave_Parallel_fns *fn = desc->iface_fns;
+
+ if (fn) {
+ unsigned char *data = (unsigned char *) buf;
+ size_t bytecount = 0;
+ int cookie = desc->cookie; /* make a local copy */
+
+ printf ("Starting Dump of FPGA Device %d...\n", cookie);
+
+ (*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ /* dump the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+ (*fn->rdata) (&(data[bytecount++]), cookie); /* read the data */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ (*fn->cs) (FALSE, FALSE, cookie); /* Deassert the chip select */
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+ puts ("Done.\n");
+
+ /* XXX - checksum the data? */
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+
+static int Spartan2_sp_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan2_Slave_Parallel_fns *fn_r, *fn =
+ (Xilinx_Spartan2_Slave_Parallel_fns *) (desc->iface_fns);
+
+ if (fn) {
+ ulong addr;
+
+ /* Get the relocated table address */
+ addr = (ulong) fn + reloc_offset;
+ fn_r = (Xilinx_Spartan2_Slave_Parallel_fns *) addr;
+
+ if (!fn_r->relocated) {
+
+ if (memcmp (fn_r, fn,
+ sizeof (Xilinx_Spartan2_Slave_Parallel_fns))
+ == 0) {
+ /* good copy of the table, fix the descriptor pointer */
+ desc->iface_fns = fn_r;
+ } else {
+ PRINTF ("%s: Invalid function table at 0x%p\n",
+ __FUNCTION__, fn_r);
+ return FPGA_FAIL;
+ }
+
+ PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
+ desc);
+
+ addr = (ulong) (fn->pre) + reloc_offset;
+ fn_r->pre = (Xilinx_pre_fn) addr;
+
+ addr = (ulong) (fn->pgm) + reloc_offset;
+ fn_r->pgm = (Xilinx_pgm_fn) addr;
+
+ addr = (ulong) (fn->init) + reloc_offset;
+ fn_r->init = (Xilinx_init_fn) addr;
+
+ addr = (ulong) (fn->done) + reloc_offset;
+ fn_r->done = (Xilinx_done_fn) addr;
+
+ addr = (ulong) (fn->clk) + reloc_offset;
+ fn_r->clk = (Xilinx_clk_fn) addr;
+
+ addr = (ulong) (fn->err) + reloc_offset;
+ fn_r->err = (Xilinx_err_fn) addr;
+
+ addr = (ulong) (fn->cs) + reloc_offset;
+ fn_r->cs = (Xilinx_cs_fn) addr;
+
+ addr = (ulong) (fn->wr) + reloc_offset;
+ fn_r->wr = (Xilinx_wr_fn) addr;
+
+ addr = (ulong) (fn->rdata) + reloc_offset;
+ fn_r->rdata = (Xilinx_rdata_fn) addr;
+
+ addr = (ulong) (fn->wdata) + reloc_offset;
+ fn_r->wdata = (Xilinx_wdata_fn) addr;
+
+ addr = (ulong) (fn->busy) + reloc_offset;
+ fn_r->busy = (Xilinx_busy_fn) addr;
+
+ addr = (ulong) (fn->abort) + reloc_offset;
+ fn_r->abort = (Xilinx_abort_fn) addr;
+
+ addr = (ulong) (fn->post) + reloc_offset;
+ fn_r->post = (Xilinx_post_fn) addr;
+
+ fn_r->relocated = TRUE;
+
+ } else {
+ /* this table has already been moved */
+ /* XXX - should check to see if the descriptor is correct */
+ desc->iface_fns = fn_r;
+ }
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int Spartan2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan2_Slave_Serial_fns *fn = desc->iface_fns;
+ int i;
+ unsigned char val;
+
+ PRINTF ("%s: start with interface functions @ 0x%p\n",
+ __FUNCTION__, fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ PRINTF ("%s: Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ __FUNCTION__, &fn, fn, fn->pgm, fn->init,
+ fn->clk, fn->wr, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (TRUE, TRUE, cookie); /* Assert the program, commit */
+
+ /* Wait for INIT state (init low) */
+ ts = get_timer (0); /* get current time */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to start.\n");
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->init) (cookie));
+
+ /* Get ready for the burn */
+ CONFIG_FPGA_DELAY ();
+ (*fn->pgm) (FALSE, TRUE, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT to go high */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie));
+
+ /* Load the data */
+ while (bytecount < bsize) {
+
+ /* Xilinx detects an error if INIT goes low (active)
+ while DONE is low (inactive) */
+ if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
+ puts ("** CRC error during FPGA load.\n");
+ return (FPGA_FAIL);
+ }
+ val = data [bytecount ++];
+ i = 8;
+ do {
+ /* Deassert the clock */
+ (*fn->clk) (FALSE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ /* Write data */
+ (*fn->wr) ((val & 0x80), TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ /* Assert the clock */
+ (*fn->clk) (TRUE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ val <<= 1;
+ i --;
+ } while (i > 0);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CONFIG_FPGA_DELAY ();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ (*fn->wr) (TRUE, TRUE, cookie);
+
+ while (! (*fn->done) (cookie)) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ putc ('*');
+
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+ putc ('\n'); /* terminate the dotted line */
+
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post) {
+ (*fn->post) (cookie);
+ }
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS) {
+ puts ("Done.\n");
+ }
+ else {
+ puts ("Fail.\n");
+ }
+#endif
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int Spartan2_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf ("%s: Slave Serial Dumping is unavailable\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+static int Spartan2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan2_Slave_Serial_fns *fn_r, *fn =
+ (Xilinx_Spartan2_Slave_Serial_fns *) (desc->iface_fns);
+
+ if (fn) {
+ ulong addr;
+
+ /* Get the relocated table address */
+ addr = (ulong) fn + reloc_offset;
+ fn_r = (Xilinx_Spartan2_Slave_Serial_fns *) addr;
+
+ if (!fn_r->relocated) {
+
+ if (memcmp (fn_r, fn,
+ sizeof (Xilinx_Spartan2_Slave_Serial_fns))
+ == 0) {
+ /* good copy of the table, fix the descriptor pointer */
+ desc->iface_fns = fn_r;
+ } else {
+ PRINTF ("%s: Invalid function table at 0x%p\n",
+ __FUNCTION__, fn_r);
+ return FPGA_FAIL;
+ }
+
+ PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
+ desc);
+
+ if (fn->pre) {
+ addr = (ulong) (fn->pre) + reloc_offset;
+ fn_r->pre = (Xilinx_pre_fn) addr;
+ }
+
+ addr = (ulong) (fn->pgm) + reloc_offset;
+ fn_r->pgm = (Xilinx_pgm_fn) addr;
+
+ addr = (ulong) (fn->init) + reloc_offset;
+ fn_r->init = (Xilinx_init_fn) addr;
+
+ addr = (ulong) (fn->done) + reloc_offset;
+ fn_r->done = (Xilinx_done_fn) addr;
+
+ addr = (ulong) (fn->clk) + reloc_offset;
+ fn_r->clk = (Xilinx_clk_fn) addr;
+
+ addr = (ulong) (fn->wr) + reloc_offset;
+ fn_r->wr = (Xilinx_wr_fn) addr;
+
+ if (fn->post) {
+ addr = (ulong) (fn->post) + reloc_offset;
+ fn_r->post = (Xilinx_post_fn) addr;
+ }
+
+ fn_r->relocated = TRUE;
+
+ } else {
+ /* this table has already been moved */
+ /* XXX - should check to see if the descriptor is correct */
+ desc->iface_fns = fn_r;
+ }
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+
+}
diff --git a/drivers/fpga/spartan3.c b/drivers/fpga/spartan3.c
new file mode 100644
index 0000000..9ce41f1
--- /dev/null
+++ b/drivers/fpga/spartan3.c
@@ -0,0 +1,668 @@
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * 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
+ *
+ */
+
+/*
+ * Configuration support for Xilinx Spartan3 devices. Based
+ * on spartan2.c (Rich Ireland, rireland@enterasys.com).
+ */
+
+#include <common.h> /* core U-Boot definitions */
+#include <spartan3.h> /* Spartan-II device family */
+
+/* Define FPGA_DEBUG to get debug printf's */
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#undef CONFIG_SYS_FPGA_CHECK_BUSY
+#undef CONFIG_SYS_FPGA_PROG_FEEDBACK
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CONFIG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CONFIG_FPGA_DELAY
+#define CONFIG_FPGA_DELAY()
+#endif
+
+#ifndef CONFIG_SYS_FPGA_WAIT
+#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
+#endif
+
+static int Spartan3_sp_load( Xilinx_desc *desc, void *buf, size_t bsize );
+static int Spartan3_sp_dump( Xilinx_desc *desc, void *buf, size_t bsize );
+/* static int Spartan3_sp_info( Xilinx_desc *desc ); */
+static int Spartan3_sp_reloc( Xilinx_desc *desc, ulong reloc_offset );
+
+static int Spartan3_ss_load( Xilinx_desc *desc, void *buf, size_t bsize );
+static int Spartan3_ss_dump( Xilinx_desc *desc, void *buf, size_t bsize );
+/* static int Spartan3_ss_info( Xilinx_desc *desc ); */
+static int Spartan3_ss_reloc( Xilinx_desc *desc, ulong reloc_offset );
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Generic Implementation */
+int Spartan3_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__);
+ ret_val = Spartan3_ss_load (desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__);
+ ret_val = Spartan3_sp_load (desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int Spartan3_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__);
+ ret_val = Spartan3_ss_dump (desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__);
+ ret_val = Spartan3_sp_dump (desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int Spartan3_info( Xilinx_desc *desc )
+{
+ return FPGA_SUCCESS;
+}
+
+
+int Spartan3_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (desc->family != Xilinx_Spartan3) {
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ return FPGA_FAIL;
+ } else
+ switch (desc->iface) {
+ case slave_serial:
+ ret_val = Spartan3_ss_reloc (desc, reloc_offset);
+ break;
+
+ case slave_parallel:
+ ret_val = Spartan3_sp_reloc (desc, reloc_offset);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Slave Parallel Generic Implementation */
+
+static int Spartan3_sp_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan3_Slave_Parallel_fns *fn = desc->iface_fns;
+
+ PRINTF ("%s: start with interface functions @ 0x%p\n",
+ __FUNCTION__, fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ PRINTF ("%s: Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pre: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "err:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "cs:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "read data:\t0x%p\n"
+ "write data:\t0x%p\n"
+ "busy:\t0x%p\n"
+ "abort:\t0x%p\n",
+ "post:\t0x%p\n\n",
+ __FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
+ fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
+ fn->abort, fn->post);
+
+ /*
+ * This code is designed to emulate the "Express Style"
+ * Continuous Data Loading in Slave Parallel Mode for
+ * the Spartan-II Family.
+ */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (TRUE, TRUE, cookie); /* Assert the program, commit */
+
+ /* Get ready for the burn */
+ CONFIG_FPGA_DELAY ();
+ (*fn->pgm) (FALSE, TRUE, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT and BUSY to go high */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie) && (*fn->busy) (cookie));
+
+ (*fn->wr) (TRUE, TRUE, cookie); /* Assert write, commit */
+ (*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ /* Load the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+ /* XXX - Check the error bit? */
+
+ (*fn->wdata) (data[bytecount++], TRUE, cookie); /* write the data */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
+ ts = get_timer (0); /* get current time */
+ while ((*fn->busy) (cookie)) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for BUSY to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->cs) (FALSE, TRUE, cookie); /* Deassert the chip select */
+ (*fn->wr) (FALSE, TRUE, cookie); /* Deassert the write pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ while ((*fn->done) (cookie) == FPGA_FAIL) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+
+ if (ret_val == FPGA_SUCCESS) {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts ("Done.\n");
+#endif
+ }
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post) {
+ (*fn->post) (cookie);
+ }
+
+ else {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts ("Fail.\n");
+#endif
+ }
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int Spartan3_sp_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan3_Slave_Parallel_fns *fn = desc->iface_fns;
+
+ if (fn) {
+ unsigned char *data = (unsigned char *) buf;
+ size_t bytecount = 0;
+ int cookie = desc->cookie; /* make a local copy */
+
+ printf ("Starting Dump of FPGA Device %d...\n", cookie);
+
+ (*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ /* dump the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+ (*fn->rdata) (&(data[bytecount++]), cookie); /* read the data */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ (*fn->cs) (FALSE, FALSE, cookie); /* Deassert the chip select */
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+ puts ("Done.\n");
+
+ /* XXX - checksum the data? */
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+
+static int Spartan3_sp_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan3_Slave_Parallel_fns *fn_r, *fn =
+ (Xilinx_Spartan3_Slave_Parallel_fns *) (desc->iface_fns);
+
+ if (fn) {
+ ulong addr;
+
+ /* Get the relocated table address */
+ addr = (ulong) fn + reloc_offset;
+ fn_r = (Xilinx_Spartan3_Slave_Parallel_fns *) addr;
+
+ if (!fn_r->relocated) {
+
+ if (memcmp (fn_r, fn,
+ sizeof (Xilinx_Spartan3_Slave_Parallel_fns))
+ == 0) {
+ /* good copy of the table, fix the descriptor pointer */
+ desc->iface_fns = fn_r;
+ } else {
+ PRINTF ("%s: Invalid function table at 0x%p\n",
+ __FUNCTION__, fn_r);
+ return FPGA_FAIL;
+ }
+
+ PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
+ desc);
+
+ addr = (ulong) (fn->pre) + reloc_offset;
+ fn_r->pre = (Xilinx_pre_fn) addr;
+
+ addr = (ulong) (fn->pgm) + reloc_offset;
+ fn_r->pgm = (Xilinx_pgm_fn) addr;
+
+ addr = (ulong) (fn->init) + reloc_offset;
+ fn_r->init = (Xilinx_init_fn) addr;
+
+ addr = (ulong) (fn->done) + reloc_offset;
+ fn_r->done = (Xilinx_done_fn) addr;
+
+ addr = (ulong) (fn->clk) + reloc_offset;
+ fn_r->clk = (Xilinx_clk_fn) addr;
+
+ addr = (ulong) (fn->err) + reloc_offset;
+ fn_r->err = (Xilinx_err_fn) addr;
+
+ addr = (ulong) (fn->cs) + reloc_offset;
+ fn_r->cs = (Xilinx_cs_fn) addr;
+
+ addr = (ulong) (fn->wr) + reloc_offset;
+ fn_r->wr = (Xilinx_wr_fn) addr;
+
+ addr = (ulong) (fn->rdata) + reloc_offset;
+ fn_r->rdata = (Xilinx_rdata_fn) addr;
+
+ addr = (ulong) (fn->wdata) + reloc_offset;
+ fn_r->wdata = (Xilinx_wdata_fn) addr;
+
+ addr = (ulong) (fn->busy) + reloc_offset;
+ fn_r->busy = (Xilinx_busy_fn) addr;
+
+ addr = (ulong) (fn->abort) + reloc_offset;
+ fn_r->abort = (Xilinx_abort_fn) addr;
+
+ addr = (ulong) (fn->post) + reloc_offset;
+ fn_r->post = (Xilinx_post_fn) addr;
+
+ fn_r->relocated = TRUE;
+
+ } else {
+ /* this table has already been moved */
+ /* XXX - should check to see if the descriptor is correct */
+ desc->iface_fns = fn_r;
+ }
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int Spartan3_ss_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan3_Slave_Serial_fns *fn = desc->iface_fns;
+ int i;
+ unsigned char val;
+
+ PRINTF ("%s: start with interface functions @ 0x%p\n",
+ __FUNCTION__, fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ PRINTF ("%s: Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ __FUNCTION__, &fn, fn, fn->pgm, fn->init,
+ fn->clk, fn->wr, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (TRUE, TRUE, cookie); /* Assert the program, commit */
+
+ /* Wait for INIT state (init low) */
+ ts = get_timer (0); /* get current time */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to start.\n");
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->init) (cookie));
+
+ /* Get ready for the burn */
+ CONFIG_FPGA_DELAY ();
+ (*fn->pgm) (FALSE, TRUE, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT to go high */
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie));
+
+ /* Load the data */
+ while (bytecount < bsize) {
+
+ /* Xilinx detects an error if INIT goes low (active)
+ while DONE is low (inactive) */
+ if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
+ puts ("** CRC error during FPGA load.\n");
+ return (FPGA_FAIL);
+ }
+ val = data [bytecount ++];
+ i = 8;
+ do {
+ /* Deassert the clock */
+ (*fn->clk) (FALSE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ /* Write data */
+ (*fn->wr) ((val & 0x80), TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ /* Assert the clock */
+ (*fn->clk) (TRUE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ val <<= 1;
+ i --;
+ } while (i > 0);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CONFIG_FPGA_DELAY ();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ (*fn->wr) (TRUE, TRUE, cookie);
+
+ while (! (*fn->done) (cookie)) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (FALSE, TRUE, cookie); /* Deassert the clock pin */
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie); /* Assert the clock pin */
+
+ putc ('*');
+
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+ putc ('\n'); /* terminate the dotted line */
+
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post) {
+ (*fn->post) (cookie);
+ }
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS) {
+ puts ("Done.\n");
+ }
+ else {
+ puts ("Fail.\n");
+ }
+#endif
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int Spartan3_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf ("%s: Slave Serial Dumping is unavailable\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+static int Spartan3_ss_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Xilinx_Spartan3_Slave_Serial_fns *fn_r, *fn =
+ (Xilinx_Spartan3_Slave_Serial_fns *) (desc->iface_fns);
+
+ if (fn) {
+ ulong addr;
+
+ /* Get the relocated table address */
+ addr = (ulong) fn + reloc_offset;
+ fn_r = (Xilinx_Spartan3_Slave_Serial_fns *) addr;
+
+ if (!fn_r->relocated) {
+
+ if (memcmp (fn_r, fn,
+ sizeof (Xilinx_Spartan3_Slave_Serial_fns))
+ == 0) {
+ /* good copy of the table, fix the descriptor pointer */
+ desc->iface_fns = fn_r;
+ } else {
+ PRINTF ("%s: Invalid function table at 0x%p\n",
+ __FUNCTION__, fn_r);
+ return FPGA_FAIL;
+ }
+
+ PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
+ desc);
+
+ if (fn->pre) {
+ addr = (ulong) (fn->pre) + reloc_offset;
+ fn_r->pre = (Xilinx_pre_fn) addr;
+ }
+
+ addr = (ulong) (fn->pgm) + reloc_offset;
+ fn_r->pgm = (Xilinx_pgm_fn) addr;
+
+ addr = (ulong) (fn->init) + reloc_offset;
+ fn_r->init = (Xilinx_init_fn) addr;
+
+ addr = (ulong) (fn->done) + reloc_offset;
+ fn_r->done = (Xilinx_done_fn) addr;
+
+ addr = (ulong) (fn->clk) + reloc_offset;
+ fn_r->clk = (Xilinx_clk_fn) addr;
+
+ addr = (ulong) (fn->wr) + reloc_offset;
+ fn_r->wr = (Xilinx_wr_fn) addr;
+
+ if (fn->post) {
+ addr = (ulong) (fn->post) + reloc_offset;
+ fn_r->post = (Xilinx_post_fn) addr;
+ }
+
+ fn_r->relocated = TRUE;
+
+ } else {
+ /* this table has already been moved */
+ /* XXX - should check to see if the descriptor is correct */
+ desc->iface_fns = fn_r;
+ }
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+
+}
diff --git a/drivers/fpga/stratixII.c b/drivers/fpga/stratixII.c
new file mode 100644
index 0000000..7556dbf
--- /dev/null
+++ b/drivers/fpga/stratixII.c
@@ -0,0 +1,231 @@
+/*
+ * (C) Copyright 2007
+ * Eran Liberty, Extricom , eran.liberty@gmail.com
+ *
+ * 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> /* core U-Boot definitions */
+#include <altera.h>
+
+int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize,
+ int isSerial, int isSecure);
+int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize);
+
+/****************************************************************/
+/* Stratix II Generic Implementation */
+int StratixII_load (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 1, 0);
+ break;
+ case fast_passive_parallel:
+ ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 0);
+ break;
+ case fast_passive_parallel_security:
+ ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 1);
+ break;
+
+ /* Add new interface types here */
+ default:
+ printf ("%s: Unsupported interface type, %d\n", __FUNCTION__,
+ desc->iface);
+ }
+ return ret_val;
+}
+
+int StratixII_dump (Altera_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ case fast_passive_parallel:
+ case fast_passive_parallel_security:
+ ret_val = StratixII_ps_fpp_dump (desc, buf, bsize);
+ break;
+ /* Add new interface types here */
+ default:
+ printf ("%s: Unsupported interface type, %d\n", __FUNCTION__,
+ desc->iface);
+ }
+ return ret_val;
+}
+
+int StratixII_info (Altera_desc * desc)
+{
+ return FPGA_SUCCESS;
+}
+
+int StratixII_reloc (Altera_desc * desc, ulong reloc_offset)
+{
+ int i;
+ uint32_t dest = (uint32_t) desc & 0xff000000;
+
+ /* we assume a relocated code and non relocated code has different upper 8 bits */
+ if (dest != ((uint32_t) desc->iface_fns & 0xff000000)) {
+ desc->iface_fns =
+ (void *)((uint32_t) (desc->iface_fns) + reloc_offset);
+ }
+ for (i = 0; i < sizeof (altera_board_specific_func) / sizeof (void *);
+ i++) {
+ if (dest !=
+ ((uint32_t) (((void **)(desc->iface_fns))[i]) & 0xff000000))
+ {
+ ((void **)(desc->iface_fns))[i] =
+ (void
+ *)(((uint32_t) (((void **)(desc->iface_fns))[i])) +
+ reloc_offset);
+ }
+ }
+ return FPGA_SUCCESS;
+}
+
+int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize)
+{
+ printf ("Stratix II Fast Passive Parallel dump is not implemented\n");
+ return FPGA_FAIL;
+}
+
+int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize,
+ int isSerial, int isSecure)
+{
+ altera_board_specific_func *fns;
+ int cookie;
+ int ret_val = FPGA_FAIL;
+ int bytecount;
+ char *buff = buf;
+ int i;
+
+ if (!desc) {
+ printf ("%s(%d) Altera_desc missing\n", __FUNCTION__, __LINE__);
+ return FPGA_FAIL;
+ }
+ if (!buff) {
+ printf ("%s(%d) buffer is missing\n", __FUNCTION__, __LINE__);
+ return FPGA_FAIL;
+ }
+ if (!bsize) {
+ printf ("%s(%d) size is zero\n", __FUNCTION__, __LINE__);
+ return FPGA_FAIL;
+ }
+ if (!desc->iface_fns) {
+ printf
+ ("%s(%d) Altera_desc function interface table is missing\n",
+ __FUNCTION__, __LINE__);
+ return FPGA_FAIL;
+ }
+ fns = (altera_board_specific_func *) (desc->iface_fns);
+ cookie = desc->cookie;
+
+ if (!
+ (fns->config && fns->status && fns->done && fns->data
+ && fns->abort)) {
+ printf
+ ("%s(%d) Missing some function in the function interface table\n",
+ __FUNCTION__, __LINE__);
+ return FPGA_FAIL;
+ }
+
+ /* 1. give board specific a chance to do anything before we start */
+ if (fns->pre) {
+ if ((ret_val = fns->pre (cookie)) < 0) {
+ return ret_val;
+ }
+ }
+
+ /* from this point on we must fail gracfully by calling lower layer abort */
+
+ /* 2. Strat burn cycle by deasserting config for t_CFG and waiting t_CF2CK after reaserted */
+ fns->config (0, 1, cookie);
+ udelay (5); /* nCONFIG low pulse width 2usec */
+ fns->config (1, 1, cookie);
+ udelay (100); /* nCONFIG high to first rising edge on DCLK */
+
+ /* 3. Start the Data cycle with clk deasserted */
+ bytecount = 0;
+ fns->clk (0, 1, cookie);
+
+ printf ("loading to fpga ");
+ while (bytecount < bsize) {
+ /* 3.1 check stratix has not signaled us an error */
+ if (fns->status (cookie) != 1) {
+ printf
+ ("\n%s(%d) Stratix failed (byte transfered till failure 0x%x)\n",
+ __FUNCTION__, __LINE__, bytecount);
+ fns->abort (cookie);
+ return FPGA_FAIL;
+ }
+ if (isSerial) {
+ int i;
+ uint8_t data = buff[bytecount++];
+ for (i = 0; i < 8; i++) {
+ /* 3.2(ps) put data on the bus */
+ fns->data ((data >> i) & 1, 1, cookie);
+
+ /* 3.3(ps) clock once */
+ fns->clk (1, 1, cookie);
+ fns->clk (0, 1, cookie);
+ }
+ } else {
+ /* 3.2(fpp) put data on the bus */
+ fns->data (buff[bytecount++], 1, cookie);
+
+ /* 3.3(fpp) clock once */
+ fns->clk (1, 1, cookie);
+ fns->clk (0, 1, cookie);
+
+ /* 3.4(fpp) for secure cycle push 3 more clocks */
+ for (i = 0; isSecure && i < 3; i++) {
+ fns->clk (1, 1, cookie);
+ fns->clk (0, 1, cookie);
+ }
+ }
+
+ /* 3.5 while clk is deasserted it is safe to print some progress indication */
+ if ((bytecount % (bsize / 100)) == 0) {
+ printf ("\b\b\b%02d\%", bytecount * 100 / bsize);
+ }
+ }
+
+ /* 4. Set one last clock and check conf done signal */
+ fns->clk (1, 1, cookie);
+ udelay (100);
+ if (!fns->done (cookie)) {
+ printf (" error!.\n");
+ fns->abort (cookie);
+ return FPGA_FAIL;
+ } else {
+ printf ("\b\b\b done.\n");
+ }
+
+ /* 5. call lower layer post configuration */
+ if (fns->post) {
+ if ((ret_val = fns->post (cookie)) < 0) {
+ fns->abort (cookie);
+ return ret_val;
+ }
+ }
+
+ return FPGA_SUCCESS;
+}
diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c
new file mode 100644
index 0000000..50d0921
--- /dev/null
+++ b/drivers/fpga/virtex2.c
@@ -0,0 +1,554 @@
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ * Keith Outwater, keith_outwater@mvis.com
+ *
+ * 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
+ *
+ */
+
+/*
+ * Configuration support for Xilinx Virtex2 devices. Based
+ * on spartan2.c (Rich Ireland, rireland@enterasys.com).
+ */
+
+#include <common.h>
+#include <virtex2.h>
+
+#if 0
+#define FPGA_DEBUG
+#endif
+
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/*
+ * If the SelectMap interface can be overrun by the processor, define
+ * CONFIG_SYS_FPGA_CHECK_BUSY and/or CONFIG_FPGA_DELAY in the board configuration
+ * file and add board-specific support for checking BUSY status. By default,
+ * assume that the SelectMap interface cannot be overrun.
+ */
+#ifndef CONFIG_SYS_FPGA_CHECK_BUSY
+#undef CONFIG_SYS_FPGA_CHECK_BUSY
+#endif
+
+#ifndef CONFIG_FPGA_DELAY
+#define CONFIG_FPGA_DELAY()
+#endif
+
+#ifndef CONFIG_SYS_FPGA_PROG_FEEDBACK
+#define CONFIG_SYS_FPGA_PROG_FEEDBACK
+#endif
+
+/*
+ * Don't allow config cycle to be interrupted
+ */
+#ifndef CONFIG_SYS_FPGA_CHECK_CTRLC
+#undef CONFIG_SYS_FPGA_CHECK_CTRLC
+#endif
+
+/*
+ * Check for errors during configuration by default
+ */
+#ifndef CONFIG_SYS_FPGA_CHECK_ERROR
+#define CONFIG_SYS_FPGA_CHECK_ERROR
+#endif
+
+/*
+ * The default timeout in mS for INIT_B to deassert after PROG_B has
+ * been deasserted. Per the latest Virtex II Handbook (page 347), the
+ * max time from PORG_B deassertion to INIT_B deassertion is 4uS per
+ * data frame for the XC2V8000. The XC2V8000 has 2860 data frames
+ * which yields 11.44 mS. So let's make it bigger in order to handle
+ * an XC2V1000, if anyone can ever get ahold of one.
+ */
+#ifndef CONFIG_SYS_FPGA_WAIT_INIT
+#define CONFIG_SYS_FPGA_WAIT_INIT CONFIG_SYS_HZ/2 /* 500 ms */
+#endif
+
+/*
+ * The default timeout for waiting for BUSY to deassert during configuration.
+ * This is normally not necessary since for most reasonable configuration
+ * clock frequencies (i.e. 66 MHz or less), BUSY monitoring is unnecessary.
+ */
+#ifndef CONFIG_SYS_FPGA_WAIT_BUSY
+#define CONFIG_SYS_FPGA_WAIT_BUSY CONFIG_SYS_HZ/200 /* 5 ms*/
+#endif
+
+/* Default timeout for waiting for FPGA to enter operational mode after
+ * configuration data has been written.
+ */
+#ifndef CONFIG_SYS_FPGA_WAIT_CONFIG
+#define CONFIG_SYS_FPGA_WAIT_CONFIG CONFIG_SYS_HZ/5 /* 200 ms */
+#endif
+
+static int Virtex2_ssm_load (Xilinx_desc * desc, void *buf, size_t bsize);
+static int Virtex2_ssm_dump (Xilinx_desc * desc, void *buf, size_t bsize);
+static int Virtex2_ssm_reloc (Xilinx_desc * desc, ulong reloc_offset);
+
+static int Virtex2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize);
+static int Virtex2_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize);
+static int Virtex2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset);
+
+int Virtex2_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__);
+ ret_val = Virtex2_ss_load (desc, buf, bsize);
+ break;
+
+ case slave_selectmap:
+ PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__);
+ ret_val = Virtex2_ssm_load (desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+ return ret_val;
+}
+
+int Virtex2_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__);
+ ret_val = Virtex2_ss_dump (desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__);
+ ret_val = Virtex2_ssm_dump (desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+ return ret_val;
+}
+
+int Virtex2_info (Xilinx_desc * desc)
+{
+ return FPGA_SUCCESS;
+}
+
+int Virtex2_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL;
+
+ if (desc->family != Xilinx_Virtex2) {
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ return FPGA_FAIL;
+ } else
+ switch (desc->iface) {
+ case slave_serial:
+ ret_val = Virtex2_ss_reloc (desc, reloc_offset);
+ break;
+
+ case slave_selectmap:
+ ret_val = Virtex2_ssm_reloc (desc, reloc_offset);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+ return ret_val;
+}
+
+/*
+ * Virtex-II Slave SelectMap configuration loader. Configuration via
+ * SelectMap is as follows:
+ * 1. Set the FPGA's PROG_B line low.
+ * 2. Set the FPGA's PROG_B line high. Wait for INIT_B to go high.
+ * 3. Write data to the SelectMap port. If INIT_B goes low at any time
+ * this process, a configuration error (most likely CRC failure) has
+ * ocurred. At this point a status word may be read from the
+ * SelectMap interface to determine the source of the problem (You
+ * could, for instance, put this in your 'abort' function handler).
+ * 4. After all data has been written, test the state of the FPGA
+ * INIT_B and DONE lines. If both are high, configuration has
+ * succeeded. Congratulations!
+ */
+static int Virtex2_ssm_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+ Xilinx_Virtex2_Slave_SelectMap_fns *fn = desc->iface_fns;
+
+ PRINTF ("%s:%d: Start with interface functions @ 0x%p\n",
+ __FUNCTION__, __LINE__, fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie;
+ unsigned long ts;
+
+ /* Gotta split this one up (so the stack won't blow??) */
+ PRINTF ("%s:%d: Function Table:\n"
+ " base 0x%p\n"
+ " struct 0x%p\n"
+ " pre 0x%p\n"
+ " prog 0x%p\n"
+ " init 0x%p\n"
+ " error 0x%p\n",
+ __FUNCTION__, __LINE__,
+ &fn, fn, fn->pre, fn->pgm, fn->init, fn->err);
+ PRINTF (" clock 0x%p\n"
+ " cs 0x%p\n"
+ " write 0x%p\n"
+ " rdata 0x%p\n"
+ " wdata 0x%p\n"
+ " busy 0x%p\n"
+ " abort 0x%p\n"
+ " post 0x%p\n\n",
+ fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata,
+ fn->busy, fn->abort, fn->post);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Initializing FPGA Device %d...\n", cookie);
+#endif
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /*
+ * Assert the program line. The minimum pulse width for
+ * Virtex II devices is 300 nS (Tprogram parameter in datasheet).
+ * There is no maximum value for the pulse width. Check to make
+ * sure that INIT_B goes low after assertion of PROG_B
+ */
+ (*fn->pgm) (TRUE, TRUE, cookie);
+ udelay (10);
+ ts = get_timer (0);
+ do {
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) {
+ printf ("%s:%d: ** Timeout after %d ticks waiting for INIT"
+ " to assert.\n", __FUNCTION__, __LINE__,
+ CONFIG_SYS_FPGA_WAIT_INIT);
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->init) (cookie));
+
+ (*fn->pgm) (FALSE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie);
+
+ /*
+ * Start a timer and wait for INIT_B to go high
+ */
+ ts = get_timer (0);
+ do {
+ CONFIG_FPGA_DELAY ();
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) {
+ printf ("%s:%d: ** Timeout after %d ticks waiting for INIT"
+ " to deassert.\n", __FUNCTION__, __LINE__,
+ CONFIG_SYS_FPGA_WAIT_INIT);
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie) && (*fn->busy) (cookie));
+
+ (*fn->wr) (TRUE, TRUE, cookie);
+ (*fn->cs) (TRUE, TRUE, cookie);
+
+ udelay (10000);
+
+ /*
+ * Load the data byte by byte
+ */
+ while (bytecount < bsize) {
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+ if (ctrlc ()) {
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#endif
+
+ if ((*fn->done) (cookie) == FPGA_SUCCESS) {
+ PRINTF ("%s:%d:done went active early, bytecount = %d\n",
+ __FUNCTION__, __LINE__, bytecount);
+ break;
+ }
+
+#ifdef CONFIG_SYS_FPGA_CHECK_ERROR
+ if ((*fn->init) (cookie)) {
+ printf ("\n%s:%d: ** Error: INIT asserted during"
+ " configuration\n", __FUNCTION__, __LINE__);
+ printf ("%d = buffer offset, %d = buffer size\n",
+ bytecount, bsize);
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#endif
+
+ (*fn->wdata) (data[bytecount++], TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+
+ /*
+ * Cycle the clock pin
+ */
+ (*fn->clk) (FALSE, TRUE, cookie);
+ CONFIG_FPGA_DELAY ();
+ (*fn->clk) (TRUE, TRUE, cookie);
+
+#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
+ ts = get_timer (0);
+ while ((*fn->busy) (cookie)) {
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_BUSY) {
+ printf ("%s:%d: ** Timeout after %d ticks waiting for"
+ " BUSY to deassert\n",
+ __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_BUSY);
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.');
+#endif
+ }
+
+ /*
+ * Finished writing the data; deassert FPGA CS_B and WRITE_B signals.
+ */
+ CONFIG_FPGA_DELAY ();
+ (*fn->cs) (FALSE, TRUE, cookie);
+ (*fn->wr) (FALSE, TRUE, cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n');
+#endif
+
+ /*
+ * Check for successful configuration. FPGA INIT_B and DONE should
+ * both be high upon successful configuration.
+ */
+ ts = get_timer (0);
+ ret_val = FPGA_SUCCESS;
+ while (((*fn->done) (cookie) == FPGA_FAIL) || (*fn->init) (cookie)) {
+ if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_CONFIG) {
+ printf ("%s:%d: ** Timeout after %d ticks waiting for DONE to"
+ "assert and INIT to deassert\n",
+ __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_CONFIG);
+ (*fn->abort) (cookie);
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+
+ if (ret_val == FPGA_SUCCESS) {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Initialization of FPGA device %d complete\n", cookie);
+#endif
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post) {
+ (*fn->post) (cookie);
+ }
+ } else {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("** Initialization of FPGA device %d FAILED\n",
+ cookie);
+#endif
+ }
+ } else {
+ printf ("%s:%d: NULL Interface function table!\n",
+ __FUNCTION__, __LINE__);
+ }
+ return ret_val;
+}
+
+/*
+ * Read the FPGA configuration data
+ */
+static int Virtex2_ssm_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+ Xilinx_Virtex2_Slave_SelectMap_fns *fn = desc->iface_fns;
+
+ if (fn) {
+ unsigned char *data = (unsigned char *) buf;
+ size_t bytecount = 0;
+ int cookie = desc->cookie;
+
+ printf ("Starting Dump of FPGA Device %d...\n", cookie);
+
+ (*fn->cs) (TRUE, TRUE, cookie);
+ (*fn->clk) (TRUE, TRUE, cookie);
+
+ while (bytecount < bsize) {
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+ if (ctrlc ()) {
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#endif
+ /*
+ * Cycle the clock and read the data
+ */
+ (*fn->clk) (FALSE, TRUE, cookie);
+ (*fn->clk) (TRUE, TRUE, cookie);
+ (*fn->rdata) (&(data[bytecount++]), cookie);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.');
+#endif
+ }
+
+ /*
+ * Deassert CS_B and cycle the clock to deselect the device.
+ */
+ (*fn->cs) (FALSE, FALSE, cookie);
+ (*fn->clk) (FALSE, TRUE, cookie);
+ (*fn->clk) (TRUE, TRUE, cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n');
+#endif
+ puts ("Done.\n");
+ } else {
+ printf ("%s:%d: NULL Interface function table!\n",
+ __FUNCTION__, __LINE__);
+ }
+ return ret_val;
+}
+
+/*
+ * Relocate the addresses in the function table from FLASH (or ROM,
+ * or whatever) to RAM.
+ */
+static int Virtex2_ssm_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ ulong addr;
+ int ret_val = FPGA_FAIL;
+ Xilinx_Virtex2_Slave_SelectMap_fns *fn_r, *fn =
+ (Xilinx_Virtex2_Slave_SelectMap_fns *) (desc->iface_fns);
+
+ if (fn) {
+ /*
+ * Get the relocated table address
+ */
+ addr = (ulong) fn + reloc_offset;
+ fn_r = (Xilinx_Virtex2_Slave_SelectMap_fns *) addr;
+
+ /*
+ * Check to see if the table has already been relocated. If not, do
+ * a sanity check to make sure there is a faithful copy of the
+ * FLASH based function table in RAM, then adjust the table.
+ */
+ if (!fn_r->relocated) {
+ if (memcmp
+ (fn_r, fn, sizeof (Xilinx_Virtex2_Slave_SelectMap_fns))
+ == 0) {
+ desc->iface_fns = fn_r;
+ } else {
+ PRINTF ("%s:%d: Invalid function table at 0x%p\n",
+ __FUNCTION__, __LINE__, fn_r);
+ return FPGA_FAIL;
+ }
+
+ PRINTF ("%s:%d: Relocating descriptor at 0x%p\n",
+ __FUNCTION__, __LINE__, desc);
+
+ addr = (ulong) (fn->pre) + reloc_offset;
+ fn_r->pre = (Xilinx_pre_fn) addr;
+ addr = (ulong) (fn->pgm) + reloc_offset;
+ fn_r->pgm = (Xilinx_pgm_fn) addr;
+ addr = (ulong) (fn->init) + reloc_offset;
+ fn_r->init = (Xilinx_init_fn) addr;
+ addr = (ulong) (fn->done) + reloc_offset;
+ fn_r->done = (Xilinx_done_fn) addr;
+ addr = (ulong) (fn->err) + reloc_offset;
+ fn_r->err = (Xilinx_err_fn) addr;
+ addr = (ulong) (fn->clk) + reloc_offset;
+ fn_r->clk = (Xilinx_clk_fn) addr;
+ addr = (ulong) (fn->cs) + reloc_offset;
+ fn_r->cs = (Xilinx_cs_fn) addr;
+ addr = (ulong) (fn->wr) + reloc_offset;
+ fn_r->wr = (Xilinx_wr_fn) addr;
+ addr = (ulong) (fn->rdata) + reloc_offset;
+ fn_r->rdata = (Xilinx_rdata_fn) addr;
+ addr = (ulong) (fn->wdata) + reloc_offset;
+ fn_r->wdata = (Xilinx_wdata_fn) addr;
+ addr = (ulong) (fn->busy) + reloc_offset;
+ fn_r->busy = (Xilinx_busy_fn) addr;
+ addr = (ulong) (fn->abort) + reloc_offset;
+ fn_r->abort = (Xilinx_abort_fn) addr;
+ addr = (ulong) (fn->post) + reloc_offset;
+ fn_r->post = (Xilinx_post_fn) addr;
+ fn_r->relocated = TRUE;
+ } else {
+ printf ("%s:%d: Function table @0x%p has already been relocated\n", __FUNCTION__, __LINE__, fn_r);
+ desc->iface_fns = fn_r;
+ }
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+ return ret_val;
+}
+
+static int Virtex2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ printf ("%s: Slave Serial Loading is unsupported\n", __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+static int Virtex2_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ printf ("%s: Slave Serial Dumping is unsupported\n", __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+static int Virtex2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL;
+ Xilinx_Virtex2_Slave_Serial_fns *fn =
+ (Xilinx_Virtex2_Slave_Serial_fns *) (desc->iface_fns);
+
+ if (fn) {
+ printf ("%s:%d: Slave Serial Loading is unsupported\n",
+ __FUNCTION__, __LINE__);
+ } else {
+ printf ("%s:%d: NULL Interface function table!\n",
+ __FUNCTION__, __LINE__);
+ }
+ return ret_val;
+}
+
+/* vim: set ts=4 tw=78: */
diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c
new file mode 100644
index 0000000..7b5e8c5
--- /dev/null
+++ b/drivers/fpga/xilinx.c
@@ -0,0 +1,307 @@
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ * Keith Outwater, keith_outwater@mvis.com
+ *
+ * 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
+ *
+ */
+
+/*
+ * Xilinx FPGA support
+ */
+
+#include <common.h>
+#include <virtex2.h>
+#include <spartan2.h>
+#include <spartan3.h>
+
+#if 0
+#define FPGA_DEBUG
+#endif
+
+/* Define FPGA_DEBUG to get debug printf's */
+#ifdef FPGA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Local Static Functions */
+static int xilinx_validate (Xilinx_desc * desc, char *fn);
+
+/* ------------------------------------------------------------------------- */
+
+int xilinx_load (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ } else
+ switch (desc->family) {
+ case Xilinx_Spartan2:
+#if defined(CONFIG_FPGA_SPARTAN2)
+ PRINTF ("%s: Launching the Spartan-II Loader...\n",
+ __FUNCTION__);
+ ret_val = Spartan2_load (desc, buf, bsize);
+#else
+ printf ("%s: No support for Spartan-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Spartan3:
+#if defined(CONFIG_FPGA_SPARTAN3)
+ PRINTF ("%s: Launching the Spartan-III Loader...\n",
+ __FUNCTION__);
+ ret_val = Spartan3_load (desc, buf, bsize);
+#else
+ printf ("%s: No support for Spartan-III devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Virtex2:
+#if defined(CONFIG_FPGA_VIRTEX2)
+ PRINTF ("%s: Launching the Virtex-II Loader...\n",
+ __FUNCTION__);
+ ret_val = Virtex2_load (desc, buf, bsize);
+#else
+ printf ("%s: No support for Virtex-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+
+ default:
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ }
+
+ return ret_val;
+}
+
+int xilinx_dump (Xilinx_desc * desc, void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ } else
+ switch (desc->family) {
+ case Xilinx_Spartan2:
+#if defined(CONFIG_FPGA_SPARTAN2)
+ PRINTF ("%s: Launching the Spartan-II Reader...\n",
+ __FUNCTION__);
+ ret_val = Spartan2_dump (desc, buf, bsize);
+#else
+ printf ("%s: No support for Spartan-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Spartan3:
+#if defined(CONFIG_FPGA_SPARTAN3)
+ PRINTF ("%s: Launching the Spartan-III Reader...\n",
+ __FUNCTION__);
+ ret_val = Spartan3_dump (desc, buf, bsize);
+#else
+ printf ("%s: No support for Spartan-III devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Virtex2:
+#if defined( CONFIG_FPGA_VIRTEX2)
+ PRINTF ("%s: Launching the Virtex-II Reader...\n",
+ __FUNCTION__);
+ ret_val = Virtex2_dump (desc, buf, bsize);
+#else
+ printf ("%s: No support for Virtex-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+
+ default:
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ }
+
+ return ret_val;
+}
+
+int xilinx_info (Xilinx_desc * desc)
+{
+ int ret_val = FPGA_FAIL;
+
+ if (xilinx_validate (desc, (char *)__FUNCTION__)) {
+ printf ("Family: \t");
+ switch (desc->family) {
+ case Xilinx_Spartan2:
+ printf ("Spartan-II\n");
+ break;
+ case Xilinx_Spartan3:
+ printf ("Spartan-III\n");
+ break;
+ case Xilinx_Virtex2:
+ printf ("Virtex-II\n");
+ break;
+ /* Add new family types here */
+ default:
+ printf ("Unknown family type, %d\n", desc->family);
+ }
+
+ printf ("Interface type:\t");
+ switch (desc->iface) {
+ case slave_serial:
+ printf ("Slave Serial\n");
+ break;
+ case master_serial: /* Not used */
+ printf ("Master Serial\n");
+ break;
+ case slave_parallel:
+ printf ("Slave Parallel\n");
+ break;
+ case jtag_mode: /* Not used */
+ printf ("JTAG Mode\n");
+ break;
+ case slave_selectmap:
+ printf ("Slave SelectMap Mode\n");
+ break;
+ case master_selectmap:
+ printf ("Master SelectMap Mode\n");
+ break;
+ /* Add new interface types here */
+ default:
+ printf ("Unsupported interface type, %d\n", desc->iface);
+ }
+
+ printf ("Device Size: \t%d bytes\n"
+ "Cookie: \t0x%x (%d)\n",
+ desc->size, desc->cookie, desc->cookie);
+
+ if (desc->iface_fns) {
+ printf ("Device Function Table @ 0x%p\n", desc->iface_fns);
+ switch (desc->family) {
+ case Xilinx_Spartan2:
+#if defined(CONFIG_FPGA_SPARTAN2)
+ Spartan2_info (desc);
+#else
+ /* just in case */
+ printf ("%s: No support for Spartan-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Spartan3:
+#if defined(CONFIG_FPGA_SPARTAN3)
+ Spartan3_info (desc);
+#else
+ /* just in case */
+ printf ("%s: No support for Spartan-III devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Virtex2:
+#if defined(CONFIG_FPGA_VIRTEX2)
+ Virtex2_info (desc);
+#else
+ /* just in case */
+ printf ("%s: No support for Virtex-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ /* Add new family types here */
+ default:
+ /* we don't need a message here - we give one up above */
+ ;
+ }
+ } else
+ printf ("No Device Function Table.\n");
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+int xilinx_reloc (Xilinx_desc * desc, ulong reloc_offset)
+{
+ int ret_val = FPGA_FAIL; /* assume a failure */
+
+ if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ } else
+ switch (desc->family) {
+ case Xilinx_Spartan2:
+#if defined(CONFIG_FPGA_SPARTAN2)
+ ret_val = Spartan2_reloc (desc, reloc_offset);
+#else
+ printf ("%s: No support for Spartan-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Spartan3:
+#if defined(CONFIG_FPGA_SPARTAN3)
+ ret_val = Spartan3_reloc (desc, reloc_offset);
+#else
+ printf ("%s: No support for Spartan-III devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ case Xilinx_Virtex2:
+#if defined(CONFIG_FPGA_VIRTEX2)
+ ret_val = Virtex2_reloc (desc, reloc_offset);
+#else
+ printf ("%s: No support for Virtex-II devices.\n",
+ __FUNCTION__);
+#endif
+ break;
+ /* Add new family types here */
+ default:
+ printf ("%s: Unsupported family type, %d\n",
+ __FUNCTION__, desc->family);
+ }
+
+ return ret_val;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+static int xilinx_validate (Xilinx_desc * desc, char *fn)
+{
+ int ret_val = FALSE;
+
+ if (desc) {
+ if ((desc->family > min_xilinx_type) &&
+ (desc->family < max_xilinx_type)) {
+ if ((desc->iface > min_xilinx_iface_type) &&
+ (desc->iface < max_xilinx_iface_type)) {
+ if (desc->size) {
+ ret_val = TRUE;
+ } else
+ printf ("%s: NULL part size\n", fn);
+ } else
+ printf ("%s: Invalid Interface type, %d\n",
+ fn, desc->iface);
+ } else
+ printf ("%s: Invalid family type, %d\n", fn, desc->family);
+ } else
+ printf ("%s: NULL descriptor!\n", fn);
+
+ return ret_val;
+}
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 7f7d3db..59302fa 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_DTT_ADT7460) += adt7460.o
COBJS-$(CONFIG_DTT_DS1621) += ds1621.o
COBJS-$(CONFIG_DTT_DS1722) += ds1722.o
COBJS-$(CONFIG_DTT_DS1775) += ds1775.o
+COBJS-$(CONFIG_DTT_LM63) += lm63.o
COBJS-$(CONFIG_DTT_LM73) += lm73.o
COBJS-$(CONFIG_DTT_LM75) += lm75.o
COBJS-$(CONFIG_DTT_LM81) += lm81.o
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index b791ec0..d753e9a 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -81,7 +81,7 @@ typedef
}
dtt_cfg_t;
-dtt_cfg_t dttcfg[] = CFG_DTT_ADM1021;
+dtt_cfg_t dttcfg[] = CONFIG_SYS_DTT_ADM1021;
int
dtt_read (int sensor, int reg)
@@ -174,7 +174,7 @@ dtt_init (void)
const char *const header = "DTT: ";
/* switch to correct I2C bus */
- I2C_SET_BUS(CFG_DTT_BUS_NUM);
+ I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
for (i = 0; i < sizeof(sensors); i++) {
if (_dtt_init(sensors[i]) != 0)
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 749aa26..d15a082 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -26,11 +26,6 @@
*/
#include <common.h>
-
-#if !defined(CFG_EEPROM_PAGE_WRITE_ENABLE) || \
- (CFG_EEPROM_PAGE_WRITE_BITS < 1)
-# error "CFG_EEPROM_PAGE_WRITE_ENABLE must be defined and CFG_EEPROM_PAGE_WRITE_BITS must be greater than 1 to use CONFIG_DTT_DS1621"
-#endif
#include <i2c.h>
#include <dtt.h>
@@ -130,7 +125,7 @@ static int _dtt_init(int sensor)
/*
* Setup High Temp.
*/
- val = ((CFG_DTT_MAX_TEMP * 2) << 7) & 0xff80;
+ val = ((CONFIG_SYS_DTT_MAX_TEMP * 2) << 7) & 0xff80;
if (dtt_write(sensor, DTT_TEMP_HIGH, val) != 0)
return 1;
udelay(50000); /* Max 50ms */
@@ -138,7 +133,7 @@ static int _dtt_init(int sensor)
/*
* Setup Low Temp - hysteresis.
*/
- val = (((CFG_DTT_MAX_TEMP - CFG_DTT_HYSTERESIS) * 2) << 7) & 0xff80;
+ val = (((CONFIG_SYS_DTT_MAX_TEMP - CONFIG_SYS_DTT_HYSTERESIS) * 2) << 7) & 0xff80;
if (dtt_write(sensor, DTT_TEMP_LOW, val) != 0)
return 1;
udelay(50000); /* Max 50ms */
diff --git a/drivers/hwmon/ds1775.c b/drivers/hwmon/ds1775.c
index 6a4d8e5..80fb26f 100644
--- a/drivers/hwmon/ds1775.c
+++ b/drivers/hwmon/ds1775.c
@@ -24,7 +24,7 @@
#include <i2c.h>
#include <dtt.h>
-#define DTT_I2C_DEV_CODE CFG_I2C_DTT_ADDR /* Dallas Semi's DS1775 device code */
+#define DTT_I2C_DEV_CODE CONFIG_SYS_I2C_DTT_ADDR /* Dallas Semi's DS1775 device code */
#define DTT_READ_TEMP 0x0
#define DTT_CONFIG 0x1
#define DTT_TEMP_HYST 0x2
@@ -105,7 +105,7 @@ static int _dtt_init(int sensor)
/*
* Setup High Temp
*/
- val = ((CFG_DTT_MAX_TEMP * 2) << 7) & 0xff80;
+ val = ((CONFIG_SYS_DTT_MAX_TEMP * 2) << 7) & 0xff80;
if (dtt_write(sensor, DTT_TEMP_OS, val) != 0)
return 1;
udelay(50000); /* Max 50ms */
@@ -113,7 +113,7 @@ static int _dtt_init(int sensor)
/*
* Setup Low Temp - hysteresis
*/
- val = (((CFG_DTT_MAX_TEMP - CFG_DTT_HYSTERESIS) * 2) << 7) & 0xff80;
+ val = (((CONFIG_SYS_DTT_MAX_TEMP - CONFIG_SYS_DTT_HYSTERESIS) * 2) << 7) & 0xff80;
if (dtt_write(sensor, DTT_TEMP_HYST, val) != 0)
return 1;
udelay(50000); /* Max 50ms */
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
new file mode 100644
index 0000000..03616e1
--- /dev/null
+++ b/drivers/hwmon/lm63.c
@@ -0,0 +1,174 @@
+/*
+ * (C) Copyright 2007-2008
+ * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
+ * based on lm75.c by Bill Hunter
+ *
+ * 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
+ */
+
+/*
+ * National LM63 Temperature Sensor
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <dtt.h>
+
+#define DTT_I2C_DEV_CODE 0x4C /* National LM63 device */
+
+#define DTT_READ_TEMP_RMT_MSB 0x01
+#define DTT_CONFIG 0x03
+#define DTT_READ_TEMP_RMT_LSB 0x10
+#define DTT_TACHLIM_LSB 0x48
+#define DTT_TACHLIM_MSB 0x49
+#define DTT_FAN_CONFIG 0x4A
+#define DTT_PWM_FREQ 0x4D
+#define DTT_PWM_LOOKUP_BASE 0x50
+
+struct pwm_lookup_entry {
+ u8 temp;
+ u8 pwm;
+};
+
+/*
+ * Device code
+ */
+
+int dtt_read(int sensor, int reg)
+{
+ int dlen;
+ uchar data[2];
+
+ /*
+ * Calculate sensor address and register.
+ */
+ sensor = DTT_I2C_DEV_CODE; /* address of lm63 is not adjustable */
+
+ dlen = 1;
+
+ /*
+ * Now try to read the register.
+ */
+ if (i2c_read(sensor, reg, 1, data, dlen) != 0)
+ return -1;
+
+ return (int)data[0];
+} /* dtt_read() */
+
+int dtt_write(int sensor, int reg, int val)
+{
+ int dlen;
+ uchar data[2];
+
+ /*
+ * Calculate sensor address and register.
+ */
+ sensor = DTT_I2C_DEV_CODE; /* address of lm63 is not adjustable */
+
+ dlen = 1;
+ data[0] = (char)(val & 0xff);
+
+ /*
+ * Write value to register.
+ */
+ if (i2c_write(sensor, reg, 1, data, dlen) != 0)
+ return 1;
+
+ return 0;
+} /* dtt_write() */
+
+static int _dtt_init(int sensor)
+{
+ int i;
+ int val;
+
+ struct pwm_lookup_entry pwm_lookup[] = CONFIG_DTT_PWM_LOOKUPTABLE;
+
+ /*
+ * Set PWM Frequency to 2.5% resolution
+ */
+ val = 20;
+ if (dtt_write(sensor, DTT_PWM_FREQ, val) != 0)
+ return 1;
+
+ /*
+ * Set Tachometer Limit
+ */
+ val = CONFIG_DTT_TACH_LIMIT;
+ if (dtt_write(sensor, DTT_TACHLIM_LSB, val & 0xff) != 0)
+ return 1;
+ if (dtt_write(sensor, DTT_TACHLIM_MSB, (val >> 8) & 0xff) != 0)
+ return 1;
+
+ /*
+ * Setup PWM Lookup-Table
+ */
+ for (i = 0; i < sizeof(pwm_lookup) / sizeof(struct pwm_lookup_entry);
+ i++) {
+ int address = DTT_PWM_LOOKUP_BASE + 2 * i;
+ val = pwm_lookup[i].temp;
+ if (dtt_write(sensor, address, val) != 0)
+ return 1;
+ val = pwm_lookup[i].pwm;
+ if (dtt_write(sensor, address + 1, val) != 0)
+ return 1;
+ }
+
+ /*
+ * Enable PWM Lookup-Table, PWM Clock 360 kHz, Tachometer Mode 2
+ */
+ val = 0x02;
+ if (dtt_write(sensor, DTT_FAN_CONFIG, val) != 0)
+ return 1;
+
+ /*
+ * Enable Tach input
+ */
+ val = dtt_read(sensor, DTT_CONFIG) | 0x04;
+ if (dtt_write(sensor, DTT_CONFIG, val) != 0)
+ return 1;
+
+ return 0;
+}
+
+int dtt_get_temp(int sensor)
+{
+ s16 temp = (dtt_read(sensor, DTT_READ_TEMP_RMT_MSB) << 8)
+ | (dtt_read(sensor, DTT_READ_TEMP_RMT_LSB));
+
+ /* Ignore LSB for now, U-Boot only prints natural numbers */
+ return temp >> 8;
+}
+
+int dtt_init(void)
+{
+ int i;
+ unsigned char sensors[] = CONFIG_DTT_SENSORS;
+ const char *const header = "DTT: ";
+
+ for (i = 0; i < sizeof(sensors); i++) {
+ if (_dtt_init(sensors[i]) != 0)
+ printf("%s%d FAILED INIT\n", header, i + 1);
+ else
+ printf("%s%d is %i C\n", header, i + 1,
+ dtt_get_temp(sensors[i]));
+ }
+
+ return 0;
+}
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
index dd24683..7b5d893 100644
--- a/drivers/hwmon/lm73.c
+++ b/drivers/hwmon/lm73.c
@@ -124,11 +124,11 @@ static int _dtt_init(int const sensor)
/*
* Setup THIGH (upper-limit) and TLOW (lower-limit) registers
*/
- val = CFG_DTT_MAX_TEMP << 7;
+ val = CONFIG_SYS_DTT_MAX_TEMP << 7;
if (dtt_write(sensor, DTT_TEMP_HIGH, val))
return -1;
- val = CFG_DTT_MIN_TEMP << 7;
+ val = CONFIG_SYS_DTT_MIN_TEMP << 7;
if (dtt_write(sensor, DTT_TEMP_LOW, val))
return -1;
/*
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 8051cb2..8119821 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -26,19 +26,17 @@
*/
#include <common.h>
-
-#if !defined(CFG_EEPROM_PAGE_WRITE_ENABLE) || \
- (CFG_EEPROM_PAGE_WRITE_BITS < 1)
-# error "CFG_EEPROM_PAGE_WRITE_ENABLE must be defined and CFG_EEPROM_PAGE_WRITE_BITS must be greater than 1 to use CONFIG_DTT_LM75"
-#endif
-
#include <i2c.h>
#include <dtt.h>
/*
* Device code
*/
+#if defined(CONFIG_SYS_I2C_DTT_ADDR)
+#define DTT_I2C_DEV_CODE CONFIG_SYS_I2C_DTT_ADDR
+#else
#define DTT_I2C_DEV_CODE 0x48 /* ON Semi's LM75 device */
+#endif
#define DTT_READ_TEMP 0x0
#define DTT_CONFIG 0x1
#define DTT_TEMP_HYST 0x2
@@ -46,159 +44,141 @@
int dtt_read(int sensor, int reg)
{
- int dlen;
- uchar data[2];
+ int dlen;
+ uchar data[2];
#ifdef CONFIG_DTT_AD7414
- /*
- * On AD7414 the first value upon bootup is not read correctly.
- * This is most likely because of the 800ms update time of the
- * temp register in normal update mode. To get current values
- * each time we issue the "dtt" command including upon powerup
- * we switch into one-short mode.
- *
- * Issue one-shot mode command
- */
- dtt_write(sensor, DTT_CONFIG, 0x64);
+ /*
+ * On AD7414 the first value upon bootup is not read correctly.
+ * This is most likely because of the 800ms update time of the
+ * temp register in normal update mode. To get current values
+ * each time we issue the "dtt" command including upon powerup
+ * we switch into one-short mode.
+ *
+ * Issue one-shot mode command
+ */
+ dtt_write(sensor, DTT_CONFIG, 0x64);
#endif
- /*
- * Validate 'reg' param
- */
- if((reg < 0) || (reg > 3))
- return -1;
-
- /*
- * Calculate sensor address and register.
- */
- sensor = DTT_I2C_DEV_CODE + (sensor & 0x07); /* calculate address of lm75 */
-
- /*
- * Prepare to handle 2 byte result.
- */
- if ((reg == DTT_READ_TEMP) ||
- (reg == DTT_TEMP_HYST) ||
- (reg == DTT_TEMP_SET))
- dlen = 2;
- else
- dlen = 1;
-
- /*
- * Now try to read the register.
- */
- if (i2c_read(sensor, reg, 1, data, dlen) != 0)
- return -1;
-
- /*
- * Handle 2 byte result.
- */
- if (dlen == 2)
- return ((int)((short)data[1] + (((short)data[0]) << 8)));
-
-
- return (int)data[0];
+ /* Validate 'reg' param */
+ if((reg < 0) || (reg > 3))
+ return -1;
+
+ /* Calculate sensor address and register. */
+ sensor = DTT_I2C_DEV_CODE + (sensor & 0x07);
+
+ /* Prepare to handle 2 byte result. */
+ if ((reg == DTT_READ_TEMP) ||
+ (reg == DTT_TEMP_HYST) ||
+ (reg == DTT_TEMP_SET))
+ dlen = 2;
+ else
+ dlen = 1;
+
+ /* Now try to read the register. */
+ if (i2c_read(sensor, reg, 1, data, dlen) != 0)
+ return -1;
+
+ /* Handle 2 byte result. */
+ if (dlen == 2)
+ return ((int)((short)data[1] + (((short)data[0]) << 8)));
+
+ return (int)data[0];
} /* dtt_read() */
int dtt_write(int sensor, int reg, int val)
{
- int dlen;
- uchar data[2];
-
- /*
- * Validate 'reg' param
- */
- if ((reg < 0) || (reg > 3))
- return 1;
-
- /*
- * Calculate sensor address and register.
- */
- sensor = DTT_I2C_DEV_CODE + (sensor & 0x07); /* calculate address of lm75 */
-
- /*
- * Handle 2 byte values.
- */
- if ((reg == DTT_READ_TEMP) ||
- (reg == DTT_TEMP_HYST) ||
- (reg == DTT_TEMP_SET)) {
- dlen = 2;
- data[0] = (char)((val >> 8) & 0xff); /* MSB first */
- data[1] = (char)(val & 0xff);
- } else {
- dlen = 1;
- data[0] = (char)(val & 0xff);
- }
-
- /*
- * Write value to register.
- */
- if (i2c_write(sensor, reg, 1, data, dlen) != 0)
- return 1;
-
- return 0;
+ int dlen;
+ uchar data[2];
+
+ /* Validate 'reg' param */
+ if ((reg < 0) || (reg > 3))
+ return 1;
+
+ /* Calculate sensor address and register. */
+ sensor = DTT_I2C_DEV_CODE + (sensor & 0x07);
+
+ /* Handle 2 byte values. */
+ if ((reg == DTT_READ_TEMP) ||
+ (reg == DTT_TEMP_HYST) ||
+ (reg == DTT_TEMP_SET)) {
+ dlen = 2;
+ data[0] = (char)((val >> 8) & 0xff); /* MSB first */
+ data[1] = (char)(val & 0xff);
+ } else {
+ dlen = 1;
+ data[0] = (char)(val & 0xff);
+ }
+
+ /* Write value to register. */
+ if (i2c_write(sensor, reg, 1, data, dlen) != 0)
+ return 1;
+
+ return 0;
} /* dtt_write() */
static int _dtt_init(int sensor)
{
- int val;
-
- /*
- * Setup TSET ( trip point ) register
- */
- val = ((CFG_DTT_MAX_TEMP * 2) << 7) & 0xff80; /* trip */
- if (dtt_write(sensor, DTT_TEMP_SET, val) != 0)
- return 1;
-
- /*
- * Setup THYST ( untrip point ) register - Hysteresis
- */
- val = (((CFG_DTT_MAX_TEMP - CFG_DTT_HYSTERESIS) * 2) << 7) & 0xff80;
- if (dtt_write(sensor, DTT_TEMP_HYST, val) != 0)
- return 1;
-
- /*
- * Setup configuraton register
- */
+ int val;
+
+ /* Setup TSET ( trip point ) register */
+ val = ((CONFIG_SYS_DTT_MAX_TEMP * 2) << 7) & 0xff80; /* trip */
+ if (dtt_write(sensor, DTT_TEMP_SET, val) != 0)
+ return 1;
+
+ /* Setup THYST ( untrip point ) register - Hysteresis */
+ val = (((CONFIG_SYS_DTT_MAX_TEMP - CONFIG_SYS_DTT_HYSTERESIS) * 2) << 7) & 0xff80;
+ if (dtt_write(sensor, DTT_TEMP_HYST, val) != 0)
+ return 1;
+
+ /* Setup configuraton register */
#ifdef CONFIG_DTT_AD7414
- /* config = alert active low and disabled */
- val = 0x60;
+ /* config = alert active low and disabled */
+ val = 0x60;
#else
- /* config = 6 sample integration, int mode, active low, and enable */
- val = 0x18;
+ /* config = 6 sample integration, int mode, active low, and enable */
+ val = 0x18;
#endif
- if (dtt_write(sensor, DTT_CONFIG, val) != 0)
- return 1;
+ if (dtt_write(sensor, DTT_CONFIG, val) != 0)
+ return 1;
- return 0;
+ return 0;
} /* _dtt_init() */
int dtt_init (void)
{
- int i;
- unsigned char sensors[] = CONFIG_DTT_SENSORS;
- const char *const header = "DTT: ";
+ int i;
+ unsigned char sensors[] = CONFIG_DTT_SENSORS;
+ const char *const header = "DTT: ";
+ int old_bus;
- for (i = 0; i < sizeof(sensors); i++) {
+ /* switch to correct I2C bus */
+ old_bus = I2C_GET_BUS();
+ I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
+
+ for (i = 0; i < sizeof(sensors); i++) {
if (_dtt_init(sensors[i]) != 0)
- printf("%s%d FAILED INIT\n", header, i+1);
+ printf("%s%d FAILED INIT\n", header, i+1);
else
- printf("%s%d is %i C\n", header, i+1,
- dtt_get_temp(sensors[i]));
- }
+ printf("%s%d is %i C\n", header, i+1,
+ dtt_get_temp(sensors[i]));
+ }
+ /* switch back to original I2C bus */
+ I2C_SET_BUS(old_bus);
- return (0);
+ return (0);
} /* dtt_init() */
int dtt_get_temp(int sensor)
{
- int const ret = dtt_read(sensor, DTT_READ_TEMP);
+ int const ret = dtt_read(sensor, DTT_READ_TEMP);
- if (ret < 0) {
- printf("DTT temperature read failed.\n");
- return 0;
- }
- return (int)((int16_t) ret / 256);
+ if (ret < 0) {
+ printf("DTT temperature read failed.\n");
+ return 0;
+ }
+ return (int)((int16_t) ret / 256);
} /* dtt_get_temp() */
diff --git a/drivers/hwmon/lm81.c b/drivers/hwmon/lm81.c
index 9349eb6..668ee9f 100644
--- a/drivers/hwmon/lm81.c
+++ b/drivers/hwmon/lm81.c
@@ -31,12 +31,6 @@
*/
#include <common.h>
-
-#if !defined(CFG_EEPROM_PAGE_WRITE_ENABLE) || \
- (CFG_EEPROM_PAGE_WRITE_BITS < 1)
-# error "CFG_EEPROM_PAGE_WRITE_ENABLE must be defined and CFG_EEPROM_PAGE_WRITE_BITS must be greater than 1 to use CONFIG_DTT_LM81"
-#endif
-
#include <i2c.h>
#include <dtt.h>
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 264553d..ce646fd 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -26,7 +26,7 @@
#include <asm/io.h>
#include <asm/fsl_i2c.h> /* HW definitions */
-#define I2C_TIMEOUT (CFG_HZ / 4)
+#define I2C_TIMEOUT (CONFIG_SYS_HZ / 4)
#define I2C_READ_BIT 1
#define I2C_WRITE_BIT 0
@@ -38,18 +38,17 @@ DECLARE_GLOBAL_DATA_PTR;
* runs from ROM, and we can't switch buses because we can't modify
* the global variables.
*/
-#ifdef CFG_SPD_BUS_NUM
-static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS_NUM;
-#else
-static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0;
+#ifndef CONFIG_SYS_SPD_BUS_NUM
+#define CONFIG_SYS_SPD_BUS_NUM 0
#endif
+static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = CONFIG_SYS_SPD_BUS_NUM;
-static unsigned int i2c_bus_speed[2] = {CFG_I2C_SPEED, CFG_I2C_SPEED};
+static unsigned int i2c_bus_speed[2] = {CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED};
static const struct fsl_i2c *i2c_dev[2] = {
- (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET),
-#ifdef CFG_I2C2_OFFSET
- (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET)
+ (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET),
+#ifdef CONFIG_SYS_I2C2_OFFSET
+ (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C2_OFFSET)
#endif
};
@@ -176,7 +175,7 @@ i2c_init(int speed, int slaveadd)
struct fsl_i2c *dev;
unsigned int temp;
- dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET);
+ dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
writeb(0, &dev->cr); /* stop I2C controller */
udelay(5); /* let it shutdown in peace */
@@ -187,8 +186,8 @@ i2c_init(int speed, int slaveadd)
writeb(0x0, &dev->sr); /* clear status register */
writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
-#ifdef CFG_I2C2_OFFSET
- dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET);
+#ifdef CONFIG_SYS_I2C2_OFFSET
+ dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C2_OFFSET);
writeb(0, &dev->cr); /* stop I2C controller */
udelay(5); /* let it shutdown in peace */
@@ -368,25 +367,9 @@ i2c_probe(uchar chip)
return i2c_read(chip, 0, 0, NULL, 0);
}
-uchar
-i2c_reg_read(uchar i2c_addr, uchar reg)
-{
- uchar buf[1];
-
- i2c_read(i2c_addr, reg, 1, buf, 1);
-
- return buf[0];
-}
-
-void
-i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
-{
- i2c_write(i2c_addr, reg, 1, &val, 1);
-}
-
int i2c_set_bus_num(unsigned int bus)
{
-#ifdef CFG_I2C2_OFFSET
+#ifdef CONFIG_SYS_I2C2_OFFSET
if (bus > 1) {
#else
if (bus > 0) {
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index 1f6ba1f..eedad06 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -47,14 +47,14 @@
#define I2SR_IIF (1 << 1)
#define I2SR_RX_NO_AK (1 << 0)
-#ifdef CFG_I2C_MX31_PORT1
+#ifdef CONFIG_SYS_I2C_MX31_PORT1
#define I2C_BASE 0x43f80000
-#elif defined (CFG_I2C_MX31_PORT2)
+#elif defined (CONFIG_SYS_I2C_MX31_PORT2)
#define I2C_BASE 0x43f98000
-#elif defined (CFG_I2C_MX31_PORT3)
+#elif defined (CONFIG_SYS_I2C_MX31_PORT3)
#define I2C_BASE 0x43f84000
#else
-#error "define CFG_I2C_MX31_PORTx to use the mx31 I2C driver"
+#error "define CONFIG_SYS_I2C_MX31_PORTx to use the mx31 I2C driver"
#endif
#ifdef DEBUG
diff --git a/drivers/i2c/omap1510_i2c.c b/drivers/i2c/omap1510_i2c.c
index 388951d..f91ee88 100644
--- a/drivers/i2c/omap1510_i2c.c
+++ b/drivers/i2c/omap1510_i2c.c
@@ -32,7 +32,7 @@ void i2c_init (int speed, int slaveadd)
udelay (5000);
}
- /* 12Mhz I2C module clock */
+ /* 12MHz I2C module clock */
outw (0, I2C_PSC);
outw (I2C_CON_EN, I2C_CON);
outw (0, I2C_SYSTEST);
@@ -205,7 +205,7 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
for (i = 0; i < len; i++) {
if (i2c_read_byte (chip, addr + i, &buffer[i])) {
printf ("I2C read: I/O error\n");
- i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
@@ -230,7 +230,7 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
for (i = 0; i < len; i++) {
if (i2c_write_byte (chip, addr + i, buffer[i])) {
printf ("I2C read: I/O error\n");
- i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index d16cfb1..4427938 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -25,9 +25,6 @@
#include <asm/arch/i2c.h>
#include <asm/io.h>
-#define inw(a) __raw_readw(a)
-#define outw(a,v) __raw_writew(a,v)
-
static void wait_for_bb (void);
static u16 wait_for_pin (void);
static void flush_fifo(void);
@@ -36,32 +33,32 @@ void i2c_init (int speed, int slaveadd)
{
u16 scl;
- outw(0x2, I2C_SYSC); /* for ES2 after soft reset */
+ writew(0x2, I2C_SYSC); /* for ES2 after soft reset */
udelay(1000);
- outw(0x0, I2C_SYSC); /* will probably self clear but */
+ writew(0x0, I2C_SYSC); /* will probably self clear but */
- if (inw (I2C_CON) & I2C_CON_EN) {
- outw (0, I2C_CON);
+ if (readw (I2C_CON) & I2C_CON_EN) {
+ writew (0, I2C_CON);
udelay (50000);
}
- /* 12Mhz I2C module clock */
- outw (0, I2C_PSC);
+ /* 12MHz I2C module clock */
+ writew (0, I2C_PSC);
speed = speed/1000; /* 100 or 400 */
scl = ((12000/(speed*2)) - 7); /* use 7 when PSC = 0 */
- outw (scl, I2C_SCLL);
- outw (scl, I2C_SCLH);
+ writew (scl, I2C_SCLL);
+ writew (scl, I2C_SCLH);
/* own address */
- outw (slaveadd, I2C_OA);
- outw (I2C_CON_EN, I2C_CON);
+ writew (slaveadd, I2C_OA);
+ writew (I2C_CON_EN, I2C_CON);
/* have to enable intrrupts or OMAP i2c module doesn't work */
- outw (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
- I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE);
+ writew (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
+ I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE);
udelay (1000);
flush_fifo();
- outw (0xFFFF, I2C_STAT);
- outw (0, I2C_CNT);
+ writew (0xFFFF, I2C_STAT);
+ writew (0, I2C_CNT);
}
static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
@@ -73,19 +70,19 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
wait_for_bb ();
/* one byte only */
- outw (1, I2C_CNT);
+ writew (1, I2C_CNT);
/* set slave address */
- outw (devaddr, I2C_SA);
+ writew (devaddr, I2C_SA);
/* no stop bit needed here */
- outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON);
+ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON);
status = wait_for_pin ();
if (status & I2C_STAT_XRDY) {
/* Important: have to use byte access */
- *(volatile u8 *) (I2C_DATA) = regoffset;
+ writeb (regoffset, I2C_DATA);
udelay (20000);
- if (inw (I2C_STAT) & I2C_STAT_NACK) {
+ if (readw (I2C_STAT) & I2C_STAT_NACK) {
i2c_error = 1;
}
} else {
@@ -94,42 +91,42 @@ static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
if (!i2c_error) {
/* free bus, otherwise we can't use a combined transction */
- outw (0, I2C_CON);
- while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) {
+ writew (0, I2C_CON);
+ while (readw (I2C_STAT) || (readw (I2C_CON) & I2C_CON_MST)) {
udelay (10000);
/* Have to clear pending interrupt to clear I2C_STAT */
- outw (0xFFFF, I2C_STAT);
+ writew (0xFFFF, I2C_STAT);
}
wait_for_bb ();
/* set slave address */
- outw (devaddr, I2C_SA);
+ writew (devaddr, I2C_SA);
/* read one byte from slave */
- outw (1, I2C_CNT);
+ writew (1, I2C_CNT);
/* need stop bit here */
- outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
- I2C_CON);
+ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
+ I2C_CON);
status = wait_for_pin ();
if (status & I2C_STAT_RRDY) {
- *value = inw (I2C_DATA);
+ *value = readw (I2C_DATA);
udelay (20000);
} else {
i2c_error = 1;
}
if (!i2c_error) {
- outw (I2C_CON_EN, I2C_CON);
- while (inw (I2C_STAT)
- || (inw (I2C_CON) & I2C_CON_MST)) {
+ writew (I2C_CON_EN, I2C_CON);
+ while (readw (I2C_STAT)
+ || (readw (I2C_CON) & I2C_CON_MST)) {
udelay (10000);
- outw (0xFFFF, I2C_STAT);
+ writew (0xFFFF, I2C_STAT);
}
}
}
flush_fifo();
- outw (0xFFFF, I2C_STAT);
- outw (0, I2C_CNT);
+ writew (0xFFFF, I2C_STAT);
+ writew (0, I2C_CNT);
return i2c_error;
}
@@ -142,22 +139,22 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
wait_for_bb ();
/* two bytes */
- outw (2, I2C_CNT);
+ writew (2, I2C_CNT);
/* set slave address */
- outw (devaddr, I2C_SA);
+ writew (devaddr, I2C_SA);
/* stop bit needed here */
- outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
- I2C_CON_STP, I2C_CON);
+ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
+ I2C_CON_STP, I2C_CON);
/* wait until state change */
status = wait_for_pin ();
if (status & I2C_STAT_XRDY) {
/* send out two bytes */
- outw ((value << 8) + regoffset, I2C_DATA);
+ writew ((value << 8) + regoffset, I2C_DATA);
/* must have enough delay to allow BB bit to go low */
udelay (50000);
- if (inw (I2C_STAT) & I2C_STAT_NACK) {
+ if (readw (I2C_STAT) & I2C_STAT_NACK) {
i2c_error = 1;
}
} else {
@@ -167,18 +164,18 @@ static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
if (!i2c_error) {
int eout = 200;
- outw (I2C_CON_EN, I2C_CON);
- while ((stat = inw (I2C_STAT)) || (inw (I2C_CON) & I2C_CON_MST)) {
+ writew (I2C_CON_EN, I2C_CON);
+ while ((stat = readw (I2C_STAT)) || (readw (I2C_CON) & I2C_CON_MST)) {
udelay (1000);
/* have to read to clear intrrupt */
- outw (0xFFFF, I2C_STAT);
+ writew (0xFFFF, I2C_STAT);
if(--eout == 0) /* better leave with error than hang */
break;
}
}
flush_fifo();
- outw (0xFFFF, I2C_STAT);
- outw (0, I2C_CNT);
+ writew (0xFFFF, I2C_STAT);
+ writew (0, I2C_CNT);
return i2c_error;
}
@@ -189,10 +186,10 @@ static void flush_fifo(void)
* you get a bus error
*/
while(1){
- stat = inw(I2C_STAT);
+ stat = readw(I2C_STAT);
if(stat == I2C_STAT_RRDY){
- inw(I2C_DATA);
- outw(I2C_STAT_RRDY,I2C_STAT);
+ readw(I2C_DATA);
+ writew(I2C_STAT_RRDY,I2C_STAT);
udelay(1000);
}else
break;
@@ -203,7 +200,7 @@ int i2c_probe (uchar chip)
{
int res = 1; /* default = fail */
- if (chip == inw (I2C_OA)) {
+ if (chip == readw (I2C_OA)) {
return res;
}
@@ -211,27 +208,27 @@ int i2c_probe (uchar chip)
wait_for_bb ();
/* try to read one byte */
- outw (1, I2C_CNT);
+ writew (1, I2C_CNT);
/* set slave address */
- outw (chip, I2C_SA);
+ writew (chip, I2C_SA);
/* stop bit needed here */
- outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON);
+ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON);
/* enough delay for the NACK bit set */
udelay (50000);
- if (!(inw (I2C_STAT) & I2C_STAT_NACK)) {
+ if (!(readw (I2C_STAT) & I2C_STAT_NACK)) {
res = 0; /* success case */
flush_fifo();
- outw(0xFFFF, I2C_STAT);
+ writew(0xFFFF, I2C_STAT);
} else {
- outw(0xFFFF, I2C_STAT); /* failue, clear sources*/
- outw (inw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */
+ writew(0xFFFF, I2C_STAT); /* failue, clear sources*/
+ writew (readw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */
udelay(20000);
wait_for_bb ();
}
flush_fifo();
- outw (0, I2C_CNT); /* don't allow any more data in...we don't want it.*/
- outw(0xFFFF, I2C_STAT);
+ writew (0, I2C_CNT); /* don't allow any more data in...we don't want it.*/
+ writew(0xFFFF, I2C_STAT);
return res;
}
@@ -252,7 +249,7 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
for (i = 0; i < len; i++) {
if (i2c_read_byte (chip, addr + i, &buffer[i])) {
printf ("I2C read: I/O error\n");
- i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
@@ -277,7 +274,7 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
for (i = 0; i < len; i++) {
if (i2c_write_byte (chip, addr + i, buffer[i])) {
printf ("I2C read: I/O error\n");
- i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
return 1;
}
}
@@ -290,17 +287,17 @@ static void wait_for_bb (void)
int timeout = 10;
u16 stat;
- outw(0xFFFF, I2C_STAT); /* clear current interruts...*/
- while ((stat = inw (I2C_STAT) & I2C_STAT_BB) && timeout--) {
- outw (stat, I2C_STAT);
+ writew(0xFFFF, I2C_STAT); /* clear current interruts...*/
+ while ((stat = readw (I2C_STAT) & I2C_STAT_BB) && timeout--) {
+ writew (stat, I2C_STAT);
udelay (50000);
}
if (timeout <= 0) {
printf ("timed out in wait_for_bb: I2C_STAT=%x\n",
- inw (I2C_STAT));
+ readw (I2C_STAT));
}
- outw(0xFFFF, I2C_STAT); /* clear delayed stuff*/
+ writew(0xFFFF, I2C_STAT); /* clear delayed stuff*/
}
static u16 wait_for_pin (void)
@@ -310,7 +307,7 @@ static u16 wait_for_pin (void)
do {
udelay (1000);
- status = inw (I2C_STAT);
+ status = readw (I2C_STAT);
} while ( !(status &
(I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
@@ -318,8 +315,8 @@ static u16 wait_for_pin (void)
if (timeout <= 0) {
printf ("timed out in wait_for_pin: I2C_STAT=%x\n",
- inw (I2C_STAT));
- outw(0xFFFF, I2C_STAT);
+ readw (I2C_STAT));
+ writew(0xFFFF, I2C_STAT);
}
return status;
}
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index 23db2ee..a27de5a 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -28,6 +28,7 @@
#include <common.h>
#ifdef CONFIG_MPC8260 /* only valid for MPC8260 */
#include <ioports.h>
+#include <asm/io.h>
#endif
#ifdef CONFIG_AT91RM9200 /* need this for the at91rm9200 */
#include <asm/io.h>
@@ -39,6 +40,9 @@
#ifdef CONFIG_LPC2292
#include <asm/arch/hardware.h>
#endif
+#ifdef CONFIG_MPC866 /* only valid for MPC866 */
+#include <asm/io.h>
+#endif
#include <i2c.h>
/* #define DEBUG_I2C */
@@ -68,17 +72,23 @@ DECLARE_GLOBAL_DATA_PTR;
#define PRINTD(fmt,args...)
#endif
+#if defined(CONFIG_I2C_MULTI_BUS)
+static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = 0;
+#endif /* CONFIG_I2C_MULTI_BUS */
+
/*-----------------------------------------------------------------------
* Local functions
*/
+#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
static void send_reset (void);
+#endif
static void send_start (void);
static void send_stop (void);
static void send_ack (int);
static int write_byte (uchar byte);
static uchar read_byte (int);
-
+#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
/*-----------------------------------------------------------------------
* Send a reset sequence consisting of 9 clocks with the data signal high
* to clock any confused device back into an idle state. Also send a
@@ -86,12 +96,7 @@ static uchar read_byte (int);
*/
static void send_reset(void)
{
-#ifdef CONFIG_MPC8260
- volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
I2C_SCL(1);
@@ -111,18 +116,14 @@ static void send_reset(void)
send_stop();
I2C_TRISTATE;
}
+#endif
/*-----------------------------------------------------------------------
* START: High -> Low on SDA while SCL is High
*/
static void send_start(void)
{
-#ifdef CONFIG_MPC8260
- volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_DELAY;
I2C_SDA(1);
@@ -139,12 +140,7 @@ static void send_start(void)
*/
static void send_stop(void)
{
-#ifdef CONFIG_MPC8260
- volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
@@ -164,12 +160,7 @@ static void send_stop(void)
*/
static void send_ack(int ack)
{
-#ifdef CONFIG_MPC8260
- volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
@@ -189,12 +180,7 @@ static void send_ack(int ack)
*/
static int write_byte(uchar data)
{
-#ifdef CONFIG_MPC8260
- volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
int nack;
@@ -230,6 +216,51 @@ static int write_byte(uchar data)
return(nack); /* not a nack is an ack */
}
+#if defined(CONFIG_I2C_MULTI_BUS)
+/*
+ * Functions for multiple I2C bus handling
+ */
+unsigned int i2c_get_bus_num(void)
+{
+ return i2c_bus_num;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+#if defined(CONFIG_I2C_MUX)
+ if (bus < CONFIG_SYS_MAX_I2C_BUS) {
+ i2c_bus_num = bus;
+ } else {
+ int ret;
+
+ ret = i2x_mux_select_mux(bus);
+ if (ret == 0)
+ i2c_bus_num = bus;
+ else
+ return ret;
+ }
+#else
+ if (bus >= CONFIG_SYS_MAX_I2C_BUS)
+ return -1;
+ i2c_bus_num = bus;
+#endif
+ return 0;
+}
+
+/* TODO: add 100/400k switching */
+unsigned int i2c_get_bus_speed(void)
+{
+ return CONFIG_SYS_I2C_SPEED;
+}
+
+int i2c_set_bus_speed(unsigned int speed)
+{
+ if (speed != CONFIG_SYS_I2C_SPEED)
+ return -1;
+
+ return 0;
+}
+#endif
/*-----------------------------------------------------------------------
* if ack == I2C_ACK, ACK the byte so can continue reading, else
@@ -237,12 +268,7 @@ static int write_byte(uchar data)
*/
static uchar read_byte(int ack)
{
-#ifdef CONFIG_MPC8260
- volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
-#endif
-#ifdef CONFIG_8xx
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
-#endif
+ I2C_SOFT_DECLARATIONS /* intentional without ';' */
int data;
int j;
@@ -275,6 +301,12 @@ static uchar read_byte(int ack)
*/
void i2c_init (int speed, int slaveaddr)
{
+#if defined(CONFIG_SYS_I2C_INIT_BOARD)
+ /* call board specific i2c bus reset routine before accessing the */
+ /* environment, which might be in a chip on that bus. For details */
+ /* about this problem see doc/I2C_Edge_Conditions. */
+ i2c_init_board();
+#else
/*
* WARNING: Do NOT save speed in a static variable: if the
* I2C routines are called before RAM is initialized (to read
@@ -282,6 +314,7 @@ void i2c_init (int speed, int slaveaddr)
* system will crash.
*/
send_reset ();
+#endif
}
/*-----------------------------------------------------------------------
@@ -313,7 +346,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
chip, addr, alen, buffer, len);
-#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
@@ -325,7 +358,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
- chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+ chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
chip, addr);
@@ -401,23 +434,3 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
send_stop();
return(failures);
}
-
-/*-----------------------------------------------------------------------
- * Read a register
- */
-uchar i2c_reg_read(uchar i2c_addr, uchar reg)
-{
- uchar buf;
-
- i2c_read(i2c_addr, reg, 1, &buf, 1);
-
- return(buf);
-}
-
-/*-----------------------------------------------------------------------
- * Write a register
- */
-void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
-{
- i2c_write(i2c_addr, reg, 1, &val, 1);
-}
diff --git a/drivers/i2c/tsi108_i2c.c b/drivers/i2c/tsi108_i2c.c
index 695e393..fda822c 100644
--- a/drivers/i2c/tsi108_i2c.c
+++ b/drivers/i2c/tsi108_i2c.c
@@ -60,14 +60,14 @@ static int i2c_read_byte (
chan_offset = TSI108_I2C_SDRAM_OFFSET;
/* Check if I2C operation is in progress */
- temp = *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
+ temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS |
I2C_CNTRL2_START))) {
/* Set device address and operation (read = 0) */
temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) |
((chip_addr >> 3) & 0x0F);
- *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) =
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) =
temp;
/* Issue the read command
@@ -75,13 +75,13 @@ static int i2c_read_byte (
* (size = 1 byte, lane = 0)
*/
- *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) =
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) =
(I2C_CNTRL2_START);
/* Wait until operation completed */
do {
/* Read I2C operation status */
- temp = *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
+ temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START))) {
if (0 == (temp &
@@ -90,7 +90,7 @@ static int i2c_read_byte (
) {
op_status = TSI108_I2C_SUCCESS;
- temp = *(u32 *) (CFG_TSI108_CSR_BASE +
+ temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
chan_offset +
I2C_RD_DATA);
@@ -172,25 +172,25 @@ static int i2c_write_byte (uchar chip_addr,/* I2C device address on the bus */
u32 op_status = TSI108_I2C_TIMEOUT_ERR;
/* Check if I2C operation is in progress */
- temp = *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
+ temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
/* Place data into the I2C Tx Register */
- *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_TX_DATA) = (u32) * buffer;
/* Set device address and operation */
temp =
I2C_CNTRL1_I2CWRITE | (byte_addr << 16) |
((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F);
- *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_CNTRL1) = temp;
/* Issue the write command (at this moment all other parameters
* are 0 (size = 1 byte, lane = 0)
*/
- *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_CNTRL2) = (I2C_CNTRL2_START);
op_status = TSI108_I2C_TIMEOUT_ERR;
@@ -198,7 +198,7 @@ static int i2c_write_byte (uchar chip_addr,/* I2C device address on the bus */
/* Wait until operation completed */
do {
/* Read I2C operation status */
- temp = *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
+ temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
if (0 == (temp &
diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c
index d152768..58094c9 100644
--- a/drivers/input/i8042.c
+++ b/drivers/input/i8042.c
@@ -41,7 +41,7 @@ extern void gt_cpcidvi_out8(u32 offset, u8 data);
#ifdef CONFIG_CONSOLE_CURSOR
extern void console_cursor (int state);
-static int blinkCount = CFG_CONSOLE_BLINK_COUNT;
+static int blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
static int cursor_state = 0;
#endif
@@ -368,7 +368,7 @@ int i8042_tstc (void)
{
cursor_state ^= 1;
console_cursor (cursor_state);
- blinkCount = CFG_CONSOLE_BLINK_COUNT;
+ blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
udelay (10);
}
#endif
@@ -409,7 +409,7 @@ int i8042_getc (void)
{
cursor_state ^= 1;
console_cursor (cursor_state);
- blinkCount = CFG_CONSOLE_BLINK_COUNT;
+ blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
}
udelay (10);
#endif
diff --git a/drivers/input/keyboard.c b/drivers/input/keyboard.c
index a634d76..512b9f2 100644
--- a/drivers/input/keyboard.c
+++ b/drivers/input/keyboard.c
@@ -258,12 +258,12 @@ void handle_scancode(unsigned char scancode)
* Init
******************************************************************/
-#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
+#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
extern int overwrite_console (void);
#define OVERWRITE_CONSOLE overwrite_console ()
#else
#define OVERWRITE_CONSOLE 0
-#endif /* CFG_CONSOLE_OVERWRITE_ROUTINE */
+#endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
int kbd_init (void)
{
diff --git a/drivers/input/ps2ser.c b/drivers/input/ps2ser.c
index 480ffa2..1af3fde 100644
--- a/drivers/input/ps2ser.c
+++ b/drivers/input/ps2ser.c
@@ -18,7 +18,7 @@
#include <asm/io.h>
#include <asm/atomic.h>
#include <ps2mult.h>
-#if defined(CFG_NS16550) || defined(CONFIG_MPC85xx)
+#if defined(CONFIG_SYS_NS16550) || defined(CONFIG_MPC85xx)
#include <ns16550.h>
#endif
@@ -51,9 +51,9 @@ DECLARE_GLOBAL_DATA_PTR;
defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
#if CONFIG_PS2SERIAL == 1
-#define COM_BASE (CFG_CCSRBAR+0x4500)
+#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500)
#elif CONFIG_PS2SERIAL == 2
-#define COM_BASE (CFG_CCSRBAR+0x4600)
+#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600)
#else
#error CONFIG_PS2SERIAL must be in 1 ... 2
#endif
@@ -88,7 +88,7 @@ int ps2ser_init(void)
/* select clock sources */
#if defined(CONFIG_MGT5100)
psc->psc_clock_select = 0xdd00;
- baseclk = (CFG_MPC5XXX_CLKIN + 16) / 32;
+ baseclk = (CONFIG_SYS_MPC5XXX_CLKIN + 16) / 32;
#elif defined(CONFIG_MPC5200)
psc->psc_clock_select = 0;
baseclk = (gd->ipb_clk + 16) / 32;
@@ -129,8 +129,8 @@ int ps2ser_init(void)
com_port->ier = 0x00;
com_port->lcr = LCR_BKSE | LCR_8N1;
- com_port->dll = (CFG_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff;
- com_port->dlm = ((CFG_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff;
+ com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff;
+ com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff;
com_port->lcr = LCR_8N1;
com_port->mcr = (MCR_DTR | MCR_RTS);
com_port->fcr = (FCR_FIFO_EN | FCR_RXSR | FCR_TXSR);
diff --git a/drivers/misc/fsl_law.c b/drivers/misc/fsl_law.c
index 2e94614..44c9e91 100644
--- a/drivers/misc/fsl_law.c
+++ b/drivers/misc/fsl_law.c
@@ -46,12 +46,13 @@ DECLARE_GLOBAL_DATA_PTR;
void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
{
- volatile u32 *base = (volatile u32 *)(CFG_IMMR + 0xc08);
+ volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
volatile u32 *lawbar = base + 8 * idx;
volatile u32 *lawar = base + 8 * idx + 2;
gd->used_laws |= (1 << idx);
+ out_be32(lawar, 0);
out_be32(lawbar, addr >> 12);
out_be32(lawar, LAWAR_EN | ((u32)id << 20) | (u32)sz);
@@ -91,7 +92,7 @@ int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
void disable_law(u8 idx)
{
- volatile u32 *base = (volatile u32 *)(CFG_IMMR + 0xc08);
+ volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
volatile u32 *lawbar = base + 8 * idx;
volatile u32 *lawar = base + 8 * idx + 2;
@@ -105,7 +106,7 @@ void disable_law(u8 idx)
void print_laws(void)
{
- volatile u32 *base = (volatile u32 *)(CFG_IMMR + 0xc08);
+ volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
volatile u32 *lawbar = base;
volatile u32 *lawar = base + 2;
int i;
diff --git a/drivers/misc/ns87308.c b/drivers/misc/ns87308.c
index 6642c2e..9130a1f 100644
--- a/drivers/misc/ns87308.c
+++ b/drivers/misc/ns87308.c
@@ -27,7 +27,7 @@
void initialise_ns87308 (void)
{
-#ifdef CFG_NS87308_PS2MOD
+#ifdef CONFIG_SYS_NS87308_PS2MOD
unsigned char data;
/*
@@ -38,80 +38,80 @@ void initialise_ns87308 (void)
write_pnp_config(SUPOERIO_CONF1, data);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_KBC1)
- PNP_SET_DEVICE_BASE(LDEV_KBC1, CFG_NS87308_KBC1_BASE);
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_KBC1)
+ PNP_SET_DEVICE_BASE(LDEV_KBC1, CONFIG_SYS_NS87308_KBC1_BASE);
write_pnp_config(LUN_CONFIG_REG, 0);
write_pnp_config(CBASE_HIGH, 0x00);
write_pnp_config(CBASE_LOW, 0x64);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_MOUSE)
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_MOUSE)
PNP_ACTIVATE_DEVICE(LDEV_MOUSE);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_RTC_APC)
- PNP_SET_DEVICE_BASE(LDEV_RTC_APC, CFG_NS87308_RTC_BASE);
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_RTC_APC)
+ PNP_SET_DEVICE_BASE(LDEV_RTC_APC, CONFIG_SYS_NS87308_RTC_BASE);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_FDC)
- PNP_SET_DEVICE_BASE(LDEV_FDC, CFG_NS87308_FDC_BASE);
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_FDC)
+ PNP_SET_DEVICE_BASE(LDEV_FDC, CONFIG_SYS_NS87308_FDC_BASE);
write_pnp_config(LUN_CONFIG_REG, 0x40);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_RARP)
- PNP_SET_DEVICE_BASE(LDEV_PARP, CFG_NS87308_LPT_BASE);
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_RARP)
+ PNP_SET_DEVICE_BASE(LDEV_PARP, CONFIG_SYS_NS87308_LPT_BASE);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_UART1)
- PNP_SET_DEVICE_BASE(LDEV_UART1, CFG_NS87308_UART1_BASE);
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_UART1)
+ PNP_SET_DEVICE_BASE(LDEV_UART1, CONFIG_SYS_NS87308_UART1_BASE);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_UART2)
- PNP_SET_DEVICE_BASE(LDEV_UART2, CFG_NS87308_UART2_BASE);
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_UART2)
+ PNP_SET_DEVICE_BASE(LDEV_UART2, CONFIG_SYS_NS87308_UART2_BASE);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_GPIO)
- PNP_SET_DEVICE_BASE(LDEV_GPIO, CFG_NS87308_GPIO_BASE);
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_GPIO)
+ PNP_SET_DEVICE_BASE(LDEV_GPIO, CONFIG_SYS_NS87308_GPIO_BASE);
#endif
-#if (CFG_NS87308_DEVS & CFG_NS87308_POWRMAN)
-#ifndef CFG_NS87308_PWMAN_BASE
+#if (CONFIG_SYS_NS87308_DEVS & CONFIG_SYS_NS87308_POWRMAN)
+#ifndef CONFIG_SYS_NS87308_PWMAN_BASE
PNP_ACTIVATE_DEVICE(LDEV_POWRMAN);
#else
- PNP_SET_DEVICE_BASE(LDEV_POWRMAN, CFG_NS87308_PWMAN_BASE);
+ PNP_SET_DEVICE_BASE(LDEV_POWRMAN, CONFIG_SYS_NS87308_PWMAN_BASE);
/*
* Enable all units
*/
- write_pm_reg(CFG_NS87308_PWMAN_BASE, PWM_FER1, 0x7d);
- write_pm_reg(CFG_NS87308_PWMAN_BASE, PWM_FER2, 0x87);
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_FER1, 0x7d);
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_FER2, 0x87);
-#ifdef CFG_NS87308_PMC1
- write_pm_reg(CFG_NS87308_PWMAN_BASE, PWM_PMC1, CFG_NS87308_PMC1);
+#ifdef CONFIG_SYS_NS87308_PMC1
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_PMC1, CONFIG_SYS_NS87308_PMC1);
#endif
-#ifdef CFG_NS87308_PMC2
- write_pm_reg(CFG_NS87308_PWMAN_BASE, PWM_PMC2, CFG_NS87308_PMC2);
+#ifdef CONFIG_SYS_NS87308_PMC2
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_PMC2, CONFIG_SYS_NS87308_PMC2);
#endif
-#ifdef CFG_NS87308_PMC3
- write_pm_reg(CFG_NS87308_PWMAN_BASE, PWM_PMC3, CFG_NS87308_PMC3);
+#ifdef CONFIG_SYS_NS87308_PMC3
+ write_pm_reg(CONFIG_SYS_NS87308_PWMAN_BASE, PWM_PMC3, CONFIG_SYS_NS87308_PMC3);
#endif
#endif
#endif
-#ifdef CFG_NS87308_CS0_BASE
- PNP_PGCS_CSLINE_BASE(0, CFG_NS87308_CS0_BASE);
- PNP_PGCS_CSLINE_CONF(0, CFG_NS87308_CS0_CONF);
+#ifdef CONFIG_SYS_NS87308_CS0_BASE
+ PNP_PGCS_CSLINE_BASE(0, CONFIG_SYS_NS87308_CS0_BASE);
+ PNP_PGCS_CSLINE_CONF(0, CONFIG_SYS_NS87308_CS0_CONF);
#endif
-#ifdef CFG_NS87308_CS1_BASE
- PNP_PGCS_CSLINE_BASE(1, CFG_NS87308_CS1_BASE);
- PNP_PGCS_CSLINE_CONF(1, CFG_NS87308_CS1_CONF);
+#ifdef CONFIG_SYS_NS87308_CS1_BASE
+ PNP_PGCS_CSLINE_BASE(1, CONFIG_SYS_NS87308_CS1_BASE);
+ PNP_PGCS_CSLINE_CONF(1, CONFIG_SYS_NS87308_CS1_CONF);
#endif
-#ifdef CFG_NS87308_CS2_BASE
- PNP_PGCS_CSLINE_BASE(2, CFG_NS87308_CS2_BASE);
- PNP_PGCS_CSLINE_CONF(2, CFG_NS87308_CS2_CONF);
+#ifdef CONFIG_SYS_NS87308_CS2_BASE
+ PNP_PGCS_CSLINE_BASE(2, CONFIG_SYS_NS87308_CS2_BASE);
+ PNP_PGCS_CSLINE_CONF(2, CONFIG_SYS_NS87308_CS2_CONF);
#endif
}
diff --git a/drivers/mmc/atmel_mci.c b/drivers/mmc/atmel_mci.c
index a151488..3aa92f2 100644
--- a/drivers/mmc/atmel_mci.c
+++ b/drivers/mmc/atmel_mci.c
@@ -38,16 +38,16 @@
#define pr_debug(...) do { } while(0)
#endif
-#ifndef CFG_MMC_CLK_OD
-#define CFG_MMC_CLK_OD 150000
+#ifndef CONFIG_SYS_MMC_CLK_OD
+#define CONFIG_SYS_MMC_CLK_OD 150000
#endif
-#ifndef CFG_MMC_CLK_PP
-#define CFG_MMC_CLK_PP 5000000
+#ifndef CONFIG_SYS_MMC_CLK_PP
+#define CONFIG_SYS_MMC_CLK_PP 5000000
#endif
-#ifndef CFG_MMC_OP_COND
-#define CFG_MMC_OP_COND 0x00100000
+#ifndef CONFIG_SYS_MMC_OP_COND
+#define CONFIG_SYS_MMC_OP_COND 0x00100000
#endif
#define MMC_DEFAULT_BLKLEN 512
@@ -349,7 +349,7 @@ static int sd_init_card(struct mmc_cid *cid, int verbose)
mmc_idle_cards();
for (i = 0; i < 1000; i++) {
- ret = mmc_acmd(SD_CMD_APP_SEND_OP_COND, CFG_MMC_OP_COND,
+ ret = mmc_acmd(SD_CMD_APP_SEND_OP_COND, CONFIG_SYS_MMC_OP_COND,
resp, R3 | NID);
if (ret || (resp[0] & 0x80000000))
break;
@@ -385,7 +385,7 @@ static int mmc_init_card(struct mmc_cid *cid, int verbose)
mmc_idle_cards();
for (i = 0; i < 1000; i++) {
- ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp,
+ ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CONFIG_SYS_MMC_OP_COND, resp,
R3 | NID | OPEN_DRAIN);
if (ret || (resp[0] & 0x80000000))
break;
@@ -434,7 +434,7 @@ static void mci_set_data_timeout(struct mmc_csd *csd)
timeout_clks = csd->nsac * 100;
timeout_clks += (((timeout_ns + 9) / 10)
- * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000;
+ * ((CONFIG_SYS_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000;
if (!mmc_card_is_sd)
timeout_clks *= 10;
else
@@ -475,7 +475,7 @@ int mmc_init(int verbose)
mmci_writel(CR, MMCI_BIT(MCIEN));
mmci_writel(DTOR, 0x5f);
mmci_writel(IDR, ~0UL);
- mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+ mci_set_mode(CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
mmc_card_is_sd = 0;
@@ -520,7 +520,7 @@ int mmc_init(int verbose)
mmc_blkdev.blksz = 512;
mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2));
- mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz);
+ mci_set_mode(CONFIG_SYS_MMC_CLK_PP, mmc_blkdev.blksz);
#if 0
if (fat_register_device(&mmc_blkdev, 1))
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 6538f7a..b665a97 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -25,8 +25,10 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmtd.a
+COBJS-$(CONFIG_CMD_UBI) += mtdcore.o mtdpart.o
COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o
COBJS-$(CONFIG_FLASH_CFI_DRIVER) += cfi_flash.o
+COBJS-$(CONFIG_FLASH_CFI_MTD) += cfi_mtd.o
COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o
COBJS-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o
COBJS-$(CONFIG_MW_EEPROM) += mw_eeprom.o
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 03ea2d0..e8afe99 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -57,12 +57,12 @@
* AMD/Spansion Application Note: Migration from Single-byte to Three-byte
* Device IDs, Publication Number 25538 Revision A, November 8, 2001
*
- * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
+ * Define CONFIG_SYS_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
* reading and writing ... (yes there is such a Hardware).
*/
-#ifndef CFG_FLASH_BANKS_LIST
-#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }
+#ifndef CONFIG_SYS_FLASH_BANKS_LIST
+#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
#endif
#define FLASH_CMD_CFI 0x98
@@ -143,7 +143,7 @@
#define CFI_CMDSET_SST 258
#define CFI_CMDSET_INTEL_PROG_REGIONS 512
-#ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
+#ifdef CONFIG_SYS_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
# undef FLASH_CMD_RESET
# define FLASH_CMD_RESET AMD_CMD_RESET /* use AMD-Reset instead */
#endif
@@ -158,12 +158,13 @@ typedef union {
#define NUM_ERASE_REGIONS 4 /* max. number of erase regions */
static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
+static uint flash_verbose = 1;
-/* use CFG_MAX_FLASH_BANKS_DETECT if defined */
-#ifdef CFG_MAX_FLASH_BANKS_DETECT
-# define CFI_MAX_FLASH_BANKS CFG_MAX_FLASH_BANKS_DETECT
+/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
+#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
+# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT
#else
-# define CFI_MAX_FLASH_BANKS CFG_MAX_FLASH_BANKS
+# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS
#endif
flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
@@ -171,12 +172,10 @@ flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
/*
* Check if chip width is defined. If not, start detecting with 8bit.
*/
-#ifndef CFG_FLASH_CFI_WIDTH
-#define CFG_FLASH_CFI_WIDTH FLASH_CFI_8BIT
+#ifndef CONFIG_SYS_FLASH_CFI_WIDTH
+#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT
#endif
-typedef unsigned long flash_sect_t;
-
/* CFI standard query structure */
struct cfi_qry {
u8 qry[3];
@@ -209,38 +208,38 @@ struct cfi_pri_hdr {
u8 minor_version;
} __attribute__((packed));
-static void flash_write8(u8 value, void *addr)
+static void __flash_write8(u8 value, void *addr)
{
__raw_writeb(value, addr);
}
-static void flash_write16(u16 value, void *addr)
+static void __flash_write16(u16 value, void *addr)
{
__raw_writew(value, addr);
}
-static void flash_write32(u32 value, void *addr)
+static void __flash_write32(u32 value, void *addr)
{
__raw_writel(value, addr);
}
-static void flash_write64(u64 value, void *addr)
+static void __flash_write64(u64 value, void *addr)
{
/* No architectures currently implement __raw_writeq() */
*(volatile u64 *)addr = value;
}
-static u8 flash_read8(void *addr)
+static u8 __flash_read8(void *addr)
{
return __raw_readb(addr);
}
-static u16 flash_read16(void *addr)
+static u16 __flash_read16(void *addr)
{
return __raw_readw(addr);
}
-static u32 flash_read32(void *addr)
+static u32 __flash_read32(void *addr)
{
return __raw_readl(addr);
}
@@ -251,24 +250,42 @@ static u64 __flash_read64(void *addr)
return *(volatile u64 *)addr;
}
+#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
+void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8")));
+void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16")));
+void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32")));
+void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64")));
+u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8")));
+u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16")));
+u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32")));
u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
+#else
+#define flash_write8 __flash_write8
+#define flash_write16 __flash_write16
+#define flash_write32 __flash_write32
+#define flash_write64 __flash_write64
+#define flash_read8 __flash_read8
+#define flash_read16 __flash_read16
+#define flash_read32 __flash_read32
+#define flash_read64 __flash_read64
+#endif
/*-----------------------------------------------------------------------
*/
-#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
+#if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
static flash_info_t *flash_get_info(ulong base)
{
int i;
flash_info_t * info = 0;
- for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
info = & flash_info[i];
if (info->size && info->start[0] <= base &&
base <= info->start[0] + info->size - 1)
break;
}
- return i == CFG_MAX_FLASH_BANKS ? 0 : info;
+ return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
}
#endif
@@ -309,7 +326,7 @@ static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
int i;
int cword_offset;
int cp_offset;
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
u32 cmd_le = cpu_to_le32(cmd);
#endif
uchar val;
@@ -317,7 +334,7 @@ static void flash_make_cmd(flash_info_t *info, u32 cmd, void *cmdbuf)
for (i = info->portwidth; i > 0; i--){
cword_offset = (info->portwidth-i)%info->chipwidth;
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
cp_offset = info->portwidth - i;
val = *((uchar*)&cmd_le + cword_offset);
#else
@@ -374,7 +391,7 @@ static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
uchar retval;
cp = flash_map (info, 0, offset);
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
retval = flash_read8(cp);
#else
retval = flash_read8(cp + info->portwidth - 1);
@@ -419,7 +436,7 @@ static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
}
#endif
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) || defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
retval = ((flash_read8(addr) << 16) |
(flash_read8(addr + info->portwidth) << 24) |
(flash_read8(addr + 2 * info->portwidth)) |
@@ -516,7 +533,7 @@ static int flash_isequal (flash_info_t * info, flash_sect_t sect,
retval = (flash_read16(addr) == cword.w);
break;
case FLASH_CFI_32BIT:
- debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
+ debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
retval = (flash_read32(addr) == cword.l);
break;
case FLASH_CFI_64BIT:
@@ -596,7 +613,8 @@ static int flash_toggle (flash_info_t * info, flash_sect_t sect,
retval = flash_read32(addr) != flash_read32(addr);
break;
case FLASH_CFI_64BIT:
- retval = flash_read64(addr) != flash_read64(addr);
+ retval = ( (flash_read32( addr ) != flash_read32( addr )) ||
+ (flash_read32(addr+4) != flash_read32(addr+4)) );
break;
default:
retval = 0;
@@ -646,8 +664,8 @@ static int flash_status_check (flash_info_t * info, flash_sect_t sector,
{
ulong start;
-#if CFG_HZ != 1000
- tout *= CFG_HZ/1000;
+#if CONFIG_SYS_HZ != 1000
+ tout *= CONFIG_SYS_HZ/1000;
#endif
/* Wait for command completion */
@@ -681,7 +699,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
- if ((retcode == ERR_OK)
+ if ((retcode != ERR_OK)
&& !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
retcode = ERR_INVAL;
printf ("Flash %s error at address %lx\n", prompt,
@@ -716,7 +734,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
*/
static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
{
-#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
unsigned short w;
unsigned int l;
unsigned long long ll;
@@ -727,7 +745,7 @@ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
cword->c = c;
break;
case FLASH_CFI_16BIT:
-#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
w = c;
w <<= 8;
cword->w = (cword->w >> 8) | w;
@@ -736,7 +754,7 @@ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
#endif
break;
case FLASH_CFI_32BIT:
-#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
l = c;
l <<= 24;
cword->l = (cword->l >> 8) | l;
@@ -745,7 +763,7 @@ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
#endif
break;
case FLASH_CFI_64BIT:
-#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA)
+#if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
ll = c;
ll <<= 56;
cword->ll = (cword->ll >> 8) | ll;
@@ -777,6 +795,7 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
{
void *dstaddr;
int flag;
+ flash_sect_t sect;
dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
@@ -818,8 +837,9 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
#ifdef CONFIG_FLASH_CFI_LEGACY
case CFI_CMDSET_AMD_LEGACY:
#endif
- flash_unlock_seq (info, 0);
- flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
+ sect = find_sector(info, dest);
+ flash_unlock_seq (info, sect);
+ flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
break;
}
@@ -848,7 +868,7 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
info->write_tout, "write");
}
-#ifdef CFG_FLASH_USE_BUFFER_WRITE
+#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
int len)
@@ -1022,7 +1042,7 @@ out_unmap:
unmap_physmem(dst, len);
return retcode;
}
-#endif /* CFG_FLASH_USE_BUFFER_WRITE */
+#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
/*-----------------------------------------------------------------------
@@ -1051,7 +1071,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
if (prot) {
printf ("- Warning: %d protected sectors will not be erased!\n",
prot);
- } else {
+ } else if (flash_verbose) {
putc ('\n');
}
@@ -1098,11 +1118,14 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
if (flash_full_status_check
(info, sect, info->erase_blk_tout, "erase")) {
rcode = 1;
- } else
+ } else if (flash_verbose)
putc ('.');
}
}
- puts (" done\n");
+
+ if (flash_verbose)
+ puts (" done\n");
+
return rcode;
}
@@ -1171,7 +1194,7 @@ void flash_print_info (flash_info_t * info)
for (i = 0; i < info->sector_count; ++i) {
if ((i % 5) == 0)
printf ("\n");
-#ifdef CFG_FLASH_EMPTY_INFO
+#ifdef CONFIG_SYS_FLASH_EMPTY_INFO
int k;
int size;
int erased;
@@ -1196,7 +1219,7 @@ void flash_print_info (flash_info_t * info)
info->start[i],
erased ? 'E' : ' ',
info->protect[i] ? "RO" : " ");
-#else /* ! CFG_FLASH_EMPTY_INFO */
+#else /* ! CONFIG_SYS_FLASH_EMPTY_INFO */
printf (" %08lX %s ",
info->start[i],
info->protect[i] ? "RO" : " ");
@@ -1214,14 +1237,16 @@ void flash_print_info (flash_info_t * info)
*/
#ifdef CONFIG_FLASH_SHOW_PROGRESS
#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \
- dots -= dots_sub; \
- if ((scale > 0) && (dots <= 0)) { \
- if ((digit % 5) == 0) \
- printf ("%d", digit / 5); \
- else \
- putc ('.'); \
- digit--; \
- dots += scale; \
+ if (flash_verbose) { \
+ dots -= dots_sub; \
+ if ((scale > 0) && (dots <= 0)) { \
+ if ((digit % 5) == 0) \
+ printf ("%d", digit / 5); \
+ else \
+ putc ('.'); \
+ digit--; \
+ dots += scale; \
+ } \
}
#else
#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)
@@ -1240,7 +1265,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
int aln;
cfiword_t cword;
int i, rc;
-#ifdef CFG_FLASH_USE_BUFFER_WRITE
+#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
int buffered_size;
#endif
#ifdef CONFIG_FLASH_SHOW_PROGRESS
@@ -1284,7 +1309,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
}
/* handle the aligned part */
-#ifdef CFG_FLASH_USE_BUFFER_WRITE
+#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
buffered_size = (info->portwidth / info->chipwidth);
buffered_size *= info->buffer_size;
while (cnt >= info->portwidth) {
@@ -1324,7 +1349,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
cnt -= info->portwidth;
FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
}
-#endif /* CFG_FLASH_USE_BUFFER_WRITE */
+#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
if (cnt == 0) {
return (0);
@@ -1348,7 +1373,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
/*-----------------------------------------------------------------------
*/
-#ifdef CFG_FLASH_PROTECTION
+#ifdef CONFIG_SYS_FLASH_PROTECTION
int flash_real_protect (flash_info_t * info, long sector, int prot)
{
@@ -1455,7 +1480,7 @@ void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
}
-#endif /* CFG_FLASH_PROTECTION */
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
/*-----------------------------------------------------------------------
* Reverse the order of the erase regions in the CFI QRY structure.
@@ -1499,7 +1524,7 @@ static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
cmdset_intel_read_jedec_ids(info);
flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
-#ifdef CFG_FLASH_PROTECTION
+#ifdef CONFIG_SYS_FLASH_PROTECTION
/* read legacy lock/unlock bit from intel flash */
if (info->ext_addr) {
info->legacy_unlock = flash_read_uchar (info,
@@ -1715,7 +1740,7 @@ static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
{
debug ("flash detect cfi\n");
- for (info->portwidth = CFG_FLASH_CFI_WIDTH;
+ for (info->portwidth = CONFIG_SYS_FLASH_CFI_WIDTH;
info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
for (info->chipwidth = FLASH_CFI_BY8;
info->chipwidth <= info->portwidth;
@@ -1791,7 +1816,7 @@ ulong flash_get_size (ulong base, int banknum)
info->ext_addr = 0;
info->cfi_version = 0;
-#ifdef CFG_FLASH_PROTECTION
+#ifdef CONFIG_SYS_FLASH_PROTECTION
info->legacy_unlock = 0;
#endif
@@ -1880,7 +1905,7 @@ ulong flash_get_size (ulong base, int banknum)
debug ("erase_region_count = %d erase_region_size = %d\n",
erase_region_count, erase_region_size);
for (j = 0; j < erase_region_count; j++) {
- if (sect_cnt >= CFG_MAX_FLASH_SECT) {
+ if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
printf("ERROR: too many flash sectors\n");
break;
}
@@ -1932,53 +1957,59 @@ ulong flash_get_size (ulong base, int banknum)
/* XXX - Need to test on x8/x16 in parallel. */
info->portwidth >>= 1;
}
+
+ flash_write_cmd (info, 0, 0, info->cmd_reset);
}
- flash_write_cmd (info, 0, 0, info->cmd_reset);
return (info->size);
}
+void flash_set_verbose(uint v)
+{
+ flash_verbose = v;
+}
+
/*-----------------------------------------------------------------------
*/
unsigned long flash_init (void)
{
unsigned long size = 0;
int i;
-#if defined(CFG_FLASH_AUTOPROTECT_LIST)
+#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
struct apl_s {
ulong start;
ulong size;
- } apl[] = CFG_FLASH_AUTOPROTECT_LIST;
+ } apl[] = CONFIG_SYS_FLASH_AUTOPROTECT_LIST;
#endif
-#ifdef CFG_FLASH_PROTECTION
+#ifdef CONFIG_SYS_FLASH_PROTECTION
char *s = getenv("unlock");
#endif
-#define BANK_BASE(i) (((unsigned long [CFI_MAX_FLASH_BANKS])CFG_FLASH_BANKS_LIST)[i])
+#define BANK_BASE(i) (((unsigned long [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
/* Init: no FLASHes known */
- for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
if (!flash_detect_legacy (BANK_BASE(i), i))
flash_get_size (BANK_BASE(i), i);
size += flash_info[i].size;
if (flash_info[i].flash_id == FLASH_UNKNOWN) {
-#ifndef CFG_FLASH_QUIET_TEST
+#ifndef CONFIG_SYS_FLASH_QUIET_TEST
printf ("## Unknown FLASH on Bank %d "
"- Size = 0x%08lx = %ld MB\n",
i+1, flash_info[i].size,
flash_info[i].size << 20);
-#endif /* CFG_FLASH_QUIET_TEST */
+#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
}
-#ifdef CFG_FLASH_PROTECTION
+#ifdef CONFIG_SYS_FLASH_PROTECTION
else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
/*
* Only the U-Boot image and it's environment
* is protected, all other sectors are
* unprotected (unlocked) if flash hardware
- * protection is used (CFG_FLASH_PROTECTION)
+ * protection is used (CONFIG_SYS_FLASH_PROTECTION)
* and the environment variable "unlock" is
* set to "yes".
*/
@@ -2019,34 +2050,34 @@ unsigned long flash_init (void)
&flash_info[i]);
}
}
-#endif /* CFG_FLASH_PROTECTION */
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
}
/* Monitor protection ON by default */
-#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
+#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
flash_protect (FLAG_PROTECT_SET,
- CFG_MONITOR_BASE,
- CFG_MONITOR_BASE + monitor_flash_len - 1,
- flash_get_info(CFG_MONITOR_BASE));
+ CONFIG_SYS_MONITOR_BASE,
+ CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
+ flash_get_info(CONFIG_SYS_MONITOR_BASE));
#endif
/* Environment protection ON by default */
-#ifdef CFG_ENV_IS_IN_FLASH
+#ifdef CONFIG_ENV_IS_IN_FLASH
flash_protect (FLAG_PROTECT_SET,
- CFG_ENV_ADDR,
- CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
- flash_get_info(CFG_ENV_ADDR));
+ CONFIG_ENV_ADDR,
+ CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
+ flash_get_info(CONFIG_ENV_ADDR));
#endif
/* Redundant environment protection ON by default */
-#ifdef CFG_ENV_ADDR_REDUND
+#ifdef CONFIG_ENV_ADDR_REDUND
flash_protect (FLAG_PROTECT_SET,
- CFG_ENV_ADDR_REDUND,
- CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
- flash_get_info(CFG_ENV_ADDR_REDUND));
+ CONFIG_ENV_ADDR_REDUND,
+ CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SIZE_REDUND - 1,
+ flash_get_info(CONFIG_ENV_ADDR_REDUND));
#endif
-#if defined(CFG_FLASH_AUTOPROTECT_LIST)
+#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
debug("autoprotecting from %08x to %08x\n",
apl[i].start, apl[i].start + apl[i].size - 1);
@@ -2056,5 +2087,10 @@ unsigned long flash_init (void)
flash_get_info(apl[i].start));
}
#endif
+
+#ifdef CONFIG_FLASH_CFI_MTD
+ cfi_mtd_init();
+#endif
+
return (size);
}
diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c
new file mode 100644
index 0000000..cf82d92
--- /dev/null
+++ b/drivers/mtd/cfi_mtd.c
@@ -0,0 +1,202 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * Written by: Piotr Ziecik <kosmo@semihalf.com>
+ *
+ * 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 <flash.h>
+
+#include <asm/errno.h>
+#include <linux/mtd/mtd.h>
+
+extern flash_info_t flash_info[];
+
+static struct mtd_info cfi_mtd_info[CONFIG_SYS_MAX_FLASH_BANKS];
+
+static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ flash_info_t *fi = mtd->priv;
+ size_t a_start = fi->start[0] + instr->addr;
+ size_t a_end = a_start + instr->len;
+ int s_first = -1;
+ int s_last = -1;
+ int error, sect;
+
+ for (sect = 0; sect < fi->sector_count - 1; sect++) {
+ if (a_start == fi->start[sect])
+ s_first = sect;
+
+ if (a_end == fi->start[sect + 1]) {
+ s_last = sect;
+ break;
+ }
+ }
+
+ if (s_first >= 0 && s_first <= s_last) {
+ instr->state = MTD_ERASING;
+
+ flash_set_verbose(0);
+ error = flash_erase(fi, s_first, s_last);
+ flash_set_verbose(1);
+
+ if (error) {
+ instr->state = MTD_ERASE_FAILED;
+ return -EIO;
+ }
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ flash_info_t *fi = mtd->priv;
+ u_char *f = (u_char*)(fi->start[0]) + from;
+
+ memcpy(buf, f, len);
+ *retlen = len;
+
+ return 0;
+}
+
+static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ flash_info_t *fi = mtd->priv;
+ u_long t = fi->start[0] + to;
+ int error;
+
+ flash_set_verbose(0);
+ error = write_buff(fi, (u_char*)buf, t, len);
+ flash_set_verbose(1);
+
+ if (!error) {
+ *retlen = len;
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static void cfi_mtd_sync(struct mtd_info *mtd)
+{
+ /*
+ * This function should wait until all pending operations
+ * finish. However this driver is fully synchronous, so
+ * this function returns immediately
+ */
+}
+
+static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ flash_info_t *fi = mtd->priv;
+
+ flash_set_verbose(0);
+ flash_protect(FLAG_PROTECT_SET, fi->start[0] + ofs,
+ fi->start[0] + ofs + len - 1, fi);
+ flash_set_verbose(1);
+
+ return 0;
+}
+
+static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ flash_info_t *fi = mtd->priv;
+
+ flash_set_verbose(0);
+ flash_protect(FLAG_PROTECT_CLEAR, fi->start[0] + ofs,
+ fi->start[0] + ofs + len - 1, fi);
+ flash_set_verbose(1);
+
+ return 0;
+}
+
+static int cfi_mtd_set_erasesize(struct mtd_info *mtd, flash_info_t *fi)
+{
+ int sect_size = 0;
+ int sect;
+
+ for (sect = 0; sect < fi->sector_count; sect++) {
+ if (!sect_size) {
+ sect_size = flash_sector_size(fi, sect);
+ continue;
+ }
+
+ if (sect_size != flash_sector_size(fi, sect)) {
+ sect_size = 0;
+ break;
+ }
+ }
+
+ if (!sect_size) {
+ puts("cfi-mtd: devices with multiple sector sizes are"
+ "not supported\n");
+ return -EINVAL;
+ }
+
+ mtd->erasesize = sect_size;
+
+ return 0;
+}
+
+int cfi_mtd_init(void)
+{
+ struct mtd_info *mtd;
+ flash_info_t *fi;
+ int error, i;
+
+ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
+ fi = &flash_info[i];
+ mtd = &cfi_mtd_info[i];
+
+ memset(mtd, 0, sizeof(struct mtd_info));
+
+ error = cfi_mtd_set_erasesize(mtd, fi);
+ if (error)
+ continue;
+
+ mtd->name = CFI_MTD_DEV_NAME;
+ mtd->type = MTD_NORFLASH;
+ mtd->flags = MTD_CAP_NORFLASH;
+ mtd->size = fi->size;
+ mtd->writesize = 1;
+
+ mtd->erase = cfi_mtd_erase;
+ mtd->read = cfi_mtd_read;
+ mtd->write = cfi_mtd_write;
+ mtd->sync = cfi_mtd_sync;
+ mtd->lock = cfi_mtd_lock;
+ mtd->unlock = cfi_mtd_unlock;
+ mtd->priv = fi;
+
+ if (add_mtd_device(mtd))
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/mtd/dataflash.c b/drivers/mtd/dataflash.c
index 049da69..96cd395 100644
--- a/drivers/mtd/dataflash.c
+++ b/drivers/mtd/dataflash.c
@@ -40,12 +40,12 @@ int AT91F_DataflashInit (void)
int dfcode;
int part;
int last_part;
- int found[CFG_MAX_DATAFLASH_BANKS];
+ int found[CONFIG_SYS_MAX_DATAFLASH_BANKS];
unsigned char protected;
AT91F_SpiInit ();
- for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_DATAFLASH_BANKS; i++) {
found[i] = 0;
dataflash_info[i].Desc.state = IDLE;
dataflash_info[i].id = 0;
@@ -131,14 +131,14 @@ int AT91F_DataflashInit (void)
break;
}
/* set the last area end to the dataflash size*/
- area_list[NB_DATAFLASH_AREA -1].end =
+ dataflash_info[i].end_address =
(dataflash_info[i].Device.pages_number *
- dataflash_info[i].Device.pages_size)-1;
+ dataflash_info[i].Device.pages_size) - 1;
part = 0;
last_part = 0;
/* set the area addresses */
- for(j = 0; j<NB_DATAFLASH_AREA; j++) {
+ for(j = 0; j < NB_DATAFLASH_AREA; j++) {
if(found[i]!=0) {
dataflash_info[i].Device.area_list[j].start =
area_list[part].start +
@@ -146,7 +146,7 @@ int AT91F_DataflashInit (void)
if(area_list[part].end == 0xffffffff) {
dataflash_info[i].Device.area_list[j].end =
dataflash_info[i].end_address +
- dataflash_info [i].logical_address;
+ dataflash_info[i].logical_address;
last_part = 1;
} else {
dataflash_info[i].Device.area_list[j].end =
@@ -179,13 +179,12 @@ void AT91F_DataflashSetEnv (void)
unsigned char s[32]; /* Will fit a long int in hex */
unsigned long start;
- for (i = 0, part= 0; i < CFG_MAX_DATAFLASH_BANKS; i++) {
- for(j = 0; j<NB_DATAFLASH_AREA; j++) {
+ for (i = 0, part= 0; i < CONFIG_SYS_MAX_DATAFLASH_BANKS; i++) {
+ for(j = 0; j < NB_DATAFLASH_AREA; j++) {
env = area_list[part].setenv;
/* Set the environment according to the label...*/
if((env & FLAG_SETENV) == FLAG_SETENV) {
- start =
- dataflash_info[i].Device.area_list[j].start;
+ start = dataflash_info[i].Device.area_list[j].start;
sprintf((char*) s,"%lX",start);
setenv((char*) area_list[part].label,(char*) s);
}
@@ -198,7 +197,7 @@ void dataflash_print_info (void)
{
int i, j;
- for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_DATAFLASH_BANKS; i++) {
if (dataflash_info[i].id != 0) {
printf("DataFlash:");
switch (dataflash_info[i].id) {
@@ -230,7 +229,7 @@ void dataflash_print_info (void)
(unsigned int) dataflash_info[i].Device.pages_number *
dataflash_info[i].Device.pages_size,
(unsigned int) dataflash_info[i].logical_address);
- for (j=0; j< NB_DATAFLASH_AREA; j++) {
+ for (j = 0; j < NB_DATAFLASH_AREA; j++) {
switch(dataflash_info[i].Device.area_list[j].protected) {
case FLAG_PROTECT_SET:
case FLAG_PROTECT_CLEAR:
@@ -258,7 +257,7 @@ AT91PS_DataFlash AT91F_DataflashSelect (AT91PS_DataFlash pFlash,
char addr_valid = 0;
int i;
- for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++)
+ for (i = 0; i < CONFIG_SYS_MAX_DATAFLASH_BANKS; i++)
if ( dataflash_info[i].id
&& ((((int) *addr) & 0xFF000000) ==
dataflash_info[i].logical_address)) {
@@ -284,7 +283,7 @@ int addr_dataflash (unsigned long addr)
int addr_valid = 0;
int i;
- for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_DATAFLASH_BANKS; i++) {
if ((((int) addr) & 0xFF000000) ==
dataflash_info[i].logical_address) {
addr_valid = 1;
@@ -322,7 +321,7 @@ int prot_dataflash (AT91PS_DataFlash pdataFlash, unsigned long addr)
int area;
/* find area */
- for (area=0; area < NB_DATAFLASH_AREA; area++) {
+ for (area = 0; area < NB_DATAFLASH_AREA; area++) {
if ((addr >= pdataFlash->pDevice->area_list[area].start) &&
(addr < pdataFlash->pDevice->area_list[area].end))
break;
@@ -349,7 +348,7 @@ int dataflash_real_protect (int flag, unsigned long start_addr,
int i,j, area1, area2, addr_valid = 0;
/* find dataflash */
- for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_DATAFLASH_BANKS; i++) {
if ((((int) start_addr) & 0xF0000000) ==
dataflash_info[i].logical_address) {
addr_valid = 1;
@@ -360,13 +359,13 @@ int dataflash_real_protect (int flag, unsigned long start_addr,
return -1;
}
/* find start area */
- for (area1=0; area1 < NB_DATAFLASH_AREA; area1++) {
+ for (area1 = 0; area1 < NB_DATAFLASH_AREA; area1++) {
if (start_addr == dataflash_info[i].Device.area_list[area1].start)
break;
}
if (area1 == NB_DATAFLASH_AREA) return -1;
/* find end area */
- for (area2=0; area2 < NB_DATAFLASH_AREA; area2++) {
+ for (area2 = 0; area2 < NB_DATAFLASH_AREA; area2++) {
if (end_addr == dataflash_info[i].Device.area_list[area2].end)
break;
}
@@ -374,7 +373,7 @@ int dataflash_real_protect (int flag, unsigned long start_addr,
return -1;
/*set protection value*/
- for(j = area1; j < area2+1 ; j++)
+ for(j = area1; j < area2 + 1 ; j++)
if(dataflash_info[i].Device.area_list[j].protected
!= FLAG_PROTECT_INVALID) {
if (flag == 0) {
@@ -386,7 +385,7 @@ int dataflash_real_protect (int flag, unsigned long start_addr,
}
}
- return (area2-area1+1);
+ return (area2 - area1 + 1);
}
/*---------------------------------------------------------------------------*/
diff --git a/drivers/mtd/jedec_flash.c b/drivers/mtd/jedec_flash.c
index 020647a..226e1e4 100644
--- a/drivers/mtd/jedec_flash.c
+++ b/drivers/mtd/jedec_flash.c
@@ -170,7 +170,7 @@ struct amd_flash_info {
#define SIZE_8MiB 23
static const struct amd_flash_info jedec_table[] = {
-#ifdef CFG_FLASH_LEGACY_256Kx8
+#ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8
{
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39LF020,
@@ -186,7 +186,7 @@ static const struct amd_flash_info jedec_table[] = {
}
},
#endif
-#ifdef CFG_FLASH_LEGACY_512Kx8
+#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8
{
.mfr_id = MANUFACTURER_AMD,
.dev_id = AM29LV040B,
@@ -216,7 +216,7 @@ static const struct amd_flash_info jedec_table[] = {
}
},
#endif
-#ifdef CFG_FLASH_LEGACY_512Kx16
+#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16
{
.mfr_id = MANUFACTURER_AMD,
.dev_id = AM29LV400BB,
@@ -307,7 +307,7 @@ static inline void fill_info(flash_info_t *info, const struct amd_flash_info *je
debug ("erase_region_count = %d erase_region_size = %d\n",
erase_region_count, erase_region_size);
for (j = 0; j < erase_region_count; j++) {
- if (sect_cnt >= CFG_MAX_FLASH_SECT) {
+ if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
printf("ERROR: too many flash sectors\n");
break;
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
new file mode 100644
index 0000000..6eb52ed
--- /dev/null
+++ b/drivers/mtd/mtdcore.c
@@ -0,0 +1,144 @@
+/*
+ * Core registration and callback routines for MTD
+ * drivers and users.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/compat.h>
+#include <ubi_uboot.h>
+
+struct mtd_info *mtd_table[MAX_MTD_DEVICES];
+
+int add_mtd_device(struct mtd_info *mtd)
+{
+ int i;
+
+ BUG_ON(mtd->writesize == 0);
+
+ for (i = 0; i < MAX_MTD_DEVICES; i++)
+ if (!mtd_table[i]) {
+ mtd_table[i] = mtd;
+ mtd->index = i;
+ mtd->usecount = 0;
+
+ /* No need to get a refcount on the module containing
+ the notifier, since we hold the mtd_table_mutex */
+
+ /* We _know_ we aren't being removed, because
+ our caller is still holding us here. So none
+ of this try_ nonsense, and no bitching about it
+ either. :) */
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * del_mtd_device - unregister an MTD device
+ * @mtd: pointer to MTD device info structure
+ *
+ * Remove a device from the list of MTD devices present in the system,
+ * and notify each currently active MTD 'user' of its departure.
+ * Returns zero on success or 1 on failure, which currently will happen
+ * if the requested device does not appear to be present in the list.
+ */
+int del_mtd_device(struct mtd_info *mtd)
+{
+ int ret;
+
+ if (mtd_table[mtd->index] != mtd) {
+ ret = -ENODEV;
+ } else if (mtd->usecount) {
+ printk(KERN_NOTICE "Removing MTD device #%d (%s)"
+ " with use count %d\n",
+ mtd->index, mtd->name, mtd->usecount);
+ ret = -EBUSY;
+ } else {
+ /* No need to get a refcount on the module containing
+ * the notifier, since we hold the mtd_table_mutex */
+ mtd_table[mtd->index] = NULL;
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/**
+ * get_mtd_device - obtain a validated handle for an MTD device
+ * @mtd: last known address of the required MTD device
+ * @num: internal device number of the required MTD device
+ *
+ * Given a number and NULL address, return the num'th entry in the device
+ * table, if any. Given an address and num == -1, search the device table
+ * for a device with that address and return if it's still present. Given
+ * both, return the num'th driver only if its address matches. Return
+ * error code if not.
+ */
+struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
+{
+ struct mtd_info *ret = NULL;
+ int i, err = -ENODEV;
+
+ if (num == -1) {
+ for (i = 0; i < MAX_MTD_DEVICES; i++)
+ if (mtd_table[i] == mtd)
+ ret = mtd_table[i];
+ } else if (num < MAX_MTD_DEVICES) {
+ ret = mtd_table[num];
+ if (mtd && mtd != ret)
+ ret = NULL;
+ }
+
+ if (!ret)
+ goto out_unlock;
+
+ ret->usecount++;
+ return ret;
+
+out_unlock:
+ return ERR_PTR(err);
+}
+
+/**
+ * get_mtd_device_nm - obtain a validated handle for an MTD device by
+ * device name
+ * @name: MTD device name to open
+ *
+ * This function returns MTD device description structure in case of
+ * success and an error code in case of failure.
+ */
+struct mtd_info *get_mtd_device_nm(const char *name)
+{
+ int i, err = -ENODEV;
+ struct mtd_info *mtd = NULL;
+
+ for (i = 0; i < MAX_MTD_DEVICES; i++) {
+ if (mtd_table[i] && !strcmp(name, mtd_table[i]->name)) {
+ mtd = mtd_table[i];
+ break;
+ }
+ }
+
+ if (!mtd)
+ goto out_unlock;
+
+ mtd->usecount++;
+ return mtd;
+
+out_unlock:
+ return ERR_PTR(err);
+}
+
+void put_mtd_device(struct mtd_info *mtd)
+{
+ int c;
+
+ c = --mtd->usecount;
+ BUG_ON(c < 0);
+}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
new file mode 100644
index 0000000..f010f5e
--- /dev/null
+++ b/drivers/mtd/mtdpart.c
@@ -0,0 +1,540 @@
+/*
+ * Simple MTD partitioning layer
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * This code is GPL
+ *
+ * 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
+ * added support for read_oob, write_oob
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/errno.h>
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/compat.h>
+
+/* Our partition linked list */
+struct list_head mtd_partitions;
+
+/* Our partition node structure */
+struct mtd_part {
+ struct mtd_info mtd;
+ struct mtd_info *master;
+ u_int32_t offset;
+ int index;
+ struct list_head list;
+ int registered;
+};
+
+/*
+ * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+ * the pointer to that structure with this macro.
+ */
+#define PART(x) ((struct mtd_part *)(x))
+
+
+/*
+ * MTD methods which simply translate the effective address and pass through
+ * to the _real_ device.
+ */
+
+static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ int res;
+
+ if (from >= mtd->size)
+ len = 0;
+ else if (from + len > mtd->size)
+ len = mtd->size - from;
+ res = part->master->read (part->master, from + part->offset,
+ len, retlen, buf);
+ if (unlikely(res)) {
+ if (res == -EUCLEAN)
+ mtd->ecc_stats.corrected++;
+ if (res == -EBADMSG)
+ mtd->ecc_stats.failed++;
+ }
+ return res;
+}
+
+#ifdef MTD_LINUX
+static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys)
+{
+ struct mtd_part *part = PART(mtd);
+ if (from >= mtd->size)
+ len = 0;
+ else if (from + len > mtd->size)
+ len = mtd->size - from;
+ return part->master->point (part->master, from + part->offset,
+ len, retlen, virt, phys);
+}
+
+static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+
+ part->master->unpoint(part->master, from + part->offset, len);
+}
+#endif
+
+static int part_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ struct mtd_part *part = PART(mtd);
+ int res;
+
+ if (from >= mtd->size)
+ return -EINVAL;
+ if (ops->datbuf && from + ops->len > mtd->size)
+ return -EINVAL;
+ res = part->master->read_oob(part->master, from + part->offset, ops);
+
+ if (unlikely(res)) {
+ if (res == -EUCLEAN)
+ mtd->ecc_stats.corrected++;
+ if (res == -EBADMSG)
+ mtd->ecc_stats.failed++;
+ }
+ return res;
+}
+
+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->read_user_prot_reg (part->master, from,
+ len, retlen, buf);
+}
+
+static int part_get_user_prot_info (struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->get_user_prot_info (part->master, buf, len);
+}
+
+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->read_fact_prot_reg (part->master, from,
+ len, retlen, buf);
+}
+
+static int part_get_fact_prot_info (struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->get_fact_prot_info (part->master, buf, len);
+}
+
+static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+ if (to >= mtd->size)
+ len = 0;
+ else if (to + len > mtd->size)
+ len = mtd->size - to;
+ return part->master->write (part->master, to + part->offset,
+ len, retlen, buf);
+}
+
+#ifdef MTD_LINUX
+static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+ if (to >= mtd->size)
+ len = 0;
+ else if (to + len > mtd->size)
+ len = mtd->size - to;
+ return part->master->panic_write (part->master, to + part->offset,
+ len, retlen, buf);
+}
+#endif
+
+static int part_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ struct mtd_part *part = PART(mtd);
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+
+ if (to >= mtd->size)
+ return -EINVAL;
+ if (ops->datbuf && to + ops->len > mtd->size)
+ return -EINVAL;
+ return part->master->write_oob(part->master, to + part->offset, ops);
+}
+
+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->write_user_prot_reg (part->master, from,
+ len, retlen, buf);
+}
+
+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->lock_user_prot_reg (part->master, from, len);
+}
+
+#ifdef MTD_LINUX
+static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
+ unsigned long count, loff_t to, size_t *retlen)
+{
+ struct mtd_part *part = PART(mtd);
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+ return part->master->writev (part->master, vecs, count,
+ to + part->offset, retlen);
+}
+#endif
+
+static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct mtd_part *part = PART(mtd);
+ int ret;
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+ if (instr->addr >= mtd->size)
+ return -EINVAL;
+ instr->addr += part->offset;
+ ret = part->master->erase(part->master, instr);
+ if (ret) {
+ if (instr->fail_addr != 0xffffffff)
+ instr->fail_addr -= part->offset;
+ instr->addr -= part->offset;
+ }
+ return ret;
+}
+
+void mtd_erase_callback(struct erase_info *instr)
+{
+ if (instr->mtd->erase == part_erase) {
+ struct mtd_part *part = PART(instr->mtd);
+
+ if (instr->fail_addr != 0xffffffff)
+ instr->fail_addr -= part->offset;
+ instr->addr -= part->offset;
+ }
+ if (instr->callback)
+ instr->callback(instr);
+}
+#ifdef MTD_LINUX
+EXPORT_SYMBOL_GPL(mtd_erase_callback);
+#endif
+
+#ifdef MTD_LINUX
+static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ if ((len + ofs) > mtd->size)
+ return -EINVAL;
+ return part->master->lock(part->master, ofs + part->offset, len);
+}
+
+static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ if ((len + ofs) > mtd->size)
+ return -EINVAL;
+ return part->master->unlock(part->master, ofs + part->offset, len);
+}
+#endif
+
+static void part_sync(struct mtd_info *mtd)
+{
+ struct mtd_part *part = PART(mtd);
+ part->master->sync(part->master);
+}
+
+#ifdef MTD_LINUX
+static int part_suspend(struct mtd_info *mtd)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->suspend(part->master);
+}
+
+static void part_resume(struct mtd_info *mtd)
+{
+ struct mtd_part *part = PART(mtd);
+ part->master->resume(part->master);
+}
+#endif
+
+static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
+{
+ struct mtd_part *part = PART(mtd);
+ if (ofs >= mtd->size)
+ return -EINVAL;
+ ofs += part->offset;
+ return part->master->block_isbad(part->master, ofs);
+}
+
+static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
+{
+ struct mtd_part *part = PART(mtd);
+ int res;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+ if (ofs >= mtd->size)
+ return -EINVAL;
+ ofs += part->offset;
+ res = part->master->block_markbad(part->master, ofs);
+#ifdef MTD_LINUX
+ if (!res)
+ mtd->ecc_stats.badblocks++;
+#endif
+ return res;
+}
+
+/*
+ * This function unregisters and destroy all slave MTD objects which are
+ * attached to the given master MTD object.
+ */
+
+int del_mtd_partitions(struct mtd_info *master)
+{
+ struct list_head *node;
+ struct mtd_part *slave;
+
+ for (node = mtd_partitions.next;
+ node != &mtd_partitions;
+ node = node->next) {
+ slave = list_entry(node, struct mtd_part, list);
+ if (slave->master == master) {
+ struct list_head *prev = node->prev;
+ __list_del(prev, node->next);
+ if(slave->registered)
+ del_mtd_device(&slave->mtd);
+ kfree(slave);
+ node = prev;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function, given a master MTD object and a partition table, creates
+ * and registers slave MTD objects which are bound to the master according to
+ * the partition definitions.
+ * (Q: should we register the master MTD object as well?)
+ */
+
+int add_mtd_partitions(struct mtd_info *master,
+ const struct mtd_partition *parts,
+ int nbparts)
+{
+ struct mtd_part *slave;
+ u_int32_t cur_offset = 0;
+ int i;
+
+ /*
+ * Need to init the list here, since LIST_INIT() does not
+ * work on platforms where relocation has problems (like MIPS
+ * & PPC).
+ */
+ if (mtd_partitions.next == NULL)
+ INIT_LIST_HEAD(&mtd_partitions);
+
+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
+
+ for (i = 0; i < nbparts; i++) {
+
+ /* allocate the partition structure */
+ slave = kzalloc (sizeof(*slave), GFP_KERNEL);
+ if (!slave) {
+ printk ("memory allocation error while creating partitions for \"%s\"\n",
+ master->name);
+ del_mtd_partitions(master);
+ return -ENOMEM;
+ }
+ list_add(&slave->list, &mtd_partitions);
+
+ /* set up the MTD object for this partition */
+ slave->mtd.type = master->type;
+ slave->mtd.flags = master->flags & ~parts[i].mask_flags;
+ slave->mtd.size = parts[i].size;
+ slave->mtd.writesize = master->writesize;
+ slave->mtd.oobsize = master->oobsize;
+ slave->mtd.oobavail = master->oobavail;
+ slave->mtd.subpage_sft = master->subpage_sft;
+
+ slave->mtd.name = parts[i].name;
+ slave->mtd.owner = master->owner;
+
+ slave->mtd.read = part_read;
+ slave->mtd.write = part_write;
+
+#ifdef MTD_LINUX
+ if (master->panic_write)
+ slave->mtd.panic_write = part_panic_write;
+
+ if(master->point && master->unpoint){
+ slave->mtd.point = part_point;
+ slave->mtd.unpoint = part_unpoint;
+ }
+#endif
+
+ if (master->read_oob)
+ slave->mtd.read_oob = part_read_oob;
+ if (master->write_oob)
+ slave->mtd.write_oob = part_write_oob;
+ if(master->read_user_prot_reg)
+ slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
+ if(master->read_fact_prot_reg)
+ slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
+ if(master->write_user_prot_reg)
+ slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
+ if(master->lock_user_prot_reg)
+ slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
+ if(master->get_user_prot_info)
+ slave->mtd.get_user_prot_info = part_get_user_prot_info;
+ if(master->get_fact_prot_info)
+ slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
+ if (master->sync)
+ slave->mtd.sync = part_sync;
+#ifdef MTD_LINUX
+ if (!i && master->suspend && master->resume) {
+ slave->mtd.suspend = part_suspend;
+ slave->mtd.resume = part_resume;
+ }
+ if (master->writev)
+ slave->mtd.writev = part_writev;
+ if (master->lock)
+ slave->mtd.lock = part_lock;
+ if (master->unlock)
+ slave->mtd.unlock = part_unlock;
+#endif
+ if (master->block_isbad)
+ slave->mtd.block_isbad = part_block_isbad;
+ if (master->block_markbad)
+ slave->mtd.block_markbad = part_block_markbad;
+ slave->mtd.erase = part_erase;
+ slave->master = master;
+ slave->offset = parts[i].offset;
+ slave->index = i;
+
+ if (slave->offset == MTDPART_OFS_APPEND)
+ slave->offset = cur_offset;
+ if (slave->offset == MTDPART_OFS_NXTBLK) {
+ slave->offset = cur_offset;
+ if ((cur_offset % master->erasesize) != 0) {
+ /* Round up to next erasesize */
+ slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
+ printk(KERN_NOTICE "Moving partition %d: "
+ "0x%08x -> 0x%08x\n", i,
+ cur_offset, slave->offset);
+ }
+ }
+ if (slave->mtd.size == MTDPART_SIZ_FULL)
+ slave->mtd.size = master->size - slave->offset;
+ cur_offset = slave->offset + slave->mtd.size;
+
+ printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
+ slave->offset + slave->mtd.size, slave->mtd.name);
+
+ /* let's do some sanity checks */
+ if (slave->offset >= master->size) {
+ /* let's register it anyway to preserve ordering */
+ slave->offset = 0;
+ slave->mtd.size = 0;
+ printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
+ parts[i].name);
+ }
+ if (slave->offset + slave->mtd.size > master->size) {
+ slave->mtd.size = master->size - slave->offset;
+ printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
+ parts[i].name, master->name, slave->mtd.size);
+ }
+ if (master->numeraseregions>1) {
+ /* Deal with variable erase size stuff */
+ int i;
+ struct mtd_erase_region_info *regions = master->eraseregions;
+
+ /* Find the first erase regions which is part of this partition. */
+ for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
+ ;
+
+ for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
+ if (slave->mtd.erasesize < regions[i].erasesize) {
+ slave->mtd.erasesize = regions[i].erasesize;
+ }
+ }
+ } else {
+ /* Single erase size */
+ slave->mtd.erasesize = master->erasesize;
+ }
+
+ if ((slave->mtd.flags & MTD_WRITEABLE) &&
+ (slave->offset % slave->mtd.erasesize)) {
+ /* Doesn't start on a boundary of major erase size */
+ /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
+ slave->mtd.flags &= ~MTD_WRITEABLE;
+ printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+ parts[i].name);
+ }
+ if ((slave->mtd.flags & MTD_WRITEABLE) &&
+ (slave->mtd.size % slave->mtd.erasesize)) {
+ slave->mtd.flags &= ~MTD_WRITEABLE;
+ printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+ parts[i].name);
+ }
+
+ slave->mtd.ecclayout = master->ecclayout;
+ if (master->block_isbad) {
+ uint32_t offs = 0;
+
+ while(offs < slave->mtd.size) {
+ if (master->block_isbad(master,
+ offs + slave->offset))
+ slave->mtd.ecc_stats.badblocks++;
+ offs += slave->mtd.erasesize;
+ }
+ }
+
+#ifdef MTD_LINUX
+ if (parts[i].mtdp) {
+ /* store the object pointer
+ * (caller may or may not register it */
+ *parts[i].mtdp = &slave->mtd;
+ slave->registered = 0;
+ } else {
+ /* register our partition */
+ add_mtd_device(&slave->mtd);
+ slave->registered = 1;
+ }
+#else
+ /* register our partition */
+ add_mtd_device(&slave->mtd);
+ slave->registered = 1;
+#endif
+ }
+
+ return 0;
+}
+
+#ifdef MTD_LINUX
+EXPORT_SYMBOL(add_mtd_partitions);
+EXPORT_SYMBOL(del_mtd_partitions);
+#endif
diff --git a/drivers/mtd/mw_eeprom.c b/drivers/mtd/mw_eeprom.c
index f32ced4..f7791b51 100644
--- a/drivers/mtd/mw_eeprom.c
+++ b/drivers/mtd/mw_eeprom.c
@@ -1,7 +1,7 @@
/* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
#include <common.h>
-#include <ssi.h>
+#include <asm/ic/ssi.h>
/*
* Serial EEPROM opcodes, including start bit
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 4cba810..e9dc4d1 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -15,8 +15,6 @@
* converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
*
* Interface to generic NAND code for M-Systems DiskOnChip devices
- *
- * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $
*/
#include <common.h>
@@ -58,13 +56,6 @@ static unsigned long __initdata doc_locations[] = {
0xe0000, 0xe2000, 0xe4000, 0xe6000,
0xe8000, 0xea000, 0xec000, 0xee000,
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
-#elif defined(__PPC__)
- 0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT)
- 0x2f000000,
- 0xff000000,
-#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
- 0xff000000,
#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
@@ -229,7 +220,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
}
}
/* If the parity is wrong, no rescue possible */
- return parity ? -1 : nerr;
+ return parity ? -EBADMSG : nerr;
}
static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
@@ -1044,7 +1035,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
else
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
- if (no_ecc_failures && (ret == -1)) {
+ if (no_ecc_failures && (ret == -EBADMSG)) {
printk(KERN_ERR "suppressing ECC failure\n");
ret = 0;
}
@@ -1139,9 +1130,9 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
goto out;
mh = (struct NFTLMediaHeader *)buf;
- mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
- mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
- mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
+ le16_to_cpus(&mh->NumEraseUnits);
+ le16_to_cpus(&mh->FirstPhysicalEUN);
+ le32_to_cpus(&mh->FormattedSize);
printk(KERN_INFO " DataOrgID = %s\n"
" NumEraseUnits = %d\n"
@@ -1249,12 +1240,12 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
mh = (struct INFTLMediaHeader *)buf;
- mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
- mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
- mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
- mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
- mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
- mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
+ le32_to_cpus(&mh->NoOfBootImageBlocks);
+ le32_to_cpus(&mh->NoOfBinaryPartitions);
+ le32_to_cpus(&mh->NoOfBDTLPartitions);
+ le32_to_cpus(&mh->BlockMultiplierBits);
+ le32_to_cpus(&mh->FormatFlags);
+ le32_to_cpus(&mh->PercentUsed);
printk(KERN_INFO " bootRecordID = %s\n"
" NoOfBootImageBlocks = %d\n"
@@ -1291,12 +1282,12 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
/* Scan the partitions */
for (i = 0; (i < 4); i++) {
ip = &(mh->Partitions[i]);
- ip->virtualUnits = le32_to_cpu(ip->virtualUnits);
- ip->firstUnit = le32_to_cpu(ip->firstUnit);
- ip->lastUnit = le32_to_cpu(ip->lastUnit);
- ip->flags = le32_to_cpu(ip->flags);
- ip->spareUnits = le32_to_cpu(ip->spareUnits);
- ip->Reserved0 = le32_to_cpu(ip->Reserved0);
+ le32_to_cpus(&ip->virtualUnits);
+ le32_to_cpus(&ip->firstUnit);
+ le32_to_cpus(&ip->lastUnit);
+ le32_to_cpus(&ip->flags);
+ le32_to_cpus(&ip->spareUnits);
+ le32_to_cpus(&ip->Reserved0);
printk(KERN_INFO " PARTITION[%d] ->\n"
" virtualUnits = %d\n"
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 674c542..367c7d7 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -75,7 +75,7 @@ struct fsl_elbc_ctrl {
struct fsl_elbc_mtd *chips[MAX_BANKS];
/* device info */
- lbus83xx_t *regs;
+ fsl_lbus_t *regs;
u8 __iomem *addr; /* Address of assigned FCM buffer */
unsigned int page; /* Last page written to / read from */
unsigned int read_bytes; /* Number of bytes read during command */
@@ -95,7 +95,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
.eccbytes = 3,
.eccpos = {6, 7, 8},
.oobfree = { {0, 5}, {9, 7} },
- .oobavail = 12,
};
/* Small Page FLASH with FMR[ECCM] = 1 */
@@ -103,7 +102,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
.eccbytes = 3,
.eccpos = {8, 9, 10},
.oobfree = { {0, 5}, {6, 2}, {11, 5} },
- .oobavail = 12,
};
/* Large Page FLASH with FMR[ECCM] = 0 */
@@ -111,7 +109,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
.eccbytes = 12,
.eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
.oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
- .oobavail = 48,
};
/* Large Page FLASH with FMR[ECCM] = 1 */
@@ -119,7 +116,48 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
.eccbytes = 12,
.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
- .oobavail = 48,
+};
+
+/*
+ * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset
+ * 1, so we have to adjust bad block pattern. This pattern should be used for
+ * x8 chips only. So far hardware does not support x16 chips anyway.
+ */
+static u8 scan_ff_pattern[] = { 0xff, };
+
+static struct nand_bbt_descr largepage_memorybased = {
+ .options = 0,
+ .offs = 0,
+ .len = 1,
+ .pattern = scan_ff_pattern,
+};
+
+/*
+ * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
+ * interfere with ECC positions, that's why we implement our own descriptors.
+ * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+ NAND_BBT_2BIT | NAND_BBT_VERSION,
+ .offs = 11,
+ .len = 4,
+ .veroffs = 15,
+ .maxblocks = 4,
+ .pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+ NAND_BBT_2BIT | NAND_BBT_VERSION,
+ .offs = 11,
+ .len = 4,
+ .veroffs = 15,
+ .maxblocks = 4,
+ .pattern = mirror_pattern,
};
/*=================================*/
@@ -133,7 +171,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
- lbus83xx_t *lbc = ctrl->regs;
+ fsl_lbus_t *lbc = ctrl->regs;
int buf_num;
ctrl->page = page_addr;
@@ -173,7 +211,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
- lbus83xx_t *lbc = ctrl->regs;
+ fsl_lbus_t *lbc = ctrl->regs;
long long end_tick;
u32 ltesr;
@@ -223,7 +261,7 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
{
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
- lbus83xx_t *lbc = ctrl->regs;
+ fsl_lbus_t *lbc = ctrl->regs;
if (priv->page_size) {
out_be32(&lbc->fir,
@@ -257,7 +295,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
- lbus83xx_t *lbc = ctrl->regs;
+ fsl_lbus_t *lbc = ctrl->regs;
ctrl->use_mdr = 0;
@@ -595,7 +633,7 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
- lbus83xx_t *lbc = ctrl->regs;
+ fsl_lbus_t *lbc = ctrl->regs;
if (ctrl->status != LTESR_CC)
return NAND_STATUS_FAIL;
@@ -655,13 +693,15 @@ static struct fsl_elbc_ctrl *elbc_ctrl;
static void fsl_elbc_ctrl_init(void)
{
- immap_t *im = (immap_t *)CFG_IMMR;
-
elbc_ctrl = kzalloc(sizeof(*elbc_ctrl), GFP_KERNEL);
if (!elbc_ctrl)
return;
- elbc_ctrl->regs = &im->lbus;
+#ifdef CONFIG_MPC85xx
+ elbc_ctrl->regs = (void *)CONFIG_SYS_MPC85xx_LBC_ADDR;
+#else
+ elbc_ctrl->regs = &((immap_t *)CONFIG_SYS_IMMR)->lbus;
+#endif
/* clear event registers */
out_be32(&elbc_ctrl->regs->ltesr, LTESR_NAND_MASK);
@@ -724,7 +764,12 @@ int board_nand_init(struct nand_chip *nand)
nand->waitfunc = fsl_elbc_wait;
/* set up nand options */
- nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+ nand->bbt_td = &bbt_main_descr;
+ nand->bbt_md = &bbt_mirror_descr;
+
+ /* set up nand options */
+ nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
+ NAND_USE_FLASH_BBT;
nand->controller = &elbc_ctrl->controller;
nand->priv = priv;
@@ -732,6 +777,20 @@ int board_nand_init(struct nand_chip *nand)
nand->ecc.read_page = fsl_elbc_read_page;
nand->ecc.write_page = fsl_elbc_write_page;
+#ifdef CONFIG_FSL_ELBC_FMR
+ priv->fmr = CONFIG_FSL_ELBC_FMR;
+#else
+ priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT);
+
+ /*
+ * Hardware expects small page has ECCM0, large page has ECCM1
+ * when booting from NAND. Board config can override if not
+ * booting from NAND.
+ */
+ if (or & OR_FCM_PGS)
+ priv->fmr |= FMR_ECCM;
+#endif
+
/* If CS Base Register selects full hardware ECC then use it */
if ((br & BR_DECC) == BR_DECC_CHK_GEN) {
nand->ecc.mode = NAND_ECC_HW;
@@ -748,11 +807,10 @@ int board_nand_init(struct nand_chip *nand)
nand->ecc.mode = NAND_ECC_SOFT;
}
- priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT);
-
- /* adjust Option Register and ECC to match Flash page size */
+ /* Large-page-specific setup */
if (or & OR_FCM_PGS) {
priv->page_size = 1;
+ nand->badblock_pattern = &largepage_memorybased;
/* adjust ecc setup if needed */
if ((br & BR_DECC) == BR_DECC_CHK_GEN) {
diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c
index ebd2acd..eeb19ff 100644
--- a/drivers/mtd/nand/nand.c
+++ b/drivers/mtd/nand/nand.c
@@ -24,15 +24,15 @@
#include <common.h>
#include <nand.h>
-#ifndef CFG_NAND_BASE_LIST
-#define CFG_NAND_BASE_LIST { CFG_NAND_BASE }
+#ifndef CONFIG_SYS_NAND_BASE_LIST
+#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
#endif
int nand_curr_device = -1;
-nand_info_t nand_info[CFG_MAX_NAND_DEVICE];
+nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
-static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];
-static ulong base_address[CFG_MAX_NAND_DEVICE] = CFG_NAND_BASE_LIST;
+static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
+static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
static const char default_nand_name[] = "nand";
@@ -61,15 +61,15 @@ void nand_init(void)
{
int i;
unsigned int size = 0;
- for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
- size += nand_info[i].size;
+ size += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = i;
}
- printf("%u MiB\n", size / (1024 * 1024));
+ printf("%u MiB\n", size / 1024);
-#ifdef CFG_NAND_SELECT_DEVICE
+#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
/*
* Select the chip in the board/cpu specific driver
*/
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0913bb8..ba05b76 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -7,7 +7,7 @@
* Basic support for AG-AND chips is provided.
*
* Additional technical information is available on
- * http://www.linux-mtd.infradead.org/tech/nand.html
+ * http://www.linux-mtd.infradead.org/doc/nand.html
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
@@ -24,6 +24,7 @@
* if we have HW ecc support.
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
+ * BBT table is not serialized, has to be fixed
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -128,7 +129,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
static int nand_wait(struct mtd_info *mtd, struct nand_chip *this);
/*
- * For devices which display every fart in the system on a seperate LED. Is
+ * For devices which display every fart in the system on a separate LED. Is
* compiled away when LED support is disabled.
*/
/* XXX U-BOOT XXX */
@@ -412,6 +413,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* We write two bytes, so we dont have to mess with 16 bit
* access
*/
+ nand_get_device(chip, mtd, FL_WRITING);
ofs += mtd->oobsize;
chip->ops.len = chip->ops.ooblen = 2;
chip->ops.datbuf = NULL;
@@ -419,9 +421,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
chip->ops.ooboffs = chip->badblockpos & ~0x01;
ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+ nand_release_device(mtd);
}
if (!ret)
mtd->ecc_stats.badblocks++;
+
return ret;
}
@@ -492,7 +496,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
void nand_wait_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
- u32 timeo = (CFG_HZ * 20) / 1000;
+ u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
reset_timer();
@@ -831,9 +835,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
int state = this->state;
if (state == FL_ERASING)
- timeo = (CFG_HZ * 400) / 1000;
+ timeo = (CONFIG_SYS_HZ * 400) / 1000;
else
- timeo = (CFG_HZ * 20) / 1000;
+ timeo = (CONFIG_SYS_HZ * 20) / 1000;
if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
@@ -911,7 +915,88 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- if (stat == -1)
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+ return 0;
+}
+
+/**
+ * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @dataofs offset of requested data within the page
+ * @readlen data length
+ * @buf: buffer to store read data
+ */
+static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
+{
+ int start_step, end_step, num_steps;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint8_t *p;
+ int data_col_addr, i, gaps = 0;
+ int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
+ int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+
+ /* Column address wihin the page aligned to ECC size (256bytes). */
+ start_step = data_offs / chip->ecc.size;
+ end_step = (data_offs + readlen - 1) / chip->ecc.size;
+ num_steps = end_step - start_step + 1;
+
+ /* Data size aligned to ECC ecc.size*/
+ datafrag_len = num_steps * chip->ecc.size;
+ eccfrag_len = num_steps * chip->ecc.bytes;
+
+ data_col_addr = start_step * chip->ecc.size;
+ /* If we read not a page aligned data */
+ if (data_col_addr != 0)
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
+
+ p = bufpoi + data_col_addr;
+ chip->read_buf(mtd, p, datafrag_len);
+
+ /* Calculate ECC */
+ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
+ chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
+
+ /* The performance is faster if to position offsets
+ according to ecc.pos. Let make sure here that
+ there are no gaps in ecc positions */
+ for (i = 0; i < eccfrag_len - 1; i++) {
+ if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=
+ eccpos[i + start_step * chip->ecc.bytes + 1]) {
+ gaps = 1;
+ break;
+ }
+ }
+ if (gaps) {
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ } else {
+ /* send the command to read the particular ecc bytes */
+ /* take care about buswidth alignment in read_buf */
+ aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1);
+ aligned_len = eccfrag_len;
+ if (eccpos[start_step * chip->ecc.bytes] & (busw - 1))
+ aligned_len++;
+ if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1))
+ aligned_len++;
+
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1);
+ chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
+ }
+
+ for (i = 0; i < eccfrag_len; i++)
+ chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]];
+
+ p = bufpoi + data_col_addr;
+ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
+ int stat;
+
+ stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
+ if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
@@ -996,7 +1081,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, oob, eccbytes);
stat = chip->ecc.correct(mtd, p, oob, NULL);
- if (stat == -1)
+ if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
@@ -1116,6 +1201,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
/* Now read the page into the buffer */
if (unlikely(ops->mode == MTD_OOB_RAW))
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
+ else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
+ ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);
else
ret = chip->ecc.read_page(mtd, chip, bufpoi);
if (ret < 0)
@@ -1123,7 +1210,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
/* Transfer not aligned data */
if (!aligned) {
- chip->pagebuf = realpage;
+ if (!NAND_SUBPAGE_READ(chip) && !oob)
+ chip->pagebuf = realpage;
memcpy(buf, chip->buffers->databuf + col, bytes);
}
@@ -2193,13 +2281,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
- /* Do call back function */
- if (!ret)
- mtd_erase_callback(instr);
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
+ /* Do call back function */
+ if (!ret)
+ mtd_erase_callback(instr);
+
/*
* If BBT requires refresh and erase was successful, rewrite any
* selected bad block tables
@@ -2356,10 +2445,17 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
+ int tmp_id, tmp_manf;
/* Select the device */
chip->select_chip(mtd, 0);
+ /*
+ * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
+ * after power-up
+ */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -2367,6 +2463,26 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
+ /* Try again to make sure, as some systems the bus-hold or other
+ * interface concerns can cause random data which looks like a
+ * possibly credible NAND flash to appear. If the two results do
+ * not match, ignore the device completely.
+ */
+
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+
+ /* Read manufacturer and device IDs */
+
+ tmp_manf = chip->read_byte(mtd);
+ tmp_id = chip->read_byte(mtd);
+
+ if (tmp_manf != *maf_id || tmp_id != dev_id) {
+ printk(KERN_INFO "%s: second ID read did not match "
+ "%02x,%02x against %02x,%02x\n", __func__,
+ *maf_id, dev_id, tmp_manf, tmp_id);
+ return ERR_PTR(-ENODEV);
+ }
+
/* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (dev_id == nand_flash_ids[i].id) {
@@ -2510,6 +2626,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
+ /* See comment in nand_get_flash_type for reset */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
@@ -2630,6 +2748,7 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.calculate = nand_calculate_ecc;
chip->ecc.correct = nand_correct_data;
chip->ecc.read_page = nand_read_page_swecc;
+ chip->ecc.read_subpage = nand_read_subpage;
chip->ecc.write_page = nand_write_page_swecc;
chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.write_oob = nand_write_oob_std;
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index b3b740d..d68a315f 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -6,8 +6,6 @@
*
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index ee1f6cc..94923b9 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -9,8 +9,6 @@
*
* Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de>
*
- * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $
- *
* This file 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 or (at your option) any
@@ -47,7 +45,8 @@
#include <linux/mtd/nand_ecc.h>
#endif
-#include<linux/mtd/mtd.h>
+#include <asm/errno.h>
+#include <linux/mtd/mtd.h>
/*
* NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(),
@@ -206,7 +205,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
return 1;
- return -1;
+ return -EBADMSG;
}
/* XXX U-BOOT XXX */
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2ff75c9..077c305 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -142,5 +140,6 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
+ {NAND_MFR_AMD, "AMD"},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 52b3d21..d86c987 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -78,9 +78,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
const char *mtd_device = meminfo->name;
struct mtd_oob_ops oob_opts;
struct nand_chip *chip = meminfo->priv;
- uint8_t buf[64];
- memset(buf, 0, sizeof(buf));
memset(&erase, 0, sizeof(erase));
memset(&oob_opts, 0, sizeof(oob_opts));
@@ -89,13 +87,9 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
erase.addr = opts->offset;
erase_length = opts->length;
-
cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
cleanmarker.totlen = cpu_to_je32(8);
- cleanmarker.hdr_crc = cpu_to_je32(
- crc32_no_comp(0, (unsigned char *) &cleanmarker,
- sizeof(struct jffs2_unknown_node) - 4));
/* scrub option allows to erase badblock. To prevent internal
* check from erase() method, set block check method to dummy
@@ -154,23 +148,21 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
}
/* format for JFFS2 ? */
- if (opts->jffs2) {
-
- chip->ops.len = chip->ops.ooblen = 64;
+ if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
+ chip->ops.ooblen = 8;
chip->ops.datbuf = NULL;
- chip->ops.oobbuf = buf;
- chip->ops.ooboffs = chip->badblockpos & ~0x01;
+ chip->ops.oobbuf = (uint8_t *)&cleanmarker;
+ chip->ops.ooboffs = 0;
+ chip->ops.mode = MTD_OOB_AUTO;
result = meminfo->write_oob(meminfo,
- erase.addr + meminfo->oobsize,
- &chip->ops);
+ erase.addr,
+ &chip->ops);
if (result != 0) {
printf("\n%s: MTD writeoob failure: %d\n",
- mtd_device, result);
+ mtd_device, result);
continue;
}
- else
- printf("%s: MTD writeoob at 0x%08x\n",mtd_device, erase.addr + meminfo->oobsize );
}
if (!opts->quiet) {
@@ -190,11 +182,11 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
percent_complete = percent;
printf("\rErasing at 0x%x -- %3d%% complete.",
- erase.addr, percent);
+ erase.addr, percent);
if (opts->jffs2 && result == 0)
- printf(" Cleanmarker written at 0x%x.",
- erase.addr);
+ printf(" Cleanmarker written at 0x%x.",
+ erase.addr);
}
}
}
@@ -495,11 +487,11 @@ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length,
if (len_incl_bad == *length) {
rval = nand_write (nand, offset, length, buffer);
- if (rval != 0) {
+ if (rval != 0)
printf ("NAND write to offset %x failed %d\n",
offset, rval);
- return rval;
- }
+
+ return rval;
}
while (left_to_write > 0) {
@@ -565,11 +557,11 @@ int nand_read_skip_bad(nand_info_t *nand, size_t offset, size_t *length,
if (len_incl_bad == *length) {
rval = nand_read (nand, offset, length, buffer);
- if (rval != 0) {
+ if (rval != 0)
printf ("NAND read from offset %x failed %d\n",
offset, rval);
- return rval;
- }
+
+ return rval;
}
while (left_to_read > 0) {
diff --git a/drivers/mtd/nand/s3c64xx.c b/drivers/mtd/nand/s3c64xx.c
index 159fe76..edaf55a 100644
--- a/drivers/mtd/nand/s3c64xx.c
+++ b/drivers/mtd/nand/s3c64xx.c
@@ -141,7 +141,7 @@ static int s3c_nand_device_ready(struct mtd_info *mtdinfo)
return !!(readl(NFSTAT) & NFSTAT_RnB);
}
-#ifdef CFG_S3C_NAND_HWECC
+#ifdef CONFIG_SYS_S3C_NAND_HWECC
/*
* This function is called before encoding ecc codes to ready ecc engine.
* Written by jsgood
@@ -256,7 +256,7 @@ static int s3c_nand_correct_data(struct mtd_info *mtd, u_char *dat,
return ret;
}
-#endif /* CFG_S3C_NAND_HWECC */
+#endif /* CONFIG_SYS_S3C_NAND_HWECC */
/*
* Board-specific NAND initialization. The following members of the
@@ -297,7 +297,7 @@ int board_nand_init(struct nand_chip *nand)
nand->read_buf = nand_read_buf;
#endif
-#ifdef CFG_S3C_NAND_HWECC
+#ifdef CONFIG_SYS_S3C_NAND_HWECC
nand->ecc.hwctl = s3c_nand_enable_hwecc;
nand->ecc.calculate = s3c_nand_calculate_ecc;
nand->ecc.correct = s3c_nand_correct_data;
@@ -307,11 +307,11 @@ int board_nand_init(struct nand_chip *nand)
* board one day, it will get more complicated...
*/
nand->ecc.mode = NAND_ECC_HW;
- nand->ecc.size = CFG_NAND_ECCSIZE;
- nand->ecc.bytes = CFG_NAND_ECCBYTES;
+ nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
+ nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
#else
nand->ecc.mode = NAND_ECC_SOFT;
-#endif /* ! CFG_S3C_NAND_HWECC */
+#endif /* ! CONFIG_SYS_S3C_NAND_HWECC */
nand->priv = nand_cs + chip_n++;
diff --git a/drivers/mtd/nand_legacy/nand_legacy.c b/drivers/mtd/nand_legacy/nand_legacy.c
index bf5565a..407e901 100644
--- a/drivers/mtd/nand_legacy/nand_legacy.c
+++ b/drivers/mtd/nand_legacy/nand_legacy.c
@@ -66,7 +66,7 @@ struct nand_oob_config {
int eccvalid_pos;
} oob_config = { {0}, 0, 0};
-struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE] = {{0}};
+struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE] = {{0}};
int curr_device = -1; /* Current NAND Device */
@@ -982,7 +982,7 @@ static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
#ifdef CONFIG_OMAP1510
archflashwp(0,0);
#endif
-#ifdef CFG_NAND_WP
+#ifdef CONFIG_SYS_NAND_WP
NAND_WP_OFF();
#endif
@@ -1036,7 +1036,7 @@ out:
#ifdef CONFIG_OMAP1510
archflashwp(0,1);
#endif
-#ifdef CFG_NAND_WP
+#ifdef CONFIG_SYS_NAND_WP
NAND_WP_ON();
#endif
@@ -1235,7 +1235,7 @@ int nand_legacy_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean)
#ifdef CONFIG_OMAP1510
archflashwp(0,0);
#endif
-#ifdef CFG_NAND_WP
+#ifdef CONFIG_SYS_NAND_WP
NAND_WP_OFF();
#endif
NAND_ENABLE_CE(nand); /* set pin low */
@@ -1321,7 +1321,7 @@ out:
#ifdef CONFIG_OMAP1510
archflashwp(0,1);
#endif
-#ifdef CFG_NAND_WP
+#ifdef CONFIG_SYS_NAND_WP
NAND_WP_ON();
#endif
@@ -1358,7 +1358,7 @@ unsigned long nand_probe(unsigned long physadr)
#endif
oob_config.badblock_pos = 5;
- for (i=0; i<CFG_MAX_NAND_DEVICE; i++) {
+ for (i=0; i<CONFIG_SYS_MAX_NAND_DEVICE; i++) {
if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) {
nand = &nand_dev_desc[i];
break;
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index c22a8a8..9b7bf3a 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1428,7 +1428,7 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
MTDDEBUG (MTD_DEBUG_LEVEL3,
"onenand_erase: start = 0x%08x, len = %i\n",
- (unsigned int)instr->addr, (unsigned int)ins tr->len);
+ (unsigned int)instr->addr, (unsigned int)instr->len);
block_size = (1 << this->erase_shift);
diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c
index d614450..08082f3 100644
--- a/drivers/mtd/onenand/onenand_uboot.c
+++ b/drivers/mtd/onenand/onenand_uboot.c
@@ -26,7 +26,7 @@ void onenand_init(void)
memset(&onenand_mtd, 0, sizeof(struct mtd_info));
memset(&onenand_chip, 0, sizeof(struct onenand_chip));
- onenand_chip.base = (void *) CFG_ONENAND_BASE;
+ onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE;
onenand_mtd.priv = &onenand_chip;
onenand_scan(&onenand_mtd, 1);
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index af6af97..3d4f892 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -27,6 +27,7 @@ LIB := $(obj)libspi_flash.a
COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o
COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o
+COBJS-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index d581cb3..d1d81af 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -134,6 +134,11 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
flash = spi_flash_probe_atmel(spi, idcode);
break;
#endif
+#ifdef CONFIG_SPI_FLASH_STMICRO
+ case 0x20:
+ flash = spi_flash_probe_stmicro(spi, idcode);
+ break;
+#endif
default:
debug("SF: Unsupported manufacturer %02X\n", idcode[0]);
flash = NULL;
diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h
index 1438050..75f5900 100644
--- a/drivers/mtd/spi/spi_flash_internal.h
+++ b/drivers/mtd/spi/spi_flash_internal.h
@@ -5,9 +5,9 @@
*/
/* Common parameters */
-#define SPI_FLASH_PROG_TIMEOUT ((10 * CFG_HZ) / 1000)
-#define SPI_FLASH_PAGE_ERASE_TIMEOUT ((50 * CFG_HZ) / 1000)
-#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CFG_HZ)
+#define SPI_FLASH_PROG_TIMEOUT ((10 * CONFIG_SYS_HZ) / 1000)
+#define SPI_FLASH_PAGE_ERASE_TIMEOUT ((50 * CONFIG_SYS_HZ) / 1000)
+#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ)
/* Common commands */
#define CMD_READ_ID 0x9f
@@ -43,3 +43,4 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
/* Manufacturer-specific probe functions */
struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode);
struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode);
+struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode);
diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c
new file mode 100644
index 0000000..86324e4
--- /dev/null
+++ b/drivers/mtd/spi/stmicro.c
@@ -0,0 +1,356 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright 2008, Network Appliance Inc.
+ * Jason McMullan <mcmullan@netapp.com>
+ *
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ *
+ * 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 <malloc.h>
+#include <spi_flash.h>
+
+#include "spi_flash_internal.h"
+
+/* M25Pxx-specific commands */
+#define CMD_M25PXX_WREN 0x06 /* Write Enable */
+#define CMD_M25PXX_WRDI 0x04 /* Write Disable */
+#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */
+#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */
+#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */
+#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
+#define CMD_M25PXX_PP 0x02 /* Page Program */
+#define CMD_M25PXX_SE 0xd8 /* Sector Erase */
+#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */
+#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */
+#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */
+
+#define STM_ID_M25P16 0x15
+#define STM_ID_M25P20 0x12
+#define STM_ID_M25P32 0x16
+#define STM_ID_M25P40 0x13
+#define STM_ID_M25P64 0x17
+#define STM_ID_M25P80 0x14
+#define STM_ID_M25P128 0x18
+
+#define STMICRO_SR_WIP (1 << 0) /* Write-in-Progress */
+
+struct stmicro_spi_flash_params {
+ u8 idcode1;
+ u16 page_size;
+ u16 pages_per_sector;
+ u16 nr_sectors;
+ const char *name;
+};
+
+struct stmicro_spi_flash {
+ const struct stmicro_spi_flash_params *params;
+ struct spi_flash flash;
+};
+
+static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash
+ *flash)
+{
+ return container_of(flash, struct stmicro_spi_flash, flash);
+}
+
+static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
+ {
+ .idcode1 = STM_ID_M25P16,
+ .page_size = 256,
+ .pages_per_sector = 256,
+ .nr_sectors = 32,
+ .name = "M25P16",
+ },
+ {
+ .idcode1 = STM_ID_M25P20,
+ .page_size = 256,
+ .pages_per_sector = 256,
+ .nr_sectors = 4,
+ .name = "M25P20",
+ },
+ {
+ .idcode1 = STM_ID_M25P32,
+ .page_size = 256,
+ .pages_per_sector = 256,
+ .nr_sectors = 64,
+ .name = "M25P32",
+ },
+ {
+ .idcode1 = STM_ID_M25P40,
+ .page_size = 256,
+ .pages_per_sector = 256,
+ .nr_sectors = 8,
+ .name = "M25P40",
+ },
+ {
+ .idcode1 = STM_ID_M25P64,
+ .page_size = 256,
+ .pages_per_sector = 256,
+ .nr_sectors = 128,
+ .name = "M25P64",
+ },
+ {
+ .idcode1 = STM_ID_M25P80,
+ .page_size = 256,
+ .pages_per_sector = 256,
+ .nr_sectors = 16,
+ .name = "M25P80",
+ },
+ {
+ .idcode1 = STM_ID_M25P128,
+ .page_size = 256,
+ .pages_per_sector = 1024,
+ .nr_sectors = 64,
+ .name = "M25P128",
+ },
+};
+
+static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
+{
+ struct spi_slave *spi = flash->spi;
+ unsigned long timebase;
+ int ret;
+ u8 status;
+ u8 cmd[4] = { CMD_M25PXX_RDSR, 0xff, 0xff, 0xff };
+
+ ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN);
+ if (ret) {
+ debug("SF: Failed to send command %02x: %d\n", cmd[0], ret);
+ return ret;
+ }
+
+ timebase = get_timer(0);
+ do {
+ ret = spi_xfer(spi, 8, NULL, &status, 0);
+ if (ret)
+ return -1;
+
+ if ((status & STMICRO_SR_WIP) == 0)
+ break;
+
+ } while (get_timer(timebase) < timeout);
+
+ spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
+
+ if ((status & STMICRO_SR_WIP) == 0)
+ return 0;
+
+ /* Timed out */
+ return -1;
+}
+
+static int stmicro_read_fast(struct spi_flash *flash,
+ u32 offset, size_t len, void *buf)
+{
+ struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
+ unsigned long page_addr;
+ unsigned long page_size;
+ u8 cmd[5];
+
+ page_size = stm->params->page_size;
+ page_addr = offset / page_size;
+
+ cmd[0] = CMD_READ_ARRAY_FAST;
+ cmd[1] = page_addr >> 8;
+ cmd[2] = page_addr;
+ cmd[3] = offset % page_size;
+ cmd[4] = 0x00;
+
+ return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
+}
+
+static int stmicro_write(struct spi_flash *flash,
+ u32 offset, size_t len, const void *buf)
+{
+ struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
+ unsigned long page_addr;
+ unsigned long byte_addr;
+ unsigned long page_size;
+ size_t chunk_len;
+ size_t actual;
+ int ret;
+ u8 cmd[4];
+
+ page_size = stm->params->page_size;
+ page_addr = offset / page_size;
+ byte_addr = offset % page_size;
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: Unable to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = 0;
+ for (actual = 0; actual < len; actual += chunk_len) {
+ chunk_len = min(len - actual, page_size - byte_addr);
+
+ cmd[0] = CMD_M25PXX_PP;
+ cmd[1] = page_addr >> 8;
+ cmd[2] = page_addr;
+ cmd[3] = byte_addr;
+
+ debug
+ ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
+ buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
+
+ ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
+ if (ret < 0) {
+ debug("SF: Enabling Write failed\n");
+ break;
+ }
+
+ ret = spi_flash_cmd_write(flash->spi, cmd, 4,
+ buf + actual, chunk_len);
+ if (ret < 0) {
+ debug("SF: STMicro Page Program failed\n");
+ break;
+ }
+
+ ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
+ if (ret < 0) {
+ debug("SF: STMicro page programming timed out\n");
+ break;
+ }
+
+ page_addr++;
+ byte_addr = 0;
+ }
+
+ debug("SF: STMicro: Successfully programmed %u bytes @ 0x%x\n",
+ len, offset);
+
+ spi_release_bus(flash->spi);
+ return ret;
+}
+
+int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
+{
+ struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
+ unsigned long sector_size;
+ size_t actual;
+ int ret;
+ u8 cmd[4];
+
+ /*
+ * This function currently uses sector erase only.
+ * probably speed things up by using bulk erase
+ * when possible.
+ */
+
+ sector_size = stm->params->page_size * stm->params->pages_per_sector;
+
+ if (offset % sector_size || len % sector_size) {
+ debug("SF: Erase offset/length not multiple of sector size\n");
+ return -1;
+ }
+
+ len /= sector_size;
+ cmd[0] = CMD_M25PXX_SE;
+ cmd[2] = 0x00;
+ cmd[3] = 0x00;
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: Unable to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = 0;
+ for (actual = 0; actual < len; actual++) {
+ cmd[1] = (offset / sector_size) + actual;
+
+ ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
+ if (ret < 0) {
+ debug("SF: Enabling Write failed\n");
+ break;
+ }
+
+ ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
+ if (ret < 0) {
+ debug("SF: STMicro page erase failed\n");
+ break;
+ }
+
+ /* Up to 2 seconds */
+ ret = stmicro_wait_ready(flash, 2 * CONFIG_SYS_HZ);
+ if (ret < 0) {
+ debug("SF: STMicro page erase timed out\n");
+ break;
+ }
+ }
+
+ debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n",
+ len * sector_size, offset);
+
+ spi_release_bus(flash->spi);
+ return ret;
+}
+
+struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
+{
+ const struct stmicro_spi_flash_params *params;
+ struct stmicro_spi_flash *stm;
+ unsigned int i;
+ int ret;
+ u8 id[3];
+
+ ret = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id));
+ if (ret)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) {
+ params = &stmicro_spi_flash_table[i];
+ if (params->idcode1 == idcode[2]) {
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(stmicro_spi_flash_table)) {
+ debug("SF: Unsupported STMicro ID %02x\n", id[1]);
+ return NULL;
+ }
+
+ stm = malloc(sizeof(struct stmicro_spi_flash));
+ if (!stm) {
+ debug("SF: Failed to allocate memory\n");
+ return NULL;
+ }
+
+ stm->params = params;
+ stm->flash.spi = spi;
+ stm->flash.name = params->name;
+
+ stm->flash.write = stmicro_write;
+ stm->flash.erase = stmicro_erase;
+ stm->flash.read = stmicro_read_fast;
+ stm->flash.size = params->page_size * params->pages_per_sector
+ * params->nr_sectors;
+
+ debug("SF: Detected %s with page size %u, total %u bytes\n",
+ params->name, params->page_size, stm->flash.size);
+
+ return &stm->flash;
+}
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
new file mode 100644
index 0000000..8bd82c3
--- /dev/null
+++ b/drivers/mtd/ubi/Makefile
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB := $(obj)libubi.a
+
+ifdef CONFIG_CMD_UBI
+COBJS-y += build.o vtbl.o vmt.o upd.o kapi.o eba.o io.o wl.o scan.o crc32.o
+
+COBJS-y += misc.o
+COBJS-y += debug.o
+endif
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
new file mode 100644
index 0000000..f4b01a9
--- /dev/null
+++ b/drivers/mtd/ubi/build.c
@@ -0,0 +1,1188 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2007
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём),
+ * Frank Haverkamp
+ */
+
+/*
+ * This file includes UBI initialization and building of UBI devices.
+ *
+ * When UBI is initialized, it attaches all the MTD devices specified as the
+ * module load parameters or the kernel boot parameters. If MTD devices were
+ * specified, UBI does not attach any MTD device, but it is possible to do
+ * later using the "UBI control device".
+ *
+ * At the moment we only attach UBI devices by scanning, which will become a
+ * bottleneck when flashes reach certain large size. Then one may improve UBI
+ * and add other methods, although it does not seem to be easy to do.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/stringify.h>
+#include <linux/stat.h>
+#include <linux/miscdevice.h>
+#include <linux/log2.h>
+#include <linux/kthread.h>
+#endif
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+/* Maximum length of the 'mtd=' parameter */
+#define MTD_PARAM_LEN_MAX 64
+
+/**
+ * struct mtd_dev_param - MTD device parameter description data structure.
+ * @name: MTD device name or number string
+ * @vid_hdr_offs: VID header offset
+ */
+struct mtd_dev_param
+{
+ char name[MTD_PARAM_LEN_MAX];
+ int vid_hdr_offs;
+};
+
+/* Numbers of elements set in the @mtd_dev_param array */
+static int mtd_devs = 0;
+
+/* MTD devices specification parameters */
+static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
+
+/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
+struct class *ubi_class;
+
+#ifdef UBI_LINUX
+/* Slab cache for wear-leveling entries */
+struct kmem_cache *ubi_wl_entry_slab;
+
+/* UBI control character device */
+static struct miscdevice ubi_ctrl_cdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ubi_ctrl",
+ .fops = &ubi_ctrl_cdev_operations,
+};
+#endif
+
+/* All UBI devices in system */
+struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
+
+#ifdef UBI_LINUX
+/* Serializes UBI devices creations and removals */
+DEFINE_MUTEX(ubi_devices_mutex);
+
+/* Protects @ubi_devices and @ubi->ref_count */
+static DEFINE_SPINLOCK(ubi_devices_lock);
+
+/* "Show" method for files in '/<sysfs>/class/ubi/' */
+static ssize_t ubi_version_show(struct class *class, char *buf)
+{
+ return sprintf(buf, "%d\n", UBI_VERSION);
+}
+
+/* UBI version attribute ('/<sysfs>/class/ubi/version') */
+static struct class_attribute ubi_version =
+ __ATTR(version, S_IRUGO, ubi_version_show, NULL);
+
+static ssize_t dev_attribute_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+/* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */
+static struct device_attribute dev_eraseblock_size =
+ __ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_avail_eraseblocks =
+ __ATTR(avail_eraseblocks, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_total_eraseblocks =
+ __ATTR(total_eraseblocks, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_volumes_count =
+ __ATTR(volumes_count, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_max_ec =
+ __ATTR(max_ec, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_reserved_for_bad =
+ __ATTR(reserved_for_bad, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_bad_peb_count =
+ __ATTR(bad_peb_count, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_max_vol_count =
+ __ATTR(max_vol_count, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_min_io_size =
+ __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_bgt_enabled =
+ __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_mtd_num =
+ __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
+#endif
+
+/**
+ * ubi_get_device - get UBI device.
+ * @ubi_num: UBI device number
+ *
+ * This function returns UBI device description object for UBI device number
+ * @ubi_num, or %NULL if the device does not exist. This function increases the
+ * device reference count to prevent removal of the device. In other words, the
+ * device cannot be removed if its reference count is not zero.
+ */
+struct ubi_device *ubi_get_device(int ubi_num)
+{
+ struct ubi_device *ubi;
+
+ spin_lock(&ubi_devices_lock);
+ ubi = ubi_devices[ubi_num];
+ if (ubi) {
+ ubi_assert(ubi->ref_count >= 0);
+ ubi->ref_count += 1;
+ get_device(&ubi->dev);
+ }
+ spin_unlock(&ubi_devices_lock);
+
+ return ubi;
+}
+
+/**
+ * ubi_put_device - drop an UBI device reference.
+ * @ubi: UBI device description object
+ */
+void ubi_put_device(struct ubi_device *ubi)
+{
+ spin_lock(&ubi_devices_lock);
+ ubi->ref_count -= 1;
+ put_device(&ubi->dev);
+ spin_unlock(&ubi_devices_lock);
+}
+
+/**
+ * ubi_get_by_major - get UBI device description object by character device
+ * major number.
+ * @major: major number
+ *
+ * This function is similar to 'ubi_get_device()', but it searches the device
+ * by its major number.
+ */
+struct ubi_device *ubi_get_by_major(int major)
+{
+ int i;
+ struct ubi_device *ubi;
+
+ spin_lock(&ubi_devices_lock);
+ for (i = 0; i < UBI_MAX_DEVICES; i++) {
+ ubi = ubi_devices[i];
+ if (ubi && MAJOR(ubi->cdev.dev) == major) {
+ ubi_assert(ubi->ref_count >= 0);
+ ubi->ref_count += 1;
+ get_device(&ubi->dev);
+ spin_unlock(&ubi_devices_lock);
+ return ubi;
+ }
+ }
+ spin_unlock(&ubi_devices_lock);
+
+ return NULL;
+}
+
+/**
+ * ubi_major2num - get UBI device number by character device major number.
+ * @major: major number
+ *
+ * This function searches UBI device number object by its major number. If UBI
+ * device was not found, this function returns -ENODEV, otherwise the UBI device
+ * number is returned.
+ */
+int ubi_major2num(int major)
+{
+ int i, ubi_num = -ENODEV;
+
+ spin_lock(&ubi_devices_lock);
+ for (i = 0; i < UBI_MAX_DEVICES; i++) {
+ struct ubi_device *ubi = ubi_devices[i];
+
+ if (ubi && MAJOR(ubi->cdev.dev) == major) {
+ ubi_num = ubi->ubi_num;
+ break;
+ }
+ }
+ spin_unlock(&ubi_devices_lock);
+
+ return ubi_num;
+}
+
+#ifdef UBI_LINUX
+/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
+static ssize_t dev_attribute_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct ubi_device *ubi;
+
+ /*
+ * The below code looks weird, but it actually makes sense. We get the
+ * UBI device reference from the contained 'struct ubi_device'. But it
+ * is unclear if the device was removed or not yet. Indeed, if the
+ * device was removed before we increased its reference count,
+ * 'ubi_get_device()' will return -ENODEV and we fail.
+ *
+ * Remember, 'struct ubi_device' is freed in the release function, so
+ * we still can use 'ubi->ubi_num'.
+ */
+ ubi = container_of(dev, struct ubi_device, dev);
+ ubi = ubi_get_device(ubi->ubi_num);
+ if (!ubi)
+ return -ENODEV;
+
+ if (attr == &dev_eraseblock_size)
+ ret = sprintf(buf, "%d\n", ubi->leb_size);
+ else if (attr == &dev_avail_eraseblocks)
+ ret = sprintf(buf, "%d\n", ubi->avail_pebs);
+ else if (attr == &dev_total_eraseblocks)
+ ret = sprintf(buf, "%d\n", ubi->good_peb_count);
+ else if (attr == &dev_volumes_count)
+ ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT);
+ else if (attr == &dev_max_ec)
+ ret = sprintf(buf, "%d\n", ubi->max_ec);
+ else if (attr == &dev_reserved_for_bad)
+ ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
+ else if (attr == &dev_bad_peb_count)
+ ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
+ else if (attr == &dev_max_vol_count)
+ ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
+ else if (attr == &dev_min_io_size)
+ ret = sprintf(buf, "%d\n", ubi->min_io_size);
+ else if (attr == &dev_bgt_enabled)
+ ret = sprintf(buf, "%d\n", ubi->thread_enabled);
+ else if (attr == &dev_mtd_num)
+ ret = sprintf(buf, "%d\n", ubi->mtd->index);
+ else
+ ret = -EINVAL;
+
+ ubi_put_device(ubi);
+ return ret;
+}
+
+/* Fake "release" method for UBI devices */
+static void dev_release(struct device *dev) { }
+
+/**
+ * ubi_sysfs_init - initialize sysfs for an UBI device.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int ubi_sysfs_init(struct ubi_device *ubi)
+{
+ int err;
+
+ ubi->dev.release = dev_release;
+ ubi->dev.devt = ubi->cdev.dev;
+ ubi->dev.class = ubi_class;
+ sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num);
+ err = device_register(&ubi->dev);
+ if (err)
+ return err;
+
+ err = device_create_file(&ubi->dev, &dev_eraseblock_size);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_total_eraseblocks);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_volumes_count);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_max_ec);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_reserved_for_bad);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_bad_peb_count);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_max_vol_count);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_min_io_size);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_bgt_enabled);
+ if (err)
+ return err;
+ err = device_create_file(&ubi->dev, &dev_mtd_num);
+ return err;
+}
+
+/**
+ * ubi_sysfs_close - close sysfs for an UBI device.
+ * @ubi: UBI device description object
+ */
+static void ubi_sysfs_close(struct ubi_device *ubi)
+{
+ device_remove_file(&ubi->dev, &dev_mtd_num);
+ device_remove_file(&ubi->dev, &dev_bgt_enabled);
+ device_remove_file(&ubi->dev, &dev_min_io_size);
+ device_remove_file(&ubi->dev, &dev_max_vol_count);
+ device_remove_file(&ubi->dev, &dev_bad_peb_count);
+ device_remove_file(&ubi->dev, &dev_reserved_for_bad);
+ device_remove_file(&ubi->dev, &dev_max_ec);
+ device_remove_file(&ubi->dev, &dev_volumes_count);
+ device_remove_file(&ubi->dev, &dev_total_eraseblocks);
+ device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
+ device_remove_file(&ubi->dev, &dev_eraseblock_size);
+ device_unregister(&ubi->dev);
+}
+#endif
+
+/**
+ * kill_volumes - destroy all volumes.
+ * @ubi: UBI device description object
+ */
+static void kill_volumes(struct ubi_device *ubi)
+{
+ int i;
+
+ for (i = 0; i < ubi->vtbl_slots; i++)
+ if (ubi->volumes[i])
+ ubi_free_volume(ubi, ubi->volumes[i]);
+}
+
+/**
+ * uif_init - initialize user interfaces for an UBI device.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int uif_init(struct ubi_device *ubi)
+{
+ int i, err;
+#ifdef UBI_LINUX
+ dev_t dev;
+#endif
+
+ sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
+
+ /*
+ * Major numbers for the UBI character devices are allocated
+ * dynamically. Major numbers of volume character devices are
+ * equivalent to ones of the corresponding UBI character device. Minor
+ * numbers of UBI character devices are 0, while minor numbers of
+ * volume character devices start from 1. Thus, we allocate one major
+ * number and ubi->vtbl_slots + 1 minor numbers.
+ */
+ err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name);
+ if (err) {
+ ubi_err("cannot register UBI character devices");
+ return err;
+ }
+
+ ubi_assert(MINOR(dev) == 0);
+ cdev_init(&ubi->cdev, &ubi_cdev_operations);
+ dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev));
+ ubi->cdev.owner = THIS_MODULE;
+
+ err = cdev_add(&ubi->cdev, dev, 1);
+ if (err) {
+ ubi_err("cannot add character device");
+ goto out_unreg;
+ }
+
+ err = ubi_sysfs_init(ubi);
+ if (err)
+ goto out_sysfs;
+
+ for (i = 0; i < ubi->vtbl_slots; i++)
+ if (ubi->volumes[i]) {
+ err = ubi_add_volume(ubi, ubi->volumes[i]);
+ if (err) {
+ ubi_err("cannot add volume %d", i);
+ goto out_volumes;
+ }
+ }
+
+ return 0;
+
+out_volumes:
+ kill_volumes(ubi);
+out_sysfs:
+ ubi_sysfs_close(ubi);
+ cdev_del(&ubi->cdev);
+out_unreg:
+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
+ ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
+ return err;
+}
+
+/**
+ * uif_close - close user interfaces for an UBI device.
+ * @ubi: UBI device description object
+ */
+static void uif_close(struct ubi_device *ubi)
+{
+ kill_volumes(ubi);
+ ubi_sysfs_close(ubi);
+ cdev_del(&ubi->cdev);
+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
+}
+
+/**
+ * attach_by_scanning - attach an MTD device using scanning method.
+ * @ubi: UBI device descriptor
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ *
+ * Note, currently this is the only method to attach UBI devices. Hopefully in
+ * the future we'll have more scalable attaching methods and avoid full media
+ * scanning. But even in this case scanning will be needed as a fall-back
+ * attaching method if there are some on-flash table corruptions.
+ */
+static int attach_by_scanning(struct ubi_device *ubi)
+{
+ int err;
+ struct ubi_scan_info *si;
+
+ si = ubi_scan(ubi);
+ if (IS_ERR(si))
+ return PTR_ERR(si);
+
+ ubi->bad_peb_count = si->bad_peb_count;
+ ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
+ ubi->max_ec = si->max_ec;
+ ubi->mean_ec = si->mean_ec;
+
+ err = ubi_read_volume_table(ubi, si);
+ if (err)
+ goto out_si;
+
+ err = ubi_wl_init_scan(ubi, si);
+ if (err)
+ goto out_vtbl;
+
+ err = ubi_eba_init_scan(ubi, si);
+ if (err)
+ goto out_wl;
+
+ ubi_scan_destroy_si(si);
+ return 0;
+
+out_wl:
+ ubi_wl_close(ubi);
+out_vtbl:
+ vfree(ubi->vtbl);
+out_si:
+ ubi_scan_destroy_si(si);
+ return err;
+}
+
+/**
+ * io_init - initialize I/O unit for a given UBI device.
+ * @ubi: UBI device description object
+ *
+ * If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are
+ * assumed:
+ * o EC header is always at offset zero - this cannot be changed;
+ * o VID header starts just after the EC header at the closest address
+ * aligned to @io->hdrs_min_io_size;
+ * o data starts just after the VID header at the closest address aligned to
+ * @io->min_io_size
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int io_init(struct ubi_device *ubi)
+{
+ if (ubi->mtd->numeraseregions != 0) {
+ /*
+ * Some flashes have several erase regions. Different regions
+ * may have different eraseblock size and other
+ * characteristics. It looks like mostly multi-region flashes
+ * have one "main" region and one or more small regions to
+ * store boot loader code or boot parameters or whatever. I
+ * guess we should just pick the largest region. But this is
+ * not implemented.
+ */
+ ubi_err("multiple regions, not implemented");
+ return -EINVAL;
+ }
+
+ if (ubi->vid_hdr_offset < 0)
+ return -EINVAL;
+
+ /*
+ * Note, in this implementation we support MTD devices with 0x7FFFFFFF
+ * physical eraseblocks maximum.
+ */
+
+ ubi->peb_size = ubi->mtd->erasesize;
+ ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize;
+ ubi->flash_size = ubi->mtd->size;
+
+ if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
+ ubi->bad_allowed = 1;
+
+ ubi->min_io_size = ubi->mtd->writesize;
+ ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
+
+ /*
+ * Make sure minimal I/O unit is power of 2. Note, there is no
+ * fundamental reason for this assumption. It is just an optimization
+ * which allows us to avoid costly division operations.
+ */
+ if (!is_power_of_2(ubi->min_io_size)) {
+ ubi_err("min. I/O unit (%d) is not power of 2",
+ ubi->min_io_size);
+ return -EINVAL;
+ }
+
+ ubi_assert(ubi->hdrs_min_io_size > 0);
+ ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size);
+ ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0);
+
+ /* Calculate default aligned sizes of EC and VID headers */
+ ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
+ ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
+
+ dbg_msg("min_io_size %d", ubi->min_io_size);
+ dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
+ dbg_msg("ec_hdr_alsize %d", ubi->ec_hdr_alsize);
+ dbg_msg("vid_hdr_alsize %d", ubi->vid_hdr_alsize);
+
+ if (ubi->vid_hdr_offset == 0)
+ /* Default offset */
+ ubi->vid_hdr_offset = ubi->vid_hdr_aloffset =
+ ubi->ec_hdr_alsize;
+ else {
+ ubi->vid_hdr_aloffset = ubi->vid_hdr_offset &
+ ~(ubi->hdrs_min_io_size - 1);
+ ubi->vid_hdr_shift = ubi->vid_hdr_offset -
+ ubi->vid_hdr_aloffset;
+ }
+
+ /* Similar for the data offset */
+ ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
+ ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
+
+ dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset);
+ dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);
+ dbg_msg("vid_hdr_shift %d", ubi->vid_hdr_shift);
+ dbg_msg("leb_start %d", ubi->leb_start);
+
+ /* The shift must be aligned to 32-bit boundary */
+ if (ubi->vid_hdr_shift % 4) {
+ ubi_err("unaligned VID header shift %d",
+ ubi->vid_hdr_shift);
+ return -EINVAL;
+ }
+
+ /* Check sanity */
+ if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE ||
+ ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||
+ ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||
+ ubi->leb_start & (ubi->min_io_size - 1)) {
+ ubi_err("bad VID header (%d) or data offsets (%d)",
+ ubi->vid_hdr_offset, ubi->leb_start);
+ return -EINVAL;
+ }
+
+ /*
+ * It may happen that EC and VID headers are situated in one minimal
+ * I/O unit. In this case we can only accept this UBI image in
+ * read-only mode.
+ */
+ if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) {
+ ubi_warn("EC and VID headers are in the same minimal I/O unit, "
+ "switch to read-only mode");
+ ubi->ro_mode = 1;
+ }
+
+ ubi->leb_size = ubi->peb_size - ubi->leb_start;
+
+ if (!(ubi->mtd->flags & MTD_WRITEABLE)) {
+ ubi_msg("MTD device %d is write-protected, attach in "
+ "read-only mode", ubi->mtd->index);
+ ubi->ro_mode = 1;
+ }
+
+ ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
+ ubi->peb_size, ubi->peb_size >> 10);
+ ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
+ ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
+ if (ubi->hdrs_min_io_size != ubi->min_io_size)
+ ubi_msg("sub-page size: %d",
+ ubi->hdrs_min_io_size);
+ ubi_msg("VID header offset: %d (aligned %d)",
+ ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
+ ubi_msg("data offset: %d", ubi->leb_start);
+
+ /*
+ * Note, ideally, we have to initialize ubi->bad_peb_count here. But
+ * unfortunately, MTD does not provide this information. We should loop
+ * over all physical eraseblocks and invoke mtd->block_is_bad() for
+ * each physical eraseblock. So, we skip ubi->bad_peb_count
+ * uninitialized and initialize it after scanning.
+ */
+
+ return 0;
+}
+
+/**
+ * autoresize - re-size the volume which has the "auto-resize" flag set.
+ * @ubi: UBI device description object
+ * @vol_id: ID of the volume to re-size
+ *
+ * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
+ * the volume table to the largest possible size. See comments in ubi-header.h
+ * for more description of the flag. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+static int autoresize(struct ubi_device *ubi, int vol_id)
+{
+ struct ubi_volume_desc desc;
+ struct ubi_volume *vol = ubi->volumes[vol_id];
+ int err, old_reserved_pebs = vol->reserved_pebs;
+
+ /*
+ * Clear the auto-resize flag in the volume in-memory copy of the
+ * volume table, and 'ubi_resize_volume()' will propogate this change
+ * to the flash.
+ */
+ ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
+
+ if (ubi->avail_pebs == 0) {
+ struct ubi_vtbl_record vtbl_rec;
+
+ /*
+ * No avalilable PEBs to re-size the volume, clear the flag on
+ * flash and exit.
+ */
+ memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
+ sizeof(struct ubi_vtbl_record));
+ err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+ if (err)
+ ubi_err("cannot clean auto-resize flag for volume %d",
+ vol_id);
+ } else {
+ desc.vol = vol;
+ err = ubi_resize_volume(&desc,
+ old_reserved_pebs + ubi->avail_pebs);
+ if (err)
+ ubi_err("cannot auto-resize volume %d", vol_id);
+ }
+
+ if (err)
+ return err;
+
+ ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id,
+ vol->name, old_reserved_pebs, vol->reserved_pebs);
+ return 0;
+}
+
+/**
+ * ubi_attach_mtd_dev - attach an MTD device.
+ * @mtd_dev: MTD device description object
+ * @ubi_num: number to assign to the new UBI device
+ * @vid_hdr_offset: VID header offset
+ *
+ * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
+ * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
+ * which case this function finds a vacant device nubert and assings it
+ * automatically. Returns the new UBI device number in case of success and a
+ * negative error code in case of failure.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
+ */
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+{
+ struct ubi_device *ubi;
+ int i, err;
+
+ /*
+ * Check if we already have the same MTD device attached.
+ *
+ * Note, this function assumes that UBI devices creations and deletions
+ * are serialized, so it does not take the &ubi_devices_lock.
+ */
+ for (i = 0; i < UBI_MAX_DEVICES; i++) {
+ ubi = ubi_devices[i];
+ if (ubi && mtd->index == ubi->mtd->index) {
+ dbg_err("mtd%d is already attached to ubi%d",
+ mtd->index, i);
+ return -EEXIST;
+ }
+ }
+
+ /*
+ * Make sure this MTD device is not emulated on top of an UBI volume
+ * already. Well, generally this recursion works fine, but there are
+ * different problems like the UBI module takes a reference to itself
+ * by attaching (and thus, opening) the emulated MTD device. This
+ * results in inability to unload the module. And in general it makes
+ * no sense to attach emulated MTD devices, so we prohibit this.
+ */
+ if (mtd->type == MTD_UBIVOLUME) {
+ ubi_err("refuse attaching mtd%d - it is already emulated on "
+ "top of UBI", mtd->index);
+ return -EINVAL;
+ }
+
+ if (ubi_num == UBI_DEV_NUM_AUTO) {
+ /* Search for an empty slot in the @ubi_devices array */
+ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
+ if (!ubi_devices[ubi_num])
+ break;
+ if (ubi_num == UBI_MAX_DEVICES) {
+ dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES);
+ return -ENFILE;
+ }
+ } else {
+ if (ubi_num >= UBI_MAX_DEVICES)
+ return -EINVAL;
+
+ /* Make sure ubi_num is not busy */
+ if (ubi_devices[ubi_num]) {
+ dbg_err("ubi%d already exists", ubi_num);
+ return -EEXIST;
+ }
+ }
+
+ ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
+ if (!ubi)
+ return -ENOMEM;
+
+ ubi->mtd = mtd;
+ ubi->ubi_num = ubi_num;
+ ubi->vid_hdr_offset = vid_hdr_offset;
+ ubi->autoresize_vol_id = -1;
+
+ mutex_init(&ubi->buf_mutex);
+ mutex_init(&ubi->ckvol_mutex);
+ mutex_init(&ubi->volumes_mutex);
+ spin_lock_init(&ubi->volumes_lock);
+
+ ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
+
+ err = io_init(ubi);
+ if (err)
+ goto out_free;
+
+ err = -ENOMEM;
+ ubi->peb_buf1 = vmalloc(ubi->peb_size);
+ if (!ubi->peb_buf1)
+ goto out_free;
+
+ ubi->peb_buf2 = vmalloc(ubi->peb_size);
+ if (!ubi->peb_buf2)
+ goto out_free;
+
+#ifdef CONFIG_MTD_UBI_DEBUG
+ mutex_init(&ubi->dbg_buf_mutex);
+ ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
+ if (!ubi->dbg_peb_buf)
+ goto out_free;
+#endif
+
+ err = attach_by_scanning(ubi);
+ if (err) {
+ dbg_err("failed to attach by scanning, error %d", err);
+ goto out_free;
+ }
+
+ if (ubi->autoresize_vol_id != -1) {
+ err = autoresize(ubi, ubi->autoresize_vol_id);
+ if (err)
+ goto out_detach;
+ }
+
+ err = uif_init(ubi);
+ if (err)
+ goto out_detach;
+
+ ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+ if (IS_ERR(ubi->bgt_thread)) {
+ err = PTR_ERR(ubi->bgt_thread);
+ ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
+ err);
+ goto out_uif;
+ }
+
+ ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
+ ubi_msg("MTD device name: \"%s\"", mtd->name);
+ ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
+ ubi_msg("number of good PEBs: %d", ubi->good_peb_count);
+ ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count);
+ ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots);
+ ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD);
+ ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
+ ubi_msg("number of user volumes: %d",
+ ubi->vol_count - UBI_INT_VOL_COUNT);
+ ubi_msg("available PEBs: %d", ubi->avail_pebs);
+ ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs);
+ ubi_msg("number of PEBs reserved for bad PEB handling: %d",
+ ubi->beb_rsvd_pebs);
+ ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
+
+ /* Enable the background thread */
+ if (!DBG_DISABLE_BGT) {
+ ubi->thread_enabled = 1;
+ wake_up_process(ubi->bgt_thread);
+ }
+
+ ubi_devices[ubi_num] = ubi;
+ return ubi_num;
+
+out_uif:
+ uif_close(ubi);
+out_detach:
+ ubi_eba_close(ubi);
+ ubi_wl_close(ubi);
+ vfree(ubi->vtbl);
+out_free:
+ vfree(ubi->peb_buf1);
+ vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+ vfree(ubi->dbg_peb_buf);
+#endif
+ kfree(ubi);
+ return err;
+}
+
+/**
+ * ubi_detach_mtd_dev - detach an MTD device.
+ * @ubi_num: UBI device number to detach from
+ * @anyway: detach MTD even if device reference count is not zero
+ *
+ * This function destroys an UBI device number @ubi_num and detaches the
+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the
+ * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not
+ * exist.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
+ */
+int ubi_detach_mtd_dev(int ubi_num, int anyway)
+{
+ struct ubi_device *ubi;
+
+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+ return -EINVAL;
+
+ spin_lock(&ubi_devices_lock);
+ ubi = ubi_devices[ubi_num];
+ if (!ubi) {
+ spin_unlock(&ubi_devices_lock);
+ return -EINVAL;
+ }
+
+ if (ubi->ref_count) {
+ if (!anyway) {
+ spin_unlock(&ubi_devices_lock);
+ return -EBUSY;
+ }
+ /* This may only happen if there is a bug */
+ ubi_err("%s reference count %d, destroy anyway",
+ ubi->ubi_name, ubi->ref_count);
+ }
+ ubi_devices[ubi_num] = NULL;
+ spin_unlock(&ubi_devices_lock);
+
+ ubi_assert(ubi_num == ubi->ubi_num);
+ dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
+
+ /*
+ * Before freeing anything, we have to stop the background thread to
+ * prevent it from doing anything on this device while we are freeing.
+ */
+ if (ubi->bgt_thread)
+ kthread_stop(ubi->bgt_thread);
+
+ uif_close(ubi);
+ ubi_eba_close(ubi);
+ ubi_wl_close(ubi);
+ vfree(ubi->vtbl);
+ put_mtd_device(ubi->mtd);
+ vfree(ubi->peb_buf1);
+ vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+ vfree(ubi->dbg_peb_buf);
+#endif
+ ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
+ kfree(ubi);
+ return 0;
+}
+
+/**
+ * find_mtd_device - open an MTD device by its name or number.
+ * @mtd_dev: name or number of the device
+ *
+ * This function tries to open and MTD device described by @mtd_dev string,
+ * which is first treated as an ASCII number, and if it is not true, it is
+ * treated as MTD device name. Returns MTD device description object in case of
+ * success and a negative error code in case of failure.
+ */
+static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
+{
+ struct mtd_info *mtd;
+ int mtd_num;
+ char *endp;
+
+ mtd_num = simple_strtoul(mtd_dev, &endp, 0);
+ if (*endp != '\0' || mtd_dev == endp) {
+ /*
+ * This does not look like an ASCII integer, probably this is
+ * MTD device name.
+ */
+ mtd = get_mtd_device_nm(mtd_dev);
+ } else
+ mtd = get_mtd_device(NULL, mtd_num);
+
+ return mtd;
+}
+
+int __init ubi_init(void)
+{
+ int err, i, k;
+
+ /* Ensure that EC and VID headers have correct size */
+ BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
+ BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
+
+ if (mtd_devs > UBI_MAX_DEVICES) {
+ ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES);
+ return -EINVAL;
+ }
+
+ /* Create base sysfs directory and sysfs files */
+ ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
+ if (IS_ERR(ubi_class)) {
+ err = PTR_ERR(ubi_class);
+ ubi_err("cannot create UBI class");
+ goto out;
+ }
+
+ err = class_create_file(ubi_class, &ubi_version);
+ if (err) {
+ ubi_err("cannot create sysfs file");
+ goto out_class;
+ }
+
+ err = misc_register(&ubi_ctrl_cdev);
+ if (err) {
+ ubi_err("cannot register device");
+ goto out_version;
+ }
+
+#ifdef UBI_LINUX
+ ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+ sizeof(struct ubi_wl_entry),
+ 0, 0, NULL);
+ if (!ubi_wl_entry_slab)
+ goto out_dev_unreg;
+#endif
+
+ /* Attach MTD devices */
+ for (i = 0; i < mtd_devs; i++) {
+ struct mtd_dev_param *p = &mtd_dev_param[i];
+ struct mtd_info *mtd;
+
+ cond_resched();
+
+ mtd = open_mtd_device(p->name);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ goto out_detach;
+ }
+
+ mutex_lock(&ubi_devices_mutex);
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO,
+ p->vid_hdr_offs);
+ mutex_unlock(&ubi_devices_mutex);
+ if (err < 0) {
+ put_mtd_device(mtd);
+ ubi_err("cannot attach mtd%d", mtd->index);
+ goto out_detach;
+ }
+ }
+
+ return 0;
+
+out_detach:
+ for (k = 0; k < i; k++)
+ if (ubi_devices[k]) {
+ mutex_lock(&ubi_devices_mutex);
+ ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+ mutex_unlock(&ubi_devices_mutex);
+ }
+#ifdef UBI_LINUX
+ kmem_cache_destroy(ubi_wl_entry_slab);
+out_dev_unreg:
+#endif
+ misc_deregister(&ubi_ctrl_cdev);
+out_version:
+ class_remove_file(ubi_class, &ubi_version);
+out_class:
+ class_destroy(ubi_class);
+out:
+ ubi_err("UBI error: cannot initialize UBI, error %d", err);
+ return err;
+}
+module_init(ubi_init);
+
+void __exit ubi_exit(void)
+{
+ int i;
+
+ for (i = 0; i < UBI_MAX_DEVICES; i++)
+ if (ubi_devices[i]) {
+ mutex_lock(&ubi_devices_mutex);
+ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
+ mutex_unlock(&ubi_devices_mutex);
+ }
+ kmem_cache_destroy(ubi_wl_entry_slab);
+ misc_deregister(&ubi_ctrl_cdev);
+ class_remove_file(ubi_class, &ubi_version);
+ class_destroy(ubi_class);
+ mtd_devs = 0;
+}
+module_exit(ubi_exit);
+
+/**
+ * bytes_str_to_int - convert a string representing number of bytes to an
+ * integer.
+ * @str: the string to convert
+ *
+ * This function returns positive resulting integer in case of success and a
+ * negative error code in case of failure.
+ */
+static int __init bytes_str_to_int(const char *str)
+{
+ char *endp;
+ unsigned long result;
+
+ result = simple_strtoul(str, &endp, 0);
+ if (str == endp || result < 0) {
+ printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n",
+ str);
+ return -EINVAL;
+ }
+
+ switch (*endp) {
+ case 'G':
+ result *= 1024;
+ case 'M':
+ result *= 1024;
+ case 'K':
+ result *= 1024;
+ if (endp[1] == 'i' && endp[2] == 'B')
+ endp += 2;
+ case '\0':
+ break;
+ default:
+ printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n",
+ str);
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+/**
+ * ubi_mtd_param_parse - parse the 'mtd=' UBI parameter.
+ * @val: the parameter value to parse
+ * @kp: not used
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of error.
+ */
+int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
+{
+ int i, len;
+ struct mtd_dev_param *p;
+ char buf[MTD_PARAM_LEN_MAX];
+ char *pbuf = &buf[0];
+ char *tokens[2] = {NULL, NULL};
+
+ if (!val)
+ return -EINVAL;
+
+ if (mtd_devs == UBI_MAX_DEVICES) {
+ printk(KERN_ERR "UBI error: too many parameters, max. is %d\n",
+ UBI_MAX_DEVICES);
+ return -EINVAL;
+ }
+
+ len = strnlen(val, MTD_PARAM_LEN_MAX);
+ if (len == MTD_PARAM_LEN_MAX) {
+ printk(KERN_ERR "UBI error: parameter \"%s\" is too long, "
+ "max. is %d\n", val, MTD_PARAM_LEN_MAX);
+ return -EINVAL;
+ }
+
+ if (len == 0) {
+ printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - "
+ "ignored\n");
+ return 0;
+ }
+
+ strcpy(buf, val);
+
+ /* Get rid of the final newline */
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+
+ for (i = 0; i < 2; i++)
+ tokens[i] = strsep(&pbuf, ",");
+
+ if (pbuf) {
+ printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n",
+ val);
+ return -EINVAL;
+ }
+
+ p = &mtd_dev_param[mtd_devs];
+ strcpy(&p->name[0], tokens[0]);
+
+ if (tokens[1])
+ p->vid_hdr_offs = bytes_str_to_int(tokens[1]);
+
+ if (p->vid_hdr_offs < 0)
+ return p->vid_hdr_offs;
+
+ mtd_devs += 1;
+ return 0;
+}
+
+module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
+MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
+ "mtd=<name|num>[,<vid_hdr_offs>].\n"
+ "Multiple \"mtd\" parameters may be specified.\n"
+ "MTD devices may be specified by their number or name.\n"
+ "Optional \"vid_hdr_offs\" parameter specifies UBI VID "
+ "header position and data starting position to be used "
+ "by UBI.\n"
+ "Example: mtd=content,1984 mtd=4 - attach MTD device"
+ "with name \"content\" using VID header offset 1984, and "
+ "MTD device number 4 with default VID header offset.");
+
+MODULE_VERSION(__stringify(UBI_VERSION));
+MODULE_DESCRIPTION("UBI - Unsorted Block Images");
+MODULE_AUTHOR("Artem Bityutskiy");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/ubi/crc32.c b/drivers/mtd/ubi/crc32.c
new file mode 100644
index 0000000..a7e26b0
--- /dev/null
+++ b/drivers/mtd/ubi/crc32.c
@@ -0,0 +1,518 @@
+/*
+ * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks!
+ * Code was from the public domain, copyright abandoned. Code was
+ * subsequently included in the kernel, thus was re-licensed under the
+ * GNU GPL v2.
+ *
+ * Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Same crc32 function was used in 5 other places in the kernel.
+ * I made one version, and deleted the others.
+ * There are various incantations of crc32(). Some use a seed of 0 or ~0.
+ * Some xor at the end with ~0. The generic crc32() function takes
+ * seed as an argument, and doesn't xor at the end. Then individual
+ * users can do whatever they need.
+ * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
+ * fs/jffs2 uses seed 0, doesn't xor with ~0.
+ * fs/partitions/efi.c uses seed ~0, xor's with ~0.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/crc32.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/compiler.h>
+#endif
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+#ifdef UBI_LINUX
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+#endif
+#include "crc32defs.h"
+#define CRC_LE_BITS 8
+
+# define __force
+#ifndef __constant_cpu_to_le32
+#define __constant_cpu_to_le32(x) ((__force __le32)(__u32)(x))
+#endif
+#ifndef __constant_le32_to_cpu
+#define __constant_le32_to_cpu(x) ((__force __u32)(__le32)(x))
+#endif
+
+#if CRC_LE_BITS == 8
+#define tole(x) __constant_cpu_to_le32(x)
+#define tobe(x) __constant_cpu_to_be32(x)
+#else
+#define tole(x) (x)
+#define tobe(x) (x)
+#endif
+#include "crc32table.h"
+#ifdef UBI_LINUX
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
+MODULE_DESCRIPTION("Ethernet CRC32 calculations");
+MODULE_LICENSE("GPL");
+#endif
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 crc32_le(u32 crc, unsigned char const *p, size_t len);
+
+#if CRC_LE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+
+u32 crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ }
+ return crc;
+}
+#else /* Table-based approach */
+
+u32 crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+# if CRC_LE_BITS == 8
+ const u32 *b =(u32 *)p;
+ const u32 *tab = crc32table_le;
+
+# ifdef __LITTLE_ENDIAN
+# define DO_CRC(x) crc = tab[ (crc ^ (x)) & 255 ] ^ (crc>>8)
+# else
+# define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8)
+# endif
+ /* printf("Crc32_le crc=%x\n",crc); */
+ crc = __cpu_to_le32(crc);
+ /* Align it */
+ if((((long)b)&3 && len)){
+ do {
+ u8 *p = (u8 *)b;
+ DO_CRC(*p++);
+ b = (void *)p;
+ } while ((--len) && ((long)b)&3 );
+ }
+ if((len >= 4)){
+ /* load data 32 bits wide, xor data 32 bits wide. */
+ size_t save_len = len & 3;
+ len = len >> 2;
+ --b; /* use pre increment below(*++b) for speed */
+ do {
+ crc ^= *++b;
+ DO_CRC(0);
+ DO_CRC(0);
+ DO_CRC(0);
+ DO_CRC(0);
+ } while (--len);
+ b++; /* point to next byte(s) */
+ len = save_len;
+ }
+ /* And the last few bytes */
+ if(len){
+ do {
+ u8 *p = (u8 *)b;
+ DO_CRC(*p++);
+ b = (void *)p;
+ } while (--len);
+ }
+
+ return __le32_to_cpu(crc);
+#undef ENDIAN_SHIFT
+#undef DO_CRC
+
+# elif CRC_LE_BITS == 4
+ while (len--) {
+ crc ^= *p++;
+ crc = (crc >> 4) ^ crc32table_le[crc & 15];
+ crc = (crc >> 4) ^ crc32table_le[crc & 15];
+ }
+ return crc;
+# elif CRC_LE_BITS == 2
+ while (len--) {
+ crc ^= *p++;
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ crc = (crc >> 2) ^ crc32table_le[crc & 3];
+ }
+ return crc;
+# endif
+}
+#endif
+#ifdef UBI_LINUX
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
+ * other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len);
+
+#if CRC_BE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+
+u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++ << 24;
+ for (i = 0; i < 8; i++)
+ crc =
+ (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
+ 0);
+ }
+ return crc;
+}
+
+#else /* Table-based approach */
+u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+# if CRC_BE_BITS == 8
+ const u32 *b =(u32 *)p;
+ const u32 *tab = crc32table_be;
+
+# ifdef __LITTLE_ENDIAN
+# define DO_CRC(x) crc = tab[ (crc ^ (x)) & 255 ] ^ (crc>>8)
+# else
+# define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8)
+# endif
+
+ crc = __cpu_to_be32(crc);
+ /* Align it */
+ if(unlikely(((long)b)&3 && len)){
+ do {
+ u8 *p = (u8 *)b;
+ DO_CRC(*p++);
+ b = (u32 *)p;
+ } while ((--len) && ((long)b)&3 );
+ }
+ if(likely(len >= 4)){
+ /* load data 32 bits wide, xor data 32 bits wide. */
+ size_t save_len = len & 3;
+ len = len >> 2;
+ --b; /* use pre increment below(*++b) for speed */
+ do {
+ crc ^= *++b;
+ DO_CRC(0);
+ DO_CRC(0);
+ DO_CRC(0);
+ DO_CRC(0);
+ } while (--len);
+ b++; /* point to next byte(s) */
+ len = save_len;
+ }
+ /* And the last few bytes */
+ if(len){
+ do {
+ u8 *p = (u8 *)b;
+ DO_CRC(*p++);
+ b = (void *)p;
+ } while (--len);
+ }
+ return __be32_to_cpu(crc);
+#undef ENDIAN_SHIFT
+#undef DO_CRC
+
+# elif CRC_BE_BITS == 4
+ while (len--) {
+ crc ^= *p++ << 24;
+ crc = (crc << 4) ^ crc32table_be[crc >> 28];
+ crc = (crc << 4) ^ crc32table_be[crc >> 28];
+ }
+ return crc;
+# elif CRC_BE_BITS == 2
+ while (len--) {
+ crc ^= *p++ << 24;
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ crc = (crc << 2) ^ crc32table_be[crc >> 30];
+ }
+ return crc;
+# endif
+}
+#endif
+
+EXPORT_SYMBOL(crc32_le);
+EXPORT_SYMBOL(crc32_be);
+#endif
+/*
+ * A brief CRC tutorial.
+ *
+ * A CRC is a long-division remainder. You add the CRC to the message,
+ * and the whole thing (message+CRC) is a multiple of the given
+ * CRC polynomial. To check the CRC, you can either check that the
+ * CRC matches the recomputed value, *or* you can check that the
+ * remainder computed on the message+CRC is 0. This latter approach
+ * is used by a lot of hardware implementations, and is why so many
+ * protocols put the end-of-frame flag after the CRC.
+ *
+ * It's actually the same long division you learned in school, except that
+ * - We're working in binary, so the digits are only 0 and 1, and
+ * - When dividing polynomials, there are no carries. Rather than add and
+ * subtract, we just xor. Thus, we tend to get a bit sloppy about
+ * the difference between adding and subtracting.
+ *
+ * A 32-bit CRC polynomial is actually 33 bits long. But since it's
+ * 33 bits long, bit 32 is always going to be set, so usually the CRC
+ * is written in hex with the most significant bit omitted. (If you're
+ * familiar with the IEEE 754 floating-point format, it's the same idea.)
+ *
+ * Note that a CRC is computed over a string of *bits*, so you have
+ * to decide on the endianness of the bits within each byte. To get
+ * the best error-detecting properties, this should correspond to the
+ * order they're actually sent. For example, standard RS-232 serial is
+ * little-endian; the most significant bit (sometimes used for parity)
+ * is sent last. And when appending a CRC word to a message, you should
+ * do it in the right order, matching the endianness.
+ *
+ * Just like with ordinary division, the remainder is always smaller than
+ * the divisor (the CRC polynomial) you're dividing by. Each step of the
+ * division, you take one more digit (bit) of the dividend and append it
+ * to the current remainder. Then you figure out the appropriate multiple
+ * of the divisor to subtract to being the remainder back into range.
+ * In binary, it's easy - it has to be either 0 or 1, and to make the
+ * XOR cancel, it's just a copy of bit 32 of the remainder.
+ *
+ * When computing a CRC, we don't care about the quotient, so we can
+ * throw the quotient bit away, but subtract the appropriate multiple of
+ * the polynomial from the remainder and we're back to where we started,
+ * ready to process the next bit.
+ *
+ * A big-endian CRC written this way would be coded like:
+ * for (i = 0; i < input_bits; i++) {
+ * multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+ * remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+ * }
+ * Notice how, to get at bit 32 of the shifted remainder, we look
+ * at bit 31 of the remainder *before* shifting it.
+ *
+ * But also notice how the next_input_bit() bits we're shifting into
+ * the remainder don't actually affect any decision-making until
+ * 32 bits later. Thus, the first 32 cycles of this are pretty boring.
+ * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
+ * the end, so we have to add 32 extra cycles shifting in zeros at the
+ * end of every message,
+ *
+ * So the standard trick is to rearrage merging in the next_input_bit()
+ * until the moment it's needed. Then the first 32 cycles can be precomputed,
+ * and merging in the final 32 zero bits to make room for the CRC can be
+ * skipped entirely.
+ * This changes the code to:
+ * for (i = 0; i < input_bits; i++) {
+ * remainder ^= next_input_bit() << 31;
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * With this optimization, the little-endian code is simpler:
+ * for (i = 0; i < input_bits; i++) {
+ * remainder ^= next_input_bit();
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder >> 1) ^ multiple;
+ * }
+ *
+ * Note that the other details of endianness have been hidden in CRCPOLY
+ * (which must be bit-reversed) and next_input_bit().
+ *
+ * However, as long as next_input_bit is returning the bits in a sensible
+ * order, we can actually do the merging 8 or more bits at a time rather
+ * than one bit at a time:
+ * for (i = 0; i < input_bytes; i++) {
+ * remainder ^= next_input_byte() << 24;
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * }
+ * Or in little-endian:
+ * for (i = 0; i < input_bytes; i++) {
+ * remainder ^= next_input_byte();
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
+ * }
+ * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
+ * word at a time and increase the inner loop count to 32.
+ *
+ * You can also mix and match the two loop styles, for example doing the
+ * bulk of a message byte-at-a-time and adding bit-at-a-time processing
+ * for any fractional bytes at the end.
+ *
+ * The only remaining optimization is to the byte-at-a-time table method.
+ * Here, rather than just shifting one bit of the remainder to decide
+ * in the correct multiple to subtract, we can shift a byte at a time.
+ * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
+ * but again the multiple of the polynomial to subtract depends only on
+ * the high bits, the high 8 bits in this case.
+ *
+ * The multile we need in that case is the low 32 bits of a 40-bit
+ * value whose high 8 bits are given, and which is a multiple of the
+ * generator polynomial. This is simply the CRC-32 of the given
+ * one-byte message.
+ *
+ * Two more details: normally, appending zero bits to a message which
+ * is already a multiple of a polynomial produces a larger multiple of that
+ * polynomial. To enable a CRC to detect this condition, it's common to
+ * invert the CRC before appending it. This makes the remainder of the
+ * message+crc come out not as zero, but some fixed non-zero value.
+ *
+ * The same problem applies to zero bits prepended to the message, and
+ * a similar solution is used. Instead of starting with a remainder of
+ * 0, an initial remainder of all ones is used. As long as you start
+ * the same way on decoding, it doesn't make a difference.
+ */
+
+#ifdef UNITTEST
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef UBI_LINUX /*Not used at present */
+static void
+buf_dump(char const *prefix, unsigned char const *buf, size_t len)
+{
+ fputs(prefix, stdout);
+ while (len--)
+ printf(" %02x", *buf++);
+ putchar('\n');
+
+}
+#endif
+
+static void bytereverse(unsigned char *buf, size_t len)
+{
+ while (len--) {
+ unsigned char x = bitrev8(*buf);
+ *buf++ = x;
+ }
+}
+
+static void random_garbage(unsigned char *buf, size_t len)
+{
+ while (len--)
+ *buf++ = (unsigned char) random();
+}
+
+#ifdef UBI_LINUX /* Not used at present */
+static void store_le(u32 x, unsigned char *buf)
+{
+ buf[0] = (unsigned char) x;
+ buf[1] = (unsigned char) (x >> 8);
+ buf[2] = (unsigned char) (x >> 16);
+ buf[3] = (unsigned char) (x >> 24);
+}
+#endif
+
+static void store_be(u32 x, unsigned char *buf)
+{
+ buf[0] = (unsigned char) (x >> 24);
+ buf[1] = (unsigned char) (x >> 16);
+ buf[2] = (unsigned char) (x >> 8);
+ buf[3] = (unsigned char) x;
+}
+
+/*
+ * This checks that CRC(buf + CRC(buf)) = 0, and that
+ * CRC commutes with bit-reversal. This has the side effect
+ * of bytewise bit-reversing the input buffer, and returns
+ * the CRC of the reversed buffer.
+ */
+static u32 test_step(u32 init, unsigned char *buf, size_t len)
+{
+ u32 crc1, crc2;
+ size_t i;
+
+ crc1 = crc32_be(init, buf, len);
+ store_be(crc1, buf + len);
+ crc2 = crc32_be(init, buf, len + 4);
+ if (crc2)
+ printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+ crc2);
+
+ for (i = 0; i <= len + 4; i++) {
+ crc2 = crc32_be(init, buf, i);
+ crc2 = crc32_be(crc2, buf + i, len + 4 - i);
+ if (crc2)
+ printf("\nCRC split fail: 0x%08x\n", crc2);
+ }
+
+ /* Now swap it around for the other test */
+
+ bytereverse(buf, len + 4);
+ init = bitrev32(init);
+ crc2 = bitrev32(crc1);
+ if (crc1 != bitrev32(crc2))
+ printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
+ crc1, crc2, bitrev32(crc2));
+ crc1 = crc32_le(init, buf, len);
+ if (crc1 != crc2)
+ printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
+ crc2);
+ crc2 = crc32_le(init, buf, len + 4);
+ if (crc2)
+ printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+ crc2);
+
+ for (i = 0; i <= len + 4; i++) {
+ crc2 = crc32_le(init, buf, i);
+ crc2 = crc32_le(crc2, buf + i, len + 4 - i);
+ if (crc2)
+ printf("\nCRC split fail: 0x%08x\n", crc2);
+ }
+
+ return crc1;
+}
+
+#define SIZE 64
+#define INIT1 0
+#define INIT2 0
+
+int main(void)
+{
+ unsigned char buf1[SIZE + 4];
+ unsigned char buf2[SIZE + 4];
+ unsigned char buf3[SIZE + 4];
+ int i, j;
+ u32 crc1, crc2, crc3;
+
+ for (i = 0; i <= SIZE; i++) {
+ printf("\rTesting length %d...", i);
+ fflush(stdout);
+ random_garbage(buf1, i);
+ random_garbage(buf2, i);
+ for (j = 0; j < i; j++)
+ buf3[j] = buf1[j] ^ buf2[j];
+
+ crc1 = test_step(INIT1, buf1, i);
+ crc2 = test_step(INIT2, buf2, i);
+ /* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
+ crc3 = test_step(INIT1 ^ INIT2, buf3, i);
+ if (crc3 != (crc1 ^ crc2))
+ printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
+ crc3, crc1, crc2);
+ }
+ printf("\nAll test complete. No failures expected.\n");
+ return 0;
+}
+
+#endif /* UNITTEST */
diff --git a/drivers/mtd/ubi/crc32defs.h b/drivers/mtd/ubi/crc32defs.h
new file mode 100644
index 0000000..f5a5401
--- /dev/null
+++ b/drivers/mtd/ubi/crc32defs.h
@@ -0,0 +1,32 @@
+/*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+#define CRCPOLY_BE 0x04c11db7
+
+/* How many bits at a time to use. Requires a table of 4<<CRC_xx_BITS bytes. */
+/* For less performance-sensitive, use 4 */
+#ifndef CRC_LE_BITS
+# define CRC_LE_BITS 8
+#endif
+#ifndef CRC_BE_BITS
+# define CRC_BE_BITS 8
+#endif
+
+/*
+ * Little-endian CRC computation. Used with serial bit streams sent
+ * lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC.
+ */
+#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
+# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#endif
+
+/*
+ * Big-endian CRC computation. Used with serial bit streams sent
+ * msbit-first. Be sure to use cpu_to_be32() to append the computed CRC.
+ */
+#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
+# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#endif
diff --git a/drivers/mtd/ubi/crc32table.h b/drivers/mtd/ubi/crc32table.h
new file mode 100644
index 0000000..0438af4
--- /dev/null
+++ b/drivers/mtd/ubi/crc32table.h
@@ -0,0 +1,136 @@
+/* this file is generated - do not edit */
+
+static const u32 crc32table_le[] = {
+tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL),
+tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L),
+tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L),
+tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L),
+tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL),
+tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L),
+tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL),
+tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L),
+tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L),
+tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL),
+tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L),
+tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L),
+tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L),
+tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL),
+tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L),
+tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL),
+tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL),
+tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L),
+tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L),
+tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L),
+tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL),
+tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L),
+tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL),
+tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L),
+tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L),
+tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL),
+tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L),
+tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L),
+tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L),
+tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL),
+tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L),
+tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL),
+tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL),
+tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L),
+tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L),
+tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L),
+tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL),
+tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L),
+tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL),
+tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L),
+tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L),
+tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL),
+tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L),
+tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L),
+tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L),
+tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL),
+tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L),
+tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL),
+tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL),
+tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L),
+tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L),
+tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L),
+tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL),
+tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L),
+tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL),
+tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L),
+tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L),
+tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL),
+tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L),
+tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L),
+tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L),
+tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL),
+tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L),
+tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL)
+};
+#ifdef UBI_LINUX
+static const u32 crc32table_be[] = {
+tobe(0x00000000L), tobe(0x04c11db7L), tobe(0x09823b6eL), tobe(0x0d4326d9L),
+tobe(0x130476dcL), tobe(0x17c56b6bL), tobe(0x1a864db2L), tobe(0x1e475005L),
+tobe(0x2608edb8L), tobe(0x22c9f00fL), tobe(0x2f8ad6d6L), tobe(0x2b4bcb61L),
+tobe(0x350c9b64L), tobe(0x31cd86d3L), tobe(0x3c8ea00aL), tobe(0x384fbdbdL),
+tobe(0x4c11db70L), tobe(0x48d0c6c7L), tobe(0x4593e01eL), tobe(0x4152fda9L),
+tobe(0x5f15adacL), tobe(0x5bd4b01bL), tobe(0x569796c2L), tobe(0x52568b75L),
+tobe(0x6a1936c8L), tobe(0x6ed82b7fL), tobe(0x639b0da6L), tobe(0x675a1011L),
+tobe(0x791d4014L), tobe(0x7ddc5da3L), tobe(0x709f7b7aL), tobe(0x745e66cdL),
+tobe(0x9823b6e0L), tobe(0x9ce2ab57L), tobe(0x91a18d8eL), tobe(0x95609039L),
+tobe(0x8b27c03cL), tobe(0x8fe6dd8bL), tobe(0x82a5fb52L), tobe(0x8664e6e5L),
+tobe(0xbe2b5b58L), tobe(0xbaea46efL), tobe(0xb7a96036L), tobe(0xb3687d81L),
+tobe(0xad2f2d84L), tobe(0xa9ee3033L), tobe(0xa4ad16eaL), tobe(0xa06c0b5dL),
+tobe(0xd4326d90L), tobe(0xd0f37027L), tobe(0xddb056feL), tobe(0xd9714b49L),
+tobe(0xc7361b4cL), tobe(0xc3f706fbL), tobe(0xceb42022L), tobe(0xca753d95L),
+tobe(0xf23a8028L), tobe(0xf6fb9d9fL), tobe(0xfbb8bb46L), tobe(0xff79a6f1L),
+tobe(0xe13ef6f4L), tobe(0xe5ffeb43L), tobe(0xe8bccd9aL), tobe(0xec7dd02dL),
+tobe(0x34867077L), tobe(0x30476dc0L), tobe(0x3d044b19L), tobe(0x39c556aeL),
+tobe(0x278206abL), tobe(0x23431b1cL), tobe(0x2e003dc5L), tobe(0x2ac12072L),
+tobe(0x128e9dcfL), tobe(0x164f8078L), tobe(0x1b0ca6a1L), tobe(0x1fcdbb16L),
+tobe(0x018aeb13L), tobe(0x054bf6a4L), tobe(0x0808d07dL), tobe(0x0cc9cdcaL),
+tobe(0x7897ab07L), tobe(0x7c56b6b0L), tobe(0x71159069L), tobe(0x75d48ddeL),
+tobe(0x6b93dddbL), tobe(0x6f52c06cL), tobe(0x6211e6b5L), tobe(0x66d0fb02L),
+tobe(0x5e9f46bfL), tobe(0x5a5e5b08L), tobe(0x571d7dd1L), tobe(0x53dc6066L),
+tobe(0x4d9b3063L), tobe(0x495a2dd4L), tobe(0x44190b0dL), tobe(0x40d816baL),
+tobe(0xaca5c697L), tobe(0xa864db20L), tobe(0xa527fdf9L), tobe(0xa1e6e04eL),
+tobe(0xbfa1b04bL), tobe(0xbb60adfcL), tobe(0xb6238b25L), tobe(0xb2e29692L),
+tobe(0x8aad2b2fL), tobe(0x8e6c3698L), tobe(0x832f1041L), tobe(0x87ee0df6L),
+tobe(0x99a95df3L), tobe(0x9d684044L), tobe(0x902b669dL), tobe(0x94ea7b2aL),
+tobe(0xe0b41de7L), tobe(0xe4750050L), tobe(0xe9362689L), tobe(0xedf73b3eL),
+tobe(0xf3b06b3bL), tobe(0xf771768cL), tobe(0xfa325055L), tobe(0xfef34de2L),
+tobe(0xc6bcf05fL), tobe(0xc27dede8L), tobe(0xcf3ecb31L), tobe(0xcbffd686L),
+tobe(0xd5b88683L), tobe(0xd1799b34L), tobe(0xdc3abdedL), tobe(0xd8fba05aL),
+tobe(0x690ce0eeL), tobe(0x6dcdfd59L), tobe(0x608edb80L), tobe(0x644fc637L),
+tobe(0x7a089632L), tobe(0x7ec98b85L), tobe(0x738aad5cL), tobe(0x774bb0ebL),
+tobe(0x4f040d56L), tobe(0x4bc510e1L), tobe(0x46863638L), tobe(0x42472b8fL),
+tobe(0x5c007b8aL), tobe(0x58c1663dL), tobe(0x558240e4L), tobe(0x51435d53L),
+tobe(0x251d3b9eL), tobe(0x21dc2629L), tobe(0x2c9f00f0L), tobe(0x285e1d47L),
+tobe(0x36194d42L), tobe(0x32d850f5L), tobe(0x3f9b762cL), tobe(0x3b5a6b9bL),
+tobe(0x0315d626L), tobe(0x07d4cb91L), tobe(0x0a97ed48L), tobe(0x0e56f0ffL),
+tobe(0x1011a0faL), tobe(0x14d0bd4dL), tobe(0x19939b94L), tobe(0x1d528623L),
+tobe(0xf12f560eL), tobe(0xf5ee4bb9L), tobe(0xf8ad6d60L), tobe(0xfc6c70d7L),
+tobe(0xe22b20d2L), tobe(0xe6ea3d65L), tobe(0xeba91bbcL), tobe(0xef68060bL),
+tobe(0xd727bbb6L), tobe(0xd3e6a601L), tobe(0xdea580d8L), tobe(0xda649d6fL),
+tobe(0xc423cd6aL), tobe(0xc0e2d0ddL), tobe(0xcda1f604L), tobe(0xc960ebb3L),
+tobe(0xbd3e8d7eL), tobe(0xb9ff90c9L), tobe(0xb4bcb610L), tobe(0xb07daba7L),
+tobe(0xae3afba2L), tobe(0xaafbe615L), tobe(0xa7b8c0ccL), tobe(0xa379dd7bL),
+tobe(0x9b3660c6L), tobe(0x9ff77d71L), tobe(0x92b45ba8L), tobe(0x9675461fL),
+tobe(0x8832161aL), tobe(0x8cf30badL), tobe(0x81b02d74L), tobe(0x857130c3L),
+tobe(0x5d8a9099L), tobe(0x594b8d2eL), tobe(0x5408abf7L), tobe(0x50c9b640L),
+tobe(0x4e8ee645L), tobe(0x4a4ffbf2L), tobe(0x470cdd2bL), tobe(0x43cdc09cL),
+tobe(0x7b827d21L), tobe(0x7f436096L), tobe(0x7200464fL), tobe(0x76c15bf8L),
+tobe(0x68860bfdL), tobe(0x6c47164aL), tobe(0x61043093L), tobe(0x65c52d24L),
+tobe(0x119b4be9L), tobe(0x155a565eL), tobe(0x18197087L), tobe(0x1cd86d30L),
+tobe(0x029f3d35L), tobe(0x065e2082L), tobe(0x0b1d065bL), tobe(0x0fdc1becL),
+tobe(0x3793a651L), tobe(0x3352bbe6L), tobe(0x3e119d3fL), tobe(0x3ad08088L),
+tobe(0x2497d08dL), tobe(0x2056cd3aL), tobe(0x2d15ebe3L), tobe(0x29d4f654L),
+tobe(0xc5a92679L), tobe(0xc1683bceL), tobe(0xcc2b1d17L), tobe(0xc8ea00a0L),
+tobe(0xd6ad50a5L), tobe(0xd26c4d12L), tobe(0xdf2f6bcbL), tobe(0xdbee767cL),
+tobe(0xe3a1cbc1L), tobe(0xe760d676L), tobe(0xea23f0afL), tobe(0xeee2ed18L),
+tobe(0xf0a5bd1dL), tobe(0xf464a0aaL), tobe(0xf9278673L), tobe(0xfde69bc4L),
+tobe(0x89b8fd09L), tobe(0x8d79e0beL), tobe(0x803ac667L), tobe(0x84fbdbd0L),
+tobe(0x9abc8bd5L), tobe(0x9e7d9662L), tobe(0x933eb0bbL), tobe(0x97ffad0cL),
+tobe(0xafb010b1L), tobe(0xab710d06L), tobe(0xa6322bdfL), tobe(0xa2f33668L),
+tobe(0xbcb4666dL), tobe(0xb8757bdaL), tobe(0xb5365d03L), tobe(0xb1f740b4L)
+};
+#endif
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
new file mode 100644
index 0000000..492ab5c
--- /dev/null
+++ b/drivers/mtd/ubi/debug.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * Here we keep all the UBI debugging stuff which should normally be disabled
+ * and compiled-out, but it is extremely helpful when hunting bugs or doing big
+ * changes.
+ */
+#include <ubi_uboot.h>
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG
+
+#include "ubi.h"
+
+/**
+ * ubi_dbg_dump_ec_hdr - dump an erase counter header.
+ * @ec_hdr: the erase counter header to dump
+ */
+void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
+{
+ dbg_msg("erase counter header dump:");
+ dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic));
+ dbg_msg("version %d", (int)ec_hdr->version);
+ dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec));
+ dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset));
+ dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
+ dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
+ dbg_msg("erase counter header hexdump:");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ ec_hdr, UBI_EC_HDR_SIZE, 1);
+}
+
+/**
+ * ubi_dbg_dump_vid_hdr - dump a volume identifier header.
+ * @vid_hdr: the volume identifier header to dump
+ */
+void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
+{
+ dbg_msg("volume identifier header dump:");
+ dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic));
+ dbg_msg("version %d", (int)vid_hdr->version);
+ dbg_msg("vol_type %d", (int)vid_hdr->vol_type);
+ dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag);
+ dbg_msg("compat %d", (int)vid_hdr->compat);
+ dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id));
+ dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum));
+ dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver));
+ dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size));
+ dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs));
+ dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad));
+ dbg_msg("sqnum %llu",
+ (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+ dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc));
+ dbg_msg("volume identifier header hexdump:");
+}
+
+/**
+ * ubi_dbg_dump_vol_info- dump volume information.
+ * @vol: UBI volume description object
+ */
+void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
+{
+ dbg_msg("volume information dump:");
+ dbg_msg("vol_id %d", vol->vol_id);
+ dbg_msg("reserved_pebs %d", vol->reserved_pebs);
+ dbg_msg("alignment %d", vol->alignment);
+ dbg_msg("data_pad %d", vol->data_pad);
+ dbg_msg("vol_type %d", vol->vol_type);
+ dbg_msg("name_len %d", vol->name_len);
+ dbg_msg("usable_leb_size %d", vol->usable_leb_size);
+ dbg_msg("used_ebs %d", vol->used_ebs);
+ dbg_msg("used_bytes %lld", vol->used_bytes);
+ dbg_msg("last_eb_bytes %d", vol->last_eb_bytes);
+ dbg_msg("corrupted %d", vol->corrupted);
+ dbg_msg("upd_marker %d", vol->upd_marker);
+
+ if (vol->name_len <= UBI_VOL_NAME_MAX &&
+ strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
+ dbg_msg("name %s", vol->name);
+ } else {
+ dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
+ vol->name[0], vol->name[1], vol->name[2],
+ vol->name[3], vol->name[4]);
+ }
+}
+
+/**
+ * ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
+ * @r: the object to dump
+ * @idx: volume table index
+ */
+void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
+{
+ int name_len = be16_to_cpu(r->name_len);
+
+ dbg_msg("volume table record %d dump:", idx);
+ dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs));
+ dbg_msg("alignment %d", be32_to_cpu(r->alignment));
+ dbg_msg("data_pad %d", be32_to_cpu(r->data_pad));
+ dbg_msg("vol_type %d", (int)r->vol_type);
+ dbg_msg("upd_marker %d", (int)r->upd_marker);
+ dbg_msg("name_len %d", name_len);
+
+ if (r->name[0] == '\0') {
+ dbg_msg("name NULL");
+ return;
+ }
+
+ if (name_len <= UBI_VOL_NAME_MAX &&
+ strnlen(&r->name[0], name_len + 1) == name_len) {
+ dbg_msg("name %s", &r->name[0]);
+ } else {
+ dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
+ r->name[0], r->name[1], r->name[2], r->name[3],
+ r->name[4]);
+ }
+ dbg_msg("crc %#08x", be32_to_cpu(r->crc));
+}
+
+/**
+ * ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object.
+ * @sv: the object to dump
+ */
+void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
+{
+ dbg_msg("volume scanning information dump:");
+ dbg_msg("vol_id %d", sv->vol_id);
+ dbg_msg("highest_lnum %d", sv->highest_lnum);
+ dbg_msg("leb_count %d", sv->leb_count);
+ dbg_msg("compat %d", sv->compat);
+ dbg_msg("vol_type %d", sv->vol_type);
+ dbg_msg("used_ebs %d", sv->used_ebs);
+ dbg_msg("last_data_size %d", sv->last_data_size);
+ dbg_msg("data_pad %d", sv->data_pad);
+}
+
+/**
+ * ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object.
+ * @seb: the object to dump
+ * @type: object type: 0 - not corrupted, 1 - corrupted
+ */
+void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
+{
+ dbg_msg("eraseblock scanning information dump:");
+ dbg_msg("ec %d", seb->ec);
+ dbg_msg("pnum %d", seb->pnum);
+ if (type == 0) {
+ dbg_msg("lnum %d", seb->lnum);
+ dbg_msg("scrub %d", seb->scrub);
+ dbg_msg("sqnum %llu", seb->sqnum);
+ dbg_msg("leb_ver %u", seb->leb_ver);
+ }
+}
+
+/**
+ * ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
+ * @req: the object to dump
+ */
+void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
+{
+ char nm[17];
+
+ dbg_msg("volume creation request dump:");
+ dbg_msg("vol_id %d", req->vol_id);
+ dbg_msg("alignment %d", req->alignment);
+ dbg_msg("bytes %lld", (long long)req->bytes);
+ dbg_msg("vol_type %d", req->vol_type);
+ dbg_msg("name_len %d", req->name_len);
+
+ memcpy(nm, req->name, 16);
+ nm[16] = 0;
+ dbg_msg("the 1st 16 characters of the name: %s", nm);
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
new file mode 100644
index 0000000..b44380b
--- /dev/null
+++ b/drivers/mtd/ubi/debug.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+#ifndef __UBI_DEBUG_H__
+#define __UBI_DEBUG_H__
+
+#ifdef CONFIG_MTD_UBI_DEBUG
+#ifdef UBI_LINUX
+#include <linux/random.h>
+#endif
+
+#define ubi_assert(expr) BUG_ON(!(expr))
+#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
+#else
+#define ubi_assert(expr) ({})
+#define dbg_err(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
+#define DBG_DISABLE_BGT 1
+#else
+#define DBG_DISABLE_BGT 0
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG
+/* Generic debugging message */
+#define dbg_msg(fmt, ...) \
+ printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", \
+ __FUNCTION__, ##__VA_ARGS__)
+
+#define ubi_dbg_dump_stack() dump_stack()
+
+struct ubi_ec_hdr;
+struct ubi_vid_hdr;
+struct ubi_volume;
+struct ubi_vtbl_record;
+struct ubi_scan_volume;
+struct ubi_scan_leb;
+struct ubi_mkvol_req;
+
+void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
+void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
+void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
+void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
+void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
+void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
+void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
+
+#else
+
+#define dbg_msg(fmt, ...) ({})
+#define ubi_dbg_dump_stack() ({})
+#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
+#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
+#define ubi_dbg_dump_vol_info(vol) ({})
+#define ubi_dbg_dump_vtbl_record(r, idx) ({})
+#define ubi_dbg_dump_sv(sv) ({})
+#define ubi_dbg_dump_seb(seb, type) ({})
+#define ubi_dbg_dump_mkvol_req(req) ({})
+
+#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
+/* Messages from the eraseblock association unit */
+#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#else
+#define dbg_eba(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
+/* Messages from the wear-leveling unit */
+#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#else
+#define dbg_wl(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
+/* Messages from the input/output unit */
+#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#else
+#define dbg_io(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
+/* Initialization and build messages */
+#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#else
+#define dbg_bld(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
+/**
+ * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
+ *
+ * Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
+ */
+static inline int ubi_dbg_is_bitflip(void)
+{
+ return !(random32() % 200);
+}
+#else
+#define ubi_dbg_is_bitflip() 0
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
+/**
+ * ubi_dbg_is_write_failure - if it is time to emulate a write failure.
+ *
+ * Returns non-zero if a write failure should be emulated, otherwise returns
+ * zero.
+ */
+static inline int ubi_dbg_is_write_failure(void)
+{
+ return !(random32() % 500);
+}
+#else
+#define ubi_dbg_is_write_failure() 0
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
+/**
+ * ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
+ *
+ * Returns non-zero if an erase failure should be emulated, otherwise returns
+ * zero.
+ */
+static inline int ubi_dbg_is_erase_failure(void)
+{
+ return !(random32() % 400);
+}
+#else
+#define ubi_dbg_is_erase_failure() 0
+#endif
+
+#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
new file mode 100644
index 0000000..d523c94
--- /dev/null
+++ b/drivers/mtd/ubi/eba.c
@@ -0,0 +1,1256 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * The UBI Eraseblock Association (EBA) unit.
+ *
+ * This unit is responsible for I/O to/from logical eraseblock.
+ *
+ * Although in this implementation the EBA table is fully kept and managed in
+ * RAM, which assumes poor scalability, it might be (partially) maintained on
+ * flash in future implementations.
+ *
+ * The EBA unit implements per-logical eraseblock locking. Before accessing a
+ * logical eraseblock it is locked for reading or writing. The per-logical
+ * eraseblock locking is implemented by means of the lock tree. The lock tree
+ * is an RB-tree which refers all the currently locked logical eraseblocks. The
+ * lock tree elements are &struct ubi_ltree_entry objects. They are indexed by
+ * (@vol_id, @lnum) pairs.
+ *
+ * EBA also maintains the global sequence counter which is incremented each
+ * time a logical eraseblock is mapped to a physical eraseblock and it is
+ * stored in the volume identifier header. This means that each VID header has
+ * a unique sequence number. The sequence number is only increased an we assume
+ * 64 bits is enough to never overflow.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/err.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+/* Number of physical eraseblocks reserved for atomic LEB change operation */
+#define EBA_RESERVED_PEBS 1
+
+/**
+ * next_sqnum - get next sequence number.
+ * @ubi: UBI device description object
+ *
+ * This function returns next sequence number to use, which is just the current
+ * global sequence counter value. It also increases the global sequence
+ * counter.
+ */
+static unsigned long long next_sqnum(struct ubi_device *ubi)
+{
+ unsigned long long sqnum;
+
+ spin_lock(&ubi->ltree_lock);
+ sqnum = ubi->global_sqnum++;
+ spin_unlock(&ubi->ltree_lock);
+
+ return sqnum;
+}
+
+/**
+ * ubi_get_compat - get compatibility flags of a volume.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ *
+ * This function returns compatibility flags for an internal volume. User
+ * volumes have no compatibility flags, so %0 is returned.
+ */
+static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
+{
+ if (vol_id == UBI_LAYOUT_VOLUME_ID)
+ return UBI_LAYOUT_VOLUME_COMPAT;
+ return 0;
+}
+
+/**
+ * ltree_lookup - look up the lock tree.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function returns a pointer to the corresponding &struct ubi_ltree_entry
+ * object if the logical eraseblock is locked and %NULL if it is not.
+ * @ubi->ltree_lock has to be locked.
+ */
+static struct ubi_ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
+ int lnum)
+{
+ struct rb_node *p;
+
+ p = ubi->ltree.rb_node;
+ while (p) {
+ struct ubi_ltree_entry *le;
+
+ le = rb_entry(p, struct ubi_ltree_entry, rb);
+
+ if (vol_id < le->vol_id)
+ p = p->rb_left;
+ else if (vol_id > le->vol_id)
+ p = p->rb_right;
+ else {
+ if (lnum < le->lnum)
+ p = p->rb_left;
+ else if (lnum > le->lnum)
+ p = p->rb_right;
+ else
+ return le;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * ltree_add_entry - add new entry to the lock tree.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function adds new entry for logical eraseblock (@vol_id, @lnum) to the
+ * lock tree. If such entry is already there, its usage counter is increased.
+ * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation
+ * failed.
+ */
+static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
+ int vol_id, int lnum)
+{
+ struct ubi_ltree_entry *le, *le1, *le_free;
+
+ le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS);
+ if (!le)
+ return ERR_PTR(-ENOMEM);
+
+ le->users = 0;
+ init_rwsem(&le->mutex);
+ le->vol_id = vol_id;
+ le->lnum = lnum;
+
+ spin_lock(&ubi->ltree_lock);
+ le1 = ltree_lookup(ubi, vol_id, lnum);
+
+ if (le1) {
+ /*
+ * This logical eraseblock is already locked. The newly
+ * allocated lock entry is not needed.
+ */
+ le_free = le;
+ le = le1;
+ } else {
+ struct rb_node **p, *parent = NULL;
+
+ /*
+ * No lock entry, add the newly allocated one to the
+ * @ubi->ltree RB-tree.
+ */
+ le_free = NULL;
+
+ p = &ubi->ltree.rb_node;
+ while (*p) {
+ parent = *p;
+ le1 = rb_entry(parent, struct ubi_ltree_entry, rb);
+
+ if (vol_id < le1->vol_id)
+ p = &(*p)->rb_left;
+ else if (vol_id > le1->vol_id)
+ p = &(*p)->rb_right;
+ else {
+ ubi_assert(lnum != le1->lnum);
+ if (lnum < le1->lnum)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+ }
+
+ rb_link_node(&le->rb, parent, p);
+ rb_insert_color(&le->rb, &ubi->ltree);
+ }
+ le->users += 1;
+ spin_unlock(&ubi->ltree_lock);
+
+ if (le_free)
+ kfree(le_free);
+
+ return le;
+}
+
+/**
+ * leb_read_lock - lock logical eraseblock for reading.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function locks a logical eraseblock for reading. Returns zero in case
+ * of success and a negative error code in case of failure.
+ */
+static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+ struct ubi_ltree_entry *le;
+
+ le = ltree_add_entry(ubi, vol_id, lnum);
+ if (IS_ERR(le))
+ return PTR_ERR(le);
+ down_read(&le->mutex);
+ return 0;
+}
+
+/**
+ * leb_read_unlock - unlock logical eraseblock.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ */
+static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+ int _free = 0;
+ struct ubi_ltree_entry *le;
+
+ spin_lock(&ubi->ltree_lock);
+ le = ltree_lookup(ubi, vol_id, lnum);
+ le->users -= 1;
+ ubi_assert(le->users >= 0);
+ if (le->users == 0) {
+ rb_erase(&le->rb, &ubi->ltree);
+ _free = 1;
+ }
+ spin_unlock(&ubi->ltree_lock);
+
+ up_read(&le->mutex);
+ if (_free)
+ kfree(le);
+}
+
+/**
+ * leb_write_lock - lock logical eraseblock for writing.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function locks a logical eraseblock for writing. Returns zero in case
+ * of success and a negative error code in case of failure.
+ */
+static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+ struct ubi_ltree_entry *le;
+
+ le = ltree_add_entry(ubi, vol_id, lnum);
+ if (IS_ERR(le))
+ return PTR_ERR(le);
+ down_write(&le->mutex);
+ return 0;
+}
+
+/**
+ * leb_write_lock - lock logical eraseblock for writing.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function locks a logical eraseblock for writing if there is no
+ * contention and does nothing if there is contention. Returns %0 in case of
+ * success, %1 in case of contention, and and a negative error code in case of
+ * failure.
+ */
+static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+ int _free;
+ struct ubi_ltree_entry *le;
+
+ le = ltree_add_entry(ubi, vol_id, lnum);
+ if (IS_ERR(le))
+ return PTR_ERR(le);
+ if (down_write_trylock(&le->mutex))
+ return 0;
+
+ /* Contention, cancel */
+ spin_lock(&ubi->ltree_lock);
+ le->users -= 1;
+ ubi_assert(le->users >= 0);
+ if (le->users == 0) {
+ rb_erase(&le->rb, &ubi->ltree);
+ _free = 1;
+ } else
+ _free = 0;
+ spin_unlock(&ubi->ltree_lock);
+ if (_free)
+ kfree(le);
+
+ return 1;
+}
+
+/**
+ * leb_write_unlock - unlock logical eraseblock.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ */
+static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+ int _free;
+ struct ubi_ltree_entry *le;
+
+ spin_lock(&ubi->ltree_lock);
+ le = ltree_lookup(ubi, vol_id, lnum);
+ le->users -= 1;
+ ubi_assert(le->users >= 0);
+ if (le->users == 0) {
+ rb_erase(&le->rb, &ubi->ltree);
+ _free = 1;
+ } else
+ _free = 0;
+ spin_unlock(&ubi->ltree_lock);
+
+ up_write(&le->mutex);
+ if (_free)
+ kfree(le);
+}
+
+/**
+ * ubi_eba_unmap_leb - un-map logical eraseblock.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ *
+ * This function un-maps logical eraseblock @lnum and schedules corresponding
+ * physical eraseblock for erasure. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
+ int lnum)
+{
+ int err, pnum, vol_id = vol->vol_id;
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ err = leb_write_lock(ubi, vol_id, lnum);
+ if (err)
+ return err;
+
+ pnum = vol->eba_tbl[lnum];
+ if (pnum < 0)
+ /* This logical eraseblock is already unmapped */
+ goto out_unlock;
+
+ dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
+
+ vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
+ err = ubi_wl_put_peb(ubi, pnum, 0);
+
+out_unlock:
+ leb_write_unlock(ubi, vol_id, lnum);
+ return err;
+}
+
+/**
+ * ubi_eba_read_leb - read data.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @buf: buffer to store the read data
+ * @offset: offset from where to read
+ * @len: how many bytes to read
+ * @check: data CRC check flag
+ *
+ * If the logical eraseblock @lnum is unmapped, @buf is filled with 0xFF
+ * bytes. The @check flag only makes sense for static volumes and forces
+ * eraseblock data CRC checking.
+ *
+ * In case of success this function returns zero. In case of a static volume,
+ * if data CRC mismatches - %-EBADMSG is returned. %-EBADMSG may also be
+ * returned for any volume type if an ECC error was detected by the MTD device
+ * driver. Other negative error cored may be returned in case of other errors.
+ */
+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+ void *buf, int offset, int len, int check)
+{
+ int err, pnum, scrub = 0, vol_id = vol->vol_id;
+ struct ubi_vid_hdr *vid_hdr;
+ uint32_t uninitialized_var(crc);
+
+ err = leb_read_lock(ubi, vol_id, lnum);
+ if (err)
+ return err;
+
+ pnum = vol->eba_tbl[lnum];
+ if (pnum < 0) {
+ /*
+ * The logical eraseblock is not mapped, fill the whole buffer
+ * with 0xFF bytes. The exception is static volumes for which
+ * it is an error to read unmapped logical eraseblocks.
+ */
+ dbg_eba("read %d bytes from offset %d of LEB %d:%d (unmapped)",
+ len, offset, vol_id, lnum);
+ leb_read_unlock(ubi, vol_id, lnum);
+ ubi_assert(vol->vol_type != UBI_STATIC_VOLUME);
+ memset(buf, 0xFF, len);
+ return 0;
+ }
+
+ dbg_eba("read %d bytes from offset %d of LEB %d:%d, PEB %d",
+ len, offset, vol_id, lnum, pnum);
+
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ check = 0;
+
+retry:
+ if (check) {
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+ if (!vid_hdr) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+ if (err && err != UBI_IO_BITFLIPS) {
+ if (err > 0) {
+ /*
+ * The header is either absent or corrupted.
+ * The former case means there is a bug -
+ * switch to read-only mode just in case.
+ * The latter case means a real corruption - we
+ * may try to recover data. FIXME: but this is
+ * not implemented.
+ */
+ if (err == UBI_IO_BAD_VID_HDR) {
+ ubi_warn("bad VID header at PEB %d, LEB"
+ "%d:%d", pnum, vol_id, lnum);
+ err = -EBADMSG;
+ } else
+ ubi_ro_mode(ubi);
+ }
+ goto out_free;
+ } else if (err == UBI_IO_BITFLIPS)
+ scrub = 1;
+
+ ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
+ ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
+
+ crc = be32_to_cpu(vid_hdr->data_crc);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ }
+
+ err = ubi_io_read_data(ubi, buf, pnum, offset, len);
+ if (err) {
+ if (err == UBI_IO_BITFLIPS) {
+ scrub = 1;
+ err = 0;
+ } else if (err == -EBADMSG) {
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ goto out_unlock;
+ scrub = 1;
+ if (!check) {
+ ubi_msg("force data checking");
+ check = 1;
+ goto retry;
+ }
+ } else
+ goto out_unlock;
+ }
+
+ if (check) {
+ uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len);
+ if (crc1 != crc) {
+ ubi_warn("CRC error: calculated %#08x, must be %#08x",
+ crc1, crc);
+ err = -EBADMSG;
+ goto out_unlock;
+ }
+ }
+
+ if (scrub)
+ err = ubi_wl_scrub_peb(ubi, pnum);
+
+ leb_read_unlock(ubi, vol_id, lnum);
+ return err;
+
+out_free:
+ ubi_free_vid_hdr(ubi, vid_hdr);
+out_unlock:
+ leb_read_unlock(ubi, vol_id, lnum);
+ return err;
+}
+
+/**
+ * recover_peb - recover from write failure.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock to recover
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ * @buf: data which was not written because of the write failure
+ * @offset: offset of the failed write
+ * @len: how many bytes should have been written
+ *
+ * This function is called in case of a write failure and moves all good data
+ * from the potentially bad physical eraseblock to a good physical eraseblock.
+ * This function also writes the data which was not written due to the failure.
+ * Returns new physical eraseblock number in case of success, and a negative
+ * error code in case of failure.
+ */
+static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
+ const void *buf, int offset, int len)
+{
+ int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
+ struct ubi_volume *vol = ubi->volumes[idx];
+ struct ubi_vid_hdr *vid_hdr;
+
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+ if (!vid_hdr) {
+ return -ENOMEM;
+ }
+
+ mutex_lock(&ubi->buf_mutex);
+
+retry:
+ new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
+ if (new_pnum < 0) {
+ mutex_unlock(&ubi->buf_mutex);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return new_pnum;
+ }
+
+ ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum);
+
+ err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+ if (err && err != UBI_IO_BITFLIPS) {
+ if (err > 0)
+ err = -EIO;
+ goto out_put;
+ }
+
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
+ if (err)
+ goto write_error;
+
+ data_size = offset + len;
+ memset(ubi->peb_buf1 + offset, 0xFF, len);
+
+ /* Read everything before the area where the write failure happened */
+ if (offset > 0) {
+ err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
+ if (err && err != UBI_IO_BITFLIPS)
+ goto out_put;
+ }
+
+ memcpy(ubi->peb_buf1 + offset, buf, len);
+
+ err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
+ if (err)
+ goto write_error;
+
+ mutex_unlock(&ubi->buf_mutex);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+
+ vol->eba_tbl[lnum] = new_pnum;
+ ubi_wl_put_peb(ubi, pnum, 1);
+
+ ubi_msg("data was successfully recovered");
+ return 0;
+
+out_put:
+ mutex_unlock(&ubi->buf_mutex);
+ ubi_wl_put_peb(ubi, new_pnum, 1);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+
+write_error:
+ /*
+ * Bad luck? This physical eraseblock is bad too? Crud. Let's try to
+ * get another one.
+ */
+ ubi_warn("failed to write to PEB %d", new_pnum);
+ ubi_wl_put_peb(ubi, new_pnum, 1);
+ if (++tries > UBI_IO_RETRIES) {
+ mutex_unlock(&ubi->buf_mutex);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+ }
+ ubi_msg("try again");
+ goto retry;
+}
+
+/**
+ * ubi_eba_write_leb - write data to dynamic volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @buf: the data to write
+ * @offset: offset within the logical eraseblock where to write
+ * @len: how many bytes to write
+ * @dtype: data type
+ *
+ * This function writes data to logical eraseblock @lnum of a dynamic volume
+ * @vol. Returns zero in case of success and a negative error code in case
+ * of failure. In case of error, it is possible that something was still
+ * written to the flash media, but may be some garbage.
+ */
+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+ const void *buf, int offset, int len, int dtype)
+{
+ int err, pnum, tries = 0, vol_id = vol->vol_id;
+ struct ubi_vid_hdr *vid_hdr;
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ err = leb_write_lock(ubi, vol_id, lnum);
+ if (err)
+ return err;
+
+ pnum = vol->eba_tbl[lnum];
+ if (pnum >= 0) {
+ dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d",
+ len, offset, vol_id, lnum, pnum);
+
+ err = ubi_io_write_data(ubi, buf, pnum, offset, len);
+ if (err) {
+ ubi_warn("failed to write data to PEB %d", pnum);
+ if (err == -EIO && ubi->bad_allowed)
+ err = recover_peb(ubi, pnum, vol_id, lnum, buf,
+ offset, len);
+ if (err)
+ ubi_ro_mode(ubi);
+ }
+ leb_write_unlock(ubi, vol_id, lnum);
+ return err;
+ }
+
+ /*
+ * The logical eraseblock is not mapped. We have to get a free physical
+ * eraseblock and write the volume identifier header there first.
+ */
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+ if (!vid_hdr) {
+ leb_write_unlock(ubi, vol_id, lnum);
+ return -ENOMEM;
+ }
+
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
+ vid_hdr->compat = ubi_get_compat(ubi, vol_id);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
+
+retry:
+ pnum = ubi_wl_get_peb(ubi, dtype);
+ if (pnum < 0) {
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ leb_write_unlock(ubi, vol_id, lnum);
+ return pnum;
+ }
+
+ dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d",
+ len, offset, vol_id, lnum, pnum);
+
+ err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+ if (err) {
+ ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+ vol_id, lnum, pnum);
+ goto write_error;
+ }
+
+ if (len) {
+ err = ubi_io_write_data(ubi, buf, pnum, offset, len);
+ if (err) {
+ ubi_warn("failed to write %d bytes at offset %d of "
+ "LEB %d:%d, PEB %d", len, offset, vol_id,
+ lnum, pnum);
+ goto write_error;
+ }
+ }
+
+ vol->eba_tbl[lnum] = pnum;
+
+ leb_write_unlock(ubi, vol_id, lnum);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return 0;
+
+write_error:
+ if (err != -EIO || !ubi->bad_allowed) {
+ ubi_ro_mode(ubi);
+ leb_write_unlock(ubi, vol_id, lnum);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+ }
+
+ /*
+ * Fortunately, this is the first write operation to this physical
+ * eraseblock, so just put it and request a new one. We assume that if
+ * this physical eraseblock went bad, the erase code will handle that.
+ */
+ err = ubi_wl_put_peb(ubi, pnum, 1);
+ if (err || ++tries > UBI_IO_RETRIES) {
+ ubi_ro_mode(ubi);
+ leb_write_unlock(ubi, vol_id, lnum);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+ }
+
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ ubi_msg("try another PEB");
+ goto retry;
+}
+
+/**
+ * ubi_eba_write_leb_st - write data to static volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @buf: data to write
+ * @len: how many bytes to write
+ * @dtype: data type
+ * @used_ebs: how many logical eraseblocks will this volume contain
+ *
+ * This function writes data to logical eraseblock @lnum of static volume
+ * @vol. The @used_ebs argument should contain total number of logical
+ * eraseblock in this static volume.
+ *
+ * When writing to the last logical eraseblock, the @len argument doesn't have
+ * to be aligned to the minimal I/O unit size. Instead, it has to be equivalent
+ * to the real data size, although the @buf buffer has to contain the
+ * alignment. In all other cases, @len has to be aligned.
+ *
+ * It is prohibited to write more then once to logical eraseblocks of static
+ * volumes. This function returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
+ int lnum, const void *buf, int len, int dtype,
+ int used_ebs)
+{
+ int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
+ struct ubi_vid_hdr *vid_hdr;
+ uint32_t crc;
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ if (lnum == used_ebs - 1)
+ /* If this is the last LEB @len may be unaligned */
+ len = ALIGN(data_size, ubi->min_io_size);
+ else
+ ubi_assert(!(len & (ubi->min_io_size - 1)));
+
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+ if (!vid_hdr)
+ return -ENOMEM;
+
+ err = leb_write_lock(ubi, vol_id, lnum);
+ if (err) {
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+ }
+
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
+ vid_hdr->compat = ubi_get_compat(ubi, vol_id);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
+
+ crc = crc32(UBI_CRC32_INIT, buf, data_size);
+ vid_hdr->vol_type = UBI_VID_STATIC;
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->used_ebs = cpu_to_be32(used_ebs);
+ vid_hdr->data_crc = cpu_to_be32(crc);
+
+retry:
+ pnum = ubi_wl_get_peb(ubi, dtype);
+ if (pnum < 0) {
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ leb_write_unlock(ubi, vol_id, lnum);
+ return pnum;
+ }
+
+ dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d",
+ len, vol_id, lnum, pnum, used_ebs);
+
+ err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+ if (err) {
+ ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+ vol_id, lnum, pnum);
+ goto write_error;
+ }
+
+ err = ubi_io_write_data(ubi, buf, pnum, 0, len);
+ if (err) {
+ ubi_warn("failed to write %d bytes of data to PEB %d",
+ len, pnum);
+ goto write_error;
+ }
+
+ ubi_assert(vol->eba_tbl[lnum] < 0);
+ vol->eba_tbl[lnum] = pnum;
+
+ leb_write_unlock(ubi, vol_id, lnum);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return 0;
+
+write_error:
+ if (err != -EIO || !ubi->bad_allowed) {
+ /*
+ * This flash device does not admit of bad eraseblocks or
+ * something nasty and unexpected happened. Switch to read-only
+ * mode just in case.
+ */
+ ubi_ro_mode(ubi);
+ leb_write_unlock(ubi, vol_id, lnum);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+ }
+
+ err = ubi_wl_put_peb(ubi, pnum, 1);
+ if (err || ++tries > UBI_IO_RETRIES) {
+ ubi_ro_mode(ubi);
+ leb_write_unlock(ubi, vol_id, lnum);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+ }
+
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ ubi_msg("try another PEB");
+ goto retry;
+}
+
+/*
+ * ubi_eba_atomic_leb_change - change logical eraseblock atomically.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @buf: data to write
+ * @len: how many bytes to write
+ * @dtype: data type
+ *
+ * This function changes the contents of a logical eraseblock atomically. @buf
+ * has to contain new logical eraseblock data, and @len - the length of the
+ * data, which has to be aligned. This function guarantees that in case of an
+ * unclean reboot the old contents is preserved. Returns zero in case of
+ * success and a negative error code in case of failure.
+ *
+ * UBI reserves one LEB for the "atomic LEB change" operation, so only one
+ * LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
+ */
+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+ int lnum, const void *buf, int len, int dtype)
+{
+ int err, pnum, tries = 0, vol_id = vol->vol_id;
+ struct ubi_vid_hdr *vid_hdr;
+ uint32_t crc;
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ if (len == 0) {
+ /*
+ * Special case when data length is zero. In this case the LEB
+ * has to be unmapped and mapped somewhere else.
+ */
+ err = ubi_eba_unmap_leb(ubi, vol, lnum);
+ if (err)
+ return err;
+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+ }
+
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+ if (!vid_hdr)
+ return -ENOMEM;
+
+ mutex_lock(&ubi->alc_mutex);
+ err = leb_write_lock(ubi, vol_id, lnum);
+ if (err)
+ goto out_mutex;
+
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
+ vid_hdr->compat = ubi_get_compat(ubi, vol_id);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
+
+ crc = crc32(UBI_CRC32_INIT, buf, len);
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->data_size = cpu_to_be32(len);
+ vid_hdr->copy_flag = 1;
+ vid_hdr->data_crc = cpu_to_be32(crc);
+
+retry:
+ pnum = ubi_wl_get_peb(ubi, dtype);
+ if (pnum < 0) {
+ err = pnum;
+ goto out_leb_unlock;
+ }
+
+ dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
+ vol_id, lnum, vol->eba_tbl[lnum], pnum);
+
+ err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+ if (err) {
+ ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+ vol_id, lnum, pnum);
+ goto write_error;
+ }
+
+ err = ubi_io_write_data(ubi, buf, pnum, 0, len);
+ if (err) {
+ ubi_warn("failed to write %d bytes of data to PEB %d",
+ len, pnum);
+ goto write_error;
+ }
+
+ if (vol->eba_tbl[lnum] >= 0) {
+ err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+ if (err)
+ goto out_leb_unlock;
+ }
+
+ vol->eba_tbl[lnum] = pnum;
+
+out_leb_unlock:
+ leb_write_unlock(ubi, vol_id, lnum);
+out_mutex:
+ mutex_unlock(&ubi->alc_mutex);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+
+write_error:
+ if (err != -EIO || !ubi->bad_allowed) {
+ /*
+ * This flash device does not admit of bad eraseblocks or
+ * something nasty and unexpected happened. Switch to read-only
+ * mode just in case.
+ */
+ ubi_ro_mode(ubi);
+ goto out_leb_unlock;
+ }
+
+ err = ubi_wl_put_peb(ubi, pnum, 1);
+ if (err || ++tries > UBI_IO_RETRIES) {
+ ubi_ro_mode(ubi);
+ goto out_leb_unlock;
+ }
+
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ ubi_msg("try another PEB");
+ goto retry;
+}
+
+/**
+ * ubi_eba_copy_leb - copy logical eraseblock.
+ * @ubi: UBI device description object
+ * @from: physical eraseblock number from where to copy
+ * @to: physical eraseblock number where to copy
+ * @vid_hdr: VID header of the @from physical eraseblock
+ *
+ * This function copies logical eraseblock from physical eraseblock @from to
+ * physical eraseblock @to. The @vid_hdr buffer may be changed by this
+ * function. Returns:
+ * o %0 in case of success;
+ * o %1 if the operation was canceled and should be tried later (e.g.,
+ * because a bit-flip was detected at the target PEB);
+ * o %2 if the volume is being deleted and this LEB should not be moved.
+ */
+int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+ struct ubi_vid_hdr *vid_hdr)
+{
+ int err, vol_id, lnum, data_size, aldata_size, idx;
+ struct ubi_volume *vol;
+ uint32_t crc;
+
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
+
+ dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
+
+ if (vid_hdr->vol_type == UBI_VID_STATIC) {
+ data_size = be32_to_cpu(vid_hdr->data_size);
+ aldata_size = ALIGN(data_size, ubi->min_io_size);
+ } else
+ data_size = aldata_size =
+ ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
+
+ idx = vol_id2idx(ubi, vol_id);
+ spin_lock(&ubi->volumes_lock);
+ /*
+ * Note, we may race with volume deletion, which means that the volume
+ * this logical eraseblock belongs to might be being deleted. Since the
+ * volume deletion unmaps all the volume's logical eraseblocks, it will
+ * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish.
+ */
+ vol = ubi->volumes[idx];
+ if (!vol) {
+ /* No need to do further work, cancel */
+ dbg_eba("volume %d is being removed, cancel", vol_id);
+ spin_unlock(&ubi->volumes_lock);
+ return 2;
+ }
+ spin_unlock(&ubi->volumes_lock);
+
+ /*
+ * We do not want anybody to write to this logical eraseblock while we
+ * are moving it, so lock it.
+ *
+ * Note, we are using non-waiting locking here, because we cannot sleep
+ * on the LEB, since it may cause deadlocks. Indeed, imagine a task is
+ * unmapping the LEB which is mapped to the PEB we are going to move
+ * (@from). This task locks the LEB and goes sleep in the
+ * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
+ * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
+ * LEB is already locked, we just do not move it and return %1.
+ */
+ err = leb_write_trylock(ubi, vol_id, lnum);
+ if (err) {
+ dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum);
+ return err;
+ }
+
+ /*
+ * The LEB might have been put meanwhile, and the task which put it is
+ * probably waiting on @ubi->move_mutex. No need to continue the work,
+ * cancel it.
+ */
+ if (vol->eba_tbl[lnum] != from) {
+ dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to "
+ "PEB %d, cancel", vol_id, lnum, from,
+ vol->eba_tbl[lnum]);
+ err = 1;
+ goto out_unlock_leb;
+ }
+
+ /*
+ * OK, now the LEB is locked and we can safely start moving iy. Since
+ * this function utilizes thie @ubi->peb1_buf buffer which is shared
+ * with some other functions, so lock the buffer by taking the
+ * @ubi->buf_mutex.
+ */
+ mutex_lock(&ubi->buf_mutex);
+ dbg_eba("read %d bytes of data", aldata_size);
+ err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
+ if (err && err != UBI_IO_BITFLIPS) {
+ ubi_warn("error %d while reading data from PEB %d",
+ err, from);
+ goto out_unlock_buf;
+ }
+
+ /*
+ * Now we have got to calculate how much data we have to to copy. In
+ * case of a static volume it is fairly easy - the VID header contains
+ * the data size. In case of a dynamic volume it is more difficult - we
+ * have to read the contents, cut 0xFF bytes from the end and copy only
+ * the first part. We must do this to avoid writing 0xFF bytes as it
+ * may have some side-effects. And not only this. It is important not
+ * to include those 0xFFs to CRC because later the they may be filled
+ * by data.
+ */
+ if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
+ aldata_size = data_size =
+ ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
+
+ cond_resched();
+ crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
+ cond_resched();
+
+ /*
+ * It may turn out to me that the whole @from physical eraseblock
+ * contains only 0xFF bytes. Then we have to only write the VID header
+ * and do not write any data. This also means we should not set
+ * @vid_hdr->copy_flag, @vid_hdr->data_size, and @vid_hdr->data_crc.
+ */
+ if (data_size > 0) {
+ vid_hdr->copy_flag = 1;
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->data_crc = cpu_to_be32(crc);
+ }
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+
+ err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
+ if (err)
+ goto out_unlock_buf;
+
+ cond_resched();
+
+ /* Read the VID header back and check if it was written correctly */
+ err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1);
+ if (err) {
+ if (err != UBI_IO_BITFLIPS)
+ ubi_warn("cannot read VID header back from PEB %d", to);
+ else
+ err = 1;
+ goto out_unlock_buf;
+ }
+
+ if (data_size > 0) {
+ err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
+ if (err)
+ goto out_unlock_buf;
+
+ cond_resched();
+
+ /*
+ * We've written the data and are going to read it back to make
+ * sure it was written correctly.
+ */
+
+ err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
+ if (err) {
+ if (err != UBI_IO_BITFLIPS)
+ ubi_warn("cannot read data back from PEB %d",
+ to);
+ else
+ err = 1;
+ goto out_unlock_buf;
+ }
+
+ cond_resched();
+
+ if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
+ ubi_warn("read data back from PEB %d - it is different",
+ to);
+ goto out_unlock_buf;
+ }
+ }
+
+ ubi_assert(vol->eba_tbl[lnum] == from);
+ vol->eba_tbl[lnum] = to;
+
+out_unlock_buf:
+ mutex_unlock(&ubi->buf_mutex);
+out_unlock_leb:
+ leb_write_unlock(ubi, vol_id, lnum);
+ return err;
+}
+
+/**
+ * ubi_eba_init_scan - initialize the EBA unit using scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+ int i, j, err, num_volumes;
+ struct ubi_scan_volume *sv;
+ struct ubi_volume *vol;
+ struct ubi_scan_leb *seb;
+ struct rb_node *rb;
+
+ dbg_eba("initialize EBA unit");
+
+ spin_lock_init(&ubi->ltree_lock);
+ mutex_init(&ubi->alc_mutex);
+ ubi->ltree = RB_ROOT;
+
+ ubi->global_sqnum = si->max_sqnum + 1;
+ num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
+
+ for (i = 0; i < num_volumes; i++) {
+ vol = ubi->volumes[i];
+ if (!vol)
+ continue;
+
+ cond_resched();
+
+ vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int),
+ GFP_KERNEL);
+ if (!vol->eba_tbl) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ for (j = 0; j < vol->reserved_pebs; j++)
+ vol->eba_tbl[j] = UBI_LEB_UNMAPPED;
+
+ sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i));
+ if (!sv)
+ continue;
+
+ ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
+ if (seb->lnum >= vol->reserved_pebs)
+ /*
+ * This may happen in case of an unclean reboot
+ * during re-size.
+ */
+ ubi_scan_move_to_list(sv, seb, &si->erase);
+ vol->eba_tbl[seb->lnum] = seb->pnum;
+ }
+ }
+
+ if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
+ ubi_err("no enough physical eraseblocks (%d, need %d)",
+ ubi->avail_pebs, EBA_RESERVED_PEBS);
+ err = -ENOSPC;
+ goto out_free;
+ }
+ ubi->avail_pebs -= EBA_RESERVED_PEBS;
+ ubi->rsvd_pebs += EBA_RESERVED_PEBS;
+
+ if (ubi->bad_allowed) {
+ ubi_calculate_reserved(ubi);
+
+ if (ubi->avail_pebs < ubi->beb_rsvd_level) {
+ /* No enough free physical eraseblocks */
+ ubi->beb_rsvd_pebs = ubi->avail_pebs;
+ ubi_warn("cannot reserve enough PEBs for bad PEB "
+ "handling, reserved %d, need %d",
+ ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
+ } else
+ ubi->beb_rsvd_pebs = ubi->beb_rsvd_level;
+
+ ubi->avail_pebs -= ubi->beb_rsvd_pebs;
+ ubi->rsvd_pebs += ubi->beb_rsvd_pebs;
+ }
+
+ dbg_eba("EBA unit is initialized");
+ return 0;
+
+out_free:
+ for (i = 0; i < num_volumes; i++) {
+ if (!ubi->volumes[i])
+ continue;
+ kfree(ubi->volumes[i]->eba_tbl);
+ }
+ return err;
+}
+
+/**
+ * ubi_eba_close - close EBA unit.
+ * @ubi: UBI device description object
+ */
+void ubi_eba_close(const struct ubi_device *ubi)
+{
+ int i, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
+
+ dbg_eba("close EBA unit");
+
+ for (i = 0; i < num_volumes; i++) {
+ if (!ubi->volumes[i])
+ continue;
+ kfree(ubi->volumes[i]->eba_tbl);
+ }
+}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
new file mode 100644
index 0000000..8423894
--- /dev/null
+++ b/drivers/mtd/ubi/io.c
@@ -0,0 +1,1274 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2006, 2007
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * UBI input/output unit.
+ *
+ * This unit provides a uniform way to work with all kinds of the underlying
+ * MTD devices. It also implements handy functions for reading and writing UBI
+ * headers.
+ *
+ * We are trying to have a paranoid mindset and not to trust to what we read
+ * from the flash media in order to be more secure and robust. So this unit
+ * validates every single header it reads from the flash media.
+ *
+ * Some words about how the eraseblock headers are stored.
+ *
+ * The erase counter header is always stored at offset zero. By default, the
+ * VID header is stored after the EC header at the closest aligned offset
+ * (i.e. aligned to the minimum I/O unit size). Data starts next to the VID
+ * header at the closest aligned offset. But this default layout may be
+ * changed. For example, for different reasons (e.g., optimization) UBI may be
+ * asked to put the VID header at further offset, and even at an unaligned
+ * offset. Of course, if the offset of the VID header is unaligned, UBI adds
+ * proper padding in front of it. Data offset may also be changed but it has to
+ * be aligned.
+ *
+ * About minimal I/O units. In general, UBI assumes flash device model where
+ * there is only one minimal I/O unit size. E.g., in case of NOR flash it is 1,
+ * in case of NAND flash it is a NAND page, etc. This is reported by MTD in the
+ * @ubi->mtd->writesize field. But as an exception, UBI admits of using another
+ * (smaller) minimal I/O unit size for EC and VID headers to make it possible
+ * to do different optimizations.
+ *
+ * This is extremely useful in case of NAND flashes which admit of several
+ * write operations to one NAND page. In this case UBI can fit EC and VID
+ * headers at one NAND page. Thus, UBI may use "sub-page" size as the minimal
+ * I/O unit for the headers (the @ubi->hdrs_min_io_size field). But it still
+ * reports NAND page size (@ubi->min_io_size) as a minimal I/O unit for the UBI
+ * users.
+ *
+ * Example: some Samsung NANDs with 2KiB pages allow 4x 512-byte writes, so
+ * although the minimal I/O unit is 2K, UBI uses 512 bytes for EC and VID
+ * headers.
+ *
+ * Q: why not just to treat sub-page as a minimal I/O unit of this flash
+ * device, e.g., make @ubi->min_io_size = 512 in the example above?
+ *
+ * A: because when writing a sub-page, MTD still writes a full 2K page but the
+ * bytes which are no relevant to the sub-page are 0xFF. So, basically, writing
+ * 4x512 sub-pages is 4 times slower then writing one 2KiB NAND page. Thus, we
+ * prefer to use sub-pages only for EV and VID headers.
+ *
+ * As it was noted above, the VID header may start at a non-aligned offset.
+ * For example, in case of a 2KiB page NAND flash with a 512 bytes sub-page,
+ * the VID header may reside at offset 1984 which is the last 64 bytes of the
+ * last sub-page (EC header is always at offset zero). This causes some
+ * difficulties when reading and writing VID headers.
+ *
+ * Suppose we have a 64-byte buffer and we read a VID header at it. We change
+ * the data and want to write this VID header out. As we can only write in
+ * 512-byte chunks, we have to allocate one more buffer and copy our VID header
+ * to offset 448 of this buffer.
+ *
+ * The I/O unit does the following trick in order to avoid this extra copy.
+ * It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID header
+ * and returns a pointer to offset @ubi->vid_hdr_shift of this buffer. When the
+ * VID header is being written out, it shifts the VID header pointer back and
+ * writes the whole sub-page.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/crc32.h>
+#include <linux/err.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
+static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
+static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_ec_hdr *ec_hdr);
+static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
+static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_vid_hdr *vid_hdr);
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len);
+#else
+#define paranoid_check_not_bad(ubi, pnum) 0
+#define paranoid_check_peb_ec_hdr(ubi, pnum) 0
+#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0
+#define paranoid_check_peb_vid_hdr(ubi, pnum) 0
+#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
+#define paranoid_check_all_ff(ubi, pnum, offset, len) 0
+#endif
+
+/**
+ * ubi_io_read - read data from a physical eraseblock.
+ * @ubi: UBI device description object
+ * @buf: buffer where to store the read data
+ * @pnum: physical eraseblock number to read from
+ * @offset: offset within the physical eraseblock from where to read
+ * @len: how many bytes to read
+ *
+ * This function reads data from offset @offset of physical eraseblock @pnum
+ * and stores the read data in the @buf buffer. The following return codes are
+ * possible:
+ *
+ * o %0 if all the requested data were successfully read;
+ * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
+ * correctable bit-flips were detected; this is harmless but may indicate
+ * that this eraseblock may become bad soon (but do not have to);
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ * example it can be an ECC error in case of NAND; this most probably means
+ * that the data is corrupted;
+ * o %-EIO if some I/O error occurred;
+ * o other negative error codes in case of other errors.
+ */
+int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
+ int len)
+{
+ int err, retries = 0;
+ size_t read;
+ loff_t addr;
+
+ dbg_io("read %d bytes from PEB %d:%d", len, pnum, offset);
+
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+ ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
+ ubi_assert(len > 0);
+
+ err = paranoid_check_not_bad(ubi, pnum);
+ if (err)
+ return err > 0 ? -EINVAL : err;
+
+ addr = (loff_t)pnum * ubi->peb_size + offset;
+retry:
+ err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+ if (err) {
+ if (err == -EUCLEAN) {
+ /*
+ * -EUCLEAN is reported if there was a bit-flip which
+ * was corrected, so this is harmless.
+ */
+ ubi_msg("fixable bit-flip detected at PEB %d", pnum);
+ ubi_assert(len == read);
+ return UBI_IO_BITFLIPS;
+ }
+
+ if (read != len && retries++ < UBI_IO_RETRIES) {
+ dbg_io("error %d while reading %d bytes from PEB %d:%d, "
+ "read only %zd bytes, retry",
+ err, len, pnum, offset, read);
+ yield();
+ goto retry;
+ }
+
+ ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+ "read %zd bytes", err, len, pnum, offset, read);
+ ubi_dbg_dump_stack();
+
+ /*
+ * The driver should never return -EBADMSG if it failed to read
+ * all the requested data. But some buggy drivers might do
+ * this, so we change it to -EIO.
+ */
+ if (read != len && err == -EBADMSG) {
+ ubi_assert(0);
+ printk("%s[%d] not here\n", __func__, __LINE__);
+/* err = -EIO; */
+ }
+ } else {
+ ubi_assert(len == read);
+
+ if (ubi_dbg_is_bitflip()) {
+ dbg_msg("bit-flip (emulated)");
+ err = UBI_IO_BITFLIPS;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ubi_io_write - write data to a physical eraseblock.
+ * @ubi: UBI device description object
+ * @buf: buffer with the data to write
+ * @pnum: physical eraseblock number to write to
+ * @offset: offset within the physical eraseblock where to write
+ * @len: how many bytes to write
+ *
+ * This function writes @len bytes of data from buffer @buf to offset @offset
+ * of physical eraseblock @pnum. If all the data were successfully written,
+ * zero is returned. If an error occurred, this function returns a negative
+ * error code. If %-EIO is returned, the physical eraseblock most probably went
+ * bad.
+ *
+ * Note, in case of an error, it is possible that something was still written
+ * to the flash media, but may be some garbage.
+ */
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+ int len)
+{
+ int err;
+ size_t written;
+ loff_t addr;
+
+ dbg_io("write %d bytes to PEB %d:%d", len, pnum, offset);
+
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+ ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
+ ubi_assert(offset % ubi->hdrs_min_io_size == 0);
+ ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0);
+
+ if (ubi->ro_mode) {
+ ubi_err("read-only mode");
+ return -EROFS;
+ }
+
+ /* The below has to be compiled out if paranoid checks are disabled */
+
+ err = paranoid_check_not_bad(ubi, pnum);
+ if (err)
+ return err > 0 ? -EINVAL : err;
+
+ /* The area we are writing to has to contain all 0xFF bytes */
+ err = paranoid_check_all_ff(ubi, pnum, offset, len);
+ if (err)
+ return err > 0 ? -EINVAL : err;
+
+ if (offset >= ubi->leb_start) {
+ /*
+ * We write to the data area of the physical eraseblock. Make
+ * sure it has valid EC and VID headers.
+ */
+ err = paranoid_check_peb_ec_hdr(ubi, pnum);
+ if (err)
+ return err > 0 ? -EINVAL : err;
+ err = paranoid_check_peb_vid_hdr(ubi, pnum);
+ if (err)
+ return err > 0 ? -EINVAL : err;
+ }
+
+ if (ubi_dbg_is_write_failure()) {
+ dbg_err("cannot write %d bytes to PEB %d:%d "
+ "(emulated)", len, pnum, offset);
+ ubi_dbg_dump_stack();
+ return -EIO;
+ }
+
+ addr = (loff_t)pnum * ubi->peb_size + offset;
+ err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
+ if (err) {
+ ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
+ " %zd bytes", err, len, pnum, offset, written);
+ ubi_dbg_dump_stack();
+ } else
+ ubi_assert(written == len);
+
+ return err;
+}
+
+/**
+ * erase_callback - MTD erasure call-back.
+ * @ei: MTD erase information object.
+ *
+ * Note, even though MTD erase interface is asynchronous, all the current
+ * implementations are synchronous anyway.
+ */
+static void erase_callback(struct erase_info *ei)
+{
+ wake_up_interruptible((wait_queue_head_t *)ei->priv);
+}
+
+/**
+ * do_sync_erase - synchronously erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to erase
+ *
+ * This function synchronously erases physical eraseblock @pnum and returns
+ * zero in case of success and a negative error code in case of failure. If
+ * %-EIO is returned, the physical eraseblock most probably went bad.
+ */
+static int do_sync_erase(struct ubi_device *ubi, int pnum)
+{
+ int err, retries = 0;
+ struct erase_info ei;
+ wait_queue_head_t wq;
+
+ dbg_io("erase PEB %d", pnum);
+
+retry:
+ init_waitqueue_head(&wq);
+ memset(&ei, 0, sizeof(struct erase_info));
+
+ ei.mtd = ubi->mtd;
+ ei.addr = (loff_t)pnum * ubi->peb_size;
+ ei.len = ubi->peb_size;
+ ei.callback = erase_callback;
+ ei.priv = (unsigned long)&wq;
+
+ err = ubi->mtd->erase(ubi->mtd, &ei);
+ if (err) {
+ if (retries++ < UBI_IO_RETRIES) {
+ dbg_io("error %d while erasing PEB %d, retry",
+ err, pnum);
+ yield();
+ goto retry;
+ }
+ ubi_err("cannot erase PEB %d, error %d", pnum, err);
+ ubi_dbg_dump_stack();
+ return err;
+ }
+
+ err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE ||
+ ei.state == MTD_ERASE_FAILED);
+ if (err) {
+ ubi_err("interrupted PEB %d erasure", pnum);
+ return -EINTR;
+ }
+
+ if (ei.state == MTD_ERASE_FAILED) {
+ if (retries++ < UBI_IO_RETRIES) {
+ dbg_io("error while erasing PEB %d, retry", pnum);
+ yield();
+ goto retry;
+ }
+ ubi_err("cannot erase PEB %d", pnum);
+ ubi_dbg_dump_stack();
+ return -EIO;
+ }
+
+ err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size);
+ if (err)
+ return err > 0 ? -EINVAL : err;
+
+ if (ubi_dbg_is_erase_failure() && !err) {
+ dbg_err("cannot erase PEB %d (emulated)", pnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * check_pattern - check if buffer contains only a certain byte pattern.
+ * @buf: buffer to check
+ * @patt: the pattern to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %1 in there are only @patt bytes in @buf, and %0 if
+ * something else was also found.
+ */
+static int check_pattern(const void *buf, uint8_t patt, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (((const uint8_t *)buf)[i] != patt)
+ return 0;
+ return 1;
+}
+
+/* Patterns to write to a physical eraseblock when torturing it */
+static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+
+/**
+ * torture_peb - test a supposedly bad physical eraseblock.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to test
+ *
+ * This function returns %-EIO if the physical eraseblock did not pass the
+ * test, a positive number of erase operations done if the test was
+ * successfully passed, and other negative error codes in case of other errors.
+ */
+static int torture_peb(struct ubi_device *ubi, int pnum)
+{
+ int err, i, patt_count;
+
+ patt_count = ARRAY_SIZE(patterns);
+ ubi_assert(patt_count > 0);
+
+ mutex_lock(&ubi->buf_mutex);
+ for (i = 0; i < patt_count; i++) {
+ err = do_sync_erase(ubi, pnum);
+ if (err)
+ goto out;
+
+ /* Make sure the PEB contains only 0xFF bytes */
+ err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+ if (err)
+ goto out;
+
+ err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
+ if (err == 0) {
+ ubi_err("erased PEB %d, but a non-0xFF byte found",
+ pnum);
+ err = -EIO;
+ goto out;
+ }
+
+ /* Write a pattern and check it */
+ memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
+ err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+ if (err)
+ goto out;
+
+ memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
+ err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+ if (err)
+ goto out;
+
+ err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size);
+ if (err == 0) {
+ ubi_err("pattern %x checking failed for PEB %d",
+ patterns[i], pnum);
+ err = -EIO;
+ goto out;
+ }
+ }
+
+ err = patt_count;
+
+out:
+ mutex_unlock(&ubi->buf_mutex);
+ if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+ /*
+ * If a bit-flip or data integrity error was detected, the test
+ * has not passed because it happened on a freshly erased
+ * physical eraseblock which means something is wrong with it.
+ */
+ ubi_err("read problems on freshly erased PEB %d, must be bad",
+ pnum);
+ err = -EIO;
+ }
+ return err;
+}
+
+/**
+ * ubi_io_sync_erase - synchronously erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to erase
+ * @torture: if this physical eraseblock has to be tortured
+ *
+ * This function synchronously erases physical eraseblock @pnum. If @torture
+ * flag is not zero, the physical eraseblock is checked by means of writing
+ * different patterns to it and reading them back. If the torturing is enabled,
+ * the physical eraseblock is erased more then once.
+ *
+ * This function returns the number of erasures made in case of success, %-EIO
+ * if the erasure failed or the torturing test failed, and other negative error
+ * codes in case of other errors. Note, %-EIO means that the physical
+ * eraseblock is bad.
+ */
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
+{
+ int err, ret = 0;
+
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+ err = paranoid_check_not_bad(ubi, pnum);
+ if (err != 0)
+ return err > 0 ? -EINVAL : err;
+
+ if (ubi->ro_mode) {
+ ubi_err("read-only mode");
+ return -EROFS;
+ }
+
+ if (torture) {
+ ret = torture_peb(ubi, pnum);
+ if (ret < 0)
+ return ret;
+ }
+
+ err = do_sync_erase(ubi, pnum);
+ if (err)
+ return err;
+
+ return ret + 1;
+}
+
+/**
+ * ubi_io_is_bad - check if a physical eraseblock is bad.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ *
+ * This function returns a positive number if the physical eraseblock is bad,
+ * zero if not, and a negative error code if an error occurred.
+ */
+int ubi_io_is_bad(const struct ubi_device *ubi, int pnum)
+{
+ struct mtd_info *mtd = ubi->mtd;
+
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+ if (ubi->bad_allowed) {
+ int ret;
+
+ ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
+ if (ret < 0)
+ ubi_err("error %d while checking if PEB %d is bad",
+ ret, pnum);
+ else if (ret)
+ dbg_io("PEB %d is bad", pnum);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * ubi_io_mark_bad - mark a physical eraseblock as bad.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to mark
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)
+{
+ int err;
+ struct mtd_info *mtd = ubi->mtd;
+
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+ if (ubi->ro_mode) {
+ ubi_err("read-only mode");
+ return -EROFS;
+ }
+
+ if (!ubi->bad_allowed)
+ return 0;
+
+ err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
+ if (err)
+ ubi_err("cannot mark PEB %d bad, error %d", pnum, err);
+ return err;
+}
+
+/**
+ * validate_ec_hdr - validate an erase counter header.
+ * @ubi: UBI device description object
+ * @ec_hdr: the erase counter header to check
+ *
+ * This function returns zero if the erase counter header is OK, and %1 if
+ * not.
+ */
+static int validate_ec_hdr(const struct ubi_device *ubi,
+ const struct ubi_ec_hdr *ec_hdr)
+{
+ long long ec;
+ int vid_hdr_offset, leb_start;
+
+ ec = be64_to_cpu(ec_hdr->ec);
+ vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
+ leb_start = be32_to_cpu(ec_hdr->data_offset);
+
+ if (ec_hdr->version != UBI_VERSION) {
+ ubi_err("node with incompatible UBI version found: "
+ "this UBI version is %d, image version is %d",
+ UBI_VERSION, (int)ec_hdr->version);
+ goto bad;
+ }
+
+ if (vid_hdr_offset != ubi->vid_hdr_offset) {
+ ubi_err("bad VID header offset %d, expected %d",
+ vid_hdr_offset, ubi->vid_hdr_offset);
+ goto bad;
+ }
+
+ if (leb_start != ubi->leb_start) {
+ ubi_err("bad data offset %d, expected %d",
+ leb_start, ubi->leb_start);
+ goto bad;
+ }
+
+ if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) {
+ ubi_err("bad erase counter %lld", ec);
+ goto bad;
+ }
+
+ return 0;
+
+bad:
+ ubi_err("bad EC header");
+ ubi_dbg_dump_ec_hdr(ec_hdr);
+ ubi_dbg_dump_stack();
+ return 1;
+}
+
+/**
+ * ubi_io_read_ec_hdr - read and check an erase counter header.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to read from
+ * @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter
+ * header
+ * @verbose: be verbose if the header is corrupted or was not found
+ *
+ * This function reads erase counter header from physical eraseblock @pnum and
+ * stores it in @ec_hdr. This function also checks CRC checksum of the read
+ * erase counter header. The following codes may be returned:
+ *
+ * o %0 if the CRC checksum is correct and the header was successfully read;
+ * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
+ * and corrected by the flash driver; this is harmless but may indicate that
+ * this eraseblock may become bad soon (but may be not);
+ * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error);
+ * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
+ * o a negative error code in case of failure.
+ */
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_ec_hdr *ec_hdr, int verbose)
+{
+ int err, read_err = 0;
+ uint32_t crc, magic, hdr_crc;
+
+ dbg_io("read EC header from PEB %d", pnum);
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+ if (UBI_IO_DEBUG)
+ verbose = 1;
+
+ err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
+ if (err) {
+ if (err != UBI_IO_BITFLIPS && err != -EBADMSG)
+ return err;
+
+ /*
+ * We read all the data, but either a correctable bit-flip
+ * occurred, or MTD reported about some data integrity error,
+ * like an ECC error in case of NAND. The former is harmless,
+ * the later may mean that the read data is corrupted. But we
+ * have a CRC check-sum and we will detect this. If the EC
+ * header is still OK, we just report this as there was a
+ * bit-flip.
+ */
+ read_err = err;
+ }
+
+ magic = be32_to_cpu(ec_hdr->magic);
+ if (magic != UBI_EC_HDR_MAGIC) {
+ /*
+ * The magic field is wrong. Let's check if we have read all
+ * 0xFF. If yes, this physical eraseblock is assumed to be
+ * empty.
+ *
+ * But if there was a read error, we do not test it for all
+ * 0xFFs. Even if it does contain all 0xFFs, this error
+ * indicates that something is still wrong with this physical
+ * eraseblock and we anyway cannot treat it as empty.
+ */
+ if (read_err != -EBADMSG &&
+ check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
+ /* The physical eraseblock is supposedly empty */
+
+ /*
+ * The below is just a paranoid check, it has to be
+ * compiled out if paranoid checks are disabled.
+ */
+ err = paranoid_check_all_ff(ubi, pnum, 0,
+ ubi->peb_size);
+ if (err)
+ return err > 0 ? UBI_IO_BAD_EC_HDR : err;
+
+ if (verbose)
+ ubi_warn("no EC header found at PEB %d, "
+ "only 0xFF bytes", pnum);
+ return UBI_IO_PEB_EMPTY;
+ }
+
+ /*
+ * This is not a valid erase counter header, and these are not
+ * 0xFF bytes. Report that the header is corrupted.
+ */
+ if (verbose) {
+ ubi_warn("bad magic number at PEB %d: %08x instead of "
+ "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
+ ubi_dbg_dump_ec_hdr(ec_hdr);
+ }
+ return UBI_IO_BAD_EC_HDR;
+ }
+
+ crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
+
+ if (hdr_crc != crc) {
+ if (verbose) {
+ ubi_warn("bad EC header CRC at PEB %d, calculated %#08x,"
+ " read %#08x", pnum, crc, hdr_crc);
+ ubi_dbg_dump_ec_hdr(ec_hdr);
+ }
+ return UBI_IO_BAD_EC_HDR;
+ }
+
+ /* And of course validate what has just been read from the media */
+ err = validate_ec_hdr(ubi, ec_hdr);
+ if (err) {
+ ubi_err("validation failed for PEB %d", pnum);
+ return -EINVAL;
+ }
+
+ return read_err ? UBI_IO_BITFLIPS : 0;
+}
+
+/**
+ * ubi_io_write_ec_hdr - write an erase counter header.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to write to
+ * @ec_hdr: the erase counter header to write
+ *
+ * This function writes erase counter header described by @ec_hdr to physical
+ * eraseblock @pnum. It also fills most fields of @ec_hdr before writing, so
+ * the caller do not have to fill them. Callers must only fill the @ec_hdr->ec
+ * field.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure. If %-EIO is returned, the physical eraseblock most probably
+ * went bad.
+ */
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_ec_hdr *ec_hdr)
+{
+ int err;
+ uint32_t crc;
+
+ dbg_io("write EC header to PEB %d", pnum);
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+ ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+ ec_hdr->version = UBI_VERSION;
+ ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
+ ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
+ crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
+ ec_hdr->hdr_crc = cpu_to_be32(crc);
+
+ err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+ if (err)
+ return -EINVAL;
+
+ err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
+ return err;
+}
+
+/**
+ * validate_vid_hdr - validate a volume identifier header.
+ * @ubi: UBI device description object
+ * @vid_hdr: the volume identifier header to check
+ *
+ * This function checks that data stored in the volume identifier header
+ * @vid_hdr. Returns zero if the VID header is OK and %1 if not.
+ */
+static int validate_vid_hdr(const struct ubi_device *ubi,
+ const struct ubi_vid_hdr *vid_hdr)
+{
+ int vol_type = vid_hdr->vol_type;
+ int copy_flag = vid_hdr->copy_flag;
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int lnum = be32_to_cpu(vid_hdr->lnum);
+ int compat = vid_hdr->compat;
+ int data_size = be32_to_cpu(vid_hdr->data_size);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
+ int data_crc = be32_to_cpu(vid_hdr->data_crc);
+ int usable_leb_size = ubi->leb_size - data_pad;
+
+ if (copy_flag != 0 && copy_flag != 1) {
+ dbg_err("bad copy_flag");
+ goto bad;
+ }
+
+ if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 ||
+ data_pad < 0) {
+ dbg_err("negative values");
+ goto bad;
+ }
+
+ if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) {
+ dbg_err("bad vol_id");
+ goto bad;
+ }
+
+ if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) {
+ dbg_err("bad compat");
+ goto bad;
+ }
+
+ if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE &&
+ compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE &&
+ compat != UBI_COMPAT_REJECT) {
+ dbg_err("bad compat");
+ goto bad;
+ }
+
+ if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
+ dbg_err("bad vol_type");
+ goto bad;
+ }
+
+ if (data_pad >= ubi->leb_size / 2) {
+ dbg_err("bad data_pad");
+ goto bad;
+ }
+
+ if (vol_type == UBI_VID_STATIC) {
+ /*
+ * Although from high-level point of view static volumes may
+ * contain zero bytes of data, but no VID headers can contain
+ * zero at these fields, because they empty volumes do not have
+ * mapped logical eraseblocks.
+ */
+ if (used_ebs == 0) {
+ dbg_err("zero used_ebs");
+ goto bad;
+ }
+ if (data_size == 0) {
+ dbg_err("zero data_size");
+ goto bad;
+ }
+ if (lnum < used_ebs - 1) {
+ if (data_size != usable_leb_size) {
+ dbg_err("bad data_size");
+ goto bad;
+ }
+ } else if (lnum == used_ebs - 1) {
+ if (data_size == 0) {
+ dbg_err("bad data_size at last LEB");
+ goto bad;
+ }
+ } else {
+ dbg_err("too high lnum");
+ goto bad;
+ }
+ } else {
+ if (copy_flag == 0) {
+ if (data_crc != 0) {
+ dbg_err("non-zero data CRC");
+ goto bad;
+ }
+ if (data_size != 0) {
+ dbg_err("non-zero data_size");
+ goto bad;
+ }
+ } else {
+ if (data_size == 0) {
+ dbg_err("zero data_size of copy");
+ goto bad;
+ }
+ }
+ if (used_ebs != 0) {
+ dbg_err("bad used_ebs");
+ goto bad;
+ }
+ }
+
+ return 0;
+
+bad:
+ ubi_err("bad VID header");
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dbg_dump_stack();
+ return 1;
+}
+
+/**
+ * ubi_io_read_vid_hdr - read and check a volume identifier header.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to read from
+ * @vid_hdr: &struct ubi_vid_hdr object where to store the read volume
+ * identifier header
+ * @verbose: be verbose if the header is corrupted or wasn't found
+ *
+ * This function reads the volume identifier header from physical eraseblock
+ * @pnum and stores it in @vid_hdr. It also checks CRC checksum of the read
+ * volume identifier header. The following codes may be returned:
+ *
+ * o %0 if the CRC checksum is correct and the header was successfully read;
+ * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
+ * and corrected by the flash driver; this is harmless but may indicate that
+ * this eraseblock may become bad soon;
+ * o %UBI_IO_BAD_VID_HRD if the volume identifier header is corrupted (a CRC
+ * error detected);
+ * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID
+ * header there);
+ * o a negative error code in case of failure.
+ */
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_vid_hdr *vid_hdr, int verbose)
+{
+ int err, read_err = 0;
+ uint32_t crc, magic, hdr_crc;
+ void *p;
+
+ dbg_io("read VID header from PEB %d", pnum);
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+ if (UBI_IO_DEBUG)
+ verbose = 1;
+
+ p = (char *)vid_hdr - ubi->vid_hdr_shift;
+ err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+ ubi->vid_hdr_alsize);
+ if (err) {
+ if (err != UBI_IO_BITFLIPS && err != -EBADMSG)
+ return err;
+
+ /*
+ * We read all the data, but either a correctable bit-flip
+ * occurred, or MTD reported about some data integrity error,
+ * like an ECC error in case of NAND. The former is harmless,
+ * the later may mean the read data is corrupted. But we have a
+ * CRC check-sum and we will identify this. If the VID header is
+ * still OK, we just report this as there was a bit-flip.
+ */
+ read_err = err;
+ }
+
+ magic = be32_to_cpu(vid_hdr->magic);
+ if (magic != UBI_VID_HDR_MAGIC) {
+ /*
+ * If we have read all 0xFF bytes, the VID header probably does
+ * not exist and the physical eraseblock is assumed to be free.
+ *
+ * But if there was a read error, we do not test the data for
+ * 0xFFs. Even if it does contain all 0xFFs, this error
+ * indicates that something is still wrong with this physical
+ * eraseblock and it cannot be regarded as free.
+ */
+ if (read_err != -EBADMSG &&
+ check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+ /* The physical eraseblock is supposedly free */
+
+ /*
+ * The below is just a paranoid check, it has to be
+ * compiled out if paranoid checks are disabled.
+ */
+ err = paranoid_check_all_ff(ubi, pnum, ubi->leb_start,
+ ubi->leb_size);
+ if (err)
+ return err > 0 ? UBI_IO_BAD_VID_HDR : err;
+
+ if (verbose)
+ ubi_warn("no VID header found at PEB %d, "
+ "only 0xFF bytes", pnum);
+ return UBI_IO_PEB_FREE;
+ }
+
+ /*
+ * This is not a valid VID header, and these are not 0xFF
+ * bytes. Report that the header is corrupted.
+ */
+ if (verbose) {
+ ubi_warn("bad magic number at PEB %d: %08x instead of "
+ "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ }
+ return UBI_IO_BAD_VID_HDR;
+ }
+
+ crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
+
+ if (hdr_crc != crc) {
+ if (verbose) {
+ ubi_warn("bad CRC at PEB %d, calculated %#08x, "
+ "read %#08x", pnum, crc, hdr_crc);
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ }
+ return UBI_IO_BAD_VID_HDR;
+ }
+
+ /* Validate the VID header that we have just read */
+ err = validate_vid_hdr(ubi, vid_hdr);
+ if (err) {
+ ubi_err("validation failed for PEB %d", pnum);
+ return -EINVAL;
+ }
+
+ return read_err ? UBI_IO_BITFLIPS : 0;
+}
+
+/**
+ * ubi_io_write_vid_hdr - write a volume identifier header.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to write to
+ * @vid_hdr: the volume identifier header to write
+ *
+ * This function writes the volume identifier header described by @vid_hdr to
+ * physical eraseblock @pnum. This function automatically fills the
+ * @vid_hdr->magic and the @vid_hdr->version fields, as well as calculates
+ * header CRC checksum and stores it at vid_hdr->hdr_crc.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure. If %-EIO is returned, the physical eraseblock probably went
+ * bad.
+ */
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_vid_hdr *vid_hdr)
+{
+ int err;
+ uint32_t crc;
+ void *p;
+
+ dbg_io("write VID header to PEB %d", pnum);
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+ err = paranoid_check_peb_ec_hdr(ubi, pnum);
+ if (err)
+ return err > 0 ? -EINVAL: err;
+
+ vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+ vid_hdr->version = UBI_VERSION;
+ crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
+ vid_hdr->hdr_crc = cpu_to_be32(crc);
+
+ err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+ if (err)
+ return -EINVAL;
+
+ p = (char *)vid_hdr - ubi->vid_hdr_shift;
+ err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
+ ubi->vid_hdr_alsize);
+ return err;
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to check
+ *
+ * This function returns zero if the physical eraseblock is good, a positive
+ * number if it is bad and a negative error code if an error occurred.
+ */
+static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
+{
+ int err;
+
+ err = ubi_io_is_bad(ubi, pnum);
+ if (!err)
+ return err;
+
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_dbg_dump_stack();
+ return err;
+}
+
+/**
+ * paranoid_check_ec_hdr - check if an erase counter header is all right.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number the erase counter header belongs to
+ * @ec_hdr: the erase counter header to check
+ *
+ * This function returns zero if the erase counter header contains valid
+ * values, and %1 if not.
+ */
+static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_ec_hdr *ec_hdr)
+{
+ int err;
+ uint32_t magic;
+
+ magic = be32_to_cpu(ec_hdr->magic);
+ if (magic != UBI_EC_HDR_MAGIC) {
+ ubi_err("bad magic %#08x, must be %#08x",
+ magic, UBI_EC_HDR_MAGIC);
+ goto fail;
+ }
+
+ err = validate_ec_hdr(ubi, ec_hdr);
+ if (err) {
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ ubi_dbg_dump_ec_hdr(ec_hdr);
+ ubi_dbg_dump_stack();
+ return 1;
+}
+
+/**
+ * paranoid_check_peb_ec_hdr - check that the erase counter header of a
+ * physical eraseblock is in-place and is all right.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ *
+ * This function returns zero if the erase counter header is all right, %1 if
+ * not, and a negative error code if an error occurred.
+ */
+static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
+{
+ int err;
+ uint32_t crc, hdr_crc;
+ struct ubi_ec_hdr *ec_hdr;
+
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
+ if (!ec_hdr)
+ return -ENOMEM;
+
+ err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
+ if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+ goto exit;
+
+ crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
+ if (hdr_crc != crc) {
+ ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_dbg_dump_ec_hdr(ec_hdr);
+ ubi_dbg_dump_stack();
+ err = 1;
+ goto exit;
+ }
+
+ err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+
+exit:
+ kfree(ec_hdr);
+ return err;
+}
+
+/**
+ * paranoid_check_vid_hdr - check that a volume identifier header is all right.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number the volume identifier header belongs to
+ * @vid_hdr: the volume identifier header to check
+ *
+ * This function returns zero if the volume identifier header is all right, and
+ * %1 if not.
+ */
+static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_vid_hdr *vid_hdr)
+{
+ int err;
+ uint32_t magic;
+
+ magic = be32_to_cpu(vid_hdr->magic);
+ if (magic != UBI_VID_HDR_MAGIC) {
+ ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
+ magic, pnum, UBI_VID_HDR_MAGIC);
+ goto fail;
+ }
+
+ err = validate_vid_hdr(ubi, vid_hdr);
+ if (err) {
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ goto fail;
+ }
+
+ return err;
+
+fail:
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dbg_dump_stack();
+ return 1;
+
+}
+
+/**
+ * paranoid_check_peb_vid_hdr - check that the volume identifier header of a
+ * physical eraseblock is in-place and is all right.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ *
+ * This function returns zero if the volume identifier header is all right,
+ * %1 if not, and a negative error code if an error occurred.
+ */
+static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
+{
+ int err;
+ uint32_t crc, hdr_crc;
+ struct ubi_vid_hdr *vid_hdr;
+ void *p;
+
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+ if (!vid_hdr)
+ return -ENOMEM;
+
+ p = (char *)vid_hdr - ubi->vid_hdr_shift;
+ err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+ ubi->vid_hdr_alsize);
+ if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+ goto exit;
+
+ crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
+ if (hdr_crc != crc) {
+ ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
+ "read %#08x", pnum, crc, hdr_crc);
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dbg_dump_stack();
+ err = 1;
+ goto exit;
+ }
+
+ err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+
+exit:
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+}
+
+/**
+ * paranoid_check_all_ff - check that a region of flash is empty.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ * @offset: the starting offset within the physical eraseblock to check
+ * @len: the length of the region to check
+ *
+ * This function returns zero if only 0xFF bytes are present at offset
+ * @offset of the physical eraseblock @pnum, %1 if not, and a negative error
+ * code if an error occurred.
+ */
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len)
+{
+ size_t read;
+ int err;
+ loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+
+ mutex_lock(&ubi->dbg_buf_mutex);
+ err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
+ if (err && err != -EUCLEAN) {
+ ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+ "read %zd bytes", err, len, pnum, offset, read);
+ goto error;
+ }
+
+ err = check_pattern(ubi->dbg_peb_buf, 0xFF, len);
+ if (err == 0) {
+ ubi_err("flash region at PEB %d:%d, length %d does not "
+ "contain all 0xFF bytes", pnum, offset, len);
+ goto fail;
+ }
+ mutex_unlock(&ubi->dbg_buf_mutex);
+
+ return 0;
+
+fail:
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ dbg_msg("hex dump of the %d-%d region", offset, offset + len);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ ubi->dbg_peb_buf, len, 1);
+ err = 1;
+error:
+ ubi_dbg_dump_stack();
+ mutex_unlock(&ubi->dbg_buf_mutex);
+ return err;
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
new file mode 100644
index 0000000..423d479
--- /dev/null
+++ b/drivers/mtd/ubi/kapi.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/* This file mostly implements UBI kernel API functions */
+
+#ifdef UBI_LINUX
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/div64.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+/**
+ * ubi_get_device_info - get information about UBI device.
+ * @ubi_num: UBI device number
+ * @di: the information is stored here
+ *
+ * This function returns %0 in case of success, %-EINVAL if the UBI device
+ * number is invalid, and %-ENODEV if there is no such UBI device.
+ */
+int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
+{
+ struct ubi_device *ubi;
+
+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+ return -EINVAL;
+
+ ubi = ubi_get_device(ubi_num);
+ if (!ubi)
+ return -ENODEV;
+
+ di->ubi_num = ubi->ubi_num;
+ di->leb_size = ubi->leb_size;
+ di->min_io_size = ubi->min_io_size;
+ di->ro_mode = ubi->ro_mode;
+ di->cdev = ubi->cdev.dev;
+
+ ubi_put_device(ubi);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ubi_get_device_info);
+
+/**
+ * ubi_get_volume_info - get information about UBI volume.
+ * @desc: volume descriptor
+ * @vi: the information is stored here
+ */
+void ubi_get_volume_info(struct ubi_volume_desc *desc,
+ struct ubi_volume_info *vi)
+{
+ const struct ubi_volume *vol = desc->vol;
+ const struct ubi_device *ubi = vol->ubi;
+
+ vi->vol_id = vol->vol_id;
+ vi->ubi_num = ubi->ubi_num;
+ vi->size = vol->reserved_pebs;
+ vi->used_bytes = vol->used_bytes;
+ vi->vol_type = vol->vol_type;
+ vi->corrupted = vol->corrupted;
+ vi->upd_marker = vol->upd_marker;
+ vi->alignment = vol->alignment;
+ vi->usable_leb_size = vol->usable_leb_size;
+ vi->name_len = vol->name_len;
+ vi->name = vol->name;
+ vi->cdev = vol->cdev.dev;
+}
+EXPORT_SYMBOL_GPL(ubi_get_volume_info);
+
+/**
+ * ubi_open_volume - open UBI volume.
+ * @ubi_num: UBI device number
+ * @vol_id: volume ID
+ * @mode: open mode
+ *
+ * The @mode parameter specifies if the volume should be opened in read-only
+ * mode, read-write mode, or exclusive mode. The exclusive mode guarantees that
+ * nobody else will be able to open this volume. UBI allows to have many volume
+ * readers and one writer at a time.
+ *
+ * If a static volume is being opened for the first time since boot, it will be
+ * checked by this function, which means it will be fully read and the CRC
+ * checksum of each logical eraseblock will be checked.
+ *
+ * This function returns volume descriptor in case of success and a negative
+ * error code in case of failure.
+ */
+struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
+{
+ int err;
+ struct ubi_volume_desc *desc;
+ struct ubi_device *ubi;
+ struct ubi_volume *vol;
+
+ dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
+
+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+ return ERR_PTR(-EINVAL);
+
+ if (mode != UBI_READONLY && mode != UBI_READWRITE &&
+ mode != UBI_EXCLUSIVE)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * First of all, we have to get the UBI device to prevent its removal.
+ */
+ ubi = ubi_get_device(ubi_num);
+ if (!ubi)
+ return ERR_PTR(-ENODEV);
+
+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
+ err = -EINVAL;
+ goto out_put_ubi;
+ }
+
+ desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
+ if (!desc) {
+ err = -ENOMEM;
+ goto out_put_ubi;
+ }
+
+ err = -ENODEV;
+ if (!try_module_get(THIS_MODULE))
+ goto out_free;
+
+ spin_lock(&ubi->volumes_lock);
+ vol = ubi->volumes[vol_id];
+ if (!vol)
+ goto out_unlock;
+
+ err = -EBUSY;
+ switch (mode) {
+ case UBI_READONLY:
+ if (vol->exclusive)
+ goto out_unlock;
+ vol->readers += 1;
+ break;
+
+ case UBI_READWRITE:
+ if (vol->exclusive || vol->writers > 0)
+ goto out_unlock;
+ vol->writers += 1;
+ break;
+
+ case UBI_EXCLUSIVE:
+ if (vol->exclusive || vol->writers || vol->readers)
+ goto out_unlock;
+ vol->exclusive = 1;
+ break;
+ }
+ get_device(&vol->dev);
+ vol->ref_count += 1;
+ spin_unlock(&ubi->volumes_lock);
+
+ desc->vol = vol;
+ desc->mode = mode;
+
+ mutex_lock(&ubi->ckvol_mutex);
+ if (!vol->checked) {
+ /* This is the first open - check the volume */
+ err = ubi_check_volume(ubi, vol_id);
+ if (err < 0) {
+ mutex_unlock(&ubi->ckvol_mutex);
+ ubi_close_volume(desc);
+ return ERR_PTR(err);
+ }
+ if (err == 1) {
+ ubi_warn("volume %d on UBI device %d is corrupted",
+ vol_id, ubi->ubi_num);
+ vol->corrupted = 1;
+ }
+ vol->checked = 1;
+ }
+ mutex_unlock(&ubi->ckvol_mutex);
+
+ return desc;
+
+out_unlock:
+ spin_unlock(&ubi->volumes_lock);
+ module_put(THIS_MODULE);
+out_free:
+ kfree(desc);
+out_put_ubi:
+ ubi_put_device(ubi);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(ubi_open_volume);
+
+/**
+ * ubi_open_volume_nm - open UBI volume by name.
+ * @ubi_num: UBI device number
+ * @name: volume name
+ * @mode: open mode
+ *
+ * This function is similar to 'ubi_open_volume()', but opens a volume by name.
+ */
+struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
+ int mode)
+{
+ int i, vol_id = -1, len;
+ struct ubi_device *ubi;
+ struct ubi_volume_desc *ret;
+
+ dbg_msg("open volume %s, mode %d", name, mode);
+
+ if (!name)
+ return ERR_PTR(-EINVAL);
+
+ len = strnlen(name, UBI_VOL_NAME_MAX + 1);
+ if (len > UBI_VOL_NAME_MAX)
+ return ERR_PTR(-EINVAL);
+
+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+ return ERR_PTR(-EINVAL);
+
+ ubi = ubi_get_device(ubi_num);
+ if (!ubi)
+ return ERR_PTR(-ENODEV);
+
+ spin_lock(&ubi->volumes_lock);
+ /* Walk all volumes of this UBI device */
+ for (i = 0; i < ubi->vtbl_slots; i++) {
+ struct ubi_volume *vol = ubi->volumes[i];
+
+ if (vol && len == vol->name_len && !strcmp(name, vol->name)) {
+ vol_id = i;
+ break;
+ }
+ }
+ spin_unlock(&ubi->volumes_lock);
+
+ if (vol_id >= 0)
+ ret = ubi_open_volume(ubi_num, vol_id, mode);
+ else
+ ret = ERR_PTR(-ENODEV);
+
+ /*
+ * We should put the UBI device even in case of success, because
+ * 'ubi_open_volume()' took a reference as well.
+ */
+ ubi_put_device(ubi);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
+
+/**
+ * ubi_close_volume - close UBI volume.
+ * @desc: volume descriptor
+ */
+void ubi_close_volume(struct ubi_volume_desc *desc)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+
+ dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
+
+ spin_lock(&ubi->volumes_lock);
+ switch (desc->mode) {
+ case UBI_READONLY:
+ vol->readers -= 1;
+ break;
+ case UBI_READWRITE:
+ vol->writers -= 1;
+ break;
+ case UBI_EXCLUSIVE:
+ vol->exclusive = 0;
+ }
+ vol->ref_count -= 1;
+ spin_unlock(&ubi->volumes_lock);
+
+ kfree(desc);
+ put_device(&vol->dev);
+ ubi_put_device(ubi);
+ module_put(THIS_MODULE);
+}
+EXPORT_SYMBOL_GPL(ubi_close_volume);
+
+/**
+ * ubi_leb_read - read data.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @buf: buffer where to store the read data
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ * @check: whether UBI has to check the read data's CRC or not.
+ *
+ * This function reads data from offset @offset of logical eraseblock @lnum and
+ * stores the data at @buf. When reading from static volumes, @check specifies
+ * whether the data has to be checked or not. If yes, the whole logical
+ * eraseblock will be read and its CRC checksum will be checked (i.e., the CRC
+ * checksum is per-eraseblock). So checking may substantially slow down the
+ * read speed. The @check argument is ignored for dynamic volumes.
+ *
+ * In case of success, this function returns zero. In case of failure, this
+ * function returns a negative error code.
+ *
+ * %-EBADMSG error code is returned:
+ * o for both static and dynamic volumes if MTD driver has detected a data
+ * integrity problem (unrecoverable ECC checksum mismatch in case of NAND);
+ * o for static volumes in case of data CRC mismatch.
+ *
+ * If the volume is damaged because of an interrupted update this function just
+ * returns immediately with %-EBADF error code.
+ */
+int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+ int len, int check)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ int err, vol_id = vol->vol_id;
+
+ dbg_msg("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
+
+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
+ lnum >= vol->used_ebs || offset < 0 || len < 0 ||
+ offset + len > vol->usable_leb_size)
+ return -EINVAL;
+
+ if (vol->vol_type == UBI_STATIC_VOLUME) {
+ if (vol->used_ebs == 0)
+ /* Empty static UBI volume */
+ return 0;
+ if (lnum == vol->used_ebs - 1 &&
+ offset + len > vol->last_eb_bytes)
+ return -EINVAL;
+ }
+
+ if (vol->upd_marker)
+ return -EBADF;
+ if (len == 0)
+ return 0;
+
+ err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
+ if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
+ ubi_warn("mark volume %d as corrupted", vol_id);
+ vol->corrupted = 1;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(ubi_leb_read);
+
+/**
+ * ubi_leb_write - write data.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to write to
+ * @buf: data to write
+ * @offset: offset within the logical eraseblock where to write
+ * @len: how many bytes to write
+ * @dtype: expected data type
+ *
+ * This function writes @len bytes of data from @buf to offset @offset of
+ * logical eraseblock @lnum. The @dtype argument describes expected lifetime of
+ * the data.
+ *
+ * This function takes care of physical eraseblock write failures. If write to
+ * the physical eraseblock write operation fails, the logical eraseblock is
+ * re-mapped to another physical eraseblock, the data is recovered, and the
+ * write finishes. UBI has a pool of reserved physical eraseblocks for this.
+ *
+ * If all the data were successfully written, zero is returned. If an error
+ * occurred and UBI has not been able to recover from it, this function returns
+ * a negative error code. Note, in case of an error, it is possible that
+ * something was still written to the flash media, but that may be some
+ * garbage.
+ *
+ * If the volume is damaged because of an interrupted update this function just
+ * returns immediately with %-EBADF code.
+ */
+int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+ int offset, int len, int dtype)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ int vol_id = vol->vol_id;
+
+ dbg_msg("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset);
+
+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
+ return -EINVAL;
+
+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+ return -EROFS;
+
+ if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 ||
+ offset + len > vol->usable_leb_size ||
+ offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
+ return -EINVAL;
+
+ if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+ dtype != UBI_UNKNOWN)
+ return -EINVAL;
+
+ if (vol->upd_marker)
+ return -EBADF;
+
+ if (len == 0)
+ return 0;
+
+ return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_write);
+
+/*
+ * ubi_leb_change - change logical eraseblock atomically.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to change
+ * @buf: data to write
+ * @len: how many bytes to write
+ * @dtype: expected data type
+ *
+ * This function changes the contents of a logical eraseblock atomically. @buf
+ * has to contain new logical eraseblock data, and @len - the length of the
+ * data, which has to be aligned. The length may be shorter then the logical
+ * eraseblock size, ant the logical eraseblock may be appended to more times
+ * later on. This function guarantees that in case of an unclean reboot the old
+ * contents is preserved. Returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
+ int len, int dtype)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ int vol_id = vol->vol_id;
+
+ dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum);
+
+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
+ return -EINVAL;
+
+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+ return -EROFS;
+
+ if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 ||
+ len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
+ return -EINVAL;
+
+ if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+ dtype != UBI_UNKNOWN)
+ return -EINVAL;
+
+ if (vol->upd_marker)
+ return -EBADF;
+
+ if (len == 0)
+ return 0;
+
+ return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_change);
+
+/**
+ * ubi_leb_erase - erase logical eraseblock.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ *
+ * This function un-maps logical eraseblock @lnum and synchronously erases the
+ * correspondent physical eraseblock. Returns zero in case of success and a
+ * negative error code in case of failure.
+ *
+ * If the volume is damaged because of an interrupted update this function just
+ * returns immediately with %-EBADF code.
+ */
+int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ int err;
+
+ dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
+
+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+ return -EROFS;
+
+ if (lnum < 0 || lnum >= vol->reserved_pebs)
+ return -EINVAL;
+
+ if (vol->upd_marker)
+ return -EBADF;
+
+ err = ubi_eba_unmap_leb(ubi, vol, lnum);
+ if (err)
+ return err;
+
+ return ubi_wl_flush(ubi);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_erase);
+
+/**
+ * ubi_leb_unmap - un-map logical eraseblock.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ *
+ * This function un-maps logical eraseblock @lnum and schedules the
+ * corresponding physical eraseblock for erasure, so that it will eventually be
+ * physically erased in background. This operation is much faster then the
+ * erase operation.
+ *
+ * Unlike erase, the un-map operation does not guarantee that the logical
+ * eraseblock will contain all 0xFF bytes when UBI is initialized again. For
+ * example, if several logical eraseblocks are un-mapped, and an unclean reboot
+ * happens after this, the logical eraseblocks will not necessarily be
+ * un-mapped again when this MTD device is attached. They may actually be
+ * mapped to the same physical eraseblocks again. So, this function has to be
+ * used with care.
+ *
+ * In other words, when un-mapping a logical eraseblock, UBI does not store
+ * any information about this on the flash media, it just marks the logical
+ * eraseblock as "un-mapped" in RAM. If UBI is detached before the physical
+ * eraseblock is physically erased, it will be mapped again to the same logical
+ * eraseblock when the MTD device is attached again.
+ *
+ * The main and obvious use-case of this function is when the contents of a
+ * logical eraseblock has to be re-written. Then it is much more efficient to
+ * first un-map it, then write new data, rather then first erase it, then write
+ * new data. Note, once new data has been written to the logical eraseblock,
+ * UBI guarantees that the old contents has gone forever. In other words, if an
+ * unclean reboot happens after the logical eraseblock has been un-mapped and
+ * then written to, it will contain the last written data.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure. If the volume is damaged because of an interrupted update
+ * this function just returns immediately with %-EBADF code.
+ */
+int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+
+ dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
+
+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+ return -EROFS;
+
+ if (lnum < 0 || lnum >= vol->reserved_pebs)
+ return -EINVAL;
+
+ if (vol->upd_marker)
+ return -EBADF;
+
+ return ubi_eba_unmap_leb(ubi, vol, lnum);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_unmap);
+
+/**
+ * ubi_leb_map - map logical erasblock to a physical eraseblock.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ * @dtype: expected data type
+ *
+ * This function maps an un-mapped logical eraseblock @lnum to a physical
+ * eraseblock. This means, that after a successfull invocation of this
+ * function the logical eraseblock @lnum will be empty (contain only %0xFF
+ * bytes) and be mapped to a physical eraseblock, even if an unclean reboot
+ * happens.
+ *
+ * This function returns zero in case of success, %-EBADF if the volume is
+ * damaged because of an interrupted update, %-EBADMSG if the logical
+ * eraseblock is already mapped, and other negative error codes in case of
+ * other failures.
+ */
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+
+ dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
+
+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+ return -EROFS;
+
+ if (lnum < 0 || lnum >= vol->reserved_pebs)
+ return -EINVAL;
+
+ if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+ dtype != UBI_UNKNOWN)
+ return -EINVAL;
+
+ if (vol->upd_marker)
+ return -EBADF;
+
+ if (vol->eba_tbl[lnum] >= 0)
+ return -EBADMSG;
+
+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_map);
+
+/**
+ * ubi_is_mapped - check if logical eraseblock is mapped.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ *
+ * This function checks if logical eraseblock @lnum is mapped to a physical
+ * eraseblock. If a logical eraseblock is un-mapped, this does not necessarily
+ * mean it will still be un-mapped after the UBI device is re-attached. The
+ * logical eraseblock may become mapped to the physical eraseblock it was last
+ * mapped to.
+ *
+ * This function returns %1 if the LEB is mapped, %0 if not, and a negative
+ * error code in case of failure. If the volume is damaged because of an
+ * interrupted update this function just returns immediately with %-EBADF error
+ * code.
+ */
+int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
+{
+ struct ubi_volume *vol = desc->vol;
+
+ dbg_msg("test LEB %d:%d", vol->vol_id, lnum);
+
+ if (lnum < 0 || lnum >= vol->reserved_pebs)
+ return -EINVAL;
+
+ if (vol->upd_marker)
+ return -EBADF;
+
+ return vol->eba_tbl[lnum] >= 0;
+}
+EXPORT_SYMBOL_GPL(ubi_is_mapped);
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
new file mode 100644
index 0000000..a6410bf
--- /dev/null
+++ b/drivers/mtd/ubi/misc.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/* Here we keep miscellaneous functions which are used all over the UBI code */
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+/**
+ * calc_data_len - calculate how much real data is stored in a buffer.
+ * @ubi: UBI device description object
+ * @buf: a buffer with the contents of the physical eraseblock
+ * @length: the buffer length
+ *
+ * This function calculates how much "real data" is stored in @buf and returnes
+ * the length. Continuous 0xFF bytes at the end of the buffer are not
+ * considered as "real data".
+ */
+int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
+ int length)
+{
+ int i;
+
+ ubi_assert(!(length & (ubi->min_io_size - 1)));
+
+ for (i = length - 1; i >= 0; i--)
+ if (((const uint8_t *)buf)[i] != 0xFF)
+ break;
+
+ /* The resulting length must be aligned to the minimum flash I/O size */
+ length = ALIGN(i + 1, ubi->min_io_size);
+ return length;
+}
+
+/**
+ * ubi_check_volume - check the contents of a static volume.
+ * @ubi: UBI device description object
+ * @vol_id: ID of the volume to check
+ *
+ * This function checks if static volume @vol_id is corrupted by fully reading
+ * it and checking data CRC. This function returns %0 if the volume is not
+ * corrupted, %1 if it is corrupted and a negative error code in case of
+ * failure. Dynamic volumes are not checked and zero is returned immediately.
+ */
+int ubi_check_volume(struct ubi_device *ubi, int vol_id)
+{
+ void *buf;
+ int err = 0, i;
+ struct ubi_volume *vol = ubi->volumes[vol_id];
+
+ if (vol->vol_type != UBI_STATIC_VOLUME)
+ return 0;
+
+ buf = vmalloc(vol->usable_leb_size);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < vol->used_ebs; i++) {
+ int size;
+
+ if (i == vol->used_ebs - 1)
+ size = vol->last_eb_bytes;
+ else
+ size = vol->usable_leb_size;
+
+ err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
+ if (err) {
+ if (err == -EBADMSG)
+ err = 1;
+ break;
+ }
+ }
+
+ vfree(buf);
+ return err;
+}
+
+/**
+ * ubi_calculate_rsvd_pool - calculate how many PEBs must be reserved for bad
+ * eraseblock handling.
+ * @ubi: UBI device description object
+ */
+void ubi_calculate_reserved(struct ubi_device *ubi)
+{
+ ubi->beb_rsvd_level = ubi->good_peb_count/100;
+ ubi->beb_rsvd_level *= CONFIG_MTD_UBI_BEB_RESERVE;
+ if (ubi->beb_rsvd_level < MIN_RESEVED_PEBS)
+ ubi->beb_rsvd_level = MIN_RESEVED_PEBS;
+}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
new file mode 100644
index 0000000..d5c1d27
--- /dev/null
+++ b/drivers/mtd/ubi/scan.c
@@ -0,0 +1,1360 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * UBI scanning unit.
+ *
+ * This unit is responsible for scanning the flash media, checking UBI
+ * headers and providing complete information about the UBI flash image.
+ *
+ * The scanning information is represented by a &struct ubi_scan_info' object.
+ * Information about found volumes is represented by &struct ubi_scan_volume
+ * objects which are kept in volume RB-tree with root at the @volumes field.
+ * The RB-tree is indexed by the volume ID.
+ *
+ * Found logical eraseblocks are represented by &struct ubi_scan_leb objects.
+ * These objects are kept in per-volume RB-trees with the root at the
+ * corresponding &struct ubi_scan_volume object. To put it differently, we keep
+ * an RB-tree of per-volume objects and each of these objects is the root of
+ * RB-tree of per-eraseblock objects.
+ *
+ * Corrupted physical eraseblocks are put to the @corr list, free physical
+ * eraseblocks are put to the @free list and the physical eraseblock to be
+ * erased are put to the @erase list.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/err.h>
+#include <linux/crc32.h>
+#include <asm/div64.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
+#else
+#define paranoid_check_si(ubi, si) 0
+#endif
+
+/* Temporary variables used during scanning */
+static struct ubi_ec_hdr *ech;
+static struct ubi_vid_hdr *vidh;
+
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @si: scanning information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ * @list: the list to add to
+ *
+ * This function adds physical eraseblock @pnum to free, erase, corrupted or
+ * alien lists. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+ struct list_head *list)
+{
+ struct ubi_scan_leb *seb;
+
+ if (list == &si->free)
+ dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
+ else if (list == &si->erase)
+ dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
+ else if (list == &si->corr)
+ dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
+ else if (list == &si->alien)
+ dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
+ else
+ BUG();
+
+ seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
+ if (!seb)
+ return -ENOMEM;
+
+ seb->pnum = pnum;
+ seb->ec = ec;
+ list_add_tail(&seb->u.list, list);
+ return 0;
+}
+
+/**
+ * validate_vid_hdr - check that volume identifier header is correct and
+ * consistent.
+ * @vid_hdr: the volume identifier header to check
+ * @sv: information about the volume this logical eraseblock belongs to
+ * @pnum: physical eraseblock number the VID header came from
+ *
+ * This function checks that data stored in @vid_hdr is consistent. Returns
+ * non-zero if an inconsistency was found and zero if not.
+ *
+ * Note, UBI does sanity check of everything it reads from the flash media.
+ * Most of the checks are done in the I/O unit. Here we check that the
+ * information in the VID header is consistent to the information in other VID
+ * headers of the same volume.
+ */
+static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
+ const struct ubi_scan_volume *sv, int pnum)
+{
+ int vol_type = vid_hdr->vol_type;
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
+
+ if (sv->leb_count != 0) {
+ int sv_vol_type;
+
+ /*
+ * This is not the first logical eraseblock belonging to this
+ * volume. Ensure that the data in its VID header is consistent
+ * to the data in previous logical eraseblock headers.
+ */
+
+ if (vol_id != sv->vol_id) {
+ dbg_err("inconsistent vol_id");
+ goto bad;
+ }
+
+ if (sv->vol_type == UBI_STATIC_VOLUME)
+ sv_vol_type = UBI_VID_STATIC;
+ else
+ sv_vol_type = UBI_VID_DYNAMIC;
+
+ if (vol_type != sv_vol_type) {
+ dbg_err("inconsistent vol_type");
+ goto bad;
+ }
+
+ if (used_ebs != sv->used_ebs) {
+ dbg_err("inconsistent used_ebs");
+ goto bad;
+ }
+
+ if (data_pad != sv->data_pad) {
+ dbg_err("inconsistent data_pad");
+ goto bad;
+ }
+ }
+
+ return 0;
+
+bad:
+ ubi_err("inconsistent VID header at PEB %d", pnum);
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dbg_dump_sv(sv);
+ return -EINVAL;
+}
+
+/**
+ * add_volume - add volume to the scanning information.
+ * @si: scanning information
+ * @vol_id: ID of the volume to add
+ * @pnum: physical eraseblock number
+ * @vid_hdr: volume identifier header
+ *
+ * If the volume corresponding to the @vid_hdr logical eraseblock is already
+ * present in the scanning information, this function does nothing. Otherwise
+ * it adds corresponding volume to the scanning information. Returns a pointer
+ * to the scanning volume object in case of success and a negative error code
+ * in case of failure.
+ */
+static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
+ int pnum,
+ const struct ubi_vid_hdr *vid_hdr)
+{
+ struct ubi_scan_volume *sv;
+ struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
+
+ ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
+
+ /* Walk the volume RB-tree to look if this volume is already present */
+ while (*p) {
+ parent = *p;
+ sv = rb_entry(parent, struct ubi_scan_volume, rb);
+
+ if (vol_id == sv->vol_id)
+ return sv;
+
+ if (vol_id > sv->vol_id)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ /* The volume is absent - add it */
+ sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL);
+ if (!sv)
+ return ERR_PTR(-ENOMEM);
+
+ sv->highest_lnum = sv->leb_count = 0;
+ sv->vol_id = vol_id;
+ sv->root = RB_ROOT;
+ sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
+ sv->compat = vid_hdr->compat;
+ sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
+ : UBI_STATIC_VOLUME;
+ if (vol_id > si->highest_vol_id)
+ si->highest_vol_id = vol_id;
+
+ rb_link_node(&sv->rb, parent, p);
+ rb_insert_color(&sv->rb, &si->volumes);
+ si->vols_found += 1;
+ dbg_bld("added volume %d", vol_id);
+ return sv;
+}
+
+/**
+ * compare_lebs - find out which logical eraseblock is newer.
+ * @ubi: UBI device description object
+ * @seb: first logical eraseblock to compare
+ * @pnum: physical eraseblock number of the second logical eraseblock to
+ * compare
+ * @vid_hdr: volume identifier header of the second logical eraseblock
+ *
+ * This function compares 2 copies of a LEB and informs which one is newer. In
+ * case of success this function returns a positive value, in case of failure, a
+ * negative error code is returned. The success return codes use the following
+ * bits:
+ * o bit 0 is cleared: the first PEB (described by @seb) is newer then the
+ * second PEB (described by @pnum and @vid_hdr);
+ * o bit 0 is set: the second PEB is newer;
+ * o bit 1 is cleared: no bit-flips were detected in the newer LEB;
+ * o bit 1 is set: bit-flips were detected in the newer LEB;
+ * o bit 2 is cleared: the older LEB is not corrupted;
+ * o bit 2 is set: the older LEB is corrupted.
+ */
+static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
+ int pnum, const struct ubi_vid_hdr *vid_hdr)
+{
+ void *buf;
+ int len, err, second_is_newer, bitflips = 0, corrupted = 0;
+ uint32_t data_crc, crc;
+ struct ubi_vid_hdr *vh = NULL;
+ unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
+
+ if (seb->sqnum == 0 && sqnum2 == 0) {
+ long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
+
+ /*
+ * UBI constantly increases the logical eraseblock version
+ * number and it can overflow. Thus, we have to bear in mind
+ * that versions that are close to %0xFFFFFFFF are less then
+ * versions that are close to %0.
+ *
+ * The UBI WL unit guarantees that the number of pending tasks
+ * is not greater then %0x7FFFFFFF. So, if the difference
+ * between any two versions is greater or equivalent to
+ * %0x7FFFFFFF, there was an overflow and the logical
+ * eraseblock with lower version is actually newer then the one
+ * with higher version.
+ *
+ * FIXME: but this is anyway obsolete and will be removed at
+ * some point.
+ */
+ dbg_bld("using old crappy leb_ver stuff");
+
+ if (v1 == v2) {
+ ubi_err("PEB %d and PEB %d have the same version %lld",
+ seb->pnum, pnum, v1);
+ return -EINVAL;
+ }
+
+ abs = v1 - v2;
+ if (abs < 0)
+ abs = -abs;
+
+ if (abs < 0x7FFFFFFF)
+ /* Non-overflow situation */
+ second_is_newer = (v2 > v1);
+ else
+ second_is_newer = (v2 < v1);
+ } else
+ /* Obviously the LEB with lower sequence counter is older */
+ second_is_newer = sqnum2 > seb->sqnum;
+
+ /*
+ * Now we know which copy is newer. If the copy flag of the PEB with
+ * newer version is not set, then we just return, otherwise we have to
+ * check data CRC. For the second PEB we already have the VID header,
+ * for the first one - we'll need to re-read it from flash.
+ *
+ * FIXME: this may be optimized so that we wouldn't read twice.
+ */
+
+ if (second_is_newer) {
+ if (!vid_hdr->copy_flag) {
+ /* It is not a copy, so it is newer */
+ dbg_bld("second PEB %d is newer, copy_flag is unset",
+ pnum);
+ return 1;
+ }
+ } else {
+ pnum = seb->pnum;
+
+ vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+ if (!vh)
+ return -ENOMEM;
+
+ err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
+ if (err) {
+ if (err == UBI_IO_BITFLIPS)
+ bitflips = 1;
+ else {
+ dbg_err("VID of PEB %d header is bad, but it "
+ "was OK earlier", pnum);
+ if (err > 0)
+ err = -EIO;
+
+ goto out_free_vidh;
+ }
+ }
+
+ if (!vh->copy_flag) {
+ /* It is not a copy, so it is newer */
+ dbg_bld("first PEB %d is newer, copy_flag is unset",
+ pnum);
+ err = bitflips << 1;
+ goto out_free_vidh;
+ }
+
+ vid_hdr = vh;
+ }
+
+ /* Read the data of the copy and check the CRC */
+
+ len = be32_to_cpu(vid_hdr->data_size);
+ buf = vmalloc(len);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_free_vidh;
+ }
+
+ err = ubi_io_read_data(ubi, buf, pnum, 0, len);
+ if (err && err != UBI_IO_BITFLIPS)
+ goto out_free_buf;
+
+ data_crc = be32_to_cpu(vid_hdr->data_crc);
+ crc = crc32(UBI_CRC32_INIT, buf, len);
+ if (crc != data_crc) {
+ dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
+ pnum, crc, data_crc);
+ corrupted = 1;
+ bitflips = 0;
+ second_is_newer = !second_is_newer;
+ } else {
+ dbg_bld("PEB %d CRC is OK", pnum);
+ bitflips = !!err;
+ }
+
+ vfree(buf);
+ ubi_free_vid_hdr(ubi, vh);
+
+ if (second_is_newer)
+ dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
+ else
+ dbg_bld("first PEB %d is newer, copy_flag is set", pnum);
+
+ return second_is_newer | (bitflips << 1) | (corrupted << 2);
+
+out_free_buf:
+ vfree(buf);
+out_free_vidh:
+ ubi_free_vid_hdr(ubi, vh);
+ return err;
+}
+
+/**
+ * ubi_scan_add_used - add information about a physical eraseblock to the
+ * scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @pnum: the physical eraseblock number
+ * @ec: erase counter
+ * @vid_hdr: the volume identifier header
+ * @bitflips: if bit-flips were detected when this physical eraseblock was read
+ *
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
+ int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
+ int bitflips)
+{
+ int err, vol_id, lnum;
+ uint32_t leb_ver;
+ unsigned long long sqnum;
+ struct ubi_scan_volume *sv;
+ struct ubi_scan_leb *seb;
+ struct rb_node **p, *parent = NULL;
+
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
+ sqnum = be64_to_cpu(vid_hdr->sqnum);
+ leb_ver = be32_to_cpu(vid_hdr->leb_ver);
+
+ dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
+ pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
+
+ sv = add_volume(si, vol_id, pnum, vid_hdr);
+ if (IS_ERR(sv) < 0)
+ return PTR_ERR(sv);
+
+ if (si->max_sqnum < sqnum)
+ si->max_sqnum = sqnum;
+
+ /*
+ * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
+ * if this is the first instance of this logical eraseblock or not.
+ */
+ p = &sv->root.rb_node;
+ while (*p) {
+ int cmp_res;
+
+ parent = *p;
+ seb = rb_entry(parent, struct ubi_scan_leb, u.rb);
+ if (lnum != seb->lnum) {
+ if (lnum < seb->lnum)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ continue;
+ }
+
+ /*
+ * There is already a physical eraseblock describing the same
+ * logical eraseblock present.
+ */
+
+ dbg_bld("this LEB already exists: PEB %d, sqnum %llu, "
+ "LEB ver %u, EC %d", seb->pnum, seb->sqnum,
+ seb->leb_ver, seb->ec);
+
+ /*
+ * Make sure that the logical eraseblocks have different
+ * versions. Otherwise the image is bad.
+ */
+ if (seb->leb_ver == leb_ver && leb_ver != 0) {
+ ubi_err("two LEBs with same version %u", leb_ver);
+ ubi_dbg_dump_seb(seb, 0);
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ return -EINVAL;
+ }
+
+ /*
+ * Make sure that the logical eraseblocks have different
+ * sequence numbers. Otherwise the image is bad.
+ *
+ * FIXME: remove 'sqnum != 0' check when leb_ver is removed.
+ */
+ if (seb->sqnum == sqnum && sqnum != 0) {
+ ubi_err("two LEBs with same sequence number %llu",
+ sqnum);
+ ubi_dbg_dump_seb(seb, 0);
+ ubi_dbg_dump_vid_hdr(vid_hdr);
+ return -EINVAL;
+ }
+
+ /*
+ * Now we have to drop the older one and preserve the newer
+ * one.
+ */
+ cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr);
+ if (cmp_res < 0)
+ return cmp_res;
+
+ if (cmp_res & 1) {
+ /*
+ * This logical eraseblock is newer then the one
+ * found earlier.
+ */
+ err = validate_vid_hdr(vid_hdr, sv, pnum);
+ if (err)
+ return err;
+
+ if (cmp_res & 4)
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->corr);
+ else
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->erase);
+ if (err)
+ return err;
+
+ seb->ec = ec;
+ seb->pnum = pnum;
+ seb->scrub = ((cmp_res & 2) || bitflips);
+ seb->sqnum = sqnum;
+ seb->leb_ver = leb_ver;
+
+ if (sv->highest_lnum == lnum)
+ sv->last_data_size =
+ be32_to_cpu(vid_hdr->data_size);
+
+ return 0;
+ } else {
+ /*
+ * This logical eraseblock is older then the one found
+ * previously.
+ */
+ if (cmp_res & 4)
+ return add_to_list(si, pnum, ec, &si->corr);
+ else
+ return add_to_list(si, pnum, ec, &si->erase);
+ }
+ }
+
+ /*
+ * We've met this logical eraseblock for the first time, add it to the
+ * scanning information.
+ */
+
+ err = validate_vid_hdr(vid_hdr, sv, pnum);
+ if (err)
+ return err;
+
+ seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
+ if (!seb)
+ return -ENOMEM;
+
+ seb->ec = ec;
+ seb->pnum = pnum;
+ seb->lnum = lnum;
+ seb->sqnum = sqnum;
+ seb->scrub = bitflips;
+ seb->leb_ver = leb_ver;
+
+ if (sv->highest_lnum <= lnum) {
+ sv->highest_lnum = lnum;
+ sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
+ }
+
+ sv->leb_count += 1;
+ rb_link_node(&seb->u.rb, parent, p);
+ rb_insert_color(&seb->u.rb, &sv->root);
+ return 0;
+}
+
+/**
+ * ubi_scan_find_sv - find information about a particular volume in the
+ * scanning information.
+ * @si: scanning information
+ * @vol_id: the requested volume ID
+ *
+ * This function returns a pointer to the volume description or %NULL if there
+ * are no data about this volume in the scanning information.
+ */
+struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
+ int vol_id)
+{
+ struct ubi_scan_volume *sv;
+ struct rb_node *p = si->volumes.rb_node;
+
+ while (p) {
+ sv = rb_entry(p, struct ubi_scan_volume, rb);
+
+ if (vol_id == sv->vol_id)
+ return sv;
+
+ if (vol_id > sv->vol_id)
+ p = p->rb_left;
+ else
+ p = p->rb_right;
+ }
+
+ return NULL;
+}
+
+/**
+ * ubi_scan_find_seb - find information about a particular logical
+ * eraseblock in the volume scanning information.
+ * @sv: a pointer to the volume scanning information
+ * @lnum: the requested logical eraseblock
+ *
+ * This function returns a pointer to the scanning logical eraseblock or %NULL
+ * if there are no data about it in the scanning volume information.
+ */
+struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
+ int lnum)
+{
+ struct ubi_scan_leb *seb;
+ struct rb_node *p = sv->root.rb_node;
+
+ while (p) {
+ seb = rb_entry(p, struct ubi_scan_leb, u.rb);
+
+ if (lnum == seb->lnum)
+ return seb;
+
+ if (lnum > seb->lnum)
+ p = p->rb_left;
+ else
+ p = p->rb_right;
+ }
+
+ return NULL;
+}
+
+/**
+ * ubi_scan_rm_volume - delete scanning information about a volume.
+ * @si: scanning information
+ * @sv: the volume scanning information to delete
+ */
+void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
+{
+ struct rb_node *rb;
+ struct ubi_scan_leb *seb;
+
+ dbg_bld("remove scanning information about volume %d", sv->vol_id);
+
+ while ((rb = rb_first(&sv->root))) {
+ seb = rb_entry(rb, struct ubi_scan_leb, u.rb);
+ rb_erase(&seb->u.rb, &sv->root);
+ list_add_tail(&seb->u.list, &si->erase);
+ }
+
+ rb_erase(&sv->rb, &si->volumes);
+ kfree(sv);
+ si->vols_found -= 1;
+}
+
+/**
+ * ubi_scan_erase_peb - erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @pnum: physical eraseblock number to erase;
+ * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown)
+ *
+ * This function erases physical eraseblock 'pnum', and writes the erase
+ * counter header to it. This function should only be used on UBI device
+ * initialization stages, when the EBA unit had not been yet initialized. This
+ * function returns zero in case of success and a negative error code in case
+ * of failure.
+ */
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+ int pnum, int ec)
+{
+ int err;
+ struct ubi_ec_hdr *ec_hdr;
+
+ if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
+ /*
+ * Erase counter overflow. Upgrade UBI and use 64-bit
+ * erase counters internally.
+ */
+ ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec);
+ return -EINVAL;
+ }
+
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ if (!ec_hdr)
+ return -ENOMEM;
+
+ ec_hdr->ec = cpu_to_be64(ec);
+
+ err = ubi_io_sync_erase(ubi, pnum, 0);
+ if (err < 0)
+ goto out_free;
+
+ err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);
+
+out_free:
+ kfree(ec_hdr);
+ return err;
+}
+
+/**
+ * ubi_scan_get_free_peb - get a free physical eraseblock.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns a free physical eraseblock. It is supposed to be
+ * called on the UBI initialization stages when the wear-leveling unit is not
+ * initialized yet. This function picks a physical eraseblocks from one of the
+ * lists, writes the EC header if it is needed, and removes it from the list.
+ *
+ * This function returns scanning physical eraseblock information in case of
+ * success and an error code in case of failure.
+ */
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
+ struct ubi_scan_info *si)
+{
+ int err = 0, i;
+ struct ubi_scan_leb *seb;
+
+ if (!list_empty(&si->free)) {
+ seb = list_entry(si->free.next, struct ubi_scan_leb, u.list);
+ list_del(&seb->u.list);
+ dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec);
+ return seb;
+ }
+
+ for (i = 0; i < 2; i++) {
+ struct list_head *head;
+ struct ubi_scan_leb *tmp_seb;
+
+ if (i == 0)
+ head = &si->erase;
+ else
+ head = &si->corr;
+
+ /*
+ * We try to erase the first physical eraseblock from the @head
+ * list and pick it if we succeed, or try to erase the
+ * next one if not. And so forth. We don't want to take care
+ * about bad eraseblocks here - they'll be handled later.
+ */
+ list_for_each_entry_safe(seb, tmp_seb, head, u.list) {
+ if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+ seb->ec = si->mean_ec;
+
+ err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1);
+ if (err)
+ continue;
+
+ seb->ec += 1;
+ list_del(&seb->u.list);
+ dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec);
+ return seb;
+ }
+ }
+
+ ubi_err("no eraseblocks found");
+ return ERR_PTR(-ENOSPC);
+}
+
+/**
+ * process_eb - read UBI headers, check them and add corresponding data
+ * to the scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @pnum: the physical eraseblock number
+ *
+ * This function returns a zero if the physical eraseblock was successfully
+ * handled and a negative error code in case of failure.
+ */
+static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
+{
+ long long uninitialized_var(ec);
+ int err, bitflips = 0, vol_id, ec_corr = 0;
+
+ dbg_bld("scan PEB %d", pnum);
+
+ /* Skip bad physical eraseblocks */
+ err = ubi_io_is_bad(ubi, pnum);
+ if (err < 0)
+ return err;
+ else if (err) {
+ /*
+ * FIXME: this is actually duty of the I/O unit to initialize
+ * this, but MTD does not provide enough information.
+ */
+ si->bad_peb_count += 1;
+ return 0;
+ }
+
+ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+ if (err < 0)
+ return err;
+ else if (err == UBI_IO_BITFLIPS)
+ bitflips = 1;
+ else if (err == UBI_IO_PEB_EMPTY)
+ return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
+ else if (err == UBI_IO_BAD_EC_HDR) {
+ /*
+ * We have to also look at the VID header, possibly it is not
+ * corrupted. Set %bitflips flag in order to make this PEB be
+ * moved and EC be re-created.
+ */
+ ec_corr = 1;
+ ec = UBI_SCAN_UNKNOWN_EC;
+ bitflips = 1;
+ }
+
+ si->is_empty = 0;
+
+ if (!ec_corr) {
+ /* Make sure UBI version is OK */
+ if (ech->version != UBI_VERSION) {
+ ubi_err("this UBI version is %d, image version is %d",
+ UBI_VERSION, (int)ech->version);
+ return -EINVAL;
+ }
+
+ ec = be64_to_cpu(ech->ec);
+ if (ec > UBI_MAX_ERASECOUNTER) {
+ /*
+ * Erase counter overflow. The EC headers have 64 bits
+ * reserved, but we anyway make use of only 31 bit
+ * values, as this seems to be enough for any existing
+ * flash. Upgrade UBI and use 64-bit erase counters
+ * internally.
+ */
+ ubi_err("erase counter overflow, max is %d",
+ UBI_MAX_ERASECOUNTER);
+ ubi_dbg_dump_ec_hdr(ech);
+ return -EINVAL;
+ }
+ }
+
+ /* OK, we've done with the EC header, let's look at the VID header */
+
+ err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
+ if (err < 0)
+ return err;
+ else if (err == UBI_IO_BITFLIPS)
+ bitflips = 1;
+ else if (err == UBI_IO_BAD_VID_HDR ||
+ (err == UBI_IO_PEB_FREE && ec_corr)) {
+ /* VID header is corrupted */
+ err = add_to_list(si, pnum, ec, &si->corr);
+ if (err)
+ return err;
+ goto adjust_mean_ec;
+ } else if (err == UBI_IO_PEB_FREE) {
+ /* No VID header - the physical eraseblock is free */
+ err = add_to_list(si, pnum, ec, &si->free);
+ if (err)
+ return err;
+ goto adjust_mean_ec;
+ }
+
+ vol_id = be32_to_cpu(vidh->vol_id);
+ if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
+ int lnum = be32_to_cpu(vidh->lnum);
+
+ /* Unsupported internal volume */
+ switch (vidh->compat) {
+ case UBI_COMPAT_DELETE:
+ ubi_msg("\"delete\" compatible internal volume %d:%d"
+ " found, remove it", vol_id, lnum);
+ err = add_to_list(si, pnum, ec, &si->corr);
+ if (err)
+ return err;
+ break;
+
+ case UBI_COMPAT_RO:
+ ubi_msg("read-only compatible internal volume %d:%d"
+ " found, switch to read-only mode",
+ vol_id, lnum);
+ ubi->ro_mode = 1;
+ break;
+
+ case UBI_COMPAT_PRESERVE:
+ ubi_msg("\"preserve\" compatible internal volume %d:%d"
+ " found", vol_id, lnum);
+ err = add_to_list(si, pnum, ec, &si->alien);
+ if (err)
+ return err;
+ si->alien_peb_count += 1;
+ return 0;
+
+ case UBI_COMPAT_REJECT:
+ ubi_err("incompatible internal volume %d:%d found",
+ vol_id, lnum);
+ return -EINVAL;
+ }
+ }
+
+ /* Both UBI headers seem to be fine */
+ err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
+ if (err)
+ return err;
+
+adjust_mean_ec:
+ if (!ec_corr) {
+ si->ec_sum += ec;
+ si->ec_count += 1;
+ if (ec > si->max_ec)
+ si->max_ec = ec;
+ if (ec < si->min_ec)
+ si->min_ec = ec;
+ }
+
+ return 0;
+}
+
+/**
+ * ubi_scan - scan an MTD device.
+ * @ubi: UBI device description object
+ *
+ * This function does full scanning of an MTD device and returns complete
+ * information about it. In case of failure, an error code is returned.
+ */
+struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
+{
+ int err, pnum;
+ struct rb_node *rb1, *rb2;
+ struct ubi_scan_volume *sv;
+ struct ubi_scan_leb *seb;
+ struct ubi_scan_info *si;
+
+ si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL);
+ if (!si)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&si->corr);
+ INIT_LIST_HEAD(&si->free);
+ INIT_LIST_HEAD(&si->erase);
+ INIT_LIST_HEAD(&si->alien);
+ si->volumes = RB_ROOT;
+ si->is_empty = 1;
+
+ err = -ENOMEM;
+ ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ if (!ech)
+ goto out_si;
+
+ vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+ if (!vidh)
+ goto out_ech;
+
+ for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+ cond_resched();
+
+ dbg_msg("process PEB %d", pnum);
+ err = process_eb(ubi, si, pnum);
+ if (err < 0)
+ goto out_vidh;
+ }
+
+ dbg_msg("scanning is finished");
+
+ /* Calculate mean erase counter */
+ if (si->ec_count) {
+ do_div(si->ec_sum, si->ec_count);
+ si->mean_ec = si->ec_sum;
+ }
+
+ if (si->is_empty)
+ ubi_msg("empty MTD device detected");
+
+ /*
+ * In case of unknown erase counter we use the mean erase counter
+ * value.
+ */
+ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+ ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
+ if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+ seb->ec = si->mean_ec;
+ }
+
+ list_for_each_entry(seb, &si->free, u.list) {
+ if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+ seb->ec = si->mean_ec;
+ }
+
+ list_for_each_entry(seb, &si->corr, u.list)
+ if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+ seb->ec = si->mean_ec;
+
+ list_for_each_entry(seb, &si->erase, u.list)
+ if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+ seb->ec = si->mean_ec;
+
+ err = paranoid_check_si(ubi, si);
+ if (err) {
+ if (err > 0)
+ err = -EINVAL;
+ goto out_vidh;
+ }
+
+ ubi_free_vid_hdr(ubi, vidh);
+ kfree(ech);
+
+ return si;
+
+out_vidh:
+ ubi_free_vid_hdr(ubi, vidh);
+out_ech:
+ kfree(ech);
+out_si:
+ ubi_scan_destroy_si(si);
+ return ERR_PTR(err);
+}
+
+/**
+ * destroy_sv - free the scanning volume information
+ * @sv: scanning volume information
+ *
+ * This function destroys the volume RB-tree (@sv->root) and the scanning
+ * volume information.
+ */
+static void destroy_sv(struct ubi_scan_volume *sv)
+{
+ struct ubi_scan_leb *seb;
+ struct rb_node *this = sv->root.rb_node;
+
+ while (this) {
+ if (this->rb_left)
+ this = this->rb_left;
+ else if (this->rb_right)
+ this = this->rb_right;
+ else {
+ seb = rb_entry(this, struct ubi_scan_leb, u.rb);
+ this = rb_parent(this);
+ if (this) {
+ if (this->rb_left == &seb->u.rb)
+ this->rb_left = NULL;
+ else
+ this->rb_right = NULL;
+ }
+
+ kfree(seb);
+ }
+ }
+ kfree(sv);
+}
+
+/**
+ * ubi_scan_destroy_si - destroy scanning information.
+ * @si: scanning information
+ */
+void ubi_scan_destroy_si(struct ubi_scan_info *si)
+{
+ struct ubi_scan_leb *seb, *seb_tmp;
+ struct ubi_scan_volume *sv;
+ struct rb_node *rb;
+
+ list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
+ list_del(&seb->u.list);
+ kfree(seb);
+ }
+ list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
+ list_del(&seb->u.list);
+ kfree(seb);
+ }
+ list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
+ list_del(&seb->u.list);
+ kfree(seb);
+ }
+ list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
+ list_del(&seb->u.list);
+ kfree(seb);
+ }
+
+ /* Destroy the volume RB-tree */
+ rb = si->volumes.rb_node;
+ while (rb) {
+ if (rb->rb_left)
+ rb = rb->rb_left;
+ else if (rb->rb_right)
+ rb = rb->rb_right;
+ else {
+ sv = rb_entry(rb, struct ubi_scan_volume, rb);
+
+ rb = rb_parent(rb);
+ if (rb) {
+ if (rb->rb_left == &sv->rb)
+ rb->rb_left = NULL;
+ else
+ rb->rb_right = NULL;
+ }
+
+ destroy_sv(sv);
+ }
+ }
+
+ kfree(si);
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_si - check if the scanning information is correct and
+ * consistent.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns zero if the scanning information is all right, %1 if
+ * not and a negative error code if an error occurred.
+ */
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+ int pnum, err, vols_found = 0;
+ struct rb_node *rb1, *rb2;
+ struct ubi_scan_volume *sv;
+ struct ubi_scan_leb *seb, *last_seb;
+ uint8_t *buf;
+
+ /*
+ * At first, check that scanning information is OK.
+ */
+ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+ int leb_count = 0;
+
+ cond_resched();
+
+ vols_found += 1;
+
+ if (si->is_empty) {
+ ubi_err("bad is_empty flag");
+ goto bad_sv;
+ }
+
+ if (sv->vol_id < 0 || sv->highest_lnum < 0 ||
+ sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 ||
+ sv->data_pad < 0 || sv->last_data_size < 0) {
+ ubi_err("negative values");
+ goto bad_sv;
+ }
+
+ if (sv->vol_id >= UBI_MAX_VOLUMES &&
+ sv->vol_id < UBI_INTERNAL_VOL_START) {
+ ubi_err("bad vol_id");
+ goto bad_sv;
+ }
+
+ if (sv->vol_id > si->highest_vol_id) {
+ ubi_err("highest_vol_id is %d, but vol_id %d is there",
+ si->highest_vol_id, sv->vol_id);
+ goto out;
+ }
+
+ if (sv->vol_type != UBI_DYNAMIC_VOLUME &&
+ sv->vol_type != UBI_STATIC_VOLUME) {
+ ubi_err("bad vol_type");
+ goto bad_sv;
+ }
+
+ if (sv->data_pad > ubi->leb_size / 2) {
+ ubi_err("bad data_pad");
+ goto bad_sv;
+ }
+
+ last_seb = NULL;
+ ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ cond_resched();
+
+ last_seb = seb;
+ leb_count += 1;
+
+ if (seb->pnum < 0 || seb->ec < 0) {
+ ubi_err("negative values");
+ goto bad_seb;
+ }
+
+ if (seb->ec < si->min_ec) {
+ ubi_err("bad si->min_ec (%d), %d found",
+ si->min_ec, seb->ec);
+ goto bad_seb;
+ }
+
+ if (seb->ec > si->max_ec) {
+ ubi_err("bad si->max_ec (%d), %d found",
+ si->max_ec, seb->ec);
+ goto bad_seb;
+ }
+
+ if (seb->pnum >= ubi->peb_count) {
+ ubi_err("too high PEB number %d, total PEBs %d",
+ seb->pnum, ubi->peb_count);
+ goto bad_seb;
+ }
+
+ if (sv->vol_type == UBI_STATIC_VOLUME) {
+ if (seb->lnum >= sv->used_ebs) {
+ ubi_err("bad lnum or used_ebs");
+ goto bad_seb;
+ }
+ } else {
+ if (sv->used_ebs != 0) {
+ ubi_err("non-zero used_ebs");
+ goto bad_seb;
+ }
+ }
+
+ if (seb->lnum > sv->highest_lnum) {
+ ubi_err("incorrect highest_lnum or lnum");
+ goto bad_seb;
+ }
+ }
+
+ if (sv->leb_count != leb_count) {
+ ubi_err("bad leb_count, %d objects in the tree",
+ leb_count);
+ goto bad_sv;
+ }
+
+ if (!last_seb)
+ continue;
+
+ seb = last_seb;
+
+ if (seb->lnum != sv->highest_lnum) {
+ ubi_err("bad highest_lnum");
+ goto bad_seb;
+ }
+ }
+
+ if (vols_found != si->vols_found) {
+ ubi_err("bad si->vols_found %d, should be %d",
+ si->vols_found, vols_found);
+ goto out;
+ }
+
+ /* Check that scanning information is correct */
+ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+ last_seb = NULL;
+ ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ int vol_type;
+
+ cond_resched();
+
+ last_seb = seb;
+
+ err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1);
+ if (err && err != UBI_IO_BITFLIPS) {
+ ubi_err("VID header is not OK (%d)", err);
+ if (err > 0)
+ err = -EIO;
+ return err;
+ }
+
+ vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
+ UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
+ if (sv->vol_type != vol_type) {
+ ubi_err("bad vol_type");
+ goto bad_vid_hdr;
+ }
+
+ if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
+ ubi_err("bad sqnum %llu", seb->sqnum);
+ goto bad_vid_hdr;
+ }
+
+ if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
+ ubi_err("bad vol_id %d", sv->vol_id);
+ goto bad_vid_hdr;
+ }
+
+ if (sv->compat != vidh->compat) {
+ ubi_err("bad compat %d", vidh->compat);
+ goto bad_vid_hdr;
+ }
+
+ if (seb->lnum != be32_to_cpu(vidh->lnum)) {
+ ubi_err("bad lnum %d", seb->lnum);
+ goto bad_vid_hdr;
+ }
+
+ if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
+ ubi_err("bad used_ebs %d", sv->used_ebs);
+ goto bad_vid_hdr;
+ }
+
+ if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
+ ubi_err("bad data_pad %d", sv->data_pad);
+ goto bad_vid_hdr;
+ }
+
+ if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
+ ubi_err("bad leb_ver %u", seb->leb_ver);
+ goto bad_vid_hdr;
+ }
+ }
+
+ if (!last_seb)
+ continue;
+
+ if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
+ ubi_err("bad highest_lnum %d", sv->highest_lnum);
+ goto bad_vid_hdr;
+ }
+
+ if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
+ ubi_err("bad last_data_size %d", sv->last_data_size);
+ goto bad_vid_hdr;
+ }
+ }
+
+ /*
+ * Make sure that all the physical eraseblocks are in one of the lists
+ * or trees.
+ */
+ buf = kzalloc(ubi->peb_count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+ err = ubi_io_is_bad(ubi, pnum);
+ if (err < 0) {
+ kfree(buf);
+ return err;
+ }
+ else if (err)
+ buf[pnum] = 1;
+ }
+
+ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
+ ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
+ buf[seb->pnum] = 1;
+
+ list_for_each_entry(seb, &si->free, u.list)
+ buf[seb->pnum] = 1;
+
+ list_for_each_entry(seb, &si->corr, u.list)
+ buf[seb->pnum] = 1;
+
+ list_for_each_entry(seb, &si->erase, u.list)
+ buf[seb->pnum] = 1;
+
+ list_for_each_entry(seb, &si->alien, u.list)
+ buf[seb->pnum] = 1;
+
+ err = 0;
+ for (pnum = 0; pnum < ubi->peb_count; pnum++)
+ if (!buf[pnum]) {
+ ubi_err("PEB %d is not referred", pnum);
+ err = 1;
+ }
+
+ kfree(buf);
+ if (err)
+ goto out;
+ return 0;
+
+bad_seb:
+ ubi_err("bad scanning information about LEB %d", seb->lnum);
+ ubi_dbg_dump_seb(seb, 0);
+ ubi_dbg_dump_sv(sv);
+ goto out;
+
+bad_sv:
+ ubi_err("bad scanning information about volume %d", sv->vol_id);
+ ubi_dbg_dump_sv(sv);
+ goto out;
+
+bad_vid_hdr:
+ ubi_err("bad scanning information about volume %d", sv->vol_id);
+ ubi_dbg_dump_sv(sv);
+ ubi_dbg_dump_vid_hdr(vidh);
+
+out:
+ ubi_dbg_dump_stack();
+ return 1;
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
new file mode 100644
index 0000000..966b9b6
--- /dev/null
+++ b/drivers/mtd/ubi/scan.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+#ifndef __UBI_SCAN_H__
+#define __UBI_SCAN_H__
+
+/* The erase counter value for this physical eraseblock is unknown */
+#define UBI_SCAN_UNKNOWN_EC (-1)
+
+/**
+ * struct ubi_scan_leb - scanning information about a physical eraseblock.
+ * @ec: erase counter (%UBI_SCAN_UNKNOWN_EC if it is unknown)
+ * @pnum: physical eraseblock number
+ * @lnum: logical eraseblock number
+ * @scrub: if this physical eraseblock needs scrubbing
+ * @sqnum: sequence number
+ * @u: unions RB-tree or @list links
+ * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects
+ * @u.list: link in one of the eraseblock lists
+ * @leb_ver: logical eraseblock version (obsolete)
+ *
+ * One object of this type is allocated for each physical eraseblock during
+ * scanning.
+ */
+struct ubi_scan_leb {
+ int ec;
+ int pnum;
+ int lnum;
+ int scrub;
+ unsigned long long sqnum;
+ union {
+ struct rb_node rb;
+ struct list_head list;
+ } u;
+ uint32_t leb_ver;
+};
+
+/**
+ * struct ubi_scan_volume - scanning information about a volume.
+ * @vol_id: volume ID
+ * @highest_lnum: highest logical eraseblock number in this volume
+ * @leb_count: number of logical eraseblocks in this volume
+ * @vol_type: volume type
+ * @used_ebs: number of used logical eraseblocks in this volume (only for
+ * static volumes)
+ * @last_data_size: amount of data in the last logical eraseblock of this
+ * volume (always equivalent to the usable logical eraseblock size in case of
+ * dynamic volumes)
+ * @data_pad: how many bytes at the end of logical eraseblocks of this volume
+ * are not used (due to volume alignment)
+ * @compat: compatibility flags of this volume
+ * @rb: link in the volume RB-tree
+ * @root: root of the RB-tree containing all the eraseblock belonging to this
+ * volume (&struct ubi_scan_leb objects)
+ *
+ * One object of this type is allocated for each volume during scanning.
+ */
+struct ubi_scan_volume {
+ int vol_id;
+ int highest_lnum;
+ int leb_count;
+ int vol_type;
+ int used_ebs;
+ int last_data_size;
+ int data_pad;
+ int compat;
+ struct rb_node rb;
+ struct rb_root root;
+};
+
+/**
+ * struct ubi_scan_info - UBI scanning information.
+ * @volumes: root of the volume RB-tree
+ * @corr: list of corrupted physical eraseblocks
+ * @free: list of free physical eraseblocks
+ * @erase: list of physical eraseblocks which have to be erased
+ * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
+ * @bad_peb_count: count of bad physical eraseblocks
+ * those belonging to "preserve"-compatible internal volumes)
+ * @vols_found: number of volumes found during scanning
+ * @highest_vol_id: highest volume ID
+ * @alien_peb_count: count of physical eraseblocks in the @alien list
+ * @is_empty: flag indicating whether the MTD device is empty or not
+ * @min_ec: lowest erase counter value
+ * @max_ec: highest erase counter value
+ * @max_sqnum: highest sequence number value
+ * @mean_ec: mean erase counter value
+ * @ec_sum: a temporary variable used when calculating @mean_ec
+ * @ec_count: a temporary variable used when calculating @mean_ec
+ *
+ * This data structure contains the result of scanning and may be used by other
+ * UBI units to build final UBI data structures, further error-recovery and so
+ * on.
+ */
+struct ubi_scan_info {
+ struct rb_root volumes;
+ struct list_head corr;
+ struct list_head free;
+ struct list_head erase;
+ struct list_head alien;
+ int bad_peb_count;
+ int vols_found;
+ int highest_vol_id;
+ int alien_peb_count;
+ int is_empty;
+ int min_ec;
+ int max_ec;
+ unsigned long long max_sqnum;
+ int mean_ec;
+ uint64_t ec_sum;
+ int ec_count;
+};
+
+struct ubi_device;
+struct ubi_vid_hdr;
+
+/*
+ * ubi_scan_move_to_list - move a physical eraseblock from the volume tree to a
+ * list.
+ *
+ * @sv: volume scanning information
+ * @seb: scanning eraseblock infprmation
+ * @list: the list to move to
+ */
+static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
+ struct ubi_scan_leb *seb,
+ struct list_head *list)
+{
+ rb_erase(&seb->u.rb, &sv->root);
+ list_add_tail(&seb->u.list, list);
+}
+
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
+ int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
+ int bitflips);
+struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
+ int vol_id);
+struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
+ int lnum);
+void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
+ struct ubi_scan_info *si);
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+ int pnum, int ec);
+struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
+void ubi_scan_destroy_si(struct ubi_scan_info *si);
+
+#endif /* !__UBI_SCAN_H__ */
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
new file mode 100644
index 0000000..c3185d9
--- /dev/null
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ * Thomas Gleixner
+ * Frank Haverkamp
+ * Oliver Lohmann
+ * Andreas Arnez
+ */
+
+/*
+ * This file defines the layout of UBI headers and all the other UBI on-flash
+ * data structures.
+ */
+
+#ifndef __UBI_MEDIA_H__
+#define __UBI_MEDIA_H__
+
+#include <asm/byteorder.h>
+
+/* The version of UBI images supported by this implementation */
+#define UBI_VERSION 1
+
+/* The highest erase counter value supported by this implementation */
+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
+
+/* The initial CRC32 value used when calculating CRC checksums */
+#define UBI_CRC32_INIT 0xFFFFFFFFU
+
+/* Erase counter header magic number (ASCII "UBI#") */
+#define UBI_EC_HDR_MAGIC 0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
+
+/*
+ * Volume type constants used in the volume identifier header.
+ *
+ * @UBI_VID_DYNAMIC: dynamic volume
+ * @UBI_VID_STATIC: static volume
+ */
+enum {
+ UBI_VID_DYNAMIC = 1,
+ UBI_VID_STATIC = 2
+};
+
+/*
+ * Volume flags used in the volume table record.
+ *
+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
+ *
+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
+ * table. UBI automatically re-sizes the volume which has this flag and makes
+ * the volume to be of largest possible size. This means that if after the
+ * initialization UBI finds out that there are available physical eraseblocks
+ * present on the device, it automatically appends all of them to the volume
+ * (the physical eraseblocks reserved for bad eraseblocks handling and other
+ * reserved physical eraseblocks are not taken). So, if there is a volume with
+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
+ * eraseblocks will be zero after UBI is loaded, because all of them will be
+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
+ * after the volume had been initialized.
+ *
+ * The auto-resize feature is useful for device production purposes. For
+ * example, different NAND flash chips may have different amount of initial bad
+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND
+ * chips usually guarantee that the amount of initial bad eraseblocks does not
+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
+ * flashed to the end devices in production, he does not know the exact amount
+ * of good physical eraseblocks the NAND chip on the device will have, but this
+ * number is required to calculate the volume sized and put them to the volume
+ * table of the UBI image. In this case, one of the volumes (e.g., the one
+ * which will store the root file system) is marked as "auto-resizable", and
+ * UBI will adjust its size on the first boot if needed.
+ *
+ * Note, first UBI reserves some amount of physical eraseblocks for bad
+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This
+ * means that the pool of reserved physical eraseblocks will always be present.
+ */
+enum {
+ UBI_VTBL_AUTORESIZE_FLG = 0x01,
+};
+
+/*
+ * Compatibility constants used by internal volumes.
+ *
+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written
+ * to the flash
+ * @UBI_COMPAT_RO: attach this device in read-only mode
+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
+ * physical eraseblocks, don't allow the wear-leveling unit to move them
+ * @UBI_COMPAT_REJECT: reject this UBI image
+ */
+enum {
+ UBI_COMPAT_DELETE = 1,
+ UBI_COMPAT_RO = 2,
+ UBI_COMPAT_PRESERVE = 4,
+ UBI_COMPAT_REJECT = 5
+};
+
+/* Sizes of UBI headers */
+#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
+
+/* Sizes of UBI headers without the ending CRC */
+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
+
+/**
+ * struct ubi_ec_hdr - UBI erase counter header.
+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
+ * @version: version of UBI implementation which is supposed to accept this
+ * UBI image
+ * @padding1: reserved for future, zeroes
+ * @ec: the erase counter
+ * @vid_hdr_offset: where the VID header starts
+ * @data_offset: where the user data start
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: erase counter header CRC checksum
+ *
+ * The erase counter header takes 64 bytes and has a plenty of unused space for
+ * future usage. The unused fields are zeroed. The @version field is used to
+ * indicate the version of UBI implementation which is supposed to be able to
+ * work with this UBI image. If @version is greater then the current UBI
+ * version, the image is rejected. This may be useful in future if something
+ * is changed radically. This field is duplicated in the volume identifier
+ * header.
+ *
+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the
+ * volume identifier header and user data, relative to the beginning of the
+ * physical eraseblock. These values have to be the same for all physical
+ * eraseblocks.
+ */
+struct ubi_ec_hdr {
+ __be32 magic;
+ __u8 version;
+ __u8 padding1[3];
+ __be64 ec; /* Warning: the current limit is 31-bit anyway! */
+ __be32 vid_hdr_offset;
+ __be32 data_offset;
+ __u8 padding2[36];
+ __be32 hdr_crc;
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_vid_hdr - on-flash UBI volume identifier header.
+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
+ * @version: UBI implementation version which is supposed to accept this UBI
+ * image (%UBI_VERSION)
+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @copy_flag: if this logical eraseblock was copied from another physical
+ * eraseblock (for wear-leveling reasons)
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @vol_id: ID of this volume
+ * @lnum: logical eraseblock number
+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
+ * removed, kept only for not breaking older UBI users)
+ * @data_size: how many bytes of data this logical eraseblock contains
+ * @used_ebs: total number of used logical eraseblocks in this volume
+ * @data_pad: how many bytes at the end of this physical eraseblock are not
+ * used
+ * @data_crc: CRC checksum of the data stored in this logical eraseblock
+ * @padding1: reserved for future, zeroes
+ * @sqnum: sequence number
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: volume identifier header CRC checksum
+ *
+ * The @sqnum is the value of the global sequence counter at the time when this
+ * VID header was created. The global sequence counter is incremented each time
+ * UBI writes a new VID header to the flash, i.e. when it maps a logical
+ * eraseblock to a new physical eraseblock. The global sequence counter is an
+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum
+ * (sequence number) is used to distinguish between older and newer versions of
+ * logical eraseblocks.
+ *
+ * There are 2 situations when there may be more then one physical eraseblock
+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id
+ * and @lnum values in the volume identifier header. Suppose we have a logical
+ * eraseblock L and it is mapped to the physical eraseblock P.
+ *
+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following
+ * situation is possible: L is asynchronously erased, so P is scheduled for
+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
+ * so P1 is written to, then an unclean reboot happens. Result - there are 2
+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock
+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
+ * flash.
+ *
+ * 2. From time to time UBI moves logical eraseblocks to other physical
+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
+ * to P1, and an unclean reboot happens before P is physically erased, there
+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to
+ * select one of them when the flash is attached. The @sqnum field says which
+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But
+ * it is not enough to select the physical eraseblock with the higher sequence
+ * number, because the unclean reboot could have happen in the middle of the
+ * copying process, so the data in P is corrupted. It is also not enough to
+ * just select the physical eraseblock with lower sequence number, because the
+ * data there may be old (consider a case if more data was added to P1 after
+ * the copying). Moreover, the unclean reboot may happen when the erasure of P
+ * was just started, so it result in unstable P, which is "mostly" OK, but
+ * still has unstable bits.
+ *
+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
+ * copy. UBI also calculates data CRC when the data is moved and stores it at
+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
+ * examined. If it is cleared, the situation* is simple and the newer one is
+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise
+ * the older one (P) is selected.
+ *
+ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum
+ * in the past. But it is not used anymore and we keep it in order to be able
+ * to deal with old UBI images. It will be removed at some point.
+ *
+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
+ * Internal volumes are not seen from outside and are used for various internal
+ * UBI purposes. In this implementation there is only one internal volume - the
+ * layout volume. Internal volumes are the main mechanism of UBI extensions.
+ * For example, in future one may introduce a journal internal volume. Internal
+ * volumes have their own reserved range of IDs.
+ *
+ * The @compat field is only used for internal volumes and contains the "degree
+ * of their compatibility". It is always zero for user volumes. This field
+ * provides a mechanism to introduce UBI extensions and to be still compatible
+ * with older UBI binaries. For example, if someone introduced a journal in
+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
+ * journal volume. And in this case, older UBI binaries, which know nothing
+ * about the journal volume, would just delete this volume and work perfectly
+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
+ * - it just ignores the Ext3fs journal.
+ *
+ * The @data_crc field contains the CRC checksum of the contents of the logical
+ * eraseblock if this is a static volume. In case of dynamic volumes, it does
+ * not contain the CRC checksum as a rule. The only exception is when the
+ * data of the physical eraseblock was moved by the wear-leveling unit, then
+ * the wear-leveling unit calculates the data CRC and stores it in the
+ * @data_crc field. And of course, the @copy_flag is %in this case.
+ *
+ * The @data_size field is used only for static volumes because UBI has to know
+ * how many bytes of data are stored in this eraseblock. For dynamic volumes,
+ * this field usually contains zero. The only exception is when the data of the
+ * physical eraseblock was moved to another physical eraseblock for
+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the
+ * contents and uses both @data_crc and @data_size fields. In this case, the
+ * @data_size field contains data size.
+ *
+ * The @used_ebs field is used only for static volumes and indicates how many
+ * eraseblocks the data of the volume takes. For dynamic volumes this field is
+ * not used and always contains zero.
+ *
+ * The @data_pad is calculated when volumes are created using the alignment
+ * parameter. So, effectively, the @data_pad field reduces the size of logical
+ * eraseblocks of this volume. This is very handy when one uses block-oriented
+ * software (say, cramfs) on top of the UBI volume.
+ */
+struct ubi_vid_hdr {
+ __be32 magic;
+ __u8 version;
+ __u8 vol_type;
+ __u8 copy_flag;
+ __u8 compat;
+ __be32 vol_id;
+ __be32 lnum;
+ __be32 leb_ver; /* obsolete, to be removed, don't use */
+ __be32 data_size;
+ __be32 used_ebs;
+ __be32 data_pad;
+ __be32 data_crc;
+ __u8 padding1[4];
+ __be64 sqnum;
+ __u8 padding2[12];
+ __be32 hdr_crc;
+} __attribute__ ((packed));
+
+/* Internal UBI volumes count */
+#define UBI_INT_VOL_COUNT 1
+
+/*
+ * Starting ID of internal volumes. There is reserved room for 4096 internal
+ * volumes.
+ */
+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
+
+/* The layout volume contains the volume table */
+
+#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
+#define UBI_LAYOUT_VOLUME_ALIGN 1
+#define UBI_LAYOUT_VOLUME_EBS 2
+#define UBI_LAYOUT_VOLUME_NAME "layout volume"
+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
+
+/* The maximum number of volumes per one UBI device */
+#define UBI_MAX_VOLUMES 128
+
+/* The maximum volume name length */
+#define UBI_VOL_NAME_MAX 127
+
+/* Size of the volume table record */
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+
+/* Size of the volume table record without the ending CRC */
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
+
+/**
+ * struct ubi_vtbl_record - a record in the volume table.
+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @upd_marker: if volume update was started but not finished
+ * @name_len: volume name length
+ * @name: the volume name
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ * @padding: reserved, zeroes
+ * @crc: a CRC32 checksum of the record
+ *
+ * The volume table records are stored in the volume table, which is stored in
+ * the layout volume. The layout volume consists of 2 logical eraseblock, each
+ * of which contains a copy of the volume table (i.e., the volume table is
+ * duplicated). The volume table is an array of &struct ubi_vtbl_record
+ * objects indexed by the volume ID.
+ *
+ * If the size of the logical eraseblock is large enough to fit
+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
+ * records. Otherwise, it contains as many records as it can fit (i.e., size of
+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
+ *
+ * The @upd_marker flag is used to implement volume update. It is set to %1
+ * before update and set to %0 after the update. So if the update operation was
+ * interrupted, UBI knows that the volume is corrupted.
+ *
+ * The @alignment field is specified when the volume is created and cannot be
+ * later changed. It may be useful, for example, when a block-oriented file
+ * system works on top of UBI. The @data_pad field is calculated using the
+ * logical eraseblock size and @alignment. The alignment must be multiple to the
+ * minimal flash I/O unit. If @alignment is 1, all the available space of
+ * the physical eraseblocks is used.
+ *
+ * Empty records contain all zeroes and the CRC checksum of those zeroes.
+ */
+struct ubi_vtbl_record {
+ __be32 reserved_pebs;
+ __be32 alignment;
+ __be32 data_pad;
+ __u8 vol_type;
+ __u8 upd_marker;
+ __be16 name_len;
+ __u8 name[UBI_VOL_NAME_MAX+1];
+ __u8 flags;
+ __u8 padding[23];
+ __be32 crc;
+} __attribute__ ((packed));
+
+#endif /* !__UBI_MEDIA_H__ */
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
new file mode 100644
index 0000000..bf77a15
--- /dev/null
+++ b/drivers/mtd/ubi/ubi.h
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2006, 2007
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+#ifndef __UBI_UBI_H__
+#define __UBI_UBI_H__
+
+#ifdef UBI_LINUX
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/ubi.h>
+#endif
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/ubi.h>
+
+#include "ubi-media.h"
+#include "scan.h"
+#include "debug.h"
+
+/* Maximum number of supported UBI devices */
+#define UBI_MAX_DEVICES 32
+
+/* UBI name used for character devices, sysfs, etc */
+#define UBI_NAME_STR "ubi"
+
+/* Normal UBI messages */
+#define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__)
+/* UBI warning messages */
+#define ubi_warn(fmt, ...) printk(KERN_WARNING "UBI warning: %s: " fmt "\n", \
+ __func__, ##__VA_ARGS__)
+/* UBI error messages */
+#define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \
+ __func__, ##__VA_ARGS__)
+
+/* Lowest number PEBs reserved for bad PEB handling */
+#define MIN_RESEVED_PEBS 2
+
+/* Background thread name pattern */
+#define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
+
+/* This marker in the EBA table means that the LEB is um-mapped */
+#define UBI_LEB_UNMAPPED -1
+
+/*
+ * In case of errors, UBI tries to repeat the operation several times before
+ * returning error. The below constant defines how many times UBI re-tries.
+ */
+#define UBI_IO_RETRIES 3
+
+/*
+ * Error codes returned by the I/O unit.
+ *
+ * UBI_IO_PEB_EMPTY: the physical eraseblock is empty, i.e. it contains only
+ * 0xFF bytes
+ * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a
+ * valid erase counter header, and the rest are %0xFF bytes
+ * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC)
+ * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or
+ * CRC)
+ * UBI_IO_BITFLIPS: bit-flips were detected and corrected
+ */
+enum {
+ UBI_IO_PEB_EMPTY = 1,
+ UBI_IO_PEB_FREE,
+ UBI_IO_BAD_EC_HDR,
+ UBI_IO_BAD_VID_HDR,
+ UBI_IO_BITFLIPS
+};
+
+/**
+ * struct ubi_wl_entry - wear-leveling entry.
+ * @rb: link in the corresponding RB-tree
+ * @ec: erase counter
+ * @pnum: physical eraseblock number
+ *
+ * This data structure is used in the WL unit. Each physical eraseblock has a
+ * corresponding &struct wl_entry object which may be kept in different
+ * RB-trees. See WL unit for details.
+ */
+struct ubi_wl_entry {
+ struct rb_node rb;
+ int ec;
+ int pnum;
+};
+
+/**
+ * struct ubi_ltree_entry - an entry in the lock tree.
+ * @rb: links RB-tree nodes
+ * @vol_id: volume ID of the locked logical eraseblock
+ * @lnum: locked logical eraseblock number
+ * @users: how many tasks are using this logical eraseblock or wait for it
+ * @mutex: read/write mutex to implement read/write access serialization to
+ * the (@vol_id, @lnum) logical eraseblock
+ *
+ * This data structure is used in the EBA unit to implement per-LEB locking.
+ * When a logical eraseblock is being locked - corresponding
+ * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree).
+ * See EBA unit for details.
+ */
+struct ubi_ltree_entry {
+ struct rb_node rb;
+ int vol_id;
+ int lnum;
+ int users;
+ struct rw_semaphore mutex;
+};
+
+struct ubi_volume_desc;
+
+/**
+ * struct ubi_volume - UBI volume description data structure.
+ * @dev: device object to make use of the the Linux device model
+ * @cdev: character device object to create character device
+ * @ubi: reference to the UBI device description object
+ * @vol_id: volume ID
+ * @ref_count: volume reference count
+ * @readers: number of users holding this volume in read-only mode
+ * @writers: number of users holding this volume in read-write mode
+ * @exclusive: whether somebody holds this volume in exclusive mode
+ *
+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @usable_leb_size: logical eraseblock size without padding
+ * @used_ebs: how many logical eraseblocks in this volume contain data
+ * @last_eb_bytes: how many bytes are stored in the last logical eraseblock
+ * @used_bytes: how many bytes of data this volume contains
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are not used at the end of physical eraseblocks to
+ * satisfy the requested alignment
+ * @name_len: volume name length
+ * @name: volume name
+ *
+ * @upd_ebs: how many eraseblocks are expected to be updated
+ * @ch_lnum: LEB number which is being changing by the atomic LEB change
+ * operation
+ * @ch_dtype: data persistency type which is being changing by the atomic LEB
+ * change operation
+ * @upd_bytes: how many bytes are expected to be received for volume update or
+ * atomic LEB change
+ * @upd_received: how many bytes were already received for volume update or
+ * atomic LEB change
+ * @upd_buf: update buffer which is used to collect update data or data for
+ * atomic LEB change
+ *
+ * @eba_tbl: EBA table of this volume (LEB->PEB mapping)
+ * @checked: %1 if this static volume was checked
+ * @corrupted: %1 if the volume is corrupted (static volumes only)
+ * @upd_marker: %1 if the update marker is set for this volume
+ * @updating: %1 if the volume is being updated
+ * @changing_leb: %1 if the atomic LEB change ioctl command is in progress
+ *
+ * @gluebi_desc: gluebi UBI volume descriptor
+ * @gluebi_refcount: reference count of the gluebi MTD device
+ * @gluebi_mtd: MTD device description object of the gluebi MTD device
+ *
+ * The @corrupted field indicates that the volume's contents is corrupted.
+ * Since UBI protects only static volumes, this field is not relevant to
+ * dynamic volumes - it is user's responsibility to assure their data
+ * integrity.
+ *
+ * The @upd_marker flag indicates that this volume is either being updated at
+ * the moment or is damaged because of an unclean reboot.
+ */
+struct ubi_volume {
+ struct device dev;
+ struct cdev cdev;
+ struct ubi_device *ubi;
+ int vol_id;
+ int ref_count;
+ int readers;
+ int writers;
+ int exclusive;
+
+ int reserved_pebs;
+ int vol_type;
+ int usable_leb_size;
+ int used_ebs;
+ int last_eb_bytes;
+ long long used_bytes;
+ int alignment;
+ int data_pad;
+ int name_len;
+ char name[UBI_VOL_NAME_MAX+1];
+
+ int upd_ebs;
+ int ch_lnum;
+ int ch_dtype;
+ long long upd_bytes;
+ long long upd_received;
+ void *upd_buf;
+
+ int *eba_tbl;
+ unsigned int checked:1;
+ unsigned int corrupted:1;
+ unsigned int upd_marker:1;
+ unsigned int updating:1;
+ unsigned int changing_leb:1;
+
+#ifdef CONFIG_MTD_UBI_GLUEBI
+ /*
+ * Gluebi-related stuff may be compiled out.
+ * TODO: this should not be built into UBI but should be a separate
+ * ubimtd driver which works on top of UBI and emulates MTD devices.
+ */
+ struct ubi_volume_desc *gluebi_desc;
+ int gluebi_refcount;
+ struct mtd_info gluebi_mtd;
+#endif
+};
+
+/**
+ * struct ubi_volume_desc - descriptor of the UBI volume returned when it is
+ * opened.
+ * @vol: reference to the corresponding volume description object
+ * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE)
+ */
+struct ubi_volume_desc {
+ struct ubi_volume *vol;
+ int mode;
+};
+
+struct ubi_wl_entry;
+
+/**
+ * struct ubi_device - UBI device description structure
+ * @dev: UBI device object to use the the Linux device model
+ * @cdev: character device object to create character device
+ * @ubi_num: UBI device number
+ * @ubi_name: UBI device name
+ * @vol_count: number of volumes in this UBI device
+ * @volumes: volumes of this UBI device
+ * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
+ * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
+ * @vol->readers, @vol->writers, @vol->exclusive,
+ * @vol->ref_count, @vol->mapping and @vol->eba_tbl.
+ * @ref_count: count of references on the UBI device
+ *
+ * @rsvd_pebs: count of reserved physical eraseblocks
+ * @avail_pebs: count of available physical eraseblocks
+ * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB
+ * handling
+ * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling
+ *
+ * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end
+ * of UBI ititializetion
+ * @vtbl_slots: how many slots are available in the volume table
+ * @vtbl_size: size of the volume table in bytes
+ * @vtbl: in-RAM volume table copy
+ * @volumes_mutex: protects on-flash volume table and serializes volume
+ * changes, like creation, deletion, update, resize
+ *
+ * @max_ec: current highest erase counter value
+ * @mean_ec: current mean erase counter value
+ *
+ * @global_sqnum: global sequence number
+ * @ltree_lock: protects the lock tree and @global_sqnum
+ * @ltree: the lock tree
+ * @alc_mutex: serializes "atomic LEB change" operations
+ *
+ * @used: RB-tree of used physical eraseblocks
+ * @free: RB-tree of free physical eraseblocks
+ * @scrub: RB-tree of physical eraseblocks which need scrubbing
+ * @prot: protection trees
+ * @prot.pnum: protection tree indexed by physical eraseblock numbers
+ * @prot.aec: protection tree indexed by absolute erase counter value
+ * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from,
+ * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works
+ * fields
+ * @move_mutex: serializes eraseblock moves
+ * @wl_scheduled: non-zero if the wear-leveling was scheduled
+ * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any
+ * physical eraseblock
+ * @abs_ec: absolute erase counter
+ * @move_from: physical eraseblock from where the data is being moved
+ * @move_to: physical eraseblock where the data is being moved to
+ * @move_to_put: if the "to" PEB was put
+ * @works: list of pending works
+ * @works_count: count of pending works
+ * @bgt_thread: background thread description object
+ * @thread_enabled: if the background thread is enabled
+ * @bgt_name: background thread name
+ *
+ * @flash_size: underlying MTD device size (in bytes)
+ * @peb_count: count of physical eraseblocks on the MTD device
+ * @peb_size: physical eraseblock size
+ * @bad_peb_count: count of bad physical eraseblocks
+ * @good_peb_count: count of good physical eraseblocks
+ * @min_io_size: minimal input/output unit size of the underlying MTD device
+ * @hdrs_min_io_size: minimal I/O unit size used for VID and EC headers
+ * @ro_mode: if the UBI device is in read-only mode
+ * @leb_size: logical eraseblock size
+ * @leb_start: starting offset of logical eraseblocks within physical
+ * eraseblocks
+ * @ec_hdr_alsize: size of the EC header aligned to @hdrs_min_io_size
+ * @vid_hdr_alsize: size of the VID header aligned to @hdrs_min_io_size
+ * @vid_hdr_offset: starting offset of the volume identifier header (might be
+ * unaligned)
+ * @vid_hdr_aloffset: starting offset of the VID header aligned to
+ * @hdrs_min_io_size
+ * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
+ * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
+ * not
+ * @mtd: MTD device descriptor
+ *
+ * @peb_buf1: a buffer of PEB size used for different purposes
+ * @peb_buf2: another buffer of PEB size used for different purposes
+ * @buf_mutex: proptects @peb_buf1 and @peb_buf2
+ * @dbg_peb_buf: buffer of PEB size used for debugging
+ * @dbg_buf_mutex: proptects @dbg_peb_buf
+ */
+struct ubi_device {
+ struct cdev cdev;
+ struct device dev;
+ int ubi_num;
+ char ubi_name[sizeof(UBI_NAME_STR)+5];
+ int vol_count;
+ struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
+ spinlock_t volumes_lock;
+ int ref_count;
+
+ int rsvd_pebs;
+ int avail_pebs;
+ int beb_rsvd_pebs;
+ int beb_rsvd_level;
+
+ int autoresize_vol_id;
+ int vtbl_slots;
+ int vtbl_size;
+ struct ubi_vtbl_record *vtbl;
+ struct mutex volumes_mutex;
+
+ int max_ec;
+ /* TODO: mean_ec is not updated run-time, fix */
+ int mean_ec;
+
+ /* EBA unit's stuff */
+ unsigned long long global_sqnum;
+ spinlock_t ltree_lock;
+ struct rb_root ltree;
+ struct mutex alc_mutex;
+
+ /* Wear-leveling unit's stuff */
+ struct rb_root used;
+ struct rb_root free;
+ struct rb_root scrub;
+ struct {
+ struct rb_root pnum;
+ struct rb_root aec;
+ } prot;
+ spinlock_t wl_lock;
+ struct mutex move_mutex;
+ struct rw_semaphore work_sem;
+ int wl_scheduled;
+ struct ubi_wl_entry **lookuptbl;
+ unsigned long long abs_ec;
+ struct ubi_wl_entry *move_from;
+ struct ubi_wl_entry *move_to;
+ int move_to_put;
+ struct list_head works;
+ int works_count;
+ struct task_struct *bgt_thread;
+ int thread_enabled;
+ char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2];
+
+ /* I/O unit's stuff */
+ long long flash_size;
+ int peb_count;
+ int peb_size;
+ int bad_peb_count;
+ int good_peb_count;
+ int min_io_size;
+ int hdrs_min_io_size;
+ int ro_mode;
+ int leb_size;
+ int leb_start;
+ int ec_hdr_alsize;
+ int vid_hdr_alsize;
+ int vid_hdr_offset;
+ int vid_hdr_aloffset;
+ int vid_hdr_shift;
+ int bad_allowed;
+ struct mtd_info *mtd;
+
+ void *peb_buf1;
+ void *peb_buf2;
+ struct mutex buf_mutex;
+ struct mutex ckvol_mutex;
+#ifdef CONFIG_MTD_UBI_DEBUG
+ void *dbg_peb_buf;
+ struct mutex dbg_buf_mutex;
+#endif
+};
+
+extern struct kmem_cache *ubi_wl_entry_slab;
+extern struct file_operations ubi_ctrl_cdev_operations;
+extern struct file_operations ubi_cdev_operations;
+extern struct file_operations ubi_vol_cdev_operations;
+extern struct class *ubi_class;
+extern struct mutex ubi_devices_mutex;
+
+/* vtbl.c */
+int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
+ struct ubi_vtbl_record *vtbl_rec);
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);
+
+/* vmt.c */
+int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
+int ubi_remove_volume(struct ubi_volume_desc *desc);
+int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs);
+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol);
+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol);
+
+/* upd.c */
+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
+ long long bytes);
+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
+ const void __user *buf, int count);
+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+ const struct ubi_leb_change_req *req);
+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
+ const void __user *buf, int count);
+
+/* misc.c */
+int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length);
+int ubi_check_volume(struct ubi_device *ubi, int vol_id);
+void ubi_calculate_reserved(struct ubi_device *ubi);
+
+/* gluebi.c */
+#ifdef CONFIG_MTD_UBI_GLUEBI
+int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
+int ubi_destroy_gluebi(struct ubi_volume *vol);
+void ubi_gluebi_updated(struct ubi_volume *vol);
+#else
+#define ubi_create_gluebi(ubi, vol) 0
+#define ubi_destroy_gluebi(vol) 0
+#define ubi_gluebi_updated(vol)
+#endif
+
+/* eba.c */
+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
+ int lnum);
+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+ void *buf, int offset, int len, int check);
+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+ const void *buf, int offset, int len, int dtype);
+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
+ int lnum, const void *buf, int len, int dtype,
+ int used_ebs);
+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+ int lnum, const void *buf, int len, int dtype);
+int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+ struct ubi_vid_hdr *vid_hdr);
+int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+void ubi_eba_close(const struct ubi_device *ubi);
+
+/* wl.c */
+int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
+int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture);
+int ubi_wl_flush(struct ubi_device *ubi);
+int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
+int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+void ubi_wl_close(struct ubi_device *ubi);
+int ubi_thread(void *u);
+
+/* io.c */
+int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
+ int len);
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+ int len);
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
+int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
+int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_ec_hdr *ec_hdr, int verbose);
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_ec_hdr *ec_hdr);
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_vid_hdr *vid_hdr, int verbose);
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
+ struct ubi_vid_hdr *vid_hdr);
+
+/* build.c */
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset);
+int ubi_detach_mtd_dev(int ubi_num, int anyway);
+struct ubi_device *ubi_get_device(int ubi_num);
+void ubi_put_device(struct ubi_device *ubi);
+struct ubi_device *ubi_get_by_major(int major);
+int ubi_major2num(int major);
+
+/*
+ * ubi_rb_for_each_entry - walk an RB-tree.
+ * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
+ * @pos: a pointer to RB-tree entry type to use as a loop counter
+ * @root: RB-tree's root
+ * @member: the name of the 'struct rb_node' within the RB-tree entry
+ */
+#define ubi_rb_for_each_entry(rb, pos, root, member) \
+ for (rb = rb_first(root), \
+ pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \
+ rb; \
+ rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member))
+
+/**
+ * ubi_zalloc_vid_hdr - allocate a volume identifier header object.
+ * @ubi: UBI device description object
+ * @gfp_flags: GFP flags to allocate with
+ *
+ * This function returns a pointer to the newly allocated and zero-filled
+ * volume identifier header object in case of success and %NULL in case of
+ * failure.
+ */
+static inline struct ubi_vid_hdr *
+ubi_zalloc_vid_hdr(const struct ubi_device *ubi, gfp_t gfp_flags)
+{
+ void *vid_hdr;
+
+ vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags);
+ if (!vid_hdr)
+ return NULL;
+
+ /*
+ * VID headers may be stored at un-aligned flash offsets, so we shift
+ * the pointer.
+ */
+ return vid_hdr + ubi->vid_hdr_shift;
+}
+
+/**
+ * ubi_free_vid_hdr - free a volume identifier header object.
+ * @ubi: UBI device description object
+ * @vid_hdr: the object to free
+ */
+static inline void ubi_free_vid_hdr(const struct ubi_device *ubi,
+ struct ubi_vid_hdr *vid_hdr)
+{
+ void *p = vid_hdr;
+
+ if (!p)
+ return;
+
+ kfree(p - ubi->vid_hdr_shift);
+}
+
+/*
+ * This function is equivalent to 'ubi_io_read()', but @offset is relative to
+ * the beginning of the logical eraseblock, not to the beginning of the
+ * physical eraseblock.
+ */
+static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf,
+ int pnum, int offset, int len)
+{
+ ubi_assert(offset >= 0);
+ return ubi_io_read(ubi, buf, pnum, offset + ubi->leb_start, len);
+}
+
+/*
+ * This function is equivalent to 'ubi_io_write()', but @offset is relative to
+ * the beginning of the logical eraseblock, not to the beginning of the
+ * physical eraseblock.
+ */
+static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf,
+ int pnum, int offset, int len)
+{
+ ubi_assert(offset >= 0);
+ return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len);
+}
+
+/**
+ * ubi_ro_mode - switch to read-only mode.
+ * @ubi: UBI device description object
+ */
+static inline void ubi_ro_mode(struct ubi_device *ubi)
+{
+ if (!ubi->ro_mode) {
+ ubi->ro_mode = 1;
+ ubi_warn("switch to read-only mode");
+ }
+}
+
+/**
+ * vol_id2idx - get table index by volume ID.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ */
+static inline int vol_id2idx(const struct ubi_device *ubi, int vol_id)
+{
+ if (vol_id >= UBI_INTERNAL_VOL_START)
+ return vol_id - UBI_INTERNAL_VOL_START + ubi->vtbl_slots;
+ else
+ return vol_id;
+}
+
+/**
+ * idx2vol_id - get volume ID by table index.
+ * @ubi: UBI device description object
+ * @idx: table index
+ */
+static inline int idx2vol_id(const struct ubi_device *ubi, int idx)
+{
+ if (idx >= ubi->vtbl_slots)
+ return idx - ubi->vtbl_slots + UBI_INTERNAL_VOL_START;
+ else
+ return idx;
+}
+
+#endif /* !__UBI_UBI_H__ */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
new file mode 100644
index 0000000..5f7ed7b
--- /dev/null
+++ b/drivers/mtd/ubi/upd.c
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ *
+ * Jan 2007: Alexander Schmidt, hacked per-volume update.
+ */
+
+/*
+ * This file contains implementation of the volume update and atomic LEB change
+ * functionality.
+ *
+ * The update operation is based on the per-volume update marker which is
+ * stored in the volume table. The update marker is set before the update
+ * starts, and removed after the update has been finished. So if the update was
+ * interrupted by an unclean re-boot or due to some other reasons, the update
+ * marker stays on the flash media and UBI finds it when it attaches the MTD
+ * device next time. If the update marker is set for a volume, the volume is
+ * treated as damaged and most I/O operations are prohibited. Only a new update
+ * operation is allowed.
+ *
+ * Note, in general it is possible to implement the update operation as a
+ * transaction with a roll-back capability.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+/**
+ * set_update_marker - set update marker.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ *
+ * This function sets the update marker flag for volume @vol. Returns zero
+ * in case of success and a negative error code in case of failure.
+ */
+static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
+{
+ int err;
+ struct ubi_vtbl_record vtbl_rec;
+
+ dbg_msg("set update marker for volume %d", vol->vol_id);
+
+ if (vol->upd_marker) {
+ ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
+ dbg_msg("already set");
+ return 0;
+ }
+
+ memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
+ sizeof(struct ubi_vtbl_record));
+ vtbl_rec.upd_marker = 1;
+
+ mutex_lock(&ubi->volumes_mutex);
+ err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
+ mutex_unlock(&ubi->volumes_mutex);
+ vol->upd_marker = 1;
+ return err;
+}
+
+/**
+ * clear_update_marker - clear update marker.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @bytes: new data size in bytes
+ *
+ * This function clears the update marker for volume @vol, sets new volume
+ * data size and clears the "corrupted" flag (static volumes only). Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
+ long long bytes)
+{
+ int err;
+ uint64_t tmp;
+ struct ubi_vtbl_record vtbl_rec;
+
+ dbg_msg("clear update marker for volume %d", vol->vol_id);
+
+ memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
+ sizeof(struct ubi_vtbl_record));
+ ubi_assert(vol->upd_marker && vtbl_rec.upd_marker);
+ vtbl_rec.upd_marker = 0;
+
+ if (vol->vol_type == UBI_STATIC_VOLUME) {
+ vol->corrupted = 0;
+ vol->used_bytes = tmp = bytes;
+ vol->last_eb_bytes = do_div(tmp, vol->usable_leb_size);
+ vol->used_ebs = tmp;
+ if (vol->last_eb_bytes)
+ vol->used_ebs += 1;
+ else
+ vol->last_eb_bytes = vol->usable_leb_size;
+ }
+
+ mutex_lock(&ubi->volumes_mutex);
+ err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
+ mutex_unlock(&ubi->volumes_mutex);
+ vol->upd_marker = 0;
+ return err;
+}
+
+/**
+ * ubi_start_update - start volume update.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @bytes: update bytes
+ *
+ * This function starts volume update operation. If @bytes is zero, the volume
+ * is just wiped out. Returns zero in case of success and a negative error code
+ * in case of failure.
+ */
+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
+ long long bytes)
+{
+ int i, err;
+ uint64_t tmp;
+
+ dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes);
+ ubi_assert(!vol->updating && !vol->changing_leb);
+ vol->updating = 1;
+
+ err = set_update_marker(ubi, vol);
+ if (err)
+ return err;
+
+ /* Before updating - wipe out the volume */
+ for (i = 0; i < vol->reserved_pebs; i++) {
+ err = ubi_eba_unmap_leb(ubi, vol, i);
+ if (err)
+ return err;
+ }
+
+ if (bytes == 0) {
+ err = clear_update_marker(ubi, vol, 0);
+ if (err)
+ return err;
+ err = ubi_wl_flush(ubi);
+ if (!err)
+ vol->updating = 0;
+ }
+
+ vol->upd_buf = vmalloc(ubi->leb_size);
+ if (!vol->upd_buf)
+ return -ENOMEM;
+
+ tmp = bytes;
+ vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size);
+ vol->upd_ebs += tmp;
+ vol->upd_bytes = bytes;
+ vol->upd_received = 0;
+ return 0;
+}
+
+/**
+ * ubi_start_leb_change - start atomic LEB change.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @req: operation request
+ *
+ * This function starts atomic LEB change operation. Returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+ const struct ubi_leb_change_req *req)
+{
+ ubi_assert(!vol->updating && !vol->changing_leb);
+
+ dbg_msg("start changing LEB %d:%d, %u bytes",
+ vol->vol_id, req->lnum, req->bytes);
+ if (req->bytes == 0)
+ return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
+ req->dtype);
+
+ vol->upd_bytes = req->bytes;
+ vol->upd_received = 0;
+ vol->changing_leb = 1;
+ vol->ch_lnum = req->lnum;
+ vol->ch_dtype = req->dtype;
+
+ vol->upd_buf = vmalloc(req->bytes);
+ if (!vol->upd_buf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * write_leb - write update data.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @buf: data to write
+ * @len: data size
+ * @used_ebs: how many logical eraseblocks will this volume contain (static
+ * volumes only)
+ *
+ * This function writes update data to corresponding logical eraseblock. In
+ * case of dynamic volume, this function checks if the data contains 0xFF bytes
+ * at the end. If yes, the 0xFF bytes are cut and not written. So if the whole
+ * buffer contains only 0xFF bytes, the LEB is left unmapped.
+ *
+ * The reason why we skip the trailing 0xFF bytes in case of dynamic volume is
+ * that we want to make sure that more data may be appended to the logical
+ * eraseblock in future. Indeed, writing 0xFF bytes may have side effects and
+ * this PEB won't be writable anymore. So if one writes the file-system image
+ * to the UBI volume where 0xFFs mean free space - UBI makes sure this free
+ * space is writable after the update.
+ *
+ * We do not do this for static volumes because they are read-only. But this
+ * also cannot be done because we have to store per-LEB CRC and the correct
+ * data length.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+ void *buf, int len, int used_ebs)
+{
+ int err;
+
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+ int l = ALIGN(len, ubi->min_io_size);
+
+ memset(buf + len, 0xFF, l - len);
+ len = ubi_calc_data_len(ubi, buf, l);
+ if (len == 0) {
+ dbg_msg("all %d bytes contain 0xFF - skip", len);
+ return 0;
+ }
+
+ err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN);
+ } else {
+ /*
+ * When writing static volume, and this is the last logical
+ * eraseblock, the length (@len) does not have to be aligned to
+ * the minimal flash I/O unit. The 'ubi_eba_write_leb_st()'
+ * function accepts exact (unaligned) length and stores it in
+ * the VID header. And it takes care of proper alignment by
+ * padding the buffer. Here we just make sure the padding will
+ * contain zeros, not random trash.
+ */
+ memset(buf + len, 0, vol->usable_leb_size - len);
+ err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len,
+ UBI_UNKNOWN, used_ebs);
+ }
+
+ return err;
+}
+
+/**
+ * ubi_more_update_data - write more update data.
+ * @vol: volume description object
+ * @buf: write data (user-space memory buffer)
+ * @count: how much bytes to write
+ *
+ * This function writes more data to the volume which is being updated. It may
+ * be called arbitrary number of times until all the update data arriveis. This
+ * function returns %0 in case of success, number of bytes written during the
+ * last call if the whole volume update has been successfully finished, and a
+ * negative error code in case of failure.
+ */
+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
+ const void __user *buf, int count)
+{
+ uint64_t tmp;
+ int lnum, offs, err = 0, len, to_write = count;
+
+ dbg_msg("write %d of %lld bytes, %lld already passed",
+ count, vol->upd_bytes, vol->upd_received);
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ tmp = vol->upd_received;
+ offs = do_div(tmp, vol->usable_leb_size);
+ lnum = tmp;
+
+ if (vol->upd_received + count > vol->upd_bytes)
+ to_write = count = vol->upd_bytes - vol->upd_received;
+
+ /*
+ * When updating volumes, we accumulate whole logical eraseblock of
+ * data and write it at once.
+ */
+ if (offs != 0) {
+ /*
+ * This is a write to the middle of the logical eraseblock. We
+ * copy the data to our update buffer and wait for more data or
+ * flush it if the whole eraseblock is written or the update
+ * is finished.
+ */
+
+ len = vol->usable_leb_size - offs;
+ if (len > count)
+ len = count;
+
+ err = copy_from_user(vol->upd_buf + offs, buf, len);
+ if (err)
+ return -EFAULT;
+
+ if (offs + len == vol->usable_leb_size ||
+ vol->upd_received + len == vol->upd_bytes) {
+ int flush_len = offs + len;
+
+ /*
+ * OK, we gathered either the whole eraseblock or this
+ * is the last chunk, it's time to flush the buffer.
+ */
+ ubi_assert(flush_len <= vol->usable_leb_size);
+ err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len,
+ vol->upd_ebs);
+ if (err)
+ return err;
+ }
+
+ vol->upd_received += len;
+ count -= len;
+ buf += len;
+ lnum += 1;
+ }
+
+ /*
+ * If we've got more to write, let's continue. At this point we know we
+ * are starting from the beginning of an eraseblock.
+ */
+ while (count) {
+ if (count > vol->usable_leb_size)
+ len = vol->usable_leb_size;
+ else
+ len = count;
+
+ err = copy_from_user(vol->upd_buf, buf, len);
+ if (err)
+ return -EFAULT;
+
+ if (len == vol->usable_leb_size ||
+ vol->upd_received + len == vol->upd_bytes) {
+ err = write_leb(ubi, vol, lnum, vol->upd_buf,
+ len, vol->upd_ebs);
+ if (err)
+ break;
+ }
+
+ vol->upd_received += len;
+ count -= len;
+ lnum += 1;
+ buf += len;
+ }
+
+ ubi_assert(vol->upd_received <= vol->upd_bytes);
+ if (vol->upd_received == vol->upd_bytes) {
+ /* The update is finished, clear the update marker */
+ err = clear_update_marker(ubi, vol, vol->upd_bytes);
+ if (err)
+ return err;
+ err = ubi_wl_flush(ubi);
+ if (err == 0) {
+ vol->updating = 0;
+ err = to_write;
+ vfree(vol->upd_buf);
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ubi_more_leb_change_data - accept more data for atomic LEB change.
+ * @vol: volume description object
+ * @buf: write data (user-space memory buffer)
+ * @count: how much bytes to write
+ *
+ * This function accepts more data to the volume which is being under the
+ * "atomic LEB change" operation. It may be called arbitrary number of times
+ * until all data arrives. This function returns %0 in case of success, number
+ * of bytes written during the last call if the whole "atomic LEB change"
+ * operation has been successfully finished, and a negative error code in case
+ * of failure.
+ */
+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
+ const void __user *buf, int count)
+{
+ int err;
+
+ dbg_msg("write %d of %lld bytes, %lld already passed",
+ count, vol->upd_bytes, vol->upd_received);
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ if (vol->upd_received + count > vol->upd_bytes)
+ count = vol->upd_bytes - vol->upd_received;
+
+ err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
+ if (err)
+ return -EFAULT;
+
+ vol->upd_received += count;
+
+ if (vol->upd_received == vol->upd_bytes) {
+ int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size);
+
+ memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes);
+ len = ubi_calc_data_len(ubi, vol->upd_buf, len);
+ err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
+ vol->upd_buf, len, UBI_UNKNOWN);
+ if (err)
+ return err;
+ }
+
+ ubi_assert(vol->upd_received <= vol->upd_bytes);
+ if (vol->upd_received == vol->upd_bytes) {
+ vol->changing_leb = 0;
+ err = count;
+ vfree(vol->upd_buf);
+ }
+
+ return err;
+}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
new file mode 100644
index 0000000..061da64
--- /dev/null
+++ b/drivers/mtd/ubi/vmt.c
@@ -0,0 +1,862 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file contains implementation of volume creation, deletion, updating and
+ * resizing.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/err.h>
+#include <asm/div64.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static void paranoid_check_volumes(struct ubi_device *ubi);
+#else
+#define paranoid_check_volumes(ubi)
+#endif
+
+#ifdef UBI_LINUX
+static ssize_t vol_attribute_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+/* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
+static struct device_attribute attr_vol_reserved_ebs =
+ __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute attr_vol_type =
+ __ATTR(type, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute attr_vol_name =
+ __ATTR(name, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute attr_vol_corrupted =
+ __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute attr_vol_alignment =
+ __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute attr_vol_usable_eb_size =
+ __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute attr_vol_data_bytes =
+ __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute attr_vol_upd_marker =
+ __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
+
+/*
+ * "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'.
+ *
+ * Consider a situation:
+ * A. process 1 opens a sysfs file related to volume Y, say
+ * /<sysfs>/class/ubi/ubiX_Y/reserved_ebs;
+ * B. process 2 removes volume Y;
+ * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file;
+ *
+ * In this situation, this function will return %-ENODEV because it will find
+ * out that the volume was removed from the @ubi->volumes array.
+ */
+static ssize_t vol_attribute_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
+ struct ubi_device *ubi;
+
+ ubi = ubi_get_device(vol->ubi->ubi_num);
+ if (!ubi)
+ return -ENODEV;
+
+ spin_lock(&ubi->volumes_lock);
+ if (!ubi->volumes[vol->vol_id]) {
+ spin_unlock(&ubi->volumes_lock);
+ ubi_put_device(ubi);
+ return -ENODEV;
+ }
+ /* Take a reference to prevent volume removal */
+ vol->ref_count += 1;
+ spin_unlock(&ubi->volumes_lock);
+
+ if (attr == &attr_vol_reserved_ebs)
+ ret = sprintf(buf, "%d\n", vol->reserved_pebs);
+ else if (attr == &attr_vol_type) {
+ const char *tp;
+
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ tp = "dynamic";
+ else
+ tp = "static";
+ ret = sprintf(buf, "%s\n", tp);
+ } else if (attr == &attr_vol_name)
+ ret = sprintf(buf, "%s\n", vol->name);
+ else if (attr == &attr_vol_corrupted)
+ ret = sprintf(buf, "%d\n", vol->corrupted);
+ else if (attr == &attr_vol_alignment)
+ ret = sprintf(buf, "%d\n", vol->alignment);
+ else if (attr == &attr_vol_usable_eb_size)
+ ret = sprintf(buf, "%d\n", vol->usable_leb_size);
+ else if (attr == &attr_vol_data_bytes)
+ ret = sprintf(buf, "%lld\n", vol->used_bytes);
+ else if (attr == &attr_vol_upd_marker)
+ ret = sprintf(buf, "%d\n", vol->upd_marker);
+ else
+ /* This must be a bug */
+ ret = -EINVAL;
+
+ /* We've done the operation, drop volume and UBI device references */
+ spin_lock(&ubi->volumes_lock);
+ vol->ref_count -= 1;
+ ubi_assert(vol->ref_count >= 0);
+ spin_unlock(&ubi->volumes_lock);
+ ubi_put_device(ubi);
+ return ret;
+}
+#endif
+
+/* Release method for volume devices */
+static void vol_release(struct device *dev)
+{
+ struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
+
+ kfree(vol);
+}
+
+#ifdef UBI_LINUX
+/**
+ * volume_sysfs_init - initialize sysfs for new volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ *
+ * Note, this function does not free allocated resources in case of failure -
+ * the caller does it. This is because this would cause release() here and the
+ * caller would oops.
+ */
+static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
+{
+ int err;
+
+ err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
+ if (err)
+ return err;
+ err = device_create_file(&vol->dev, &attr_vol_type);
+ if (err)
+ return err;
+ err = device_create_file(&vol->dev, &attr_vol_name);
+ if (err)
+ return err;
+ err = device_create_file(&vol->dev, &attr_vol_corrupted);
+ if (err)
+ return err;
+ err = device_create_file(&vol->dev, &attr_vol_alignment);
+ if (err)
+ return err;
+ err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
+ if (err)
+ return err;
+ err = device_create_file(&vol->dev, &attr_vol_data_bytes);
+ if (err)
+ return err;
+ err = device_create_file(&vol->dev, &attr_vol_upd_marker);
+ return err;
+}
+
+/**
+ * volume_sysfs_close - close sysfs for a volume.
+ * @vol: volume description object
+ */
+static void volume_sysfs_close(struct ubi_volume *vol)
+{
+ device_remove_file(&vol->dev, &attr_vol_upd_marker);
+ device_remove_file(&vol->dev, &attr_vol_data_bytes);
+ device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
+ device_remove_file(&vol->dev, &attr_vol_alignment);
+ device_remove_file(&vol->dev, &attr_vol_corrupted);
+ device_remove_file(&vol->dev, &attr_vol_name);
+ device_remove_file(&vol->dev, &attr_vol_type);
+ device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
+ device_unregister(&vol->dev);
+}
+#endif
+
+/**
+ * ubi_create_volume - create volume.
+ * @ubi: UBI device description object
+ * @req: volume creation request
+ *
+ * This function creates volume described by @req. If @req->vol_id id
+ * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume
+ * and saves it in @req->vol_id. Returns zero in case of success and a negative
+ * error code in case of failure. Note, the caller has to have the
+ * @ubi->volumes_mutex locked.
+ */
+int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
+{
+ int i, err, vol_id = req->vol_id, dont_free = 0;
+ struct ubi_volume *vol;
+ struct ubi_vtbl_record vtbl_rec;
+ uint64_t bytes;
+ dev_t dev;
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
+ if (!vol)
+ return -ENOMEM;
+
+ spin_lock(&ubi->volumes_lock);
+ if (vol_id == UBI_VOL_NUM_AUTO) {
+ /* Find unused volume ID */
+ dbg_msg("search for vacant volume ID");
+ for (i = 0; i < ubi->vtbl_slots; i++)
+ if (!ubi->volumes[i]) {
+ vol_id = i;
+ break;
+ }
+
+ if (vol_id == UBI_VOL_NUM_AUTO) {
+ dbg_err("out of volume IDs");
+ err = -ENFILE;
+ goto out_unlock;
+ }
+ req->vol_id = vol_id;
+ }
+
+ dbg_msg("volume ID %d, %llu bytes, type %d, name %s",
+ vol_id, (unsigned long long)req->bytes,
+ (int)req->vol_type, req->name);
+
+ /* Ensure that this volume does not exist */
+ err = -EEXIST;
+ if (ubi->volumes[vol_id]) {
+ dbg_err("volume %d already exists", vol_id);
+ goto out_unlock;
+ }
+
+ /* Ensure that the name is unique */
+ for (i = 0; i < ubi->vtbl_slots; i++)
+ if (ubi->volumes[i] &&
+ ubi->volumes[i]->name_len == req->name_len &&
+ !strcmp(ubi->volumes[i]->name, req->name)) {
+ dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
+ goto out_unlock;
+ }
+
+ /* Calculate how many eraseblocks are requested */
+ vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
+ bytes = req->bytes;
+ if (do_div(bytes, vol->usable_leb_size))
+ vol->reserved_pebs = 1;
+ vol->reserved_pebs += bytes;
+
+ /* Reserve physical eraseblocks */
+ if (vol->reserved_pebs > ubi->avail_pebs) {
+ dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+ ubi->avail_pebs -= vol->reserved_pebs;
+ ubi->rsvd_pebs += vol->reserved_pebs;
+ spin_unlock(&ubi->volumes_lock);
+
+ vol->vol_id = vol_id;
+ vol->alignment = req->alignment;
+ vol->data_pad = ubi->leb_size % vol->alignment;
+ vol->vol_type = req->vol_type;
+ vol->name_len = req->name_len;
+ memcpy(vol->name, req->name, vol->name_len + 1);
+ vol->ubi = ubi;
+
+ /*
+ * Finish all pending erases because there may be some LEBs belonging
+ * to the same volume ID.
+ */
+ err = ubi_wl_flush(ubi);
+ if (err)
+ goto out_acc;
+
+ vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL);
+ if (!vol->eba_tbl) {
+ err = -ENOMEM;
+ goto out_acc;
+ }
+
+ for (i = 0; i < vol->reserved_pebs; i++)
+ vol->eba_tbl[i] = UBI_LEB_UNMAPPED;
+
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+ vol->used_ebs = vol->reserved_pebs;
+ vol->last_eb_bytes = vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
+ } else {
+ bytes = vol->used_bytes;
+ vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
+ vol->used_ebs = bytes;
+ if (vol->last_eb_bytes)
+ vol->used_ebs += 1;
+ else
+ vol->last_eb_bytes = vol->usable_leb_size;
+ }
+
+ /* Register character device for the volume */
+ cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
+ vol->cdev.owner = THIS_MODULE;
+ dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
+ err = cdev_add(&vol->cdev, dev, 1);
+ if (err) {
+ ubi_err("cannot add character device");
+ goto out_mapping;
+ }
+
+ err = ubi_create_gluebi(ubi, vol);
+ if (err)
+ goto out_cdev;
+
+ vol->dev.release = vol_release;
+ vol->dev.parent = &ubi->dev;
+ vol->dev.devt = dev;
+ vol->dev.class = ubi_class;
+
+ sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
+ err = device_register(&vol->dev);
+ if (err) {
+ ubi_err("cannot register device");
+ goto out_gluebi;
+ }
+
+ err = volume_sysfs_init(ubi, vol);
+ if (err)
+ goto out_sysfs;
+
+ /* Fill volume table record */
+ memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
+ vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
+ vtbl_rec.alignment = cpu_to_be32(vol->alignment);
+ vtbl_rec.data_pad = cpu_to_be32(vol->data_pad);
+ vtbl_rec.name_len = cpu_to_be16(vol->name_len);
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ vtbl_rec.vol_type = UBI_VID_DYNAMIC;
+ else
+ vtbl_rec.vol_type = UBI_VID_STATIC;
+ memcpy(vtbl_rec.name, vol->name, vol->name_len + 1);
+
+ err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+ if (err)
+ goto out_sysfs;
+
+ spin_lock(&ubi->volumes_lock);
+ ubi->volumes[vol_id] = vol;
+ ubi->vol_count += 1;
+ spin_unlock(&ubi->volumes_lock);
+
+ paranoid_check_volumes(ubi);
+ return 0;
+
+out_sysfs:
+ /*
+ * We have registered our device, we should not free the volume*
+ * description object in this function in case of an error - it is
+ * freed by the release function.
+ *
+ * Get device reference to prevent the release function from being
+ * called just after sysfs has been closed.
+ */
+ dont_free = 1;
+ get_device(&vol->dev);
+ volume_sysfs_close(vol);
+out_gluebi:
+ if (ubi_destroy_gluebi(vol))
+ dbg_err("cannot destroy gluebi for volume %d:%d",
+ ubi->ubi_num, vol_id);
+out_cdev:
+ cdev_del(&vol->cdev);
+out_mapping:
+ kfree(vol->eba_tbl);
+out_acc:
+ spin_lock(&ubi->volumes_lock);
+ ubi->rsvd_pebs -= vol->reserved_pebs;
+ ubi->avail_pebs += vol->reserved_pebs;
+out_unlock:
+ spin_unlock(&ubi->volumes_lock);
+ if (dont_free)
+ put_device(&vol->dev);
+ else
+ kfree(vol);
+ ubi_err("cannot create volume %d, error %d", vol_id, err);
+ return err;
+}
+
+/**
+ * ubi_remove_volume - remove volume.
+ * @desc: volume descriptor
+ *
+ * This function removes volume described by @desc. The volume has to be opened
+ * in "exclusive" mode. Returns zero in case of success and a negative error
+ * code in case of failure. The caller has to have the @ubi->volumes_mutex
+ * locked.
+ */
+int ubi_remove_volume(struct ubi_volume_desc *desc)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs;
+
+ dbg_msg("remove UBI volume %d", vol_id);
+ ubi_assert(desc->mode == UBI_EXCLUSIVE);
+ ubi_assert(vol == ubi->volumes[vol_id]);
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ spin_lock(&ubi->volumes_lock);
+ if (vol->ref_count > 1) {
+ /*
+ * The volume is busy, probably someone is reading one of its
+ * sysfs files.
+ */
+ err = -EBUSY;
+ goto out_unlock;
+ }
+ ubi->volumes[vol_id] = NULL;
+ spin_unlock(&ubi->volumes_lock);
+
+ err = ubi_destroy_gluebi(vol);
+ if (err)
+ goto out_err;
+
+ err = ubi_change_vtbl_record(ubi, vol_id, NULL);
+ if (err)
+ goto out_err;
+
+ for (i = 0; i < vol->reserved_pebs; i++) {
+ err = ubi_eba_unmap_leb(ubi, vol, i);
+ if (err)
+ goto out_err;
+ }
+
+ kfree(vol->eba_tbl);
+ vol->eba_tbl = NULL;
+ cdev_del(&vol->cdev);
+ volume_sysfs_close(vol);
+
+ spin_lock(&ubi->volumes_lock);
+ ubi->rsvd_pebs -= reserved_pebs;
+ ubi->avail_pebs += reserved_pebs;
+ i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
+ if (i > 0) {
+ i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
+ ubi->avail_pebs -= i;
+ ubi->rsvd_pebs += i;
+ ubi->beb_rsvd_pebs += i;
+ if (i > 0)
+ ubi_msg("reserve more %d PEBs", i);
+ }
+ ubi->vol_count -= 1;
+ spin_unlock(&ubi->volumes_lock);
+
+ paranoid_check_volumes(ubi);
+ return 0;
+
+out_err:
+ ubi_err("cannot remove volume %d, error %d", vol_id, err);
+ spin_lock(&ubi->volumes_lock);
+ ubi->volumes[vol_id] = vol;
+out_unlock:
+ spin_unlock(&ubi->volumes_lock);
+ return err;
+}
+
+/**
+ * ubi_resize_volume - re-size volume.
+ * @desc: volume descriptor
+ * @reserved_pebs: new size in physical eraseblocks
+ *
+ * This function re-sizes the volume and returns zero in case of success, and a
+ * negative error code in case of failure. The caller has to have the
+ * @ubi->volumes_mutex locked.
+ */
+int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
+{
+ int i, err, pebs, *new_mapping;
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ struct ubi_vtbl_record vtbl_rec;
+ int vol_id = vol->vol_id;
+
+ if (ubi->ro_mode)
+ return -EROFS;
+
+ dbg_msg("re-size volume %d to from %d to %d PEBs",
+ vol_id, vol->reserved_pebs, reserved_pebs);
+
+ if (vol->vol_type == UBI_STATIC_VOLUME &&
+ reserved_pebs < vol->used_ebs) {
+ dbg_err("too small size %d, %d LEBs contain data",
+ reserved_pebs, vol->used_ebs);
+ return -EINVAL;
+ }
+
+ /* If the size is the same, we have nothing to do */
+ if (reserved_pebs == vol->reserved_pebs)
+ return 0;
+
+ new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL);
+ if (!new_mapping)
+ return -ENOMEM;
+
+ for (i = 0; i < reserved_pebs; i++)
+ new_mapping[i] = UBI_LEB_UNMAPPED;
+
+ spin_lock(&ubi->volumes_lock);
+ if (vol->ref_count > 1) {
+ spin_unlock(&ubi->volumes_lock);
+ err = -EBUSY;
+ goto out_free;
+ }
+ spin_unlock(&ubi->volumes_lock);
+
+ /* Reserve physical eraseblocks */
+ pebs = reserved_pebs - vol->reserved_pebs;
+ if (pebs > 0) {
+ spin_lock(&ubi->volumes_lock);
+ if (pebs > ubi->avail_pebs) {
+ dbg_err("not enough PEBs: requested %d, available %d",
+ pebs, ubi->avail_pebs);
+ spin_unlock(&ubi->volumes_lock);
+ err = -ENOSPC;
+ goto out_free;
+ }
+ ubi->avail_pebs -= pebs;
+ ubi->rsvd_pebs += pebs;
+ for (i = 0; i < vol->reserved_pebs; i++)
+ new_mapping[i] = vol->eba_tbl[i];
+ kfree(vol->eba_tbl);
+ vol->eba_tbl = new_mapping;
+ spin_unlock(&ubi->volumes_lock);
+ }
+
+ /* Change volume table record */
+ memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
+ vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
+ err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+ if (err)
+ goto out_acc;
+
+ if (pebs < 0) {
+ for (i = 0; i < -pebs; i++) {
+ err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
+ if (err)
+ goto out_acc;
+ }
+ spin_lock(&ubi->volumes_lock);
+ ubi->rsvd_pebs += pebs;
+ ubi->avail_pebs -= pebs;
+ pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
+ if (pebs > 0) {
+ pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs;
+ ubi->avail_pebs -= pebs;
+ ubi->rsvd_pebs += pebs;
+ ubi->beb_rsvd_pebs += pebs;
+ if (pebs > 0)
+ ubi_msg("reserve more %d PEBs", pebs);
+ }
+ for (i = 0; i < reserved_pebs; i++)
+ new_mapping[i] = vol->eba_tbl[i];
+ kfree(vol->eba_tbl);
+ vol->eba_tbl = new_mapping;
+ spin_unlock(&ubi->volumes_lock);
+ }
+
+ vol->reserved_pebs = reserved_pebs;
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+ vol->used_ebs = reserved_pebs;
+ vol->last_eb_bytes = vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
+ }
+
+ paranoid_check_volumes(ubi);
+ return 0;
+
+out_acc:
+ if (pebs > 0) {
+ spin_lock(&ubi->volumes_lock);
+ ubi->rsvd_pebs -= pebs;
+ ubi->avail_pebs += pebs;
+ spin_unlock(&ubi->volumes_lock);
+ }
+out_free:
+ kfree(new_mapping);
+ return err;
+}
+
+/**
+ * ubi_add_volume - add volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ *
+ * This function adds an existing volume and initializes all its data
+ * structures. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
+{
+ int err, vol_id = vol->vol_id;
+ dev_t dev;
+
+ dbg_msg("add volume %d", vol_id);
+ ubi_dbg_dump_vol_info(vol);
+
+ /* Register character device for the volume */
+ cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
+ vol->cdev.owner = THIS_MODULE;
+ dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1);
+ err = cdev_add(&vol->cdev, dev, 1);
+ if (err) {
+ ubi_err("cannot add character device for volume %d, error %d",
+ vol_id, err);
+ return err;
+ }
+
+ err = ubi_create_gluebi(ubi, vol);
+ if (err)
+ goto out_cdev;
+
+ vol->dev.release = vol_release;
+ vol->dev.parent = &ubi->dev;
+ vol->dev.devt = dev;
+ vol->dev.class = ubi_class;
+ sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
+ err = device_register(&vol->dev);
+ if (err)
+ goto out_gluebi;
+
+ err = volume_sysfs_init(ubi, vol);
+ if (err) {
+ cdev_del(&vol->cdev);
+ err = ubi_destroy_gluebi(vol);
+ volume_sysfs_close(vol);
+ return err;
+ }
+
+ paranoid_check_volumes(ubi);
+ return 0;
+
+out_gluebi:
+ err = ubi_destroy_gluebi(vol);
+out_cdev:
+ cdev_del(&vol->cdev);
+ return err;
+}
+
+/**
+ * ubi_free_volume - free volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ *
+ * This function frees all resources for volume @vol but does not remove it.
+ * Used only when the UBI device is detached.
+ */
+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
+{
+ int err;
+
+ dbg_msg("free volume %d", vol->vol_id);
+
+ ubi->volumes[vol->vol_id] = NULL;
+ err = ubi_destroy_gluebi(vol);
+ cdev_del(&vol->cdev);
+ volume_sysfs_close(vol);
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_volume - check volume information.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ */
+static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
+{
+ int idx = vol_id2idx(ubi, vol_id);
+ int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
+ const struct ubi_volume *vol;
+ long long n;
+ const char *name;
+
+ spin_lock(&ubi->volumes_lock);
+ reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+ vol = ubi->volumes[idx];
+
+ if (!vol) {
+ if (reserved_pebs) {
+ ubi_err("no volume info, but volume exists");
+ goto fail;
+ }
+ spin_unlock(&ubi->volumes_lock);
+ return;
+ }
+
+ if (vol->exclusive) {
+ /*
+ * The volume may be being created at the moment, do not check
+ * it (e.g., it may be in the middle of ubi_create_volume().
+ */
+ spin_unlock(&ubi->volumes_lock);
+ return;
+ }
+
+ if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 ||
+ vol->name_len < 0) {
+ ubi_err("negative values");
+ goto fail;
+ }
+ if (vol->alignment > ubi->leb_size || vol->alignment == 0) {
+ ubi_err("bad alignment");
+ goto fail;
+ }
+
+ n = vol->alignment & (ubi->min_io_size - 1);
+ if (vol->alignment != 1 && n) {
+ ubi_err("alignment is not multiple of min I/O unit");
+ goto fail;
+ }
+
+ n = ubi->leb_size % vol->alignment;
+ if (vol->data_pad != n) {
+ ubi_err("bad data_pad, has to be %lld", n);
+ goto fail;
+ }
+
+ if (vol->vol_type != UBI_DYNAMIC_VOLUME &&
+ vol->vol_type != UBI_STATIC_VOLUME) {
+ ubi_err("bad vol_type");
+ goto fail;
+ }
+
+ if (vol->upd_marker && vol->corrupted) {
+ dbg_err("update marker and corrupted simultaneously");
+ goto fail;
+ }
+
+ if (vol->reserved_pebs > ubi->good_peb_count) {
+ ubi_err("too large reserved_pebs");
+ goto fail;
+ }
+
+ n = ubi->leb_size - vol->data_pad;
+ if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) {
+ ubi_err("bad usable_leb_size, has to be %lld", n);
+ goto fail;
+ }
+
+ if (vol->name_len > UBI_VOL_NAME_MAX) {
+ ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX);
+ goto fail;
+ }
+
+ if (!vol->name) {
+ ubi_err("NULL volume name");
+ goto fail;
+ }
+
+ n = strnlen(vol->name, vol->name_len + 1);
+ if (n != vol->name_len) {
+ ubi_err("bad name_len %lld", n);
+ goto fail;
+ }
+
+ n = (long long)vol->used_ebs * vol->usable_leb_size;
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+ if (vol->corrupted) {
+ ubi_err("corrupted dynamic volume");
+ goto fail;
+ }
+ if (vol->used_ebs != vol->reserved_pebs) {
+ ubi_err("bad used_ebs");
+ goto fail;
+ }
+ if (vol->last_eb_bytes != vol->usable_leb_size) {
+ ubi_err("bad last_eb_bytes");
+ goto fail;
+ }
+ if (vol->used_bytes != n) {
+ ubi_err("bad used_bytes");
+ goto fail;
+ }
+ } else {
+ if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
+ ubi_err("bad used_ebs");
+ goto fail;
+ }
+ if (vol->last_eb_bytes < 0 ||
+ vol->last_eb_bytes > vol->usable_leb_size) {
+ ubi_err("bad last_eb_bytes");
+ goto fail;
+ }
+ if (vol->used_bytes < 0 || vol->used_bytes > n ||
+ vol->used_bytes < n - vol->usable_leb_size) {
+ ubi_err("bad used_bytes");
+ goto fail;
+ }
+ }
+
+ alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment);
+ data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
+ name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len);
+ upd_marker = ubi->vtbl[vol_id].upd_marker;
+ name = &ubi->vtbl[vol_id].name[0];
+ if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
+ vol_type = UBI_DYNAMIC_VOLUME;
+ else
+ vol_type = UBI_STATIC_VOLUME;
+
+ if (alignment != vol->alignment || data_pad != vol->data_pad ||
+ upd_marker != vol->upd_marker || vol_type != vol->vol_type ||
+ name_len!= vol->name_len || strncmp(name, vol->name, name_len)) {
+ ubi_err("volume info is different");
+ goto fail;
+ }
+
+ spin_unlock(&ubi->volumes_lock);
+ return;
+
+fail:
+ ubi_err("paranoid check failed for volume %d", vol_id);
+ ubi_dbg_dump_vol_info(vol);
+ ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+ spin_unlock(&ubi->volumes_lock);
+ BUG();
+}
+
+/**
+ * paranoid_check_volumes - check information about all volumes.
+ * @ubi: UBI device description object
+ */
+static void paranoid_check_volumes(struct ubi_device *ubi)
+{
+ int i;
+
+ for (i = 0; i < ubi->vtbl_slots; i++)
+ paranoid_check_volume(ubi, i);
+}
+#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
new file mode 100644
index 0000000..9264ac6
--- /dev/null
+++ b/drivers/mtd/ubi/vtbl.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2006, 2007
+ *
+ * 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
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file includes volume table manipulation code. The volume table is an
+ * on-flash table containing volume meta-data like name, number of reserved
+ * physical eraseblocks, type, etc. The volume table is stored in the so-called
+ * "layout volume".
+ *
+ * The layout volume is an internal volume which is organized as follows. It
+ * consists of two logical eraseblocks - LEB 0 and LEB 1. Each logical
+ * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each
+ * other. This redundancy guarantees robustness to unclean reboots. The volume
+ * table is basically an array of volume table records. Each record contains
+ * full information about the volume and protected by a CRC checksum.
+ *
+ * The volume table is changed, it is first changed in RAM. Then LEB 0 is
+ * erased, and the updated volume table is written back to LEB 0. Then same for
+ * LEB 1. This scheme guarantees recoverability from unclean reboots.
+ *
+ * In this UBI implementation the on-flash volume table does not contain any
+ * information about how many data static volumes contain. This information may
+ * be found from the scanning data.
+ *
+ * But it would still be beneficial to store this information in the volume
+ * table. For example, suppose we have a static volume X, and all its physical
+ * eraseblocks became bad for some reasons. Suppose we are attaching the
+ * corresponding MTD device, the scanning has found no logical eraseblocks
+ * corresponding to the volume X. According to the volume table volume X does
+ * exist. So we don't know whether it is just empty or all its physical
+ * eraseblocks went bad. So we cannot alarm the user about this corruption.
+ *
+ * The volume table also stores so-called "update marker", which is used for
+ * volume updates. Before updating the volume, the update marker is set, and
+ * after the update operation is finished, the update marker is cleared. So if
+ * the update operation was interrupted (e.g. by an unclean reboot) - the
+ * update marker is still there and we know that the volume's contents is
+ * damaged.
+ */
+
+#ifdef UBI_LINUX
+#include <linux/crc32.h>
+#include <linux/err.h>
+#include <asm/div64.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static void paranoid_vtbl_check(const struct ubi_device *ubi);
+#else
+#define paranoid_vtbl_check(ubi)
+#endif
+
+/* Empty volume table record */
+static struct ubi_vtbl_record empty_vtbl_record;
+
+/**
+ * ubi_change_vtbl_record - change volume table record.
+ * @ubi: UBI device description object
+ * @idx: table index to change
+ * @vtbl_rec: new volume table record
+ *
+ * This function changes volume table record @idx. If @vtbl_rec is %NULL, empty
+ * volume table record is written. The caller does not have to calculate CRC of
+ * the record as it is done by this function. Returns zero in case of success
+ * and a negative error code in case of failure.
+ */
+int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
+ struct ubi_vtbl_record *vtbl_rec)
+{
+ int i, err;
+ uint32_t crc;
+ struct ubi_volume *layout_vol;
+
+ ubi_assert(idx >= 0 && idx < ubi->vtbl_slots);
+ layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
+
+ if (!vtbl_rec)
+ vtbl_rec = &empty_vtbl_record;
+ else {
+ crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl_rec->crc = cpu_to_be32(crc);
+ }
+
+ memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
+ for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
+ err = ubi_eba_unmap_leb(ubi, layout_vol, i);
+ if (err)
+ return err;
+
+ err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
+ ubi->vtbl_size, UBI_LONGTERM);
+ if (err)
+ return err;
+ }
+
+ paranoid_vtbl_check(ubi);
+ return 0;
+}
+
+/**
+ * vtbl_check - check if volume table is not corrupted and contains sensible
+ * data.
+ * @ubi: UBI device description object
+ * @vtbl: volume table
+ *
+ * This function returns zero if @vtbl is all right, %1 if CRC is incorrect,
+ * and %-EINVAL if it contains inconsistent data.
+ */
+static int vtbl_check(const struct ubi_device *ubi,
+ const struct ubi_vtbl_record *vtbl)
+{
+ int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len;
+ int upd_marker, err;
+ uint32_t crc;
+ const char *name;
+
+ for (i = 0; i < ubi->vtbl_slots; i++) {
+ cond_resched();
+
+ reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ alignment = be32_to_cpu(vtbl[i].alignment);
+ data_pad = be32_to_cpu(vtbl[i].data_pad);
+ upd_marker = vtbl[i].upd_marker;
+ vol_type = vtbl[i].vol_type;
+ name_len = be16_to_cpu(vtbl[i].name_len);
+ name = (const char *) &vtbl[i].name[0];
+
+ crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
+ if (be32_to_cpu(vtbl[i].crc) != crc) {
+ ubi_err("bad CRC at record %u: %#08x, not %#08x",
+ i, crc, be32_to_cpu(vtbl[i].crc));
+ ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+ return 1;
+ }
+
+ if (reserved_pebs == 0) {
+ if (memcmp(&vtbl[i], &empty_vtbl_record,
+ UBI_VTBL_RECORD_SIZE)) {
+ err = 2;
+ goto bad;
+ }
+ continue;
+ }
+
+ if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 ||
+ name_len < 0) {
+ err = 3;
+ goto bad;
+ }
+
+ if (alignment > ubi->leb_size || alignment == 0) {
+ err = 4;
+ goto bad;
+ }
+
+ n = alignment & (ubi->min_io_size - 1);
+ if (alignment != 1 && n) {
+ err = 5;
+ goto bad;
+ }
+
+ n = ubi->leb_size % alignment;
+ if (data_pad != n) {
+ dbg_err("bad data_pad, has to be %d", n);
+ err = 6;
+ goto bad;
+ }
+
+ if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
+ err = 7;
+ goto bad;
+ }
+
+ if (upd_marker != 0 && upd_marker != 1) {
+ err = 8;
+ goto bad;
+ }
+
+ if (reserved_pebs > ubi->good_peb_count) {
+ dbg_err("too large reserved_pebs, good PEBs %d",
+ ubi->good_peb_count);
+ err = 9;
+ goto bad;
+ }
+
+ if (name_len > UBI_VOL_NAME_MAX) {
+ err = 10;
+ goto bad;
+ }
+
+ if (name[0] == '\0') {
+ err = 11;
+ goto bad;
+ }
+
+ if (name_len != strnlen(name, name_len + 1)) {
+ err = 12;
+ goto bad;
+ }
+ }
+
+ /* Checks that all names are unique */
+ for (i = 0; i < ubi->vtbl_slots - 1; i++) {
+ for (n = i + 1; n < ubi->vtbl_slots; n++) {
+ int len1 = be16_to_cpu(vtbl[i].name_len);
+ int len2 = be16_to_cpu(vtbl[n].name_len);
+
+ if (len1 > 0 && len1 == len2 &&
+ !strncmp((char *)vtbl[i].name, (char *)vtbl[n].name, len1)) {
+ ubi_err("volumes %d and %d have the same name"
+ " \"%s\"", i, n, vtbl[i].name);
+ ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+ ubi_dbg_dump_vtbl_record(&vtbl[n], n);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+
+bad:
+ ubi_err("volume table check failed: record %d, error %d", i, err);
+ ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+ return -EINVAL;
+}
+
+/**
+ * create_vtbl - create a copy of volume table.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @copy: number of the volume table copy
+ * @vtbl: contents of the volume table
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
+ int copy, void *vtbl)
+{
+ int err, tries = 0;
+ static struct ubi_vid_hdr *vid_hdr;
+ struct ubi_scan_volume *sv;
+ struct ubi_scan_leb *new_seb, *old_seb = NULL;
+
+ ubi_msg("create volume table (copy #%d)", copy + 1);
+
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+ if (!vid_hdr)
+ return -ENOMEM;
+
+ /*
+ * Check if there is a logical eraseblock which would have to contain
+ * this volume table copy was found during scanning. It has to be wiped
+ * out.
+ */
+ sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
+ if (sv)
+ old_seb = ubi_scan_find_seb(sv, copy);
+
+retry:
+ new_seb = ubi_scan_get_free_peb(ubi, si);
+ if (IS_ERR(new_seb)) {
+ err = PTR_ERR(new_seb);
+ goto out_free;
+ }
+
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID);
+ vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
+ vid_hdr->data_size = vid_hdr->used_ebs =
+ vid_hdr->data_pad = cpu_to_be32(0);
+ vid_hdr->lnum = cpu_to_be32(copy);
+ vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+ vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
+
+ /* The EC header is already there, write the VID header */
+ err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
+ if (err)
+ goto write_error;
+
+ /* Write the layout volume contents */
+ err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size);
+ if (err)
+ goto write_error;
+
+ /*
+ * And add it to the scanning information. Don't delete the old
+ * @old_seb as it will be deleted and freed in 'ubi_scan_add_used()'.
+ */
+ err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
+ vid_hdr, 0);
+ kfree(new_seb);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+
+write_error:
+ if (err == -EIO && ++tries <= 5) {
+ /*
+ * Probably this physical eraseblock went bad, try to pick
+ * another one.
+ */
+ list_add_tail(&new_seb->u.list, &si->corr);
+ goto retry;
+ }
+ kfree(new_seb);
+out_free:
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return err;
+
+}
+
+/**
+ * process_lvol - process the layout volume.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @sv: layout volume scanning information
+ *
+ * This function is responsible for reading the layout volume, ensuring it is
+ * not corrupted, and recovering from corruptions if needed. Returns volume
+ * table in case of success and a negative error code in case of failure.
+ */
+static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
+ struct ubi_scan_info *si,
+ struct ubi_scan_volume *sv)
+{
+ int err;
+ struct rb_node *rb;
+ struct ubi_scan_leb *seb;
+ struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL };
+ int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1};
+
+ /*
+ * UBI goes through the following steps when it changes the layout
+ * volume:
+ * a. erase LEB 0;
+ * b. write new data to LEB 0;
+ * c. erase LEB 1;
+ * d. write new data to LEB 1.
+ *
+ * Before the change, both LEBs contain the same data.
+ *
+ * Due to unclean reboots, the contents of LEB 0 may be lost, but there
+ * should LEB 1. So it is OK if LEB 0 is corrupted while LEB 1 is not.
+ * Similarly, LEB 1 may be lost, but there should be LEB 0. And
+ * finally, unclean reboots may result in a situation when neither LEB
+ * 0 nor LEB 1 are corrupted, but they are different. In this case, LEB
+ * 0 contains more recent information.
+ *
+ * So the plan is to first check LEB 0. Then
+ * a. if LEB 0 is OK, it must be containing the most resent data; then
+ * we compare it with LEB 1, and if they are different, we copy LEB
+ * 0 to LEB 1;
+ * b. if LEB 0 is corrupted, but LEB 1 has to be OK, and we copy LEB 1
+ * to LEB 0.
+ */
+
+ dbg_msg("check layout volume");
+
+ /* Read both LEB 0 and LEB 1 into memory */
+ ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
+ leb[seb->lnum] = vmalloc(ubi->vtbl_size);
+ if (!leb[seb->lnum]) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ memset(leb[seb->lnum], 0, ubi->vtbl_size);
+
+ err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
+ ubi->vtbl_size);
+ if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+ /*
+ * Scrub the PEB later. Note, -EBADMSG indicates an
+ * uncorrectable ECC error, but we have our own CRC and
+ * the data will be checked later. If the data is OK,
+ * the PEB will be scrubbed (because we set
+ * seb->scrub). If the data is not OK, the contents of
+ * the PEB will be recovered from the second copy, and
+ * seb->scrub will be cleared in
+ * 'ubi_scan_add_used()'.
+ */
+ seb->scrub = 1;
+ else if (err)
+ goto out_free;
+ }
+
+ err = -EINVAL;
+ if (leb[0]) {
+ leb_corrupted[0] = vtbl_check(ubi, leb[0]);
+ if (leb_corrupted[0] < 0)
+ goto out_free;
+ }
+
+ if (!leb_corrupted[0]) {
+ /* LEB 0 is OK */
+ if (leb[1])
+ leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size);
+ if (leb_corrupted[1]) {
+ ubi_warn("volume table copy #2 is corrupted");
+ err = create_vtbl(ubi, si, 1, leb[0]);
+ if (err)
+ goto out_free;
+ ubi_msg("volume table was restored");
+ }
+
+ /* Both LEB 1 and LEB 2 are OK and consistent */
+ vfree(leb[1]);
+ return leb[0];
+ } else {
+ /* LEB 0 is corrupted or does not exist */
+ if (leb[1]) {
+ leb_corrupted[1] = vtbl_check(ubi, leb[1]);
+ if (leb_corrupted[1] < 0)
+ goto out_free;
+ }
+ if (leb_corrupted[1]) {
+ /* Both LEB 0 and LEB 1 are corrupted */
+ ubi_err("both volume tables are corrupted");
+ goto out_free;
+ }
+
+ ubi_warn("volume table copy #1 is corrupted");
+ err = create_vtbl(ubi, si, 0, leb[1]);
+ if (err)
+ goto out_free;
+ ubi_msg("volume table was restored");
+
+ vfree(leb[0]);
+ return leb[1];
+ }
+
+out_free:
+ vfree(leb[0]);
+ vfree(leb[1]);
+ return ERR_PTR(err);
+}
+
+/**
+ * create_empty_lvol - create empty layout volume.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns volume table contents in case of success and a
+ * negative error code in case of failure.
+ */
+static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
+ struct ubi_scan_info *si)
+{
+ int i;
+ struct ubi_vtbl_record *vtbl;
+
+ vtbl = vmalloc(ubi->vtbl_size);
+ if (!vtbl)
+ return ERR_PTR(-ENOMEM);
+ memset(vtbl, 0, ubi->vtbl_size);
+
+ for (i = 0; i < ubi->vtbl_slots; i++)
+ memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
+
+ for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
+ int err;
+
+ err = create_vtbl(ubi, si, i, vtbl);
+ if (err) {
+ vfree(vtbl);
+ return ERR_PTR(err);
+ }
+ }
+
+ return vtbl;
+}
+
+/**
+ * init_volumes - initialize volume information for existing volumes.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @vtbl: volume table
+ *
+ * This function allocates volume description objects for existing volumes.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
+ const struct ubi_vtbl_record *vtbl)
+{
+ int i, reserved_pebs = 0;
+ struct ubi_scan_volume *sv;
+ struct ubi_volume *vol;
+
+ for (i = 0; i < ubi->vtbl_slots; i++) {
+ cond_resched();
+
+ if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
+ continue; /* Empty record */
+
+ vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
+ if (!vol)
+ return -ENOMEM;
+
+ vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ vol->alignment = be32_to_cpu(vtbl[i].alignment);
+ vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
+ vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
+ UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
+ vol->name_len = be16_to_cpu(vtbl[i].name_len);
+ vol->usable_leb_size = ubi->leb_size - vol->data_pad;
+ memcpy(vol->name, vtbl[i].name, vol->name_len);
+ vol->name[vol->name_len] = '\0';
+ vol->vol_id = i;
+
+ if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
+ /* Auto re-size flag may be set only for one volume */
+ if (ubi->autoresize_vol_id != -1) {
+ ubi_err("more then one auto-resize volume (%d "
+ "and %d)", ubi->autoresize_vol_id, i);
+ kfree(vol);
+ return -EINVAL;
+ }
+
+ ubi->autoresize_vol_id = i;
+ }
+
+ ubi_assert(!ubi->volumes[i]);
+ ubi->volumes[i] = vol;
+ ubi->vol_count += 1;
+ vol->ubi = ubi;
+ reserved_pebs += vol->reserved_pebs;
+
+ /*
+ * In case of dynamic volume UBI knows nothing about how many
+ * data is stored there. So assume the whole volume is used.
+ */
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+ vol->used_ebs = vol->reserved_pebs;
+ vol->last_eb_bytes = vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
+ continue;
+ }
+
+ /* Static volumes only */
+ sv = ubi_scan_find_sv(si, i);
+ if (!sv) {
+ /*
+ * No eraseblocks belonging to this volume found. We
+ * don't actually know whether this static volume is
+ * completely corrupted or just contains no data. And
+ * we cannot know this as long as data size is not
+ * stored on flash. So we just assume the volume is
+ * empty. FIXME: this should be handled.
+ */
+ continue;
+ }
+
+ if (sv->leb_count != sv->used_ebs) {
+ /*
+ * We found a static volume which misses several
+ * eraseblocks. Treat it as corrupted.
+ */
+ ubi_warn("static volume %d misses %d LEBs - corrupted",
+ sv->vol_id, sv->used_ebs - sv->leb_count);
+ vol->corrupted = 1;
+ continue;
+ }
+
+ vol->used_ebs = sv->used_ebs;
+ vol->used_bytes =
+ (long long)(vol->used_ebs - 1) * vol->usable_leb_size;
+ vol->used_bytes += sv->last_data_size;
+ vol->last_eb_bytes = sv->last_data_size;
+ }
+
+ /* And add the layout volume */
+ vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
+ if (!vol)
+ return -ENOMEM;
+
+ vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS;
+ vol->alignment = 1;
+ vol->vol_type = UBI_DYNAMIC_VOLUME;
+ vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1;
+ memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1);
+ vol->usable_leb_size = ubi->leb_size;
+ vol->used_ebs = vol->reserved_pebs;
+ vol->last_eb_bytes = vol->reserved_pebs;
+ vol->used_bytes =
+ (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
+ vol->vol_id = UBI_LAYOUT_VOLUME_ID;
+ vol->ref_count = 1;
+
+ ubi_assert(!ubi->volumes[i]);
+ ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol;
+ reserved_pebs += vol->reserved_pebs;
+ ubi->vol_count += 1;
+ vol->ubi = ubi;
+
+ if (reserved_pebs > ubi->avail_pebs)
+ ubi_err("not enough PEBs, required %d, available %d",
+ reserved_pebs, ubi->avail_pebs);
+ ubi->rsvd_pebs += reserved_pebs;
+ ubi->avail_pebs -= reserved_pebs;
+
+ return 0;
+}
+
+/**
+ * check_sv - check volume scanning information.
+ * @vol: UBI volume description object
+ * @sv: volume scanning information
+ *
+ * This function returns zero if the volume scanning information is consistent
+ * to the data read from the volume tabla, and %-EINVAL if not.
+ */
+static int check_sv(const struct ubi_volume *vol,
+ const struct ubi_scan_volume *sv)
+{
+ int err;
+
+ if (sv->highest_lnum >= vol->reserved_pebs) {
+ err = 1;
+ goto bad;
+ }
+ if (sv->leb_count > vol->reserved_pebs) {
+ err = 2;
+ goto bad;
+ }
+ if (sv->vol_type != vol->vol_type) {
+ err = 3;
+ goto bad;
+ }
+ if (sv->used_ebs > vol->reserved_pebs) {
+ err = 4;
+ goto bad;
+ }
+ if (sv->data_pad != vol->data_pad) {
+ err = 5;
+ goto bad;
+ }
+ return 0;
+
+bad:
+ ubi_err("bad scanning information, error %d", err);
+ ubi_dbg_dump_sv(sv);
+ ubi_dbg_dump_vol_info(vol);
+ return -EINVAL;
+}
+
+/**
+ * check_scanning_info - check that scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * Even though we protect on-flash data by CRC checksums, we still don't trust
+ * the media. This function ensures that scanning information is consistent to
+ * the information read from the volume table. Returns zero if the scanning
+ * information is OK and %-EINVAL if it is not.
+ */
+static int check_scanning_info(const struct ubi_device *ubi,
+ struct ubi_scan_info *si)
+{
+ int err, i;
+ struct ubi_scan_volume *sv;
+ struct ubi_volume *vol;
+
+ if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
+ ubi_err("scanning found %d volumes, maximum is %d + %d",
+ si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
+ return -EINVAL;
+ }
+
+ if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
+ si->highest_vol_id < UBI_INTERNAL_VOL_START) {
+ ubi_err("too large volume ID %d found by scanning",
+ si->highest_vol_id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+ cond_resched();
+
+ sv = ubi_scan_find_sv(si, i);
+ vol = ubi->volumes[i];
+ if (!vol) {
+ if (sv)
+ ubi_scan_rm_volume(si, sv);
+ continue;
+ }
+
+ if (vol->reserved_pebs == 0) {
+ ubi_assert(i < ubi->vtbl_slots);
+
+ if (!sv)
+ continue;
+
+ /*
+ * During scanning we found a volume which does not
+ * exist according to the information in the volume
+ * table. This must have happened due to an unclean
+ * reboot while the volume was being removed. Discard
+ * these eraseblocks.
+ */
+ ubi_msg("finish volume %d removal", sv->vol_id);
+ ubi_scan_rm_volume(si, sv);
+ } else if (sv) {
+ err = check_sv(vol, sv);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ubi_read_volume_table - read volume table.
+ * information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function reads volume table, checks it, recover from errors if needed,
+ * or creates it if needed. Returns zero in case of success and a negative
+ * error code in case of failure.
+ */
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+ int i, err;
+ struct ubi_scan_volume *sv;
+
+ empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
+
+ /*
+ * The number of supported volumes is limited by the eraseblock size
+ * and by the UBI_MAX_VOLUMES constant.
+ */
+ ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE;
+ if (ubi->vtbl_slots > UBI_MAX_VOLUMES)
+ ubi->vtbl_slots = UBI_MAX_VOLUMES;
+
+ ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
+ ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
+
+ sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
+ if (!sv) {
+ /*
+ * No logical eraseblocks belonging to the layout volume were
+ * found. This could mean that the flash is just empty. In
+ * this case we create empty layout volume.
+ *
+ * But if flash is not empty this must be a corruption or the
+ * MTD device just contains garbage.
+ */
+ if (si->is_empty) {
+ ubi->vtbl = create_empty_lvol(ubi, si);
+ if (IS_ERR(ubi->vtbl))
+ return PTR_ERR(ubi->vtbl);
+ } else {
+ ubi_err("the layout volume was not found");
+ return -EINVAL;
+ }
+ } else {
+ if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) {
+ /* This must not happen with proper UBI images */
+ dbg_err("too many LEBs (%d) in layout volume",
+ sv->leb_count);
+ return -EINVAL;
+ }
+
+ ubi->vtbl = process_lvol(ubi, si, sv);
+ if (IS_ERR(ubi->vtbl))
+ return PTR_ERR(ubi->vtbl);
+ }
+
+ ubi->avail_pebs = ubi->good_peb_count;
+
+ /*
+ * The layout volume is OK, initialize the corresponding in-RAM data
+ * structures.
+ */
+ err = init_volumes(ubi, si, ubi->vtbl);
+ if (err)
+ goto out_free;
+
+ /*
+ * Get sure that the scanning information is consistent to the
+ * information stored in the volume table.
+ */
+ err = check_scanning_info(ubi, si);
+ if (err)
+ goto out_free;
+
+ return 0;
+
+out_free:
+ vfree(ubi->vtbl);
+ for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
+ if (ubi->volumes[i]) {
+ kfree(ubi->volumes[i]);
+ ubi->volumes[i] = NULL;
+ }
+ return err;
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_vtbl_check - check volume table.
+ * @ubi: UBI device description object
+ */
+static void paranoid_vtbl_check(const struct ubi_device *ubi)
+{
+ if (vtbl_check(ubi, ubi->vtbl)) {
+ ubi_err("paranoid check failed");
+ BUG();
+ }
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
new file mode 100644
index 0000000..2f9a5e3
--- /dev/null
+++ b/drivers/mtd/ubi/wl.c
@@ -0,0 +1,1670 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём), Thomas Gleixner
+ */
+
+/*
+ * UBI wear-leveling unit.
+ *
+ * This unit is responsible for wear-leveling. It works in terms of physical
+ * eraseblocks and erase counters and knows nothing about logical eraseblocks,
+ * volumes, etc. From this unit's perspective all physical eraseblocks are of
+ * two types - used and free. Used physical eraseblocks are those that were
+ * "get" by the 'ubi_wl_get_peb()' function, and free physical eraseblocks are
+ * those that were put by the 'ubi_wl_put_peb()' function.
+ *
+ * Physical eraseblocks returned by 'ubi_wl_get_peb()' have only erase counter
+ * header. The rest of the physical eraseblock contains only 0xFF bytes.
+ *
+ * When physical eraseblocks are returned to the WL unit by means of the
+ * 'ubi_wl_put_peb()' function, they are scheduled for erasure. The erasure is
+ * done asynchronously in context of the per-UBI device background thread,
+ * which is also managed by the WL unit.
+ *
+ * The wear-leveling is ensured by means of moving the contents of used
+ * physical eraseblocks with low erase counter to free physical eraseblocks
+ * with high erase counter.
+ *
+ * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick
+ * an "optimal" physical eraseblock. For example, when it is known that the
+ * physical eraseblock will be "put" soon because it contains short-term data,
+ * the WL unit may pick a free physical eraseblock with low erase counter, and
+ * so forth.
+ *
+ * If the WL unit fails to erase a physical eraseblock, it marks it as bad.
+ *
+ * This unit is also responsible for scrubbing. If a bit-flip is detected in a
+ * physical eraseblock, it has to be moved. Technically this is the same as
+ * moving it for wear-leveling reasons.
+ *
+ * As it was said, for the UBI unit all physical eraseblocks are either "free"
+ * or "used". Free eraseblock are kept in the @wl->free RB-tree, while used
+ * eraseblocks are kept in a set of different RB-trees: @wl->used,
+ * @wl->prot.pnum, @wl->prot.aec, and @wl->scrub.
+ *
+ * Note, in this implementation, we keep a small in-RAM object for each physical
+ * eraseblock. This is surely not a scalable solution. But it appears to be good
+ * enough for moderately large flashes and it is simple. In future, one may
+ * re-work this unit and make it more scalable.
+ *
+ * At the moment this unit does not utilize the sequence number, which was
+ * introduced relatively recently. But it would be wise to do this because the
+ * sequence number of a logical eraseblock characterizes how old is it. For
+ * example, when we move a PEB with low erase counter, and we need to pick the
+ * target PEB, we pick a PEB with the highest EC if our PEB is "old" and we
+ * pick target PEB with an average EC if our PEB is not very "old". This is a
+ * room for future re-works of the WL unit.
+ *
+ * FIXME: looks too complex, should be simplified (later).
+ */
+
+#ifdef UBI_LINUX
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
+#endif
+
+#include <ubi_uboot.h>
+#include "ubi.h"
+
+/* Number of physical eraseblocks reserved for wear-leveling purposes */
+#define WL_RESERVED_PEBS 1
+
+/*
+ * How many erase cycles are short term, unknown, and long term physical
+ * eraseblocks protected.
+ */
+#define ST_PROTECTION 16
+#define U_PROTECTION 10
+#define LT_PROTECTION 4
+
+/*
+ * Maximum difference between two erase counters. If this threshold is
+ * exceeded, the WL unit starts moving data from used physical eraseblocks with
+ * low erase counter to free physical eraseblocks with high erase counter.
+ */
+#define UBI_WL_THRESHOLD CONFIG_MTD_UBI_WL_THRESHOLD
+
+/*
+ * When a physical eraseblock is moved, the WL unit has to pick the target
+ * physical eraseblock to move to. The simplest way would be just to pick the
+ * one with the highest erase counter. But in certain workloads this could lead
+ * to an unlimited wear of one or few physical eraseblock. Indeed, imagine a
+ * situation when the picked physical eraseblock is constantly erased after the
+ * data is written to it. So, we have a constant which limits the highest erase
+ * counter of the free physical eraseblock to pick. Namely, the WL unit does
+ * not pick eraseblocks with erase counter greater then the lowest erase
+ * counter plus %WL_FREE_MAX_DIFF.
+ */
+#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)
+
+/*
+ * Maximum number of consecutive background thread failures which is enough to
+ * switch to read-only mode.
+ */
+#define WL_MAX_FAILURES 32
+
+/**
+ * struct ubi_wl_prot_entry - PEB protection entry.
+ * @rb_pnum: link in the @wl->prot.pnum RB-tree
+ * @rb_aec: link in the @wl->prot.aec RB-tree
+ * @abs_ec: the absolute erase counter value when the protection ends
+ * @e: the wear-leveling entry of the physical eraseblock under protection
+ *
+ * When the WL unit returns a physical eraseblock, the physical eraseblock is
+ * protected from being moved for some "time". For this reason, the physical
+ * eraseblock is not directly moved from the @wl->free tree to the @wl->used
+ * tree. There is one more tree in between where this physical eraseblock is
+ * temporarily stored (@wl->prot).
+ *
+ * All this protection stuff is needed because:
+ * o we don't want to move physical eraseblocks just after we have given them
+ * to the user; instead, we first want to let users fill them up with data;
+ *
+ * o there is a chance that the user will put the physical eraseblock very
+ * soon, so it makes sense not to move it for some time, but wait; this is
+ * especially important in case of "short term" physical eraseblocks.
+ *
+ * Physical eraseblocks stay protected only for limited time. But the "time" is
+ * measured in erase cycles in this case. This is implemented with help of the
+ * absolute erase counter (@wl->abs_ec). When it reaches certain value, the
+ * physical eraseblocks are moved from the protection trees (@wl->prot.*) to
+ * the @wl->used tree.
+ *
+ * Protected physical eraseblocks are searched by physical eraseblock number
+ * (when they are put) and by the absolute erase counter (to check if it is
+ * time to move them to the @wl->used tree). So there are actually 2 RB-trees
+ * storing the protected physical eraseblocks: @wl->prot.pnum and
+ * @wl->prot.aec. They are referred to as the "protection" trees. The
+ * first one is indexed by the physical eraseblock number. The second one is
+ * indexed by the absolute erase counter. Both trees store
+ * &struct ubi_wl_prot_entry objects.
+ *
+ * Each physical eraseblock has 2 main states: free and used. The former state
+ * corresponds to the @wl->free tree. The latter state is split up on several
+ * sub-states:
+ * o the WL movement is allowed (@wl->used tree);
+ * o the WL movement is temporarily prohibited (@wl->prot.pnum and
+ * @wl->prot.aec trees);
+ * o scrubbing is needed (@wl->scrub tree).
+ *
+ * Depending on the sub-state, wear-leveling entries of the used physical
+ * eraseblocks may be kept in one of those trees.
+ */
+struct ubi_wl_prot_entry {
+ struct rb_node rb_pnum;
+ struct rb_node rb_aec;
+ unsigned long long abs_ec;
+ struct ubi_wl_entry *e;
+};
+
+/**
+ * struct ubi_work - UBI work description data structure.
+ * @list: a link in the list of pending works
+ * @func: worker function
+ * @priv: private data of the worker function
+ *
+ * @e: physical eraseblock to erase
+ * @torture: if the physical eraseblock has to be tortured
+ *
+ * The @func pointer points to the worker function. If the @cancel argument is
+ * not zero, the worker has to free the resources and exit immediately. The
+ * worker has to return zero in case of success and a negative error code in
+ * case of failure.
+ */
+struct ubi_work {
+ struct list_head list;
+ int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
+ /* The below fields are only relevant to erasure works */
+ struct ubi_wl_entry *e;
+ int torture;
+};
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
+static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
+ struct rb_root *root);
+#else
+#define paranoid_check_ec(ubi, pnum, ec) 0
+#define paranoid_check_in_wl_tree(e, root)
+#endif
+
+/**
+ * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
+ * @e: the wear-leveling entry to add
+ * @root: the root of the tree
+ *
+ * Note, we use (erase counter, physical eraseblock number) pairs as keys in
+ * the @ubi->used and @ubi->free RB-trees.
+ */
+static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root)
+{
+ struct rb_node **p, *parent = NULL;
+
+ p = &root->rb_node;
+ while (*p) {
+ struct ubi_wl_entry *e1;
+
+ parent = *p;
+ e1 = rb_entry(parent, struct ubi_wl_entry, rb);
+
+ if (e->ec < e1->ec)
+ p = &(*p)->rb_left;
+ else if (e->ec > e1->ec)
+ p = &(*p)->rb_right;
+ else {
+ ubi_assert(e->pnum != e1->pnum);
+ if (e->pnum < e1->pnum)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+ }
+
+ rb_link_node(&e->rb, parent, p);
+ rb_insert_color(&e->rb, root);
+}
+
+/**
+ * do_work - do one pending work.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int do_work(struct ubi_device *ubi)
+{
+ int err;
+ struct ubi_work *wrk;
+
+ cond_resched();
+
+ /*
+ * @ubi->work_sem is used to synchronize with the workers. Workers take
+ * it in read mode, so many of them may be doing works at a time. But
+ * the queue flush code has to be sure the whole queue of works is
+ * done, and it takes the mutex in write mode.
+ */
+ down_read(&ubi->work_sem);
+ spin_lock(&ubi->wl_lock);
+ if (list_empty(&ubi->works)) {
+ spin_unlock(&ubi->wl_lock);
+ up_read(&ubi->work_sem);
+ return 0;
+ }
+
+ wrk = list_entry(ubi->works.next, struct ubi_work, list);
+ list_del(&wrk->list);
+ ubi->works_count -= 1;
+ ubi_assert(ubi->works_count >= 0);
+ spin_unlock(&ubi->wl_lock);
+
+ /*
+ * Call the worker function. Do not touch the work structure
+ * after this call as it will have been freed or reused by that
+ * time by the worker function.
+ */
+ err = wrk->func(ubi, wrk, 0);
+ if (err)
+ ubi_err("work failed with error code %d", err);
+ up_read(&ubi->work_sem);
+
+ return err;
+}
+
+/**
+ * produce_free_peb - produce a free physical eraseblock.
+ * @ubi: UBI device description object
+ *
+ * This function tries to make a free PEB by means of synchronous execution of
+ * pending works. This may be needed if, for example the background thread is
+ * disabled. Returns zero in case of success and a negative error code in case
+ * of failure.
+ */
+static int produce_free_peb(struct ubi_device *ubi)
+{
+ int err;
+
+ spin_lock(&ubi->wl_lock);
+ while (!ubi->free.rb_node) {
+ spin_unlock(&ubi->wl_lock);
+
+ dbg_wl("do one work synchronously");
+ err = do_work(ubi);
+ if (err)
+ return err;
+
+ spin_lock(&ubi->wl_lock);
+ }
+ spin_unlock(&ubi->wl_lock);
+
+ return 0;
+}
+
+/**
+ * in_wl_tree - check if wear-leveling entry is present in a WL RB-tree.
+ * @e: the wear-leveling entry to check
+ * @root: the root of the tree
+ *
+ * This function returns non-zero if @e is in the @root RB-tree and zero if it
+ * is not.
+ */
+static int in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root)
+{
+ struct rb_node *p;
+
+ p = root->rb_node;
+ while (p) {
+ struct ubi_wl_entry *e1;
+
+ e1 = rb_entry(p, struct ubi_wl_entry, rb);
+
+ if (e->pnum == e1->pnum) {
+ ubi_assert(e == e1);
+ return 1;
+ }
+
+ if (e->ec < e1->ec)
+ p = p->rb_left;
+ else if (e->ec > e1->ec)
+ p = p->rb_right;
+ else {
+ ubi_assert(e->pnum != e1->pnum);
+ if (e->pnum < e1->pnum)
+ p = p->rb_left;
+ else
+ p = p->rb_right;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * prot_tree_add - add physical eraseblock to protection trees.
+ * @ubi: UBI device description object
+ * @e: the physical eraseblock to add
+ * @pe: protection entry object to use
+ * @abs_ec: absolute erase counter value when this physical eraseblock has
+ * to be removed from the protection trees.
+ *
+ * @wl->lock has to be locked.
+ */
+static void prot_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e,
+ struct ubi_wl_prot_entry *pe, int abs_ec)
+{
+ struct rb_node **p, *parent = NULL;
+ struct ubi_wl_prot_entry *pe1;
+
+ pe->e = e;
+ pe->abs_ec = ubi->abs_ec + abs_ec;
+
+ p = &ubi->prot.pnum.rb_node;
+ while (*p) {
+ parent = *p;
+ pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_pnum);
+
+ if (e->pnum < pe1->e->pnum)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+ rb_link_node(&pe->rb_pnum, parent, p);
+ rb_insert_color(&pe->rb_pnum, &ubi->prot.pnum);
+
+ p = &ubi->prot.aec.rb_node;
+ parent = NULL;
+ while (*p) {
+ parent = *p;
+ pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_aec);
+
+ if (pe->abs_ec < pe1->abs_ec)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+ rb_link_node(&pe->rb_aec, parent, p);
+ rb_insert_color(&pe->rb_aec, &ubi->prot.aec);
+}
+
+/**
+ * find_wl_entry - find wear-leveling entry closest to certain erase counter.
+ * @root: the RB-tree where to look for
+ * @max: highest possible erase counter
+ *
+ * This function looks for a wear leveling entry with erase counter closest to
+ * @max and less then @max.
+ */
+static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
+{
+ struct rb_node *p;
+ struct ubi_wl_entry *e;
+
+ e = rb_entry(rb_first(root), struct ubi_wl_entry, rb);
+ max += e->ec;
+
+ p = root->rb_node;
+ while (p) {
+ struct ubi_wl_entry *e1;
+
+ e1 = rb_entry(p, struct ubi_wl_entry, rb);
+ if (e1->ec >= max)
+ p = p->rb_left;
+ else {
+ p = p->rb_right;
+ e = e1;
+ }
+ }
+
+ return e;
+}
+
+/**
+ * ubi_wl_get_peb - get a physical eraseblock.
+ * @ubi: UBI device description object
+ * @dtype: type of data which will be stored in this physical eraseblock
+ *
+ * This function returns a physical eraseblock in case of success and a
+ * negative error code in case of failure. Might sleep.
+ */
+int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
+{
+ int err, protect, medium_ec;
+ struct ubi_wl_entry *e, *first, *last;
+ struct ubi_wl_prot_entry *pe;
+
+ ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
+ dtype == UBI_UNKNOWN);
+
+ pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS);
+ if (!pe)
+ return -ENOMEM;
+
+retry:
+ spin_lock(&ubi->wl_lock);
+ if (!ubi->free.rb_node) {
+ if (ubi->works_count == 0) {
+ ubi_assert(list_empty(&ubi->works));
+ ubi_err("no free eraseblocks");
+ spin_unlock(&ubi->wl_lock);
+ kfree(pe);
+ return -ENOSPC;
+ }
+ spin_unlock(&ubi->wl_lock);
+
+ err = produce_free_peb(ubi);
+ if (err < 0) {
+ kfree(pe);
+ return err;
+ }
+ goto retry;
+ }
+
+ switch (dtype) {
+ case UBI_LONGTERM:
+ /*
+ * For long term data we pick a physical eraseblock
+ * with high erase counter. But the highest erase
+ * counter we can pick is bounded by the the lowest
+ * erase counter plus %WL_FREE_MAX_DIFF.
+ */
+ e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+ protect = LT_PROTECTION;
+ break;
+ case UBI_UNKNOWN:
+ /*
+ * For unknown data we pick a physical eraseblock with
+ * medium erase counter. But we by no means can pick a
+ * physical eraseblock with erase counter greater or
+ * equivalent than the lowest erase counter plus
+ * %WL_FREE_MAX_DIFF.
+ */
+ first = rb_entry(rb_first(&ubi->free),
+ struct ubi_wl_entry, rb);
+ last = rb_entry(rb_last(&ubi->free),
+ struct ubi_wl_entry, rb);
+
+ if (last->ec - first->ec < WL_FREE_MAX_DIFF)
+ e = rb_entry(ubi->free.rb_node,
+ struct ubi_wl_entry, rb);
+ else {
+ medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
+ e = find_wl_entry(&ubi->free, medium_ec);
+ }
+ protect = U_PROTECTION;
+ break;
+ case UBI_SHORTTERM:
+ /*
+ * For short term data we pick a physical eraseblock
+ * with the lowest erase counter as we expect it will
+ * be erased soon.
+ */
+ e = rb_entry(rb_first(&ubi->free),
+ struct ubi_wl_entry, rb);
+ protect = ST_PROTECTION;
+ break;
+ default:
+ protect = 0;
+ e = NULL;
+ BUG();
+ }
+
+ /*
+ * Move the physical eraseblock to the protection trees where it will
+ * be protected from being moved for some time.
+ */
+ paranoid_check_in_wl_tree(e, &ubi->free);
+ rb_erase(&e->rb, &ubi->free);
+ prot_tree_add(ubi, e, pe, protect);
+
+ dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect);
+ spin_unlock(&ubi->wl_lock);
+
+ return e->pnum;
+}
+
+/**
+ * prot_tree_del - remove a physical eraseblock from the protection trees
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock to remove
+ *
+ * This function returns PEB @pnum from the protection trees and returns zero
+ * in case of success and %-ENODEV if the PEB was not found in the protection
+ * trees.
+ */
+static int prot_tree_del(struct ubi_device *ubi, int pnum)
+{
+ struct rb_node *p;
+ struct ubi_wl_prot_entry *pe = NULL;
+
+ p = ubi->prot.pnum.rb_node;
+ while (p) {
+
+ pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum);
+
+ if (pnum == pe->e->pnum)
+ goto found;
+
+ if (pnum < pe->e->pnum)
+ p = p->rb_left;
+ else
+ p = p->rb_right;
+ }
+
+ return -ENODEV;
+
+found:
+ ubi_assert(pe->e->pnum == pnum);
+ rb_erase(&pe->rb_aec, &ubi->prot.aec);
+ rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
+ kfree(pe);
+ return 0;
+}
+
+/**
+ * sync_erase - synchronously erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @e: the the physical eraseblock to erase
+ * @torture: if the physical eraseblock has to be tortured
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture)
+{
+ int err;
+ struct ubi_ec_hdr *ec_hdr;
+ unsigned long long ec = e->ec;
+
+ dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
+
+ err = paranoid_check_ec(ubi, e->pnum, e->ec);
+ if (err > 0)
+ return -EINVAL;
+
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
+ if (!ec_hdr)
+ return -ENOMEM;
+
+ err = ubi_io_sync_erase(ubi, e->pnum, torture);
+ if (err < 0)
+ goto out_free;
+
+ ec += err;
+ if (ec > UBI_MAX_ERASECOUNTER) {
+ /*
+ * Erase counter overflow. Upgrade UBI and use 64-bit
+ * erase counters internally.
+ */
+ ubi_err("erase counter overflow at PEB %d, EC %llu",
+ e->pnum, ec);
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
+
+ ec_hdr->ec = cpu_to_be64(ec);
+
+ err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
+ if (err)
+ goto out_free;
+
+ e->ec = ec;
+ spin_lock(&ubi->wl_lock);
+ if (e->ec > ubi->max_ec)
+ ubi->max_ec = e->ec;
+ spin_unlock(&ubi->wl_lock);
+
+out_free:
+ kfree(ec_hdr);
+ return err;
+}
+
+/**
+ * check_protection_over - check if it is time to stop protecting some
+ * physical eraseblocks.
+ * @ubi: UBI device description object
+ *
+ * This function is called after each erase operation, when the absolute erase
+ * counter is incremented, to check if some physical eraseblock have not to be
+ * protected any longer. These physical eraseblocks are moved from the
+ * protection trees to the used tree.
+ */
+static void check_protection_over(struct ubi_device *ubi)
+{
+ struct ubi_wl_prot_entry *pe;
+
+ /*
+ * There may be several protected physical eraseblock to remove,
+ * process them all.
+ */
+ while (1) {
+ spin_lock(&ubi->wl_lock);
+ if (!ubi->prot.aec.rb_node) {
+ spin_unlock(&ubi->wl_lock);
+ break;
+ }
+
+ pe = rb_entry(rb_first(&ubi->prot.aec),
+ struct ubi_wl_prot_entry, rb_aec);
+
+ if (pe->abs_ec > ubi->abs_ec) {
+ spin_unlock(&ubi->wl_lock);
+ break;
+ }
+
+ dbg_wl("PEB %d protection over, abs_ec %llu, PEB abs_ec %llu",
+ pe->e->pnum, ubi->abs_ec, pe->abs_ec);
+ rb_erase(&pe->rb_aec, &ubi->prot.aec);
+ rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
+ wl_tree_add(pe->e, &ubi->used);
+ spin_unlock(&ubi->wl_lock);
+
+ kfree(pe);
+ cond_resched();
+ }
+}
+
+/**
+ * schedule_ubi_work - schedule a work.
+ * @ubi: UBI device description object
+ * @wrk: the work to schedule
+ *
+ * This function enqueues a work defined by @wrk to the tail of the pending
+ * works list.
+ */
+static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
+{
+ spin_lock(&ubi->wl_lock);
+ list_add_tail(&wrk->list, &ubi->works);
+ ubi_assert(ubi->works_count >= 0);
+ ubi->works_count += 1;
+ if (ubi->thread_enabled)
+ wake_up_process(ubi->bgt_thread);
+ spin_unlock(&ubi->wl_lock);
+}
+
+static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+ int cancel);
+
+/**
+ * schedule_erase - schedule an erase work.
+ * @ubi: UBI device description object
+ * @e: the WL entry of the physical eraseblock to erase
+ * @torture: if the physical eraseblock has to be tortured
+ *
+ * This function returns zero in case of success and a %-ENOMEM in case of
+ * failure.
+ */
+static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
+ int torture)
+{
+ struct ubi_work *wl_wrk;
+
+ dbg_wl("schedule erasure of PEB %d, EC %d, torture %d",
+ e->pnum, e->ec, torture);
+
+ wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
+ if (!wl_wrk)
+ return -ENOMEM;
+
+ wl_wrk->func = &erase_worker;
+ wl_wrk->e = e;
+ wl_wrk->torture = torture;
+
+ schedule_ubi_work(ubi, wl_wrk);
+ return 0;
+}
+
+/**
+ * wear_leveling_worker - wear-leveling worker function.
+ * @ubi: UBI device description object
+ * @wrk: the work object
+ * @cancel: non-zero if the worker has to free memory and exit
+ *
+ * This function copies a more worn out physical eraseblock to a less worn out
+ * one. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
+ int cancel)
+{
+ int err, put = 0, scrubbing = 0, protect = 0;
+ struct ubi_wl_prot_entry *uninitialized_var(pe);
+ struct ubi_wl_entry *e1, *e2;
+ struct ubi_vid_hdr *vid_hdr;
+
+ kfree(wrk);
+
+ if (cancel)
+ return 0;
+
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+ if (!vid_hdr)
+ return -ENOMEM;
+
+ mutex_lock(&ubi->move_mutex);
+ spin_lock(&ubi->wl_lock);
+ ubi_assert(!ubi->move_from && !ubi->move_to);
+ ubi_assert(!ubi->move_to_put);
+
+ if (!ubi->free.rb_node ||
+ (!ubi->used.rb_node && !ubi->scrub.rb_node)) {
+ /*
+ * No free physical eraseblocks? Well, they must be waiting in
+ * the queue to be erased. Cancel movement - it will be
+ * triggered again when a free physical eraseblock appears.
+ *
+ * No used physical eraseblocks? They must be temporarily
+ * protected from being moved. They will be moved to the
+ * @ubi->used tree later and the wear-leveling will be
+ * triggered again.
+ */
+ dbg_wl("cancel WL, a list is empty: free %d, used %d",
+ !ubi->free.rb_node, !ubi->used.rb_node);
+ goto out_cancel;
+ }
+
+ if (!ubi->scrub.rb_node) {
+ /*
+ * Now pick the least worn-out used physical eraseblock and a
+ * highly worn-out free physical eraseblock. If the erase
+ * counters differ much enough, start wear-leveling.
+ */
+ e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb);
+ e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+
+ if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
+ dbg_wl("no WL needed: min used EC %d, max free EC %d",
+ e1->ec, e2->ec);
+ goto out_cancel;
+ }
+ paranoid_check_in_wl_tree(e1, &ubi->used);
+ rb_erase(&e1->rb, &ubi->used);
+ dbg_wl("move PEB %d EC %d to PEB %d EC %d",
+ e1->pnum, e1->ec, e2->pnum, e2->ec);
+ } else {
+ /* Perform scrubbing */
+ scrubbing = 1;
+ e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb);
+ e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+ paranoid_check_in_wl_tree(e1, &ubi->scrub);
+ rb_erase(&e1->rb, &ubi->scrub);
+ dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
+ }
+
+ paranoid_check_in_wl_tree(e2, &ubi->free);
+ rb_erase(&e2->rb, &ubi->free);
+ ubi->move_from = e1;
+ ubi->move_to = e2;
+ spin_unlock(&ubi->wl_lock);
+
+ /*
+ * Now we are going to copy physical eraseblock @e1->pnum to @e2->pnum.
+ * We so far do not know which logical eraseblock our physical
+ * eraseblock (@e1) belongs to. We have to read the volume identifier
+ * header first.
+ *
+ * Note, we are protected from this PEB being unmapped and erased. The
+ * 'ubi_wl_put_peb()' would wait for moving to be finished if the PEB
+ * which is being moved was unmapped.
+ */
+
+ err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0);
+ if (err && err != UBI_IO_BITFLIPS) {
+ if (err == UBI_IO_PEB_FREE) {
+ /*
+ * We are trying to move PEB without a VID header. UBI
+ * always write VID headers shortly after the PEB was
+ * given, so we have a situation when it did not have
+ * chance to write it down because it was preempted.
+ * Just re-schedule the work, so that next time it will
+ * likely have the VID header in place.
+ */
+ dbg_wl("PEB %d has no VID header", e1->pnum);
+ goto out_not_moved;
+ }
+
+ ubi_err("error %d while reading VID header from PEB %d",
+ err, e1->pnum);
+ if (err > 0)
+ err = -EIO;
+ goto out_error;
+ }
+
+ err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr);
+ if (err) {
+
+ if (err < 0)
+ goto out_error;
+ if (err == 1)
+ goto out_not_moved;
+
+ /*
+ * For some reason the LEB was not moved - it might be because
+ * the volume is being deleted. We should prevent this PEB from
+ * being selected for wear-levelling movement for some "time",
+ * so put it to the protection tree.
+ */
+
+ dbg_wl("cancelled moving PEB %d", e1->pnum);
+ pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS);
+ if (!pe) {
+ err = -ENOMEM;
+ goto out_error;
+ }
+
+ protect = 1;
+ }
+
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ spin_lock(&ubi->wl_lock);
+ if (protect)
+ prot_tree_add(ubi, e1, pe, protect);
+ if (!ubi->move_to_put)
+ wl_tree_add(e2, &ubi->used);
+ else
+ put = 1;
+ ubi->move_from = ubi->move_to = NULL;
+ ubi->move_to_put = ubi->wl_scheduled = 0;
+ spin_unlock(&ubi->wl_lock);
+
+ if (put) {
+ /*
+ * Well, the target PEB was put meanwhile, schedule it for
+ * erasure.
+ */
+ dbg_wl("PEB %d was put meanwhile, erase", e2->pnum);
+ err = schedule_erase(ubi, e2, 0);
+ if (err)
+ goto out_error;
+ }
+
+ if (!protect) {
+ err = schedule_erase(ubi, e1, 0);
+ if (err)
+ goto out_error;
+ }
+
+
+ dbg_wl("done");
+ mutex_unlock(&ubi->move_mutex);
+ return 0;
+
+ /*
+ * For some reasons the LEB was not moved, might be an error, might be
+ * something else. @e1 was not changed, so return it back. @e2 might
+ * be changed, schedule it for erasure.
+ */
+out_not_moved:
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ spin_lock(&ubi->wl_lock);
+ if (scrubbing)
+ wl_tree_add(e1, &ubi->scrub);
+ else
+ wl_tree_add(e1, &ubi->used);
+ ubi->move_from = ubi->move_to = NULL;
+ ubi->move_to_put = ubi->wl_scheduled = 0;
+ spin_unlock(&ubi->wl_lock);
+
+ err = schedule_erase(ubi, e2, 0);
+ if (err)
+ goto out_error;
+
+ mutex_unlock(&ubi->move_mutex);
+ return 0;
+
+out_error:
+ ubi_err("error %d while moving PEB %d to PEB %d",
+ err, e1->pnum, e2->pnum);
+
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ spin_lock(&ubi->wl_lock);
+ ubi->move_from = ubi->move_to = NULL;
+ ubi->move_to_put = ubi->wl_scheduled = 0;
+ spin_unlock(&ubi->wl_lock);
+
+ kmem_cache_free(ubi_wl_entry_slab, e1);
+ kmem_cache_free(ubi_wl_entry_slab, e2);
+ ubi_ro_mode(ubi);
+
+ mutex_unlock(&ubi->move_mutex);
+ return err;
+
+out_cancel:
+ ubi->wl_scheduled = 0;
+ spin_unlock(&ubi->wl_lock);
+ mutex_unlock(&ubi->move_mutex);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ return 0;
+}
+
+/**
+ * ensure_wear_leveling - schedule wear-leveling if it is needed.
+ * @ubi: UBI device description object
+ *
+ * This function checks if it is time to start wear-leveling and schedules it
+ * if yes. This function returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+static int ensure_wear_leveling(struct ubi_device *ubi)
+{
+ int err = 0;
+ struct ubi_wl_entry *e1;
+ struct ubi_wl_entry *e2;
+ struct ubi_work *wrk;
+
+ spin_lock(&ubi->wl_lock);
+ if (ubi->wl_scheduled)
+ /* Wear-leveling is already in the work queue */
+ goto out_unlock;
+
+ /*
+ * If the ubi->scrub tree is not empty, scrubbing is needed, and the
+ * the WL worker has to be scheduled anyway.
+ */
+ if (!ubi->scrub.rb_node) {
+ if (!ubi->used.rb_node || !ubi->free.rb_node)
+ /* No physical eraseblocks - no deal */
+ goto out_unlock;
+
+ /*
+ * We schedule wear-leveling only if the difference between the
+ * lowest erase counter of used physical eraseblocks and a high
+ * erase counter of free physical eraseblocks is greater then
+ * %UBI_WL_THRESHOLD.
+ */
+ e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb);
+ e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+
+ if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD))
+ goto out_unlock;
+ dbg_wl("schedule wear-leveling");
+ } else
+ dbg_wl("schedule scrubbing");
+
+ ubi->wl_scheduled = 1;
+ spin_unlock(&ubi->wl_lock);
+
+ wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
+ if (!wrk) {
+ err = -ENOMEM;
+ goto out_cancel;
+ }
+
+ wrk->func = &wear_leveling_worker;
+ schedule_ubi_work(ubi, wrk);
+ return err;
+
+out_cancel:
+ spin_lock(&ubi->wl_lock);
+ ubi->wl_scheduled = 0;
+out_unlock:
+ spin_unlock(&ubi->wl_lock);
+ return err;
+}
+
+/**
+ * erase_worker - physical eraseblock erase worker function.
+ * @ubi: UBI device description object
+ * @wl_wrk: the work object
+ * @cancel: non-zero if the worker has to free memory and exit
+ *
+ * This function erases a physical eraseblock and perform torture testing if
+ * needed. It also takes care about marking the physical eraseblock bad if
+ * needed. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+ int cancel)
+{
+ struct ubi_wl_entry *e = wl_wrk->e;
+ int pnum = e->pnum, err, need;
+
+ if (cancel) {
+ dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
+ kfree(wl_wrk);
+ kmem_cache_free(ubi_wl_entry_slab, e);
+ return 0;
+ }
+
+ dbg_wl("erase PEB %d EC %d", pnum, e->ec);
+
+ err = sync_erase(ubi, e, wl_wrk->torture);
+ if (!err) {
+ /* Fine, we've erased it successfully */
+ kfree(wl_wrk);
+
+ spin_lock(&ubi->wl_lock);
+ ubi->abs_ec += 1;
+ wl_tree_add(e, &ubi->free);
+ spin_unlock(&ubi->wl_lock);
+
+ /*
+ * One more erase operation has happened, take care about protected
+ * physical eraseblocks.
+ */
+ check_protection_over(ubi);
+
+ /* And take care about wear-leveling */
+ err = ensure_wear_leveling(ubi);
+ return err;
+ }
+
+ ubi_err("failed to erase PEB %d, error %d", pnum, err);
+ kfree(wl_wrk);
+ kmem_cache_free(ubi_wl_entry_slab, e);
+
+ if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+ err == -EBUSY) {
+ int err1;
+
+ /* Re-schedule the LEB for erasure */
+ err1 = schedule_erase(ubi, e, 0);
+ if (err1) {
+ err = err1;
+ goto out_ro;
+ }
+ return err;
+ } else if (err != -EIO) {
+ /*
+ * If this is not %-EIO, we have no idea what to do. Scheduling
+ * this physical eraseblock for erasure again would cause
+ * errors again and again. Well, lets switch to RO mode.
+ */
+ goto out_ro;
+ }
+
+ /* It is %-EIO, the PEB went bad */
+
+ if (!ubi->bad_allowed) {
+ ubi_err("bad physical eraseblock %d detected", pnum);
+ goto out_ro;
+ }
+
+ spin_lock(&ubi->volumes_lock);
+ need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+ if (need > 0) {
+ need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+ ubi->avail_pebs -= need;
+ ubi->rsvd_pebs += need;
+ ubi->beb_rsvd_pebs += need;
+ if (need > 0)
+ ubi_msg("reserve more %d PEBs", need);
+ }
+
+ if (ubi->beb_rsvd_pebs == 0) {
+ spin_unlock(&ubi->volumes_lock);
+ ubi_err("no reserved physical eraseblocks");
+ goto out_ro;
+ }
+
+ spin_unlock(&ubi->volumes_lock);
+ ubi_msg("mark PEB %d as bad", pnum);
+
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ goto out_ro;
+
+ spin_lock(&ubi->volumes_lock);
+ ubi->beb_rsvd_pebs -= 1;
+ ubi->bad_peb_count += 1;
+ ubi->good_peb_count -= 1;
+ ubi_calculate_reserved(ubi);
+ if (ubi->beb_rsvd_pebs == 0)
+ ubi_warn("last PEB from the reserved pool was used");
+ spin_unlock(&ubi->volumes_lock);
+
+ return err;
+
+out_ro:
+ ubi_ro_mode(ubi);
+ return err;
+}
+
+/**
+ * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling unit.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to return
+ * @torture: if this physical eraseblock has to be tortured
+ *
+ * This function is called to return physical eraseblock @pnum to the pool of
+ * free physical eraseblocks. The @torture flag has to be set if an I/O error
+ * occurred to this @pnum and it has to be tested. This function returns zero
+ * in case of success, and a negative error code in case of failure.
+ */
+int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
+{
+ int err;
+ struct ubi_wl_entry *e;
+
+ dbg_wl("PEB %d", pnum);
+ ubi_assert(pnum >= 0);
+ ubi_assert(pnum < ubi->peb_count);
+
+retry:
+ spin_lock(&ubi->wl_lock);
+ e = ubi->lookuptbl[pnum];
+ if (e == ubi->move_from) {
+ /*
+ * User is putting the physical eraseblock which was selected to
+ * be moved. It will be scheduled for erasure in the
+ * wear-leveling worker.
+ */
+ dbg_wl("PEB %d is being moved, wait", pnum);
+ spin_unlock(&ubi->wl_lock);
+
+ /* Wait for the WL worker by taking the @ubi->move_mutex */
+ mutex_lock(&ubi->move_mutex);
+ mutex_unlock(&ubi->move_mutex);
+ goto retry;
+ } else if (e == ubi->move_to) {
+ /*
+ * User is putting the physical eraseblock which was selected
+ * as the target the data is moved to. It may happen if the EBA
+ * unit already re-mapped the LEB in 'ubi_eba_copy_leb()' but
+ * the WL unit has not put the PEB to the "used" tree yet, but
+ * it is about to do this. So we just set a flag which will
+ * tell the WL worker that the PEB is not needed anymore and
+ * should be scheduled for erasure.
+ */
+ dbg_wl("PEB %d is the target of data moving", pnum);
+ ubi_assert(!ubi->move_to_put);
+ ubi->move_to_put = 1;
+ spin_unlock(&ubi->wl_lock);
+ return 0;
+ } else {
+ if (in_wl_tree(e, &ubi->used)) {
+ paranoid_check_in_wl_tree(e, &ubi->used);
+ rb_erase(&e->rb, &ubi->used);
+ } else if (in_wl_tree(e, &ubi->scrub)) {
+ paranoid_check_in_wl_tree(e, &ubi->scrub);
+ rb_erase(&e->rb, &ubi->scrub);
+ } else {
+ err = prot_tree_del(ubi, e->pnum);
+ if (err) {
+ ubi_err("PEB %d not found", pnum);
+ ubi_ro_mode(ubi);
+ spin_unlock(&ubi->wl_lock);
+ return err;
+ }
+ }
+ }
+ spin_unlock(&ubi->wl_lock);
+
+ err = schedule_erase(ubi, e, torture);
+ if (err) {
+ spin_lock(&ubi->wl_lock);
+ wl_tree_add(e, &ubi->used);
+ spin_unlock(&ubi->wl_lock);
+ }
+
+ return err;
+}
+
+/**
+ * ubi_wl_scrub_peb - schedule a physical eraseblock for scrubbing.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock to schedule
+ *
+ * If a bit-flip in a physical eraseblock is detected, this physical eraseblock
+ * needs scrubbing. This function schedules a physical eraseblock for
+ * scrubbing which is done in background. This function returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum)
+{
+ struct ubi_wl_entry *e;
+
+ ubi_msg("schedule PEB %d for scrubbing", pnum);
+
+retry:
+ spin_lock(&ubi->wl_lock);
+ e = ubi->lookuptbl[pnum];
+ if (e == ubi->move_from || in_wl_tree(e, &ubi->scrub)) {
+ spin_unlock(&ubi->wl_lock);
+ return 0;
+ }
+
+ if (e == ubi->move_to) {
+ /*
+ * This physical eraseblock was used to move data to. The data
+ * was moved but the PEB was not yet inserted to the proper
+ * tree. We should just wait a little and let the WL worker
+ * proceed.
+ */
+ spin_unlock(&ubi->wl_lock);
+ dbg_wl("the PEB %d is not in proper tree, retry", pnum);
+ yield();
+ goto retry;
+ }
+
+ if (in_wl_tree(e, &ubi->used)) {
+ paranoid_check_in_wl_tree(e, &ubi->used);
+ rb_erase(&e->rb, &ubi->used);
+ } else {
+ int err;
+
+ err = prot_tree_del(ubi, e->pnum);
+ if (err) {
+ ubi_err("PEB %d not found", pnum);
+ ubi_ro_mode(ubi);
+ spin_unlock(&ubi->wl_lock);
+ return err;
+ }
+ }
+
+ wl_tree_add(e, &ubi->scrub);
+ spin_unlock(&ubi->wl_lock);
+
+ /*
+ * Technically scrubbing is the same as wear-leveling, so it is done
+ * by the WL worker.
+ */
+ return ensure_wear_leveling(ubi);
+}
+
+/**
+ * ubi_wl_flush - flush all pending works.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_wl_flush(struct ubi_device *ubi)
+{
+ int err;
+
+ /*
+ * Erase while the pending works queue is not empty, but not more then
+ * the number of currently pending works.
+ */
+ dbg_wl("flush (%d pending works)", ubi->works_count);
+ while (ubi->works_count) {
+ err = do_work(ubi);
+ if (err)
+ return err;
+ }
+
+ /*
+ * Make sure all the works which have been done in parallel are
+ * finished.
+ */
+ down_write(&ubi->work_sem);
+ up_write(&ubi->work_sem);
+
+ /*
+ * And in case last was the WL worker and it cancelled the LEB
+ * movement, flush again.
+ */
+ while (ubi->works_count) {
+ dbg_wl("flush more (%d pending works)", ubi->works_count);
+ err = do_work(ubi);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * tree_destroy - destroy an RB-tree.
+ * @root: the root of the tree to destroy
+ */
+static void tree_destroy(struct rb_root *root)
+{
+ struct rb_node *rb;
+ struct ubi_wl_entry *e;
+
+ rb = root->rb_node;
+ while (rb) {
+ if (rb->rb_left)
+ rb = rb->rb_left;
+ else if (rb->rb_right)
+ rb = rb->rb_right;
+ else {
+ e = rb_entry(rb, struct ubi_wl_entry, rb);
+
+ rb = rb_parent(rb);
+ if (rb) {
+ if (rb->rb_left == &e->rb)
+ rb->rb_left = NULL;
+ else
+ rb->rb_right = NULL;
+ }
+
+ kmem_cache_free(ubi_wl_entry_slab, e);
+ }
+ }
+}
+
+/**
+ * ubi_thread - UBI background thread.
+ * @u: the UBI device description object pointer
+ */
+int ubi_thread(void *u)
+{
+ int failures = 0;
+ struct ubi_device *ubi = u;
+
+ ubi_msg("background thread \"%s\" started, PID %d",
+ ubi->bgt_name, task_pid_nr(current));
+
+ set_freezable();
+ for (;;) {
+ int err;
+
+ if (kthread_should_stop())
+ break;
+
+ if (try_to_freeze())
+ continue;
+
+ spin_lock(&ubi->wl_lock);
+ if (list_empty(&ubi->works) || ubi->ro_mode ||
+ !ubi->thread_enabled) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock(&ubi->wl_lock);
+ schedule();
+ continue;
+ }
+ spin_unlock(&ubi->wl_lock);
+
+ err = do_work(ubi);
+ if (err) {
+ ubi_err("%s: work failed with error code %d",
+ ubi->bgt_name, err);
+ if (failures++ > WL_MAX_FAILURES) {
+ /*
+ * Too many failures, disable the thread and
+ * switch to read-only mode.
+ */
+ ubi_msg("%s: %d consecutive failures",
+ ubi->bgt_name, WL_MAX_FAILURES);
+ ubi_ro_mode(ubi);
+ break;
+ }
+ } else
+ failures = 0;
+
+ cond_resched();
+ }
+
+ dbg_wl("background thread \"%s\" is killed", ubi->bgt_name);
+ return 0;
+}
+
+/**
+ * cancel_pending - cancel all pending works.
+ * @ubi: UBI device description object
+ */
+static void cancel_pending(struct ubi_device *ubi)
+{
+ while (!list_empty(&ubi->works)) {
+ struct ubi_work *wrk;
+
+ wrk = list_entry(ubi->works.next, struct ubi_work, list);
+ list_del(&wrk->list);
+ wrk->func(ubi, wrk, 1);
+ ubi->works_count -= 1;
+ ubi_assert(ubi->works_count >= 0);
+ }
+}
+
+/**
+ * ubi_wl_init_scan - initialize the wear-leveling unit using scanning
+ * information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns zero in case of success, and a negative error code in
+ * case of failure.
+ */
+int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+ int err;
+ struct rb_node *rb1, *rb2;
+ struct ubi_scan_volume *sv;
+ struct ubi_scan_leb *seb, *tmp;
+ struct ubi_wl_entry *e;
+
+
+ ubi->used = ubi->free = ubi->scrub = RB_ROOT;
+ ubi->prot.pnum = ubi->prot.aec = RB_ROOT;
+ spin_lock_init(&ubi->wl_lock);
+ mutex_init(&ubi->move_mutex);
+ init_rwsem(&ubi->work_sem);
+ ubi->max_ec = si->max_ec;
+ INIT_LIST_HEAD(&ubi->works);
+
+ sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
+
+ err = -ENOMEM;
+ ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL);
+ if (!ubi->lookuptbl)
+ return err;
+
+ list_for_each_entry_safe(seb, tmp, &si->erase, u.list) {
+ cond_resched();
+
+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+ if (!e)
+ goto out_free;
+
+ e->pnum = seb->pnum;
+ e->ec = seb->ec;
+ ubi->lookuptbl[e->pnum] = e;
+ if (schedule_erase(ubi, e, 0)) {
+ kmem_cache_free(ubi_wl_entry_slab, e);
+ goto out_free;
+ }
+ }
+
+ list_for_each_entry(seb, &si->free, u.list) {
+ cond_resched();
+
+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+ if (!e)
+ goto out_free;
+
+ e->pnum = seb->pnum;
+ e->ec = seb->ec;
+ ubi_assert(e->ec >= 0);
+ wl_tree_add(e, &ubi->free);
+ ubi->lookuptbl[e->pnum] = e;
+ }
+
+ list_for_each_entry(seb, &si->corr, u.list) {
+ cond_resched();
+
+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+ if (!e)
+ goto out_free;
+
+ e->pnum = seb->pnum;
+ e->ec = seb->ec;
+ ubi->lookuptbl[e->pnum] = e;
+ if (schedule_erase(ubi, e, 0)) {
+ kmem_cache_free(ubi_wl_entry_slab, e);
+ goto out_free;
+ }
+ }
+
+ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+ ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ cond_resched();
+
+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+ if (!e)
+ goto out_free;
+
+ e->pnum = seb->pnum;
+ e->ec = seb->ec;
+ ubi->lookuptbl[e->pnum] = e;
+ if (!seb->scrub) {
+ dbg_wl("add PEB %d EC %d to the used tree",
+ e->pnum, e->ec);
+ wl_tree_add(e, &ubi->used);
+ } else {
+ dbg_wl("add PEB %d EC %d to the scrub tree",
+ e->pnum, e->ec);
+ wl_tree_add(e, &ubi->scrub);
+ }
+ }
+ }
+
+ if (ubi->avail_pebs < WL_RESERVED_PEBS) {
+ ubi_err("no enough physical eraseblocks (%d, need %d)",
+ ubi->avail_pebs, WL_RESERVED_PEBS);
+ goto out_free;
+ }
+ ubi->avail_pebs -= WL_RESERVED_PEBS;
+ ubi->rsvd_pebs += WL_RESERVED_PEBS;
+
+ /* Schedule wear-leveling if needed */
+ err = ensure_wear_leveling(ubi);
+ if (err)
+ goto out_free;
+
+ return 0;
+
+out_free:
+ cancel_pending(ubi);
+ tree_destroy(&ubi->used);
+ tree_destroy(&ubi->free);
+ tree_destroy(&ubi->scrub);
+ kfree(ubi->lookuptbl);
+ return err;
+}
+
+/**
+ * protection_trees_destroy - destroy the protection RB-trees.
+ * @ubi: UBI device description object
+ */
+static void protection_trees_destroy(struct ubi_device *ubi)
+{
+ struct rb_node *rb;
+ struct ubi_wl_prot_entry *pe;
+
+ rb = ubi->prot.aec.rb_node;
+ while (rb) {
+ if (rb->rb_left)
+ rb = rb->rb_left;
+ else if (rb->rb_right)
+ rb = rb->rb_right;
+ else {
+ pe = rb_entry(rb, struct ubi_wl_prot_entry, rb_aec);
+
+ rb = rb_parent(rb);
+ if (rb) {
+ if (rb->rb_left == &pe->rb_aec)
+ rb->rb_left = NULL;
+ else
+ rb->rb_right = NULL;
+ }
+
+ kmem_cache_free(ubi_wl_entry_slab, pe->e);
+ kfree(pe);
+ }
+ }
+}
+
+/**
+ * ubi_wl_close - close the wear-leveling unit.
+ * @ubi: UBI device description object
+ */
+void ubi_wl_close(struct ubi_device *ubi)
+{
+ dbg_wl("close the UBI wear-leveling unit");
+
+ cancel_pending(ubi);
+ protection_trees_destroy(ubi);
+ tree_destroy(&ubi->used);
+ tree_destroy(&ubi->free);
+ tree_destroy(&ubi->scrub);
+ kfree(ubi->lookuptbl);
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_ec - make sure that the erase counter of a physical eraseblock
+ * is correct.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ * @ec: the erase counter to check
+ *
+ * This function returns zero if the erase counter of physical eraseblock @pnum
+ * is equivalent to @ec, %1 if not, and a negative error code if an error
+ * occurred.
+ */
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
+{
+ int err;
+ long long read_ec;
+ struct ubi_ec_hdr *ec_hdr;
+
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
+ if (!ec_hdr)
+ return -ENOMEM;
+
+ err = ubi_io_read_ec_hdr(ubi, pnum, ec_hdr, 0);
+ if (err && err != UBI_IO_BITFLIPS) {
+ /* The header does not have to exist */
+ err = 0;
+ goto out_free;
+ }
+
+ read_ec = be64_to_cpu(ec_hdr->ec);
+ if (ec != read_ec) {
+ ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("read EC is %lld, should be %d", read_ec, ec);
+ ubi_dbg_dump_stack();
+ err = 1;
+ } else
+ err = 0;
+
+out_free:
+ kfree(ec_hdr);
+ return err;
+}
+
+/**
+ * paranoid_check_in_wl_tree - make sure that a wear-leveling entry is present
+ * in a WL RB-tree.
+ * @e: the wear-leveling entry to check
+ * @root: the root of the tree
+ *
+ * This function returns zero if @e is in the @root RB-tree and %1 if it
+ * is not.
+ */
+static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
+ struct rb_root *root)
+{
+ if (in_wl_tree(e, root))
+ return 0;
+
+ ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ",
+ e->pnum, e->ec, root);
+ ubi_dbg_dump_stack();
+ return 1;
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
new file mode 100644
index 0000000..1978269
--- /dev/null
+++ b/drivers/net/4xx_enet.c
@@ -0,0 +1,2126 @@
+/*-----------------------------------------------------------------------------+
+ *
+ * This source code has been made available to you by IBM on an AS-IS
+ * basis. Anyone receiving this source is licensed under IBM
+ * copyrights to use it in any way he or she deems fit, including
+ * copying it, modifying it, compiling it, and redistributing it either
+ * with or without modifications. No license under IBM patents or
+ * patent applications is to be implied by the copyright license.
+ *
+ * Any user of this software should understand that IBM cannot provide
+ * technical support for this software and will not be responsible for
+ * any consequences resulting from the use of this software.
+ *
+ * Any person who transfers this source code or any derivative work
+ * must include the IBM copyright notice, this paragraph, and the
+ * preceding two paragraphs in the transferred software.
+ *
+ * COPYRIGHT I B M CORPORATION 1995
+ * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------+
+ *
+ * File Name: enetemac.c
+ *
+ * Function: Device driver for the ethernet EMAC3 macro on the 405GP.
+ *
+ * Author: Mark Wisner
+ *
+ * Change Activity-
+ *
+ * Date Description of Change BY
+ * --------- --------------------- ---
+ * 05-May-99 Created MKW
+ * 27-Jun-99 Clean up JWB
+ * 16-Jul-99 Added MAL error recovery and better IP packet handling MKW
+ * 29-Jul-99 Added Full duplex support MKW
+ * 06-Aug-99 Changed names for Mal CR reg MKW
+ * 23-Aug-99 Turned off SYE when running at 10Mbs MKW
+ * 24-Aug-99 Marked descriptor empty after call_xlc MKW
+ * 07-Sep-99 Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16 MCG
+ * to avoid chaining maximum sized packets. Push starting
+ * RX descriptor address up to the next cache line boundary.
+ * 16-Jan-00 Added support for booting with IP of 0x0 MKW
+ * 15-Mar-00 Updated enetInit() to enable broadcast addresses in the
+ * EMAC_RXM register. JWB
+ * 12-Mar-01 anne-sophie.harnois@nextream.fr
+ * - Variables are compatible with those already defined in
+ * include/net.h
+ * - Receive buffer descriptor ring is used to send buffers
+ * to the user
+ * - Info print about send/received/handled packet number if
+ * INFO_405_ENET is set
+ * 17-Apr-01 stefan.roese@esd-electronics.com
+ * - MAL reset in "eth_halt" included
+ * - Enet speed and duplex output now in one line
+ * 08-May-01 stefan.roese@esd-electronics.com
+ * - MAL error handling added (eth_init called again)
+ * 13-Nov-01 stefan.roese@esd-electronics.com
+ * - Set IST bit in EMAC_M1 reg upon 100MBit or full duplex
+ * 04-Jan-02 stefan.roese@esd-electronics.com
+ * - Wait for PHY auto negotiation to complete added
+ * 06-Feb-02 stefan.roese@esd-electronics.com
+ * - Bug fixed in waiting for auto negotiation to complete
+ * 26-Feb-02 stefan.roese@esd-electronics.com
+ * - rx and tx buffer descriptors now allocated (no fixed address
+ * used anymore)
+ * 17-Jun-02 stefan.roese@esd-electronics.com
+ * - MAL error debug printf 'M' removed (rx de interrupt may
+ * occur upon many incoming packets with only 4 rx buffers).
+ *-----------------------------------------------------------------------------*
+ * 17-Nov-03 travis.sawyer@sandburst.com
+ * - ported from 405gp_enet.c to utilized upto 4 EMAC ports
+ * in the 440GX. This port should work with the 440GP
+ * (2 EMACs) also
+ * 15-Aug-05 sr@denx.de
+ * - merged 405gp_enet.c and 440gx_enet.c to generic 4xx_enet.c
+ now handling all 4xx cpu's.
+ *-----------------------------------------------------------------------------*/
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <commproc.h>
+#include <ppc4xx.h>
+#include <ppc4xx_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+#include <malloc.h>
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_NET_MULTI)
+#error "CONFIG_NET_MULTI has to be defined for NetConsole"
+#endif
+
+#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */
+#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* 5000 ms autonegotiate timeout */
+
+/* Ethernet Transmit and Receive Buffers */
+/* AS.HARNOIS
+ * In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from
+ * PKTSIZE and PKTSIZE_ALIGN (include/net.h)
+ */
+#define ENET_MAX_MTU PKTSIZE
+#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN
+
+/*-----------------------------------------------------------------------------+
+ * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
+ * Interrupt Controller).
+ *-----------------------------------------------------------------------------*/
+#define ETH_IRQ_NUM(dev) (VECNUM_ETH0 + ((dev) * VECNUM_ETH1_OFFS))
+
+#if defined(CONFIG_HAS_ETH3)
+#if !defined(CONFIG_440GX)
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \
+ UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))
+#else
+/* Unfortunately 440GX spreads EMAC interrupts on multiple UIC's */
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))
+#define UIC_ETHxB (UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))
+#endif /* !defined(CONFIG_440GX) */
+#elif defined(CONFIG_HAS_ETH2)
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \
+ UIC_MASK(ETH_IRQ_NUM(2)))
+#elif defined(CONFIG_HAS_ETH1)
+#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))
+#else
+#define UIC_ETHx UIC_MASK(ETH_IRQ_NUM(0))
+#endif
+
+/*
+ * Define a default version for UIC_ETHxB for non 440GX so that we can
+ * use common code for all 4xx variants
+ */
+#if !defined(UIC_ETHxB)
+#define UIC_ETHxB 0
+#endif
+
+#define UIC_MAL_SERR UIC_MASK(VECNUM_MAL_SERR)
+#define UIC_MAL_TXDE UIC_MASK(VECNUM_MAL_TXDE)
+#define UIC_MAL_RXDE UIC_MASK(VECNUM_MAL_RXDE)
+#define UIC_MAL_TXEOB UIC_MASK(VECNUM_MAL_TXEOB)
+#define UIC_MAL_RXEOB UIC_MASK(VECNUM_MAL_RXEOB)
+
+#define MAL_UIC_ERR (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)
+#define MAL_UIC_DEF (UIC_MAL_RXEOB | MAL_UIC_ERR)
+
+/*
+ * We have 3 different interrupt types:
+ * - MAL interrupts indicating successful transfer
+ * - MAL error interrupts indicating MAL related errors
+ * - EMAC interrupts indicating EMAC related errors
+ *
+ * All those interrupts can be on different UIC's, but since
+ * now at least all interrupts from one type are on the same
+ * UIC. Only exception is 440GX where the EMAC interrupts are
+ * spread over two UIC's!
+ */
+#if defined(CONFIG_440GX)
+#define UIC_BASE_MAL UIC1_DCR_BASE
+#define UIC_BASE_MAL_ERR UIC2_DCR_BASE
+#define UIC_BASE_EMAC UIC2_DCR_BASE
+#define UIC_BASE_EMAC_B UIC3_DCR_BASE
+#else
+#define UIC_BASE_MAL (UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_TXEOB) * 0x10))
+#define UIC_BASE_MAL_ERR (UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_SERR) * 0x10))
+#define UIC_BASE_EMAC (UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))
+#define UIC_BASE_EMAC_B (UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))
+#endif
+
+#undef INFO_4XX_ENET
+
+#define BI_PHYMODE_NONE 0
+#define BI_PHYMODE_ZMII 1
+#define BI_PHYMODE_RGMII 2
+#define BI_PHYMODE_GMII 3
+#define BI_PHYMODE_RTBI 4
+#define BI_PHYMODE_TBI 5
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+#define BI_PHYMODE_SMII 6
+#define BI_PHYMODE_MII 7
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define BI_PHYMODE_RMII 8
+#endif
+#endif
+#define BI_PHYMODE_SGMII 9
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+#define SDR0_MFR_ETH_CLK_SEL_V(n) ((0x01<<27) / (n+1))
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define SDR0_ETH_CFG_CLK_SEL_V(n) (0x01 << (8 + n))
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define MAL_RX_CHAN_MUL 8 /* 460EX/GT uses MAL channel 8 for EMAC1 */
+#else
+#define MAL_RX_CHAN_MUL 1
+#endif
+
+/*--------------------------------------------------------------------+
+ * Fixed PHY (PHY-less) support for Ethernet Ports.
+ *--------------------------------------------------------------------*/
+
+/*
+ * Some boards do not have a PHY for each ethernet port. These ports
+ * are known as Fixed PHY (or PHY-less) ports. For such ports, set
+ * the appropriate CONFIG_PHY_ADDR equal to CONFIG_FIXED_PHY and
+ * then define CONFIG_SYS_FIXED_PHY_PORTS to define what the speed and
+ * duplex should be for these ports in the board configuration
+ * file.
+ *
+ * For Example:
+ * #define CONFIG_FIXED_PHY 0xFFFFFFFF
+ *
+ * #define CONFIG_PHY_ADDR CONFIG_FIXED_PHY
+ * #define CONFIG_PHY1_ADDR 1
+ * #define CONFIG_PHY2_ADDR CONFIG_FIXED_PHY
+ * #define CONFIG_PHY3_ADDR 3
+ *
+ * #define CONFIG_SYS_FIXED_PHY_PORT(devnum,speed,duplex) \
+ * {devnum, speed, duplex},
+ *
+ * #define CONFIG_SYS_FIXED_PHY_PORTS \
+ * CONFIG_SYS_FIXED_PHY_PORT(0,1000,FULL) \
+ * CONFIG_SYS_FIXED_PHY_PORT(2,100,HALF)
+ */
+
+#ifndef CONFIG_FIXED_PHY
+#define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */
+#endif
+
+#ifndef CONFIG_SYS_FIXED_PHY_PORTS
+#define CONFIG_SYS_FIXED_PHY_PORTS /* default is an empty array */
+#endif
+
+struct fixed_phy_port {
+ unsigned int devnum; /* ethernet port */
+ unsigned int speed; /* specified speed 10,100 or 1000 */
+ unsigned int duplex; /* specified duplex FULL or HALF */
+};
+
+static const struct fixed_phy_port fixed_phy_port[] = {
+ CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
+};
+
+/*-----------------------------------------------------------------------------+
+ * Global variables. TX and RX descriptors and buffers.
+ *-----------------------------------------------------------------------------*/
+#if !defined(CONFIG_NET_MULTI)
+struct eth_device *emac0_dev = NULL;
+#endif
+
+/*
+ * Get count of EMAC devices (doesn't have to be the max. possible number
+ * supported by the cpu)
+ *
+ * CONFIG_BOARD_EMAC_COUNT added so now a "dynamic" way to configure the
+ * EMAC count is possible. As it is needed for the Kilauea/Haleakala
+ * 405EX/405EXr eval board, using the same binary.
+ */
+#if defined(CONFIG_BOARD_EMAC_COUNT)
+#define LAST_EMAC_NUM board_emac_count()
+#else /* CONFIG_BOARD_EMAC_COUNT */
+#if defined(CONFIG_HAS_ETH3)
+#define LAST_EMAC_NUM 4
+#elif defined(CONFIG_HAS_ETH2)
+#define LAST_EMAC_NUM 3
+#elif defined(CONFIG_HAS_ETH1)
+#define LAST_EMAC_NUM 2
+#else
+#define LAST_EMAC_NUM 1
+#endif
+#endif /* CONFIG_BOARD_EMAC_COUNT */
+
+/* normal boards start with EMAC0 */
+#if !defined(CONFIG_EMAC_NR_START)
+#define CONFIG_EMAC_NR_START 0
+#endif
+
+#define MAL_RX_DESC_SIZE 2048
+#define MAL_TX_DESC_SIZE 2048
+#define MAL_ALLOC_SIZE (MAL_TX_DESC_SIZE + MAL_RX_DESC_SIZE)
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes and externals.
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (struct eth_device *dev, unsigned long malisr);
+
+int enetInt (struct eth_device *dev);
+static void mal_err (struct eth_device *dev, unsigned long isr,
+ unsigned long uic, unsigned long maldef,
+ unsigned long mal_errr);
+static void emac_err (struct eth_device *dev, unsigned long isr);
+
+extern int phy_setup_aneg (char *devname, unsigned char addr);
+extern int emac4xx_miiphy_read (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value);
+extern int emac4xx_miiphy_write (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value);
+
+int board_emac_count(void);
+
+static void emac_loopback_enable(EMAC_4XX_HW_PST hw_p)
+{
+#if defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_405EX)
+ u32 val;
+
+ mfsdr(sdr_mfr, val);
+ val |= SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
+ mtsdr(sdr_mfr, val);
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ u32 val;
+
+ mfsdr(SDR0_ETH_CFG, val);
+ val |= SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum);
+ mtsdr(SDR0_ETH_CFG, val);
+#endif
+}
+
+static void emac_loopback_disable(EMAC_4XX_HW_PST hw_p)
+{
+#if defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_405EX)
+ u32 val;
+
+ mfsdr(sdr_mfr, val);
+ val &= ~SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
+ mtsdr(sdr_mfr, val);
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ u32 val;
+
+ mfsdr(SDR0_ETH_CFG, val);
+ val &= ~SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum);
+ mtsdr(SDR0_ETH_CFG, val);
+#endif
+}
+
+/*-----------------------------------------------------------------------------+
+| ppc_4xx_eth_halt
+| Disable MAL channel, and EMACn
++-----------------------------------------------------------------------------*/
+static void ppc_4xx_eth_halt (struct eth_device *dev)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+ u32 val = 10000;
+
+ out_be32((void *)EMAC_IER + hw_p->hw_addr, 0x00000000); /* disable emac interrupts */
+
+ /* 1st reset MAL channel */
+ /* Note: writing a 0 to a channel has no effect */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (maltxcarr, (MAL_CR_MMSR >> (hw_p->devnum * 2)));
+#else
+ mtdcr (maltxcarr, (MAL_CR_MMSR >> hw_p->devnum));
+#endif
+ mtdcr (malrxcarr, (MAL_CR_MMSR >> hw_p->devnum));
+
+ /* wait for reset */
+ while (mfdcr (malrxcasr) & (MAL_CR_MMSR >> hw_p->devnum)) {
+ udelay (1000); /* Delay 1 MS so as not to hammer the register */
+ val--;
+ if (val == 0)
+ break;
+ }
+
+ /* provide clocks for EMAC internal loopback */
+ emac_loopback_enable(hw_p);
+
+ /* EMAC RESET */
+ out_be32((void *)EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
+
+ /* remove clocks for EMAC internal loopback */
+ emac_loopback_disable(hw_p);
+
+#ifndef CONFIG_NETCONSOLE
+ hw_p->print_speed = 1; /* print speed message again next time */
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ /* don't bypass the TAHOE0/TAHOE1 cores for Linux */
+ mfsdr(SDR0_ETH_CFG, val);
+ val &= ~(SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);
+ mtsdr(SDR0_ETH_CFG, val);
+#endif
+
+ return;
+}
+
+#if defined (CONFIG_440GX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ unsigned long pfc1;
+ unsigned long zmiifer;
+ unsigned long rmiifer;
+
+ mfsdr(sdr_pfc1, pfc1);
+ pfc1 = SDR0_PFC1_EPS_DECODE(pfc1);
+
+ zmiifer = 0;
+ rmiifer = 0;
+
+ switch (pfc1) {
+ case 1:
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ case 2:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ case 3:
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 4:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 5:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 6:
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ break;
+ case 0:
+ default:
+ zmiifer = ZMII_FER_MII << ZMII_FER_V(devnum);
+ rmiifer = 0x0;
+ bis->bi_phymode[0] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[1] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[2] = BI_PHYMODE_ZMII;
+ bis->bi_phymode[3] = BI_PHYMODE_ZMII;
+ break;
+ }
+
+ /* Ensure we setup mdio for this devnum and ONLY this devnum */
+ zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
+
+ out_be32((void *)ZMII_FER, zmiifer);
+ out_be32((void *)RGMII_FER, rmiifer);
+
+ return ((int)pfc1);
+}
+#endif /* CONFIG_440_GX */
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ unsigned long zmiifer=0x0;
+ unsigned long pfc1;
+
+ mfsdr(sdr_pfc1, pfc1);
+ pfc1 &= SDR0_PFC1_SELECT_MASK;
+
+ switch (pfc1) {
+ case SDR0_PFC1_SELECT_CONFIG_2:
+ /* 1 x GMII port */
+ out_be32((void *)ZMII_FER, 0x00);
+ out_be32((void *)RGMII_FER, 0x00000037);
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case SDR0_PFC1_SELECT_CONFIG_4:
+ /* 2 x RGMII ports */
+ out_be32((void *)ZMII_FER, 0x00);
+ out_be32((void *)RGMII_FER, 0x00000055);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ break;
+ case SDR0_PFC1_SELECT_CONFIG_6:
+ /* 2 x SMII ports */
+ out_be32((void *)ZMII_FER,
+ ((ZMII_FER_SMII) << ZMII_FER_V(0)) |
+ ((ZMII_FER_SMII) << ZMII_FER_V(1)));
+ out_be32((void *)RGMII_FER, 0x00000000);
+ bis->bi_phymode[0] = BI_PHYMODE_SMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SMII;
+ break;
+ case SDR0_PFC1_SELECT_CONFIG_1_2:
+ /* only 1 x MII supported */
+ out_be32((void *)ZMII_FER, (ZMII_FER_MII) << ZMII_FER_V(0));
+ out_be32((void *)RGMII_FER, 0x00000000);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ default:
+ break;
+ }
+
+ /* Ensure we setup mdio for this devnum and ONLY this devnum */
+ zmiifer = in_be32((void *)ZMII_FER);
+ zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
+ out_be32((void *)ZMII_FER, zmiifer);
+
+ return ((int)0x0);
+}
+#endif /* CONFIG_440EPX */
+
+#if defined(CONFIG_405EX)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ u32 rgmiifer = 0;
+
+ /*
+ * The 405EX(r)'s RGMII bridge can operate in one of several
+ * modes, only one of which (2 x RGMII) allows the
+ * simultaneous use of both EMACs on the 405EX.
+ */
+
+ switch (CONFIG_EMAC_PHY_MODE) {
+
+ case EMAC_PHY_MODE_NONE:
+ /* No ports */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_NONE_RGMII:
+ /* 1 x RGMII port on channel 0 */
+ rgmiifer |= RGMII_FER_RGMII << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_RGMII_NONE:
+ /* 1 x RGMII port on channel 1 */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_RGMII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ break;
+ case EMAC_PHY_MODE_RGMII_RGMII:
+ /* 2 x RGMII ports */
+ rgmiifer |= RGMII_FER_RGMII << 0;
+ rgmiifer |= RGMII_FER_RGMII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ break;
+ case EMAC_PHY_MODE_NONE_GMII:
+ /* 1 x GMII port on channel 0 */
+ rgmiifer |= RGMII_FER_GMII << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_NONE_MII:
+ /* 1 x MII port on channel 0 */
+ rgmiifer |= RGMII_FER_MII << 0;
+ rgmiifer |= RGMII_FER_DIS << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ break;
+ case EMAC_PHY_MODE_GMII_NONE:
+ /* 1 x GMII port on channel 1 */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_GMII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_GMII;
+ break;
+ case EMAC_PHY_MODE_MII_NONE:
+ /* 1 x MII port on channel 1 */
+ rgmiifer |= RGMII_FER_DIS << 0;
+ rgmiifer |= RGMII_FER_MII << 4;
+ out_be32((void *)RGMII_FER, rgmiifer);
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_MII;
+ break;
+ default:
+ break;
+ }
+
+ /* Ensure we setup mdio for this devnum and ONLY this devnum */
+ rgmiifer = in_be32((void *)RGMII_FER);
+ rgmiifer |= (1 << (19-devnum));
+ out_be32((void *)RGMII_FER, rgmiifer);
+
+ return ((int)0x0);
+}
+#endif /* CONFIG_405EX */
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
+{
+ u32 eth_cfg;
+ u32 zmiifer; /* ZMII0_FER reg. */
+ u32 rmiifer; /* RGMII0_FER reg. Bridge 0 */
+ u32 rmiifer1; /* RGMII0_FER reg. Bridge 1 */
+ int mode;
+
+ zmiifer = 0;
+ rmiifer = 0;
+ rmiifer1 = 0;
+
+#if defined(CONFIG_460EX)
+ mode = 9;
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
+ ((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0))
+ mode = 11; /* config SGMII */
+#else
+ mode = 10;
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
+ ((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0) &&
+ ((eth_cfg & SDR0_ETH_CFG_SGMII2_ENABLE) > 0))
+ mode = 12; /* config SGMII */
+#endif
+
+ /* TODO:
+ * NOTE: 460GT has 2 RGMII bridge cores:
+ * emac0 ------ RGMII0_BASE
+ * |
+ * emac1 -----+
+ *
+ * emac2 ------ RGMII1_BASE
+ * |
+ * emac3 -----+
+ *
+ * 460EX has 1 RGMII bridge core:
+ * and RGMII1_BASE is disabled
+ * emac0 ------ RGMII0_BASE
+ * |
+ * emac1 -----+
+ */
+
+ /*
+ * Right now only 2*RGMII is supported. Please extend when needed.
+ * sr - 2008-02-19
+ * Add SGMII support.
+ * vg - 2008-07-28
+ */
+ switch (mode) {
+ case 1:
+ /* 1 MII - 460EX */
+ /* GMC0 EMAC4_0, ZMII Bridge */
+ zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 2:
+ /* 2 MII - 460GT */
+ /* GMC0 EMAC4_0, GMC1 EMAC4_2, ZMII Bridge */
+ zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_MII << ZMII_FER_V(2);
+ bis->bi_phymode[0] = BI_PHYMODE_MII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_MII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 3:
+ /* 2 RMII - 460EX */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
+ bis->bi_phymode[0] = BI_PHYMODE_RMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 4:
+ /* 4 RMII - 460GT */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC1 EMAC4_2, GMC1, EMAC4_3 */
+ /* ZMII Bridge */
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_RMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RMII;
+ break;
+ case 5:
+ /* 2 SMII - 460EX */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ bis->bi_phymode[0] = BI_PHYMODE_SMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 6:
+ /* 4 SMII - 460GT */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC0 EMAC4_3, GMC0 EMAC4_3 */
+ /* ZMII Bridge */
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_SMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SMII;
+ bis->bi_phymode[2] = BI_PHYMODE_SMII;
+ bis->bi_phymode[3] = BI_PHYMODE_SMII;
+ break;
+ case 7:
+ /* This is the default mode that we want for board bringup - Maple */
+ /* 1 GMII - 460EX */
+ /* GMC0 EMAC4_0, RGMII Bridge 0 */
+ rmiifer |= RGMII_FER_MDIO(0);
+
+ if (devnum == 0) {
+ rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC0 */
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ } else {
+ rmiifer |= RGMII_FER_GMII << RGMII_FER_V(3); /* CH1CFG - EMAC1 */
+ bis->bi_phymode[0] = BI_PHYMODE_NONE;
+ bis->bi_phymode[1] = BI_PHYMODE_GMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ }
+ break;
+ case 8:
+ /* 2 GMII - 460GT */
+ /* GMC0 EMAC4_0, RGMII Bridge 0 */
+ /* GMC1 EMAC4_2, RGMII Bridge 1 */
+ rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC0 */
+ rmiifer1 |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC2 */
+ rmiifer |= RGMII_FER_MDIO(0); /* enable MDIO - EMAC0 */
+ rmiifer1 |= RGMII_FER_MDIO(0); /* enable MDIO - EMAC2 */
+
+ bis->bi_phymode[0] = BI_PHYMODE_GMII;
+ bis->bi_phymode[1] = BI_PHYMODE_NONE;
+ bis->bi_phymode[2] = BI_PHYMODE_GMII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 9:
+ /* 2 RGMII - 460EX */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ rmiifer |= RGMII_FER_MDIO(0); /* enable MDIO - EMAC0 */
+
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 10:
+ /* 4 RGMII - 460GT */
+ /* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */
+ /* GMC1 EMAC4_2, GMC1 EMAC4_3, RGMII Bridge 1 */
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(2);
+ rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(3);
+ bis->bi_phymode[0] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_RGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_RGMII;
+ break;
+ case 11:
+ /* 2 SGMII - 460EX */
+ bis->bi_phymode[0] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_NONE;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ case 12:
+ /* 3 SGMII - 460GT */
+ bis->bi_phymode[0] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[1] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[2] = BI_PHYMODE_SGMII;
+ bis->bi_phymode[3] = BI_PHYMODE_NONE;
+ break;
+ default:
+ break;
+ }
+
+ /* Set EMAC for MDIO */
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ eth_cfg |= SDR0_ETH_CFG_MDIO_SEL_EMAC0;
+ mtsdr(SDR0_ETH_CFG, eth_cfg);
+
+ out_be32((void *)RGMII_FER, rmiifer);
+#if defined(CONFIG_460GT)
+ out_be32((void *)RGMII_FER + RGMII1_BASE_OFFSET, rmiifer1);
+#endif
+
+ /* bypass the TAHOE0/TAHOE1 cores for U-Boot */
+ mfsdr(SDR0_ETH_CFG, eth_cfg);
+ eth_cfg |= (SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);
+ mtsdr(SDR0_ETH_CFG, eth_cfg);
+
+ return 0;
+}
+#endif /* CONFIG_460EX || CONFIG_460GT */
+
+static inline void *malloc_aligned(u32 size, u32 align)
+{
+ return (void *)(((u32)malloc(size + align) + align - 1) &
+ ~(align - 1));
+}
+
+static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
+{
+ int i;
+ unsigned long reg = 0;
+ unsigned long msr;
+ unsigned long speed;
+ unsigned long duplex;
+ unsigned long failsafe;
+ unsigned mode_reg;
+ unsigned short devnum;
+ unsigned short reg_short;
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ sys_info_t sysinfo;
+#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ int ethgroup = -1;
+#endif
+#endif
+ u32 bd_cached;
+ u32 bd_uncached = 0;
+#ifdef CONFIG_4xx_DCACHE
+ static u32 last_used_ea = 0;
+#endif
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ int rgmii_channel;
+#endif
+
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ /* before doing anything, figure out if we have a MAC address */
+ /* if not, bail */
+ if (memcmp (dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) {
+ printf("ERROR: ethaddr not set!\n");
+ return -1;
+ }
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ /* Need to get the OPB frequency so we can access the PHY */
+ get_sys_info (&sysinfo);
+#endif
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE)); /* disable interrupts */
+
+ devnum = hw_p->devnum;
+
+#ifdef INFO_4XX_ENET
+ /* AS.HARNOIS
+ * We should have :
+ * hw_p->stats.pkts_handled <= hw_p->stats.pkts_rx <= hw_p->stats.pkts_handled+PKTBUFSRX
+ * In the most cases hw_p->stats.pkts_handled = hw_p->stats.pkts_rx, but it
+ * is possible that new packets (without relationship with
+ * current transfer) have got the time to arrived before
+ * netloop calls eth_halt
+ */
+ printf ("About preceeding transfer (eth%d):\n"
+ "- Sent packet number %d\n"
+ "- Received packet number %d\n"
+ "- Handled packet number %d\n",
+ hw_p->devnum,
+ hw_p->stats.pkts_tx,
+ hw_p->stats.pkts_rx, hw_p->stats.pkts_handled);
+
+ hw_p->stats.pkts_tx = 0;
+ hw_p->stats.pkts_rx = 0;
+ hw_p->stats.pkts_handled = 0;
+ hw_p->print_speed = 1; /* print speed message again next time */
+#endif
+
+ hw_p->tx_err_index = 0; /* Transmit Error Index for tx_err_log */
+ hw_p->rx_err_index = 0; /* Receive Error Index for rx_err_log */
+
+ hw_p->rx_slot = 0; /* MAL Receive Slot */
+ hw_p->rx_i_index = 0; /* Receive Interrupt Queue Index */
+ hw_p->rx_u_index = 0; /* Receive User Queue Index */
+
+ hw_p->tx_slot = 0; /* MAL Transmit Slot */
+ hw_p->tx_i_index = 0; /* Transmit Interrupt Queue Index */
+ hw_p->tx_u_index = 0; /* Transmit User Queue Index */
+
+#if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
+ /* set RMII mode */
+ /* NOTE: 440GX spec states that mode is mutually exclusive */
+ /* NOTE: Therefore, disable all other EMACS, since we handle */
+ /* NOTE: only one emac at a time */
+ reg = 0;
+ out_be32((void *)ZMII_FER, 0);
+ udelay (100);
+
+#if defined(CONFIG_440GP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ out_be32((void *)ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
+#elif defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
+#endif
+
+ out_be32((void *)ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
+#if defined(CONFIG_405EX)
+ ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
+#endif
+
+ sync();
+
+ /* provide clocks for EMAC internal loopback */
+ emac_loopback_enable(hw_p);
+
+ /* EMAC RESET */
+ out_be32((void *)EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);
+
+ /* remove clocks for EMAC internal loopback */
+ emac_loopback_disable(hw_p);
+
+ failsafe = 1000;
+ while ((in_be32((void *)EMAC_M0 + hw_p->hw_addr) & (EMAC_M0_SRST)) && failsafe) {
+ udelay (1000);
+ failsafe--;
+ }
+ if (failsafe <= 0)
+ printf("\nProblem resetting EMAC!\n");
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ /* Whack the M1 register */
+ mode_reg = 0x0;
+ mode_reg &= ~0x00000038;
+ if (sysinfo.freqOPB <= 50000000);
+ else if (sysinfo.freqOPB <= 66666667)
+ mode_reg |= EMAC_M1_OBCI_66;
+ else if (sysinfo.freqOPB <= 83333333)
+ mode_reg |= EMAC_M1_OBCI_83;
+ else if (sysinfo.freqOPB <= 100000000)
+ mode_reg |= EMAC_M1_OBCI_100;
+ else
+ mode_reg |= EMAC_M1_OBCI_GT100;
+
+ out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);
+#endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */
+
+#if defined(CONFIG_GPCS_PHY_ADDR) || defined(CONFIG_GPCS_PHY1_ADDR) || \
+ defined(CONFIG_GPCS_PHY2_ADDR) || defined(CONFIG_GPCS_PHY3_ADDR)
+ if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {
+ /*
+ * In SGMII mode, GPCS access is needed for
+ * communication with the internal SGMII SerDes.
+ */
+ switch (devnum) {
+#if defined(CONFIG_GPCS_PHY_ADDR)
+ case 0:
+ reg = CONFIG_GPCS_PHY_ADDR;
+ break;
+#endif
+#if defined(CONFIG_GPCS_PHY1_ADDR)
+ case 1:
+ reg = CONFIG_GPCS_PHY1_ADDR;
+ break;
+#endif
+#if defined(CONFIG_GPCS_PHY2_ADDR)
+ case 2:
+ reg = CONFIG_GPCS_PHY2_ADDR;
+ break;
+#endif
+#if defined(CONFIG_GPCS_PHY3_ADDR)
+ case 3:
+ reg = CONFIG_GPCS_PHY3_ADDR;
+ break;
+#endif
+ }
+
+ mode_reg = in_be32((void *)EMAC_M1 + hw_p->hw_addr);
+ mode_reg |= EMAC_M1_MF_1000GPCS | EMAC_M1_IPPA_SET(reg);
+ out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);
+
+ /* Configure GPCS interface to recommended setting for SGMII */
+ miiphy_reset(dev->name, reg);
+ miiphy_write(dev->name, reg, 0x04, 0x8120); /* AsymPause, FDX */
+ miiphy_write(dev->name, reg, 0x07, 0x2801); /* msg_pg, toggle */
+ miiphy_write(dev->name, reg, 0x00, 0x0140); /* 1Gbps, FDX */
+ }
+#endif /* defined(CONFIG_GPCS_PHY_ADDR) */
+
+ /* wait for PHY to complete auto negotiation */
+ reg_short = 0;
+ switch (devnum) {
+ case 0:
+ reg = CONFIG_PHY_ADDR;
+ break;
+#if defined (CONFIG_PHY1_ADDR)
+ case 1:
+ reg = CONFIG_PHY1_ADDR;
+ break;
+#endif
+#if defined (CONFIG_PHY2_ADDR)
+ case 2:
+ reg = CONFIG_PHY2_ADDR;
+ break;
+#endif
+#if defined (CONFIG_PHY3_ADDR)
+ case 3:
+ reg = CONFIG_PHY3_ADDR;
+ break;
+#endif
+ default:
+ reg = CONFIG_PHY_ADDR;
+ break;
+ }
+
+ bis->bi_phynum[devnum] = reg;
+
+ if (reg == CONFIG_FIXED_PHY)
+ goto get_speed;
+
+#if defined(CONFIG_PHY_RESET)
+ /*
+ * Reset the phy, only if its the first time through
+ * otherwise, just check the speeds & feeds
+ */
+ if (hw_p->first_init == 0) {
+#if defined(CONFIG_M88E1111_PHY)
+ miiphy_write (dev->name, reg, 0x14, 0x0ce3);
+ miiphy_write (dev->name, reg, 0x18, 0x4101);
+ miiphy_write (dev->name, reg, 0x09, 0x0e00);
+ miiphy_write (dev->name, reg, 0x04, 0x01e1);
+#endif
+#if defined(CONFIG_M88E1112_PHY)
+ if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {
+ /*
+ * Marvell 88E1112 PHY needs to have the SGMII MAC
+ * interace (page 2) properly configured to
+ * communicate with the 460EX/GT GPCS interface.
+ */
+
+ /* Set access to Page 2 */
+ miiphy_write(dev->name, reg, 0x16, 0x0002);
+
+ miiphy_write(dev->name, reg, 0x00, 0x0040); /* 1Gbps */
+ miiphy_read(dev->name, reg, 0x1a, &reg_short);
+ reg_short |= 0x8000; /* bypass Auto-Negotiation */
+ miiphy_write(dev->name, reg, 0x1a, reg_short);
+ miiphy_reset(dev->name, reg); /* reset MAC interface */
+
+ /* Reset access to Page 0 */
+ miiphy_write(dev->name, reg, 0x16, 0x0000);
+ }
+#endif /* defined(CONFIG_M88E1112_PHY) */
+ miiphy_reset (dev->name, reg);
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+
+#if defined(CONFIG_CIS8201_PHY)
+ /*
+ * Cicada 8201 PHY needs to have an extended register whacked
+ * for RGMII mode.
+ */
+ if (((devnum == 2) || (devnum == 3)) && (4 == ethgroup)) {
+#if defined(CONFIG_CIS8201_SHORT_ETCH)
+ miiphy_write (dev->name, reg, 23, 0x1300);
+#else
+ miiphy_write (dev->name, reg, 23, 0x1000);
+#endif
+ /*
+ * Vitesse VSC8201/Cicada CIS8201 errata:
+ * Interoperability problem with Intel 82547EI phys
+ * This work around (provided by Vitesse) changes
+ * the default timer convergence from 8ms to 12ms
+ */
+ miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+ miiphy_write (dev->name, reg, 0x08, 0x0200);
+ miiphy_write (dev->name, reg, 0x1f, 0x52b5);
+ miiphy_write (dev->name, reg, 0x02, 0x0004);
+ miiphy_write (dev->name, reg, 0x01, 0x0671);
+ miiphy_write (dev->name, reg, 0x00, 0x8fae);
+ miiphy_write (dev->name, reg, 0x1f, 0x2a30);
+ miiphy_write (dev->name, reg, 0x08, 0x0000);
+ miiphy_write (dev->name, reg, 0x1f, 0x0000);
+ /* end Vitesse/Cicada errata */
+ }
+#endif /* defined(CONFIG_CIS8201_PHY) */
+
+#if defined(CONFIG_ET1011C_PHY)
+ /*
+ * Agere ET1011c PHY needs to have an extended register whacked
+ * for RGMII mode.
+ */
+ if (((devnum == 2) || (devnum ==3)) && (4 == ethgroup)) {
+ miiphy_read (dev->name, reg, 0x16, &reg_short);
+ reg_short &= ~(0x7);
+ reg_short |= 0x6; /* RGMII DLL Delay*/
+ miiphy_write (dev->name, reg, 0x16, reg_short);
+
+ miiphy_read (dev->name, reg, 0x17, &reg_short);
+ reg_short &= ~(0x40);
+ miiphy_write (dev->name, reg, 0x17, reg_short);
+
+ miiphy_write(dev->name, reg, 0x1c, 0x74f0);
+ }
+#endif /* defined(CONFIG_ET1011C_PHY) */
+
+#endif /* defined(CONFIG_440GX) ... */
+ /* Start/Restart autonegotiation */
+ phy_setup_aneg (dev->name, reg);
+ udelay (1000);
+ }
+#endif /* defined(CONFIG_PHY_RESET) */
+
+ miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);
+
+ /*
+ * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
+ */
+ if ((reg_short & PHY_BMSR_AUTN_ABLE)
+ && !(reg_short & PHY_BMSR_AUTN_COMP)) {
+ puts ("Waiting for PHY auto negotiation to complete");
+ i = 0;
+ while (!(reg_short & PHY_BMSR_AUTN_COMP)) {
+ /*
+ * Timeout reached ?
+ */
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ puts (" TIMEOUT !\n");
+ break;
+ }
+
+ if ((i++ % 1000) == 0) {
+ putc ('.');
+ }
+ udelay (1000); /* 1 ms */
+ miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);
+ }
+ puts (" done\n");
+ udelay (500000); /* another 500 ms (results in faster booting) */
+ }
+
+get_speed:
+ if (reg == CONFIG_FIXED_PHY) {
+ for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
+ if (devnum == fixed_phy_port[i].devnum) {
+ speed = fixed_phy_port[i].speed;
+ duplex = fixed_phy_port[i].duplex;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(fixed_phy_port)) {
+ printf("ERROR: PHY (%s) not configured correctly!\n",
+ dev->name);
+ return -1;
+ }
+ } else {
+ speed = miiphy_speed(dev->name, reg);
+ duplex = miiphy_duplex(dev->name, reg);
+ }
+
+ if (hw_p->print_speed) {
+ hw_p->print_speed = 0;
+ printf ("ENET Speed is %d Mbps - %s duplex connection (EMAC%d)\n",
+ (int) speed, (duplex == HALF) ? "HALF" : "FULL",
+ hw_p->devnum);
+ }
+
+#if defined(CONFIG_440) && \
+ !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
+ !defined(CONFIG_440EPX) && !defined(CONFIG_440GRX) && \
+ !defined(CONFIG_460EX) && !defined(CONFIG_460GT)
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mfsdr(sdr_mfr, reg);
+ if (speed == 100) {
+ reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M;
+ } else {
+ reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M;
+ }
+ mtsdr(sdr_mfr, reg);
+#endif
+
+ /* Set ZMII/RGMII speed according to the phy link speed */
+ reg = in_be32((void *)ZMII_SSR);
+ if ( (speed == 100) || (speed == 1000) )
+ out_be32((void *)ZMII_SSR, reg | (ZMII_SSR_SP << ZMII_SSR_V (devnum)));
+ else
+ out_be32((void *)ZMII_SSR, reg & (~(ZMII_SSR_SP << ZMII_SSR_V (devnum))));
+
+ if ((devnum == 2) || (devnum == 3)) {
+ if (speed == 1000)
+ reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V (devnum));
+ else if (speed == 100)
+ reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V (devnum));
+ else if (speed == 10)
+ reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum));
+ else {
+ printf("Error in RGMII Speed\n");
+ return -1;
+ }
+ out_be32((void *)RGMII_SSR, reg);
+ }
+#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ if (devnum >= 2)
+ rgmii_channel = devnum - 2;
+ else
+ rgmii_channel = devnum;
+
+ if (speed == 1000)
+ reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V(rgmii_channel));
+ else if (speed == 100)
+ reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V(rgmii_channel));
+ else if (speed == 10)
+ reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V(rgmii_channel));
+ else {
+ printf("Error in RGMII Speed\n");
+ return -1;
+ }
+ out_be32((void *)RGMII_SSR, reg);
+#if defined(CONFIG_460GT)
+ if ((devnum == 2) || (devnum == 3))
+ out_be32((void *)RGMII_SSR + RGMII1_BASE_OFFSET, reg);
+#endif
+#endif
+
+ /* set the Mal configuration reg */
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA |
+ MAL_CR_PLBLT_DEFAULT | MAL_CR_EOPIE | 0x00330000);
+#else
+ mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+ /* Errata 1.12: MAL_1 -- Disable MAL bursting */
+ if (get_pvr() == PVR_440GP_RB) {
+ mtdcr (malmcr, mfdcr(malmcr) & ~MAL_CR_PLBB);
+ }
+#endif
+
+ /*
+ * Malloc MAL buffer desciptors, make sure they are
+ * aligned on cache line boundary size
+ * (401/403/IOP480 = 16, 405 = 32)
+ * and doesn't cross cache block boundaries.
+ */
+ if (hw_p->first_init == 0) {
+ debug("*** Allocating descriptor memory ***\n");
+
+ bd_cached = (u32)malloc_aligned(MAL_ALLOC_SIZE, 4096);
+ if (!bd_cached) {
+ printf("%s: Error allocating MAL descriptor buffers!\n", __func__);
+ return -1;
+ }
+
+#ifdef CONFIG_4xx_DCACHE
+ flush_dcache_range(bd_cached, bd_cached + MAL_ALLOC_SIZE);
+ if (!last_used_ea)
+#if defined(CONFIG_SYS_MEM_TOP_HIDE)
+ bd_uncached = bis->bi_memsize + CONFIG_SYS_MEM_TOP_HIDE;
+#else
+ bd_uncached = bis->bi_memsize;
+#endif
+ else
+ bd_uncached = last_used_ea + MAL_ALLOC_SIZE;
+
+ last_used_ea = bd_uncached;
+ program_tlb(bd_cached, bd_uncached, MAL_ALLOC_SIZE,
+ TLB_WORD2_I_ENABLE);
+#else
+ bd_uncached = bd_cached;
+#endif
+ hw_p->tx_phys = bd_cached;
+ hw_p->rx_phys = bd_cached + MAL_TX_DESC_SIZE;
+ hw_p->tx = (mal_desc_t *)(bd_uncached);
+ hw_p->rx = (mal_desc_t *)(bd_uncached + MAL_TX_DESC_SIZE);
+ debug("hw_p->tx=%08x, hw_p->rx=%08x\n", hw_p->tx, hw_p->rx);
+ }
+
+ for (i = 0; i < NUM_TX_BUFF; i++) {
+ hw_p->tx[i].ctrl = 0;
+ hw_p->tx[i].data_len = 0;
+ if (hw_p->first_init == 0)
+ hw_p->txbuf_ptr = malloc_aligned(MAL_ALLOC_SIZE,
+ L1_CACHE_BYTES);
+ hw_p->tx[i].data_ptr = hw_p->txbuf_ptr;
+ if ((NUM_TX_BUFF - 1) == i)
+ hw_p->tx[i].ctrl |= MAL_TX_CTRL_WRAP;
+ hw_p->tx_run[i] = -1;
+ debug("TX_BUFF %d @ 0x%08lx\n", i, (u32)hw_p->tx[i].data_ptr);
+ }
+
+ for (i = 0; i < NUM_RX_BUFF; i++) {
+ hw_p->rx[i].ctrl = 0;
+ hw_p->rx[i].data_len = 0;
+ hw_p->rx[i].data_ptr = (char *)NetRxPackets[i];
+ if ((NUM_RX_BUFF - 1) == i)
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_WRAP;
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
+ hw_p->rx_ready[i] = -1;
+ debug("RX_BUFF %d @ 0x%08lx\n", i, (u32)hw_p->rx[i].data_ptr);
+ }
+
+ reg = 0x00000000;
+
+ reg |= dev->enetaddr[0]; /* set high address */
+ reg = reg << 8;
+ reg |= dev->enetaddr[1];
+
+ out_be32((void *)EMAC_IAH + hw_p->hw_addr, reg);
+
+ reg = 0x00000000;
+ reg |= dev->enetaddr[2]; /* set low address */
+ reg = reg << 8;
+ reg |= dev->enetaddr[3];
+ reg = reg << 8;
+ reg |= dev->enetaddr[4];
+ reg = reg << 8;
+ reg |= dev->enetaddr[5];
+
+ out_be32((void *)EMAC_IAL + hw_p->hw_addr, reg);
+
+ switch (devnum) {
+ case 1:
+ /* setup MAL tx & rx channel pointers */
+#if defined (CONFIG_405EP) || defined (CONFIG_440EP) || defined (CONFIG_440GR)
+ mtdcr (maltxctp2r, hw_p->tx_phys);
+#else
+ mtdcr (maltxctp1r, hw_p->tx_phys);
+#endif
+#if defined(CONFIG_440)
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ mtdcr (malrxctp8r, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (malrcbs8, ENET_MAX_MTU_ALIGNED / 16);
+#else
+ mtdcr (malrxctp1r, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (malrcbs1, ENET_MAX_MTU_ALIGNED / 16);
+#endif
+ break;
+#if defined (CONFIG_440GX)
+ case 2:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+ mtdcr (maltxctp2r, hw_p->tx_phys);
+ mtdcr (malrxctp2r, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (malrcbs2, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ case 3:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (maltxctp3r, hw_p->tx_phys);
+ mtdcr (malrxbattr, 0x0);
+ mtdcr (malrxctp3r, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (malrcbs3, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+#endif /* CONFIG_440GX */
+#if defined (CONFIG_460GT)
+ case 2:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+ mtdcr (maltxctp2r, hw_p->tx_phys);
+ mtdcr (malrxctp16r, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (malrcbs16, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ case 3:
+ /* setup MAL tx & rx channel pointers */
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+ mtdcr (maltxctp3r, hw_p->tx_phys);
+ mtdcr (malrxctp24r, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (malrcbs24, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+#endif /* CONFIG_460GT */
+ case 0:
+ default:
+ /* setup MAL tx & rx channel pointers */
+#if defined(CONFIG_440)
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+#endif
+ mtdcr (maltxctp0r, hw_p->tx_phys);
+ mtdcr (malrxctp0r, hw_p->rx_phys);
+ /* set RX buffer size */
+ mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16);
+ break;
+ }
+
+ /* Enable MAL transmit and receive channels */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (maltxcasr, (MAL_TXRX_CASR >> (hw_p->devnum*2)));
+#else
+ mtdcr (maltxcasr, (MAL_TXRX_CASR >> hw_p->devnum));
+#endif
+ mtdcr (malrxcasr, (MAL_TXRX_CASR >> hw_p->devnum));
+
+ /* set transmit enable & receive enable */
+ out_be32((void *)EMAC_M0 + hw_p->hw_addr, EMAC_M0_TXE | EMAC_M0_RXE);
+
+ mode_reg = in_be32((void *)EMAC_M1 + hw_p->hw_addr);
+
+ /* set rx-/tx-fifo size */
+ mode_reg = (mode_reg & ~EMAC_MR1_FIFO_MASK) | EMAC_MR1_FIFO_SIZE;
+
+ /* set speed */
+ if (speed == _1000BASET) {
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ unsigned long pfc1;
+
+ mfsdr (sdr_pfc1, pfc1);
+ pfc1 |= SDR0_PFC1_EM_1000;
+ mtsdr (sdr_pfc1, pfc1);
+#endif
+ mode_reg = mode_reg | EMAC_M1_MF_1000MBPS | EMAC_M1_IST;
+ } else if (speed == _100BASET)
+ mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
+ else
+ mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */
+ if (duplex == FULL)
+ mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST;
+
+ out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);
+
+ /* Enable broadcast and indvidual address */
+ /* TBS: enabling runts as some misbehaved nics will send runts */
+ out_be32((void *)EMAC_RXM + hw_p->hw_addr, EMAC_RMR_BAE | EMAC_RMR_IAE);
+
+ /* we probably need to set the tx mode1 reg? maybe at tx time */
+
+ /* set transmit request threshold register */
+ out_be32((void *)EMAC_TRTR + hw_p->hw_addr, 0x18000000); /* 256 byte threshold */
+
+ /* set receive low/high water mark register */
+#if defined(CONFIG_440)
+ /* 440s has a 64 byte burst length */
+ out_be32((void *)EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x80009000);
+#else
+ /* 405s have a 16 byte burst length */
+ out_be32((void *)EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x0f002000);
+#endif /* defined(CONFIG_440) */
+ out_be32((void *)EMAC_TXM1 + hw_p->hw_addr, 0xf8640000);
+
+ /* Set fifo limit entry in tx mode 0 */
+ out_be32((void *)EMAC_TXM0 + hw_p->hw_addr, 0x00000003);
+ /* Frame gap set */
+ out_be32((void *)EMAC_I_FRAME_GAP_REG + hw_p->hw_addr, 0x00000008);
+
+ /* Set EMAC IER */
+ hw_p->emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE;
+ if (speed == _100BASET)
+ hw_p->emac_ier = hw_p->emac_ier | EMAC_ISR_SYE;
+
+ out_be32((void *)EMAC_ISR + hw_p->hw_addr, 0xffffffff); /* clear pending interrupts */
+ out_be32((void *)EMAC_IER + hw_p->hw_addr, hw_p->emac_ier);
+
+ if (hw_p->first_init == 0) {
+ /*
+ * Connect interrupt service routines
+ */
+ irq_install_handler(ETH_IRQ_NUM(hw_p->devnum),
+ (interrupt_handler_t *) enetInt, dev);
+ }
+
+ mtmsr (msr); /* enable interrupts again */
+
+ hw_p->bis = bis;
+ hw_p->first_init = 1;
+
+ return 0;
+}
+
+
+static int ppc_4xx_eth_send (struct eth_device *dev, volatile void *ptr,
+ int len)
+{
+ struct enet_frame *ef_ptr;
+ ulong time_start, time_now;
+ unsigned long temp_txm0;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ ef_ptr = (struct enet_frame *) ptr;
+
+ /*-----------------------------------------------------------------------+
+ * Copy in our address into the frame.
+ *-----------------------------------------------------------------------*/
+ (void) memcpy (ef_ptr->source_addr, dev->enetaddr, ENET_ADDR_LENGTH);
+
+ /*-----------------------------------------------------------------------+
+ * If frame is too long or too short, modify length.
+ *-----------------------------------------------------------------------*/
+ /* TBS: where does the fragment go???? */
+ if (len > ENET_MAX_MTU)
+ len = ENET_MAX_MTU;
+
+ /* memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */
+ memcpy ((void *) hw_p->txbuf_ptr, (const void *) ptr, len);
+ flush_dcache_range((u32)hw_p->txbuf_ptr, (u32)hw_p->txbuf_ptr + len);
+
+ /*-----------------------------------------------------------------------+
+ * set TX Buffer busy, and send it
+ *-----------------------------------------------------------------------*/
+ hw_p->tx[hw_p->tx_slot].ctrl = (MAL_TX_CTRL_LAST |
+ EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP) &
+ ~(EMAC_TX_CTRL_ISA | EMAC_TX_CTRL_RSA);
+ if ((NUM_TX_BUFF - 1) == hw_p->tx_slot)
+ hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_WRAP;
+
+ hw_p->tx[hw_p->tx_slot].data_len = (short) len;
+ hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_READY;
+
+ sync();
+
+ out_be32((void *)EMAC_TXM0 + hw_p->hw_addr,
+ in_be32((void *)EMAC_TXM0 + hw_p->hw_addr) | EMAC_TXM0_GNP0);
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_tx++;
+#endif
+
+ /*-----------------------------------------------------------------------+
+ * poll unitl the packet is sent and then make sure it is OK
+ *-----------------------------------------------------------------------*/
+ time_start = get_timer (0);
+ while (1) {
+ temp_txm0 = in_be32((void *)EMAC_TXM0 + hw_p->hw_addr);
+ /* loop until either TINT turns on or 3 seconds elapse */
+ if ((temp_txm0 & EMAC_TXM0_GNP0) != 0) {
+ /* transmit is done, so now check for errors
+ * If there is an error, an interrupt should
+ * happen when we return
+ */
+ time_now = get_timer (0);
+ if ((time_now - time_start) > 3000) {
+ return (-1);
+ }
+ } else {
+ return (len);
+ }
+ }
+}
+
+int enetInt (struct eth_device *dev)
+{
+ int serviced;
+ int rc = -1; /* default to not us */
+ u32 mal_isr;
+ u32 emac_isr = 0;
+ u32 mal_eob;
+ u32 uic_mal;
+ u32 uic_mal_err;
+ u32 uic_emac;
+ u32 uic_emac_b;
+ EMAC_4XX_HW_PST hw_p;
+
+ /*
+ * Because the mal is generic, we need to get the current
+ * eth device
+ */
+#if defined(CONFIG_NET_MULTI)
+ dev = eth_get_dev();
+#else
+ dev = emac0_dev;
+#endif
+
+ hw_p = dev->priv;
+
+ /* enter loop that stays in interrupt code until nothing to service */
+ do {
+ serviced = 0;
+
+ uic_mal = mfdcr(UIC_BASE_MAL + UIC_MSR);
+ uic_mal_err = mfdcr(UIC_BASE_MAL_ERR + UIC_MSR);
+ uic_emac = mfdcr(UIC_BASE_EMAC + UIC_MSR);
+ uic_emac_b = mfdcr(UIC_BASE_EMAC_B + UIC_MSR);
+
+ if (!(uic_mal & (UIC_MAL_RXEOB | UIC_MAL_TXEOB))
+ && !(uic_mal_err & (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE))
+ && !(uic_emac & UIC_ETHx) && !(uic_emac_b & UIC_ETHxB)) {
+ /* not for us */
+ return (rc);
+ }
+
+ /* get and clear controller status interrupts */
+ /* look at MAL and EMAC error interrupts */
+ if (uic_mal_err & (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)) {
+ /* we have a MAL error interrupt */
+ mal_isr = mfdcr(malesr);
+ mal_err(dev, mal_isr, uic_mal_err,
+ MAL_UIC_DEF, MAL_UIC_ERR);
+
+ /* clear MAL error interrupt status bits */
+ mtdcr(UIC_BASE_MAL_ERR + UIC_SR,
+ UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE);
+
+ return -1;
+ }
+
+ /* look for EMAC errors */
+ if ((uic_emac & UIC_ETHx) || (uic_emac_b & UIC_ETHxB)) {
+ emac_isr = in_be32((void *)EMAC_ISR + hw_p->hw_addr);
+ emac_err(dev, emac_isr);
+
+ /* clear EMAC error interrupt status bits */
+ mtdcr(UIC_BASE_EMAC + UIC_SR, UIC_ETHx);
+ mtdcr(UIC_BASE_EMAC_B + UIC_SR, UIC_ETHxB);
+
+ return -1;
+ }
+
+ /* handle MAX TX EOB interrupt from a tx */
+ if (uic_mal & UIC_MAL_TXEOB) {
+ /* clear MAL interrupt status bits */
+ mal_eob = mfdcr(maltxeobisr);
+ mtdcr(maltxeobisr, mal_eob);
+ mtdcr(UIC_BASE_MAL + UIC_SR, UIC_MAL_TXEOB);
+
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+
+ /* handle MAL RX EOB interupt from a receive */
+ /* check for EOB on valid channels */
+ if (uic_mal & UIC_MAL_RXEOB) {
+ mal_eob = mfdcr(malrxeobisr);
+ if (mal_eob &
+ (0x80000000 >> (hw_p->devnum * MAL_RX_CHAN_MUL))) {
+ /* push packet to upper layer */
+ enet_rcv(dev, emac_isr);
+
+ /* clear MAL interrupt status bits */
+ mtdcr(UIC_BASE_MAL + UIC_SR, UIC_MAL_RXEOB);
+
+ /* indicate that we serviced an interrupt */
+ serviced = 1;
+ rc = 0;
+ }
+ }
+ } while (serviced);
+
+ return (rc);
+}
+
+/*-----------------------------------------------------------------------------+
+ * MAL Error Routine
+ *-----------------------------------------------------------------------------*/
+static void mal_err (struct eth_device *dev, unsigned long isr,
+ unsigned long uic, unsigned long maldef,
+ unsigned long mal_errr)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ mtdcr (malesr, isr); /* clear interrupt */
+
+ /* clear DE interrupt */
+ mtdcr (maltxdeir, 0xC0000000);
+ mtdcr (malrxdeir, 0x80000000);
+
+#ifdef INFO_4XX_ENET
+ printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n", isr, uic, maldef, mal_errr);
+#endif
+
+ eth_init (hw_p->bis); /* start again... */
+}
+
+/*-----------------------------------------------------------------------------+
+ * EMAC Error Routine
+ *-----------------------------------------------------------------------------*/
+static void emac_err (struct eth_device *dev, unsigned long isr)
+{
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ printf ("EMAC%d error occured.... ISR = %lx\n", hw_p->devnum, isr);
+ out_be32((void *)EMAC_ISR + hw_p->hw_addr, isr);
+}
+
+/*-----------------------------------------------------------------------------+
+ * enet_rcv() handles the ethernet receive data
+ *-----------------------------------------------------------------------------*/
+static void enet_rcv (struct eth_device *dev, unsigned long malisr)
+{
+ struct enet_frame *ef_ptr;
+ unsigned long data_len;
+ unsigned long rx_eob_isr;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ int handled = 0;
+ int i;
+ int loop_count = 0;
+
+ rx_eob_isr = mfdcr (malrxeobisr);
+ if ((0x80000000 >> (hw_p->devnum * MAL_RX_CHAN_MUL)) & rx_eob_isr) {
+ /* clear EOB */
+ mtdcr (malrxeobisr, rx_eob_isr);
+
+ /* EMAC RX done */
+ while (1) { /* do all */
+ i = hw_p->rx_slot;
+
+ if ((MAL_RX_CTRL_EMPTY & hw_p->rx[i].ctrl)
+ || (loop_count >= NUM_RX_BUFF))
+ break;
+
+ loop_count++;
+ handled++;
+ data_len = (unsigned long) hw_p->rx[i].data_len & 0x0fff; /* Get len */
+ if (data_len) {
+ if (data_len > ENET_MAX_MTU) /* Check len */
+ data_len = 0;
+ else {
+ if (EMAC_RX_ERRORS & hw_p->rx[i].ctrl) { /* Check Errors */
+ data_len = 0;
+ hw_p->stats.rx_err_log[hw_p->
+ rx_err_index]
+ = hw_p->rx[i].ctrl;
+ hw_p->rx_err_index++;
+ if (hw_p->rx_err_index ==
+ MAX_ERR_LOG)
+ hw_p->rx_err_index =
+ 0;
+ } /* emac_erros */
+ } /* data_len < max mtu */
+ } /* if data_len */
+ if (!data_len) { /* no data */
+ hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY; /* Free Recv Buffer */
+
+ hw_p->stats.data_len_err++; /* Error at Rx */
+ }
+
+ /* !data_len */
+ /* AS.HARNOIS */
+ /* Check if user has already eaten buffer */
+ /* if not => ERROR */
+ else if (hw_p->rx_ready[hw_p->rx_i_index] != -1) {
+ if (hw_p->is_receiving)
+ printf ("ERROR : Receive buffers are full!\n");
+ break;
+ } else {
+ hw_p->stats.rx_frames++;
+ hw_p->stats.rx += data_len;
+ ef_ptr = (struct enet_frame *) hw_p->rx[i].
+ data_ptr;
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_rx++;
+#endif
+ /* AS.HARNOIS
+ * use ring buffer
+ */
+ hw_p->rx_ready[hw_p->rx_i_index] = i;
+ hw_p->rx_i_index++;
+ if (NUM_RX_BUFF == hw_p->rx_i_index)
+ hw_p->rx_i_index = 0;
+
+ hw_p->rx_slot++;
+ if (NUM_RX_BUFF == hw_p->rx_slot)
+ hw_p->rx_slot = 0;
+
+ /* AS.HARNOIS
+ * free receive buffer only when
+ * buffer has been handled (eth_rx)
+ rx[i].ctrl |= MAL_RX_CTRL_EMPTY;
+ */
+ } /* if data_len */
+ } /* while */
+ } /* if EMACK_RXCHL */
+}
+
+
+static int ppc_4xx_eth_rx (struct eth_device *dev)
+{
+ int length;
+ int user_index;
+ unsigned long msr;
+ EMAC_4XX_HW_PST hw_p = dev->priv;
+
+ hw_p->is_receiving = 1; /* tell driver */
+
+ for (;;) {
+ /* AS.HARNOIS
+ * use ring buffer and
+ * get index from rx buffer desciptor queue
+ */
+ user_index = hw_p->rx_ready[hw_p->rx_u_index];
+ if (user_index == -1) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ msr = mfmsr ();
+ mtmsr (msr & ~(MSR_EE));
+
+ length = hw_p->rx[user_index].data_len & 0x0fff;
+
+ /* Pass the packet up to the protocol layers. */
+ /* NetReceive(NetRxPackets[rxIdx], length - 4); */
+ /* NetReceive(NetRxPackets[i], length); */
+ invalidate_dcache_range((u32)hw_p->rx[user_index].data_ptr,
+ (u32)hw_p->rx[user_index].data_ptr +
+ length - 4);
+ NetReceive (NetRxPackets[user_index], length - 4);
+ /* Free Recv Buffer */
+ hw_p->rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
+ /* Free rx buffer descriptor queue */
+ hw_p->rx_ready[hw_p->rx_u_index] = -1;
+ hw_p->rx_u_index++;
+ if (NUM_RX_BUFF == hw_p->rx_u_index)
+ hw_p->rx_u_index = 0;
+
+#ifdef INFO_4XX_ENET
+ hw_p->stats.pkts_handled++;
+#endif
+
+ mtmsr (msr); /* Enable IRQ's */
+ }
+
+ hw_p->is_receiving = 0; /* tell driver */
+
+ return length;
+}
+
+int ppc_4xx_eth_initialize (bd_t * bis)
+{
+ static int virgin = 0;
+ struct eth_device *dev;
+ int eth_num = 0;
+ EMAC_4XX_HW_PST hw = NULL;
+ u8 ethaddr[4 + CONFIG_EMAC_NR_START][6];
+ u32 hw_addr[4];
+ u32 mal_ier;
+
+#if defined(CONFIG_440GX)
+ unsigned long pfc1;
+
+ mfsdr (sdr_pfc1, pfc1);
+ pfc1 &= ~(0x01e00000);
+ pfc1 |= 0x01200000;
+ mtsdr (sdr_pfc1, pfc1);
+#endif
+
+ /* first clear all mac-addresses */
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++)
+ memcpy(ethaddr[eth_num], "\0\0\0\0\0\0", 6);
+
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+ switch (eth_num) {
+ default: /* fall through */
+ case 0:
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enetaddr, 6);
+ hw_addr[eth_num] = 0x0;
+ break;
+#ifdef CONFIG_HAS_ETH1
+ case 1:
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enet1addr, 6);
+ hw_addr[eth_num] = 0x100;
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH2
+ case 2:
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enet2addr, 6);
+#if defined(CONFIG_460GT)
+ hw_addr[eth_num] = 0x300;
+#else
+ hw_addr[eth_num] = 0x400;
+#endif
+ break;
+#endif
+#ifdef CONFIG_HAS_ETH3
+ case 3:
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enet3addr, 6);
+#if defined(CONFIG_460GT)
+ hw_addr[eth_num] = 0x400;
+#else
+ hw_addr[eth_num] = 0x600;
+#endif
+ break;
+#endif
+ }
+ }
+
+ /* set phy num and mode */
+ bis->bi_phynum[0] = CONFIG_PHY_ADDR;
+ bis->bi_phymode[0] = 0;
+
+#if defined(CONFIG_PHY1_ADDR)
+ bis->bi_phynum[1] = CONFIG_PHY1_ADDR;
+ bis->bi_phymode[1] = 0;
+#endif
+#if defined(CONFIG_440GX)
+ bis->bi_phynum[2] = CONFIG_PHY2_ADDR;
+ bis->bi_phynum[3] = CONFIG_PHY3_ADDR;
+ bis->bi_phymode[2] = 2;
+ bis->bi_phymode[3] = 2;
+#endif
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_405EX)
+ ppc_4xx_eth_setup_bridge(0, bis);
+#endif
+
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+ /*
+ * See if we can actually bring up the interface,
+ * otherwise, skip it
+ */
+ if (memcmp (ethaddr[eth_num], "\0\0\0\0\0\0", 6) == 0) {
+ bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+ continue;
+ }
+
+ /* Allocate device structure */
+ dev = (struct eth_device *) malloc (sizeof (*dev));
+ if (dev == NULL) {
+ printf ("ppc_4xx_eth_initialize: "
+ "Cannot allocate eth_device %d\n", eth_num);
+ return (-1);
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ /* Allocate our private use data */
+ hw = (EMAC_4XX_HW_PST) malloc (sizeof (*hw));
+ if (hw == NULL) {
+ printf ("ppc_4xx_eth_initialize: "
+ "Cannot allocate private hw data for eth_device %d",
+ eth_num);
+ free (dev);
+ return (-1);
+ }
+ memset(hw, 0, sizeof(*hw));
+
+ hw->hw_addr = hw_addr[eth_num];
+ memcpy (dev->enetaddr, ethaddr[eth_num], 6);
+ hw->devnum = eth_num;
+ hw->print_speed = 1;
+
+ sprintf (dev->name, "ppc_4xx_eth%d", eth_num - CONFIG_EMAC_NR_START);
+ dev->priv = (void *) hw;
+ dev->init = ppc_4xx_eth_init;
+ dev->halt = ppc_4xx_eth_halt;
+ dev->send = ppc_4xx_eth_send;
+ dev->recv = ppc_4xx_eth_rx;
+
+ if (0 == virgin) {
+ /* set the MAL IER ??? names may change with new spec ??? */
+#if defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+ mal_ier =
+ MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE |
+ MAL_IER_DE | MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE ;
+#else
+ mal_ier =
+ MAL_IER_DE | MAL_IER_NE | MAL_IER_TE |
+ MAL_IER_OPBE | MAL_IER_PLBE;
+#endif
+ mtdcr (malesr, 0xffffffff); /* clear pending interrupts */
+ mtdcr (maltxdeir, 0xffffffff); /* clear pending interrupts */
+ mtdcr (malrxdeir, 0xffffffff); /* clear pending interrupts */
+ mtdcr (malier, mal_ier);
+
+ /* install MAL interrupt handler */
+ irq_install_handler (VECNUM_MAL_SERR,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_TXEOB,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_RXEOB,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_TXDE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ irq_install_handler (VECNUM_MAL_RXDE,
+ (interrupt_handler_t *) enetInt,
+ dev);
+ virgin = 1;
+ }
+
+#if defined(CONFIG_NET_MULTI)
+ eth_register (dev);
+#else
+ emac0_dev = dev;
+#endif
+
+#if defined(CONFIG_NET_MULTI)
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register (dev->name,
+ emac4xx_miiphy_read, emac4xx_miiphy_write);
+#endif
+#endif
+ } /* end for each supported device */
+
+ return 0;
+}
+
+#if !defined(CONFIG_NET_MULTI)
+void eth_halt (void) {
+ if (emac0_dev) {
+ ppc_4xx_eth_halt(emac0_dev);
+ free(emac0_dev);
+ emac0_dev = NULL;
+ }
+}
+
+int eth_init (bd_t *bis)
+{
+ ppc_4xx_eth_initialize(bis);
+ if (emac0_dev) {
+ return ppc_4xx_eth_init(emac0_dev, bis);
+ } else {
+ printf("ERROR: ethaddr not set!\n");
+ return -1;
+ }
+}
+
+int eth_send(volatile void *packet, int length)
+{
+ return (ppc_4xx_eth_send(emac0_dev, packet, length));
+}
+
+int eth_rx(void)
+{
+ return (ppc_4xx_eth_rx(emac0_dev));
+}
+
+int emac4xx_miiphy_initialize (bd_t * bis)
+{
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register ("ppc_4xx_eth0",
+ emac4xx_miiphy_read, emac4xx_miiphy_write);
+#endif
+
+ return 0;
+}
+#endif /* !defined(CONFIG_NET_MULTI) */
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a084000..631336a 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libnet.a
COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o
+COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o
COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o
COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o
COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o
@@ -34,20 +35,18 @@ COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o
COBJS-$(CONFIG_E1000) += e1000.o
COBJS-$(CONFIG_EEPRO100) += eepro100.o
COBJS-$(CONFIG_ENC28J60) += enc28j60.o
-COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o
+COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
COBJS-$(CONFIG_GRETH) += greth.o
COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
COBJS-$(CONFIG_DRIVER_LAN91C96) += lan91c96.o
COBJS-$(CONFIG_MACB) += macb.o
-COBJS-$(CONFIG_MCFFEC) += mcffec.o
+COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
COBJS-$(CONFIG_MPC512x_FEC) += mpc512x_fec.o
COBJS-$(CONFIG_NATSEMI) += natsemi.o
-ifeq ($(CONFIG_DRIVER_NE2000),y)
-COBJS-y += ne2000.o
-COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o
-endif
+COBJS-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o
+COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o
COBJS-$(CONFIG_DRIVER_NETARMETH) += netarm_eth.o
COBJS-$(CONFIG_NETCONSOLE) += netconsole.o
COBJS-$(CONFIG_DRIVER_NS7520_ETHERNET) += ns7520_eth.o
@@ -55,6 +54,7 @@ COBJS-$(CONFIG_NS8382X) += ns8382x.o
COBJS-$(CONFIG_DRIVER_NS9750_ETHERNET) += ns9750_eth.o
COBJS-$(CONFIG_PCNET) += pcnet.o
COBJS-$(CONFIG_PLB2800_ETHER) += plb2800_eth.o
+COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
COBJS-$(CONFIG_DRIVER_RTL8019) += rtl8019.o
COBJS-$(CONFIG_RTL8139) += rtl8139.o
COBJS-$(CONFIG_RTL8169) += rtl8169.o
diff --git a/drivers/net/ax88180.c b/drivers/net/ax88180.c
new file mode 100644
index 0000000..d843397
--- /dev/null
+++ b/drivers/net/ax88180.c
@@ -0,0 +1,727 @@
+/*
+ * ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver
+ *
+ * This program is free software; you can distribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ * This program is distributed in the hope 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.
+ */
+
+/*
+ * ========================================================================
+ * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
+ *
+ * The AX88180 Ethernet controller is a high performance and highly
+ * integrated local CPU bus Ethernet controller with embedded 40K bytes
+ * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
+ * embedded systems.
+ * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
+ * controller that supports both MII and RGMII interfaces and is
+ * compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
+ *
+ * Please visit ASIX's web site (http://www.asix.com.tw) for more
+ * details.
+ *
+ * Module Name : ax88180.c
+ * Date : 2008-07-07
+ * History
+ * 09/06/2006 : New release for AX88180 US2 chip.
+ * 07/07/2008 : Fix up the coding style and using inline functions
+ * instead of macros
+ * ========================================================================
+ */
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <malloc.h>
+#include "ax88180.h"
+
+/*
+ * ===========================================================================
+ * Local SubProgram Declaration
+ * ===========================================================================
+ */
+static void ax88180_rx_handler (struct eth_device *dev);
+static int ax88180_phy_initial (struct eth_device *dev);
+static void ax88180_meidia_config (struct eth_device *dev);
+static unsigned long get_CicadaPHY_meida_mode (struct eth_device *dev);
+static unsigned long get_MarvellPHY_meida_mode (struct eth_device *dev);
+static unsigned short ax88180_mdio_read (struct eth_device *dev,
+ unsigned long regaddr);
+static void ax88180_mdio_write (struct eth_device *dev,
+ unsigned long regaddr, unsigned short regdata);
+
+/*
+ * ===========================================================================
+ * Local SubProgram Bodies
+ * ===========================================================================
+ */
+static int ax88180_mdio_check_complete (struct eth_device *dev)
+{
+ int us_cnt = 10000;
+ unsigned short tmpval;
+
+ /* MDIO read/write should not take more than 10 ms */
+ while (--us_cnt) {
+ tmpval = INW (dev, MDIOCTRL);
+ if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0))
+ break;
+ }
+
+ return us_cnt;
+}
+
+static unsigned short
+ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long tmpval = 0;
+
+ OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
+
+ if (ax88180_mdio_check_complete (dev))
+ tmpval = INW (dev, MDIODP);
+ else
+ printf ("Failed to read PHY register!\n");
+
+ return (unsigned short)(tmpval & 0xFFFF);
+}
+
+static void
+ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr,
+ unsigned short regdata)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+
+ OUTW (dev, regdata, MDIODP);
+
+ OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
+
+ if (!ax88180_mdio_check_complete (dev))
+ printf ("Failed to write PHY register!\n");
+}
+
+static int ax88180_phy_reset (struct eth_device *dev)
+{
+ unsigned short delay_cnt = 500;
+
+ ax88180_mdio_write (dev, BMCR, (PHY_RESET | AUTONEG_EN));
+
+ /* Wait for the reset to complete, or time out (500 ms) */
+ while (ax88180_mdio_read (dev, BMCR) & PHY_RESET) {
+ udelay (1000);
+ if (--delay_cnt == 0) {
+ printf ("Failed to reset PHY!\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void ax88180_mac_reset (struct eth_device *dev)
+{
+ unsigned long tmpval;
+ unsigned char i;
+
+ struct {
+ unsigned short offset, value;
+ } program_seq[] = {
+ {
+ MISC, MISC_NORMAL}, {
+ RXINDICATOR, DEFAULT_RXINDICATOR}, {
+ TXCMD, DEFAULT_TXCMD}, {
+ TXBS, DEFAULT_TXBS}, {
+ TXDES0, DEFAULT_TXDES0}, {
+ TXDES1, DEFAULT_TXDES1}, {
+ TXDES2, DEFAULT_TXDES2}, {
+ TXDES3, DEFAULT_TXDES3}, {
+ TXCFG, DEFAULT_TXCFG}, {
+ MACCFG2, DEFAULT_MACCFG2}, {
+ MACCFG3, DEFAULT_MACCFG3}, {
+ TXLEN, DEFAULT_TXLEN}, {
+ RXBTHD0, DEFAULT_RXBTHD0}, {
+ RXBTHD1, DEFAULT_RXBTHD1}, {
+ RXFULTHD, DEFAULT_RXFULTHD}, {
+ DOGTHD0, DEFAULT_DOGTHD0}, {
+ DOGTHD1, DEFAULT_DOGTHD1},};
+
+ OUTW (dev, MISC_RESET_MAC, MISC);
+ tmpval = INW (dev, MISC);
+
+ for (i = 0; i < (sizeof (program_seq) / sizeof (program_seq[0])); i++)
+ OUTW (dev, program_seq[i].value, program_seq[i].offset);
+}
+
+static int ax88180_poll_tx_complete (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long tmpval, txbs_txdp;
+ int TimeOutCnt = 10000;
+
+ txbs_txdp = 1 << priv->NextTxDesc;
+
+ while (TimeOutCnt--) {
+
+ tmpval = INW (dev, TXBS);
+
+ if ((tmpval & txbs_txdp) == 0)
+ break;
+
+ udelay (100);
+ }
+
+ if (TimeOutCnt)
+ return 0;
+ else
+ return -TimeOutCnt;
+}
+
+static void ax88180_rx_handler (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long data_size;
+ unsigned short rxcurt_ptr, rxbound_ptr, next_ptr;
+ int i;
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ unsigned short *rxdata = (unsigned short *)NetRxPackets[0];
+#else
+ unsigned long *rxdata = (unsigned long *)NetRxPackets[0];
+#endif
+ unsigned short count;
+
+ rxcurt_ptr = INW (dev, RXCURT);
+ rxbound_ptr = INW (dev, RXBOUND);
+ next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
+
+ debug ("ax88180: RX original RXBOUND=0x%04x,"
+ " RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
+
+ while (next_ptr != rxcurt_ptr) {
+
+ OUTW (dev, RX_START_READ, RXINDICATOR);
+
+ data_size = READ_RXBUF (dev) & 0xFFFF;
+
+ if ((data_size == 0) || (data_size > MAX_RX_SIZE)) {
+
+ OUTW (dev, RX_STOP_READ, RXINDICATOR);
+
+ ax88180_mac_reset (dev);
+ printf ("ax88180: Invalid Rx packet length!"
+ " (len=0x%04lx)\n", data_size);
+
+ debug ("ax88180: RX RXBOUND=0x%04x,"
+ "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
+ return;
+ }
+
+ rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1;
+ rxbound_ptr &= RX_PAGE_NUM_MASK;
+
+ /* Comput access times */
+ count = (data_size + priv->PadSize) >> priv->BusWidth;
+
+ for (i = 0; i < count; i++) {
+ *(rxdata + i) = READ_RXBUF (dev);
+ }
+
+ OUTW (dev, RX_STOP_READ, RXINDICATOR);
+
+ /* Pass the packet up to the protocol layers. */
+ NetReceive (NetRxPackets[0], data_size);
+
+ OUTW (dev, rxbound_ptr, RXBOUND);
+
+ rxcurt_ptr = INW (dev, RXCURT);
+ rxbound_ptr = INW (dev, RXBOUND);
+ next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
+
+ debug ("ax88180: RX updated RXBOUND=0x%04x,"
+ "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
+ }
+
+ return;
+}
+
+static int ax88180_phy_initial (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long tmp_regval;
+
+ /* Check avaliable PHY chipset */
+ priv->PhyAddr = MARVELL_88E1111_PHYADDR;
+ priv->PhyID0 = ax88180_mdio_read (dev, PHYIDR0);
+
+ if (priv->PhyID0 == MARVELL_88E1111_PHYIDR0) {
+
+ debug ("ax88180: Found Marvell 88E1111 PHY."
+ " (PHY Addr=0x%x)\n", priv->PhyAddr);
+
+ tmp_regval = ax88180_mdio_read (dev, M88_EXT_SSR);
+ if ((tmp_regval & HWCFG_MODE_MASK) == RGMII_COPPER_MODE) {
+
+ ax88180_mdio_write (dev, M88_EXT_SCR, DEFAULT_EXT_SCR);
+ if (ax88180_phy_reset (dev) < 0)
+ return 0;
+ ax88180_mdio_write (dev, M88_IER, LINK_CHANGE_INT);
+ }
+ } else {
+
+ priv->PhyAddr = CICADA_CIS8201_PHYADDR;
+ priv->PhyID0 = ax88180_mdio_read (dev, PHYIDR0);
+
+ if (priv->PhyID0 == CICADA_CIS8201_PHYIDR0) {
+
+ debug ("ax88180: Found CICADA CIS8201 PHY"
+ " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr);
+ ax88180_mdio_write (dev, CIS_IMR,
+ (CIS_INT_ENABLE | LINK_CHANGE_INT));
+
+ /* Set CIS_SMI_PRIORITY bit before force the media mode */
+ tmp_regval =
+ ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS);
+ tmp_regval &= ~CIS_SMI_PRIORITY;
+ ax88180_mdio_write (dev, CIS_AUX_CTRL_STATUS,
+ tmp_regval);
+ } else {
+ printf ("ax88180: Unknown PHY chipset!!\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void ax88180_meidia_config (struct eth_device *dev)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned long bmcr_val, bmsr_val;
+ unsigned long rxcfg_val, maccfg0_val, maccfg1_val;
+ unsigned long RealMediaMode;
+ int i;
+
+ /* Waiting 2 seconds for PHY link stable */
+ for (i = 0; i < 20000; i++) {
+ bmsr_val = ax88180_mdio_read (dev, BMSR);
+ if (bmsr_val & LINKOK) {
+ break;
+ }
+ udelay (100);
+ }
+
+ bmsr_val = ax88180_mdio_read (dev, BMSR);
+ debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val);
+
+ if (bmsr_val & LINKOK) {
+ bmcr_val = ax88180_mdio_read (dev, BMCR);
+
+ if (bmcr_val & AUTONEG_EN) {
+
+ /*
+ * Waiting for Auto-negotiation completion, this may
+ * take up to 5 seconds.
+ */
+ debug ("ax88180: Auto-negotiation is "
+ "enabled. Waiting for NWay completion..\n");
+ for (i = 0; i < 50000; i++) {
+ bmsr_val = ax88180_mdio_read (dev, BMSR);
+ if (bmsr_val & AUTONEG_COMPLETE) {
+ break;
+ }
+ udelay (100);
+ }
+ } else
+ debug ("ax88180: Auto-negotiation is disabled.\n");
+
+ debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n",
+ (unsigned int)bmcr_val, (unsigned int)bmsr_val);
+
+ /* Get real media mode here */
+ if (priv->PhyID0 == MARVELL_88E1111_PHYIDR0) {
+ RealMediaMode = get_MarvellPHY_meida_mode (dev);
+ } else if (priv->PhyID0 == CICADA_CIS8201_PHYIDR0) {
+ RealMediaMode = get_CicadaPHY_meida_mode (dev);
+ } else {
+ RealMediaMode = MEDIA_1000FULL;
+ }
+
+ priv->LinkState = INS_LINK_UP;
+
+ switch (RealMediaMode) {
+ case MEDIA_1000FULL:
+ debug ("ax88180: 1000Mbps Full-duplex mode.\n");
+ rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
+ maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
+ maccfg1_val = GIGA_MODE_EN | RXFLOW_EN |
+ FULLDUPLEX | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_1000HALF:
+ debug ("ax88180: 1000Mbps Half-duplex mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_100FULL:
+ debug ("ax88180: 100Mbps Full-duplex mode.\n");
+ rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
+ maccfg0_val = SPEED100 | TXFLOW_ENABLE
+ | DEFAULT_MACCFG0;
+ maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_100HALF:
+ debug ("ax88180: 100Mbps Half-duplex mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = SPEED100 | DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_10FULL:
+ debug ("ax88180: 10Mbps Full-duplex mode.\n");
+ rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
+ maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
+ maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
+ break;
+
+ case MEDIA_10HALF:
+ debug ("ax88180: 10Mbps Half-duplex mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+ break;
+ default:
+ debug ("ax88180: Unknow media mode.\n");
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+
+ priv->LinkState = INS_LINK_DOWN;
+ break;
+ }
+
+ } else {
+ rxcfg_val = DEFAULT_RXCFG;
+ maccfg0_val = DEFAULT_MACCFG0;
+ maccfg1_val = DEFAULT_MACCFG1;
+
+ priv->LinkState = INS_LINK_DOWN;
+ }
+
+ OUTW (dev, rxcfg_val, RXCFG);
+ OUTW (dev, maccfg0_val, MACCFG0);
+ OUTW (dev, maccfg1_val, MACCFG1);
+
+ return;
+}
+
+static unsigned long get_MarvellPHY_meida_mode (struct eth_device *dev)
+{
+ unsigned long m88_ssr;
+ unsigned long MediaMode;
+
+ m88_ssr = ax88180_mdio_read (dev, M88_SSR);
+ switch (m88_ssr & SSR_MEDIA_MASK) {
+ case SSR_1000FULL:
+ MediaMode = MEDIA_1000FULL;
+ break;
+ case SSR_1000HALF:
+ MediaMode = MEDIA_1000HALF;
+ break;
+ case SSR_100FULL:
+ MediaMode = MEDIA_100FULL;
+ break;
+ case SSR_100HALF:
+ MediaMode = MEDIA_100HALF;
+ break;
+ case SSR_10FULL:
+ MediaMode = MEDIA_10FULL;
+ break;
+ case SSR_10HALF:
+ MediaMode = MEDIA_10HALF;
+ break;
+ default:
+ MediaMode = MEDIA_UNKNOWN;
+ break;
+ }
+
+ return MediaMode;
+}
+
+static unsigned long get_CicadaPHY_meida_mode (struct eth_device *dev)
+{
+ unsigned long tmp_regval;
+ unsigned long MediaMode;
+
+ tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS);
+ switch (tmp_regval & CIS_MEDIA_MASK) {
+ case CIS_1000FULL:
+ MediaMode = MEDIA_1000FULL;
+ break;
+ case CIS_1000HALF:
+ MediaMode = MEDIA_1000HALF;
+ break;
+ case CIS_100FULL:
+ MediaMode = MEDIA_100FULL;
+ break;
+ case CIS_100HALF:
+ MediaMode = MEDIA_100HALF;
+ break;
+ case CIS_10FULL:
+ MediaMode = MEDIA_10FULL;
+ break;
+ case CIS_10HALF:
+ MediaMode = MEDIA_10HALF;
+ break;
+ default:
+ MediaMode = MEDIA_UNKNOWN;
+ break;
+ }
+
+ return MediaMode;
+}
+
+static void ax88180_halt (struct eth_device *dev)
+{
+ /* Disable AX88180 TX/RX functions */
+ OUTW (dev, WAKEMOD, CMD);
+}
+
+static int ax88180_init (struct eth_device *dev, bd_t * bd)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned short tmp_regval;
+
+ ax88180_mac_reset (dev);
+
+ /* Disable interrupt */
+ OUTW (dev, CLEAR_IMR, IMR);
+
+ /* Disable AX88180 TX/RX functions */
+ OUTW (dev, WAKEMOD, CMD);
+
+ /* Fill the MAC address */
+ tmp_regval =
+ dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8);
+ OUTW (dev, tmp_regval, MACID0);
+
+ tmp_regval =
+ dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8);
+ OUTW (dev, tmp_regval, MACID1);
+
+ tmp_regval =
+ dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8);
+ OUTW (dev, tmp_regval, MACID2);
+
+ ax88180_meidia_config (dev);
+
+ OUTW (dev, DEFAULT_RXFILTER, RXFILTER);
+
+ /* Initial variables here */
+ priv->FirstTxDesc = TXDP0;
+ priv->NextTxDesc = TXDP0;
+
+ /* Check if there is any invalid interrupt status and clear it. */
+ OUTW (dev, INW (dev, ISR), ISR);
+
+ /* Start AX88180 TX/RX functions */
+ OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD);
+
+ return 0;
+}
+
+/* Get a data block via Ethernet */
+static int ax88180_recv (struct eth_device *dev)
+{
+ unsigned short ISR_Status;
+ unsigned short tmp_regval;
+
+ /* Read and check interrupt status here. */
+ ISR_Status = INW (dev, ISR);
+
+ while (ISR_Status) {
+ /* Clear the interrupt status */
+ OUTW (dev, ISR_Status, ISR);
+
+ debug ("\nax88180: The interrupt status = 0x%04x\n",
+ ISR_Status);
+
+ if (ISR_Status & ISR_PHY) {
+ /* Read ISR register once to clear PHY interrupt bit */
+ tmp_regval = ax88180_mdio_read (dev, M88_ISR);
+ ax88180_meidia_config (dev);
+ }
+
+ if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) {
+ ax88180_rx_handler (dev);
+ }
+
+ /* Read and check interrupt status again */
+ ISR_Status = INW (dev, ISR);
+ }
+
+ return 0;
+}
+
+/* Send a data block via Ethernet. */
+static int
+ax88180_send (struct eth_device *dev, volatile void *packet, int length)
+{
+ struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
+ unsigned short TXDES_addr;
+ unsigned short txcmd_txdp, txbs_txdp;
+ unsigned short tmp_data;
+ int i;
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ volatile unsigned short *txdata = (volatile unsigned short *)packet;
+#else
+ volatile unsigned long *txdata = (volatile unsigned long *)packet;
+#endif
+ unsigned short count;
+
+ if (priv->LinkState != INS_LINK_UP) {
+ return 0;
+ }
+
+ priv->FirstTxDesc = priv->NextTxDesc;
+ txbs_txdp = 1 << priv->FirstTxDesc;
+
+ debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc);
+
+ txcmd_txdp = priv->FirstTxDesc << 13;
+ TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2);
+
+ OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD);
+
+ /* Comput access times */
+ count = (length + priv->PadSize) >> priv->BusWidth;
+
+ for (i = 0; i < count; i++) {
+ WRITE_TXBUF (dev, *(txdata + i));
+ }
+
+ OUTW (dev, txcmd_txdp | length, TXCMD);
+ OUTW (dev, txbs_txdp, TXBS);
+ OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr);
+
+ priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK;
+
+ /*
+ * Check the available transmit descriptor, if we had exhausted all
+ * transmit descriptor ,then we have to wait for at least one free
+ * descriptor
+ */
+ txbs_txdp = 1 << priv->NextTxDesc;
+ tmp_data = INW (dev, TXBS);
+
+ if (tmp_data & txbs_txdp) {
+ if (ax88180_poll_tx_complete (dev) < 0) {
+ ax88180_mac_reset (dev);
+ priv->FirstTxDesc = TXDP0;
+ priv->NextTxDesc = TXDP0;
+ printf ("ax88180: Transmit time out occurred!\n");
+ }
+ }
+
+ return 0;
+}
+
+static void ax88180_read_mac_addr (struct eth_device *dev)
+{
+ unsigned short macid0_val, macid1_val, macid2_val;
+ unsigned short tmp_regval;
+ unsigned short i;
+
+ /* Reload MAC address from EEPROM */
+ OUTW (dev, RELOAD_EEPROM, PROMCTRL);
+
+ /* Waiting for reload eeprom completion */
+ for (i = 0; i < 500; i++) {
+ tmp_regval = INW (dev, PROMCTRL);
+ if ((tmp_regval & RELOAD_EEPROM) == 0)
+ break;
+ udelay (1000);
+ }
+
+ /* Get MAC addresses */
+ macid0_val = INW (dev, MACID0);
+ macid1_val = INW (dev, MACID1);
+ macid2_val = INW (dev, MACID2);
+
+ if (((macid0_val | macid1_val | macid2_val) != 0) &&
+ ((macid0_val & 0x01) == 0)) {
+ dev->enetaddr[0] = (unsigned char)macid0_val;
+ dev->enetaddr[1] = (unsigned char)(macid0_val >> 8);
+ dev->enetaddr[2] = (unsigned char)macid1_val;
+ dev->enetaddr[3] = (unsigned char)(macid1_val >> 8);
+ dev->enetaddr[4] = (unsigned char)macid2_val;
+ dev->enetaddr[5] = (unsigned char)(macid2_val >> 8);
+ }
+}
+
+/*
+===========================================================================
+<<<<<< Exported SubProgram Bodies >>>>>>
+===========================================================================
+*/
+int ax88180_initialize (bd_t * bis)
+{
+ struct eth_device *dev;
+ struct ax88180_private *priv;
+
+ dev = (struct eth_device *)malloc (sizeof *dev);
+
+ if (NULL == dev)
+ return 0;
+
+ memset (dev, 0, sizeof *dev);
+
+ priv = (struct ax88180_private *)malloc (sizeof (*priv));
+
+ if (NULL == priv)
+ return 0;
+
+ memset (priv, 0, sizeof *priv);
+
+ sprintf (dev->name, "ax88180");
+ dev->iobase = AX88180_BASE;
+ dev->priv = priv;
+ dev->init = ax88180_init;
+ dev->halt = ax88180_halt;
+ dev->send = ax88180_send;
+ dev->recv = ax88180_recv;
+
+ priv->BusWidth = BUS_WIDTH_32;
+ priv->PadSize = 3;
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ OUTW (dev, (START_BASE >> 8), BASE);
+ OUTW (dev, DECODE_EN, DECODE);
+
+ priv->BusWidth = BUS_WIDTH_16;
+ priv->PadSize = 1;
+#endif
+
+ ax88180_mac_reset (dev);
+
+ /* Disable interrupt */
+ OUTW (dev, CLEAR_IMR, IMR);
+
+ /* Disable AX88180 TX/RX functions */
+ OUTW (dev, WAKEMOD, CMD);
+
+ ax88180_read_mac_addr (dev);
+
+ eth_register (dev);
+
+ return ax88180_phy_initial (dev);
+
+}
diff --git a/drivers/net/ax88180.h b/drivers/net/ax88180.h
new file mode 100644
index 0000000..d2113df
--- /dev/null
+++ b/drivers/net/ax88180.h
@@ -0,0 +1,412 @@
+/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */
+/*
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+
+#ifndef _AX88180_H_
+#define _AX88180_H_
+
+#include <asm/types.h>
+#include <config.h>
+
+typedef enum _ax88180_link_state {
+ INS_LINK_DOWN,
+ INS_LINK_UP,
+ INS_LINK_UNKNOWN
+} ax88180_link_state;
+
+struct ax88180_private {
+ unsigned char BusWidth;
+ unsigned char PadSize;
+ unsigned short PhyAddr;
+ unsigned short PhyID0;
+ unsigned short FirstTxDesc;
+ unsigned short NextTxDesc;
+ ax88180_link_state LinkState;
+};
+
+#define BUS_WIDTH_16 1
+#define BUS_WIDTH_32 2
+
+#define ENABLE_JUMBO 1
+#define DISABLE_JUMBO 0
+
+#define ENABLE_BURST 1
+#define DISABLE_BURST 0
+
+#define NORMAL_RX_MODE 0
+#define RX_LOOPBACK_MODE 1
+#define RX_INIFINIT_LOOP_MODE 2
+#define TX_INIFINIT_LOOP_MODE 3
+
+#define DEFAULT_ETH_MTU 1500
+
+/* Jumbo packet size 4086 bytes included 4 bytes CRC*/
+#define MAX_JUMBO_MTU 4072
+
+/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */
+#define MAX_TX_JUMBO_SIZE 4086
+
+/* Max Rx Jumbo size is 15K Bytes */
+#define MAX_RX_SIZE 0x3C00
+
+#define MARVELL_88E1111_PHYADDR 0x18
+#define MARVELL_88E1111_PHYIDR0 0x0141
+
+#define CICADA_CIS8201_PHYADDR 0x01
+#define CICADA_CIS8201_PHYIDR0 0x000F
+
+#define MEDIA_AUTO 0
+#define MEDIA_1000FULL 1
+#define MEDIA_1000HALF 2
+#define MEDIA_100FULL 3
+#define MEDIA_100HALF 4
+#define MEDIA_10FULL 5
+#define MEDIA_10HALF 6
+#define MEDIA_UNKNOWN 7
+
+#define AUTO_MEDIA 0
+#define FORCE_MEDIA 1
+
+#define TXDP_MASK 3
+#define TXDP0 0
+#define TXDP1 1
+#define TXDP2 2
+#define TXDP3 3
+
+#define CMD_MAP_SIZE 0x100
+
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+ #define AX88180_MEMORY_SIZE 0x00004000
+ #define START_BASE 0x1000
+
+ #define RX_BUF_SIZE 0x1000
+ #define TX_BUF_SIZE 0x0F00
+
+ #define TX_BASE START_BASE
+ #define CMD_BASE (TX_BASE + TX_BUF_SIZE)
+ #define RX_BASE (CMD_BASE + CMD_MAP_SIZE)
+#else
+ #define AX88180_MEMORY_SIZE 0x00010000
+
+ #define RX_BUF_SIZE 0x8000
+ #define TX_BUF_SIZE 0x7C00
+
+ #define RX_BASE 0x0000
+ #define TX_BASE (RX_BASE + RX_BUF_SIZE)
+ #define CMD_BASE (TX_BASE + TX_BUF_SIZE)
+#endif
+
+/* AX88180 Memory Mapping Definition */
+#define RXBUFFER_START RX_BASE
+ #define RX_PACKET_LEN_OFFSET 0
+ #define RX_PAGE_NUM_MASK 0x7FF /* RX pages 0~7FFh */
+#define TXBUFFER_START TX_BASE
+
+/* AX88180 MAC Register Definition */
+#define DECODE (0)
+ #define DECODE_EN 0x00000001
+#define BASE (6)
+#define CMD (CMD_BASE + 0x0000)
+ #define WAKEMOD 0x00000001
+ #define TXEN 0x00000100
+ #define RXEN 0x00000200
+ #define DEFAULT_CMD WAKEMOD
+#define IMR (CMD_BASE + 0x0004)
+ #define IMR_RXBUFFOVR 0x00000001
+ #define IMR_WATCHDOG 0x00000002
+ #define IMR_TX 0x00000008
+ #define IMR_RX 0x00000010
+ #define IMR_PHY 0x00000020
+ #define CLEAR_IMR 0x00000000
+ #define DEFAULT_IMR (IMR_PHY | IMR_RX | IMR_TX |\
+ IMR_RXBUFFOVR | IMR_WATCHDOG)
+#define ISR (CMD_BASE + 0x0008)
+ #define ISR_RXBUFFOVR 0x00000001
+ #define ISR_WATCHDOG 0x00000002
+ #define ISR_TX 0x00000008
+ #define ISR_RX 0x00000010
+ #define ISR_PHY 0x00000020
+#define TXCFG (CMD_BASE + 0x0010)
+ #define AUTOPAD_CRC 0x00000050
+ #define DEFAULT_TXCFG AUTOPAD_CRC
+#define TXCMD (CMD_BASE + 0x0014)
+ #define TXCMD_TXDP_MASK 0x00006000
+ #define TXCMD_TXDP0 0x00000000
+ #define TXCMD_TXDP1 0x00002000
+ #define TXCMD_TXDP2 0x00004000
+ #define TXCMD_TXDP3 0x00006000
+ #define TX_START_WRITE 0x00008000
+ #define TX_STOP_WRITE 0x00000000
+ #define DEFAULT_TXCMD 0x00000000
+#define TXBS (CMD_BASE + 0x0018)
+ #define TXDP0_USED 0x00000001
+ #define TXDP1_USED 0x00000002
+ #define TXDP2_USED 0x00000004
+ #define TXDP3_USED 0x00000008
+ #define DEFAULT_TXBS 0x00000000
+#define TXDES0 (CMD_BASE + 0x0020)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES0 0x00000000
+#define TXDES1 (CMD_BASE + 0x0024)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES1 0x00000000
+#define TXDES2 (CMD_BASE + 0x0028)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES2 0x00000000
+#define TXDES3 (CMD_BASE + 0x002C)
+ #define TXDPx_ENABLE 0x00008000
+ #define TXDPx_LEN_MASK 0x00001FFF
+ #define DEFAULT_TXDES3 0x00000000
+#define RXCFG (CMD_BASE + 0x0030)
+ #define RXBUFF_PROTECT 0x00000001
+ #define RXTCPCRC_CHECK 0x00000010
+ #define RXFLOW_ENABLE 0x00000100
+ #define DEFAULT_RXCFG RXBUFF_PROTECT
+#define RXCURT (CMD_BASE + 0x0034)
+ #define DEFAULT_RXCURT 0x00000000
+#define RXBOUND (CMD_BASE + 0x0038)
+ #define DEFAULT_RXBOUND 0x7FF /* RX pages 0~7FFh */
+#define MACCFG0 (CMD_BASE + 0x0040)
+ #define MACCFG0_BIT3_0 0x00000007
+ #define IPGT_VAL 0x00000150
+ #define TXFLOW_ENABLE 0x00001000
+ #define SPEED100 0x00008000
+ #define DEFAULT_MACCFG0 (IPGT_VAL | MACCFG0_BIT3_0)
+#define MACCFG1 (CMD_BASE + 0x0044)
+ #define RGMII_EN 0x00000002
+ #define RXFLOW_EN 0x00000020
+ #define FULLDUPLEX 0x00000040
+ #define MAX_JUMBO_LEN 0x00000780
+ #define RXJUMBO_EN 0x00000800
+ #define GIGA_MODE_EN 0x00001000
+ #define RXCRC_CHECK 0x00002000
+ #define RXPAUSE_DA_CHECK 0x00004000
+
+ #define JUMBO_LEN_4K 0x00000200
+ #define JUMBO_LEN_15K 0x00000780
+ #define DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK | \
+ RGMII_EN)
+ #define CICADA_DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK)
+#define MACCFG2 (CMD_BASE + 0x0048)
+ #define MACCFG2_BIT15_8 0x00000100
+ #define JAM_LIMIT_MASK 0x000000FC
+ #define DEFAULT_JAM_LIMIT 0x00000064
+ #define DEFAULT_MACCFG2 MACCFG2_BIT15_8
+#define MACCFG3 (CMD_BASE + 0x004C)
+ #define IPGR2_VAL 0x0000000E
+ #define IPGR1_VAL 0x00000600
+ #define NOABORT 0x00008000
+ #define DEFAULT_MACCFG3 (IPGR1_VAL | IPGR2_VAL)
+#define TXPAUT (CMD_BASE + 0x0054)
+ #define DEFAULT_TXPAUT 0x001FE000
+#define RXBTHD0 (CMD_BASE + 0x0058)
+ #define DEFAULT_RXBTHD0 0x00000300
+#define RXBTHD1 (CMD_BASE + 0x005C)
+ #define DEFAULT_RXBTHD1 0x00000600
+#define RXFULTHD (CMD_BASE + 0x0060)
+ #define DEFAULT_RXFULTHD 0x00000100
+#define MISC (CMD_BASE + 0x0068)
+ /* Normal operation mode */
+ #define MISC_NORMAL 0x00000003
+ /* Clear bit 0 to reset MAC */
+ #define MISC_RESET_MAC 0x00000002
+ /* Clear bit 1 to reset PHY */
+ #define MISC_RESET_PHY 0x00000001
+ /* Clear bit 0 and 1 to reset MAC and PHY */
+ #define MISC_RESET_MAC_PHY 0x00000000
+ #define DEFAULT_MISC MISC_NORMAL
+#define MACID0 (CMD_BASE + 0x0070)
+#define MACID1 (CMD_BASE + 0x0074)
+#define MACID2 (CMD_BASE + 0x0078)
+#define TXLEN (CMD_BASE + 0x007C)
+ #define DEFAULT_TXLEN 0x000005FC
+#define RXFILTER (CMD_BASE + 0x0080)
+ #define RX_RXANY 0x00000001
+ #define RX_MULTICAST 0x00000002
+ #define RX_UNICAST 0x00000004
+ #define RX_BROADCAST 0x00000008
+ #define RX_MULTI_HASH 0x00000010
+ #define DISABLE_RXFILTER 0x00000000
+ #define DEFAULT_RXFILTER (RX_BROADCAST + RX_UNICAST)
+#define MDIOCTRL (CMD_BASE + 0x0084)
+ #define PHY_ADDR_MASK 0x0000001F
+ #define REG_ADDR_MASK 0x00001F00
+ #define READ_PHY 0x00004000
+ #define WRITE_PHY 0x00008000
+#define MDIODP (CMD_BASE + 0x0088)
+#define GPIOCTRL (CMD_BASE + 0x008C)
+#define RXINDICATOR (CMD_BASE + 0x0090)
+ #define RX_START_READ 0x00000001
+ #define RX_STOP_READ 0x00000000
+ #define DEFAULT_RXINDICATOR RX_STOP_READ
+#define TXST (CMD_BASE + 0x0094)
+#define MDCCLKPAT (CMD_BASE + 0x00A0)
+#define RXIPCRCCNT (CMD_BASE + 0x00A4)
+#define RXCRCCNT (CMD_BASE + 0x00A8)
+#define TXFAILCNT (CMD_BASE + 0x00AC)
+#define PROMDP (CMD_BASE + 0x00B0)
+#define PROMCTRL (CMD_BASE + 0x00B4)
+ #define RELOAD_EEPROM 0x00000200
+#define MAXRXLEN (CMD_BASE + 0x00B8)
+#define HASHTAB0 (CMD_BASE + 0x00C0)
+#define HASHTAB1 (CMD_BASE + 0x00C4)
+#define HASHTAB2 (CMD_BASE + 0x00C8)
+#define HASHTAB3 (CMD_BASE + 0x00CC)
+#define DOGTHD0 (CMD_BASE + 0x00E0)
+ #define DEFAULT_DOGTHD0 0x0000FFFF
+#define DOGTHD1 (CMD_BASE + 0x00E4)
+ #define START_WATCHDOG_TIMER 0x00008000
+ #define DEFAULT_DOGTHD1 0x00000FFF
+#define SOFTRST (CMD_BASE + 0x00EC)
+ #define SOFTRST_NORMAL 0x00000003
+ #define SOFTRST_RESET_MAC 0x00000002
+
+/* External PHY Register Definition */
+#define BMCR 0x0000
+ #define LINE_SPEED_MSB 0x0040
+ #define DUPLEX_MODE 0x0100
+ #define RESTART_AUTONEG 0x0200
+ #define POWER_DOWN 0x0800
+ #define AUTONEG_EN 0x1000
+ #define LINE_SPEED_LSB 0x2000
+ #define PHY_RESET 0x8000
+
+ #define MEDIAMODE_MASK (LINE_SPEED_MSB | LINE_SPEED_LSB |\
+ DUPLEX_MODE)
+ #define BMCR_SPEED_1000 LINE_SPEED_MSB
+ #define BMCR_SPEED_100 LINE_SPEED_LSB
+ #define BMCR_SPEED_10 0x0000
+
+ #define BMCR_1000FULL (BMCR_SPEED_1000 | DUPLEX_MODE)
+ #define BMCR_100FULL (BMCR_SPEED_100 | DUPLEX_MODE)
+ #define BMCR_100HALF BMCR_SPEED_100
+ #define BMCR_10FULL DUPLEX_MODE
+ #define BMCR_10HALF 0x0000
+#define BMSR 0x0001
+ #define LINKOK 0x0004
+ #define AUTONEG_ENABLE_STS 0x0008
+ #define AUTONEG_COMPLETE 0x0020
+#define PHYIDR0 0x0002
+#define PHYIDR1 0x0003
+#define ANAR 0x0004
+ #define ANAR_PAUSE 0x0400
+ #define ANAR_100FULL 0x0100
+ #define ANAR_100HALF 0x0080
+ #define ANAR_10FULL 0x0040
+ #define ANAR_10HALF 0x0020
+ #define ANAR_8023BIT 0x0001
+#define ANLPAR 0x0005
+#define ANER 0x0006
+#define AUX_1000_CTRL 0x0009
+ #define ENABLE_1000HALF 0x0100
+ #define ENABLE_1000FULL 0x0200
+ #define DEFAULT_AUX_1000_CTRL (ENABLE_1000HALF | ENABLE_1000FULL)
+#define AUX_1000_STATUS 0x000A
+ #define LP_1000HALF 0x0400
+ #define LP_1000FULL 0x0800
+
+/* Marvell 88E1111 Gigabit PHY Register Definition */
+#define M88_SSR 0x0011
+ #define SSR_SPEED_MASK 0xC000
+ #define SSR_SPEED_1000 0x8000
+ #define SSR_SPEED_100 0x4000
+ #define SSR_SPEED_10 0x0000
+ #define SSR_DUPLEX 0x2000
+ #define SSR_MEDIA_RESOLVED_OK 0x0800
+
+ #define SSR_MEDIA_MASK (SSR_SPEED_MASK | SSR_DUPLEX)
+ #define SSR_1000FULL (SSR_SPEED_1000 | SSR_DUPLEX)
+ #define SSR_1000HALF SSR_SPEED_1000
+ #define SSR_100FULL (SSR_SPEED_100 | SSR_DUPLEX)
+ #define SSR_100HALF SSR_SPEED_100
+ #define SSR_10FULL (SSR_SPEED_10 | SSR_DUPLEX)
+ #define SSR_10HALF SSR_SPEED_10
+#define M88_IER 0x0012
+ #define LINK_CHANGE_INT 0x0400
+#define M88_ISR 0x0013
+ #define LINK_CHANGE_STATUS 0x0400
+#define M88_EXT_SCR 0x0014
+ #define RGMII_RXCLK_DELAY 0x0080
+ #define RGMII_TXCLK_DELAY 0x0002
+ #define DEFAULT_EXT_SCR (RGMII_TXCLK_DELAY | RGMII_RXCLK_DELAY)
+#define M88_EXT_SSR 0x001B
+ #define HWCFG_MODE_MASK 0x000F
+ #define RGMII_COPPER_MODE 0x000B
+
+/* CICADA CIS8201 Gigabit PHY Register Definition */
+#define CIS_IMR 0x0019
+ #define CIS_INT_ENABLE 0x8000
+ #define CIS_LINK_CHANGE_INT 0x2000
+#define CIS_ISR 0x001A
+ #define CIS_INT_PENDING 0x8000
+ #define CIS_LINK_CHANGE_STATUS 0x2000
+#define CIS_AUX_CTRL_STATUS 0x001C
+ #define CIS_AUTONEG_COMPLETE 0x8000
+ #define CIS_SPEED_MASK 0x0018
+ #define CIS_SPEED_1000 0x0010
+ #define CIS_SPEED_100 0x0008
+ #define CIS_SPEED_10 0x0000
+ #define CIS_DUPLEX 0x0020
+
+ #define CIS_MEDIA_MASK (CIS_SPEED_MASK | CIS_DUPLEX)
+ #define CIS_1000FULL (CIS_SPEED_1000 | CIS_DUPLEX)
+ #define CIS_1000HALF CIS_SPEED_1000
+ #define CIS_100FULL (CIS_SPEED_100 | CIS_DUPLEX)
+ #define CIS_100HALF CIS_SPEED_100
+ #define CIS_10FULL (CIS_SPEED_10 | CIS_DUPLEX)
+ #define CIS_10HALF CIS_SPEED_10
+ #define CIS_SMI_PRIORITY 0x0004
+
+static inline unsigned short INW (struct eth_device *dev, unsigned long addr)
+{
+ return le16_to_cpu (*(volatile unsigned short *) (addr + dev->iobase));
+}
+
+static inline void OUTW (struct eth_device *dev, unsigned short command, unsigned long addr)
+{
+ *(volatile unsigned short *) ((addr + dev->iobase)) = cpu_to_le16 (command);
+}
+
+/*
+ Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer
+*/
+#if defined (CONFIG_DRIVER_AX88180_16BIT)
+static inline unsigned short READ_RXBUF (struct eth_device *dev)
+{
+ return le16_to_cpu (*(volatile unsigned short *) (RXBUFFER_START + dev->iobase));
+}
+
+static inline void WRITE_TXBUF (struct eth_device *dev, unsigned short data)
+{
+ *(volatile unsigned short *) ((TXBUFFER_START + dev->iobase)) = cpu_to_le16 (data);
+}
+#else
+static inline unsigned long READ_RXBUF (struct eth_device *dev)
+{
+ return le32_to_cpu (*(volatile unsigned long *) (RXBUFFER_START + dev->iobase));
+}
+
+static inline void WRITE_TXBUF (struct eth_device *dev, unsigned long data)
+{
+ *(volatile unsigned long *) ((TXBUFFER_START + dev->iobase)) = cpu_to_le32 (data);
+}
+#endif
+
+#endif /* _AX88180_H_ */
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 39cd101..2089141 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -143,7 +143,7 @@ static void ax88796_mac_read(u8 *buff)
}
}
-int get_prom(u8* mac_addr)
+int get_prom(u8* mac_addr, u8* base_addr)
{
u8 prom[32];
int i;
diff --git a/drivers/net/bcm570x.c b/drivers/net/bcm570x.c
index 6b28b95..185764e 100644
--- a/drivers/net/bcm570x.c
+++ b/drivers/net/bcm570x.c
@@ -439,9 +439,9 @@ int eth_init (bd_t * bis)
/* Setup timer delays */
if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
pDevice->UseTaggedStatus = TRUE;
- pUmDevice->timer_interval = CFG_HZ;
+ pUmDevice->timer_interval = CONFIG_SYS_HZ;
} else {
- pUmDevice->timer_interval = CFG_HZ / 50;
+ pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
}
/* Grab name .... */
@@ -458,15 +458,15 @@ int eth_init (bd_t * bis)
pUmDevice->rx_last_cnt = pUmDevice->tx_last_cnt = 0;
/* delay for 4 seconds */
- pUmDevice->delayed_link_ind = (4 * CFG_HZ) / pUmDevice->timer_interval;
+ pUmDevice->delayed_link_ind = (4 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
- pUmDevice->adaptive_expiry = CFG_HZ / pUmDevice->timer_interval;
+ pUmDevice->adaptive_expiry = CONFIG_SYS_HZ / pUmDevice->timer_interval;
/* Sometimes we get spurious ints. after reset when link is down. */
/* This field tells the isr to service the int. even if there is */
/* no status block update. */
pUmDevice->adapter_just_inited =
- (3 * CFG_HZ) / pUmDevice->timer_interval;
+ (3 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
/* Initialize 570x */
if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) {
@@ -1046,9 +1046,9 @@ LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
pDevice->UseTaggedStatus = TRUE;
- pUmDevice->timer_interval = CFG_HZ;
+ pUmDevice->timer_interval = CONFIG_SYS_HZ;
} else {
- pUmDevice->timer_interval = CFG_HZ / 50;
+ pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
}
pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index];
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 3ee5d96..504fd10 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <config.h>
#include <net.h>
+#include <netdev.h>
#include <command.h>
#include <malloc.h>
@@ -465,7 +466,7 @@ ADI_ETHER_BUFFER *SetupTxBuffer(int no)
return buf;
}
-#if defined(CONFIG_POST) && defined(CFG_POST_ETHER)
+#if defined(CONFIG_POST) && defined(CONFIG_SYS_POST_ETHER)
int ether_post_test(int flags)
{
uchar buf[64];
diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c
index ae1983a..35a9baf 100644
--- a/drivers/net/cs8900.c
+++ b/drivers/net/cs8900.c
@@ -90,7 +90,7 @@ static void eth_reset (void)
udelay (200000);
/* Wait until the chip is reset */
- tmo = get_timer (0) + 1 * CFG_HZ;
+ tmo = get_timer (0) + 1 * CONFIG_SYS_HZ;
while ((((us = get_reg_init_bus (PP_SelfSTAT)) & PP_SelfSTAT_InitD) == 0)
&& tmo < get_timer (0))
/*NOP*/;
@@ -244,7 +244,7 @@ retry:
#ifdef DEBUG
printf ("cs: unable to send packet; retrying...\n");
#endif
- for (tmo = get_timer (0) + 5 * CFG_HZ; get_timer (0) < tmo;)
+ for (tmo = get_timer (0) + 5 * CONFIG_SYS_HZ; get_timer (0) < tmo;)
/*NOP*/;
eth_reset ();
eth_reginit ();
@@ -257,7 +257,7 @@ retry:
CS8900_RTDATA = *addr++;
/* wait for transfer to succeed */
- tmo = get_timer (0) + 5 * CFG_HZ;
+ tmo = get_timer (0) + 5 * CONFIG_SYS_HZ;
while ((s = get_reg (PP_TER) & ~0x1F) == 0) {
if (get_timer (0) >= tmo)
break;
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index 8117239..c0137a7 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -21,6 +21,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <pci.h>
#undef DEBUG_SROM
diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c
index 3a61b80..ffb739d 100644
--- a/drivers/net/dm9000x.c
+++ b/drivers/net/dm9000x.c
@@ -447,7 +447,7 @@ eth_send(volatile void *packet, int length)
DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
/* wait for end of transmission */
- tmo = get_timer(0) + 5 * CFG_HZ;
+ tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
!(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
if (get_timer(0) >= tmo) {
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index c8b4e98..2dcaa2c 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -3059,5 +3059,5 @@ e1000_initialize(bd_t * bis)
card_number++;
}
- return 1;
+ return card_number;
}
diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h
index c258bc2..08042a8 100644
--- a/drivers/net/e1000.h
+++ b/drivers/net/e1000.h
@@ -36,6 +36,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 9de0fb5..9c06b25 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -24,6 +24,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
#include <miiphy.h>
@@ -193,14 +194,14 @@ struct descriptor { /* A generic descriptor. */
unsigned char params[0];
};
-#define CFG_CMD_EL 0x8000
-#define CFG_CMD_SUSPEND 0x4000
-#define CFG_CMD_INT 0x2000
-#define CFG_CMD_IAS 0x0001 /* individual address setup */
-#define CFG_CMD_CONFIGURE 0x0002 /* configure */
+#define CONFIG_SYS_CMD_EL 0x8000
+#define CONFIG_SYS_CMD_SUSPEND 0x4000
+#define CONFIG_SYS_CMD_INT 0x2000
+#define CONFIG_SYS_CMD_IAS 0x0001 /* individual address setup */
+#define CONFIG_SYS_CMD_CONFIGURE 0x0002 /* configure */
-#define CFG_STATUS_C 0x8000
-#define CFG_STATUS_OK 0x2000
+#define CONFIG_SYS_STATUS_C 0x8000
+#define CONFIG_SYS_STATUS_OK 0x2000
/* Misc.
*/
@@ -528,7 +529,7 @@ static int eepro100_init (struct eth_device *dev, bd_t * bis)
tx_next = ((tx_next + 1) % NUM_TX_DESC);
cfg_cmd = (struct descriptor *) &tx_ring[tx_cur];
- cfg_cmd->command = cpu_to_le16 ((CFG_CMD_SUSPEND | CFG_CMD_CONFIGURE));
+ cfg_cmd->command = cpu_to_le16 ((CONFIG_SYS_CMD_SUSPEND | CONFIG_SYS_CMD_CONFIGURE));
cfg_cmd->status = 0;
cfg_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
@@ -536,7 +537,7 @@ static int eepro100_init (struct eth_device *dev, bd_t * bis)
sizeof (i82558_config_cmd));
if (!wait_for_eepro100 (dev)) {
- printf ("Error---CFG_CMD_CONFIGURE: Can not reset ethernet controller.\n");
+ printf ("Error---CONFIG_SYS_CMD_CONFIGURE: Can not reset ethernet controller.\n");
goto Done;
}
@@ -544,7 +545,7 @@ static int eepro100_init (struct eth_device *dev, bd_t * bis)
OUTW (dev, SCB_M | CU_START, SCBCmd);
for (i = 0;
- !(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_C);
+ !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
i++) {
if (i >= TOUT_LOOP) {
printf ("%s: Tx error buffer not ready\n", dev->name);
@@ -552,7 +553,7 @@ static int eepro100_init (struct eth_device *dev, bd_t * bis)
}
}
- if (!(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_OK)) {
+ if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
printf ("TX error status = 0x%08X\n",
le16_to_cpu (tx_ring[tx_cur].status));
goto Done;
@@ -564,7 +565,7 @@ static int eepro100_init (struct eth_device *dev, bd_t * bis)
tx_next = ((tx_next + 1) % NUM_TX_DESC);
ias_cmd = (struct descriptor *) &tx_ring[tx_cur];
- ias_cmd->command = cpu_to_le16 ((CFG_CMD_SUSPEND | CFG_CMD_IAS));
+ ias_cmd->command = cpu_to_le16 ((CONFIG_SYS_CMD_SUSPEND | CONFIG_SYS_CMD_IAS));
ias_cmd->status = 0;
ias_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
@@ -580,7 +581,7 @@ static int eepro100_init (struct eth_device *dev, bd_t * bis)
OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
OUTW (dev, SCB_M | CU_START, SCBCmd);
- for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_C);
+ for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
i++) {
if (i >= TOUT_LOOP) {
printf ("%s: Tx error buffer not ready\n",
@@ -589,7 +590,7 @@ static int eepro100_init (struct eth_device *dev, bd_t * bis)
}
}
- if (!(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_OK)) {
+ if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
printf ("TX error status = 0x%08X\n",
le16_to_cpu (tx_ring[tx_cur].status));
goto Done;
@@ -639,7 +640,7 @@ static int eepro100_send (struct eth_device *dev, volatile void *packet, int len
OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
OUTW (dev, SCB_M | CU_START, SCBCmd);
- for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_C);
+ for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
i++) {
if (i >= TOUT_LOOP) {
printf ("%s: Tx error buffer not ready\n", dev->name);
@@ -647,7 +648,7 @@ static int eepro100_send (struct eth_device *dev, volatile void *packet, int len
}
}
- if (!(le16_to_cpu (tx_ring[tx_cur].status) & CFG_STATUS_OK)) {
+ if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
printf ("TX error status = 0x%08X\n",
le16_to_cpu (tx_ring[tx_cur].status));
goto Done;
diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c
index 59524a5..d056010 100644
--- a/drivers/net/fsl_mcdmafec.c
+++ b/drivers/net/fsl_mcdmafec.c
@@ -56,12 +56,12 @@
DECLARE_GLOBAL_DATA_PTR;
struct fec_info_dma fec_info[] = {
-#ifdef CFG_FEC0_IOBASE
+#ifdef CONFIG_SYS_FEC0_IOBASE
{
0, /* index */
- CFG_FEC0_IOBASE, /* io base */
- CFG_FEC0_PINMUX, /* gpio pin muxing */
- CFG_FEC0_MIIBASE, /* mii base */
+ CONFIG_SYS_FEC0_IOBASE, /* io base */
+ CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC0_MIIBASE, /* mii base */
-1, /* phy_addr */
0, /* duplex and speed */
0, /* phy name */
@@ -83,17 +83,17 @@ struct fec_info_dma fec_info[] = {
0, /* cleanTbdNum */
},
#endif
-#ifdef CFG_FEC1_IOBASE
+#ifdef CONFIG_SYS_FEC1_IOBASE
{
1, /* index */
- CFG_FEC1_IOBASE, /* io base */
- CFG_FEC1_PINMUX, /* gpio pin muxing */
- CFG_FEC1_MIIBASE, /* mii base */
+ CONFIG_SYS_FEC1_IOBASE, /* io base */
+ CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC1_MIIBASE, /* mii base */
-1, /* phy_addr */
0, /* duplex and speed */
0, /* phy name */
0, /* phy name init */
-#ifdef CFG_DMA_USE_INTSRAM
+#ifdef CONFIG_SYS_DMA_USE_INTSRAM
(cbd_t *)DBUF_LENGTH, /* RX BD */
#else
0, /* RX BD */
@@ -203,7 +203,7 @@ static int fec_send(struct eth_device *dev, volatile void *packet, int length)
miiphy_read(dev->name, info->phy_addr, PHY_BMSR, &phyStatus);
/* process all the consumed TBDs */
- while (info->cleanTbdNum < CFG_TX_ETH_BUFFER) {
+ while (info->cleanTbdNum < CONFIG_SYS_TX_ETH_BUFFER) {
pUsedTbd = &info->txbd[info->usedTbdIdx];
if (pUsedTbd->cbd_sc & BD_ENET_TX_READY) {
#ifdef ET_DEBUG
@@ -214,14 +214,14 @@ static int fec_send(struct eth_device *dev, volatile void *packet, int length)
}
/* clean this buffer descriptor */
- if (info->usedTbdIdx == (CFG_TX_ETH_BUFFER - 1))
+ if (info->usedTbdIdx == (CONFIG_SYS_TX_ETH_BUFFER - 1))
pUsedTbd->cbd_sc = BD_ENET_TX_WRAP;
else
pUsedTbd->cbd_sc = 0;
/* update some indeces for a correct handling of the TBD ring */
info->cleanTbdNum++;
- info->usedTbdIdx = (info->usedTbdIdx + 1) % CFG_TX_ETH_BUFFER;
+ info->usedTbdIdx = (info->usedTbdIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER;
}
/* Check for valid length of data. */
@@ -240,7 +240,7 @@ static int fec_send(struct eth_device *dev, volatile void *packet, int length)
pTbd->cbd_datlen = length;
pTbd->cbd_bufaddr = (u32) packet;
pTbd->cbd_sc |= BD_ENET_TX_LAST | BD_ENET_TX_TC | BD_ENET_TX_READY;
- info->txIdx = (info->txIdx + 1) % CFG_TX_ETH_BUFFER;
+ info->txIdx = (info->txIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER;
/* Enable DMA transmit task */
MCD_continDma(info->txTask);
@@ -379,15 +379,15 @@ static int fec_init(struct eth_device *dev, bd_t * bd)
fec_halt(dev);
#if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \
- defined (CFG_DISCOVER_PHY)
+ defined (CONFIG_SYS_DISCOVER_PHY)
mii_init();
set_fec_duplex_speed(fecp, bd, info->dup_spd);
#else
-#ifndef CFG_DISCOVER_PHY
+#ifndef CONFIG_SYS_DISCOVER_PHY
set_fec_duplex_speed(fecp, bd, (FECDUPLEX << 16) | FECSPEED);
-#endif /* ifndef CFG_DISCOVER_PHY */
+#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */
#endif /* CONFIG_CMD_MII || CONFIG_MII */
/* We use strictly polling mode only */
@@ -397,7 +397,7 @@ static int fec_init(struct eth_device *dev, bd_t * bd)
fecp->eir = 0xffffffff;
/* Set station address */
- if ((u32) fecp == CFG_FEC0_IOBASE) {
+ if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
fec_set_hwaddr(fecp, bd->bi_enetaddr);
} else {
fec_set_hwaddr(fecp, bd->bi_enet1addr);
@@ -421,15 +421,15 @@ static int fec_init(struct eth_device *dev, bd_t * bd)
/* Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
* Settings: Last, Tx CRC */
- for (i = 0; i < CFG_TX_ETH_BUFFER; i++) {
+ for (i = 0; i < CONFIG_SYS_TX_ETH_BUFFER; i++) {
info->txbd[i].cbd_sc = 0;
info->txbd[i].cbd_datlen = 0;
info->txbd[i].cbd_bufaddr = (uint) (&info->txbuf[0]);
}
- info->txbd[CFG_TX_ETH_BUFFER - 1].cbd_sc |= BD_ENET_TX_WRAP;
+ info->txbd[CONFIG_SYS_TX_ETH_BUFFER - 1].cbd_sc |= BD_ENET_TX_WRAP;
info->usedTbdIdx = 0;
- info->cleanTbdNum = CFG_TX_ETH_BUFFER;
+ info->cleanTbdNum = CONFIG_SYS_TX_ETH_BUFFER;
/* Set Rx FIFO alarm and granularity value */
fecp->rfcr = 0x0c000000;
@@ -516,14 +516,14 @@ int mcdmafec_initialize(bd_t * bis)
{
struct eth_device *dev;
int i;
-#ifdef CFG_DMA_USE_INTSRAM
- u32 tmp = CFG_INTSRAM + 0x2000;
+#ifdef CONFIG_SYS_DMA_USE_INTSRAM
+ u32 tmp = CONFIG_SYS_INTSRAM + 0x2000;
#endif
for (i = 0; i < sizeof(fec_info) / sizeof(fec_info[0]); i++) {
dev =
- (struct eth_device *)memalign(CFG_CACHELINE_SIZE,
+ (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE,
sizeof *dev);
if (dev == NULL)
hang();
@@ -539,7 +539,7 @@ int mcdmafec_initialize(bd_t * bis)
dev->recv = fec_recv;
/* setup Receive and Transmit buffer descriptor */
-#ifdef CFG_DMA_USE_INTSRAM
+#ifdef CONFIG_SYS_DMA_USE_INTSRAM
fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp);
tmp = (u32)fec_info[i].rxbd;
fec_info[i].txbd =
@@ -548,17 +548,17 @@ int mcdmafec_initialize(bd_t * bis)
tmp = (u32)fec_info[i].txbd;
fec_info[i].txbuf =
(char *)((u32)fec_info[i].txbuf + tmp +
- (CFG_TX_ETH_BUFFER * sizeof(cbd_t)));
+ (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
tmp = (u32)fec_info[i].txbuf;
#else
fec_info[i].rxbd =
- (cbd_t *) memalign(CFG_CACHELINE_SIZE,
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
(PKTBUFSRX * sizeof(cbd_t)));
fec_info[i].txbd =
- (cbd_t *) memalign(CFG_CACHELINE_SIZE,
- (CFG_TX_ETH_BUFFER * sizeof(cbd_t)));
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
+ (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
fec_info[i].txbuf =
- (char *)memalign(CFG_CACHELINE_SIZE, DBUF_LENGTH);
+ (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH);
#endif
#ifdef ET_DEBUG
@@ -566,7 +566,7 @@ int mcdmafec_initialize(bd_t * bis)
(int)fec_info[i].rxbd, (int)fec_info[i].txbd);
#endif
- fec_info[i].phy_name = (char *)memalign(CFG_CACHELINE_SIZE, 32);
+ fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
eth_register(dev);
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 90c5338..79bc4d9 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -27,6 +27,7 @@
#include <common.h>
#include <command.h>
#include <net.h>
+#include <netdev.h>
#include <malloc.h>
#include <asm/processor.h>
#include <ambapp.h>
diff --git a/drivers/net/inca-ip_sw.c b/drivers/net/inca-ip_sw.c
index d852a15..492f5ce 100644
--- a/drivers/net/inca-ip_sw.c
+++ b/drivers/net/inca-ip_sw.c
@@ -28,6 +28,7 @@
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/inca-ip.h>
#include <asm/addrspace.h>
@@ -199,7 +200,7 @@ int inca_switch_initialize(bd_t * bis)
printf("Leaving inca_switch_initialize()\n");
#endif
- return 1;
+ return 0;
}
diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c
index c23a400..318bdf4 100644
--- a/drivers/net/lan91c96.c
+++ b/drivers/net/lan91c96.c
@@ -267,7 +267,7 @@ static void smc_shutdown (void);
static int poll4int (byte mask, int timeout)
{
- int tmo = get_timer (0) + timeout * CFG_HZ;
+ int tmo = get_timer (0) + timeout * CONFIG_SYS_HZ;
int is_timeout = 0;
word old_bank = SMC_inw (LAN91C96_BANK_SELECT);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index aa39284..98e8c73 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -28,7 +28,7 @@
* allocate our own, but we need one such buffer in case a packet
* wraps around the DMA ring so that we have to copy it.
*
- * Therefore, define CFG_RX_ETH_BUFFER to 1 in the board-specific
+ * Therefore, define CONFIG_SYS_RX_ETH_BUFFER to 1 in the board-specific
* configuration header. This way, the core allocates one RX buffer
* and one TX buffer, each of which can hold a ethernet packet of
* maximum size.
@@ -40,6 +40,7 @@
*/
#include <net.h>
+#include <netdev.h>
#include <malloc.h>
#include <linux/mii.h>
@@ -51,11 +52,11 @@
#define barrier() asm volatile("" ::: "memory")
-#define CFG_MACB_RX_BUFFER_SIZE 4096
-#define CFG_MACB_RX_RING_SIZE (CFG_MACB_RX_BUFFER_SIZE / 128)
-#define CFG_MACB_TX_RING_SIZE 16
-#define CFG_MACB_TX_TIMEOUT 1000
-#define CFG_MACB_AUTONEG_TIMEOUT 5000000
+#define CONFIG_SYS_MACB_RX_BUFFER_SIZE 4096
+#define CONFIG_SYS_MACB_RX_RING_SIZE (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128)
+#define CONFIG_SYS_MACB_TX_RING_SIZE 16
+#define CONFIG_SYS_MACB_TX_TIMEOUT 1000
+#define CONFIG_SYS_MACB_AUTONEG_TIMEOUT 5000000
struct macb_dma_desc {
u32 addr;
@@ -177,7 +178,7 @@ static int macb_send(struct eth_device *netdev, volatile void *packet,
ctrl = length & TXBUF_FRMLEN_MASK;
ctrl |= TXBUF_FRAME_END;
- if (tx_head == (CFG_MACB_TX_RING_SIZE - 1)) {
+ if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) {
ctrl |= TXBUF_WRAP;
macb->tx_head = 0;
} else
@@ -192,7 +193,7 @@ static int macb_send(struct eth_device *netdev, volatile void *packet,
* I guess this is necessary because the networking core may
* re-use the transmit buffer as soon as we return...
*/
- for (i = 0; i <= CFG_MACB_TX_TIMEOUT; i++) {
+ for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) {
barrier();
ctrl = macb->tx_ring[tx_head].ctrl;
if (ctrl & TXBUF_USED)
@@ -202,7 +203,7 @@ static int macb_send(struct eth_device *netdev, volatile void *packet,
dma_unmap_single(packet, length, paddr);
- if (i <= CFG_MACB_TX_TIMEOUT) {
+ if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) {
if (ctrl & TXBUF_UNDERRUN)
printf("%s: TX underrun\n", netdev->name);
if (ctrl & TXBUF_EXHAUSTED)
@@ -225,7 +226,7 @@ static void reclaim_rx_buffers(struct macb_device *macb,
while (i > new_tail) {
macb->rx_ring[i].addr &= ~RXADDR_USED;
i++;
- if (i > CFG_MACB_RX_RING_SIZE)
+ if (i > CONFIG_SYS_MACB_RX_RING_SIZE)
i = 0;
}
@@ -264,7 +265,7 @@ static int macb_recv(struct eth_device *netdev)
if (wrapped) {
unsigned int headlen, taillen;
- headlen = 128 * (CFG_MACB_RX_RING_SIZE
+ headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE
- macb->rx_tail);
taillen = length - headlen;
memcpy((void *)NetRxPackets[0],
@@ -275,11 +276,11 @@ static int macb_recv(struct eth_device *netdev)
}
NetReceive(buffer, length);
- if (++rx_tail >= CFG_MACB_RX_RING_SIZE)
+ if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE)
rx_tail = 0;
reclaim_rx_buffers(macb, rx_tail);
} else {
- if (++rx_tail >= CFG_MACB_RX_RING_SIZE) {
+ if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) {
wrapped = 1;
rx_tail = 0;
}
@@ -302,7 +303,7 @@ static void macb_phy_reset(struct macb_device *macb)
macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
| BMCR_ANRESTART));
- for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+ for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
status = macb_mdio_read(macb, MII_BMSR);
if (status & BMSR_ANEGCOMPLETE)
break;
@@ -336,7 +337,7 @@ static int macb_phy_init(struct macb_device *macb)
/* Try to re-negotiate if we don't have link already. */
macb_phy_reset(macb);
- for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+ for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
status = macb_mdio_read(macb, MII_BMSR);
if (status & BMSR_LSTATUS)
break;
@@ -387,16 +388,16 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
/* initialize DMA descriptors */
paddr = macb->rx_buffer_dma;
- for (i = 0; i < CFG_MACB_RX_RING_SIZE; i++) {
- if (i == (CFG_MACB_RX_RING_SIZE - 1))
+ for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) {
+ if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1))
paddr |= RXADDR_WRAP;
macb->rx_ring[i].addr = paddr;
macb->rx_ring[i].ctrl = 0;
paddr += 128;
}
- for (i = 0; i < CFG_MACB_TX_RING_SIZE; i++) {
+ for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) {
macb->tx_ring[i].addr = 0;
- if (i == (CFG_MACB_TX_RING_SIZE - 1))
+ if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1))
macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
else
macb->tx_ring[i].ctrl = TXBUF_USED;
@@ -472,12 +473,12 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
netdev = &macb->netdev;
- macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE,
+ macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE,
&macb->rx_buffer_dma);
- macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE
+ macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE
* sizeof(struct macb_dma_desc),
&macb->rx_ring_dma);
- macb->tx_ring = dma_alloc_coherent(CFG_MACB_TX_RING_SIZE
+ macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE
* sizeof(struct macb_dma_desc),
&macb->tx_ring_dma);
diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c
index 50d6508..18240a8 100644
--- a/drivers/net/mcffec.c
+++ b/drivers/net/mcffec.c
@@ -27,13 +27,14 @@
#include <common.h>
#include <malloc.h>
-#include <asm/fec.h>
-#include <asm/immap.h>
-
#include <command.h>
#include <net.h>
+#include <netdev.h>
#include <miiphy.h>
+#include <asm/fec.h>
+#include <asm/immap.h>
+
#undef ET_DEBUG
#undef MII_DEBUG
@@ -50,12 +51,12 @@
DECLARE_GLOBAL_DATA_PTR;
struct fec_info_s fec_info[] = {
-#ifdef CFG_FEC0_IOBASE
+#ifdef CONFIG_SYS_FEC0_IOBASE
{
0, /* index */
- CFG_FEC0_IOBASE, /* io base */
- CFG_FEC0_PINMUX, /* gpio pin muxing */
- CFG_FEC0_MIIBASE, /* mii base */
+ CONFIG_SYS_FEC0_IOBASE, /* io base */
+ CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC0_MIIBASE, /* mii base */
-1, /* phy_addr */
0, /* duplex and speed */
0, /* phy name */
@@ -69,17 +70,17 @@ struct fec_info_s fec_info[] = {
(struct fec_info_s *)-1,
},
#endif
-#ifdef CFG_FEC1_IOBASE
+#ifdef CONFIG_SYS_FEC1_IOBASE
{
1, /* index */
- CFG_FEC1_IOBASE, /* io base */
- CFG_FEC1_PINMUX, /* gpio pin muxing */
- CFG_FEC1_MIIBASE, /* mii base */
+ CONFIG_SYS_FEC1_IOBASE, /* io base */
+ CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */
+ CONFIG_SYS_FEC1_MIIBASE, /* mii base */
-1, /* phy_addr */
0, /* duplex and speed */
0, /* phy name */
0, /* phy name init */
-#ifdef CFG_FEC_BUF_USE_SRAM
+#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
(cbd_t *)DBUF_LENGTH, /* RX BD */
#else
0, /* RX BD */
@@ -100,18 +101,6 @@ int fec_init(struct eth_device *dev, bd_t * bd);
void fec_halt(struct eth_device *dev);
void fec_reset(struct eth_device *dev);
-extern int fecpin_setclear(struct eth_device *dev, int setclear);
-
-#ifdef CFG_DISCOVER_PHY
-extern void __mii_init(void);
-extern uint mii_send(uint mii_cmd);
-extern int mii_discover_phy(struct eth_device *dev);
-extern int mcffec_miiphy_read(char *devname, unsigned char addr,
- unsigned char reg, unsigned short *value);
-extern int mcffec_miiphy_write(char *devname, unsigned char addr,
- unsigned char reg, unsigned short value);
-#endif
-
void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd)
{
if ((dup_spd >> 16) == FULL) {
@@ -174,7 +163,7 @@ int fec_send(struct eth_device *dev, volatile void *packet, int length)
/* Activate transmit Buffer Descriptor polling */
fecp->tdar = 0x01000000; /* Descriptor polling active */
-#ifndef CFG_FEC_BUF_USE_SRAM
+#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM
/*
* FEC unable to initial transmit data packet.
* A nop will ensure the descriptor polling active completed.
@@ -186,7 +175,7 @@ int fec_send(struct eth_device *dev, volatile void *packet, int length)
#endif
-#ifdef CFG_UNIFY_CACHE
+#ifdef CONFIG_SYS_UNIFY_CACHE
icache_invalid();
#endif
@@ -221,9 +210,9 @@ int fec_recv(struct eth_device *dev)
int length;
for (;;) {
-#ifndef CFG_FEC_BUF_USE_SRAM
+#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM
#endif
-#ifdef CFG_UNIFY_CACHE
+#ifdef CONFIG_SYS_UNIFY_CACHE
icache_invalid();
#endif
/* section 16.9.23.2 */
@@ -434,15 +423,15 @@ int fec_init(struct eth_device *dev, bd_t * bd)
fec_reset(dev);
#if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \
- defined (CFG_DISCOVER_PHY)
+ defined (CONFIG_SYS_DISCOVER_PHY)
mii_init();
setFecDuplexSpeed(fecp, bd, info->dup_spd);
#else
-#ifndef CFG_DISCOVER_PHY
+#ifndef CONFIG_SYS_DISCOVER_PHY
setFecDuplexSpeed(fecp, bd, (FECDUPLEX << 16) | FECSPEED);
-#endif /* ifndef CFG_DISCOVER_PHY */
+#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */
#endif /* CONFIG_CMD_MII || CONFIG_MII */
/* We use strictly polling mode only */
@@ -452,9 +441,9 @@ int fec_init(struct eth_device *dev, bd_t * bd)
fecp->eir = 0xffffffff;
/* Set station address */
- if ((u32) fecp == CFG_FEC0_IOBASE) {
-#ifdef CFG_FEC1_IOBASE
- volatile fec_t *fecp1 = (fec_t *) (CFG_FEC1_IOBASE);
+ if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
+#ifdef CONFIG_SYS_FEC1_IOBASE
+ volatile fec_t *fecp1 = (fec_t *) (CONFIG_SYS_FEC1_IOBASE);
ea = &bd->bi_enet1addr[0];
fecp1->palr =
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
@@ -465,14 +454,14 @@ int fec_init(struct eth_device *dev, bd_t * bd)
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
fecp->paur = (ea[4] << 24) | (ea[5] << 16);
} else {
-#ifdef CFG_FEC0_IOBASE
- volatile fec_t *fecp0 = (fec_t *) (CFG_FEC0_IOBASE);
+#ifdef CONFIG_SYS_FEC0_IOBASE
+ volatile fec_t *fecp0 = (fec_t *) (CONFIG_SYS_FEC0_IOBASE);
ea = &bd->bi_enetaddr[0];
fecp0->palr =
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
fecp0->paur = (ea[4] << 24) | (ea[5] << 16);
#endif
-#ifdef CFG_FEC1_IOBASE
+#ifdef CONFIG_SYS_FEC1_IOBASE
ea = &bd->bi_enet1addr[0];
fecp->palr =
(ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
@@ -567,14 +556,14 @@ int mcffec_initialize(bd_t * bis)
{
struct eth_device *dev;
int i;
-#ifdef CFG_FEC_BUF_USE_SRAM
- u32 tmp = CFG_INIT_RAM_ADDR + 0x1000;
+#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
+ u32 tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000;
#endif
for (i = 0; i < sizeof(fec_info) / sizeof(fec_info[0]); i++) {
dev =
- (struct eth_device *)memalign(CFG_CACHELINE_SIZE,
+ (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE,
sizeof *dev);
if (dev == NULL)
hang();
@@ -590,7 +579,7 @@ int mcffec_initialize(bd_t * bis)
dev->recv = fec_recv;
/* setup Receive and Transmit buffer descriptor */
-#ifdef CFG_FEC_BUF_USE_SRAM
+#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp);
tmp = (u32)fec_info[i].rxbd;
fec_info[i].txbd =
@@ -599,17 +588,17 @@ int mcffec_initialize(bd_t * bis)
tmp = (u32)fec_info[i].txbd;
fec_info[i].txbuf =
(char *)((u32)fec_info[i].txbuf + tmp +
- (CFG_TX_ETH_BUFFER * sizeof(cbd_t)));
+ (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
tmp = (u32)fec_info[i].txbuf;
#else
fec_info[i].rxbd =
- (cbd_t *) memalign(CFG_CACHELINE_SIZE,
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
(PKTBUFSRX * sizeof(cbd_t)));
fec_info[i].txbd =
- (cbd_t *) memalign(CFG_CACHELINE_SIZE,
+ (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
(TX_BUF_CNT * sizeof(cbd_t)));
fec_info[i].txbuf =
- (char *)memalign(CFG_CACHELINE_SIZE, DBUF_LENGTH);
+ (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH);
#endif
#ifdef ET_DEBUG
@@ -617,7 +606,7 @@ int mcffec_initialize(bd_t * bis)
(int)fec_info[i].rxbd, (int)fec_info[i].txbd);
#endif
- fec_info[i].phy_name = (char *)memalign(CFG_CACHELINE_SIZE, 32);
+ fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
eth_register(dev);
diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c
new file mode 100644
index 0000000..2b733c6
--- /dev/null
+++ b/drivers/net/mcfmii.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ *
+ * 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 <config.h>
+#include <net.h>
+#include <netdev.h>
+
+#ifdef CONFIG_MCF547x_8x
+#include <asm/fsl_mcdmafec.h>
+#else
+#include <asm/fec.h>
+#endif
+#include <asm/immap.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI)
+#undef MII_DEBUG
+#undef ET_DEBUG
+
+/*extern int fecpin_setclear(struct eth_device *dev, int setclear);*/
+
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+
+/* Make MII read/write commands for the FEC. */
+#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18))
+#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18) | (VAL & 0xffff))
+
+#ifndef CONFIG_SYS_UNSPEC_PHYID
+# define CONFIG_SYS_UNSPEC_PHYID 0
+#endif
+#ifndef CONFIG_SYS_UNSPEC_STRID
+# define CONFIG_SYS_UNSPEC_STRID 0
+#endif
+
+#ifdef CONFIG_MCF547x_8x
+typedef struct fec_info_dma FEC_INFO_T;
+#define FEC_T fecdma_t
+#else
+typedef struct fec_info_s FEC_INFO_T;
+#define FEC_T fec_t
+#endif
+
+typedef struct phy_info_struct {
+ u32 phyid;
+ char *strid;
+} phy_info_t;
+
+phy_info_t phyinfo[] = {
+ {0x0022561B, "AMD79C784VC"}, /* AMD 79C784VC */
+ {0x00406322, "BCM5222"}, /* Broadcom 5222 */
+ {0x02a80150, "Intel82555"}, /* Intel 82555 */
+ {0x0016f870, "LSI80225"}, /* LSI 80225 */
+ {0x0016f880, "LSI80225/B"}, /* LSI 80225/B */
+ {0x78100000, "LXT970"}, /* LXT970 */
+ {0x001378e0, "LXT971"}, /* LXT971 and 972 */
+ {0x00221619, "KS8721BL"}, /* Micrel KS8721BL/SL */
+ {0x00221512, "KSZ8041NL"}, /* Micrel KSZ8041NL */
+ {0x20005CE1, "N83640"}, /* National 83640 */
+ {0x20005C90, "N83848"}, /* National 83848 */
+ {0x20005CA2, "N83849"}, /* National 83849 */
+ {0x01814400, "QS6612"}, /* QS6612 */
+#if defined(CONFIG_SYS_UNSPEC_PHYID) && defined(CONFIG_SYS_UNSPEC_STRID)
+ {CONFIG_SYS_UNSPEC_PHYID, CONFIG_SYS_UNSPEC_STRID},
+#endif
+ {0, 0}
+};
+
+/*
+ * mii_init -- Initialize the MII for MII command without ethernet
+ * This function is a subset of eth_init
+ */
+void mii_reset(FEC_INFO_T *info)
+{
+ volatile FEC_T *fecp = (FEC_T *) (info->miibase);
+ int i;
+
+ fecp->ecr = FEC_ECR_RESET;
+
+ for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) {
+ udelay(1);
+ }
+ if (i == FEC_RESET_DELAY)
+ printf("FEC_RESET_DELAY timeout\n");
+}
+
+/* send command to phy using mii, wait for result */
+uint mii_send(uint mii_cmd)
+{
+ FEC_INFO_T *info;
+ volatile FEC_T *ep;
+ struct eth_device *dev;
+ uint mii_reply;
+ int j = 0;
+
+ /* retrieve from register structure */
+ dev = eth_get_dev();
+ info = dev->priv;
+
+ ep = (FEC_T *) info->miibase;
+
+ ep->mmfr = mii_cmd; /* command to phy */
+
+ /* wait for mii complete */
+ while (!(ep->eir & FEC_EIR_MII) && (j < MCFFEC_TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j >= MCFFEC_TOUT_LOOP) {
+ printf("MII not complete\n");
+ return -1;
+ }
+
+ mii_reply = ep->mmfr; /* result from phy */
+ ep->eir = FEC_EIR_MII; /* clear MII complete */
+#ifdef ET_DEBUG
+ printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
+ __FILE__, __LINE__, __FUNCTION__, mii_cmd, mii_reply);
+#endif
+
+ return (mii_reply & 0xffff); /* data read from phy */
+}
+#endif /* CONFIG_SYS_DISCOVER_PHY || (CONFIG_MII) */
+
+#if defined(CONFIG_SYS_DISCOVER_PHY)
+int mii_discover_phy(struct eth_device *dev)
+{
+#define MAX_PHY_PASSES 11
+ FEC_INFO_T *info = dev->priv;
+ int phyaddr, pass;
+ uint phyno, phytype;
+ int i, found = 0;
+
+ if (info->phyname_init)
+ return info->phy_addr;
+
+ phyaddr = -1; /* didn't find a PHY yet */
+ for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
+ if (pass > 1) {
+ /* PHY may need more time to recover from reset.
+ * The LXT970 needs 50ms typical, no maximum is
+ * specified, so wait 10ms before try again.
+ * With 11 passes this gives it 100ms to wake up.
+ */
+ udelay(10000); /* wait 10ms */
+ }
+
+ for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
+
+ phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR1));
+#ifdef ET_DEBUG
+ printf("PHY type 0x%x pass %d type\n", phytype, pass);
+#endif
+ if (phytype != 0xffff) {
+ phyaddr = phyno;
+ phytype <<= 16;
+ phytype |=
+ mii_send(mk_mii_read(phyno, PHY_PHYIDR2));
+
+#ifdef ET_DEBUG
+ printf("PHY @ 0x%x pass %d\n", phyno, pass);
+#endif
+
+ for (i = 0; i < (sizeof(phyinfo) / sizeof(phy_info_t)); i++) {
+ if (phyinfo[i].phyid == phytype) {
+#ifdef ET_DEBUG
+ printf("phyid %x - %s\n",
+ phyinfo[i].phyid,
+ phyinfo[i].strid);
+#endif
+ strcpy(info->phy_name, phyinfo[i].strid);
+ info->phyname_init = 1;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+#ifdef ET_DEBUG
+ printf("0x%08x\n", phytype);
+#endif
+ strcpy(info->phy_name, "unknown");
+ info->phyname_init = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (phyaddr < 0)
+ printf("No PHY device found.\n");
+
+ return phyaddr;
+}
+#endif /* CONFIG_SYS_DISCOVER_PHY */
+
+void mii_init(void) __attribute__((weak,alias("__mii_init")));
+
+void __mii_init(void)
+{
+ FEC_INFO_T *info;
+ volatile FEC_T *fecp;
+ struct eth_device *dev;
+ int miispd = 0, i = 0;
+ u16 autoneg = 0;
+
+ /* retrieve from register structure */
+ dev = eth_get_dev();
+ info = dev->priv;
+
+ fecp = (FEC_T *) info->miibase;
+
+ fecpin_setclear(dev, 1);
+
+ mii_reset(info);
+
+ /* We use strictly polling mode only */
+ fecp->eimr = 0;
+
+ /* Clear any pending interrupt */
+ fecp->eir = 0xffffffff;
+
+ /* Set MII speed */
+ miispd = (gd->bus_clk / 1000000) / 5;
+ fecp->mscr = miispd << 1;
+
+ info->phy_addr = mii_discover_phy(dev);
+
+#define AUTONEGLINK (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS)
+ while (i < MCFFEC_TOUT_LOOP) {
+ autoneg = 0;
+ miiphy_read(dev->name, info->phy_addr, PHY_BMSR, &autoneg);
+ i++;
+
+ if ((autoneg & AUTONEGLINK) == AUTONEGLINK)
+ break;
+
+ udelay(500);
+ }
+ if (i >= MCFFEC_TOUT_LOOP) {
+ printf("Auto Negotiation not complete\n");
+ }
+
+ /* adapt to the half/full speed settings */
+ info->dup_spd = miiphy_duplex(dev->name, info->phy_addr) << 16;
+ info->dup_spd |= miiphy_speed(dev->name, info->phy_addr);
+}
+
+/*
+ * Read and write a MII PHY register, routines used by MII Utilities
+ *
+ * FIXME: These routines are expected to return 0 on success, but mii_send
+ * does _not_ return an error code. Maybe 0xFFFF means error, i.e.
+ * no PHY connected...
+ * For now always return 0.
+ * FIXME: These routines only work after calling eth_init() at least once!
+ * Otherwise they hang in mii_send() !!! Sorry!
+ */
+
+int mcffec_miiphy_read(char *devname, unsigned char addr, unsigned char reg,
+ unsigned short *value)
+{
+ short rdreg; /* register working value */
+
+#ifdef MII_DEBUG
+ printf("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
+#endif
+ rdreg = mii_send(mk_mii_read(addr, reg));
+
+ *value = rdreg;
+
+#ifdef MII_DEBUG
+ printf("0x%04x\n", *value);
+#endif
+
+ return 0;
+}
+
+int mcffec_miiphy_write(char *devname, unsigned char addr, unsigned char reg,
+ unsigned short value)
+{
+ short rdreg; /* register working value */
+
+#ifdef MII_DEBUG
+ printf("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
+#endif
+
+ rdreg = mii_send(mk_mii_write(addr, reg, value));
+
+#ifdef MII_DEBUG
+ printf("0x%04x\n", value);
+#endif
+
+ return 0;
+}
+
+#endif /* CONFIG_CMD_NET, FEC_ENET & NET_MULTI */
diff --git a/drivers/net/mpc512x_fec.c b/drivers/net/mpc512x_fec.c
index 7caeeda..7078c4e 100644
--- a/drivers/net/mpc512x_fec.c
+++ b/drivers/net/mpc512x_fec.c
@@ -10,6 +10,7 @@
#include <mpc512x.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <miiphy.h>
#include "mpc512x_fec.h"
@@ -363,7 +364,7 @@ int mpc512x_fec_init_phy (struct eth_device *dev, bd_t * bis)
/*
* Wait for AN completion
*/
- timeout = 50000;
+ timeout = 2500;
do {
udelay (1000);
diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c
index 3d3eb8b..f8618b1 100644
--- a/drivers/net/mpc5xxx_fec.c
+++ b/drivers/net/mpc5xxx_fec.c
@@ -11,6 +11,7 @@
#include <mpc5xxx_sdma.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <miiphy.h>
#include "mpc5xxx_fec.h"
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 4aee048..ce12c3b 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -53,6 +53,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
@@ -408,7 +409,7 @@ natsemi_initialize(bd_t * bis)
The EEPROM code is for common 93c06/46 EEPROMs w/ 6bit addresses. */
/* Delay between EEPROM clock transitions.
- No extra delay is needed with 33Mhz PCI, but future 66Mhz
+ No extra delay is needed with 33MHz PCI, but future 66MHz
access may need a delay. */
#define eeprom_delay(ee_addr) INL(dev, ee_addr)
diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c
index ec92485..ab5eec7 100644
--- a/drivers/net/ne2000.c
+++ b/drivers/net/ne2000.c
@@ -74,600 +74,11 @@ Add SNMP
#include <common.h>
#include <command.h>
-#include <net.h>
-#include <malloc.h>
-
-#define mdelay(n) udelay((n)*1000)
-/* forward definition of function used for the uboot interface */
-void uboot_push_packet_len(int len);
-void uboot_push_tx_done(int key, int val);
-
-/*
- * Debugging details
- *
- * Set to perms of:
- * 0 disables all debug output
- * 1 for process debug output
- * 2 for added data IO output: get_reg, put_reg
- * 4 for packet allocation/free output
- * 8 for only startup status, so we can tell we're installed OK
- */
-#if 0
-#define DEBUG 0xf
-#else
-#define DEBUG 0
-#endif
-
-#if DEBUG & 1
-#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
-#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
-#define PRINTK(args...) printf(args)
-#else
-#define DEBUG_FUNCTION() do {} while(0)
-#define DEBUG_LINE() do {} while(0)
-#define PRINTK(args...)
-#endif
/* NE2000 base header file */
#include "ne2000_base.h"
-#if defined(CONFIG_DRIVER_AX88796L)
-/* AX88796L support */
-#include "ax88796.h"
-#else
-/* Basic NE2000 chip support */
-#include "ne2000.h"
-#endif
-
-static dp83902a_priv_data_t nic; /* just one instance of the card supported */
-
-static bool
-dp83902a_init(void)
-{
- dp83902a_priv_data_t *dp = &nic;
- u8* base;
-#if defined(NE2000_BASIC_INIT)
- int i;
-#endif
-
- DEBUG_FUNCTION();
-
- base = dp->base;
- if (!base)
- return false; /* No device found */
-
- DEBUG_LINE();
-
-#if defined(NE2000_BASIC_INIT)
- /* AX88796L doesn't need */
- /* Prepare ESA */
- DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */
- /* Use the address from the serial EEPROM */
- for (i = 0; i < 6; i++)
- DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
- DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */
-
- printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
- "eeprom",
- dp->esa[0],
- dp->esa[1],
- dp->esa[2],
- dp->esa[3],
- dp->esa[4],
- dp->esa[5] );
-
-#endif /* NE2000_BASIC_INIT */
- return true;
-}
-
-static void
-dp83902a_stop(void)
-{
- dp83902a_priv_data_t *dp = &nic;
- u8 *base = dp->base;
-
- DEBUG_FUNCTION();
-
- DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
- DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
- DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */
-
- dp->running = false;
-}
-
-/*
- * This function is called to "start up" the interface. It may be called
- * multiple times, even when the hardware is already running. It will be
- * called whenever something "hardware oriented" changes and should leave
- * the hardware ready to send/receive packets.
- */
-static void
-dp83902a_start(u8 * enaddr)
-{
- dp83902a_priv_data_t *dp = &nic;
- u8 *base = dp->base;
- int i;
-
- DEBUG_FUNCTION();
-
- DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
- DP_OUT(base, DP_DCR, DP_DCR_INIT);
- DP_OUT(base, DP_RBCH, 0); /* Remote byte count */
- DP_OUT(base, DP_RBCL, 0);
- DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */
- DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */
- DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */
- dp->tx1 = dp->tx2 = 0;
- dp->tx_next = dp->tx_buf1;
- dp->tx_started = false;
- dp->running = true;
- DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
- DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
- DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */
- dp->rx_next = dp->rx_buf_start - 1;
- dp->running = true;
- DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
- DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */
- DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */
- DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */
- dp->running = true;
- for (i = 0; i < ETHER_ADDR_LEN; i++) {
- /* FIXME */
- /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
- * 0x1400)) = enaddr[i];*/
- DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
- }
- /* Enable and start device */
- DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
- DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
- DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
- dp->running = true;
-}
-
-/*
- * This routine is called to start the transmitter. It is split out from the
- * data handling routine so it may be called either when data becomes first
- * available or when an Tx interrupt occurs
- */
-
-static void
-dp83902a_start_xmit(int start_page, int len)
-{
- dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
- u8 *base = dp->base;
-
- DEBUG_FUNCTION();
-
-#if DEBUG & 1
- printf("Tx pkt %d len %d\n", start_page, len);
- if (dp->tx_started)
- printf("TX already started?!?\n");
-#endif
-
- DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
- DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
- DP_OUT(base, DP_TBCL, len & 0xFF);
- DP_OUT(base, DP_TBCH, len >> 8);
- DP_OUT(base, DP_TPSR, start_page);
- DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
-
- dp->tx_started = true;
-}
-
-/*
- * This routine is called to send data to the hardware. It is known a-priori
- * that there is free buffer space (dp->tx_next).
- */
-static void
-dp83902a_send(u8 *data, int total_len, u32 key)
-{
- struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
- u8 *base = dp->base;
- int len, start_page, pkt_len, i, isr;
-#if DEBUG & 4
- int dx;
-#endif
-
- DEBUG_FUNCTION();
-
- len = pkt_len = total_len;
- if (pkt_len < IEEE_8023_MIN_FRAME)
- pkt_len = IEEE_8023_MIN_FRAME;
-
- start_page = dp->tx_next;
- if (dp->tx_next == dp->tx_buf1) {
- dp->tx1 = start_page;
- dp->tx1_len = pkt_len;
- dp->tx1_key = key;
- dp->tx_next = dp->tx_buf2;
- } else {
- dp->tx2 = start_page;
- dp->tx2_len = pkt_len;
- dp->tx2_key = key;
- dp->tx_next = dp->tx_buf1;
- }
-
-#if DEBUG & 5
- printf("TX prep page %d len %d\n", start_page, pkt_len);
-#endif
-
- DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
- {
- /*
- * Dummy read. The manual sez something slightly different,
- * but the code is extended a bit to do what Hitachi's monitor
- * does (i.e., also read data).
- */
-
- u16 tmp;
- int len = 1;
-
- DP_OUT(base, DP_RSAL, 0x100 - len);
- DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
- DP_OUT(base, DP_RBCL, len);
- DP_OUT(base, DP_RBCH, 0);
- DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
- DP_IN_DATA(dp->data, tmp);
- }
-
-#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
- /*
- * Stall for a bit before continuing to work around random data
- * corruption problems on some platforms.
- */
- CYGACC_CALL_IF_DELAY_US(1);
-#endif
-
- /* Send data to device buffer(s) */
- DP_OUT(base, DP_RSAL, 0);
- DP_OUT(base, DP_RSAH, start_page);
- DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
- DP_OUT(base, DP_RBCH, pkt_len >> 8);
- DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
-
- /* Put data into buffer */
-#if DEBUG & 4
- printf(" sg buf %08lx len %08x\n ", (u32)data, len);
- dx = 0;
-#endif
- while (len > 0) {
-#if DEBUG & 4
- printf(" %02x", *data);
- if (0 == (++dx % 16)) printf("\n ");
-#endif
-
- DP_OUT_DATA(dp->data, *data++);
- len--;
- }
-#if DEBUG & 4
- printf("\n");
-#endif
- if (total_len < pkt_len) {
-#if DEBUG & 4
- printf(" + %d bytes of padding\n", pkt_len - total_len);
-#endif
- /* Padding to 802.3 length was required */
- for (i = total_len; i < pkt_len;) {
- i++;
- DP_OUT_DATA(dp->data, 0);
- }
- }
-
-#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
- /*
- * After last data write, delay for a bit before accessing the
- * device again, or we may get random data corruption in the last
- * datum (on some platforms).
- */
- CYGACC_CALL_IF_DELAY_US(1);
-#endif
-
- /* Wait for DMA to complete */
- do {
- DP_IN(base, DP_ISR, isr);
- } while ((isr & DP_ISR_RDC) == 0);
-
- /* Then disable DMA */
- DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
-
- /* Start transmit if not already going */
- if (!dp->tx_started) {
- if (start_page == dp->tx1) {
- dp->tx_int = 1; /* Expecting interrupt from BUF1 */
- } else {
- dp->tx_int = 2; /* Expecting interrupt from BUF2 */
- }
- dp83902a_start_xmit(start_page, pkt_len);
- }
-}
-
-/*
- * This function is called when a packet has been received. It's job is
- * to prepare to unload the packet from the hardware. Once the length of
- * the packet is known, the upper layer of the driver can be told. When
- * the upper layer is ready to unload the packet, the internal function
- * 'dp83902a_recv' will be called to actually fetch it from the hardware.
- */
-static void
-dp83902a_RxEvent(void)
-{
- struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
- u8 *base = dp->base;
- u8 rsr;
- u8 rcv_hdr[4];
- int i, len, pkt, cur;
-
- DEBUG_FUNCTION();
-
- DP_IN(base, DP_RSR, rsr);
- while (true) {
- /* Read incoming packet header */
- DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
- DP_IN(base, DP_P1_CURP, cur);
- DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
- DP_IN(base, DP_BNDRY, pkt);
-
- pkt += 1;
- if (pkt == dp->rx_buf_end)
- pkt = dp->rx_buf_start;
-
- if (pkt == cur) {
- break;
- }
- DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
- DP_OUT(base, DP_RBCH, 0);
- DP_OUT(base, DP_RSAL, 0);
- DP_OUT(base, DP_RSAH, pkt);
- if (dp->rx_next == pkt) {
- if (cur == dp->rx_buf_start)
- DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
- else
- DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
- return;
- }
- dp->rx_next = pkt;
- DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
- DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
-#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
- CYGACC_CALL_IF_DELAY_US(10);
-#endif
-
- /* read header (get data size)*/
- for (i = 0; i < sizeof(rcv_hdr);) {
- DP_IN_DATA(dp->data, rcv_hdr[i++]);
- }
-
-#if DEBUG & 5
- printf("rx hdr %02x %02x %02x %02x\n",
- rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
-#endif
- len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
-
- /* data read */
- uboot_push_packet_len(len);
-
- if (rcv_hdr[1] == dp->rx_buf_start)
- DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
- else
- DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
- }
-}
-
-/*
- * This function is called as a result of the "eth_drv_recv()" call above.
- * It's job is to actually fetch data for a packet from the hardware once
- * memory buffers have been allocated for the packet. Note that the buffers
- * may come in pieces, using a scatter-gather list. This allows for more
- * efficient processing in the upper layers of the stack.
- */
-static void
-dp83902a_recv(u8 *data, int len)
-{
- struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
- u8 *base = dp->base;
- int i, mlen;
- u8 saved_char = 0;
- bool saved;
-#if DEBUG & 4
- int dx;
-#endif
-
- DEBUG_FUNCTION();
-
-#if DEBUG & 5
- printf("Rx packet %d length %d\n", dp->rx_next, len);
-#endif
-
- /* Read incoming packet data */
- DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
- DP_OUT(base, DP_RBCL, len & 0xFF);
- DP_OUT(base, DP_RBCH, len >> 8);
- DP_OUT(base, DP_RSAL, 4); /* Past header */
- DP_OUT(base, DP_RSAH, dp->rx_next);
- DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
- DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
-#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
- CYGACC_CALL_IF_DELAY_US(10);
-#endif
-
- saved = false;
- for (i = 0; i < 1; i++) {
- if (data) {
- mlen = len;
-#if DEBUG & 4
- printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
- dx = 0;
-#endif
- while (0 < mlen) {
- /* Saved byte from previous loop? */
- if (saved) {
- *data++ = saved_char;
- mlen--;
- saved = false;
- continue;
- }
-
- {
- u8 tmp;
- DP_IN_DATA(dp->data, tmp);
-#if DEBUG & 4
- printf(" %02x", tmp);
- if (0 == (++dx % 16)) printf("\n ");
-#endif
- *data++ = tmp;;
- mlen--;
- }
- }
-#if DEBUG & 4
- printf("\n");
-#endif
- }
- }
-}
-
-static void
-dp83902a_TxEvent(void)
-{
- struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
- u8 *base = dp->base;
- u8 tsr;
- u32 key;
-
- DEBUG_FUNCTION();
-
- DP_IN(base, DP_TSR, tsr);
- if (dp->tx_int == 1) {
- key = dp->tx1_key;
- dp->tx1 = 0;
- } else {
- key = dp->tx2_key;
- dp->tx2 = 0;
- }
- /* Start next packet if one is ready */
- dp->tx_started = false;
- if (dp->tx1) {
- dp83902a_start_xmit(dp->tx1, dp->tx1_len);
- dp->tx_int = 1;
- } else if (dp->tx2) {
- dp83902a_start_xmit(dp->tx2, dp->tx2_len);
- dp->tx_int = 2;
- } else {
- dp->tx_int = 0;
- }
- /* Tell higher level we sent this packet */
- uboot_push_tx_done(key, 0);
-}
-
-/*
- * Read the tally counters to clear them. Called in response to a CNT
- * interrupt.
- */
-static void
-dp83902a_ClearCounters(void)
-{
- struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
- u8 *base = dp->base;
- u8 cnt1, cnt2, cnt3;
-
- DP_IN(base, DP_FER, cnt1);
- DP_IN(base, DP_CER, cnt2);
- DP_IN(base, DP_MISSED, cnt3);
- DP_OUT(base, DP_ISR, DP_ISR_CNT);
-}
-
-/*
- * Deal with an overflow condition. This code follows the procedure set
- * out in section 7.0 of the datasheet.
- */
-static void
-dp83902a_Overflow(void)
-{
- struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
- u8 *base = dp->base;
- u8 isr;
-
- /* Issue a stop command and wait 1.6ms for it to complete. */
- DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
- CYGACC_CALL_IF_DELAY_US(1600);
-
- /* Clear the remote byte counter registers. */
- DP_OUT(base, DP_RBCL, 0);
- DP_OUT(base, DP_RBCH, 0);
-
- /* Enter loopback mode while we clear the buffer. */
- DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
- DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
-
- /*
- * Read in as many packets as we can and acknowledge any and receive
- * interrupts. Since the buffer has overflowed, a receive event of
- * some kind will have occured.
- */
- dp83902a_RxEvent();
- DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
-
- /* Clear the overflow condition and leave loopback mode. */
- DP_OUT(base, DP_ISR, DP_ISR_OFLW);
- DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
-
- /*
- * If a transmit command was issued, but no transmit event has occured,
- * restart it here.
- */
- DP_IN(base, DP_ISR, isr);
- if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
- DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
- }
-}
-
-static void
-dp83902a_poll(void)
-{
- struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
- u8 *base = dp->base;
- u8 isr;
-
- DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
- DP_IN(base, DP_ISR, isr);
- while (0 != isr) {
- /*
- * The CNT interrupt triggers when the MSB of one of the error
- * counters is set. We don't much care about these counters, but
- * we should read their values to reset them.
- */
- if (isr & DP_ISR_CNT) {
- dp83902a_ClearCounters();
- }
- /*
- * Check for overflow. It's a special case, since there's a
- * particular procedure that must be followed to get back into
- * a running state.a
- */
- if (isr & DP_ISR_OFLW) {
- dp83902a_Overflow();
- } else {
- /*
- * Other kinds of interrupts can be acknowledged simply by
- * clearing the relevant bits of the ISR. Do that now, then
- * handle the interrupts we care about.
- */
- DP_OUT(base, DP_ISR, isr); /* Clear set bits */
- if (!dp->running) break; /* Is this necessary? */
- /*
- * Check for tx_started on TX event since these may happen
- * spuriously it seems.
- */
- if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
- dp83902a_TxEvent();
- }
- if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
- dp83902a_RxEvent();
- }
- }
- DP_IN(base, DP_ISR, isr);
- }
-}
-
+#define mdelay(n) udelay((n)*1000)
/* find prom (taken from pc_net_cs.c from Linux) */
#include "8390.h"
@@ -763,18 +174,16 @@ static hw_info_t hw_info[] = {
#define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */
#define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */
-static void pcnet_reset_8390(void)
+static void pcnet_reset_8390(u8* addr)
{
int i, r;
- PRINTK("nic base is %lx\n", nic.base);
-
n2k_outb(E8390_NODMA + E8390_PAGE0+E8390_STOP, E8390_CMD);
- PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD));
+ PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD));
n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD);
- PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD));
+ PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD));
n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
- PRINTK("cmd (at %lx) is %x\n", nic.base + E8390_CMD, n2k_inb(E8390_CMD));
+ PRINTK("cmd (at %lx) is %x\n", addr + E8390_CMD, n2k_inb(E8390_CMD));
n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET);
@@ -791,8 +200,7 @@ static void pcnet_reset_8390(void)
printf("pcnet_reset_8390() did not complete.\n");
} /* pcnet_reset_8390 */
-int get_prom(u8* mac_addr) __attribute__ ((weak, alias ("__get_prom")));
-int __get_prom(u8* mac_addr)
+int get_prom(u8* mac_addr, u8* base_addr)
{
u8 prom[32];
int i, j;
@@ -816,7 +224,7 @@ int __get_prom(u8* mac_addr)
PRINTK ("trying to get MAC via prom reading\n");
- pcnet_reset_8390 ();
+ pcnet_reset_8390 (base_addr);
mdelay (10);
@@ -849,116 +257,3 @@ int __get_prom(u8* mac_addr)
}
return 0;
}
-
-/* U-boot specific routines */
-static u8 *pbuf = NULL;
-
-static int pkey = -1;
-static int initialized = 0;
-
-void uboot_push_packet_len(int len) {
- PRINTK("pushed len = %d\n", len);
- if (len >= 2000) {
- printf("NE2000: packet too big\n");
- return;
- }
- dp83902a_recv(&pbuf[0], len);
-
- /*Just pass it to the upper layer*/
- NetReceive(&pbuf[0], len);
-}
-
-void uboot_push_tx_done(int key, int val) {
- PRINTK("pushed key = %d\n", key);
- pkey = key;
-}
-
-int eth_init(bd_t *bd) {
- int r;
- u8 dev_addr[6];
- char ethaddr[20];
-
- PRINTK("### eth_init\n");
-
- if (!pbuf) {
- pbuf = malloc(2000);
- if (!pbuf) {
- printf("Cannot allocate rx buffer\n");
- return -1;
- }
- }
-
-#ifdef CONFIG_DRIVER_NE2000_CCR
- {
- vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
-
- PRINTK("CCR before is %x\n", *p);
- *p = CONFIG_DRIVER_NE2000_VAL;
- PRINTK("CCR after is %x\n", *p);
- }
-#endif
-
- nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
-
- r = get_prom(dev_addr);
- if (!r)
- return -1;
-
- sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
- dev_addr[0], dev_addr[1],
- dev_addr[2], dev_addr[3],
- dev_addr[4], dev_addr[5]) ;
- PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
- setenv ("ethaddr", ethaddr);
-
- nic.data = nic.base + DP_DATA;
- nic.tx_buf1 = START_PG;
- nic.tx_buf2 = START_PG2;
- nic.rx_buf_start = RX_START;
- nic.rx_buf_end = RX_END;
-
- if (dp83902a_init() == false)
- return -1;
-
- dp83902a_start(dev_addr);
- initialized = 1;
-
- return 0;
-}
-
-void eth_halt() {
-
- PRINTK("### eth_halt\n");
- if(initialized)
- dp83902a_stop();
- initialized = 0;
-}
-
-int eth_rx() {
- dp83902a_poll();
- return 1;
-}
-
-int eth_send(volatile void *packet, int length) {
- int tmo;
-
- PRINTK("### eth_send\n");
-
- pkey = -1;
-
- dp83902a_send((u8 *) packet, length, 666);
- tmo = get_timer (0) + TOUT * CFG_HZ;
- while(1) {
- dp83902a_poll();
- if (pkey != -1) {
- PRINTK("Packet sucesfully sent\n");
- return 0;
- }
- if (get_timer (0) >= tmo) {
- printf("transmission error (timoeut)\n");
- return 0;
- }
-
- }
- return 0;
-}
diff --git a/drivers/net/ne2000_base.c b/drivers/net/ne2000_base.c
new file mode 100644
index 0000000..f93f932
--- /dev/null
+++ b/drivers/net/ne2000_base.c
@@ -0,0 +1,757 @@
+/*
+Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
+
+Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
+eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
+are GPL, so this is, of course, GPL.
+
+==========================================================================
+
+dev/if_dp83902a.c
+
+Ethernet device driver for NS DP83902a ethernet controller
+
+==========================================================================
+####ECOSGPLCOPYRIGHTBEGIN####
+-------------------------------------------
+This file is part of eCos, the Embedded Configurable Operating System.
+Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+eCos 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 or (at your option) any later version.
+
+eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file does not
+by itself cause the resulting work to be covered by the GNU General Public
+License. However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based on
+this file might be covered by the GNU General Public License.
+
+Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+at http://sources.redhat.com/ecos/ecos-license/
+-------------------------------------------
+####ECOSGPLCOPYRIGHTEND####
+####BSDCOPYRIGHTBEGIN####
+
+-------------------------------------------
+
+Portions of this software may have been derived from OpenBSD or other sources,
+and are covered by the appropriate copyright disclaimers included herein.
+
+-------------------------------------------
+
+####BSDCOPYRIGHTEND####
+==========================================================================
+#####DESCRIPTIONBEGIN####
+
+Author(s): gthomas
+Contributors: gthomas, jskov, rsandifo
+Date: 2001-06-13
+Purpose:
+Description:
+
+FIXME: Will fail if pinged with large packets (1520 bytes)
+Add promisc config
+Add SNMP
+
+####DESCRIPTIONEND####
+
+==========================================================================
+*/
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <malloc.h>
+
+#define mdelay(n) udelay((n)*1000)
+/* forward definition of function used for the uboot interface */
+void uboot_push_packet_len(int len);
+void uboot_push_tx_done(int key, int val);
+
+/* NE2000 base header file */
+#include "ne2000_base.h"
+
+#if defined(CONFIG_DRIVER_AX88796L)
+/* AX88796L support */
+#include "ax88796.h"
+#else
+/* Basic NE2000 chip support */
+#include "ne2000.h"
+#endif
+
+static dp83902a_priv_data_t nic; /* just one instance of the card supported */
+
+static bool
+dp83902a_init(void)
+{
+ dp83902a_priv_data_t *dp = &nic;
+ u8* base;
+#if defined(NE2000_BASIC_INIT)
+ int i;
+#endif
+
+ DEBUG_FUNCTION();
+
+ base = dp->base;
+ if (!base)
+ return false; /* No device found */
+
+ DEBUG_LINE();
+
+#if defined(NE2000_BASIC_INIT)
+ /* AX88796L doesn't need */
+ /* Prepare ESA */
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */
+ /* Use the address from the serial EEPROM */
+ for (i = 0; i < 6; i++)
+ DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */
+
+ printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ "eeprom",
+ dp->esa[0],
+ dp->esa[1],
+ dp->esa[2],
+ dp->esa[3],
+ dp->esa[4],
+ dp->esa[5] );
+
+#endif /* NE2000_BASIC_INIT */
+ return true;
+}
+
+static void
+dp83902a_stop(void)
+{
+ dp83902a_priv_data_t *dp = &nic;
+ u8 *base = dp->base;
+
+ DEBUG_FUNCTION();
+
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
+ DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
+ DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */
+
+ dp->running = false;
+}
+
+/*
+ * This function is called to "start up" the interface. It may be called
+ * multiple times, even when the hardware is already running. It will be
+ * called whenever something "hardware oriented" changes and should leave
+ * the hardware ready to send/receive packets.
+ */
+static void
+dp83902a_start(u8 * enaddr)
+{
+ dp83902a_priv_data_t *dp = &nic;
+ u8 *base = dp->base;
+ int i;
+
+ DEBUG_FUNCTION();
+
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
+ DP_OUT(base, DP_DCR, DP_DCR_INIT);
+ DP_OUT(base, DP_RBCH, 0); /* Remote byte count */
+ DP_OUT(base, DP_RBCL, 0);
+ DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */
+ DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */
+ DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */
+ dp->tx1 = dp->tx2 = 0;
+ dp->tx_next = dp->tx_buf1;
+ dp->tx_started = false;
+ dp->running = true;
+ DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
+ DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
+ DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */
+ dp->rx_next = dp->rx_buf_start - 1;
+ dp->running = true;
+ DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
+ DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */
+ DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */
+ dp->running = true;
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ /* FIXME */
+ /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
+ * 0x1400)) = enaddr[i];*/
+ DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
+ }
+ /* Enable and start device */
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
+ DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
+ dp->running = true;
+}
+
+/*
+ * This routine is called to start the transmitter. It is split out from the
+ * data handling routine so it may be called either when data becomes first
+ * available or when an Tx interrupt occurs
+ */
+
+static void
+dp83902a_start_xmit(int start_page, int len)
+{
+ dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
+ u8 *base = dp->base;
+
+ DEBUG_FUNCTION();
+
+#if DEBUG & 1
+ printf("Tx pkt %d len %d\n", start_page, len);
+ if (dp->tx_started)
+ printf("TX already started?!?\n");
+#endif
+
+ DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_OUT(base, DP_TBCL, len & 0xFF);
+ DP_OUT(base, DP_TBCH, len >> 8);
+ DP_OUT(base, DP_TPSR, start_page);
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
+
+ dp->tx_started = true;
+}
+
+/*
+ * This routine is called to send data to the hardware. It is known a-priori
+ * that there is free buffer space (dp->tx_next).
+ */
+static void
+dp83902a_send(u8 *data, int total_len, u32 key)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ int len, start_page, pkt_len, i, isr;
+#if DEBUG & 4
+ int dx;
+#endif
+
+ DEBUG_FUNCTION();
+
+ len = pkt_len = total_len;
+ if (pkt_len < IEEE_8023_MIN_FRAME)
+ pkt_len = IEEE_8023_MIN_FRAME;
+
+ start_page = dp->tx_next;
+ if (dp->tx_next == dp->tx_buf1) {
+ dp->tx1 = start_page;
+ dp->tx1_len = pkt_len;
+ dp->tx1_key = key;
+ dp->tx_next = dp->tx_buf2;
+ } else {
+ dp->tx2 = start_page;
+ dp->tx2_len = pkt_len;
+ dp->tx2_key = key;
+ dp->tx_next = dp->tx_buf1;
+ }
+
+#if DEBUG & 5
+ printf("TX prep page %d len %d\n", start_page, pkt_len);
+#endif
+
+ DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+ {
+ /*
+ * Dummy read. The manual sez something slightly different,
+ * but the code is extended a bit to do what Hitachi's monitor
+ * does (i.e., also read data).
+ */
+
+ u16 tmp;
+ int len = 1;
+
+ DP_OUT(base, DP_RSAL, 0x100 - len);
+ DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
+ DP_OUT(base, DP_RBCL, len);
+ DP_OUT(base, DP_RBCH, 0);
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
+ DP_IN_DATA(dp->data, tmp);
+ }
+
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
+ /*
+ * Stall for a bit before continuing to work around random data
+ * corruption problems on some platforms.
+ */
+ CYGACC_CALL_IF_DELAY_US(1);
+#endif
+
+ /* Send data to device buffer(s) */
+ DP_OUT(base, DP_RSAL, 0);
+ DP_OUT(base, DP_RSAH, start_page);
+ DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
+ DP_OUT(base, DP_RBCH, pkt_len >> 8);
+ DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
+
+ /* Put data into buffer */
+#if DEBUG & 4
+ printf(" sg buf %08lx len %08x\n ", (u32)data, len);
+ dx = 0;
+#endif
+ while (len > 0) {
+#if DEBUG & 4
+ printf(" %02x", *data);
+ if (0 == (++dx % 16)) printf("\n ");
+#endif
+
+ DP_OUT_DATA(dp->data, *data++);
+ len--;
+ }
+#if DEBUG & 4
+ printf("\n");
+#endif
+ if (total_len < pkt_len) {
+#if DEBUG & 4
+ printf(" + %d bytes of padding\n", pkt_len - total_len);
+#endif
+ /* Padding to 802.3 length was required */
+ for (i = total_len; i < pkt_len;) {
+ i++;
+ DP_OUT_DATA(dp->data, 0);
+ }
+ }
+
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
+ /*
+ * After last data write, delay for a bit before accessing the
+ * device again, or we may get random data corruption in the last
+ * datum (on some platforms).
+ */
+ CYGACC_CALL_IF_DELAY_US(1);
+#endif
+
+ /* Wait for DMA to complete */
+ do {
+ DP_IN(base, DP_ISR, isr);
+ } while ((isr & DP_ISR_RDC) == 0);
+
+ /* Then disable DMA */
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+
+ /* Start transmit if not already going */
+ if (!dp->tx_started) {
+ if (start_page == dp->tx1) {
+ dp->tx_int = 1; /* Expecting interrupt from BUF1 */
+ } else {
+ dp->tx_int = 2; /* Expecting interrupt from BUF2 */
+ }
+ dp83902a_start_xmit(start_page, pkt_len);
+ }
+}
+
+/*
+ * This function is called when a packet has been received. It's job is
+ * to prepare to unload the packet from the hardware. Once the length of
+ * the packet is known, the upper layer of the driver can be told. When
+ * the upper layer is ready to unload the packet, the internal function
+ * 'dp83902a_recv' will be called to actually fetch it from the hardware.
+ */
+static void
+dp83902a_RxEvent(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ u8 rsr;
+ u8 rcv_hdr[4];
+ int i, len, pkt, cur;
+
+ DEBUG_FUNCTION();
+
+ DP_IN(base, DP_RSR, rsr);
+ while (true) {
+ /* Read incoming packet header */
+ DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
+ DP_IN(base, DP_P1_CURP, cur);
+ DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_IN(base, DP_BNDRY, pkt);
+
+ pkt += 1;
+ if (pkt == dp->rx_buf_end)
+ pkt = dp->rx_buf_start;
+
+ if (pkt == cur) {
+ break;
+ }
+ DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
+ DP_OUT(base, DP_RBCH, 0);
+ DP_OUT(base, DP_RSAL, 0);
+ DP_OUT(base, DP_RSAH, pkt);
+ if (dp->rx_next == pkt) {
+ if (cur == dp->rx_buf_start)
+ DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
+ else
+ DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
+ return;
+ }
+ dp->rx_next = pkt;
+ DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+ DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
+ CYGACC_CALL_IF_DELAY_US(10);
+#endif
+
+ /* read header (get data size)*/
+ for (i = 0; i < sizeof(rcv_hdr);) {
+ DP_IN_DATA(dp->data, rcv_hdr[i++]);
+ }
+
+#if DEBUG & 5
+ printf("rx hdr %02x %02x %02x %02x\n",
+ rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
+#endif
+ len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
+
+ /* data read */
+ uboot_push_packet_len(len);
+
+ if (rcv_hdr[1] == dp->rx_buf_start)
+ DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
+ else
+ DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
+ }
+}
+
+/*
+ * This function is called as a result of the "eth_drv_recv()" call above.
+ * It's job is to actually fetch data for a packet from the hardware once
+ * memory buffers have been allocated for the packet. Note that the buffers
+ * may come in pieces, using a scatter-gather list. This allows for more
+ * efficient processing in the upper layers of the stack.
+ */
+static void
+dp83902a_recv(u8 *data, int len)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ int i, mlen;
+ u8 saved_char = 0;
+ bool saved;
+#if DEBUG & 4
+ int dx;
+#endif
+
+ DEBUG_FUNCTION();
+
+#if DEBUG & 5
+ printf("Rx packet %d length %d\n", dp->rx_next, len);
+#endif
+
+ /* Read incoming packet data */
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+ DP_OUT(base, DP_RBCL, len & 0xFF);
+ DP_OUT(base, DP_RBCH, len >> 8);
+ DP_OUT(base, DP_RSAL, 4); /* Past header */
+ DP_OUT(base, DP_RSAH, dp->rx_next);
+ DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
+ DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
+#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
+ CYGACC_CALL_IF_DELAY_US(10);
+#endif
+
+ saved = false;
+ for (i = 0; i < 1; i++) {
+ if (data) {
+ mlen = len;
+#if DEBUG & 4
+ printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
+ dx = 0;
+#endif
+ while (0 < mlen) {
+ /* Saved byte from previous loop? */
+ if (saved) {
+ *data++ = saved_char;
+ mlen--;
+ saved = false;
+ continue;
+ }
+
+ {
+ u8 tmp;
+ DP_IN_DATA(dp->data, tmp);
+#if DEBUG & 4
+ printf(" %02x", tmp);
+ if (0 == (++dx % 16)) printf("\n ");
+#endif
+ *data++ = tmp;;
+ mlen--;
+ }
+ }
+#if DEBUG & 4
+ printf("\n");
+#endif
+ }
+ }
+}
+
+static void
+dp83902a_TxEvent(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ u8 tsr;
+ u32 key;
+
+ DEBUG_FUNCTION();
+
+ DP_IN(base, DP_TSR, tsr);
+ if (dp->tx_int == 1) {
+ key = dp->tx1_key;
+ dp->tx1 = 0;
+ } else {
+ key = dp->tx2_key;
+ dp->tx2 = 0;
+ }
+ /* Start next packet if one is ready */
+ dp->tx_started = false;
+ if (dp->tx1) {
+ dp83902a_start_xmit(dp->tx1, dp->tx1_len);
+ dp->tx_int = 1;
+ } else if (dp->tx2) {
+ dp83902a_start_xmit(dp->tx2, dp->tx2_len);
+ dp->tx_int = 2;
+ } else {
+ dp->tx_int = 0;
+ }
+ /* Tell higher level we sent this packet */
+ uboot_push_tx_done(key, 0);
+}
+
+/*
+ * Read the tally counters to clear them. Called in response to a CNT
+ * interrupt.
+ */
+static void
+dp83902a_ClearCounters(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ u8 cnt1, cnt2, cnt3;
+
+ DP_IN(base, DP_FER, cnt1);
+ DP_IN(base, DP_CER, cnt2);
+ DP_IN(base, DP_MISSED, cnt3);
+ DP_OUT(base, DP_ISR, DP_ISR_CNT);
+}
+
+/*
+ * Deal with an overflow condition. This code follows the procedure set
+ * out in section 7.0 of the datasheet.
+ */
+static void
+dp83902a_Overflow(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
+ u8 *base = dp->base;
+ u8 isr;
+
+ /* Issue a stop command and wait 1.6ms for it to complete. */
+ DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
+ CYGACC_CALL_IF_DELAY_US(1600);
+
+ /* Clear the remote byte counter registers. */
+ DP_OUT(base, DP_RBCL, 0);
+ DP_OUT(base, DP_RBCH, 0);
+
+ /* Enter loopback mode while we clear the buffer. */
+ DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
+ DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
+
+ /*
+ * Read in as many packets as we can and acknowledge any and receive
+ * interrupts. Since the buffer has overflowed, a receive event of
+ * some kind will have occured.
+ */
+ dp83902a_RxEvent();
+ DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
+
+ /* Clear the overflow condition and leave loopback mode. */
+ DP_OUT(base, DP_ISR, DP_ISR_OFLW);
+ DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
+
+ /*
+ * If a transmit command was issued, but no transmit event has occured,
+ * restart it here.
+ */
+ DP_IN(base, DP_ISR, isr);
+ if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
+ }
+}
+
+static void
+dp83902a_poll(void)
+{
+ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
+ u8 *base = dp->base;
+ u8 isr;
+
+ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
+ DP_IN(base, DP_ISR, isr);
+ while (0 != isr) {
+ /*
+ * The CNT interrupt triggers when the MSB of one of the error
+ * counters is set. We don't much care about these counters, but
+ * we should read their values to reset them.
+ */
+ if (isr & DP_ISR_CNT) {
+ dp83902a_ClearCounters();
+ }
+ /*
+ * Check for overflow. It's a special case, since there's a
+ * particular procedure that must be followed to get back into
+ * a running state.a
+ */
+ if (isr & DP_ISR_OFLW) {
+ dp83902a_Overflow();
+ } else {
+ /*
+ * Other kinds of interrupts can be acknowledged simply by
+ * clearing the relevant bits of the ISR. Do that now, then
+ * handle the interrupts we care about.
+ */
+ DP_OUT(base, DP_ISR, isr); /* Clear set bits */
+ if (!dp->running) break; /* Is this necessary? */
+ /*
+ * Check for tx_started on TX event since these may happen
+ * spuriously it seems.
+ */
+ if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
+ dp83902a_TxEvent();
+ }
+ if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
+ dp83902a_RxEvent();
+ }
+ }
+ DP_IN(base, DP_ISR, isr);
+ }
+}
+
+
+/* U-boot specific routines */
+static u8 *pbuf = NULL;
+
+static int pkey = -1;
+static int initialized = 0;
+
+void uboot_push_packet_len(int len) {
+ PRINTK("pushed len = %d\n", len);
+ if (len >= 2000) {
+ printf("NE2000: packet too big\n");
+ return;
+ }
+ dp83902a_recv(&pbuf[0], len);
+
+ /*Just pass it to the upper layer*/
+ NetReceive(&pbuf[0], len);
+}
+
+void uboot_push_tx_done(int key, int val) {
+ PRINTK("pushed key = %d\n", key);
+ pkey = key;
+}
+
+int eth_init(bd_t *bd) {
+ int r;
+ u8 dev_addr[6];
+ char ethaddr[20];
+
+ PRINTK("### eth_init\n");
+
+ if (!pbuf) {
+ pbuf = malloc(2000);
+ if (!pbuf) {
+ printf("Cannot allocate rx buffer\n");
+ return -1;
+ }
+ }
+
+#ifdef CONFIG_DRIVER_NE2000_CCR
+ {
+ vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
+
+ PRINTK("CCR before is %x\n", *p);
+ *p = CONFIG_DRIVER_NE2000_VAL;
+ PRINTK("CCR after is %x\n", *p);
+ }
+#endif
+
+ nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
+
+ r = get_prom(dev_addr, nic.base);
+ if (!r)
+ return -1;
+
+ sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
+ dev_addr[0], dev_addr[1],
+ dev_addr[2], dev_addr[3],
+ dev_addr[4], dev_addr[5]) ;
+ PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
+ setenv ("ethaddr", ethaddr);
+
+ nic.data = nic.base + DP_DATA;
+ nic.tx_buf1 = START_PG;
+ nic.tx_buf2 = START_PG2;
+ nic.rx_buf_start = RX_START;
+ nic.rx_buf_end = RX_END;
+
+ if (dp83902a_init() == false)
+ return -1;
+
+ dp83902a_start(dev_addr);
+ initialized = 1;
+
+ return 0;
+}
+
+void eth_halt() {
+
+ PRINTK("### eth_halt\n");
+ if(initialized)
+ dp83902a_stop();
+ initialized = 0;
+}
+
+int eth_rx() {
+ dp83902a_poll();
+ return 1;
+}
+
+int eth_send(volatile void *packet, int length) {
+ int tmo;
+
+ PRINTK("### eth_send\n");
+
+ pkey = -1;
+
+ dp83902a_send((u8 *) packet, length, 666);
+ tmo = get_timer (0) + TOUT * CONFIG_SYS_HZ;
+ while(1) {
+ dp83902a_poll();
+ if (pkey != -1) {
+ PRINTK("Packet sucesfully sent\n");
+ return 0;
+ }
+ if (get_timer (0) >= tmo) {
+ printf("transmission error (timoeut)\n");
+ return 0;
+ }
+
+ }
+ return 0;
+}
diff --git a/drivers/net/ne2000_base.h b/drivers/net/ne2000_base.h
index 948b290..5446de4 100644
--- a/drivers/net/ne2000_base.h
+++ b/drivers/net/ne2000_base.h
@@ -80,10 +80,35 @@ are GPL, so this is, of course, GPL.
#define __NE2000_BASE_H__
#define bool int
-
#define false 0
#define true 1
+/*
+ * Debugging details
+ *
+ * Set to perms of:
+ * 0 disables all debug output
+ * 1 for process debug output
+ * 2 for added data IO output: get_reg, put_reg
+ * 4 for packet allocation/free output
+ * 8 for only startup status, so we can tell we're installed OK
+ */
+#if 0
+#define DEBUG 0xf
+#else
+#define DEBUG 0
+#endif
+
+#if DEBUG & 1
+#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
+#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
+#define PRINTK(args...) printf(args)
+#else
+#define DEBUG_FUNCTION() do {} while(0)
+#define DEBUG_LINE() do {} while(0)
+#define PRINTK(args...)
+#endif
+
/* timeout for tx/rx in s */
#define TOUT 5
/* Ether MAC address size */
@@ -119,11 +144,6 @@ typedef struct dp83902a_priv_data {
int rx_buf_start, rx_buf_end;
} dp83902a_priv_data_t;
-/*
- * Some forward declarations
- */
-static void dp83902a_poll(void);
-
/* ------------------------------------------------------------------------ */
/* Register offsets */
@@ -281,4 +301,8 @@ static void dp83902a_poll(void);
#define IEEE_8023_MAX_FRAME 1518 /* Largest possible ethernet frame */
#define IEEE_8023_MIN_FRAME 64 /* Smallest possible ethernet frame */
+
+/* Functions */
+int get_prom(u8* mac_addr, u8* base_addr);
+
#endif /* __NE2000_BASE_H__ */
diff --git a/drivers/net/netarm_eth.c b/drivers/net/netarm_eth.c
index c011809..c9e324e 100644
--- a/drivers/net/netarm_eth.c
+++ b/drivers/net/netarm_eth.c
@@ -56,7 +56,7 @@ static void na_mii_write (int reg, int value)
int mii_addr;
/* Select register */
- mii_addr = CFG_ETH_PHY_ADDR + reg;
+ mii_addr = CONFIG_SYS_ETH_PHY_ADDR + reg;
SET_EADDR (NETARM_ETH_MII_ADDR, mii_addr);
/* Write value */
SET_EADDR (NETARM_ETH_MII_WRITE, value);
@@ -68,7 +68,7 @@ static unsigned int na_mii_read (int reg)
int mii_addr, val;
/* Select register */
- mii_addr = CFG_ETH_PHY_ADDR + reg;
+ mii_addr = CONFIG_SYS_ETH_PHY_ADDR + reg;
SET_EADDR (NETARM_ETH_MII_ADDR, mii_addr);
/* do one management cycle */
SET_EADDR (NETARM_ETH_MII_CMD,
diff --git a/drivers/net/ns7520_eth.c b/drivers/net/ns7520_eth.c
index e19c223..c28726e 100644
--- a/drivers/net/ns7520_eth.c
+++ b/drivers/net/ns7520_eth.c
@@ -86,8 +86,8 @@ static int nDebugLvl = DEBUG_ERROR_CRIT;
# define ASSERT(expr, func)
#endif /* DEBUG */
-#define NS7520_MII_NEG_DELAY (5*CFG_HZ) /* in s */
-#define TX_TIMEOUT (5*CFG_HZ) /* in s */
+#define NS7520_MII_NEG_DELAY (5*CONFIG_SYS_HZ) /* in s */
+#define TX_TIMEOUT (5*CONFIG_SYS_HZ) /* in s */
#define RX_STALL_WORKAROUND_CNT 100
static int ns7520_eth_reset(void);
diff --git a/drivers/net/ns8382x.c b/drivers/net/ns8382x.c
index bb58438..198f73d 100644
--- a/drivers/net/ns8382x.c
+++ b/drivers/net/ns8382x.c
@@ -53,6 +53,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
@@ -444,7 +445,7 @@ ns8382x_initialize(bd_t * bis)
Read and write MII registers using software-generated serial MDIO
protocol. See the MII specifications or DP83840A data sheet for details.
- The maximum data clock rate is 2.5 Mhz. To meet minimum timing we
+ The maximum data clock rate is 2.5 MHz. To meet minimum timing we
must flush writes to the PCI bus with a PCI read. */
#define mdio_delay(mdio_addr) INL(dev, mdio_addr)
diff --git a/drivers/net/ns9750_eth.c b/drivers/net/ns9750_eth.c
index cade831..d4901b4 100644
--- a/drivers/net/ns9750_eth.c
+++ b/drivers/net/ns9750_eth.c
@@ -90,8 +90,8 @@ static int nDebugLvl = DEBUG_ERROR_CRIT;
# define ASSERT(expr, func)
#endif /* DEBUG */
-#define NS9750_MII_NEG_DELAY (5*CFG_HZ) /* in s */
-#define TX_TIMEOUT (5*CFG_HZ) /* in s */
+#define NS9750_MII_NEG_DELAY (5*CONFIG_SYS_HZ) /* in s */
+#define TX_TIMEOUT (5*CONFIG_SYS_HZ) /* in s */
/* @TODO move it to eeprom.h */
#define FS_EEPROM_AUTONEG_MASK 0x7
diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c
index a4f0214..99b6942 100644
--- a/drivers/net/pcnet.c
+++ b/drivers/net/pcnet.c
@@ -26,6 +26,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c
index 6446012..e3c163a 100644
--- a/drivers/net/phy/miiphybb.c
+++ b/drivers/net/phy/miiphybb.c
@@ -39,7 +39,7 @@ static void miiphy_pre (char read, unsigned char addr, unsigned char reg)
{
int j; /* counter */
#if !(defined(CONFIG_EP8248) || defined(CONFIG_EP82XXM))
- volatile ioport_t *iop = ioport_addr ((immap_t *) CFG_IMMR, MDIO_PORT);
+ volatile ioport_t *iop = ioport_addr ((immap_t *) CONFIG_SYS_IMMR, MDIO_PORT);
#endif
/*
@@ -124,7 +124,7 @@ int bb_miiphy_read (char *devname, unsigned char addr,
short rdreg; /* register working value */
int j; /* counter */
#if !(defined(CONFIG_EP8248) || defined(CONFIG_EP82XXM))
- volatile ioport_t *iop = ioport_addr ((immap_t *) CFG_IMMR, MDIO_PORT);
+ volatile ioport_t *iop = ioport_addr ((immap_t *) CONFIG_SYS_IMMR, MDIO_PORT);
#endif
miiphy_pre (1, addr, reg);
@@ -191,7 +191,7 @@ int bb_miiphy_write (char *devname, unsigned char addr,
{
int j; /* counter */
#if !(defined(CONFIG_EP8248) || defined(CONFIG_EP82XXM))
- volatile ioport_t *iop = ioport_addr ((immap_t *) CFG_IMMR, MDIO_PORT);
+ volatile ioport_t *iop = ioport_addr ((immap_t *) CONFIG_SYS_IMMR, MDIO_PORT);
#endif
miiphy_pre (0, addr, reg);
diff --git a/drivers/net/plb2800_eth.c b/drivers/net/plb2800_eth.c
index dad842c..d799c73 100644
--- a/drivers/net/plb2800_eth.c
+++ b/drivers/net/plb2800_eth.c
@@ -26,6 +26,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/addrspace.h>
@@ -105,7 +106,7 @@ int plb2800_eth_initialize(bd_t * bis)
if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
{
printf("Failed to allocate memory\n");
- return 0;
+ return -1;
}
memset(dev, 0, sizeof(*dev));
@@ -140,7 +141,7 @@ int plb2800_eth_initialize(bd_t * bis)
printf("Leaving plb2800_eth_initialize()\n");
#endif
- return 1;
+ return 0;
}
static int plb2800_eth_init(struct eth_device *dev, bd_t * bis)
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
index 4fd20ac..db8a727 100644
--- a/drivers/net/rtl8139.c
+++ b/drivers/net/rtl8139.c
@@ -74,6 +74,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
@@ -286,7 +287,7 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis)
/*
Delay between EEPROM clock transitions.
- No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ No extra delay is needed with 33MHz PCI, but 66MHz may change this.
*/
#define eeprom_delay() inl(ee_addr)
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index 7c00926..e9f6391 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -55,6 +55,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
index af34d7b..8d372b5 100644
--- a/drivers/net/sk98lin/h/skdrv1st.h
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -174,7 +174,7 @@ typedef struct s_AC SK_AC;
#if 0
#define SK_TICKS_PER_SEC HZ
#else
-#define SK_TICKS_PER_SEC CFG_HZ
+#define SK_TICKS_PER_SEC CONFIG_SYS_HZ
#endif
#define SK_MEM_MAPPED_IO
diff --git a/drivers/net/sk98lin/h/skgehw.h b/drivers/net/sk98lin/h/skgehw.h
index 52dc83f..8aad442 100644
--- a/drivers/net/sk98lin/h/skgehw.h
+++ b/drivers/net/sk98lin/h/skgehw.h
@@ -1107,10 +1107,10 @@ extern "C" {
/* Values of connector and PMD type comply to SysKonnect internal std */
/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */
-#define CFG_CHIP_R_MSK (0xf<<4) /* Bit 7.. 4: Chip Revision */
+#define CONFIG_SYS_CHIP_R_MSK (0xf<<4) /* Bit 7.. 4: Chip Revision */
/* Bit 3.. 2: reserved */
-#define CFG_DIS_M2_CLK BIT_1S /* Disable Clock for 2nd MAC */
-#define CFG_SNG_MAC BIT_0S /* MAC Config: 0=2 MACs / 1=1 MAC*/
+#define CONFIG_SYS_DIS_M2_CLK BIT_1S /* Disable Clock for 2nd MAC */
+#define CONFIG_SYS_SNG_MAC BIT_0S /* MAC Config: 0=2 MACs / 1=1 MAC*/
/* B2_CHIP_ID 8 bit Chip Identification Number */
#define CHIP_ID_GENESIS 0x0a /* Chip ID for GENESIS */
diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c
index ab740c7..df63f27 100644
--- a/drivers/net/sk98lin/skgeinit.c
+++ b/drivers/net/sk98lin/skgeinit.c
@@ -1882,10 +1882,10 @@ SK_IOC IoC) /* IO context */
/* read number of MACs */
SK_IN8(IoC, B2_MAC_CFG, &Byte);
- pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;
+ pAC->GIni.GIMacsFound = (Byte & CONFIG_SYS_SNG_MAC) ? 1 : 2;
/* get Chip Revision Number */
- pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);
+ pAC->GIni.GIChipRev = (SK_U8)((Byte & CONFIG_SYS_CHIP_R_MSK) >> 4);
/* get diff. PCI parameters */
SK_IN16(IoC, B0_CTST, &CtrlStat);
diff --git a/drivers/net/sk98lin/u-boot_compat.h b/drivers/net/sk98lin/u-boot_compat.h
index 1e385f8..cadf402 100644
--- a/drivers/net/sk98lin/u-boot_compat.h
+++ b/drivers/net/sk98lin/u-boot_compat.h
@@ -54,7 +54,7 @@
#define EAGAIN 2
#define EBUSY 3
-#define HZ CFG_HZ
+#define HZ CONFIG_SYS_HZ
#define printk printf
diff --git a/drivers/net/sk98lin/uboot_drv.c b/drivers/net/sk98lin/uboot_drv.c
index 205e7d2..0199b33 100644
--- a/drivers/net/sk98lin/uboot_drv.c
+++ b/drivers/net/sk98lin/uboot_drv.c
@@ -24,6 +24,7 @@
*/
#include <common.h>
+#include <netdev.h>
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
index e8b235b..82abb02 100644
--- a/drivers/net/smc91111.c
+++ b/drivers/net/smc91111.c
@@ -383,7 +383,7 @@ static void smc_write_phy_register(byte phyreg, word phydata);
static int poll4int (byte mask, int timeout)
{
- int tmo = get_timer (0) + timeout * CFG_HZ;
+ int tmo = get_timer (0) + timeout * CONFIG_SYS_HZ;
int is_timeout = 0;
word old_bank = SMC_inw (BSR_REG);
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 0fff820..648c94c 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -57,6 +57,11 @@ static inline void reg_write(u32 addr, u32 val)
#error "SMC911X: undefined bus width"
#endif /* CONFIG_DRIVER_SMC911X_16_BIT */
+u32 pkt_data_pull(u32 addr) \
+ __attribute__ ((weak, alias ("reg_read")));
+void pkt_data_push(u32 addr, u32 val) \
+ __attribute__ ((weak, alias ("reg_write")));
+
#define mdelay(n) udelay((n)*1000)
/* Below are the register offsets and bit definitions
@@ -641,7 +646,7 @@ int eth_send(volatile void *packet, int length)
tmplen = (length + 3) / 4;
while (tmplen--)
- reg_write(TX_DATA_FIFO, *data++);
+ pkt_data_push(TX_DATA_FIFO, *data++);
/* wait for transmission */
while (!((reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16));
@@ -684,7 +689,7 @@ int eth_rx(void)
tmplen = (pktlen + 2+ 3) / 4;
while (tmplen--)
- *data++ = reg_read(RX_DATA_FIFO);
+ *data++ = pkt_data_pull(RX_DATA_FIFO);
if (status & RX_STS_ES)
printf(DRIVERNAME
diff --git a/drivers/net/tigon3.c b/drivers/net/tigon3.c
index ab448b0..e4e004e 100644
--- a/drivers/net/tigon3.c
+++ b/drivers/net/tigon3.c
@@ -2247,7 +2247,7 @@ LM_STATUS LM_ResetAdapter (PLM_DEVICE_BLOCK pDevice)
REG_WR (pDevice, Grc.Mode, Value32);
/* Setup the timer prescalar register. */
- REG_WR (pDevice, Grc.MiscCfg, 65 << 1); /* Clock is alwasy 66Mhz. */
+ REG_WR (pDevice, Grc.MiscCfg, 65 << 1); /* Clock is alwasy 66MHz. */
/* Set up the MBUF pool base address and size. */
REG_WR (pDevice, BufMgr.MbufPoolAddr, pDevice->MbufBase);
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 6e0f2c6..fbc9a6d 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -16,8 +16,8 @@
#include <malloc.h>
#include <net.h>
#include <command.h>
+#include <tsec.h>
-#include "tsec.h"
#include "miiphy.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -32,69 +32,12 @@ typedef volatile struct rtxbd {
rxbd8_t rxbd[PKTBUFSRX];
} RTXBD;
-struct tsec_info_struct {
- unsigned int phyaddr;
- u32 flags;
- unsigned int phyregidx;
-};
-
-/* The tsec_info structure contains 3 values which the
- * driver uses to determine how to operate a given ethernet
- * device. The information needed is:
- * phyaddr - The address of the PHY which is attached to
- * the given device.
- *
- * flags - This variable indicates whether the device
- * supports gigabit speed ethernet, and whether it should be
- * in reduced mode.
- *
- * phyregidx - This variable specifies which ethernet device
- * controls the MII Management registers which are connected
- * to the PHY. For now, only TSEC1 (index 0) has
- * access to the PHYs, so all of the entries have "0".
- *
- * The values specified in the table are taken from the board's
- * config file in include/configs/. When implementing a new
- * board with ethernet capability, it is necessary to define:
- * TSECn_PHY_ADDR
- * TSECn_PHYIDX
- *
- * for n = 1,2,3, etc. And for FEC:
- * FEC_PHY_ADDR
- * FEC_PHYIDX
- */
-static struct tsec_info_struct tsec_info[] = {
-#ifdef CONFIG_TSEC1
- {TSEC1_PHY_ADDR, TSEC1_FLAGS, TSEC1_PHYIDX},
-#else
- {0, 0, 0},
-#endif
-#ifdef CONFIG_TSEC2
- {TSEC2_PHY_ADDR, TSEC2_FLAGS, TSEC2_PHYIDX},
-#else
- {0, 0, 0},
-#endif
-#ifdef CONFIG_MPC85XX_FEC
- {FEC_PHY_ADDR, FEC_FLAGS, FEC_PHYIDX},
-#else
-#ifdef CONFIG_TSEC3
- {TSEC3_PHY_ADDR, TSEC3_FLAGS, TSEC3_PHYIDX},
-#else
- {0, 0, 0},
-#endif
-#ifdef CONFIG_TSEC4
- {TSEC4_PHY_ADDR, TSEC4_FLAGS, TSEC4_PHYIDX},
-#else
- {0, 0, 0},
-#endif /* CONFIG_TSEC4 */
-#endif /* CONFIG_MPC85XX_FEC */
-};
-
-#define MAXCONTROLLERS (4)
+#define MAXCONTROLLERS (8)
static int relocated = 0;
static struct tsec_private *privlist[MAXCONTROLLERS];
+static int num_tsecs = 0;
#ifdef __GNUC__
static RTXBD rtx __attribute__ ((aligned(8)));
@@ -127,10 +70,51 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set);
#endif
+/* Default initializations for TSEC controllers. */
+
+static struct tsec_info_struct tsec_info[] = {
+#ifdef CONFIG_TSEC1
+ STD_TSEC_INFO(1), /* TSEC1 */
+#endif
+#ifdef CONFIG_TSEC2
+ STD_TSEC_INFO(2), /* TSEC2 */
+#endif
+#ifdef CONFIG_MPC85XX_FEC
+ {
+ .regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000),
+ .miiregs = (tsec_t *)(TSEC_BASE_ADDR),
+ .devname = CONFIG_MPC85XX_FEC_NAME,
+ .phyaddr = FEC_PHY_ADDR,
+ .flags = FEC_FLAGS
+ }, /* FEC */
+#endif
+#ifdef CONFIG_TSEC3
+ STD_TSEC_INFO(3), /* TSEC3 */
+#endif
+#ifdef CONFIG_TSEC4
+ STD_TSEC_INFO(4), /* TSEC4 */
+#endif
+};
+
+int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ tsec_initialize(bis, &tsecs[i]);
+
+ return 0;
+}
+
+int tsec_standard_init(bd_t *bis)
+{
+ return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
+}
+
/* Initialize device structure. Returns success if PHY
* initialization succeeded (i.e. if it recognizes the PHY)
*/
-int tsec_initialize(bd_t * bis, int index, char *devname)
+int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
{
struct eth_device *dev;
int i;
@@ -148,16 +132,14 @@ int tsec_initialize(bd_t * bis, int index, char *devname)
if (NULL == priv)
return 0;
- privlist[index] = priv;
- priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index * TSEC_SIZE);
- priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR +
- tsec_info[index].phyregidx *
- TSEC_SIZE);
+ privlist[num_tsecs++] = priv;
+ priv->regs = tsec_info->regs;
+ priv->phyregs = tsec_info->miiregs;
- priv->phyaddr = tsec_info[index].phyaddr;
- priv->flags = tsec_info[index].flags;
+ priv->phyaddr = tsec_info->phyaddr;
+ priv->flags = tsec_info->flags;
- sprintf(dev->name, devname);
+ sprintf(dev->name, tsec_info->devname);
dev->iobase = 0;
dev->priv = priv;
dev->init = tsec_init;
@@ -232,64 +214,84 @@ int tsec_init(struct eth_device *dev, bd_t * bd)
/* If there's no link, fail */
return (priv->link ? 0 : -1);
-
}
-/* Write value to the device's PHY through the registers
- * specified in priv, modifying the register specified in regnum.
- * It will wait for the write to be done (or for a timeout to
- * expire) before exiting
- */
-void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value)
+/* Writes the given phy's reg with value, using the specified MDIO regs */
+static void tsec_local_mdio_write(volatile tsec_t *phyregs, uint addr,
+ uint reg, uint value)
{
- volatile tsec_t *regbase = priv->phyregs;
int timeout = 1000000;
- regbase->miimadd = (phyid << 8) | regnum;
- regbase->miimcon = value;
+ phyregs->miimadd = (addr << 8) | reg;
+ phyregs->miimcon = value;
asm("sync");
timeout = 1000000;
- while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
+ while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ;
}
-/* #define to provide old write_phy_reg functionality without duplicating code */
-#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value)
+
+/* Provide the default behavior of writing the PHY of this ethernet device */
+#define write_phy_reg(priv, regnum, value) tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value)
/* Reads register regnum on the device's PHY through the
- * registers specified in priv. It lowers and raises the read
+ * specified registers. It lowers and raises the read
* command, and waits for the data to become valid (miimind
* notvalid bit cleared), and the bus to cease activity (miimind
* busy bit cleared), and then returns the value
*/
-uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum)
+uint tsec_local_mdio_read(volatile tsec_t *phyregs, uint phyid, uint regnum)
{
uint value;
- volatile tsec_t *regbase = priv->phyregs;
/* Put the address of the phy, and the register
* number into MIIMADD */
- regbase->miimadd = (phyid << 8) | regnum;
+ phyregs->miimadd = (phyid << 8) | regnum;
/* Clear the command register, and wait */
- regbase->miimcom = 0;
+ phyregs->miimcom = 0;
asm("sync");
/* Initiate a read command, and wait */
- regbase->miimcom = MIIM_READ_COMMAND;
+ phyregs->miimcom = MIIM_READ_COMMAND;
asm("sync");
/* Wait for the the indication that the read is done */
- while ((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
+ while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
/* Grab the value read from the PHY */
- value = regbase->miimstat;
+ value = phyregs->miimstat;
return value;
}
/* #define to provide old read_phy_reg functionality without duplicating code */
-#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum)
+#define read_phy_reg(priv,regnum) tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum)
+
+#define TBIANA_SETTINGS ( \
+ TBIANA_ASYMMETRIC_PAUSE \
+ | TBIANA_SYMMETRIC_PAUSE \
+ | TBIANA_FULL_DUPLEX \
+ )
+
+#define TBICR_SETTINGS ( \
+ TBICR_PHY_RESET \
+ | TBICR_ANEG_ENABLE \
+ | TBICR_FULL_DUPLEX \
+ | TBICR_SPEED1_SET \
+ )
+/* Configure the TBI for SGMII operation */
+static void tsec_configure_serdes(struct tsec_private *priv)
+{
+ /* Access TBI PHY registers at given TSEC register offset as opposed to the
+ * register offset used for external PHY accesses */
+ tsec_local_mdio_write(priv->regs, priv->regs->tbipa, TBI_ANA,
+ TBIANA_SETTINGS);
+ tsec_local_mdio_write(priv->regs, priv->regs->tbipa, TBI_TBICON,
+ TBICON_CLK_SELECT);
+ tsec_local_mdio_write(priv->regs, priv->regs->tbipa, TBI_CR,
+ TBICR_SETTINGS);
+}
/* Discover which PHY is attached to the device, and configure it
* properly. If the PHY is not recognized, then return 0
@@ -299,12 +301,12 @@ static int init_phy(struct eth_device *dev)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct phy_info *curphy;
- volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);
+ volatile tsec_t *phyregs = priv->phyregs;
+ volatile tsec_t *regs = priv->regs;
/* Assign a Physical address to the TBI */
- regs->tbipa = CFG_TBIPA_VALUE;
- regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);
- regs->tbipa = CFG_TBIPA_VALUE;
+ regs->tbipa = CONFIG_SYS_TBIPA_VALUE;
+ phyregs->tbipa = CONFIG_SYS_TBIPA_VALUE;
asm("sync");
/* Reset MII (due to new addresses) */
@@ -328,6 +330,9 @@ static int init_phy(struct eth_device *dev)
return 0;
}
+ if (regs->ecntrl & ECNTRL_SGMII_MODE)
+ tsec_configure_serdes(priv);
+
priv->phyinfo = curphy;
phy_run_commands(priv, priv->phyinfo->config);
@@ -1157,6 +1162,57 @@ struct phy_info phy_info_M88E1118 = {
},
};
+/*
+ * Since to access LED register we need do switch the page, we
+ * do LED configuring in the miim_read-like function as follows
+ */
+uint mii_88E1121_set_led (uint mii_reg, struct tsec_private *priv)
+{
+ uint pg;
+
+ /* Switch the page to access the led register */
+ pg = read_phy_reg(priv, MIIM_88E1121_PHY_PAGE);
+ write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, MIIM_88E1121_PHY_LED_PAGE);
+
+ /* Configure leds */
+ write_phy_reg(priv, MIIM_88E1121_PHY_LED_CTRL,
+ MIIM_88E1121_PHY_LED_DEF);
+
+ /* Restore the page pointer */
+ write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, pg);
+ return 0;
+}
+
+struct phy_info phy_info_M88E1121R = {
+ 0x01410cb,
+ "Marvell 88E1121R",
+ 4,
+ (struct phy_cmd[]){ /* config */
+ /* Reset and configure the PHY */
+ {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+ {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+ {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+ /* Configure leds */
+ {MIIM_88E1121_PHY_LED_CTRL, miim_read,
+ &mii_88E1121_set_led},
+ {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+ /* Disable IRQs and de-assert interrupt */
+ {MIIM_88E1121_PHY_IRQ_EN, 0, NULL},
+ {MIIM_88E1121_PHY_IRQ_STATUS, miim_read, NULL},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* startup */
+ /* Status is read once to clear old link state */
+ {MIIM_STATUS, miim_read, NULL},
+ {MIIM_STATUS, miim_read, &mii_parse_sr},
+ {MIIM_STATUS, miim_read, &mii_parse_link},
+ {miim_end,}
+ },
+ (struct phy_cmd[]){ /* shutdown */
+ {miim_end,}
+ },
+};
+
static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv)
{
uint mii_data = read_phy_reg(priv, mii_reg);
@@ -1304,15 +1360,17 @@ struct phy_info phy_info_VSC8601 = {
/* Override PHY config settings */
/* Configure some basic stuff */
{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
-#ifdef CFG_VSC8601_SKEWFIX
+#ifdef CONFIG_SYS_VSC8601_SKEWFIX
{MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL},
-#if defined(CFG_VSC8601_SKEW_TX) && defined(CFG_VSC8601_SKEW_RX)
+#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX)
{MIIM_EXT_PAGE_ACCESS,1,NULL},
-#define VSC8101_SKEW (CFG_VSC8601_SKEW_TX<<14)|(CFG_VSC8601_SKEW_RX<<12)
+#define VSC8101_SKEW (CONFIG_SYS_VSC8601_SKEW_TX<<14)|(CONFIG_SYS_VSC8601_SKEW_RX<<12)
{MIIM_VSC8601_SKEW_CTRL,VSC8101_SKEW,NULL},
{MIIM_EXT_PAGE_ACCESS,0,NULL},
#endif
#endif
+ {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+ {MIIM_CONTROL, MIIM_CONTROL_RESTART, &mii_cr_init},
{miim_end,}
},
(struct phy_cmd[]){ /* startup */
@@ -1522,6 +1580,7 @@ struct phy_info *phy_info[] = {
&phy_info_M88E1011S,
&phy_info_M88E1111S,
&phy_info_M88E1118,
+ &phy_info_M88E1121R,
&phy_info_M88E1145,
&phy_info_M88E1149S,
&phy_info_dm9161,
@@ -1670,7 +1729,7 @@ static int tsec_miiphy_read(char *devname, unsigned char addr,
return -1;
}
- ret = (unsigned short)read_any_phy_reg(priv, addr, reg);
+ ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg);
*value = ret;
return 0;
@@ -1692,7 +1751,7 @@ static int tsec_miiphy_write(char *devname, unsigned char addr,
return -1;
}
- write_any_phy_reg(priv, addr, reg, value);
+ tsec_local_mdio_write(priv->phyregs, addr, reg, value);
return 0;
}
diff --git a/drivers/net/tsec.h b/drivers/net/tsec.h
deleted file mode 100644
index 6a2338b..0000000
--- a/drivers/net/tsec.h
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * tsec.h
- *
- * Driver for the Motorola Triple Speed Ethernet Controller
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * Copyright 2004, 2007 Freescale Semiconductor, Inc.
- * (C) Copyright 2003, Motorola, Inc.
- * maintained by Xianghua Xiao (x.xiao@motorola.com)
- * author Andy Fleming
- *
- */
-
-#ifndef __TSEC_H
-#define __TSEC_H
-
-#include <net.h>
-#include <config.h>
-
-#ifndef CFG_TSEC1_OFFSET
- #define CFG_TSEC1_OFFSET (0x24000)
-#endif
-
-#define TSEC_SIZE 0x01000
-
-/* FIXME: Should these be pushed back to 83xx and 85xx config files? */
-#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
- #define TSEC_BASE_ADDR (CFG_IMMR + CFG_TSEC1_OFFSET)
-#elif defined(CONFIG_MPC83XX)
- #define TSEC_BASE_ADDR (CFG_IMMR + CFG_TSEC1_OFFSET)
-#endif
-
-
-#define MAC_ADDR_LEN 6
-
-/* #define TSEC_TIMEOUT 1000000 */
-#define TSEC_TIMEOUT 1000
-#define TOUT_LOOP 1000000
-
-#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* in ms */
-
-/* MAC register bits */
-#define MACCFG1_SOFT_RESET 0x80000000
-#define MACCFG1_RESET_RX_MC 0x00080000
-#define MACCFG1_RESET_TX_MC 0x00040000
-#define MACCFG1_RESET_RX_FUN 0x00020000
-#define MACCFG1_RESET_TX_FUN 0x00010000
-#define MACCFG1_LOOPBACK 0x00000100
-#define MACCFG1_RX_FLOW 0x00000020
-#define MACCFG1_TX_FLOW 0x00000010
-#define MACCFG1_SYNCD_RX_EN 0x00000008
-#define MACCFG1_RX_EN 0x00000004
-#define MACCFG1_SYNCD_TX_EN 0x00000002
-#define MACCFG1_TX_EN 0x00000001
-
-#define MACCFG2_INIT_SETTINGS 0x00007205
-#define MACCFG2_FULL_DUPLEX 0x00000001
-#define MACCFG2_IF 0x00000300
-#define MACCFG2_GMII 0x00000200
-#define MACCFG2_MII 0x00000100
-
-#define ECNTRL_INIT_SETTINGS 0x00001000
-#define ECNTRL_TBI_MODE 0x00000020
-#define ECNTRL_R100 0x00000008
-#define ECNTRL_SGMII_MODE 0x00000002
-
-#define miim_end -2
-#define miim_read -1
-
-#ifndef CFG_TBIPA_VALUE
- #define CFG_TBIPA_VALUE 0x1f
-#endif
-#define MIIMCFG_INIT_VALUE 0x00000003
-#define MIIMCFG_RESET 0x80000000
-
-#define MIIMIND_BUSY 0x00000001
-#define MIIMIND_NOTVALID 0x00000004
-
-#define MIIM_CONTROL 0x00
-#define MIIM_CONTROL_RESET 0x00009140
-#define MIIM_CONTROL_INIT 0x00001140
-#define MIIM_CONTROL_RESTART 0x00001340
-#define MIIM_ANEN 0x00001000
-
-#define MIIM_CR 0x00
-#define MIIM_CR_RST 0x00008000
-#define MIIM_CR_INIT 0x00001000
-
-#define MIIM_STATUS 0x1
-#define MIIM_STATUS_AN_DONE 0x00000020
-#define MIIM_STATUS_LINK 0x0004
-#define PHY_BMSR_AUTN_ABLE 0x0008
-#define PHY_BMSR_AUTN_COMP 0x0020
-
-#define MIIM_PHYIR1 0x2
-#define MIIM_PHYIR2 0x3
-
-#define MIIM_ANAR 0x4
-#define MIIM_ANAR_INIT 0x1e1
-
-#define MIIM_TBI_ANLPBPA 0x5
-#define MIIM_TBI_ANLPBPA_HALF 0x00000040
-#define MIIM_TBI_ANLPBPA_FULL 0x00000020
-
-#define MIIM_TBI_ANEX 0x6
-#define MIIM_TBI_ANEX_NP 0x00000004
-#define MIIM_TBI_ANEX_PRX 0x00000002
-
-#define MIIM_GBIT_CONTROL 0x9
-#define MIIM_GBIT_CONTROL_INIT 0xe00
-
-#define MIIM_EXT_PAGE_ACCESS 0x1f
-
-/* Broadcom BCM54xx -- taken from linux sungem_phy */
-#define MIIM_BCM54xx_AUXSTATUS 0x19
-#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700
-#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8
-
-/* Cicada Auxiliary Control/Status Register */
-#define MIIM_CIS8201_AUX_CONSTAT 0x1c
-#define MIIM_CIS8201_AUXCONSTAT_INIT 0x0004
-#define MIIM_CIS8201_AUXCONSTAT_DUPLEX 0x0020
-#define MIIM_CIS8201_AUXCONSTAT_SPEED 0x0018
-#define MIIM_CIS8201_AUXCONSTAT_GBIT 0x0010
-#define MIIM_CIS8201_AUXCONSTAT_100 0x0008
-
-/* Cicada Extended Control Register 1 */
-#define MIIM_CIS8201_EXT_CON1 0x17
-#define MIIM_CIS8201_EXTCON1_INIT 0x0000
-
-/* Cicada 8204 Extended PHY Control Register 1 */
-#define MIIM_CIS8204_EPHY_CON 0x17
-#define MIIM_CIS8204_EPHYCON_INIT 0x0006
-#define MIIM_CIS8204_EPHYCON_RGMII 0x1100
-
-/* Cicada 8204 Serial LED Control Register */
-#define MIIM_CIS8204_SLED_CON 0x1b
-#define MIIM_CIS8204_SLEDCON_INIT 0x1115
-
-#define MIIM_GBIT_CON 0x09
-#define MIIM_GBIT_CON_ADVERT 0x0e00
-
-/* Entry for Vitesse VSC8244 regs starts here */
-/* Vitesse VSC8244 Auxiliary Control/Status Register */
-#define MIIM_VSC8244_AUX_CONSTAT 0x1c
-#define MIIM_VSC8244_AUXCONSTAT_INIT 0x0000
-#define MIIM_VSC8244_AUXCONSTAT_DUPLEX 0x0020
-#define MIIM_VSC8244_AUXCONSTAT_SPEED 0x0018
-#define MIIM_VSC8244_AUXCONSTAT_GBIT 0x0010
-#define MIIM_VSC8244_AUXCONSTAT_100 0x0008
-#define MIIM_CONTROL_INIT_LOOPBACK 0x4000
-
-/* Vitesse VSC8244 Extended PHY Control Register 1 */
-#define MIIM_VSC8244_EPHY_CON 0x17
-#define MIIM_VSC8244_EPHYCON_INIT 0x0006
-
-/* Vitesse VSC8244 Serial LED Control Register */
-#define MIIM_VSC8244_LED_CON 0x1b
-#define MIIM_VSC8244_LEDCON_INIT 0xF011
-
-/* Entry for Vitesse VSC8601 regs starts here (Not complete) */
-/* Vitesse VSC8601 Extended PHY Control Register 1 */
-#define MIIM_VSC8601_EPHY_CON 0x17
-#define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120
-#define MIIM_VSC8601_SKEW_CTRL 0x1c
-
-/* 88E1011 PHY Status Register */
-#define MIIM_88E1011_PHY_STATUS 0x11
-#define MIIM_88E1011_PHYSTAT_SPEED 0xc000
-#define MIIM_88E1011_PHYSTAT_GBIT 0x8000
-#define MIIM_88E1011_PHYSTAT_100 0x4000
-#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000
-#define MIIM_88E1011_PHYSTAT_SPDDONE 0x0800
-#define MIIM_88E1011_PHYSTAT_LINK 0x0400
-
-#define MIIM_88E1011_PHY_SCR 0x10
-#define MIIM_88E1011_PHY_MDI_X_AUTO 0x0060
-
-/* 88E1111 PHY LED Control Register */
-#define MIIM_88E1111_PHY_LED_CONTROL 24
-#define MIIM_88E1111_PHY_LED_DIRECT 0x4100
-#define MIIM_88E1111_PHY_LED_COMBINE 0x411C
-
-/* 88E1145 Extended PHY Specific Control Register */
-#define MIIM_88E1145_PHY_EXT_CR 20
-#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080
-#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002
-
-#define MIIM_88E1145_PHY_PAGE 29
-#define MIIM_88E1145_PHY_CAL_OV 30
-
-/* RTL8211B PHY Status Register */
-#define MIIM_RTL8211B_PHY_STATUS 0x11
-#define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000
-#define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000
-#define MIIM_RTL8211B_PHYSTAT_100 0x4000
-#define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000
-#define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800
-#define MIIM_RTL8211B_PHYSTAT_LINK 0x0400
-
-/* DM9161 Control register values */
-#define MIIM_DM9161_CR_STOP 0x0400
-#define MIIM_DM9161_CR_RSTAN 0x1200
-
-#define MIIM_DM9161_SCR 0x10
-#define MIIM_DM9161_SCR_INIT 0x0610
-
-/* DM9161 Specified Configuration and Status Register */
-#define MIIM_DM9161_SCSR 0x11
-#define MIIM_DM9161_SCSR_100F 0x8000
-#define MIIM_DM9161_SCSR_100H 0x4000
-#define MIIM_DM9161_SCSR_10F 0x2000
-#define MIIM_DM9161_SCSR_10H 0x1000
-
-/* DM9161 10BT Configuration/Status */
-#define MIIM_DM9161_10BTCSR 0x12
-#define MIIM_DM9161_10BTCSR_INIT 0x7800
-
-/* LXT971 Status 2 registers */
-#define MIIM_LXT971_SR2 0x11 /* Status Register 2 */
-#define MIIM_LXT971_SR2_SPEED_MASK 0x4200
-#define MIIM_LXT971_SR2_10HDX 0x0000 /* 10 Mbit half duplex selected */
-#define MIIM_LXT971_SR2_10FDX 0x0200 /* 10 Mbit full duplex selected */
-#define MIIM_LXT971_SR2_100HDX 0x4000 /* 100 Mbit half duplex selected */
-#define MIIM_LXT971_SR2_100FDX 0x4200 /* 100 Mbit full duplex selected */
-
-/* DP83865 Control register values */
-#define MIIM_DP83865_CR_INIT 0x9200
-
-/* DP83865 Link and Auto-Neg Status Register */
-#define MIIM_DP83865_LANR 0x11
-#define MIIM_DP83865_SPD_MASK 0x0018
-#define MIIM_DP83865_SPD_1000 0x0010
-#define MIIM_DP83865_SPD_100 0x0008
-#define MIIM_DP83865_DPX_FULL 0x0002
-
-#define MIIM_READ_COMMAND 0x00000001
-
-#define MRBLR_INIT_SETTINGS PKTSIZE_ALIGN
-
-#define MINFLR_INIT_SETTINGS 0x00000040
-
-#define DMACTRL_INIT_SETTINGS 0x000000c3
-#define DMACTRL_GRS 0x00000010
-#define DMACTRL_GTS 0x00000008
-
-#define TSTAT_CLEAR_THALT 0x80000000
-#define RSTAT_CLEAR_RHALT 0x00800000
-
-
-#define IEVENT_INIT_CLEAR 0xffffffff
-#define IEVENT_BABR 0x80000000
-#define IEVENT_RXC 0x40000000
-#define IEVENT_BSY 0x20000000
-#define IEVENT_EBERR 0x10000000
-#define IEVENT_MSRO 0x04000000
-#define IEVENT_GTSC 0x02000000
-#define IEVENT_BABT 0x01000000
-#define IEVENT_TXC 0x00800000
-#define IEVENT_TXE 0x00400000
-#define IEVENT_TXB 0x00200000
-#define IEVENT_TXF 0x00100000
-#define IEVENT_IE 0x00080000
-#define IEVENT_LC 0x00040000
-#define IEVENT_CRL 0x00020000
-#define IEVENT_XFUN 0x00010000
-#define IEVENT_RXB0 0x00008000
-#define IEVENT_GRSC 0x00000100
-#define IEVENT_RXF0 0x00000080
-
-#define IMASK_INIT_CLEAR 0x00000000
-#define IMASK_TXEEN 0x00400000
-#define IMASK_TXBEN 0x00200000
-#define IMASK_TXFEN 0x00100000
-#define IMASK_RXFEN0 0x00000080
-
-
-/* Default Attribute fields */
-#define ATTR_INIT_SETTINGS 0x000000c0
-#define ATTRELI_INIT_SETTINGS 0x00000000
-
-
-/* TxBD status field bits */
-#define TXBD_READY 0x8000
-#define TXBD_PADCRC 0x4000
-#define TXBD_WRAP 0x2000
-#define TXBD_INTERRUPT 0x1000
-#define TXBD_LAST 0x0800
-#define TXBD_CRC 0x0400
-#define TXBD_DEF 0x0200
-#define TXBD_HUGEFRAME 0x0080
-#define TXBD_LATECOLLISION 0x0080
-#define TXBD_RETRYLIMIT 0x0040
-#define TXBD_RETRYCOUNTMASK 0x003c
-#define TXBD_UNDERRUN 0x0002
-#define TXBD_STATS 0x03ff
-
-/* RxBD status field bits */
-#define RXBD_EMPTY 0x8000
-#define RXBD_RO1 0x4000
-#define RXBD_WRAP 0x2000
-#define RXBD_INTERRUPT 0x1000
-#define RXBD_LAST 0x0800
-#define RXBD_FIRST 0x0400
-#define RXBD_MISS 0x0100
-#define RXBD_BROADCAST 0x0080
-#define RXBD_MULTICAST 0x0040
-#define RXBD_LARGE 0x0020
-#define RXBD_NONOCTET 0x0010
-#define RXBD_SHORT 0x0008
-#define RXBD_CRCERR 0x0004
-#define RXBD_OVERRUN 0x0002
-#define RXBD_TRUNCATED 0x0001
-#define RXBD_STATS 0x003f
-
-typedef struct txbd8
-{
- ushort status; /* Status Fields */
- ushort length; /* Buffer length */
- uint bufPtr; /* Buffer Pointer */
-} txbd8_t;
-
-typedef struct rxbd8
-{
- ushort status; /* Status Fields */
- ushort length; /* Buffer Length */
- uint bufPtr; /* Buffer Pointer */
-} rxbd8_t;
-
-typedef struct rmon_mib
-{
- /* Transmit and Receive Counters */
- uint tr64; /* Transmit and Receive 64-byte Frame Counter */
- uint tr127; /* Transmit and Receive 65-127 byte Frame Counter */
- uint tr255; /* Transmit and Receive 128-255 byte Frame Counter */
- uint tr511; /* Transmit and Receive 256-511 byte Frame Counter */
- uint tr1k; /* Transmit and Receive 512-1023 byte Frame Counter */
- uint trmax; /* Transmit and Receive 1024-1518 byte Frame Counter */
- uint trmgv; /* Transmit and Receive 1519-1522 byte Good VLAN Frame */
- /* Receive Counters */
- uint rbyt; /* Receive Byte Counter */
- uint rpkt; /* Receive Packet Counter */
- uint rfcs; /* Receive FCS Error Counter */
- uint rmca; /* Receive Multicast Packet (Counter) */
- uint rbca; /* Receive Broadcast Packet */
- uint rxcf; /* Receive Control Frame Packet */
- uint rxpf; /* Receive Pause Frame Packet */
- uint rxuo; /* Receive Unknown OP Code */
- uint raln; /* Receive Alignment Error */
- uint rflr; /* Receive Frame Length Error */
- uint rcde; /* Receive Code Error */
- uint rcse; /* Receive Carrier Sense Error */
- uint rund; /* Receive Undersize Packet */
- uint rovr; /* Receive Oversize Packet */
- uint rfrg; /* Receive Fragments */
- uint rjbr; /* Receive Jabber */
- uint rdrp; /* Receive Drop */
- /* Transmit Counters */
- uint tbyt; /* Transmit Byte Counter */
- uint tpkt; /* Transmit Packet */
- uint tmca; /* Transmit Multicast Packet */
- uint tbca; /* Transmit Broadcast Packet */
- uint txpf; /* Transmit Pause Control Frame */
- uint tdfr; /* Transmit Deferral Packet */
- uint tedf; /* Transmit Excessive Deferral Packet */
- uint tscl; /* Transmit Single Collision Packet */
- /* (0x2_n700) */
- uint tmcl; /* Transmit Multiple Collision Packet */
- uint tlcl; /* Transmit Late Collision Packet */
- uint txcl; /* Transmit Excessive Collision Packet */
- uint tncl; /* Transmit Total Collision */
-
- uint res2;
-
- uint tdrp; /* Transmit Drop Frame */
- uint tjbr; /* Transmit Jabber Frame */
- uint tfcs; /* Transmit FCS Error */
- uint txcf; /* Transmit Control Frame */
- uint tovr; /* Transmit Oversize Frame */
- uint tund; /* Transmit Undersize Frame */
- uint tfrg; /* Transmit Fragments Frame */
- /* General Registers */
- uint car1; /* Carry Register One */
- uint car2; /* Carry Register Two */
- uint cam1; /* Carry Register One Mask */
- uint cam2; /* Carry Register Two Mask */
-} rmon_mib_t;
-
-typedef struct tsec_hash_regs
-{
- uint iaddr0; /* Individual Address Register 0 */
- uint iaddr1; /* Individual Address Register 1 */
- uint iaddr2; /* Individual Address Register 2 */
- uint iaddr3; /* Individual Address Register 3 */
- uint iaddr4; /* Individual Address Register 4 */
- uint iaddr5; /* Individual Address Register 5 */
- uint iaddr6; /* Individual Address Register 6 */
- uint iaddr7; /* Individual Address Register 7 */
- uint res1[24];
- uint gaddr0; /* Group Address Register 0 */
- uint gaddr1; /* Group Address Register 1 */
- uint gaddr2; /* Group Address Register 2 */
- uint gaddr3; /* Group Address Register 3 */
- uint gaddr4; /* Group Address Register 4 */
- uint gaddr5; /* Group Address Register 5 */
- uint gaddr6; /* Group Address Register 6 */
- uint gaddr7; /* Group Address Register 7 */
- uint res2[24];
-} tsec_hash_t;
-
-typedef struct tsec
-{
- /* General Control and Status Registers (0x2_n000) */
- uint res000[4];
-
- uint ievent; /* Interrupt Event */
- uint imask; /* Interrupt Mask */
- uint edis; /* Error Disabled */
- uint res01c;
- uint ecntrl; /* Ethernet Control */
- uint minflr; /* Minimum Frame Length */
- uint ptv; /* Pause Time Value */
- uint dmactrl; /* DMA Control */
- uint tbipa; /* TBI PHY Address */
-
- uint res034[3];
- uint res040[48];
-
- /* Transmit Control and Status Registers (0x2_n100) */
- uint tctrl; /* Transmit Control */
- uint tstat; /* Transmit Status */
- uint res108;
- uint tbdlen; /* Tx BD Data Length */
- uint res110[5];
- uint ctbptr; /* Current TxBD Pointer */
- uint res128[23];
- uint tbptr; /* TxBD Pointer */
- uint res188[30];
- /* (0x2_n200) */
- uint res200;
- uint tbase; /* TxBD Base Address */
- uint res208[42];
- uint ostbd; /* Out of Sequence TxBD */
- uint ostbdp; /* Out of Sequence Tx Data Buffer Pointer */
- uint res2b8[18];
-
- /* Receive Control and Status Registers (0x2_n300) */
- uint rctrl; /* Receive Control */
- uint rstat; /* Receive Status */
- uint res308;
- uint rbdlen; /* RxBD Data Length */
- uint res310[4];
- uint res320;
- uint crbptr; /* Current Receive Buffer Pointer */
- uint res328[6];
- uint mrblr; /* Maximum Receive Buffer Length */
- uint res344[16];
- uint rbptr; /* RxBD Pointer */
- uint res388[30];
- /* (0x2_n400) */
- uint res400;
- uint rbase; /* RxBD Base Address */
- uint res408[62];
-
- /* MAC Registers (0x2_n500) */
- uint maccfg1; /* MAC Configuration #1 */
- uint maccfg2; /* MAC Configuration #2 */
- uint ipgifg; /* Inter Packet Gap/Inter Frame Gap */
- uint hafdup; /* Half-duplex */
- uint maxfrm; /* Maximum Frame */
- uint res514;
- uint res518;
-
- uint res51c;
-
- uint miimcfg; /* MII Management: Configuration */
- uint miimcom; /* MII Management: Command */
- uint miimadd; /* MII Management: Address */
- uint miimcon; /* MII Management: Control */
- uint miimstat; /* MII Management: Status */
- uint miimind; /* MII Management: Indicators */
-
- uint res538;
-
- uint ifstat; /* Interface Status */
- uint macstnaddr1; /* Station Address, part 1 */
- uint macstnaddr2; /* Station Address, part 2 */
- uint res548[46];
-
- /* (0x2_n600) */
- uint res600[32];
-
- /* RMON MIB Registers (0x2_n680-0x2_n73c) */
- rmon_mib_t rmon;
- uint res740[48];
-
- /* Hash Function Registers (0x2_n800) */
- tsec_hash_t hash;
-
- uint res900[128];
-
- /* Pattern Registers (0x2_nb00) */
- uint resb00[62];
- uint attr; /* Default Attribute Register */
- uint attreli; /* Default Attribute Extract Length and Index */
-
- /* TSEC Future Expansion Space (0x2_nc00-0x2_nffc) */
- uint resc00[256];
-} tsec_t;
-
-#define TSEC_GIGABIT (1)
-
-/* This flag currently only has
- * meaning if we're using the eTSEC */
-#define TSEC_REDUCED (1 << 1)
-
-struct tsec_private {
- volatile tsec_t *regs;
- volatile tsec_t *phyregs;
- struct phy_info *phyinfo;
- uint phyaddr;
- u32 flags;
- uint link;
- uint duplexity;
- uint speed;
-};
-
-
-/*
- * struct phy_cmd: A command for reading or writing a PHY register
- *
- * mii_reg: The register to read or write
- *
- * mii_data: For writes, the value to put in the register.
- * A value of -1 indicates this is a read.
- *
- * funct: A function pointer which is invoked for each command.
- * For reads, this function will be passed the value read
- * from the PHY, and process it.
- * For writes, the result of this function will be written
- * to the PHY register
- */
-struct phy_cmd {
- uint mii_reg;
- uint mii_data;
- uint (*funct) (uint mii_reg, struct tsec_private * priv);
-};
-
-/* struct phy_info: a structure which defines attributes for a PHY
- *
- * id will contain a number which represents the PHY. During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is. The 32-bit result
- * gotten from the PHY will be shifted right by "shift" bits to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * The struct phy_cmd entries represent pointers to an arrays of
- * commands which tell the driver what to do to the PHY.
- */
-struct phy_info {
- uint id;
- char *name;
- uint shift;
- /* Called to configure the PHY, and modify the controller
- * based on the results */
- struct phy_cmd *config;
-
- /* Called when starting up the controller */
- struct phy_cmd *startup;
-
- /* Called when bringing down the controller */
- struct phy_cmd *shutdown;
-};
-
-#endif /* __TSEC_H */
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 2534097..079354a 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -34,6 +34,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/cache.h>
#ifdef DEBUG
@@ -53,7 +54,7 @@ printf ("%s %d: " fmt, __FUNCTION__, __LINE__, ##args)
#define RX_PRINT_ERRORS
#define TX_PRINT_ERRORS
-#define ETH_BASE (CFG_TSI108_CSR_BASE + 0x6000)
+#define ETH_BASE (CONFIG_SYS_TSI108_CSR_BASE + 0x6000)
#define ETH_PORT_OFFSET 0x400
diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c
index d87638c..9ea5ac2 100644
--- a/drivers/net/uli526x.c
+++ b/drivers/net/uli526x.c
@@ -16,6 +16,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
+#include <netdev.h>
#include <asm/io.h>
#include <pci.h>
#include <miiphy.h>
diff --git a/drivers/net/vsc7385.c b/drivers/net/vsc7385.c
index 4e7259f..ada42c4 100644
--- a/drivers/net/vsc7385.c
+++ b/drivers/net/vsc7385.c
@@ -35,13 +35,13 @@ int vsc7385_upload_firmware(void *firmware, unsigned int size)
u8 *fw = firmware;
unsigned int i;
- u32 *gloreset = (u32 *) (CFG_VSC7385_BASE + 0x1c050);
- u32 *icpu_ctrl = (u32 *) (CFG_VSC7385_BASE + 0x1c040);
- u32 *icpu_addr = (u32 *) (CFG_VSC7385_BASE + 0x1c044);
- u32 *icpu_data = (u32 *) (CFG_VSC7385_BASE + 0x1c048);
- u32 *icpu_rom_map = (u32 *) (CFG_VSC7385_BASE + 0x1c070);
+ u32 *gloreset = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c050);
+ u32 *icpu_ctrl = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c040);
+ u32 *icpu_addr = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c044);
+ u32 *icpu_data = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c048);
+ u32 *icpu_rom_map = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c070);
#ifdef DEBUG
- u32 *chipid = (u32 *) (CFG_VSC7385_BASE + 0x1c060);
+ u32 *chipid = (u32 *) (CONFIG_SYS_VSC7385_BASE + 0x1c060);
#endif
out_be32(gloreset, 3);
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 9ba4096..0e96ef1 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -70,10 +70,10 @@ typedef struct {
static xemaclite emaclite;
-static char etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
+static u32 etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
/* hardcoded MAC address for the Xilinx EMAC Core when env is nowhere*/
-#ifdef CFG_ENV_IS_NOWHERE
+#ifdef CONFIG_ENV_IS_NOWHERE
static u8 emacaddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 };
#else
static u8 emacaddr[ENET_ADDR_LENGTH];
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index bb2813f..1db42fd 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -18,6 +18,8 @@
#include <common.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/*
* PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's
*
@@ -39,10 +41,94 @@ void pciauto_prescan_setup_bridge(struct pci_controller *hose,
pci_dev_t dev, int sub_bus);
void pciauto_postscan_setup_bridge(struct pci_controller *hose,
pci_dev_t dev, int sub_bus);
-
void pciauto_config_init(struct pci_controller *hose);
-void
-fsl_pci_init(struct pci_controller *hose)
+
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS
+#define CONFIG_SYS_PCI_MEMORY_BUS 0
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
+#define CONFIG_SYS_PCI_MEMORY_PHYS 0
+#endif
+
+#if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
+#define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024)
+#endif
+
+int fsl_pci_setup_inbound_windows(struct pci_region *r)
+{
+ struct pci_region *rgn_base = r;
+ u64 sz = min((u64)gd->ram_size, (1ull << 32) - 1);
+
+ phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
+ pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
+ pci_size_t pci_sz = 1ull << __ilog2_u64(sz);
+
+ debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r++, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_MEMORY |
+ PCI_REGION_PREFETCH);
+
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R1 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r++, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_MEMORY |
+ PCI_REGION_PREFETCH);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ }
+
+#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
+ /*
+ * On 64-bit capable systems, set up a mapping for all of DRAM
+ * in high pci address space.
+ */
+ pci_sz = 1ull << __ilog2_u64(gd->ram_size);
+ /* round up to the next largest power of two */
+ if (gd->ram_size > pci_sz)
+ pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
+ debug ("R64 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
+ (u64)CONFIG_SYS_PCI_MEMORY_PHYS,
+ (u64)pci_sz);
+ pci_set_region(r++,
+ CONFIG_SYS_PCI64_MEMORY_BUS,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ pci_sz,
+ PCI_REGION_MEM | PCI_REGION_MEMORY |
+ PCI_REGION_PREFETCH);
+#else
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R2 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r++, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_MEMORY |
+ PCI_REGION_PREFETCH);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ }
+#endif
+
+#ifdef CONFIG_PHYS_64BIT
+ if (sz && (((u64)gd->ram_size) < (1ull << 32)))
+ printf("Was not able to map all of memory via "
+ "inbound windows -- %lld remaining\n", sz);
+#endif
+
+ return r - rgn_base;
+}
+
+void fsl_pci_init(struct pci_controller *hose)
{
u16 temp16;
u32 temp32;
@@ -65,25 +151,36 @@ fsl_pci_init(struct pci_controller *hose)
#endif
for (r=0; r<hose->region_count; r++) {
+ u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1);
if (hose->regions[r].flags & PCI_REGION_MEMORY) { /* inbound */
- pi->pitar = (hose->regions[r].bus_start >> 12) & 0x000fffff;
- pi->piwbar = (hose->regions[r].phys_start >> 12) & 0x000fffff;
+ u32 flag = PIWAR_EN | PIWAR_LOCAL |
+ PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+ pi->pitar = (hose->regions[r].phys_start >> 12);
+ pi->piwbar = (hose->regions[r].bus_start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ pi->piwbear = (hose->regions[r].bus_start >> 44);
+#else
pi->piwbear = 0;
- pi->piwar = PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
- PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP |
- (__ilog2(hose->regions[r].size) - 1);
+#endif
+ if (hose->regions[r].flags & PCI_REGION_PREFETCH)
+ flag |= PIWAR_PF;
+ pi->piwar = flag | sz;
pi++;
inbound = hose->regions[r].size > 0;
} else { /* Outbound */
- po->powbar = (hose->regions[r].phys_start >> 12) & 0x000fffff;
- po->potar = (hose->regions[r].bus_start >> 12) & 0x000fffff;
+ po->powbar = (hose->regions[r].phys_start >> 12);
+ po->potar = (hose->regions[r].bus_start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ po->potear = (hose->regions[r].bus_start >> 44);
+#else
po->potear = 0;
+#endif
if (hose->regions[r].flags & PCI_REGION_IO)
- po->powar = POWAR_EN | POWAR_IO_READ | POWAR_IO_WRITE |
- (__ilog2(hose->regions[r].size) - 1);
+ po->powar = POWAR_EN | sz |
+ POWAR_IO_READ | POWAR_IO_WRITE;
else
- po->powar = POWAR_EN | POWAR_MEM_READ | POWAR_MEM_WRITE |
- (__ilog2(hose->regions[r].size) - 1);
+ po->powar = POWAR_EN | sz |
+ POWAR_MEM_READ | POWAR_MEM_WRITE;
po++;
}
}
@@ -168,8 +265,21 @@ fsl_pci_init(struct pci_controller *hose)
}
#ifndef CONFIG_PCI_NOSCAN
- printf (" Scanning PCI bus %02x\n", hose->current_busno);
- hose->last_busno = pci_hose_scan_bus(hose,hose->current_busno);
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &temp8);
+
+ /* Programming Interface (PCI_CLASS_PROG)
+ * 0 == pci host or pcie root-complex,
+ * 1 == pci agent or pcie end-point
+ */
+ if (!temp8) {
+ printf(" Scanning PCI bus %02x\n",
+ hose->current_busno);
+ hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno);
+ } else {
+ debug(" Not scanning PCI bus %02x. PI=%x\n",
+ hose->current_busno, temp8);
+ hose->last_busno = hose->current_busno;
+ }
if ( bridge ) { /* update limit regs and subordinate busno */
pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
@@ -195,3 +305,23 @@ fsl_pci_init(struct pci_controller *hose)
pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
}
}
+
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <libfdt.h>
+#include <fdt_support.h>
+
+void ft_fsl_pci_setup(void *blob, const char *pci_alias,
+ struct pci_controller *hose)
+{
+ int off = fdt_path_offset(blob, pci_alias);
+
+ if (off >= 0) {
+ u32 bus_range[2];
+
+ bus_range[0] = 0;
+ bus_range[1] = hose->last_busno - hose->first_busno;
+ fdt_setprop(blob, off, "bus-range", &bus_range[0], 2*4);
+ fdt_pci_dma_ranges(blob, off, hose);
+ }
+}
+#endif
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b5eea89..e2b05d8 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -157,7 +157,7 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
for (hose = hose_head; hose; hose = hose->next)
{
-#ifdef CFG_SCSI_SCAN_BUS_REVERSE
+#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
#else
for (bus = hose->first_busno; bus <= hose->last_busno; bus++)
@@ -218,12 +218,12 @@ pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
*
*/
-unsigned long pci_hose_phys_to_bus (struct pci_controller *hose,
+pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose,
phys_addr_t phys_addr,
unsigned long flags)
{
struct pci_region *res;
- unsigned long bus_addr;
+ pci_addr_t bus_addr;
int i;
if (!hose) {
@@ -252,7 +252,7 @@ Done:
}
phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
- unsigned long bus_addr,
+ pci_addr_t bus_addr,
unsigned long flags)
{
struct pci_region *res;
@@ -288,15 +288,17 @@ Done:
int pci_hose_config_device(struct pci_controller *hose,
pci_dev_t dev,
unsigned long io,
- unsigned long mem,
+ pci_addr_t mem,
unsigned long command)
{
- unsigned int bar_response, bar_size, bar_value, old_command;
+ unsigned int bar_response, old_command;
+ pci_addr_t bar_value;
+ pci_size_t bar_size;
unsigned char pin;
int bar, found_mem64;
- debug ("PCI Config: I/O=0x%lx, Memory=0x%lx, Command=0x%lx\n",
- io, mem, command);
+ debug ("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n",
+ io, (u64)mem, command);
pci_hose_write_config_dword (hose, dev, PCI_COMMAND, 0);
@@ -319,10 +321,19 @@ int pci_hose_config_device(struct pci_controller *hose,
io = io + bar_size;
} else {
if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
- PCI_BASE_ADDRESS_MEM_TYPE_64)
- found_mem64 = 1;
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+ pci_hose_write_config_dword(hose, dev, bar+4, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar+4, &bar_response_upper);
- bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
/* round up region base address to multiple of size */
mem = ((mem - 1) | (bar_size - 1)) + 1;
@@ -332,11 +343,15 @@ int pci_hose_config_device(struct pci_controller *hose,
}
/* Write it out and update our limit */
- pci_hose_write_config_dword (hose, dev, bar, bar_value);
+ pci_hose_write_config_dword (hose, dev, bar, (u32)bar_value);
if (found_mem64) {
bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value>>32));
+#else
pci_hose_write_config_dword (hose, dev, bar, 0x00000000);
+#endif
}
}
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index 2acf9bf..c20b981 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -26,9 +26,9 @@
#define PCIAUTO_IDE_MODE_MASK 0x05
-/* the user can define CFG_PCI_CACHE_LINE_SIZE to avoid problems */
-#ifndef CFG_PCI_CACHE_LINE_SIZE
-#define CFG_PCI_CACHE_LINE_SIZE 8
+/* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */
+#ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE
+#define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8
#endif
/*
@@ -45,14 +45,14 @@ void pciauto_region_init(struct pci_region* res)
res->bus_lower = res->bus_start ? res->bus_start : 0x1000;
}
-void pciauto_region_align(struct pci_region *res, unsigned long size)
+void pciauto_region_align(struct pci_region *res, pci_size_t size)
{
res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1;
}
-int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned int *bar)
+int pciauto_region_allocate(struct pci_region* res, pci_size_t size, pci_addr_t *bar)
{
- unsigned long addr;
+ pci_addr_t addr;
if (!res) {
DEBUGF("No resource");
@@ -68,13 +68,13 @@ int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned
res->bus_lower = addr + size;
- DEBUGF("address=0x%lx bus_lower=%x", addr, res->bus_lower);
+ DEBUGF("address=0x%llx bus_lower=0x%llx", (u64)addr, (u64)res->bus_lower);
*bar = addr;
return 0;
error:
- *bar = 0xffffffff;
+ *bar = (pci_addr_t)-1;
return -1;
}
@@ -88,7 +88,9 @@ void pciauto_setup_device(struct pci_controller *hose,
struct pci_region *prefetch,
struct pci_region *io)
{
- unsigned int bar_value, bar_response, bar_size;
+ unsigned int bar_response;
+ pci_addr_t bar_value;
+ pci_size_t bar_size;
unsigned int cmdstat = 0;
struct pci_region *bar_res;
int bar, bar_nr = 0;
@@ -114,33 +116,46 @@ void pciauto_setup_device(struct pci_controller *hose,
& 0xffff) + 1;
bar_res = io;
- DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%x, ", bar_nr, bar_size);
+ DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", bar_nr, (u64)bar_size);
} else {
if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
- PCI_BASE_ADDRESS_MEM_TYPE_64)
- found_mem64 = 1;
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+ pci_hose_write_config_dword(hose, dev, bar+4, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar+4, &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
- bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
bar_res = prefetch;
else
bar_res = mem;
- DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%x, ", bar_nr, bar_size);
+ DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%llx, ", bar_nr, (u64)bar_size);
}
if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) {
/* Write it out and update our limit */
- pci_hose_write_config_dword(hose, dev, bar, bar_value);
+ pci_hose_write_config_dword(hose, dev, bar, (u32)bar_value);
- /*
- * If we are a 64-bit decoder then increment to the
- * upper 32 bits of the bar and force it to locate
- * in the lower 4GB of memory.
- */
if (found_mem64) {
bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value>>32));
+#else
+ /*
+ * If we are a 64-bit decoder then increment to the
+ * upper 32 bits of the bar and force it to locate
+ * in the lower 4GB of memory.
+ */
pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
+#endif
}
cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
@@ -154,7 +169,7 @@ void pciauto_setup_device(struct pci_controller *hose,
pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
- CFG_PCI_CACHE_LINE_SIZE);
+ CONFIG_SYS_PCI_CACHE_LINE_SIZE);
pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
}
@@ -289,35 +304,36 @@ void pciauto_config_init(struct pci_controller *hose)
if (hose->pci_mem) {
pciauto_region_init(hose->pci_mem);
- DEBUGF("PCI Autoconfig: Bus Memory region: [%lx-%lx],\n"
- "\t\tPhysical Memory [%x-%x]\n",
- hose->pci_mem->bus_start,
- hose->pci_mem->bus_start + hose->pci_mem->size - 1,
- hose->pci_mem->phys_start,
- hose->pci_mem->phys_start + hose->pci_mem->size - 1);
+ DEBUGF("PCI Autoconfig: Bus Memory region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llxx]\n",
+ (u64)hose->pci_mem->bus_start,
+ (u64)(hose->pci_mem->bus_start + hose->pci_mem->size - 1),
+ (u64)hose->pci_mem->phys_start,
+ (u64)(hose->pci_mem->phys_start + hose->pci_mem->size - 1));
}
if (hose->pci_prefetch) {
pciauto_region_init(hose->pci_prefetch);
- DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [%lx-%lx],\n"
- "\t\tPhysical Memory [%x-%x]\n",
- hose->pci_prefetch->bus_start,
- hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1,
- hose->pci_prefetch->phys_start,
- hose->pci_prefetch->phys_start +
- hose->pci_prefetch->size - 1);
+ DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llx]\n",
+ (u64)hose->pci_prefetch->bus_start,
+ (u64)(hose->pci_prefetch->bus_start +
+ hose->pci_prefetch->size - 1),
+ (u64)hose->pci_prefetch->phys_start,
+ (u64)(hose->pci_prefetch->phys_start +
+ hose->pci_prefetch->size - 1));
}
if (hose->pci_io) {
pciauto_region_init(hose->pci_io);
- DEBUGF("PCI Autoconfig: Bus I/O region: [%lx-%lx],\n"
- "\t\tPhysical Memory: [%x-%x]\n",
- hose->pci_io->bus_start,
- hose->pci_io->bus_start + hose->pci_io->size - 1,
- hose->pci_io->phys_start,
- hose->pci_io->phys_start + hose->pci_io->size - 1);
+ DEBUGF("PCI Autoconfig: Bus I/O region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory: [%llx-%llx]\n",
+ (u64)hose->pci_io->bus_start,
+ (u64)(hose->pci_io->bus_start + hose->pci_io->size - 1),
+ (u64)hose->pci_io->phys_start,
+ (u64)(hose->pci_io->phys_start + hose->pci_io->size - 1));
}
}
diff --git a/drivers/pci/pci_sh7751.c b/drivers/pci/pci_sh7751.c
index a058e1d..df6d76f 100644
--- a/drivers/pci/pci_sh7751.c
+++ b/drivers/pci/pci_sh7751.c
@@ -23,18 +23,19 @@
*/
#include <common.h>
+#include <pci.h>
#include <asm/processor.h>
#include <asm/io.h>
-#include <pci.h>
+#include <asm/pci.h>
/* Register addresses and such */
#define SH7751_BCR1 (vu_long *)0xFF800000
-#define SH7751_BCR2 (vu_short*)0xFF800004
+#define SH7751_BCR2 (vu_short *)0xFF800004
#define SH7751_WCR1 (vu_long *)0xFF800008
#define SH7751_WCR2 (vu_long *)0xFF80000C
#define SH7751_WCR3 (vu_long *)0xFF800010
#define SH7751_MCR (vu_long *)0xFF800014
-#define SH7751_BCR3 (vu_short*)0xFF800050
+#define SH7751_BCR3 (vu_short *)0xFF800050
#define SH7751_PCICONF0 (vu_long *)0xFE200000
#define SH7751_PCICONF1 (vu_long *)0xFE200004
#define SH7751_PCICONF2 (vu_long *)0xFE200008
@@ -87,12 +88,12 @@
#define SH7751_PCIPAR (vu_long *)0xFE2001C0
#define SH7751_PCIPDR (vu_long *)0xFE200220
-#define p4_in(addr) *(addr)
-#define p4_out(data,addr) *(addr) = (data)
+#define p4_in(addr) (*addr)
+#define p4_out(data, addr) (*addr) = (data)
/* Double word */
int pci_sh4_read_config_dword(struct pci_controller *hose,
- pci_dev_t dev, int offset, u32 * value)
+ pci_dev_t dev, int offset, u32 *value)
{
u32 par_data = 0x80000000 | dev;
@@ -103,7 +104,7 @@ int pci_sh4_read_config_dword(struct pci_controller *hose,
}
int pci_sh4_write_config_dword(struct pci_controller *hose,
- pci_dev_t dev, int offset, u32 * value)
+ pci_dev_t dev, int offset, u32 value)
{
u32 par_data = 0x80000000 | dev;
@@ -126,15 +127,18 @@ int pci_sh7751_init(struct pci_controller *hose)
/* Double-check some BSC config settings */
/* (Area 3 non-MPX 32-bit, PCI bus pins) */
if ((p4_in(SH7751_BCR1) & 0x20008) == 0x20000) {
- printf("SH7751_BCR1 0x%08X\n", p4_in(SH7751_BCR1));
+ printf("SH7751_BCR1 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR1));
return 2;
}
if ((p4_in(SH7751_BCR2) & 0xC0) != 0xC0) {
- printf("SH7751_BCR2 0x%08X\n", p4_in(SH7751_BCR2));
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
return 3;
}
if (p4_in(SH7751_BCR2) & 0x01) {
- printf("SH7751_BCR2 0x%08X\n", p4_in(SH7751_BCR2));
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
return 4;
}
@@ -183,8 +187,8 @@ int pci_sh7751_init(struct pci_controller *hose)
/* Copy BSC registers into PCI BSC */
p4_out(inl(SH7751_BCR1), SH7751_PCIBCR1);
- p4_out(inl(SH7751_BCR2), SH7751_PCIBCR2);
- p4_out(inl(SH7751_BCR3), SH7751_PCIBCR3);
+ p4_out(inw(SH7751_BCR2), SH7751_PCIBCR2);
+ p4_out(inw(SH7751_BCR3), SH7751_PCIBCR3);
p4_out(inl(SH7751_WCR1), SH7751_PCIWCR1);
p4_out(inl(SH7751_WCR2), SH7751_PCIWCR2);
p4_out(inl(SH7751_WCR3), SH7751_PCIWCR3);
diff --git a/drivers/pci/pci_sh7780.c b/drivers/pci/pci_sh7780.c
index 2d04b4f..7555d96 100644
--- a/drivers/pci/pci_sh7780.c
+++ b/drivers/pci/pci_sh7780.c
@@ -25,9 +25,10 @@
#include <common.h>
+#include <pci.h>
#include <asm/processor.h>
+#include <asm/pci.h>
#include <asm/io.h>
-#include <pci.h>
#define SH7780_VENDOR_ID 0x1912
#define SH7780_DEVICE_ID 0x0002
@@ -41,10 +42,10 @@
#define SH7780_PCICR_PRST 0x00000002
#define SH7780_PCICR_CFIN 0x00000001
-#define p4_in(addr) *((vu_long *)addr)
-#define p4_out(data,addr) *(vu_long *)(addr) = (data)
-#define p4_inw(addr) *((vu_short *)addr)
-#define p4_outw(data,addr) *(vu_short *)(addr) = (data)
+#define p4_in(addr) (*(vu_long *)addr)
+#define p4_out(data, addr) (*(vu_long *)addr) = (data)
+#define p4_inw(addr) (*(vu_short *)addr)
+#define p4_outw(data, addr) (*(vu_short *)addr) = (data)
int pci_sh4_read_config_dword(struct pci_controller *hose,
pci_dev_t dev, int offset, u32 *value)
@@ -72,9 +73,9 @@ int pci_sh7780_init(struct pci_controller *hose)
p4_out(0x01, SH7780_PCIECR);
if (p4_inw(SH7780_PCIVID) != SH7780_VENDOR_ID
- && p4_inw(SH7780_PCIDID) != SH7780_DEVICE_ID){
+ && p4_inw(SH7780_PCIDID) != SH7780_DEVICE_ID) {
printf("PCI: Unknown PCI host bridge.\n");
- return;
+ return -1;
}
printf("PCI: SH7780 PCI host bridge found.\n");
diff --git a/drivers/pci/tsi108_pci.c b/drivers/pci/tsi108_pci.c
index edd614f..d153fc6 100644
--- a/drivers/pci/tsi108_pci.c
+++ b/drivers/pci/tsi108_pci.c
@@ -47,32 +47,32 @@ void tsi108_clear_pci_error (void)
* requests.
*/
/* Read PB Error Log Registers */
- err_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+ err_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
TSI108_PB_REG_OFFSET + PB_ERRCS);
- err_addr = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+ err_addr = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
TSI108_PB_REG_OFFSET + PB_AERR);
if (err_stat & PB_ERRCS_ES) {
/* Clear PCI/X bus errors if applicable */
- if ((err_addr & 0xFF000000) == CFG_PCI_CFG_BASE) {
+ if ((err_addr & 0xFF000000) == CONFIG_SYS_PCI_CFG_BASE) {
/* Clear error flag */
- *(u32 *) (CFG_TSI108_CSR_BASE +
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
TSI108_PB_REG_OFFSET + PB_ERRCS) =
PB_ERRCS_ES;
/* Clear read error reported in PB_ISR */
- *(u32 *) (CFG_TSI108_CSR_BASE +
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
TSI108_PB_REG_OFFSET + PB_ISR) =
PB_ISR_PBS_RD_ERR;
/* Clear errors reported by PCI CSR (Normally Master Abort) */
- pci_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+ pci_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
TSI108_PCI_REG_OFFSET +
PCI_CSR);
- *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+ *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
TSI108_PCI_REG_OFFSET + PCI_CSR) =
pci_stat;
- *(volatile u32 *)(CFG_TSI108_CSR_BASE +
+ *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
TSI108_PCI_REG_OFFSET +
PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR;
}
@@ -102,8 +102,8 @@ unsigned int __get_pci_config_dword (u32 addr)
static int tsi108_read_config_dword (struct pci_controller *hose,
pci_dev_t dev, int offset, u32 * value)
{
- dev &= (CFG_PCI_CFG_SIZE - 1);
- dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc));
+ dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1);
+ dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc));
*value = __get_pci_config_dword(dev);
if (0xFFFFFFFF == *value)
tsi108_clear_pci_error ();
@@ -113,8 +113,8 @@ static int tsi108_read_config_dword (struct pci_controller *hose,
static int tsi108_write_config_dword (struct pci_controller *hose,
pci_dev_t dev, int offset, u32 value)
{
- dev &= (CFG_PCI_CFG_SIZE - 1);
- dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc));
+ dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1);
+ dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc));
out_le32 ((volatile unsigned *)dev, value);
@@ -129,19 +129,19 @@ void pci_init_board (void)
hose->last_busno = 0xff;
pci_set_region (hose->regions + 0,
- CFG_PCI_MEMORY_BUS,
- CFG_PCI_MEMORY_PHYS,
- CFG_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_MEMORY);
+ CONFIG_SYS_PCI_MEMORY_BUS,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ CONFIG_SYS_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_MEMORY);
/* PCI memory space */
pci_set_region (hose->regions + 1,
- CFG_PCI_MEM_BUS,
- CFG_PCI_MEM_PHYS, CFG_PCI_MEM_SIZE, PCI_REGION_MEM);
+ CONFIG_SYS_PCI_MEM_BUS,
+ CONFIG_SYS_PCI_MEM_PHYS, CONFIG_SYS_PCI_MEM_SIZE, PCI_REGION_MEM);
/* PCI I/O space */
pci_set_region (hose->regions + 2,
- CFG_PCI_IO_BUS,
- CFG_PCI_IO_PHYS, CFG_PCI_IO_SIZE, PCI_REGION_IO);
+ CONFIG_SYS_PCI_IO_BUS,
+ CONFIG_SYS_PCI_IO_PHYS, CONFIG_SYS_PCI_IO_SIZE, PCI_REGION_IO);
hose->region_count = 3;
diff --git a/drivers/pci/w83c553f.c b/drivers/pci/w83c553f.c
index d7355a4..8561422 100644
--- a/drivers/pci/w83c553f.c
+++ b/drivers/pci/w83c553f.c
@@ -42,7 +42,7 @@
out_be16((u16*) (addr),(val)); udelay(1); \
} while (0)
-extern uint ide_bus_offset[CFG_IDE_MAXBUS];
+extern uint ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];
void initialise_pic(void);
void initialise_dma(void);
@@ -105,7 +105,7 @@ void initialise_w83c553f(void)
pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &ide_bus_offset[0]);
ide_bus_offset[0] &= ~1;
-#if CFG_IDE_MAXBUS > 1
+#if CONFIG_SYS_IDE_MAXBUS > 1
pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_2, &ide_bus_offset[1]);
ide_bus_offset[1] &= ~1;
#endif
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 1e2431e..1bcb3a5 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -909,8 +909,8 @@ int i82365_init (void)
mem.map = 0;
mem.flags = MAP_ATTRIB | MAP_ACTIVE;
mem.speed = 300;
- mem.sys_start = CFG_PCMCIA_MEM_ADDR;
- mem.sys_stop = CFG_PCMCIA_MEM_ADDR + CFG_PCMCIA_MEM_SIZE - 1;
+ mem.sys_start = CONFIG_SYS_PCMCIA_MEM_ADDR;
+ mem.sys_stop = CONFIG_SYS_PCMCIA_MEM_ADDR + CONFIG_SYS_PCMCIA_MEM_SIZE - 1;
mem.card_start = 0;
i365_set_mem_map (&socket, &mem);
@@ -918,8 +918,8 @@ int i82365_init (void)
mem.map = 1;
mem.flags = MAP_ACTIVE;
mem.speed = 300;
- mem.sys_start = CFG_PCMCIA_MEM_ADDR + CFG_PCMCIA_MEM_SIZE;
- mem.sys_stop = CFG_PCMCIA_MEM_ADDR + (2 * CFG_PCMCIA_MEM_SIZE) - 1;
+ mem.sys_start = CONFIG_SYS_PCMCIA_MEM_ADDR + CONFIG_SYS_PCMCIA_MEM_SIZE;
+ mem.sys_stop = CONFIG_SYS_PCMCIA_MEM_ADDR + (2 * CONFIG_SYS_PCMCIA_MEM_SIZE) - 1;
mem.card_start = 0;
i365_set_mem_map (&socket, &mem);
@@ -988,8 +988,8 @@ static void i82365_dump_regions (pci_dev_t dev)
{
u_int tmp[2];
u_int *mem = (void *) socket.cb_phys;
- u_char *cis = (void *) CFG_PCMCIA_MEM_ADDR;
- u_char *ide = (void *) (CFG_ATA_BASE_ADDR + CFG_ATA_REG_OFFSET);
+ u_char *cis = (void *) CONFIG_SYS_PCMCIA_MEM_ADDR;
+ u_char *ide = (void *) (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_REG_OFFSET);
pci_read_config_dword (dev, 0x00, tmp + 0);
pci_read_config_dword (dev, 0x80, tmp + 1);
diff --git a/drivers/pcmcia/marubun_pcmcia.c b/drivers/pcmcia/marubun_pcmcia.c
index d075ba3..f715dec 100644
--- a/drivers/pcmcia/marubun_pcmcia.c
+++ b/drivers/pcmcia/marubun_pcmcia.c
@@ -38,20 +38,20 @@
#if defined(CONFIG_PCMCIA)
/* MR-SHPC-01 register */
-#define MRSHPC_MODE (CFG_MARUBUN_MRSHPC + 4)
-#define MRSHPC_OPTION (CFG_MARUBUN_MRSHPC + 6)
-#define MRSHPC_CSR (CFG_MARUBUN_MRSHPC + 8)
-#define MRSHPC_ISR (CFG_MARUBUN_MRSHPC + 10)
-#define MRSHPC_ICR (CFG_MARUBUN_MRSHPC + 12)
-#define MRSHPC_CPWCR (CFG_MARUBUN_MRSHPC + 14)
-#define MRSHPC_MW0CR1 (CFG_MARUBUN_MRSHPC + 16)
-#define MRSHPC_MW1CR1 (CFG_MARUBUN_MRSHPC + 18)
-#define MRSHPC_IOWCR1 (CFG_MARUBUN_MRSHPC + 20)
-#define MRSHPC_MW0CR2 (CFG_MARUBUN_MRSHPC + 22)
-#define MRSHPC_MW1CR2 (CFG_MARUBUN_MRSHPC + 24)
-#define MRSHPC_IOWCR2 (CFG_MARUBUN_MRSHPC + 26)
-#define MRSHPC_CDCR (CFG_MARUBUN_MRSHPC + 28)
-#define MRSHPC_PCIC_INFO (CFG_MARUBUN_MRSHPC + 30)
+#define MRSHPC_MODE (CONFIG_SYS_MARUBUN_MRSHPC + 4)
+#define MRSHPC_OPTION (CONFIG_SYS_MARUBUN_MRSHPC + 6)
+#define MRSHPC_CSR (CONFIG_SYS_MARUBUN_MRSHPC + 8)
+#define MRSHPC_ISR (CONFIG_SYS_MARUBUN_MRSHPC + 10)
+#define MRSHPC_ICR (CONFIG_SYS_MARUBUN_MRSHPC + 12)
+#define MRSHPC_CPWCR (CONFIG_SYS_MARUBUN_MRSHPC + 14)
+#define MRSHPC_MW0CR1 (CONFIG_SYS_MARUBUN_MRSHPC + 16)
+#define MRSHPC_MW1CR1 (CONFIG_SYS_MARUBUN_MRSHPC + 18)
+#define MRSHPC_IOWCR1 (CONFIG_SYS_MARUBUN_MRSHPC + 20)
+#define MRSHPC_MW0CR2 (CONFIG_SYS_MARUBUN_MRSHPC + 22)
+#define MRSHPC_MW1CR2 (CONFIG_SYS_MARUBUN_MRSHPC + 24)
+#define MRSHPC_IOWCR2 (CONFIG_SYS_MARUBUN_MRSHPC + 26)
+#define MRSHPC_CDCR (CONFIG_SYS_MARUBUN_MRSHPC + 28)
+#define MRSHPC_PCIC_INFO (CONFIG_SYS_MARUBUN_MRSHPC + 30)
int pcmcia_on (void)
{
@@ -98,8 +98,8 @@ int pcmcia_on (void)
outw(0x0000,MRSHPC_ISR);
outw(0x2000,MRSHPC_ICR);
- outb(0x00,(CFG_MARUBUN_MW2 + 0x206));
- outb(0x42,(CFG_MARUBUN_MW2 + 0x200));
+ outb(0x00,(CONFIG_SYS_MARUBUN_MW2 + 0x206));
+ outb(0x42,(CONFIG_SYS_MARUBUN_MW2 + 0x200));
return 0;
}
diff --git a/drivers/pcmcia/mpc8xx_pcmcia.c b/drivers/pcmcia/mpc8xx_pcmcia.c
index 14477a4..95ea5e9 100644
--- a/drivers/pcmcia/mpc8xx_pcmcia.c
+++ b/drivers/pcmcia/mpc8xx_pcmcia.c
@@ -34,8 +34,8 @@ static u_int m8xx_get_speed(u_int ns, u_int is_io);
/* look up table for pgcrx registers */
u_int *pcmcia_pgcrx[2] = {
- &((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcra,
- &((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcrb,
+ &((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia.pcmc_pgcra,
+ &((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia.pcmc_pgcrb,
};
/*
@@ -66,11 +66,11 @@ static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] =
#endif
#if defined(CONFIG_LWMON) || defined(CONFIG_NSCU)
-#define CFG_PCMCIA_TIMING ( PCMCIA_SHT(9) \
+#define CONFIG_SYS_PCMCIA_TIMING ( PCMCIA_SHT(9) \
| PCMCIA_SST(3) \
| PCMCIA_SL(12))
#else
-#define CFG_PCMCIA_TIMING ( PCMCIA_SHT(2) \
+#define CONFIG_SYS_PCMCIA_TIMING ( PCMCIA_SHT(2) \
| PCMCIA_SST(4) \
| PCMCIA_SL(9))
#endif
@@ -88,12 +88,12 @@ int pcmcia_on (void)
debug ("Enable PCMCIA " PCMCIA_SLOT_MSG "\n");
/* intialize the fixed memory windows */
- win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
- base = CFG_PCMCIA_MEM_ADDR;
+ win = (pcmcia_win_t *)(&((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia.pcmc_pbr0);
+ base = CONFIG_SYS_PCMCIA_MEM_ADDR;
- if((reg = m8xx_get_graycode(CFG_PCMCIA_MEM_SIZE)) == -1) {
+ if((reg = m8xx_get_graycode(CONFIG_SYS_PCMCIA_MEM_SIZE)) == -1) {
printf ("Cannot set window size to 0x%08x\n",
- CFG_PCMCIA_MEM_SIZE);
+ CONFIG_SYS_PCMCIA_MEM_SIZE);
return (1);
}
@@ -125,7 +125,7 @@ int pcmcia_on (void)
| PCMCIA_PRS_ATTR
| slotbit
| PCMCIA_PV
- | CFG_PCMCIA_TIMING );
+ | CONFIG_SYS_PCMCIA_TIMING );
break;
}
case 5:
@@ -135,7 +135,7 @@ int pcmcia_on (void)
| PCMCIA_PRS_IO
| slotbit
| PCMCIA_PV
- | CFG_PCMCIA_TIMING );
+ | CONFIG_SYS_PCMCIA_TIMING );
break;
}
case 6:
@@ -145,7 +145,7 @@ int pcmcia_on (void)
| PCMCIA_PRS_IO
| slotbit
| PCMCIA_PV
- | CFG_PCMCIA_TIMING );
+ | CONFIG_SYS_PCMCIA_TIMING );
break;
}
#endif /* CONFIG_IDE_8xx_PCCARD */
@@ -157,7 +157,7 @@ int pcmcia_on (void)
| PCMCIA_PRS_IO
| slotbit
| PCMCIA_PV
- | CFG_PCMCIA_TIMING );
+ | CONFIG_SYS_PCMCIA_TIMING );
break;
}
#endif /* CONFIG_HMI10 */
@@ -168,7 +168,7 @@ int pcmcia_on (void)
debug ("MemWin %d: PBR 0x%08lX POR %08lX\n",
i, win->br, win->or);
- base += CFG_PCMCIA_MEM_SIZE;
+ base += CONFIG_SYS_PCMCIA_MEM_SIZE;
++win;
}
@@ -198,14 +198,14 @@ int pcmcia_off (void)
printf ("Disable PCMCIA " PCMCIA_SLOT_MSG "\n");
/* clear interrupt state, and disable interrupts */
- ((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pscr = PCMCIA_MASK(_slot_);
- ((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_per &= ~PCMCIA_MASK(_slot_);
+ ((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia.pcmc_pscr = PCMCIA_MASK(_slot_);
+ ((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia.pcmc_per &= ~PCMCIA_MASK(_slot_);
/* turn off interrupt and disable CxOE */
PCMCIA_PGCRX(_slot_) = __MY_PCMCIA_GCRX_CXOE;
/* turn off memory windows */
- win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
+ win = (pcmcia_win_t *)(&((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia.pcmc_pbr0);
for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
/* disable memory window */
diff --git a/drivers/pcmcia/pxa_pcmcia.c b/drivers/pcmcia/pxa_pcmcia.c
index 11d8590..d06ab74 100644
--- a/drivers/pcmcia/pxa_pcmcia.c
+++ b/drivers/pcmcia/pxa_pcmcia.c
@@ -13,12 +13,12 @@ static inline void msWait(unsigned msVal)
int pcmcia_on (void)
{
unsigned int reg_arr[] = {
- 0x48000028, CFG_MCMEM0_VAL,
- 0x4800002c, CFG_MCMEM1_VAL,
- 0x48000030, CFG_MCATT0_VAL,
- 0x48000034, CFG_MCATT1_VAL,
- 0x48000038, CFG_MCIO0_VAL,
- 0x4800003c, CFG_MCIO1_VAL,
+ 0x48000028, CONFIG_SYS_MCMEM0_VAL,
+ 0x4800002c, CONFIG_SYS_MCMEM1_VAL,
+ 0x48000030, CONFIG_SYS_MCATT0_VAL,
+ 0x48000034, CONFIG_SYS_MCATT1_VAL,
+ 0x48000038, CONFIG_SYS_MCIO0_VAL,
+ 0x4800003c, CONFIG_SYS_MCIO1_VAL,
0, 0
};
diff --git a/drivers/pcmcia/ti_pci1410a.c b/drivers/pcmcia/ti_pci1410a.c
index c876d0c..6ab9759 100644
--- a/drivers/pcmcia/ti_pci1410a.c
+++ b/drivers/pcmcia/ti_pci1410a.c
@@ -88,8 +88,8 @@ const char *indent = "\t ";
int do_pinit(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
-#ifndef CFG_FIRST_PCMCIA_BUS
-# define CFG_FIRST_PCMCIA_BUS 0
+#ifndef CONFIG_SYS_FIRST_PCMCIA_BUS
+# define CONFIG_SYS_FIRST_PCMCIA_BUS 0
#endif
int rcode = 0;
@@ -99,7 +99,7 @@ int do_pinit(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
return 1;
}
if (strcmp(argv[1],"on") == 0) {
- rcode = pcmcia_on(CFG_FIRST_PCMCIA_BUS);
+ rcode = pcmcia_on(CONFIG_SYS_FIRST_PCMCIA_BUS);
} else if (strcmp(argv[1],"off") == 0) {
rcode = pcmcia_off();
} else {
@@ -148,11 +148,11 @@ int pcmcia_on(int ide_base_bus)
debug("Enable PCMCIA Ti PCI1410A\n");
}
- pcmcia_cis_ptr = CFG_PCMCIA_CIS_WIN;
- cis_len = CFG_PCMCIA_CIS_WIN_SIZE;
+ pcmcia_cis_ptr = CONFIG_SYS_PCMCIA_CIS_WIN;
+ cis_len = CONFIG_SYS_PCMCIA_CIS_WIN_SIZE;
- io_base = CFG_PCMCIA_IO_WIN;
- io_len = CFG_PCMCIA_IO_WIN_SIZE;
+ io_base = CONFIG_SYS_PCMCIA_IO_WIN;
+ io_len = CONFIG_SYS_PCMCIA_IO_WIN_SIZE;
/*
* Setup the PCI device.
diff --git a/drivers/pcmcia/tqm8xx_pcmcia.c b/drivers/pcmcia/tqm8xx_pcmcia.c
index cc980c2..6ba8b5c 100644
--- a/drivers/pcmcia/tqm8xx_pcmcia.c
+++ b/drivers/pcmcia/tqm8xx_pcmcia.c
@@ -40,7 +40,7 @@
static inline void power_config(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
/*
* Configure Port B pins for
* 5 Volts Enable and 3 Volts enable
@@ -50,21 +50,21 @@ static inline void power_config(int slot)
static inline void power_off(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
/* remove all power */
immap->im_cpm.cp_pbdat |= 0x00000300;
}
static inline void power_on_5_0(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
immap->im_cpm.cp_pbdat &= ~(0x0000100);
immap->im_cpm.cp_pbdir |= 0x00000300;
}
static inline void power_on_3_3(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
immap->im_cpm.cp_pbdat &= ~(0x0000200);
immap->im_cpm.cp_pbdir |= 0x00000300;
}
@@ -97,7 +97,7 @@ static inline void power_on_3_3(int slot)
static inline void power_config(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
/*
* Configure Port C pins for
* 5 Volts Enable and 3 Volts enable
@@ -108,20 +108,20 @@ static inline void power_config(int slot)
static inline void power_off(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
}
static inline void power_on_5_0(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
immap->im_ioport.iop_pcdat |= 0x0004;
immap->im_ioport.iop_pcdir |= (0x0002 | 0x0004);
}
static inline void power_on_3_3(int slot)
{
- volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
immap->im_ioport.iop_pcdat |= 0x0002;
immap->im_ioport.iop_pcdir |= (0x0002 | 0x0004);
}
@@ -132,14 +132,14 @@ static inline void power_on_3_3(int slot)
static inline int check_card_is_absent(int slot)
{
volatile pcmconf8xx_t *pcmp =
- (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
return pcmp->pcmc_pipr & (0x10000000 >> (slot << 4));
}
#else
static inline int check_card_is_absent(int slot)
{
volatile pcmconf8xx_t *pcmp =
- (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
return pcmp->pcmc_pipr & (0x18000000 >> (slot << 4));
}
#endif
@@ -153,9 +153,9 @@ static inline int check_card_is_absent(int slot)
int pcmcia_hardware_enable(int slot)
{
volatile pcmconf8xx_t *pcmp =
- (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
volatile sysconf8xx_t *sysp =
- (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+ (sysconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_siu_conf));
uint reg, mask;
debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
@@ -271,7 +271,7 @@ int pcmcia_voltage_set(int slot, int vcc, int vpp)
u_long reg;
# ifdef DEBUG
volatile pcmconf8xx_t *pcmp =
- (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
# endif
debug ("voltage_set: " PCMCIA_BOARD_MSG
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index 344c649..bba3ef2 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -34,12 +34,12 @@
#ifdef CONFIG_UEC_ETH1
static uec_info_t eth1_uec_info = {
.uf_info = {
- .ucc_num = CFG_UEC1_UCC_NUM,
- .rx_clock = CFG_UEC1_RX_CLK,
- .tx_clock = CFG_UEC1_TX_CLK,
- .eth_type = CFG_UEC1_ETH_TYPE,
+ .ucc_num = CONFIG_SYS_UEC1_UCC_NUM,
+ .rx_clock = CONFIG_SYS_UEC1_RX_CLK,
+ .tx_clock = CONFIG_SYS_UEC1_TX_CLK,
+ .eth_type = CONFIG_SYS_UEC1_ETH_TYPE,
},
-#if (CFG_UEC1_ETH_TYPE == FAST_ETH)
+#if (CONFIG_SYS_UEC1_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
@@ -50,19 +50,19 @@ static uec_info_t eth1_uec_info = {
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16,
.rx_bd_ring_len = 16,
- .phy_address = CFG_UEC1_PHY_ADDR,
- .enet_interface = CFG_UEC1_INTERFACE_MODE,
+ .phy_address = CONFIG_SYS_UEC1_PHY_ADDR,
+ .enet_interface = CONFIG_SYS_UEC1_INTERFACE_MODE,
};
#endif
#ifdef CONFIG_UEC_ETH2
static uec_info_t eth2_uec_info = {
.uf_info = {
- .ucc_num = CFG_UEC2_UCC_NUM,
- .rx_clock = CFG_UEC2_RX_CLK,
- .tx_clock = CFG_UEC2_TX_CLK,
- .eth_type = CFG_UEC2_ETH_TYPE,
+ .ucc_num = CONFIG_SYS_UEC2_UCC_NUM,
+ .rx_clock = CONFIG_SYS_UEC2_RX_CLK,
+ .tx_clock = CONFIG_SYS_UEC2_TX_CLK,
+ .eth_type = CONFIG_SYS_UEC2_ETH_TYPE,
},
-#if (CFG_UEC2_ETH_TYPE == FAST_ETH)
+#if (CONFIG_SYS_UEC2_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
@@ -73,19 +73,19 @@ static uec_info_t eth2_uec_info = {
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16,
.rx_bd_ring_len = 16,
- .phy_address = CFG_UEC2_PHY_ADDR,
- .enet_interface = CFG_UEC2_INTERFACE_MODE,
+ .phy_address = CONFIG_SYS_UEC2_PHY_ADDR,
+ .enet_interface = CONFIG_SYS_UEC2_INTERFACE_MODE,
};
#endif
#ifdef CONFIG_UEC_ETH3
static uec_info_t eth3_uec_info = {
.uf_info = {
- .ucc_num = CFG_UEC3_UCC_NUM,
- .rx_clock = CFG_UEC3_RX_CLK,
- .tx_clock = CFG_UEC3_TX_CLK,
- .eth_type = CFG_UEC3_ETH_TYPE,
+ .ucc_num = CONFIG_SYS_UEC3_UCC_NUM,
+ .rx_clock = CONFIG_SYS_UEC3_RX_CLK,
+ .tx_clock = CONFIG_SYS_UEC3_TX_CLK,
+ .eth_type = CONFIG_SYS_UEC3_ETH_TYPE,
},
-#if (CFG_UEC3_ETH_TYPE == FAST_ETH)
+#if (CONFIG_SYS_UEC3_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
@@ -96,19 +96,19 @@ static uec_info_t eth3_uec_info = {
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16,
.rx_bd_ring_len = 16,
- .phy_address = CFG_UEC3_PHY_ADDR,
- .enet_interface = CFG_UEC3_INTERFACE_MODE,
+ .phy_address = CONFIG_SYS_UEC3_PHY_ADDR,
+ .enet_interface = CONFIG_SYS_UEC3_INTERFACE_MODE,
};
#endif
#ifdef CONFIG_UEC_ETH4
static uec_info_t eth4_uec_info = {
.uf_info = {
- .ucc_num = CFG_UEC4_UCC_NUM,
- .rx_clock = CFG_UEC4_RX_CLK,
- .tx_clock = CFG_UEC4_TX_CLK,
- .eth_type = CFG_UEC4_ETH_TYPE,
+ .ucc_num = CONFIG_SYS_UEC4_UCC_NUM,
+ .rx_clock = CONFIG_SYS_UEC4_RX_CLK,
+ .tx_clock = CONFIG_SYS_UEC4_TX_CLK,
+ .eth_type = CONFIG_SYS_UEC4_ETH_TYPE,
},
-#if (CFG_UEC4_ETH_TYPE == FAST_ETH)
+#if (CONFIG_SYS_UEC4_ETH_TYPE == FAST_ETH)
.num_threads_tx = UEC_NUM_OF_THREADS_1,
.num_threads_rx = UEC_NUM_OF_THREADS_1,
#else
@@ -119,12 +119,58 @@ static uec_info_t eth4_uec_info = {
.riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
.tx_bd_ring_len = 16,
.rx_bd_ring_len = 16,
- .phy_address = CFG_UEC4_PHY_ADDR,
- .enet_interface = CFG_UEC4_INTERFACE_MODE,
+ .phy_address = CONFIG_SYS_UEC4_PHY_ADDR,
+ .enet_interface = CONFIG_SYS_UEC4_INTERFACE_MODE,
+};
+#endif
+#ifdef CONFIG_UEC_ETH5
+static uec_info_t eth5_uec_info = {
+ .uf_info = {
+ .ucc_num = CONFIG_SYS_UEC5_UCC_NUM,
+ .rx_clock = CONFIG_SYS_UEC5_RX_CLK,
+ .tx_clock = CONFIG_SYS_UEC5_TX_CLK,
+ .eth_type = CONFIG_SYS_UEC5_ETH_TYPE,
+ },
+#if (CONFIG_SYS_UEC5_ETH_TYPE == FAST_ETH)
+ .num_threads_tx = UEC_NUM_OF_THREADS_1,
+ .num_threads_rx = UEC_NUM_OF_THREADS_1,
+#else
+ .num_threads_tx = UEC_NUM_OF_THREADS_4,
+ .num_threads_rx = UEC_NUM_OF_THREADS_4,
+#endif
+ .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+ .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+ .tx_bd_ring_len = 16,
+ .rx_bd_ring_len = 16,
+ .phy_address = CONFIG_SYS_UEC5_PHY_ADDR,
+ .enet_interface = CONFIG_SYS_UEC5_INTERFACE_MODE,
+};
+#endif
+#ifdef CONFIG_UEC_ETH6
+static uec_info_t eth6_uec_info = {
+ .uf_info = {
+ .ucc_num = CONFIG_SYS_UEC6_UCC_NUM,
+ .rx_clock = CONFIG_SYS_UEC6_RX_CLK,
+ .tx_clock = CONFIG_SYS_UEC6_TX_CLK,
+ .eth_type = CONFIG_SYS_UEC6_ETH_TYPE,
+ },
+#if (CONFIG_SYS_UEC6_ETH_TYPE == FAST_ETH)
+ .num_threads_tx = UEC_NUM_OF_THREADS_1,
+ .num_threads_rx = UEC_NUM_OF_THREADS_1,
+#else
+ .num_threads_tx = UEC_NUM_OF_THREADS_4,
+ .num_threads_rx = UEC_NUM_OF_THREADS_4,
+#endif
+ .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+ .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+ .tx_bd_ring_len = 16,
+ .rx_bd_ring_len = 16,
+ .phy_address = CONFIG_SYS_UEC6_PHY_ADDR,
+ .enet_interface = CONFIG_SYS_UEC6_INTERFACE_MODE,
};
#endif
-#define MAXCONTROLLERS (4)
+#define MAXCONTROLLERS (6)
static struct eth_device *devlist[MAXCONTROLLERS];
@@ -424,6 +470,7 @@ static int uec_set_mac_if_mode(uec_private_t *uec, enet_interface_e if_mode)
upsmr |= (UPSMR_RPM | UPSMR_TBIM);
break;
case ENET_1000_RGMII_RXID:
+ case ENET_1000_RGMII_ID:
case ENET_1000_RGMII:
maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
upsmr |= UPSMR_RPM;
@@ -639,6 +686,31 @@ static void phy_change(struct eth_device *dev)
&& !defined(BITBANGMII)
/*
+ * Find a device index from the devlist by name
+ *
+ * Returns:
+ * The index where the device is located, -1 on error
+ */
+static int uec_miiphy_find_dev_by_name(char *devname)
+{
+ int i;
+
+ for (i = 0; i < MAXCONTROLLERS; i++) {
+ if (strncmp(devname, devlist[i]->name, strlen(devname)) == 0) {
+ break;
+ }
+ }
+
+ /* If device cannot be found, returns -1 */
+ if (i == MAXCONTROLLERS) {
+ debug ("%s: device %s not found in devlist\n", __FUNCTION__, devname);
+ i = -1;
+ }
+
+ return i;
+}
+
+/*
* Read a MII PHY register.
*
* Returns:
@@ -647,8 +719,16 @@ static void phy_change(struct eth_device *dev)
static int uec_miiphy_read(char *devname, unsigned char addr,
unsigned char reg, unsigned short *value)
{
- *value = uec_read_phy_reg(devlist[0], addr, reg);
+ int devindex = 0;
+ if (devname == NULL || value == NULL) {
+ debug("%s: NULL pointer given\n", __FUNCTION__);
+ } else {
+ devindex = uec_miiphy_find_dev_by_name(devname);
+ if (devindex >= 0) {
+ *value = uec_read_phy_reg(devlist[devindex], addr, reg);
+ }
+ }
return 0;
}
@@ -661,11 +741,18 @@ static int uec_miiphy_read(char *devname, unsigned char addr,
static int uec_miiphy_write(char *devname, unsigned char addr,
unsigned char reg, unsigned short value)
{
- uec_write_phy_reg(devlist[0], addr, reg, value);
+ int devindex = 0;
+ if (devname == NULL) {
+ debug("%s: NULL pointer given\n", __FUNCTION__);
+ } else {
+ devindex = uec_miiphy_find_dev_by_name(devname);
+ if (devindex >= 0) {
+ uec_write_phy_reg(devlist[devindex], addr, reg, value);
+ }
+ }
return 0;
}
-
#endif
static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr)
@@ -1368,6 +1455,14 @@ int uec_initialize(int index)
#ifdef CONFIG_UEC_ETH4
uec_info = &eth4_uec_info;
#endif
+ } else if (index == 4) {
+#ifdef CONFIG_UEC_ETH5
+ uec_info = &eth5_uec_info;
+#endif
+ } else if (index == 5) {
+#ifdef CONFIG_UEC_ETH6
+ uec_info = &eth6_uec_info;
+#endif
} else {
printf("%s: index is illegal.\n", __FUNCTION__);
return -EINVAL;
diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h
index e357a92..0b64499 100644
--- a/drivers/qe/uec.h
+++ b/drivers/qe/uec.h
@@ -642,6 +642,7 @@ typedef enum enet_interface {
ENET_100_RGMII,
ENET_1000_GMII,
ENET_1000_RGMII,
+ ENET_1000_RGMII_ID,
ENET_1000_RGMII_RXID,
ENET_1000_TBI,
ENET_1000_RTBI
diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c
index 186922e..829f082 100644
--- a/drivers/qe/uec_phy.c
+++ b/drivers/qe/uec_phy.c
@@ -44,6 +44,54 @@
#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
#endif /* UEC_VERBOSE_DEBUG */
+/*--------------------------------------------------------------------+
+ * Fixed PHY (PHY-less) support for Ethernet Ports.
+ *
+ * Copied from cpu/ppc4xx/4xx_enet.c
+ *--------------------------------------------------------------------*/
+
+/*
+ * Some boards do not have a PHY for each ethernet port. These ports
+ * are known as Fixed PHY (or PHY-less) ports. For such ports, set
+ * the appropriate CONFIG_PHY_ADDR equal to CONFIG_FIXED_PHY and
+ * then define CONFIG_SYS_FIXED_PHY_PORTS to define what the speed and
+ * duplex should be for these ports in the board configuration
+ * file.
+ *
+ * For Example:
+ * #define CONFIG_FIXED_PHY 0xFFFFFFFF
+ *
+ * #define CONFIG_PHY_ADDR CONFIG_FIXED_PHY
+ * #define CONFIG_PHY1_ADDR 1
+ * #define CONFIG_PHY2_ADDR CONFIG_FIXED_PHY
+ * #define CONFIG_PHY3_ADDR 3
+ *
+ * #define CONFIG_SYS_FIXED_PHY_PORT(devnum,speed,duplex) \
+ * {devnum, speed, duplex},
+ *
+ * #define CONFIG_SYS_FIXED_PHY_PORTS \
+ * CONFIG_SYS_FIXED_PHY_PORT(0,SPEED_100,DUPLEX_FULL) \
+ * CONFIG_SYS_FIXED_PHY_PORT(2,SPEED_100,DUPLEX_HALF)
+ */
+
+#ifndef CONFIG_FIXED_PHY
+#define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */
+#endif
+
+#ifndef CONFIG_SYS_FIXED_PHY_PORTS
+#define CONFIG_SYS_FIXED_PHY_PORTS /* default is an empty array */
+#endif
+
+struct fixed_phy_port {
+ unsigned int devnum; /* ethernet port */
+ unsigned int speed; /* specified speed 10,100 or 1000 */
+ unsigned int duplex; /* specified duplex FULL or HALF */
+};
+
+static const struct fixed_phy_port fixed_phy_port[] = {
+ CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
+};
+
static void config_genmii_advert (struct uec_mii_info *mii_info);
static void genmii_setup_forced (struct uec_mii_info *mii_info);
static void genmii_restart_aneg (struct uec_mii_info *mii_info);
@@ -376,6 +424,29 @@ static int bcm_init(struct uec_mii_info *mii_info)
return 0;
}
+static int marvell_init(struct uec_mii_info *mii_info)
+{
+ struct eth_device *edev = mii_info->dev;
+ uec_private_t *uec = edev->priv;
+
+ if (uec->uec_info->enet_interface == ENET_1000_RGMII_ID) {
+ int temp;
+
+ temp = phy_read(mii_info, MII_M1111_PHY_EXT_CR);
+ temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
+ phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp);
+
+ temp = phy_read(mii_info, MII_M1111_PHY_EXT_SR);
+ temp &= ~MII_M1111_HWCFG_MODE_MASK;
+ temp |= MII_M1111_HWCFG_MODE_RGMII;
+ phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp);
+
+ phy_write(mii_info, PHY_BMCR, PHY_BMCR_RESET);
+ }
+
+ return 0;
+}
+
static int marvell_read_status (struct uec_mii_info *mii_info)
{
u16 status;
@@ -510,6 +581,28 @@ static void dm9161_close (struct uec_mii_info *mii_info)
{
}
+static int fixed_phy_aneg (struct uec_mii_info *mii_info)
+{
+ mii_info->autoneg = 0; /* Turn off auto negotiation for fixed phy */
+ return 0;
+}
+
+static int fixed_phy_read_status (struct uec_mii_info *mii_info)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
+ if (mii_info->mii_id == fixed_phy_port[i].devnum) {
+ mii_info->speed = fixed_phy_port[i].speed;
+ mii_info->duplex = fixed_phy_port[i].duplex;
+ mii_info->link = 1; /* Link is always UP */
+ mii_info->pause = 0;
+ break;
+ }
+ }
+ return 0;
+}
+
static struct phy_info phy_info_dm9161 = {
.phy_id = 0x0181b880,
.phy_id_mask = 0x0ffffff0,
@@ -538,6 +631,7 @@ static struct phy_info phy_info_marvell = {
.phy_id_mask = 0xffffff00,
.name = "Marvell 88E11x1",
.features = MII_GBIT_FEATURES,
+ .init = &marvell_init,
.config_aneg = &marvell_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -553,6 +647,14 @@ static struct phy_info phy_info_bcm5481 = {
.init = bcm_init,
};
+static struct phy_info phy_info_fixedphy = {
+ .phy_id = CONFIG_FIXED_PHY,
+ .phy_id_mask = CONFIG_FIXED_PHY,
+ .name = "Fixed PHY",
+ .config_aneg = fixed_phy_aneg,
+ .read_status = fixed_phy_read_status,
+};
+
static struct phy_info phy_info_genmii = {
.phy_id = 0x00000000,
.phy_id_mask = 0x00000000,
@@ -567,6 +669,7 @@ static struct phy_info *phy_info[] = {
&phy_info_dm9161a,
&phy_info_marvell,
&phy_info_bcm5481,
+ &phy_info_fixedphy,
&phy_info_genmii,
NULL
};
diff --git a/drivers/qe/uec_phy.h b/drivers/qe/uec_phy.h
index 6f769fb..7ac1ff9 100644
--- a/drivers/qe/uec_phy.h
+++ b/drivers/qe/uec_phy.h
@@ -77,6 +77,14 @@
#define MII_M1011_IMASK_INIT 0x6400
#define MII_M1011_IMASK_CLEAR 0x0000
+/* 88E1111 PHY Register */
+#define MII_M1111_PHY_EXT_CR 0x14
+#define MII_M1111_RX_DELAY 0x80
+#define MII_M1111_TX_DELAY 0x2
+#define MII_M1111_PHY_EXT_SR 0x1b
+#define MII_M1111_HWCFG_MODE_MASK 0xf
+#define MII_M1111_HWCFG_MODE_RGMII 0xb
+
#define MII_DM9161_SCR 0x10
#define MII_DM9161_SCR_INIT 0x0610
#define MII_DM9161_SCR_RMII_INIT 0x0710
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f41f33d..94bc518 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -32,8 +32,8 @@ COBJS-y += date.o
COBJS-$(CONFIG_RTC_DS12887) += ds12887.o
COBJS-$(CONFIG_RTC_DS1302) += ds1302.o
COBJS-$(CONFIG_RTC_DS1306) += ds1306.o
-COBJS-$(CONFIG_RTC_DS1307)$(CONFIG_RTC_DS1338) += ds1307.o
-COBJS-y += $(COBJS-yy)
+COBJS-$(CONFIG_RTC_DS1307) += ds1307.o
+COBJS-$(CONFIG_RTC_DS1338) += ds1307.o
COBJS-$(CONFIG_RTC_DS1337) += ds1337.o
COBJS-$(CONFIG_RTC_DS1374) += ds1374.o
COBJS-$(CONFIG_RTC_DS1556) += ds1556.o
@@ -59,7 +59,7 @@ COBJS-$(CONFIG_RTC_RX8025) += rx8025.o
COBJS-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
COBJS-$(CONFIG_RTC_X1205) += x1205.o
-COBJS := $(COBJS-y)
+COBJS := $(sort $(COBJS-y))
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c
index ee8acd3..5de6953 100644
--- a/drivers/rtc/bfin_rtc.c
+++ b/drivers/rtc/bfin_rtc.c
@@ -26,10 +26,17 @@
#define NUM_SECS_IN_HR HRS_TO_SECS(1)
#define NUM_SECS_IN_DAY DAYS_TO_SECS(1)
+/* Enable the RTC prescaler enable register */
+static void rtc_init(void)
+{
+ if (!(bfin_read_RTC_PREN() & 0x1))
+ bfin_write_RTC_PREN(0x1);
+}
+
/* Our on-chip RTC has no notion of "reset" */
void rtc_reset(void)
{
- return;
+ rtc_init();
}
/* Wait for pending writes to complete */
@@ -42,18 +49,10 @@ static void wait_for_complete(void)
bfin_write_RTC_ISTAT(WRITE_COMPLETE);
}
-/* Enable the RTC prescaler enable register */
-int rtc_init(void)
-{
- pr_stamp();
- bfin_write_RTC_PREN(0x1);
- return 0;
-}
-
/* Set the time. Get the time_in_secs which is the number of seconds since Jan 1970 and set the RTC registers
* based on this value.
*/
-void rtc_set(struct rtc_time *tmp)
+int rtc_set(struct rtc_time *tmp)
{
unsigned long remain, days, hrs, mins, secs;
@@ -61,9 +60,10 @@ void rtc_set(struct rtc_time *tmp)
if (tmp == NULL) {
puts("Error setting the date/time\n");
- return;
+ return -1;
}
+ rtc_init();
wait_for_complete();
/* Calculate number of seconds this incoming time represents */
@@ -82,6 +82,8 @@ void rtc_set(struct rtc_time *tmp)
/* Encode these time values into our RTC_STAT register */
bfin_write_RTC_STAT(SET_ALARM(days, hrs, mins, secs));
+
+ return 0;
}
/* Read the time from the RTC_STAT. time_in_seconds is seconds since Jan 1970 */
@@ -98,6 +100,7 @@ int rtc_get(struct rtc_time *tmp)
return -1;
}
+ rtc_init();
wait_for_complete();
/* Read the RTC_STAT register */
diff --git a/drivers/rtc/ds12887.c b/drivers/rtc/ds12887.c
index fb1825b..25ca133 100644
--- a/drivers/rtc/ds12887.c
+++ b/drivers/rtc/ds12887.c
@@ -154,7 +154,7 @@ else
return 0;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
uchar save_ctrl_b;
uchar sec, min, hour, mday, wday, mon, year;
@@ -202,6 +202,8 @@ void rtc_set (struct rtc_time *tmp)
/* enables the RTC to update the regs */
save_ctrl_b &= ~RTC_CB_SET;
rtc_write(RTC_CONTROL_B, save_ctrl_b);
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/ds1302.c b/drivers/rtc/ds1302.c
index d28a9fd..87ddd01 100644
--- a/drivers/rtc/ds1302.c
+++ b/drivers/rtc/ds1302.c
@@ -287,8 +287,7 @@ rtc_get(struct rtc_time *tmp)
return rel;
}
-void
-rtc_set(struct rtc_time *tmp)
+int rtc_set(struct rtc_time *tmp)
{
struct ds1302_st bbclk;
unsigned char b=0;
@@ -326,6 +325,8 @@ rtc_set(struct rtc_time *tmp)
write_ser_drv(0x8e,&b,1); /* disable write protect */
write_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* write burst */
+
+ return 0;
}
#endif
diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c
index 12528ed..75f88a9 100644
--- a/drivers/rtc/ds1306.c
+++ b/drivers/rtc/ds1306.c
@@ -86,7 +86,7 @@ static void init_spi (void);
/* read clock time from DS1306 and return it in *tmp */
int rtc_get (struct rtc_time *tmp)
{
- volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
unsigned char spi_byte; /* Data Byte */
init_spi (); /* set port B for software SPI */
@@ -141,9 +141,9 @@ int rtc_get (struct rtc_time *tmp)
/* ------------------------------------------------------------------------- */
/* set clock time in DS1306 RTC and in MPC8xx RTC */
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
- volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
init_spi (); /* set port B for software SPI */
@@ -209,6 +209,8 @@ void rtc_set (struct rtc_time *tmp)
debug ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
}
/* ------------------------------------------------------------------------- */
@@ -216,7 +218,7 @@ void rtc_set (struct rtc_time *tmp)
/* Initialize Port B for software SPI */
static void init_spi (void)
{
- volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
/* Force output pins to begin at logic 0 */
immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
@@ -233,7 +235,7 @@ static void init_spi (void)
/* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
static void soft_spi_send (unsigned char n)
{
- volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
unsigned char bitpos; /* bit position to receive */
unsigned char i; /* Loop Control */
@@ -262,7 +264,7 @@ static void soft_spi_send (unsigned char n)
/* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
static unsigned char soft_spi_read (void)
{
- volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
unsigned char spi_byte = 0; /* Return value, assume success */
unsigned char bitpos; /* bit position to receive */
@@ -312,7 +314,7 @@ int rtc_get (struct rtc_time *tmp)
* step just once.
*/
if (!slave) {
- slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000,
+ slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
SPI_MODE_3 | SPI_CS_HIGH);
if (!slave)
return;
@@ -371,11 +373,11 @@ int rtc_get (struct rtc_time *tmp)
/* ------------------------------------------------------------------------- */
/* set clock time from *tmp in DS1306 RTC */
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
/* Assuming Vcc = 2.0V (lowest speed) */
if (!slave) {
- slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000,
+ slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
SPI_MODE_3 | SPI_CS_HIGH);
if (!slave)
return;
@@ -406,7 +408,7 @@ void rtc_reset (void)
{
/* Assuming Vcc = 2.0V (lowest speed) */
if (!slave) {
- slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000,
+ slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
SPI_MODE_3 | SPI_CS_HIGH);
if (!slave)
return;
diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c
index 11fc14f..0650d91 100644
--- a/drivers/rtc/ds1307.c
+++ b/drivers/rtc/ds1307.c
@@ -47,11 +47,11 @@
#endif
/*---------------------------------------------------------------------*/
-#ifndef CFG_I2C_RTC_ADDR
-# define CFG_I2C_RTC_ADDR 0x68
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+# define CONFIG_SYS_I2C_RTC_ADDR 0x68
#endif
-#if defined(CONFIG_RTC_DS1307) && (CFG_I2C_SPEED > 100000)
+#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000)
# error The DS1307 is specified only up to 100kHz!
#endif
@@ -128,7 +128,7 @@ int rtc_get (struct rtc_time *tmp)
/*
* Set the RTC
*/
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -144,6 +144,8 @@ void rtc_set (struct rtc_time *tmp)
rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+
+ return 0;
}
@@ -185,13 +187,13 @@ void rtc_reset (void)
static
uchar rtc_read (uchar reg)
{
- return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg));
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
}
static void rtc_write (uchar reg, uchar val)
{
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
static unsigned bcd2bin (uchar n)
diff --git a/drivers/rtc/ds1337.c b/drivers/rtc/ds1337.c
index df1132a..58e3966 100644
--- a/drivers/rtc/ds1337.c
+++ b/drivers/rtc/ds1337.c
@@ -132,7 +132,7 @@ int rtc_get (struct rtc_time *tmp)
/*
* Set the RTC
*/
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
uchar century;
@@ -150,6 +150,8 @@ void rtc_set (struct rtc_time *tmp)
rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+
+ return 0;
}
@@ -158,10 +160,10 @@ void rtc_set (struct rtc_time *tmp)
* SQW/INTB* pin and program it for 32,768 Hz output. Note that
* according to the datasheet, turning on the square wave output
* increases the current drain on the backup battery from about
- * 600 nA to 2uA. Define CFG_RTC_DS1337_NOOSC if you wish to turn
+ * 600 nA to 2uA. Define CONFIG_SYS_RTC_DS1337_NOOSC if you wish to turn
* off the OSC output.
*/
-#ifdef CFG_RTC_DS1337_NOOSC
+#ifdef CONFIG_SYS_RTC_DS1337_NOOSC
#define RTC_DS1337_RESET_VAL \
(RTC_CTL_BIT_INTCN | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2)
#else
@@ -180,13 +182,13 @@ void rtc_reset (void)
static
uchar rtc_read (uchar reg)
{
- return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg));
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
}
static void rtc_write (uchar reg, uchar val)
{
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
static unsigned bcd2bin (uchar n)
diff --git a/drivers/rtc/ds1374.c b/drivers/rtc/ds1374.c
index 130588c..d61a228 100644
--- a/drivers/rtc/ds1374.c
+++ b/drivers/rtc/ds1374.c
@@ -48,11 +48,11 @@
#endif
/*---------------------------------------------------------------------*/
-#ifndef CFG_I2C_RTC_ADDR
-# define CFG_I2C_RTC_ADDR 0x68
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+# define CONFIG_SYS_I2C_RTC_ADDR 0x68
#endif
-#if defined(CONFIG_RTC_DS1374) && (CFG_I2C_SPEED > 400000)
+#if defined(CONFIG_RTC_DS1374) && (CONFIG_SYS_I2C_SPEED > 400000)
# error The DS1374 is specified up to 400kHz in fast mode!
#endif
@@ -160,7 +160,7 @@ int rtc_get (struct rtc_time *tm){
/*
* Set the RTC
*/
-void rtc_set (struct rtc_time *tmp){
+int rtc_set (struct rtc_time *tmp){
unsigned long time;
unsigned i;
@@ -186,6 +186,8 @@ void rtc_set (struct rtc_time *tmp){
/* Start clock */
rtc_write(RTC_CTL_ADDR, RTC_CTL_BIT_EN_OSC, FALSE);
+
+ return 0;
}
/*
@@ -237,22 +239,22 @@ void rtc_reset (void){
*/
static uchar rtc_read (uchar reg)
{
- return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg));
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
}
static void rtc_write (uchar reg, uchar val, boolean_t set)
{
if (set == TRUE) {
- val |= i2c_reg_read (CFG_I2C_RTC_ADDR, reg);
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ val |= i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
} else {
- val = i2c_reg_read (CFG_I2C_RTC_ADDR, reg) & ~val;
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ val = i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg) & ~val;
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
}
static void rtc_write_raw (uchar reg, uchar val)
{
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
#endif
diff --git a/drivers/rtc/ds1556.c b/drivers/rtc/ds1556.c
index f95f28e..763d22a 100644
--- a/drivers/rtc/ds1556.c
+++ b/drivers/rtc/ds1556.c
@@ -43,7 +43,7 @@ static void rtc_write( unsigned int addr, uchar val);
static uchar bin2bcd (unsigned int n);
static unsigned bcd2bin(uchar c);
-#define RTC_BASE ( CFG_NVRAM_SIZE + CFG_NVRAM_BASE_ADDR )
+#define RTC_BASE ( CONFIG_SYS_NVRAM_SIZE + CONFIG_SYS_NVRAM_BASE_ADDR )
#define RTC_YEAR ( RTC_BASE + 0xf )
#define RTC_MONTH ( RTC_BASE + 0xe )
@@ -120,7 +120,7 @@ int rtc_get( struct rtc_time *tmp )
return 0;
}
-void rtc_set( struct rtc_time *tmp )
+int rtc_set( struct rtc_time *tmp )
{
uchar reg_a;
#ifdef RTC_DEBUG
@@ -146,6 +146,8 @@ void rtc_set( struct rtc_time *tmp )
/* unlock clock registers after read */
rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/ds164x.c b/drivers/rtc/ds164x.c
index c621a9e..1e96679 100644
--- a/drivers/rtc/ds164x.c
+++ b/drivers/rtc/ds164x.c
@@ -49,7 +49,7 @@ static unsigned bcd2bin(uchar c);
/*
* DS164x registers layout
*/
-#define RTC_BASE ( CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE )
+#define RTC_BASE ( CONFIG_SYS_NVRAM_BASE_ADDR + CONFIG_SYS_NVRAM_SIZE )
#define RTC_YEAR ( RTC_BASE + 0x07 )
#define RTC_MONTH ( RTC_BASE + 0x06 )
@@ -119,7 +119,7 @@ int rtc_get( struct rtc_time *tmp )
return 0;
}
-void rtc_set( struct rtc_time *tmp )
+int rtc_set( struct rtc_time *tmp )
{
uchar reg_a;
@@ -145,6 +145,8 @@ void rtc_set( struct rtc_time *tmp )
/* unlock clock registers after read */
rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/ds174x.c b/drivers/rtc/ds174x.c
index 3f486b1..738d118 100644
--- a/drivers/rtc/ds174x.c
+++ b/drivers/rtc/ds174x.c
@@ -40,7 +40,7 @@ static void rtc_write( unsigned int addr, uchar val);
static uchar bin2bcd (unsigned int n);
static unsigned bcd2bin(uchar c);
-#define RTC_BASE ( CFG_NVRAM_SIZE + CFG_NVRAM_BASE_ADDR )
+#define RTC_BASE ( CONFIG_SYS_NVRAM_SIZE + CONFIG_SYS_NVRAM_BASE_ADDR )
#define RTC_YEAR ( RTC_BASE + 7 )
#define RTC_MONTH ( RTC_BASE + 6 )
@@ -117,7 +117,7 @@ int rtc_get( struct rtc_time *tmp )
return 0;
}
-void rtc_set( struct rtc_time *tmp )
+int rtc_set( struct rtc_time *tmp )
{
uchar reg_a;
#ifdef RTC_DEBUG
@@ -143,6 +143,8 @@ void rtc_set( struct rtc_time *tmp )
/* unlock clock registers after read */
rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/ds3231.c b/drivers/rtc/ds3231.c
index d8cd47d..ef03358 100644
--- a/drivers/rtc/ds3231.c
+++ b/drivers/rtc/ds3231.c
@@ -134,7 +134,7 @@ int rtc_get (struct rtc_time *tmp)
/*
* Set the RTC
*/
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
uchar century;
@@ -152,6 +152,8 @@ void rtc_set (struct rtc_time *tmp)
rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+
+ return 0;
}
@@ -175,13 +177,13 @@ void rtc_reset (void)
static
uchar rtc_read (uchar reg)
{
- return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg));
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
}
static void rtc_write (uchar reg, uchar val)
{
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
static unsigned bcd2bin (uchar n)
diff --git a/drivers/rtc/isl1208.c b/drivers/rtc/isl1208.c
index 3d46fd0..71f63d5 100644
--- a/drivers/rtc/isl1208.c
+++ b/drivers/rtc/isl1208.c
@@ -118,7 +118,7 @@ int rtc_get (struct rtc_time *tmp)
/*
* Set the RTC
*/
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -139,6 +139,8 @@ void rtc_set (struct rtc_time *tmp)
/* disable write */
rtc_write(RTC_STAT_REG_ADDR,
rtc_read(RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_WRTC);
+
+ return 0;
}
void rtc_reset (void)
@@ -151,12 +153,12 @@ void rtc_reset (void)
static uchar rtc_read (uchar reg)
{
- return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg));
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
}
static void rtc_write (uchar reg, uchar val)
{
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
static unsigned bcd2bin (uchar n)
diff --git a/drivers/rtc/m41t11.c b/drivers/rtc/m41t11.c
index 3727310..3a77c1b 100644
--- a/drivers/rtc/m41t11.c
+++ b/drivers/rtc/m41t11.c
@@ -35,15 +35,15 @@
is what should be done.
#define CONFIG_RTC_M41T11 1
-#define CFG_I2C_RTC_ADDR 0x68
+#define CONFIG_SYS_I2C_RTC_ADDR 0x68
#if 0
-#define CFG_M41T11_EXT_CENTURY_DATA
+#define CONFIG_SYS_M41T11_EXT_CENTURY_DATA
#else
-#define CFG_M41T11_BASE_YEAR 2000
+#define CONFIG_SYS_M41T11_BASE_YEAR 2000
#endif
*/
-#if defined(CFG_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE)
+#if defined(CONFIG_SYS_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE)
static unsigned bcd2bin (uchar n)
{
@@ -75,7 +75,7 @@ static unsigned char bin2bcd (unsigned int n)
#define RTC_CONTROL_ADDR 0x7
-#ifndef CFG_M41T11_EXT_CENTURY_DATA
+#ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA
#define REG_CNT (RTC_REG_CNT+1)
@@ -83,8 +83,8 @@ static unsigned char bin2bcd (unsigned int n)
you only get 00-99 for the year we will asume you
want from the year 2000 if you don't set the config
*/
-#ifndef CFG_M41T11_BASE_YEAR
-#define CFG_M41T11_BASE_YEAR 2000
+#ifndef CONFIG_SYS_M41T11_BASE_YEAR
+#define CONFIG_SYS_M41T11_BASE_YEAR 2000
#endif
#else
@@ -101,7 +101,7 @@ int rtc_get (struct rtc_time *tmp)
int rel = 0;
uchar data[RTC_REG_CNT];
- i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
if( data[RTC_SEC_ADDR] & 0x80 ){
printf( "m41t11 RTC Clock stopped!!!\n" );
@@ -112,14 +112,14 @@ int rtc_get (struct rtc_time *tmp)
tmp->tm_hour = bcd2bin (data[RTC_HOUR_ADDR] & 0x3F);
tmp->tm_mday = bcd2bin (data[RTC_DATE_ADDR] & 0x3F);
tmp->tm_mon = bcd2bin (data[RTC_MONTH_ADDR]& 0x1F);
-#ifndef CFG_M41T11_EXT_CENTURY_DATA
- tmp->tm_year = CFG_M41T11_BASE_YEAR
+#ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA
+ tmp->tm_year = CONFIG_SYS_M41T11_BASE_YEAR
+ bcd2bin(data[RTC_YEARS_ADDR])
+ ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0);
#else
{
unsigned char cent;
- i2c_read(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
if( !(data[RTC_HOUR_ADDR] & 0x80) ){
printf( "m41t11 RTC: cann't keep track of years without CEB set\n" );
rel = -1;
@@ -127,7 +127,7 @@ int rtc_get (struct rtc_time *tmp)
if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){
/*century flip store off new year*/
cent += 1;
- i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
}
tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]);
}
@@ -143,7 +143,7 @@ int rtc_get (struct rtc_time *tmp)
return rel;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
uchar data[RTC_REG_CNT];
@@ -161,34 +161,36 @@ void rtc_set (struct rtc_time *tmp)
data[RTC_HOUR_ADDR] |= 0x80;/*we will always use CEB*/
data[RTC_YEARS_ADDR] = bin2bcd(tmp->tm_year%100);/*same thing either way*/
-#ifndef CFG_M41T11_EXT_CENTURY_DATA
- if( ((tmp->tm_year - CFG_M41T11_BASE_YEAR) > 200) ||
- (tmp->tm_year < CFG_M41T11_BASE_YEAR) ){
+#ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA
+ if( ((tmp->tm_year - CONFIG_SYS_M41T11_BASE_YEAR) > 200) ||
+ (tmp->tm_year < CONFIG_SYS_M41T11_BASE_YEAR) ){
printf( "m41t11 RTC setting year out of range!!need recompile\n" );
}
- data[RTC_HOUR_ADDR] |= (tmp->tm_year - CFG_M41T11_BASE_YEAR) > 100 ? 0x40 : 0;
+ data[RTC_HOUR_ADDR] |= (tmp->tm_year - CONFIG_SYS_M41T11_BASE_YEAR) > 100 ? 0x40 : 0;
#else
{
unsigned char cent;
cent = tmp->tm_year ? tmp->tm_year / 100 : 0;
data[RTC_HOUR_ADDR] |= (cent & 0x1) ? 0x40 : 0;
- i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
}
#endif
- i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+
+ return 0;
}
void rtc_reset (void)
{
unsigned char val;
/* clear all control & status registers */
- i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1);
val = val & 0x7F;/*make sure we are running*/
- i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT);
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT);
- i2c_read(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
val = val & 0x3F;/*turn off freq test keep calibration*/
- i2c_write(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
}
int rtc_store(int addr, unsigned char* data, int size)
@@ -196,12 +198,12 @@ int rtc_store(int addr, unsigned char* data, int size)
/*don't let things wrap onto the time on a write*/
if( (addr+size) >= M41T11_STORAGE_SZ )
return 1;
- return i2c_write( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
+ return i2c_write( CONFIG_SYS_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
}
int rtc_recall(int addr, unsigned char* data, int size)
{
- return i2c_read( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
+ return i2c_read( CONFIG_SYS_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
}
#endif
diff --git a/drivers/rtc/m41t60.c b/drivers/rtc/m41t60.c
index 402a8c8..e34a5f4 100644
--- a/drivers/rtc/m41t60.c
+++ b/drivers/rtc/m41t60.c
@@ -34,7 +34,7 @@
#include <rtc.h>
#include <i2c.h>
-#if defined(CFG_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE)
+#if defined(CONFIG_SYS_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE)
static unsigned bcd2bin(uchar n)
{
@@ -85,7 +85,7 @@ static void rtc_dump(char const *const label)
{
uchar data[8];
- if (i2c_read(CFG_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
+ if (i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
printf("I2C read failed in rtc_dump()\n");
return;
}
@@ -114,7 +114,7 @@ static uchar *rtc_validate(void)
uchar min, date, month, years;
rtc_dump("begin validate");
- if (i2c_read(CFG_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
+ if (i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
printf("I2C read failed in rtc_validate()\n");
return 0;
}
@@ -125,7 +125,7 @@ static uchar *rtc_validate(void)
if (0x00 != (data[RTC_CTRL] & 0x80)) {
printf("M41T60 RTC clock lost power.\n");
data[RTC_SEC] = 0x80;
- if (i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC, 1, data, 1)) {
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC, 1, data, 1)) {
printf("I2C write failed in rtc_validate()\n");
return 0;
}
@@ -161,7 +161,7 @@ static uchar *rtc_validate(void)
data[RTC_YEAR] = 0x00;
data[RTC_CTRL] &= 0x7F; /* reset OUT bit */
- if (i2c_write(CFG_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
printf("I2C write failed in rtc_validate()\n");
return 0;
}
@@ -193,12 +193,12 @@ int rtc_get(struct rtc_time *tmp)
return 0;
}
-void rtc_set(struct rtc_time *tmp)
+int rtc_set(struct rtc_time *tmp)
{
uchar *const data = rtc_validate();
if (!data)
- return;
+ return -1;
debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -212,10 +212,12 @@ void rtc_set(struct rtc_time *tmp)
data[RTC_YEAR] = bin2bcd(tmp->tm_year % 100);
data[RTC_MONTH] |= year2cb(tmp->tm_year) << 6;
data[RTC_DAY] = bin2bcd(tmp->tm_wday + 1) & 0x07;
- if (i2c_write(CFG_I2C_RTC_ADDR, 0, 1, data, RTC_REG_CNT)) {
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, RTC_REG_CNT)) {
printf("I2C write failed in rtc_set()\n");
- return;
+ return -1;
}
+
+ return 0;
}
void rtc_reset(void)
@@ -253,10 +255,10 @@ void rtc_reset(void)
* Turn off frequency test.
*/
data[RTC_CTRL] &= 0xBF;
- if (i2c_write(CFG_I2C_RTC_ADDR, RTC_CTRL, 1, data + RTC_CTRL, 1)) {
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_CTRL, 1, data + RTC_CTRL, 1)) {
printf("I2C write failed in rtc_reset()\n");
return;
}
rtc_dump("end reset");
}
-#endif /* CONFIG_RTC_M41T60 && CFG_I2C_RTC_ADDR && CONFIG_CMD_DATE */
+#endif /* CONFIG_RTC_M41T60 && CONFIG_SYS_I2C_RTC_ADDR && CONFIG_CMD_DATE */
diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c
index 89d4ccd..cfe84f9 100644
--- a/drivers/rtc/m41t62.c
+++ b/drivers/rtc/m41t62.c
@@ -68,7 +68,7 @@ int rtc_get(struct rtc_time *tm)
{
u8 buf[M41T62_DATETIME_REG_SIZE];
- i2c_read(CFG_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE);
debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
@@ -96,7 +96,7 @@ int rtc_get(struct rtc_time *tm)
return 0;
}
-void rtc_set(struct rtc_time *tm)
+int rtc_set(struct rtc_time *tm)
{
u8 buf[M41T62_DATETIME_REG_SIZE];
@@ -104,7 +104,7 @@ void rtc_set(struct rtc_time *tm)
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
- i2c_read(CFG_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE);
/* Merge time-data and register flags into buf[0..7] */
buf[M41T62_REG_SSEC] = 0;
@@ -123,8 +123,12 @@ void rtc_set(struct rtc_time *tm)
/* assume 20YY not 19YY */
buf[M41T62_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
- if (i2c_write(CFG_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE))
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE)) {
printf("I2C write failed in %s()\n", __func__);
+ return -1;
+ }
+
+ return 0;
}
void rtc_reset(void)
diff --git a/drivers/rtc/m48t35ax.c b/drivers/rtc/m48t35ax.c
index 353a30e..1482edd 100644
--- a/drivers/rtc/m48t35ax.c
+++ b/drivers/rtc/m48t35ax.c
@@ -87,7 +87,7 @@ int rtc_get (struct rtc_time *tmp)
return 0;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
uchar ccr; /* Clock control register */
uchar century;
@@ -116,6 +116,8 @@ void rtc_set (struct rtc_time *tmp)
ccr = rtc_read(0);
ccr = ccr & 0x7F;
rtc_write(0, ccr);
+
+ return 0;
}
void rtc_reset (void)
@@ -145,14 +147,14 @@ static uchar rtc_read (uchar reg)
{
uchar val;
val = *(unsigned char *)
- ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg);
+ ((CONFIG_SYS_NVRAM_BASE_ADDR + CONFIG_SYS_NVRAM_SIZE - 8) + reg);
return val;
}
static void rtc_write (uchar reg, uchar val)
{
*(unsigned char *)
- ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg) = val;
+ ((CONFIG_SYS_NVRAM_BASE_ADDR + CONFIG_SYS_NVRAM_SIZE - 8) + reg) = val;
}
static unsigned bcd2bin (uchar n)
diff --git a/drivers/rtc/max6900.c b/drivers/rtc/max6900.c
index 4cfc5de..7c99c5e 100644
--- a/drivers/rtc/max6900.c
+++ b/drivers/rtc/max6900.c
@@ -34,20 +34,20 @@
#if defined(CONFIG_CMD_DATE)
-#ifndef CFG_I2C_RTC_ADDR
-#define CFG_I2C_RTC_ADDR 0x50
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+#define CONFIG_SYS_I2C_RTC_ADDR 0x50
#endif
/* ------------------------------------------------------------------------- */
static uchar rtc_read (uchar reg)
{
- return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg));
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
}
static void rtc_write (uchar reg, uchar val)
{
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
udelay(2500);
}
@@ -107,7 +107,7 @@ int rtc_get (struct rtc_time *tmp)
return 0;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
@@ -124,6 +124,8 @@ void rtc_set (struct rtc_time *tmp)
rtc_write (0x84, bin2bcd(tmp->tm_hour));
rtc_write (0x82, bin2bcd(tmp->tm_min ));
rtc_write (0x80, bin2bcd(tmp->tm_sec ));
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/mc13783-rtc.c b/drivers/rtc/mc13783-rtc.c
index b6e1501..05db2f1 100644
--- a/drivers/rtc/mc13783-rtc.c
+++ b/drivers/rtc/mc13783-rtc.c
@@ -34,7 +34,8 @@ int rtc_get(struct rtc_time *rtc)
if (!slave) {
/* FIXME: Verify the max SCK rate */
- slave = spi_setup_slave(1, 0, 1000000,
+ slave = spi_setup_slave(CONFIG_MC13783_SPI_BUS,
+ CONFIG_MC13783_SPI_CS, 1000000,
SPI_MODE_2 | SPI_CS_HIGH);
if (!slave)
return -1;
@@ -77,16 +78,17 @@ int rtc_get(struct rtc_time *rtc)
return 0;
}
-void rtc_set(struct rtc_time *rtc)
+int rtc_set(struct rtc_time *rtc)
{
u32 time, day, reg;
if (!slave) {
/* FIXME: Verify the max SCK rate */
- slave = spi_setup_slave(1, 0, 1000000,
+ slave = spi_setup_slave(CONFIG_MC13783_SPI_BUS,
+ CONFIG_MC13783_SPI_CS, 1000000,
SPI_MODE_2 | SPI_CS_HIGH);
if (!slave)
- return;
+ return -1;
}
time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday,
@@ -95,7 +97,7 @@ void rtc_set(struct rtc_time *rtc)
time %= 86400;
if (spi_claim_bus(slave))
- return;
+ return -1;
reg = 0x2c000000 | day | 0x80000000;
spi_xfer(slave, 32, (uchar *)&reg, (uchar *)&day,
@@ -106,6 +108,8 @@ void rtc_set(struct rtc_time *rtc)
SPI_XFER_BEGIN | SPI_XFER_END);
spi_release_bus(slave);
+
+ return -1;
}
void rtc_reset(void)
diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c
index 460a0e6..38484ce 100644
--- a/drivers/rtc/mc146818.c
+++ b/drivers/rtc/mc146818.c
@@ -38,7 +38,7 @@ static void rtc_write (uchar reg, uchar val);
static uchar bin2bcd (unsigned int n);
static unsigned bcd2bin(uchar c);
-#define RTC_PORT_MC146818 CFG_ISA_IO_BASE_ADDRESS + 0x70
+#define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70
#define RTC_SECONDS 0x00
#define RTC_SECONDS_ALARM 0x01
#define RTC_MINUTES 0x02
@@ -105,7 +105,7 @@ int rtc_get (struct rtc_time *tmp)
return 0;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
#ifdef RTC_DEBUG
printf ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
@@ -127,6 +127,7 @@ void rtc_set (struct rtc_time *tmp)
rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec ));
rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
+ return 0;
}
void rtc_reset (void)
@@ -140,18 +141,18 @@ void rtc_reset (void)
/* ------------------------------------------------------------------------- */
-#ifdef CFG_RTC_REG_BASE_ADDR
+#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
/*
* use direct memory access
*/
static uchar rtc_read (uchar reg)
{
- return(in8(CFG_RTC_REG_BASE_ADDR+reg));
+ return(in8(CONFIG_SYS_RTC_REG_BASE_ADDR+reg));
}
static void rtc_write (uchar reg, uchar val)
{
- out8(CFG_RTC_REG_BASE_ADDR+reg, val);
+ out8(CONFIG_SYS_RTC_REG_BASE_ADDR+reg, val);
}
#else
static uchar rtc_read (uchar reg)
diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c
index 30b2a81..979c466 100644
--- a/drivers/rtc/mcfrtc.c
+++ b/drivers/rtc/mcfrtc.c
@@ -32,7 +32,7 @@
#undef RTC_DEBUG
-#ifndef CFG_MCFRTC_BASE
+#ifndef CONFIG_SYS_MCFRTC_BASE
#error RTC_BASE is not defined!
#endif
@@ -41,7 +41,7 @@
int rtc_get(struct rtc_time *tmp)
{
- volatile rtc_t *rtc = (rtc_t *) (CFG_MCFRTC_BASE);
+ volatile rtc_t *rtc = (rtc_t *) (CONFIG_SYS_MCFRTC_BASE);
int rtc_days, rtc_hrs, rtc_mins;
int tim;
@@ -68,9 +68,9 @@ int rtc_get(struct rtc_time *tmp)
return 0;
}
-void rtc_set(struct rtc_time *tmp)
+int rtc_set(struct rtc_time *tmp)
{
- volatile rtc_t *rtc = (rtc_t *) (CFG_MCFRTC_BASE);
+ volatile rtc_t *rtc = (rtc_t *) (CONFIG_SYS_MCFRTC_BASE);
static int month_days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
@@ -106,11 +106,13 @@ void rtc_set(struct rtc_time *tmp)
rtc->days = days;
rtc->hourmin = (tmp->tm_hour << 8) | tmp->tm_min;
rtc->seconds = tmp->tm_sec;
+
+ return 0;
}
void rtc_reset(void)
{
- volatile rtc_t *rtc = (rtc_t *) (CFG_MCFRTC_BASE);
+ volatile rtc_t *rtc = (rtc_t *) (CONFIG_SYS_MCFRTC_BASE);
if ((rtc->cr & RTC_CR_EN) == 0) {
printf("real-time-clock was stopped. Now starting...\n");
diff --git a/drivers/rtc/mk48t59.c b/drivers/rtc/mk48t59.c
index 918c291..dabf322 100644
--- a/drivers/rtc/mk48t59.c
+++ b/drivers/rtc/mk48t59.c
@@ -185,7 +185,7 @@ int rtc_get (struct rtc_time *tmp)
return 0;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
uchar save_ctrl_a;
@@ -210,6 +210,8 @@ void rtc_set (struct rtc_time *tmp)
save_ctrl_a &= ~RTC_CA_WRITE;
rtc_write(RTC_CONTROLA, save_ctrl_a); /* enables the RTC to update the regs */
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/mpc5xxx.c b/drivers/rtc/mpc5xxx.c
index 1450649..ec0b0ef 100644
--- a/drivers/rtc/mpc5xxx.c
+++ b/drivers/rtc/mpc5xxx.c
@@ -57,7 +57,7 @@ typedef struct rtc5200 {
*****************************************************************************/
int rtc_get (struct rtc_time *tmp)
{
- RTC5200 *rtc = (RTC5200 *) (CFG_MBAR+0x800);
+ RTC5200 *rtc = (RTC5200 *) (CONFIG_SYS_MBAR+0x800);
ulong time, date, time2;
/* read twice to avoid getting a funny time when the second is just changing */
@@ -88,9 +88,9 @@ int rtc_get (struct rtc_time *tmp)
/*****************************************************************************
* set time
*****************************************************************************/
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
- RTC5200 *rtc = (RTC5200 *) (CFG_MBAR+0x800);
+ RTC5200 *rtc = (RTC5200 *) (CONFIG_SYS_MBAR+0x800);
ulong time, date, year;
debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
@@ -129,6 +129,8 @@ void rtc_set (struct rtc_time *tmp)
udelay (1000);
rtc->tsr = time;
udelay (1000);
+
+ return 0;
}
/*****************************************************************************
diff --git a/drivers/rtc/mpc8xx.c b/drivers/rtc/mpc8xx.c
index 9435069..1c24e59 100644
--- a/drivers/rtc/mpc8xx.c
+++ b/drivers/rtc/mpc8xx.c
@@ -37,7 +37,7 @@
int rtc_get (struct rtc_time *tmp)
{
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
ulong tim;
tim = immr->im_sit.sit_rtc;
@@ -51,9 +51,9 @@ int rtc_get (struct rtc_time *tmp)
return 0;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
ulong tim;
debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
@@ -65,6 +65,8 @@ void rtc_set (struct rtc_time *tmp)
immr->im_sitk.sitk_rtck = KAPWR_KEY;
immr->im_sit.sit_rtc = tim;
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/pcf8563.c b/drivers/rtc/pcf8563.c
index 1274ffa..cd9fb65 100644
--- a/drivers/rtc/pcf8563.c
+++ b/drivers/rtc/pcf8563.c
@@ -86,7 +86,7 @@ int rtc_get (struct rtc_time *tmp)
return rel;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
uchar century;
@@ -104,6 +104,8 @@ void rtc_set (struct rtc_time *tmp)
rtc_write (0x04, bin2bcd(tmp->tm_hour));
rtc_write (0x03, bin2bcd(tmp->tm_min ));
rtc_write (0x02, bin2bcd(tmp->tm_sec ));
+
+ return 0;
}
void rtc_reset (void)
@@ -127,12 +129,12 @@ void rtc_reset (void)
static uchar rtc_read (uchar reg)
{
- return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg));
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
}
static void rtc_write (uchar reg, uchar val)
{
- i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
}
static unsigned bcd2bin (uchar n)
diff --git a/drivers/rtc/pl031.c b/drivers/rtc/pl031.c
index 276c184..8b2b174 100755..100644
--- a/drivers/rtc/pl031.c
+++ b/drivers/rtc/pl031.c
@@ -29,8 +29,8 @@
#if defined(CONFIG_CMD_DATE)
-#ifndef CFG_RTC_PL031_BASE
-#error CFG_RTC_PL031_BASE is not defined!
+#ifndef CONFIG_SYS_RTC_PL031_BASE
+#error CONFIG_SYS_RTC_PL031_BASE is not defined!
#endif
/*
@@ -48,9 +48,9 @@
#define RTC_CR_START (1 << 0)
#define RTC_WRITE_REG(addr, val) \
- (*(volatile unsigned int *)(CFG_RTC_PL031_BASE + (addr)) = (val))
+ (*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)) = (val))
#define RTC_READ_REG(addr) \
- (*(volatile unsigned int *)(CFG_RTC_PL031_BASE + (addr)))
+ (*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)))
static int pl031_initted = 0;
@@ -75,7 +75,7 @@ void rtc_reset(void)
/*
* Set the RTC
*/
-void rtc_set(struct rtc_time *tmp)
+int rtc_set(struct rtc_time *tmp)
{
unsigned long tim;
@@ -84,7 +84,7 @@ void rtc_set(struct rtc_time *tmp)
if (tmp == NULL) {
puts("Error setting the date/time\n");
- return;
+ return -1;
}
/* Calculate number of seconds this incoming time represents */
@@ -92,6 +92,8 @@ void rtc_set(struct rtc_time *tmp)
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
RTC_WRITE_REG(RTC_LR, tim);
+
+ return -1;
}
/*
diff --git a/drivers/rtc/rs5c372.c b/drivers/rtc/rs5c372.c
index 38db199..d6cd7c8 100644
--- a/drivers/rtc/rs5c372.c
+++ b/drivers/rtc/rs5c372.c
@@ -50,8 +50,8 @@ static unsigned int rtc_debug = DEBUG;
#define rtc_debug 0 /* gcc will remove all the debug code for us */
#endif
-#ifndef CFG_I2C_RTC_ADDR
-#define CFG_I2C_RTC_ADDR 0x32
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+#define CONFIG_SYS_I2C_RTC_ADDR 0x32
#endif
#define RS5C372_RAM_SIZE 0x10
@@ -77,7 +77,7 @@ rs5c372_readram(unsigned char *buf, int len)
{
int ret;
- ret = i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, len);
+ ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, len);
if (ret != 0) {
printf("%s: failed to read\n", __FUNCTION__);
return ret;
@@ -117,7 +117,7 @@ rs5c372_enable(void)
buf[14] = 0; /* reg. 13 */
buf[15] = 0; /* reg. 14 */
buf[16] = USE_24HOUR_MODE; /* reg. 15 */
- ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1);
+ ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1);
if (ret != 0) {
printf("%s: failed\n", __FUNCTION__);
return;
@@ -195,8 +195,7 @@ rtc_get (struct rtc_time *tmp)
/*
* Set the RTC
*/
-void
-rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
unsigned char buf[8], reg15;
int ret;
@@ -205,7 +204,7 @@ rtc_set (struct rtc_time *tmp)
rs5c372_enable();
if (!setup_done)
- return;
+ return -1;
if(rtc_debug > 2) {
printf("rtc_set: tm_year = %d\n", tmp->tm_year);
@@ -219,7 +218,7 @@ rtc_set (struct rtc_time *tmp)
memset(buf, 0, sizeof(buf));
/* only read register 15 */
- ret = i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, 1);
+ ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 1);
if (ret == 0) {
/* need to save register 15 */
@@ -248,12 +247,16 @@ rtc_set (struct rtc_time *tmp)
printf("WARNING: year should be between 1970 and 2069!\n");
buf[7] = bin2bcd(tmp->tm_year % 100);
- ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, 8);
- if (ret != 0)
+ ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 8);
+ if (ret != 0) {
printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret);
+ return -1;
+ }
+ } else {
+ return -1;
}
- return;
+ return 0;
}
/*
diff --git a/drivers/rtc/rx8025.c b/drivers/rtc/rx8025.c
index 064138e..da87394 100644
--- a/drivers/rtc/rx8025.c
+++ b/drivers/rtc/rx8025.c
@@ -42,8 +42,8 @@
#endif
/*---------------------------------------------------------------------*/
-#ifndef CFG_I2C_RTC_ADDR
-# define CFG_I2C_RTC_ADDR 0x32
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+# define CONFIG_SYS_I2C_RTC_ADDR 0x32
#endif
/*
@@ -102,7 +102,7 @@ int rtc_get (struct rtc_time *tmp)
uchar sec, min, hour, mday, wday, mon, year, ctl2;
uchar buf[16];
- if (i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, 16))
+ if (i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 16))
printf("Error reading from RTC\n");
sec = rtc_read(RTC_SEC_REG_ADDR);
@@ -136,7 +136,11 @@ int rtc_get (struct rtc_time *tmp)
tmp->tm_sec = bcd2bin (sec & 0x7F);
tmp->tm_min = bcd2bin (min & 0x7F);
- tmp->tm_hour = bcd2bin (hour & 0x3F);
+ if (rtc_read(RTC_CTL1_REG_ADDR) & RTC_CTL1_BIT_2412)
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ else
+ tmp->tm_hour = bcd2bin (hour & 0x1F) % 12 +
+ ((hour & 0x20) ? 12 : 0);
tmp->tm_mday = bcd2bin (mday & 0x3F);
tmp->tm_mon = bcd2bin (mon & 0x1F);
tmp->tm_year = bcd2bin (year) + ( bcd2bin (year) >= 70 ? 1900 : 2000);
@@ -154,7 +158,7 @@ int rtc_get (struct rtc_time *tmp)
/*
* Set the RTC
*/
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -172,6 +176,8 @@ void rtc_set (struct rtc_time *tmp)
rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
rtc_write (RTC_CTL1_REG_ADDR, RTC_CTL1_BIT_2412);
+
+ return 0;
}
/*
@@ -183,7 +189,7 @@ void rtc_reset (void)
uchar buf[16];
uchar ctl2;
- if (i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, 16))
+ if (i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 16))
printf("Error reading from RTC\n");
ctl2 = rtc_read(RTC_CTL2_REG_ADDR);
@@ -215,7 +221,7 @@ static void rtc_write (uchar reg, uchar val)
uchar buf[2];
buf[0] = reg << 4;
buf[1] = val;
- if (i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, 2) != 0)
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 2) != 0)
printf("Error writing to RTC\n");
}
diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c
index 13d077b..0d3372f 100644
--- a/drivers/rtc/s3c24x0_rtc.c
+++ b/drivers/rtc/s3c24x0_rtc.c
@@ -135,7 +135,7 @@ int rtc_get (struct rtc_time *tmp)
return 0;
}
-void rtc_set (struct rtc_time *tmp)
+int rtc_set (struct rtc_time *tmp)
{
S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC();
uchar sec, min, hour, mday, wday, mon, year;
@@ -167,6 +167,8 @@ void rtc_set (struct rtc_time *tmp)
/* disable access to RTC registers */
SetRTC_Access(RTC_DISABLE);
+
+ return 0;
}
void rtc_reset (void)
diff --git a/drivers/rtc/x1205.c b/drivers/rtc/x1205.c
index 7025cf4..56115b0 100644
--- a/drivers/rtc/x1205.c
+++ b/drivers/rtc/x1205.c
@@ -96,7 +96,7 @@
static void rtc_write(int reg, u8 val)
{
- i2c_write(CFG_I2C_RTC_ADDR, reg, 2, &val, 1);
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, reg, 2, &val, 1);
}
/*
@@ -108,7 +108,7 @@ int rtc_get(struct rtc_time *tm)
{
u8 buf[8];
- i2c_read(CFG_I2C_RTC_ADDR, X1205_CCR_BASE, 2, buf, 8);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, X1205_CCR_BASE, 2, buf, 8);
debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
@@ -134,7 +134,7 @@ int rtc_get(struct rtc_time *tm)
return 0;
}
-void rtc_set(struct rtc_time *tm)
+int rtc_set(struct rtc_time *tm)
{
int i;
u8 buf[8];
@@ -168,6 +168,8 @@ void rtc_set(struct rtc_time *tm)
rtc_write(X1205_CCR_BASE + i, buf[i]);
rtc_write(X1205_REG_SR, 0);
+
+ return 0;
}
void rtc_reset(void)
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index f30014d..17235ff 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -33,13 +33,14 @@ COBJS-$(CONFIG_DRIVER_S3C4510_UART) += s3c4510b_uart.o
COBJS-$(CONFIG_S3C64XX) += s3c64xx.o
COBJS-y += serial.o
COBJS-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
-COBJS-y += serial_pl010.o
-COBJS-y += serial_pl011.o
+COBJS-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
+COBJS-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o
COBJS-$(CONFIG_USB_TTY) += usbtty.o
+COBJS-$(CONFIG_VCTH_SERIAL) += vcth.o
-COBJS := $(COBJS-y)
+COBJS := $(sort $(COBJS-y))
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
diff --git a/drivers/serial/mcfuart.c b/drivers/serial/mcfuart.c
index a1fcd05..e04fc29 100644
--- a/drivers/serial/mcfuart.c
+++ b/drivers/serial/mcfuart.c
@@ -41,7 +41,7 @@ int serial_init(void)
volatile uart_t *uart;
u32 counter;
- uart = (volatile uart_t *)(CFG_UART_BASE);
+ uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
uart_port_conf();
@@ -76,7 +76,7 @@ int serial_init(void)
void serial_putc(const char c)
{
- volatile uart_t *uart = (volatile uart_t *)(CFG_UART_BASE);
+ volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
if (c == '\n')
serial_putc('\r');
@@ -96,7 +96,7 @@ void serial_puts(const char *s)
int serial_getc(void)
{
- volatile uart_t *uart = (volatile uart_t *)(CFG_UART_BASE);
+ volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
/* Wait for a character to arrive. */
while (!(uart->usr & UART_USR_RXRDY)) ;
@@ -105,14 +105,14 @@ int serial_getc(void)
int serial_tstc(void)
{
- volatile uart_t *uart = (volatile uart_t *)(CFG_UART_BASE);
+ volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
return (uart->usr & UART_USR_RXRDY);
}
void serial_setbrg(void)
{
- volatile uart_t *uart = (volatile uart_t *)(CFG_UART_BASE);
+ volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
u32 counter;
counter = ((gd->bus_clk / gd->baudrate)) >> 5;
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 6b3f60e..93c2243 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -1,12 +1,12 @@
/*
* COM1 NS16550 support
* originally from linux source (arch/ppc/boot/ns16550.c)
- * modified to use CFG_ISA_MEM and new defines
+ * modified to use CONFIG_SYS_ISA_MEM and new defines
*/
#include <config.h>
-#ifdef CFG_NS16550
+#ifdef CONFIG_SYS_NS16550
#include <ns16550.h>
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index b361eef..bce7548 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -23,7 +23,7 @@
#include <common.h>
-#ifdef CFG_NS16550_SERIAL
+#ifdef CONFIG_SYS_NS16550_SERIAL
#include <ns16550.h>
#ifdef CONFIG_NS87308
@@ -48,13 +48,13 @@ DECLARE_GLOBAL_DATA_PTR;
#error "Invalid console index value."
#endif
-#if CONFIG_CONS_INDEX == 1 && !defined(CFG_NS16550_COM1)
+#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1)
#error "Console port 1 defined but not configured."
-#elif CONFIG_CONS_INDEX == 2 && !defined(CFG_NS16550_COM2)
+#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2)
#error "Console port 2 defined but not configured."
-#elif CONFIG_CONS_INDEX == 3 && !defined(CFG_NS16550_COM3)
+#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3)
#error "Console port 3 defined but not configured."
-#elif CONFIG_CONS_INDEX == 4 && !defined(CFG_NS16550_COM4)
+#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4)
#error "Console port 4 defined but not configured."
#endif
@@ -62,23 +62,23 @@ DECLARE_GLOBAL_DATA_PTR;
* the array is 0 based.
*/
static NS16550_t serial_ports[4] = {
-#ifdef CFG_NS16550_COM1
- (NS16550_t)CFG_NS16550_COM1,
+#ifdef CONFIG_SYS_NS16550_COM1
+ (NS16550_t)CONFIG_SYS_NS16550_COM1,
#else
NULL,
#endif
-#ifdef CFG_NS16550_COM2
- (NS16550_t)CFG_NS16550_COM2,
+#ifdef CONFIG_SYS_NS16550_COM2
+ (NS16550_t)CONFIG_SYS_NS16550_COM2,
#else
NULL,
#endif
-#ifdef CFG_NS16550_COM3
- (NS16550_t)CFG_NS16550_COM3,
+#ifdef CONFIG_SYS_NS16550_COM3
+ (NS16550_t)CONFIG_SYS_NS16550_COM3,
#else
NULL,
#endif
-#ifdef CFG_NS16550_COM4
- (NS16550_t)CFG_NS16550_COM4
+#ifdef CONFIG_SYS_NS16550_COM4
+ (NS16550_t)CONFIG_SYS_NS16550_COM4
#else
NULL
#endif
@@ -126,7 +126,7 @@ static int calc_divisor (NS16550_t port)
{
#ifdef CONFIG_OMAP1510
/* If can't cleanly clock 115200 set div to 1 */
- if ((CFG_NS16550_CLK == 12000000) && (gd->baudrate == 115200)) {
+ if ((CONFIG_SYS_NS16550_CLK == 12000000) && (gd->baudrate == 115200)) {
port->osc_12m_sel = OSC_12M_SEL; /* enable 6.5 * divisor */
return (1); /* return 1 for base divisor */
}
@@ -134,7 +134,7 @@ static int calc_divisor (NS16550_t port)
#endif
#ifdef CONFIG_OMAP1610
/* If can't cleanly clock 115200 set div to 1 */
- if ((CFG_NS16550_CLK == 48000000) && (gd->baudrate == 115200)) {
+ if ((CONFIG_SYS_NS16550_CLK == 48000000) && (gd->baudrate == 115200)) {
return (26); /* return 26 for base divisor */
}
#endif
@@ -146,11 +146,11 @@ static int calc_divisor (NS16550_t port)
#endif
/* Compute divisor value. Normally, we should simply return:
- * CFG_NS16550_CLK) / MODE_X_DIV / gd->baudrate
+ * CONFIG_SYS_NS16550_CLK) / MODE_X_DIV / gd->baudrate
* but we need to round that value by adding 0.5.
* Rounding is especially important at high baud rates.
*/
- return (CFG_NS16550_CLK + (gd->baudrate * (MODE_X_DIV / 2))) /
+ return (CONFIG_SYS_NS16550_CLK + (gd->baudrate * (MODE_X_DIV / 2))) /
(MODE_X_DIV * gd->baudrate);
}
@@ -163,19 +163,19 @@ int serial_init (void)
initialise_ns87308();
#endif
-#ifdef CFG_NS16550_COM1
+#ifdef CONFIG_SYS_NS16550_COM1
clock_divisor = calc_divisor(serial_ports[0]);
NS16550_init(serial_ports[0], clock_divisor);
#endif
-#ifdef CFG_NS16550_COM2
+#ifdef CONFIG_SYS_NS16550_COM2
clock_divisor = calc_divisor(serial_ports[1]);
NS16550_init(serial_ports[1], clock_divisor);
#endif
-#ifdef CFG_NS16550_COM3
+#ifdef CONFIG_SYS_NS16550_COM3
clock_divisor = calc_divisor(serial_ports[2]);
NS16550_init(serial_ports[2], clock_divisor);
#endif
-#ifdef CFG_NS16550_COM4
+#ifdef CONFIG_SYS_NS16550_COM4
clock_divisor = calc_divisor(serial_ports[3]);
NS16550_init(serial_ports[3], clock_divisor);
#endif
diff --git a/drivers/serial/serial_pl011.c b/drivers/serial/serial_pl011.c
deleted file mode 100644
index 4d35fe5..0000000
--- a/drivers/serial/serial_pl011.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * (C) Copyright 2000
- * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
- *
- * (C) Copyright 2004
- * ARM Ltd.
- * Philippe Robin, <philippe.robin@arm.com>
- *
- * 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
- */
-
-/* Simple U-Boot driver for the PrimeCell PL011 UARTs on the IntegratorCP */
-/* Should be fairly simple to make it work with the PL010 as well */
-
-#include <common.h>
-
-#ifdef CFG_PL011_SERIAL
-
-#include "serial_pl011.h"
-
-#define IO_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (val))
-#define IO_READ(addr) (*(volatile unsigned int *)(addr))
-
-/*
- * IntegratorCP has two UARTs, use the first one, at 38400-8-N-1
- * Versatile PB has four UARTs.
- */
-
-#define CONSOLE_PORT CONFIG_CONS_INDEX
-#define baudRate CONFIG_BAUDRATE
-static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS;
-#define NUM_PORTS (sizeof(port)/sizeof(port[0]))
-
-static void pl011_putc (int portnum, char c);
-static int pl011_getc (int portnum);
-static int pl011_tstc (int portnum);
-
-
-int serial_init (void)
-{
- unsigned int temp;
- unsigned int divider;
- unsigned int remainder;
- unsigned int fraction;
-
- /*
- ** First, disable everything.
- */
- IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR, 0x0);
-
- /*
- ** Set baud rate
- **
- ** IBRD = UART_CLK / (16 * BAUD_RATE)
- ** FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
- */
- temp = 16 * baudRate;
- divider = CONFIG_PL011_CLOCK / temp;
- remainder = CONFIG_PL011_CLOCK % temp;
- temp = (8 * remainder) / baudRate;
- fraction = (temp >> 1) + (temp & 1);
-
- IO_WRITE (port[CONSOLE_PORT] + UART_PL011_IBRD, divider);
- IO_WRITE (port[CONSOLE_PORT] + UART_PL011_FBRD, fraction);
-
- /*
- ** Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled.
- */
- IO_WRITE (port[CONSOLE_PORT] + UART_PL011_LCRH,
- (UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN));
-
- /*
- ** Finally, enable the UART
- */
- IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR,
- (UART_PL011_CR_UARTEN | UART_PL011_CR_TXE |
- UART_PL011_CR_RXE));
-
- return 0;
-}
-
-void serial_putc (const char c)
-{
- if (c == '\n')
- pl011_putc (CONSOLE_PORT, '\r');
-
- pl011_putc (CONSOLE_PORT, c);
-}
-
-void serial_puts (const char *s)
-{
- while (*s) {
- serial_putc (*s++);
- }
-}
-
-int serial_getc (void)
-{
- return pl011_getc (CONSOLE_PORT);
-}
-
-int serial_tstc (void)
-{
- return pl011_tstc (CONSOLE_PORT);
-}
-
-void serial_setbrg (void)
-{
-}
-
-static void pl011_putc (int portnum, char c)
-{
- /* Wait until there is space in the FIFO */
- while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_TXFF);
-
- /* Send the character */
- IO_WRITE (port[portnum] + UART_PL01x_DR, c);
-}
-
-static int pl011_getc (int portnum)
-{
- unsigned int data;
-
- /* Wait until there is data in the FIFO */
- while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_RXFE);
-
- data = IO_READ (port[portnum] + UART_PL01x_DR);
-
- /* Check for an error flag */
- if (data & 0xFFFFFF00) {
- /* Clear the error */
- IO_WRITE (port[portnum] + UART_PL01x_ECR, 0xFFFFFFFF);
- return -1;
- }
-
- return (int) data;
-}
-
-static int pl011_tstc (int portnum)
-{
- return !(IO_READ (port[portnum] + UART_PL01x_FR) &
- UART_PL01x_FR_RXFE);
-}
-
-#endif
diff --git a/drivers/serial/serial_pl010.c b/drivers/serial/serial_pl01x.c
index 134ed09..c645cef 100644
--- a/drivers/serial/serial_pl010.c
+++ b/drivers/serial/serial_pl01x.c
@@ -25,30 +25,31 @@
* MA 02111-1307 USA
*/
-/* Simple U-Boot driver for the PrimeCell PL011 UARTs on the IntegratorCP */
-/* Should be fairly simple to make it work with the PL010 as well */
+/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */
#include <common.h>
#include <watchdog.h>
-#ifdef CFG_PL010_SERIAL
-
-#include "serial_pl011.h"
+#include "serial_pl01x.h"
#define IO_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (val))
#define IO_READ(addr) (*(volatile unsigned int *)(addr))
-/* Integrator AP has two UARTs, we use the first one, at 38400-8-N-1 */
+/*
+ * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1
+ * Integrator CP has two UARTs, use the first one, at 38400-8-N-1
+ * Versatile PB has four UARTs.
+ */
#define CONSOLE_PORT CONFIG_CONS_INDEX
#define baudRate CONFIG_BAUDRATE
static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS;
#define NUM_PORTS (sizeof(port)/sizeof(port[0]))
+static void pl01x_putc (int portnum, char c);
+static int pl01x_getc (int portnum);
+static int pl01x_tstc (int portnum);
-static void pl010_putc (int portnum, char c);
-static int pl010_getc (int portnum);
-static int pl010_tstc (int portnum);
-
+#ifdef CONFIG_PL010_SERIAL
int serial_init (void)
{
@@ -103,15 +104,64 @@ int serial_init (void)
*/
IO_WRITE (port[CONSOLE_PORT] + UART_PL010_CR, (UART_PL010_CR_UARTEN));
- return (0);
+ return 0;
}
+#endif /* CONFIG_PL010_SERIAL */
+
+#ifdef CONFIG_PL011_SERIAL
+
+int serial_init (void)
+{
+ unsigned int temp;
+ unsigned int divider;
+ unsigned int remainder;
+ unsigned int fraction;
+
+ /*
+ ** First, disable everything.
+ */
+ IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR, 0x0);
+
+ /*
+ ** Set baud rate
+ **
+ ** IBRD = UART_CLK / (16 * BAUD_RATE)
+ ** FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
+ */
+ temp = 16 * baudRate;
+ divider = CONFIG_PL011_CLOCK / temp;
+ remainder = CONFIG_PL011_CLOCK % temp;
+ temp = (8 * remainder) / baudRate;
+ fraction = (temp >> 1) + (temp & 1);
+
+ IO_WRITE (port[CONSOLE_PORT] + UART_PL011_IBRD, divider);
+ IO_WRITE (port[CONSOLE_PORT] + UART_PL011_FBRD, fraction);
+
+ /*
+ ** Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled.
+ */
+ IO_WRITE (port[CONSOLE_PORT] + UART_PL011_LCRH,
+ (UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN));
+
+ /*
+ ** Finally, enable the UART
+ */
+ IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR,
+ (UART_PL011_CR_UARTEN | UART_PL011_CR_TXE |
+ UART_PL011_CR_RXE));
+
+ return 0;
+}
+
+#endif /* CONFIG_PL011_SERIAL */
+
void serial_putc (const char c)
{
if (c == '\n')
- pl010_putc (CONSOLE_PORT, '\r');
+ pl01x_putc (CONSOLE_PORT, '\r');
- pl010_putc (CONSOLE_PORT, c);
+ pl01x_putc (CONSOLE_PORT, c);
}
void serial_puts (const char *s)
@@ -123,19 +173,19 @@ void serial_puts (const char *s)
int serial_getc (void)
{
- return pl010_getc (CONSOLE_PORT);
+ return pl01x_getc (CONSOLE_PORT);
}
int serial_tstc (void)
{
- return pl010_tstc (CONSOLE_PORT);
+ return pl01x_tstc (CONSOLE_PORT);
}
void serial_setbrg (void)
{
}
-static void pl010_putc (int portnum, char c)
+static void pl01x_putc (int portnum, char c)
{
/* Wait until there is space in the FIFO */
while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_TXFF)
@@ -145,7 +195,7 @@ static void pl010_putc (int portnum, char c)
IO_WRITE (port[portnum] + UART_PL01x_DR, c);
}
-static int pl010_getc (int portnum)
+static int pl01x_getc (int portnum)
{
unsigned int data;
@@ -165,11 +215,9 @@ static int pl010_getc (int portnum)
return (int) data;
}
-static int pl010_tstc (int portnum)
+static int pl01x_tstc (int portnum)
{
WATCHDOG_RESET();
return !(IO_READ (port[portnum] + UART_PL01x_FR) &
UART_PL01x_FR_RXFE);
}
-
-#endif
diff --git a/drivers/serial/serial_pl011.h b/drivers/serial/serial_pl01x.h
index 5f20fdd..5f20fdd 100644
--- a/drivers/serial/serial_pl011.h
+++ b/drivers/serial/serial_pl01x.h
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index 61c2b82..1d76a19 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -76,7 +76,7 @@
# define FIFOLEVEL_MASK 0xFF
# endif
#elif defined(CONFIG_CPU_SH7723)
-# if defined(CONIFG_SCIF_A)
+# if defined(CONFIG_SCIF_A)
# define SCLSR SCFSR
# define LSR_ORER 0x0200
# define FIFOLEVEL_MASK 0x3F
@@ -94,7 +94,7 @@
# define LSR_ORER 1
# define FIFOLEVEL_MASK 0x1F
#elif defined(CONFIG_CPU_SH7720)
-# define SCLSR (vu_short *)(SCIF_BASE + 0x24)
+# define SCLSR SCFSR
# define LSR_ORER 0x0200
# define FIFOLEVEL_MASK 0x1F
#elif defined(CONFIG_CPU_SH7710) || \
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
index e738c56..7eba470 100644
--- a/drivers/serial/usbtty.c
+++ b/drivers/serial/usbtty.c
@@ -22,16 +22,14 @@
*/
#include <common.h>
-
+#include <config.h>
#include <circbuf.h>
#include <devices.h>
#include "usbtty.h"
#include "usb_cdc_acm.h"
#include "usbdescriptors.h"
-#include <config.h> /* If defined, override Linux identifiers with
- * vendor specific ones */
-#if 0
+#ifdef DEBUG
#define TTYDBG(fmt,args...)\
serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
#else
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index 71c47bc..ecefde5 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -24,11 +24,11 @@
#ifndef __USB_TTY_H__
#define __USB_TTY_H__
-#include "usbdcore.h"
+#include <usbdcore.h>
#if defined(CONFIG_PPC)
-#include "usbdcore_mpc8xx.h"
+#include <usbdcore_mpc8xx.h>
#elif defined(CONFIG_ARM)
-#include "usbdcore_omap1510.h"
+#include <usbdcore_omap1510.h>
#endif
#include <version_autogenerated.h>
@@ -36,14 +36,25 @@
/* If no VendorID/ProductID is defined in config.h, pretend to be Linux
* DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */
-#define CONFIG_USBD_VENDORID 0x0525 /* Linux/NetChip */
-#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6 /* gserial */
-#define CONFIG_USBD_PRODUCTID_CDCACM 0xa4a7 /* CDC ACM */
-#define CONFIG_USBD_MANUFACTURER "Das U-Boot"
-#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION
-
+#ifndef CONFIG_USBD_VENDORID
+#define CONFIG_USBD_VENDORID 0x0525 /* Linux/NetChip */
+#endif
+#ifndef CONFIG_USBD_PRODUCTID_GSERIAL
+#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6 /* gserial */
+#endif
+#ifndef CONFIG_USBD_PRODUCTID_CDCACM
+#define CONFIG_USBD_PRODUCTID_CDCACM 0xa4a7 /* CDC ACM */
+#endif
+#ifndef CONFIG_USBD_MANUFACTURER
+#define CONFIG_USBD_MANUFACTURER "Das U-Boot"
+#endif
+#ifndef CONFIG_USBD_PRODUCT_NAME
+#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION
+#endif
-#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
+#ifndef CONFIG_USBD_CONFIGURATION_STR
+#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
+#endif
#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT
#define CONFIG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE
diff --git a/drivers/serial/vcth.c b/drivers/serial/vcth.c
new file mode 100755
index 0000000..2c847d0
--- /dev/null
+++ b/drivers/serial/vcth.c
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * 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 <config.h>
+#include <common.h>
+#include <asm/io.h>
+
+#define UART_1_BASE 0xBF89C000
+
+#define UART_RBR_OFF 0x00 /* receiver buffer reg */
+#define UART_THR_OFF 0x00 /* transmit holding reg */
+#define UART_DLL_OFF 0x00 /* divisor latch low reg */
+#define UART_IER_OFF 0x04 /* interrupt enable reg */
+#define UART_DLH_OFF 0x04 /* receiver buffer reg */
+#define UART_FCR_OFF 0x08 /* fifo control register */
+#define UART_LCR_OFF 0x0c /* line control register */
+#define UART_MCR_OFF 0x10 /* modem control register */
+#define UART_LSR_OFF 0x14 /* line status register */
+#define UART_MSR_OFF 0x18 /* modem status register */
+#define UART_SCR_OFF 0x1c /* scratch pad register */
+
+#define UART_RCV_DATA_RDY 0x01 /* Data Received */
+#define UART_XMT_HOLD_EMPTY 0x20
+#define UART_TRANSMIT_EMPTY 0x40
+
+/* 7 bit on line control reg. enalbing rw to dll and dlh */
+#define UART_LCR_DLAB 0x0080
+
+#define UART___9600_BDR 0x84
+#define UART__19200_BDR 0x42
+#define UART_115200_BDR 0x08
+
+#define UART_DIS_ALL_INTER 0x00 /* disable all interrupts */
+
+#define UART_5DATA_BITS 0x0000 /* 5 [bits] 1.5 bits 2 */
+#define UART_6DATA_BITS 0x0001 /* 6 [bits] 1 bits 2 */
+#define UART_7DATA_BITS 0x0002 /* 7 [bits] 1 bits 2 */
+#define UART_8DATA_BITS 0x0003 /* 8 [bits] 1 bits 2 */
+
+static void vcth_uart_set_baud_rate(u32 address, u32 dh, u32 dl)
+{
+ u32 val = __raw_readl(UART_1_BASE + UART_LCR_OFF);
+
+ /* set 7 bit on 1 */
+ val |= UART_LCR_DLAB;
+ __raw_writel(val, UART_1_BASE + UART_LCR_OFF);
+
+ __raw_writel(dl, UART_1_BASE + UART_DLL_OFF);
+ __raw_writel(dh, UART_1_BASE + UART_DLH_OFF);
+
+ /* set 7 bit on 0 */
+ val &= ~UART_LCR_DLAB;
+ __raw_writel(val, UART_1_BASE + UART_LCR_OFF);
+
+ return;
+}
+
+int serial_init(void)
+{
+ __raw_writel(UART_DIS_ALL_INTER, UART_1_BASE + UART_IER_OFF);
+ vcth_uart_set_baud_rate(UART_1_BASE, 0, UART_115200_BDR);
+ __raw_writel(UART_8DATA_BITS, UART_1_BASE + UART_LCR_OFF);
+
+ return 0;
+}
+
+void serial_setbrg(void)
+{
+ /*
+ * Baudrate change not supported currently, fixed to 115200 baud
+ */
+}
+
+void serial_putc(const char c)
+{
+ if (c == '\n')
+ serial_putc('\r');
+
+ while (!(UART_XMT_HOLD_EMPTY & __raw_readl(UART_1_BASE + UART_LSR_OFF)))
+ ;
+
+ __raw_writel(c, UART_1_BASE + UART_THR_OFF);
+}
+
+void serial_puts(const char *s)
+{
+ while (*s)
+ serial_putc(*s++);
+}
+
+int serial_getc(void)
+{
+ while (!(UART_RCV_DATA_RDY & __raw_readl(UART_1_BASE + UART_LSR_OFF)))
+ ;
+
+ return __raw_readl(UART_1_BASE + UART_RBR_OFF) & 0xff;
+}
+
+int serial_tstc(void)
+{
+ if (!(UART_RCV_DATA_RDY & __raw_readl(UART_1_BASE + UART_LSR_OFF)))
+ return 0;
+
+ return 1;
+}
diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c
index 9eaf986..c4b36f0 100644
--- a/drivers/spi/mpc8xxx_spi.c
+++ b/drivers/spi/mpc8xxx_spi.c
@@ -67,7 +67,7 @@ void spi_free_slave(struct spi_slave *slave)
void spi_init(void)
{
- volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi;
+ volatile spi8xxx_t *spi = &((immap_t *) (CONFIG_SYS_IMMR))->spi;
/*
* SPI pins on the MPC83xx are not muxed, so all we do is initialize
@@ -94,7 +94,7 @@ void spi_release_bus(struct spi_slave *slave)
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
- volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi;
+ volatile spi8xxx_t *spi = &((immap_t *) (CONFIG_SYS_IMMR))->spi;
unsigned int tmpdout, tmpdin, event;
int numBlks = bitlen / 32 + (bitlen % 32 ? 1 : 0);
int tm, isRead = 0;
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index 25b589a..13df8cb 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -59,7 +59,7 @@ static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
void spi_init (void)
{
#ifdef SPI_INIT
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
SPI_INIT;
#endif
@@ -95,8 +95,8 @@ void spi_free_slave(struct spi_slave *slave)
int spi_claim_bus(struct spi_slave *slave)
{
-#ifdef CFG_IMMR
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#ifdef CONFIG_SYS_IMMR
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
#endif
struct soft_spi_slave *ss = to_soft_spi(slave);
@@ -132,8 +132,8 @@ void spi_release_bus(struct spi_slave *slave)
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
-#ifdef CFG_IMMR
- volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#ifdef CONFIG_SYS_IMMR
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
#endif
struct soft_spi_slave *ss = to_soft_spi(slave);
uchar tmpdin = 0;
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c67a490..856f51a 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -25,15 +25,22 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb.a
+# core
+COBJS-y += usbdcore.o
+COBJS-$(CONFIG_USB_OHCI_NEW) += usb_ohci.o
+
+# host
+COBJS-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
COBJS-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
+COBJS-$(CONFIG_USB_SL811HS) += sl811_usb.o
-COBJS-y += isp116x-hcd.o
-COBJS-y += sl811_usb.o
-COBJS-y += usb_ohci.o
-COBJS-y += usbdcore.o
+# device
+ifdef CONFIG_USB_DEVICE
COBJS-y += usbdcore_ep0.o
-COBJS-y += usbdcore_mpc8xx.o
-COBJS-y += usbdcore_omap1510.o
+COBJS-$(CONFIG_OMAP1510) += usbdcore_omap1510.o
+COBJS-$(CONFIG_OMAP1610) += usbdcore_omap1510.o
+COBJS-$(CONFIG_MPC885_FAMILY) += usbdcore_mpc8xx.o
+endif
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/isp116x-hcd.c b/drivers/usb/isp116x-hcd.c
index 6b9b23b..348e404 100644
--- a/drivers/usb/isp116x-hcd.c
+++ b/drivers/usb/isp116x-hcd.c
@@ -56,8 +56,6 @@
*/
#include <common.h>
-
-#ifdef CONFIG_USB_ISP116X_HCD
#include <asm/io.h>
#include <usb.h>
#include <malloc.h>
@@ -687,7 +685,7 @@ retry_same:
/* Start the data transfer */
/* Allow more time for a BULK device to react - some are slow */
- if (usb_pipetype(pipe) == PIPE_BULK)
+ if (usb_pipebulk(pipe))
timeout = 5000;
else
timeout = 100;
@@ -822,7 +820,7 @@ static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
u16 wIndex;
u16 wLength;
- if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ if (usb_pipeint(pipe)) {
INFO("Root-Hub submit IRQ: NOT implemented");
return 0;
}
@@ -1441,5 +1439,3 @@ int usb_lowlevel_stop(void)
return 0;
}
-
-#endif /* CONFIG_USB_ISP116X_HCD */
diff --git a/drivers/usb/r8a66597-hcd.c b/drivers/usb/r8a66597-hcd.c
index 0d3931e..288f41a 100644
--- a/drivers/usb/r8a66597-hcd.c
+++ b/drivers/usb/r8a66597-hcd.c
@@ -530,7 +530,7 @@ static int check_usb_device_connecting(struct r8a66597 *r8a66597)
/* based on usb_ohci.c */
#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+ ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
/*-------------------------------------------------------------------------*
* Virtual Root Hub
*-------------------------------------------------------------------------*/
@@ -654,7 +654,7 @@ static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
R8A66597_DPRINT("%s\n", __func__);
- if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ if (usb_pipeint(pipe)) {
printf("Root-Hub submit IRQ: NOT implemented");
return 0;
}
@@ -794,7 +794,7 @@ static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
case RH_SET_CONFIGURATION:
break;
default:
- dbg("unsupported root hub command");
+ R8A66597_DPRINT("unsupported root hub command");
stat = USB_ST_STALLED;
}
diff --git a/drivers/usb/sl811_usb.c b/drivers/usb/sl811_usb.c
index 159cc25..a03e469 100644
--- a/drivers/usb/sl811_usb.c
+++ b/drivers/usb/sl811_usb.c
@@ -36,7 +36,6 @@
*/
#include <common.h>
-#ifdef CONFIG_USB_SL811HS
#include <mpc8xx.h>
#include <usb.h>
#include "sl811.h"
@@ -111,7 +110,7 @@ static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
int usb_init_kup4x (void)
{
- volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
volatile memctl8xx_t *memctl = &immap->im_memctl;
int i;
unsigned char tmp;
@@ -265,7 +264,7 @@ static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *b
sl811_write(SL811_CTRL_A, ctrl);
while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
- if (5*CFG_HZ < get_timer(time_start)) {
+ if (5*CONFIG_SYS_HZ < get_timer(time_start)) {
printf("USB transmit timed out\n");
return -USB_ST_CRC_ERR;
}
@@ -733,5 +732,3 @@ static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
return status == 0 ? len : status;
}
-
-#endif /* CONFIG_USB_SL811HS */
diff --git a/drivers/usb/usb_ohci.c b/drivers/usb/usb_ohci.c
index 0bfa4d7..d68fdcf 100644
--- a/drivers/usb/usb_ohci.c
+++ b/drivers/usb/usb_ohci.c
@@ -46,9 +46,6 @@
*/
#include <common.h>
-
-#ifdef CONFIG_USB_OHCI_NEW
-
#include <asm/byteorder.h>
#if defined(CONFIG_PCI_OHCI)
@@ -73,7 +70,7 @@
defined(CONFIG_440EP) || \
defined(CONFIG_PCI_OHCI) || \
defined(CONFIG_MPC5200) || \
- defined(CFG_OHCI_USE_NPS)
+ defined(CONFIG_SYS_OHCI_USE_NPS)
# define OHCI_USE_NPS /* force NoPowerSwitching mode */
#endif
@@ -89,15 +86,16 @@
/*
* e.g. PCI controllers need this
*/
-#ifdef CFG_OHCI_SWAP_REG_ACCESS
+#ifdef CONFIG_SYS_OHCI_SWAP_REG_ACCESS
# define readl(a) __swap_32(*((volatile u32 *)(a)))
# define writel(a, b) (*((volatile u32 *)(b)) = __swap_32((volatile u32)a))
#else
# define readl(a) (*((volatile u32 *)(a)))
# define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
-#endif /* CFG_OHCI_SWAP_REG_ACCESS */
+#endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */
-#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define min_t(type, x, y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
#ifdef CONFIG_PCI_OHCI
static struct pci_device_id ohci_pci_ids[] = {
@@ -109,25 +107,33 @@ static struct pci_device_id ohci_pci_ids[] = {
};
#endif
+#ifdef CONFIG_PCI_EHCI_DEVNO
+static struct pci_device_id ehci_pci_ids[] = {
+ {0x1131, 0x1562}, /* Philips 1562 PCI EHCI module ids */
+ /* Please add supported PCI EHCI controller ids here */
+ {0, 0}
+};
+#endif
+
#ifdef DEBUG
#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
#else
-#define dbg(format, arg...) do {} while(0)
+#define dbg(format, arg...) do {} while (0)
#endif /* DEBUG */
#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
#ifdef SHOW_INFO
#define info(format, arg...) printf("INFO: " format "\n", ## arg)
#else
-#define info(format, arg...) do {} while(0)
+#define info(format, arg...) do {} while (0)
#endif
-#ifdef CFG_OHCI_BE_CONTROLLER
+#ifdef CONFIG_SYS_OHCI_BE_CONTROLLER
# define m16_swap(x) cpu_to_be16(x)
# define m32_swap(x) cpu_to_be32(x)
#else
# define m16_swap(x) cpu_to_le16(x)
# define m32_swap(x) cpu_to_le32(x)
-#endif /* CFG_OHCI_BE_CONTROLLER */
+#endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
/* global ohci_t */
static ohci_t gohci;
@@ -137,25 +143,24 @@ struct ohci_hcca ghcca[1];
struct ohci_hcca *phcca;
/* this allocates EDs for all possible endpoints */
struct ohci_device ohci_dev;
-/* RHSC flag */
-int got_rhsc;
/* device which was disconnected */
struct usb_device *devgone;
-static inline u32 roothub_a (struct ohci *hc)
- { return readl (&hc->regs->roothub.a); }
-static inline u32 roothub_b (struct ohci *hc)
- { return readl (&hc->regs->roothub.b); }
-static inline u32 roothub_status (struct ohci *hc)
- { return readl (&hc->regs->roothub.status); }
-static inline u32 roothub_portstatus (struct ohci *hc, int i)
- { return readl (&hc->regs->roothub.portstatus[i]); }
+static inline u32 roothub_a(struct ohci *hc)
+ { return readl(&hc->regs->roothub.a); }
+static inline u32 roothub_b(struct ohci *hc)
+ { return readl(&hc->regs->roothub.b); }
+static inline u32 roothub_status(struct ohci *hc)
+ { return readl(&hc->regs->roothub.status); }
+static inline u32 roothub_portstatus(struct ohci *hc, int i)
+ { return readl(&hc->regs->roothub.portstatus[i]); }
/* forward declaration */
-static int hc_interrupt (void);
-static void
-td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
- int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+static int hc_interrupt(void);
+static void td_submit_job(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,
+ struct devrequest *setup, urb_priv_t *urb,
+ int interval);
/*-------------------------------------------------------------------------*
* URB support functions
@@ -163,11 +168,11 @@ td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
/* free HCD-private data associated with this URB */
-static void urb_free_priv (urb_priv_t * urb)
+static void urb_free_priv(urb_priv_t *urb)
{
int i;
int last;
- struct td * td;
+ struct td *td;
last = urb->length - 1;
if (last >= 0) {
@@ -185,72 +190,74 @@ static void urb_free_priv (urb_priv_t * urb)
/*-------------------------------------------------------------------------*/
#ifdef DEBUG
-static int sohci_get_current_frame_number (struct usb_device * dev);
+static int sohci_get_current_frame_number(struct usb_device *dev);
/* debug| print the main components of an URB
* small: 0) header + data packets 1) just header */
-static void pkt_print (urb_priv_t *purb, struct usb_device * dev,
- unsigned long pipe, void * buffer,
- int transfer_len, struct devrequest * setup, char * str, int small)
+static void pkt_print(urb_priv_t *purb, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int transfer_len,
+ struct devrequest *setup, char *str, int small)
{
- dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+ dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx",
str,
- sohci_get_current_frame_number (dev),
- usb_pipedevice (pipe),
- usb_pipeendpoint (pipe),
- usb_pipeout (pipe)? 'O': 'I',
- usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
- (usb_pipecontrol (pipe)? "CTRL": "BULK"),
+ sohci_get_current_frame_number(dev),
+ usb_pipedevice(pipe),
+ usb_pipeendpoint(pipe),
+ usb_pipeout(pipe)? 'O': 'I',
+ usb_pipetype(pipe) < 2 ? \
+ (usb_pipeint(pipe)? "INTR": "ISOC"): \
+ (usb_pipecontrol(pipe)? "CTRL": "BULK"),
(purb ? purb->actual_length : 0),
transfer_len, dev->status);
#ifdef OHCI_VERBOSE_DEBUG
if (!small) {
int i, len;
- if (usb_pipecontrol (pipe)) {
- printf (__FILE__ ": cmd(8):");
+ if (usb_pipecontrol(pipe)) {
+ printf(__FILE__ ": cmd(8):");
for (i = 0; i < 8 ; i++)
- printf (" %02x", ((__u8 *) setup) [i]);
- printf ("\n");
+ printf(" %02x", ((__u8 *) setup) [i]);
+ printf("\n");
}
if (transfer_len > 0 && buffer) {
- printf (__FILE__ ": data(%d/%d):",
+ printf(__FILE__ ": data(%d/%d):",
(purb ? purb->actual_length : 0),
transfer_len);
- len = usb_pipeout (pipe)?
- transfer_len:
+ len = usb_pipeout(pipe)? transfer_len:
(purb ? purb->actual_length : 0);
for (i = 0; i < 16 && i < len; i++)
- printf (" %02x", ((__u8 *) buffer) [i]);
- printf ("%s\n", i < len? "...": "");
+ printf(" %02x", ((__u8 *) buffer) [i]);
+ printf("%s\n", i < len? "...": "");
}
}
#endif
}
-/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
-void ep_print_int_eds (ohci_t *ohci, char * str) {
+/* just for debugging; prints non-empty branches of the int ed tree
+ * inclusive iso eds */
+void ep_print_int_eds(ohci_t *ohci, char *str)
+{
int i, j;
- __u32 * ed_p;
- for (i= 0; i < 32; i++) {
+ __u32 *ed_p;
+ for (i = 0; i < 32; i++) {
j = 5;
ed_p = &(ohci->hcca->int_table [i]);
if (*ed_p == 0)
continue;
- printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+ printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
while (*ed_p != 0 && j--) {
ed_t *ed = (ed_t *)m32_swap(ed_p);
- printf (" ed: %4x;", ed->hwINFO);
+ printf(" ed: %4x;", ed->hwINFO);
ed_p = &ed->hwNextED;
}
- printf ("\n");
+ printf("\n");
}
}
-static void ohci_dump_intr_mask (char *label, __u32 mask)
+static void ohci_dump_intr_mask(char *label, __u32 mask)
{
- dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ dbg("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
label,
mask,
(mask & OHCI_INTR_MIE) ? " MIE" : "",
@@ -265,46 +272,46 @@ static void ohci_dump_intr_mask (char *label, __u32 mask)
);
}
-static void maybe_print_eds (char *label, __u32 value)
+static void maybe_print_eds(char *label, __u32 value)
{
ed_t *edp = (ed_t *)value;
if (value) {
- dbg ("%s %08x", label, value);
- dbg ("%08x", edp->hwINFO);
- dbg ("%08x", edp->hwTailP);
- dbg ("%08x", edp->hwHeadP);
- dbg ("%08x", edp->hwNextED);
+ dbg("%s %08x", label, value);
+ dbg("%08x", edp->hwINFO);
+ dbg("%08x", edp->hwTailP);
+ dbg("%08x", edp->hwHeadP);
+ dbg("%08x", edp->hwNextED);
}
}
-static char * hcfs2string (int state)
+static char *hcfs2string(int state)
{
switch (state) {
- case OHCI_USB_RESET: return "reset";
- case OHCI_USB_RESUME: return "resume";
- case OHCI_USB_OPER: return "operational";
- case OHCI_USB_SUSPEND: return "suspend";
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
}
return "?";
}
/* dump control and status registers */
-static void ohci_dump_status (ohci_t *controller)
+static void ohci_dump_status(ohci_t *controller)
{
struct ohci_regs *regs = controller->regs;
__u32 temp;
- temp = readl (&regs->revision) & 0xff;
+ temp = readl(&regs->revision) & 0xff;
if (temp != 0x10)
- dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+ dbg("spec %d.%d", (temp >> 4), (temp & 0x0f));
- temp = readl (&regs->control);
- dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ temp = readl(&regs->control);
+ dbg("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
(temp & OHCI_CTRL_RWE) ? " RWE" : "",
(temp & OHCI_CTRL_RWC) ? " RWC" : "",
(temp & OHCI_CTRL_IR) ? " IR" : "",
- hcfs2string (temp & OHCI_CTRL_HCFS),
+ hcfs2string(temp & OHCI_CTRL_HCFS),
(temp & OHCI_CTRL_BLE) ? " BLE" : "",
(temp & OHCI_CTRL_CLE) ? " CLE" : "",
(temp & OHCI_CTRL_IE) ? " IE" : "",
@@ -312,8 +319,8 @@ static void ohci_dump_status (ohci_t *controller)
temp & OHCI_CTRL_CBSR
);
- temp = readl (&regs->cmdstatus);
- dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ temp = readl(&regs->cmdstatus);
+ dbg("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
(temp & OHCI_SOC) >> 16,
(temp & OHCI_OCR) ? " OCR" : "",
(temp & OHCI_BLF) ? " BLF" : "",
@@ -321,31 +328,31 @@ static void ohci_dump_status (ohci_t *controller)
(temp & OHCI_HCR) ? " HCR" : ""
);
- ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
- ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+ ohci_dump_intr_mask("intrstatus", readl(&regs->intrstatus));
+ ohci_dump_intr_mask("intrenable", readl(&regs->intrenable));
- maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+ maybe_print_eds("ed_periodcurrent", readl(&regs->ed_periodcurrent));
- maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
- maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+ maybe_print_eds("ed_controlhead", readl(&regs->ed_controlhead));
+ maybe_print_eds("ed_controlcurrent", readl(&regs->ed_controlcurrent));
- maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
- maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+ maybe_print_eds("ed_bulkhead", readl(&regs->ed_bulkhead));
+ maybe_print_eds("ed_bulkcurrent", readl(&regs->ed_bulkcurrent));
- maybe_print_eds ("donehead", readl (&regs->donehead));
+ maybe_print_eds("donehead", readl(&regs->donehead));
}
-static void ohci_dump_roothub (ohci_t *controller, int verbose)
+static void ohci_dump_roothub(ohci_t *controller, int verbose)
{
__u32 temp, ndp, i;
- temp = roothub_a (controller);
+ temp = roothub_a(controller);
ndp = (temp & RH_A_NDP);
#ifdef CONFIG_AT91C_PQFP_UHPBUG
ndp = (ndp == 2) ? 1:0;
#endif
if (verbose) {
- dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ dbg("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
((temp & RH_A_POTPGT) >> 24) & 0xff,
(temp & RH_A_NOCP) ? " NOCP" : "",
(temp & RH_A_OCPM) ? " OCPM" : "",
@@ -354,14 +361,14 @@ static void ohci_dump_roothub (ohci_t *controller, int verbose)
(temp & RH_A_PSM) ? " PSM" : "",
ndp
);
- temp = roothub_b (controller);
- dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp = roothub_b(controller);
+ dbg("roothub.b: %08x PPCM=%04x DR=%04x",
temp,
(temp & RH_B_PPCM) >> 16,
(temp & RH_B_DR)
);
- temp = roothub_status (controller);
- dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp = roothub_status(controller);
+ dbg("roothub.status: %08x%s%s%s%s%s%s",
temp,
(temp & RH_HS_CRWE) ? " CRWE" : "",
(temp & RH_HS_OCIC) ? " OCIC" : "",
@@ -373,8 +380,8 @@ static void ohci_dump_roothub (ohci_t *controller, int verbose)
}
for (i = 0; i < ndp; i++) {
- temp = roothub_portstatus (controller, i);
- dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ temp = roothub_portstatus(controller, i);
+ dbg("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
i,
temp,
(temp & RH_PS_PRSC) ? " PRSC" : "",
@@ -395,16 +402,16 @@ static void ohci_dump_roothub (ohci_t *controller, int verbose)
}
}
-static void ohci_dump (ohci_t *controller, int verbose)
+static void ohci_dump(ohci_t *controller, int verbose)
{
- dbg ("OHCI controller usb-%s state", controller->slot_name);
+ dbg("OHCI controller usb-%s state", controller->slot_name);
/* dumps some of the state we know about */
- ohci_dump_status (controller);
+ ohci_dump_status(controller);
if (verbose)
- ep_print_int_eds (controller, "hcca");
- dbg ("hcca frame #%04x", controller->hcca->frame_no);
- ohci_dump_roothub (controller, 1);
+ ep_print_int_eds(controller, "hcca");
+ dbg("hcca frame #%04x", controller->hcca->frame_no);
+ ohci_dump_roothub(controller, 1);
}
#endif /* DEBUG */
@@ -417,7 +424,7 @@ static void ohci_dump (ohci_t *controller, int verbose)
int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
{
ohci_t *ohci;
- ed_t * ed;
+ ed_t *ed;
urb_priv_t *purb_priv = urb;
int i, size = 0;
struct usb_device *dev = urb->dev;
@@ -435,27 +442,29 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
return -1;
}
- /* we're about to begin a new transaction here so mark the URB unfinished */
+ /* we're about to begin a new transaction here so mark the
+ * URB unfinished */
urb->finished = 0;
/* every endpoint has a ed, locate and fill it */
- if (!(ed = ep_add_ed (dev, pipe, interval, 1))) {
+ ed = ep_add_ed(dev, pipe, interval, 1);
+ if (!ed) {
err("sohci_submit_job: ENOMEM");
return -1;
}
/* for the private part of the URB we need the number of TDs (size) */
- switch (usb_pipetype (pipe)) {
- case PIPE_BULK: /* one TD for every 4096 Byte */
- size = (transfer_len - 1) / 4096 + 1;
- break;
- case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
- size = (transfer_len == 0)? 2:
- (transfer_len - 1) / 4096 + 3;
- break;
- case PIPE_INTERRUPT: /* 1 TD */
- size = 1;
- break;
+ switch (usb_pipetype(pipe)) {
+ case PIPE_BULK: /* one TD for every 4096 Byte */
+ size = (transfer_len - 1) / 4096 + 1;
+ break;
+ case PIPE_CONTROL:/* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+ size = (transfer_len == 0)? 2:
+ (transfer_len - 1) / 4096 + 3;
+ break;
+ case PIPE_INTERRUPT: /* 1 TD */
+ size = 1;
+ break;
}
ed->purb = urb;
@@ -474,27 +483,28 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
/* allocate the TDs */
/* note that td[0] was allocated in ep_add_ed */
for (i = 0; i < size; i++) {
- purb_priv->td[i] = td_alloc (dev);
+ purb_priv->td[i] = td_alloc(dev);
if (!purb_priv->td[i]) {
purb_priv->length = i;
- urb_free_priv (purb_priv);
+ urb_free_priv(purb_priv);
err("sohci_submit_job: ENOMEM");
return -1;
}
}
if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
- urb_free_priv (purb_priv);
+ urb_free_priv(purb_priv);
err("sohci_submit_job: EINVAL");
return -1;
}
/* link the ed into a chain if is not already */
if (ed->state != ED_OPER)
- ep_link (ohci, ed);
+ ep_link(ohci, ed);
/* fill the TDs and link it to the ed */
- td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+ td_submit_job(dev, pipe, buffer, transfer_len,
+ setup, purb_priv, interval);
return 0;
}
@@ -503,19 +513,19 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
{
struct ohci_regs *regs = hc->regs;
- switch (usb_pipetype (urb->pipe)) {
+ switch (usb_pipetype(urb->pipe)) {
case PIPE_INTERRUPT:
/* implicitly requeued */
if (urb->dev->irq_handle &&
(urb->dev->irq_act_len = urb->actual_length)) {
- writel (OHCI_INTR_WDH, &regs->intrenable);
- readl (&regs->intrenable); /* PCI posting flush */
+ writel(OHCI_INTR_WDH, &regs->intrenable);
+ readl(&regs->intrenable); /* PCI posting flush */
urb->dev->irq_handle(urb->dev);
- writel (OHCI_INTR_WDH, &regs->intrdisable);
- readl (&regs->intrdisable); /* PCI posting flush */
+ writel(OHCI_INTR_WDH, &regs->intrdisable);
+ readl(&regs->intrdisable); /* PCI posting flush */
}
urb->actual_length = 0;
- td_submit_job (
+ td_submit_job(
urb->dev,
urb->pipe,
urb->transfer_buffer,
@@ -538,11 +548,11 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
#ifdef DEBUG
/* tell us the current USB frame number */
-static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+static int sohci_get_current_frame_number(struct usb_device *usb_dev)
{
ohci_t *ohci = &gohci;
- return m16_swap (ohci->hcca->frame_no);
+ return m16_swap(ohci->hcca->frame_no);
}
#endif
@@ -555,7 +565,7 @@ static int sohci_get_current_frame_number (struct usb_device *usb_dev)
* returns the branch and
* sets the interval to interval = 2^integer (ld (interval)) */
-static int ep_int_ballance (ohci_t * ohci, int interval, int load)
+static int ep_int_ballance(ohci_t *ohci, int interval, int load)
{
int i, branch = 0;
@@ -577,20 +587,19 @@ static int ep_int_ballance (ohci_t * ohci, int interval, int load)
/* 2^int( ld (inter)) */
-static int ep_2_n_interval (int inter)
+static int ep_2_n_interval(int inter)
{
int i;
- for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++);
+ for (i = 0; ((inter >> i) > 1) && (i < 5); i++);
return 1 << i;
}
/*-------------------------------------------------------------------------*/
/* the int tree is a binary tree
- * in order to process it sequentially the indexes of the branches have to be mapped
- * the mapping reverses the bits of a word of num_bits length */
-
-static int ep_rev (int num_bits, int word)
+ * in order to process it sequentially the indexes of the branches have to
+ * be mapped the mapping reverses the bits of a word of num_bits length */
+static int ep_rev(int num_bits, int word)
{
int i, wout = 0;
@@ -605,7 +614,7 @@ static int ep_rev (int num_bits, int word)
/* link an ed into one of the HC chains */
-static int ep_link (ohci_t *ohci, ed_t *edi)
+static int ep_link(ohci_t *ohci, ed_t *edi)
{
volatile ed_t *ed = edi;
int int_branch;
@@ -613,7 +622,7 @@ static int ep_link (ohci_t *ohci, ed_t *edi)
int inter;
int interval;
int load;
- __u32 * ed_p;
+ __u32 *ed_p;
ed->state = ED_OPER;
ed->int_interval = 0;
@@ -621,49 +630,54 @@ static int ep_link (ohci_t *ohci, ed_t *edi)
switch (ed->type) {
case PIPE_CONTROL:
ed->hwNextED = 0;
- if (ohci->ed_controltail == NULL) {
- writel (ed, &ohci->regs->ed_controlhead);
- } else {
- ohci->ed_controltail->hwNextED = m32_swap ((unsigned long)ed);
- }
+ if (ohci->ed_controltail == NULL)
+ writel(ed, &ohci->regs->ed_controlhead);
+ else
+ ohci->ed_controltail->hwNextED =
+ m32_swap((unsigned long)ed);
+
ed->ed_prev = ohci->ed_controltail;
if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
!ohci->ed_rm_list[1] && !ohci->sleeping) {
ohci->hc_control |= OHCI_CTRL_CLE;
- writel (ohci->hc_control, &ohci->regs->control);
+ writel(ohci->hc_control, &ohci->regs->control);
}
ohci->ed_controltail = edi;
break;
case PIPE_BULK:
ed->hwNextED = 0;
- if (ohci->ed_bulktail == NULL) {
- writel (ed, &ohci->regs->ed_bulkhead);
- } else {
- ohci->ed_bulktail->hwNextED = m32_swap ((unsigned long)ed);
- }
+ if (ohci->ed_bulktail == NULL)
+ writel(ed, &ohci->regs->ed_bulkhead);
+ else
+ ohci->ed_bulktail->hwNextED =
+ m32_swap((unsigned long)ed);
+
ed->ed_prev = ohci->ed_bulktail;
if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
!ohci->ed_rm_list[1] && !ohci->sleeping) {
ohci->hc_control |= OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
+ writel(ohci->hc_control, &ohci->regs->control);
}
ohci->ed_bulktail = edi;
break;
case PIPE_INTERRUPT:
load = ed->int_load;
- interval = ep_2_n_interval (ed->int_period);
+ interval = ep_2_n_interval(ed->int_period);
ed->int_interval = interval;
- int_branch = ep_int_ballance (ohci, interval, load);
+ int_branch = ep_int_ballance(ohci, interval, load);
ed->int_branch = int_branch;
- for (i = 0; i < ep_rev (6, interval); i += inter) {
+ for (i = 0; i < ep_rev(6, interval); i += inter) {
inter = 1;
- for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]);
- (*ed_p != 0) && (((ed_t *)ed_p)->int_interval >= interval);
+ for (ed_p = &(ohci->hcca->int_table[\
+ ep_rev(5, i) + int_branch]);
+ (*ed_p != 0) &&
+ (((ed_t *)ed_p)->int_interval >= interval);
ed_p = &(((ed_t *)ed_p)->hwNextED))
- inter = ep_rev (6, ((ed_t *)ed_p)->int_interval);
+ inter = ep_rev(6,
+ ((ed_t *)ed_p)->int_interval);
ed->hwNextED = *ed_p;
*ed_p = m32_swap((unsigned long)ed);
}
@@ -675,19 +689,21 @@ static int ep_link (ohci_t *ohci, ed_t *edi)
/*-------------------------------------------------------------------------*/
/* scan the periodic table to find and unlink this ED */
-static void periodic_unlink ( struct ohci *ohci, volatile struct ed *ed,
- unsigned index, unsigned period)
+static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
+ unsigned index, unsigned period)
{
for (; index < NUM_INTS; index += period) {
__u32 *ed_p = &ohci->hcca->int_table [index];
/* ED might have been unlinked through another path */
while (*ed_p != 0) {
- if (((struct ed *)m32_swap ((unsigned long)ed_p)) == ed) {
+ if (((struct ed *)
+ m32_swap((unsigned long)ed_p)) == ed) {
*ed_p = ed->hwNextED;
break;
}
- ed_p = & (((struct ed *)m32_swap ((unsigned long)ed_p))->hwNextED);
+ ed_p = &(((struct ed *)
+ m32_swap((unsigned long)ed_p))->hwNextED);
}
}
}
@@ -697,28 +713,30 @@ static void periodic_unlink ( struct ohci *ohci, volatile struct ed *ed,
* the link from the ed still points to another operational ed or 0
* so the HC can eventually finish the processing of the unlinked ed */
-static int ep_unlink (ohci_t *ohci, ed_t *edi)
+static int ep_unlink(ohci_t *ohci, ed_t *edi)
{
volatile ed_t *ed = edi;
int i;
- ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
+ ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
switch (ed->type) {
case PIPE_CONTROL:
if (ed->ed_prev == NULL) {
if (!ed->hwNextED) {
ohci->hc_control &= ~OHCI_CTRL_CLE;
- writel (ohci->hc_control, &ohci->regs->control);
+ writel(ohci->hc_control, &ohci->regs->control);
}
- writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+ writel(m32_swap(*((__u32 *)&ed->hwNextED)),
+ &ohci->regs->ed_controlhead);
} else {
ed->ed_prev->hwNextED = ed->hwNextED;
}
if (ohci->ed_controltail == ed) {
ohci->ed_controltail = ed->ed_prev;
} else {
- ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ ((ed_t *)m32_swap(
+ *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
}
break;
@@ -726,21 +744,23 @@ static int ep_unlink (ohci_t *ohci, ed_t *edi)
if (ed->ed_prev == NULL) {
if (!ed->hwNextED) {
ohci->hc_control &= ~OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
+ writel(ohci->hc_control, &ohci->regs->control);
}
- writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+ writel(m32_swap(*((__u32 *)&ed->hwNextED)),
+ &ohci->regs->ed_bulkhead);
} else {
ed->ed_prev->hwNextED = ed->hwNextED;
}
if (ohci->ed_bulktail == ed) {
ohci->ed_bulktail = ed->ed_prev;
} else {
- ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ ((ed_t *)m32_swap(
+ *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
}
break;
case PIPE_INTERRUPT:
- periodic_unlink (ohci, ed, 0, 1);
+ periodic_unlink(ohci, ed, 0, 1);
for (i = ed->int_branch; i < 32; i += ed->int_interval)
ohci->ohci_int_load[i] -= ed->int_load;
break;
@@ -759,15 +779,15 @@ static int ep_unlink (ohci_t *ohci, ed_t *edi)
* info fields are setted anyway even though most of them should not
* change
*/
-static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe,
- int interval, int load)
+static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
+ int interval, int load)
{
td_t *td;
ed_t *ed_ret;
volatile ed_t *ed;
- ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
- (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+ ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) |
+ (usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))];
if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
err("ep_add_ed: pending delete");
@@ -776,22 +796,22 @@ static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe,
}
if (ed->state == ED_NEW) {
- ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
/* dummy td; end of td list for ed */
- td = td_alloc (usb_dev);
- ed->hwTailP = m32_swap ((unsigned long)td);
+ td = td_alloc(usb_dev);
+ ed->hwTailP = m32_swap((unsigned long)td);
ed->hwHeadP = ed->hwTailP;
ed->state = ED_UNLINK;
- ed->type = usb_pipetype (pipe);
+ ed->type = usb_pipetype(pipe);
ohci_dev.ed_cnt++;
}
- ed->hwINFO = m32_swap (usb_pipedevice (pipe)
- | usb_pipeendpoint (pipe) << 7
- | (usb_pipeisoc (pipe)? 0x8000: 0)
- | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
- | usb_pipeslow (pipe) << 13
- | usb_maxpacket (usb_dev, pipe) << 16);
+ ed->hwINFO = m32_swap(usb_pipedevice(pipe)
+ | usb_pipeendpoint(pipe) << 7
+ | (usb_pipeisoc(pipe)? 0x8000: 0)
+ | (usb_pipecontrol(pipe)? 0: \
+ (usb_pipeout(pipe)? 0x800: 0x1000))
+ | usb_pipeslow(pipe) << 13
+ | usb_maxpacket(usb_dev, pipe) << 16);
if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
ed->int_period = interval;
@@ -807,7 +827,7 @@ static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe,
/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
-static void td_fill (ohci_t *ohci, unsigned int info,
+static void td_fill(ohci_t *ohci, unsigned int info,
void *data, int len,
struct usb_device *dev, int index, urb_priv_t *urb_priv)
{
@@ -825,29 +845,31 @@ static void td_fill (ohci_t *ohci, unsigned int info,
td_pt->hwNextTD = 0;
/* fill the old dummy TD */
- td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
+ td = urb_priv->td [index] =
+ (td_t *)(m32_swap(urb_priv->ed->hwTailP) & ~0xf);
td->ed = urb_priv->ed;
td->next_dl_td = NULL;
td->index = index;
td->data = (__u32)data;
#ifdef OHCI_FILL_TRACE
- if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
+ if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
for (i = 0; i < len; i++)
- printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+ printf("td->data[%d] %#2x ", i, ((unsigned char *)td->data)[i]);
printf("\n");
}
#endif
if (!len)
data = 0;
- td->hwINFO = m32_swap (info);
- td->hwCBP = m32_swap ((unsigned long)data);
+ td->hwINFO = m32_swap(info);
+ td->hwCBP = m32_swap((unsigned long)data);
if (data)
- td->hwBE = m32_swap ((unsigned long)(data + len - 1));
+ td->hwBE = m32_swap((unsigned long)(data + len - 1));
else
td->hwBE = 0;
- td->hwNextTD = m32_swap ((unsigned long)td_pt);
+
+ td->hwNextTD = m32_swap((unsigned long)td_pt);
/* append to queue */
td->ed->hwTailP = td->hwNextTD;
@@ -857,8 +879,10 @@ static void td_fill (ohci_t *ohci, unsigned int info,
/* prepare all TDs of a transfer */
-static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+static void td_submit_job(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,
+ struct devrequest *setup, urb_priv_t *urb,
+ int interval)
{
ohci_t *ohci = &gohci;
int data_len = transfer_len;
@@ -867,12 +891,14 @@ static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buf
__u32 info = 0;
unsigned int toggle = 0;
- /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
- if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle
+ * bits for reseting */
+ if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
toggle = TD_T_TOGGLE;
} else {
toggle = TD_T_DATA0;
- usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+ usb_settoggle(dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe), 1);
}
urb->td_cnt = 0;
if (data_len)
@@ -880,44 +906,58 @@ static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buf
else
data = 0;
- switch (usb_pipetype (pipe)) {
+ switch (usb_pipetype(pipe)) {
case PIPE_BULK:
- info = usb_pipeout (pipe)?
+ info = usb_pipeout(pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
- while(data_len > 4096) {
- td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+ while (data_len > 4096) {
+ td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle),
+ data, 4096, dev, cnt, urb);
data += 4096; data_len -= 4096; cnt++;
}
- info = usb_pipeout (pipe)?
+ info = usb_pipeout(pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
- td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+ td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle), data,
+ data_len, dev, cnt, urb);
cnt++;
- if (!ohci->sleeping)
- writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ if (!ohci->sleeping) {
+ /* start bulk list */
+ writel(OHCI_BLF, &ohci->regs->cmdstatus);
+ }
break;
case PIPE_CONTROL:
+ /* Setup phase */
info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
- td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+ td_fill(ohci, info, setup, 8, dev, cnt++, urb);
+
+ /* Optional Data phase */
if (data_len > 0) {
- info = usb_pipeout (pipe)?
- TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+ info = usb_pipeout(pipe)?
+ TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 :
+ TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
/* NOTE: mishandles transfers >8K, some >4K */
- td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+ td_fill(ohci, info, data, data_len, dev, cnt++, urb);
+ }
+
+ /* Status phase */
+ info = usb_pipeout(pipe)?
+ TD_CC | TD_DP_IN | TD_T_DATA1:
+ TD_CC | TD_DP_OUT | TD_T_DATA1;
+ td_fill(ohci, info, data, 0, dev, cnt++, urb);
+
+ if (!ohci->sleeping) {
+ /* start Control list */
+ writel(OHCI_CLF, &ohci->regs->cmdstatus);
}
- info = usb_pipeout (pipe)?
- TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
- td_fill (ohci, info, data, 0, dev, cnt++, urb);
- if (!ohci->sleeping)
- writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
break;
case PIPE_INTERRUPT:
- info = usb_pipeout (urb->pipe)?
+ info = usb_pipeout(urb->pipe)?
TD_CC | TD_DP_OUT | toggle:
TD_CC | TD_R | TD_DP_IN | toggle;
- td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+ td_fill(ohci, info, data, data_len, dev, cnt++, urb);
break;
}
if (urb->length != cnt)
@@ -930,16 +970,16 @@ static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buf
/* calculate the transfer length and update the urb */
-static void dl_transfer_length(td_t * td)
+static void dl_transfer_length(td_t *td)
{
__u32 tdINFO, tdBE, tdCBP;
urb_priv_t *lurb_priv = td->ed->purb;
- tdINFO = m32_swap (td->hwINFO);
- tdBE = m32_swap (td->hwBE);
- tdCBP = m32_swap (td->hwCBP);
+ tdINFO = m32_swap(td->hwINFO);
+ tdBE = m32_swap(td->hwBE);
+ tdCBP = m32_swap(td->hwCBP);
- if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
+ if (!(usb_pipecontrol(lurb_priv->pipe) &&
((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
if (tdBE != 0) {
if (td->hwCBP == 0)
@@ -951,105 +991,127 @@ static void dl_transfer_length(td_t * td)
}
/*-------------------------------------------------------------------------*/
+static void check_status(td_t *td_list)
+{
+ urb_priv_t *lurb_priv = td_list->ed->purb;
+ int urb_len = lurb_priv->length;
+ __u32 *phwHeadP = &td_list->ed->hwHeadP;
+ int cc;
+
+ cc = TD_CC_GET(m32_swap(td_list->hwINFO));
+ if (cc) {
+ err(" USB-error: %s (%x)", cc_to_string[cc], cc);
+
+ if (*phwHeadP & m32_swap(0x1)) {
+ if (lurb_priv &&
+ ((td_list->index + 1) < urb_len)) {
+ *phwHeadP =
+ (lurb_priv->td[urb_len - 1]->hwNextTD &\
+ m32_swap(0xfffffff0)) |
+ (*phwHeadP & m32_swap(0x2));
+
+ lurb_priv->td_cnt += urb_len -
+ td_list->index - 1;
+ } else
+ *phwHeadP &= m32_swap(0xfffffff2);
+ }
+#ifdef CONFIG_MPC5200
+ td_list->hwNextTD = 0;
+#endif
+ }
+}
/* replies to the request have to be on a FIFO basis so
* we reverse the reversed done-list */
-
-static td_t * dl_reverse_done_list (ohci_t *ohci)
+static td_t *dl_reverse_done_list(ohci_t *ohci)
{
__u32 td_list_hc;
td_t *td_rev = NULL;
td_t *td_list = NULL;
- urb_priv_t *lurb_priv = NULL;
- td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
+ td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
ohci->hcca->done_head = 0;
while (td_list_hc) {
td_list = (td_t *)td_list_hc;
-
- if (TD_CC_GET (m32_swap (td_list->hwINFO))) {
- lurb_priv = td_list->ed->purb;
- dbg(" USB-error/status: %x : %p",
- TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
- if (td_list->ed->hwHeadP & m32_swap (0x1)) {
- if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
- td_list->ed->hwHeadP =
- (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
- (td_list->ed->hwHeadP & m32_swap (0x2));
- lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
- } else
- td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
- }
-#ifdef CONFIG_MPC5200
- td_list->hwNextTD = 0;
-#endif
- }
-
+ check_status(td_list);
td_list->next_dl_td = td_rev;
td_rev = td_list;
- td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
+ td_list_hc = m32_swap(td_list->hwNextTD) & 0xfffffff0;
}
return td_list;
}
/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
-/* td done list */
-static int dl_done_list (ohci_t *ohci, td_t *td_list)
+static void finish_urb(ohci_t *ohci, urb_priv_t *urb, int status)
+{
+ if ((status & (ED_OPER | ED_UNLINK)) && (urb->state != URB_DEL))
+ urb->finished = sohci_return_job(ohci, urb);
+ else
+ dbg("finish_urb: strange.., ED state %x, \n", status);
+}
+
+/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames). This bug has been observed on ZF Micro systems.
+ */
+static int takeback_td(ohci_t *ohci, td_t *td_list)
{
- td_t *td_list_next = NULL;
ed_t *ed;
- int cc = 0;
+ int cc;
int stat = 0;
/* urb_t *urb; */
urb_priv_t *lurb_priv;
__u32 tdINFO, edHeadP, edTailP;
- while (td_list) {
- td_list_next = td_list->next_dl_td;
+ tdINFO = m32_swap(td_list->hwINFO);
- tdINFO = m32_swap (td_list->hwINFO);
+ ed = td_list->ed;
+ lurb_priv = ed->purb;
- ed = td_list->ed;
- lurb_priv = ed->purb;
+ dl_transfer_length(td_list);
- dl_transfer_length(td_list);
+ lurb_priv->td_cnt++;
- /* error code of transfer */
- cc = TD_CC_GET (tdINFO);
- if (cc != 0) {
- dbg("ConditionCode %#x", cc);
- stat = cc_to_error[cc];
- }
+ /* error code of transfer */
+ cc = TD_CC_GET(tdINFO);
+ if (cc) {
+ err("USB-error: %s (%x)", cc_to_string[cc], cc);
+ stat = cc_to_error[cc];
+ }
- /* see if this done list makes for all TD's of current URB,
- * and mark the URB finished if so */
- if (++(lurb_priv->td_cnt) == lurb_priv->length) {
-#if 1
- if ((ed->state & (ED_OPER | ED_UNLINK)) &&
- (lurb_priv->state != URB_DEL))
-#else
- if ((ed->state & (ED_OPER | ED_UNLINK)))
-#endif
- lurb_priv->finished = sohci_return_job(ohci,
- lurb_priv);
- else
- dbg("dl_done_list: strange.., ED state %x, ed->state\n");
- } else
- dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
- lurb_priv->length);
- if (ed->state != ED_NEW &&
- (usb_pipetype (lurb_priv->pipe) != PIPE_INTERRUPT)) {
- edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
- edTailP = m32_swap (ed->hwTailP);
-
- /* unlink eds if they are not busy */
- if ((edHeadP == edTailP) && (ed->state == ED_OPER))
- ep_unlink (ohci, ed);
- }
+ /* see if this done list makes for all TD's of current URB,
+ * and mark the URB finished if so */
+ if (lurb_priv->td_cnt == lurb_priv->length)
+ finish_urb(ohci, lurb_priv, ed->state);
+
+ dbg("dl_done_list: processing TD %x, len %x\n",
+ lurb_priv->td_cnt, lurb_priv->length);
- td_list = td_list_next;
+ if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
+ edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
+ edTailP = m32_swap(ed->hwTailP);
+
+ /* unlink eds if they are not busy */
+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+ ep_unlink(ohci, ed);
+ }
+ return stat;
+}
+
+static int dl_done_list(ohci_t *ohci)
+{
+ int stat = 0;
+ td_t *td_list = dl_reverse_done_list(ohci);
+
+ while (td_list) {
+ td_t *td_next = td_list->next_dl_td;
+ stat = takeback_td(ohci, td_list);
+ td_list = td_next;
}
return stat;
}
@@ -1092,7 +1154,7 @@ static __u8 root_hub_config_des[] =
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes;
- Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
0x00, /* __u8 MaxPower; */
/* interface */
@@ -1162,14 +1224,17 @@ static unsigned char root_hub_str_index1[] =
#define OK(x) len = (x); break
#ifdef DEBUG
-#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
-#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#define WR_RH_STAT(x) {info("WR:status %#8x", (x)); writel((x), \
+ &gohci.regs->roothub.status); }
+#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, \
+ (x)); writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); }
#else
#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
-#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#define WR_RH_PORTSTAT(x) writel((x), \
+ &gohci.regs->roothub.portstatus[wIndex-1])
#endif
#define RD_RH_STAT roothub_status(&gohci)
-#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1)
+#define RD_RH_PORTSTAT roothub_portstatus(&gohci, wIndex-1)
/* request to virtual root hub */
@@ -1179,13 +1244,13 @@ int rh_check_port_status(ohci_t *controller)
int res;
res = -1;
- temp = roothub_a (controller);
+ temp = roothub_a(controller);
ndp = (temp & RH_A_NDP);
#ifdef CONFIG_AT91C_PQFP_UHPBUG
ndp = (ndp == 2) ? 1:0;
#endif
for (i = 0; i < ndp; i++) {
- temp = roothub_portstatus (controller, i);
+ temp = roothub_portstatus(controller, i);
/* check for a device disconnect */
if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
(RH_PS_PESC | RH_PS_CSC)) &&
@@ -1200,7 +1265,7 @@ int rh_check_port_status(ohci_t *controller)
static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int transfer_len, struct devrequest *cmd)
{
- void * data = buffer;
+ void *data = buffer;
int leni = transfer_len;
int len = 0;
int stat = 0;
@@ -1212,19 +1277,20 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
__u16 wLength;
#ifdef DEBUG
-pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+pkt_print(NULL, dev, pipe, buffer, transfer_len,
+ cmd, "SUB(rh)", usb_pipein(pipe));
#else
wait_ms(1);
#endif
- if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ if (usb_pipeint(pipe)) {
info("Root-Hub submit IRQ: NOT implemented");
return 0;
}
bmRType_bReq = cmd->requesttype | (cmd->request << 8);
- wValue = le16_to_cpu (cmd->value);
- wIndex = le16_to_cpu (cmd->index);
- wLength = le16_to_cpu (cmd->length);
+ wValue = le16_to_cpu(cmd->value);
+ wIndex = le16_to_cpu(cmd->index);
+ wLength = le16_to_cpu(cmd->length);
info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
@@ -1239,118 +1305,118 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe
*/
case RH_GET_STATUS:
- *(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
+ *(__u16 *) data_buf = cpu_to_le16(1);
+ OK(2);
case RH_GET_STATUS | RH_INTERFACE:
- *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+ *(__u16 *) data_buf = cpu_to_le16(0);
+ OK(2);
case RH_GET_STATUS | RH_ENDPOINT:
- *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+ *(__u16 *) data_buf = cpu_to_le16(0);
+ OK(2);
case RH_GET_STATUS | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32 (
+ *(__u32 *) data_buf = cpu_to_le32(
RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
- OK (4);
+ OK(4);
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
+ *(__u32 *) data_buf = cpu_to_le32(RD_RH_PORTSTAT);
+ OK(4);
case RH_CLEAR_FEATURE | RH_ENDPOINT:
switch (wValue) {
- case (RH_ENDPOINT_STALL): OK (0);
+ case (RH_ENDPOINT_STALL):
+ OK(0);
}
break;
case RH_CLEAR_FEATURE | RH_CLASS:
switch (wValue) {
- case RH_C_HUB_LOCAL_POWER:
- OK(0);
- case (RH_C_HUB_OVER_CURRENT):
- WR_RH_STAT(RH_HS_OCIC); OK (0);
+ case RH_C_HUB_LOCAL_POWER:
+ OK(0);
+ case (RH_C_HUB_OVER_CURRENT):
+ WR_RH_STAT(RH_HS_OCIC);
+ OK(0);
}
break;
case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
switch (wValue) {
- case (RH_PORT_ENABLE):
- WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
- case (RH_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
- case (RH_PORT_POWER):
- WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
- case (RH_C_PORT_CONNECTION):
- WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
- case (RH_C_PORT_ENABLE):
- WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
- case (RH_C_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
- case (RH_C_PORT_OVER_CURRENT):
- WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
- case (RH_C_PORT_RESET):
- WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+ case (RH_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_CCS); OK(0);
+ case (RH_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_POCI); OK(0);
+ case (RH_PORT_POWER): WR_RH_PORTSTAT(RH_PS_LSDA); OK(0);
+ case (RH_C_PORT_CONNECTION): WR_RH_PORTSTAT(RH_PS_CSC); OK(0);
+ case (RH_C_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_PESC); OK(0);
+ case (RH_C_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_PSSC); OK(0);
+ case (RH_C_PORT_OVER_CURRENT):WR_RH_PORTSTAT(RH_PS_OCIC); OK(0);
+ case (RH_C_PORT_RESET): WR_RH_PORTSTAT(RH_PS_PRSC); OK(0);
}
break;
case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
switch (wValue) {
- case (RH_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
- case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT (RH_PS_PRS);
- OK (0);
- case (RH_PORT_POWER):
- WR_RH_PORTSTAT (RH_PS_PPS );
- wait_ms(100);
- OK (0);
- case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT (RH_PS_PES );
- OK (0);
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT(RH_PS_PSS); OK(0);
+ case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT(RH_PS_PRS);
+ OK(0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT(RH_PS_PPS);
+ wait_ms(100);
+ OK(0);
+ case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT(RH_PS_PES);
+ OK(0);
}
break;
- case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+ case RH_SET_ADDRESS:
+ gohci.rh.devnum = wValue;
+ OK(0);
case RH_GET_DESCRIPTOR:
switch ((wValue & 0xff00) >> 8) {
- case (0x01): /* device descriptor */
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des; OK(len);
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des; OK(len);
+ case (0x03): /* string descriptors */
+ if (wValue == 0x0300) {
len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_dev_des),
- wLength));
- data_buf = root_hub_dev_des; OK(len);
- case (0x02): /* configuration descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_config_des),
- wLength));
- data_buf = root_hub_config_des; OK(len);
- case (0x03): /* string descriptors */
- if(wValue==0x0300) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_str_index0),
- wLength));
- data_buf = root_hub_str_index0;
- OK(len);
- }
- if(wValue==0x0301) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_str_index1),
- wLength));
- data_buf = root_hub_str_index1;
- OK(len);
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ OK(len);
}
- default:
- stat = USB_ST_STALLED;
+ if (wValue == 0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ OK(len);
+ }
+ default:
+ stat = USB_ST_STALLED;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
{
- __u32 temp = roothub_a (&gohci);
+ __u32 temp = roothub_a(&gohci);
data_buf [0] = 9; /* min length; */
data_buf [1] = 0x29;
@@ -1363,13 +1429,13 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe
data_buf [3] |= 0x1;
if (temp & RH_A_NOCP) /* no overcurrent reporting? */
data_buf [3] |= 0x10;
- else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */
data_buf [3] |= 0x8;
/* corresponds to data_buf[4-7] */
datab [1] = 0;
data_buf [5] = (temp & RH_A_POTPGT) >> 24;
- temp = roothub_b (&gohci);
+ temp = roothub_b(&gohci);
data_buf [7] = temp & RH_B_DR;
if (data_buf [2] < 7) {
data_buf [8] = 0xff;
@@ -1381,32 +1447,33 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe
len = min_t(unsigned int, leni,
min_t(unsigned int, data_buf [0], wLength));
- OK (len);
+ OK(len);
}
- case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
+ case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK(1);
- case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
+ case RH_SET_CONFIGURATION: WR_RH_STAT(0x10000); OK(0);
default:
- dbg ("unsupported root hub command");
+ dbg("unsupported root hub command");
stat = USB_ST_STALLED;
}
#ifdef DEBUG
- ohci_dump_roothub (&gohci, 1);
+ ohci_dump_roothub(&gohci, 1);
#else
wait_ms(1);
#endif
len = min_t(int, len, leni);
if (data != data_buf)
- memcpy (data, data_buf, len);
+ memcpy(data, data_buf, len);
dev->act_len = len;
dev->status = stat;
#ifdef DEBUG
- pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+ pkt_print(NULL, dev, pipe, buffer,
+ transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
#else
wait_ms(1);
#endif
@@ -1443,7 +1510,8 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
#ifdef DEBUG
urb->actual_length = 0;
- pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+ pkt_print(urb, dev, pipe, buffer, transfer_len,
+ setup, "SUB", usb_pipein(pipe));
#else
wait_ms(1);
#endif
@@ -1465,7 +1533,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
/* allow more time for a BULK device to react - some are slow */
#define BULK_TO 5000 /* timeout in milliseconds */
- if (usb_pipetype (pipe) == PIPE_BULK)
+ if (usb_pipebulk(pipe))
timeout = BULK_TO;
else
timeout = 100;
@@ -1496,7 +1564,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
if (--timeout) {
wait_ms(1);
if (!urb->finished)
- dbg("\%");
+ dbg("*");
} else {
err("CTL:TIMEOUT ");
@@ -1511,14 +1579,15 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
dev->act_len = transfer_len;
#ifdef DEBUG
- pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+ pkt_print(urb, dev, pipe, buffer, transfer_len,
+ setup, "RET(ctlr)", usb_pipein(pipe));
#else
wait_ms(1);
#endif
/* free TDs in urb_priv */
- if (usb_pipetype (pipe) != PIPE_INTERRUPT)
- urb_free_priv (urb);
+ if (!usb_pipeint(pipe))
+ urb_free_priv(urb);
return 0;
}
@@ -1537,7 +1606,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
info("submit_control_msg");
#ifdef DEBUG
- pkt_print(NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+ pkt_print(NULL, dev, pipe, buffer, transfer_len,
+ setup, "SUB", usb_pipein(pipe));
#else
wait_ms(1);
#endif
@@ -1570,18 +1640,46 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
/* reset the HC and BUS */
-static int hc_reset (ohci_t *ohci)
+static int hc_reset(ohci_t *ohci)
{
+#ifdef CONFIG_PCI_EHCI_DEVNO
+ pci_dev_t pdev;
+#endif
int timeout = 30;
int smm_timeout = 50; /* 0,5 sec */
dbg("%s\n", __FUNCTION__);
- if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
- writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+#ifdef CONFIG_PCI_EHCI_DEVNO
+ /*
+ * Some multi-function controllers (e.g. ISP1562) allow root hub
+ * resetting via EHCI registers only.
+ */
+ pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVNO);
+ if (pdev != -1) {
+ u32 base;
+ int timeout = 1000;
+
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
+ writel(readl(base + EHCI_USBCMD_OFF) | EHCI_USBCMD_HCRESET,
+ base + EHCI_USBCMD_OFF);
+
+ while (readl(base + EHCI_USBCMD_OFF) & EHCI_USBCMD_HCRESET) {
+ if (timeout-- <= 0) {
+ printf("USB RootHub reset timed out!");
+ break;
+ }
+ udelay(1);
+ }
+ } else
+ printf("No EHCI func at %d index!\n", CONFIG_PCI_EHCI_DEVNO);
+#endif
+ if (readl(&ohci->regs->control) & OHCI_CTRL_IR) {
+ /* SMM owns the HC */
+ writel(OHCI_OCR, &ohci->regs->cmdstatus);/* request ownership */
info("USB HC TakeOver from SMM");
- while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
- wait_ms (10);
+ while (readl(&ohci->regs->control) & OHCI_CTRL_IR) {
+ wait_ms(10);
if (--smm_timeout == 0) {
err("USB HC TakeOver failed!");
return -1;
@@ -1590,7 +1688,7 @@ static int hc_reset (ohci_t *ohci)
}
/* Disable HC interrupts */
- writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ writel(OHCI_INTR_MIE, &ohci->regs->intrdisable);
dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
ohci->slot_name,
@@ -1598,16 +1696,16 @@ static int hc_reset (ohci_t *ohci)
/* Reset USB (needed by some controllers) */
ohci->hc_control = 0;
- writel (ohci->hc_control, &ohci->regs->control);
+ writel(ohci->hc_control, &ohci->regs->control);
/* HC Reset requires max 10 us delay */
- writel (OHCI_HCR, &ohci->regs->cmdstatus);
- while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+ writel(OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl(&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--timeout == 0) {
err("USB HC reset timed out!");
return -1;
}
- udelay (1);
+ udelay(1);
}
return 0;
}
@@ -1618,7 +1716,7 @@ static int hc_reset (ohci_t *ohci)
* enable interrupts
* connect the virtual root hub */
-static int hc_start (ohci_t * ohci)
+static int hc_start(ohci_t *ohci)
{
__u32 mask;
unsigned int fminterval;
@@ -1628,44 +1726,44 @@ static int hc_start (ohci_t * ohci)
/* Tell the controller where the control and bulk lists are
* The lists are empty now. */
- writel (0, &ohci->regs->ed_controlhead);
- writel (0, &ohci->regs->ed_bulkhead);
+ writel(0, &ohci->regs->ed_controlhead);
+ writel(0, &ohci->regs->ed_bulkhead);
- writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+ writel((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
fminterval = 0x2edf;
- writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+ writel((fminterval * 9) / 10, &ohci->regs->periodicstart);
fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
- writel (fminterval, &ohci->regs->fminterval);
- writel (0x628, &ohci->regs->lsthresh);
+ writel(fminterval, &ohci->regs->fminterval);
+ writel(0x628, &ohci->regs->lsthresh);
/* start controller operations */
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
ohci->disabled = 0;
- writel (ohci->hc_control, &ohci->regs->control);
+ writel(ohci->hc_control, &ohci->regs->control);
/* disable all interrupts */
mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
OHCI_INTR_OC | OHCI_INTR_MIE);
- writel (mask, &ohci->regs->intrdisable);
+ writel(mask, &ohci->regs->intrdisable);
/* clear all interrupts */
mask &= ~OHCI_INTR_MIE;
- writel (mask, &ohci->regs->intrstatus);
+ writel(mask, &ohci->regs->intrstatus);
/* Choose the interrupts we care about now - but w/o MIE */
mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
- writel (mask, &ohci->regs->intrenable);
+ writel(mask, &ohci->regs->intrenable);
#ifdef OHCI_USE_NPS
/* required for AMD-756 and some Mac platforms */
- writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+ writel((roothub_a(ohci) | RH_A_NPS) & ~RH_A_PSM,
&ohci->regs->roothub.a);
- writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+ writel(RH_HS_LPSC, &ohci->regs->roothub.status);
#endif /* OHCI_USE_NPS */
-#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); })
/* POTPGT delay is bits 24-31, in 2 ms units. */
- mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+ mdelay((roothub_a(ohci) >> 23) & 0x1fe);
/* connect the virtual root hub */
ohci->rh.devnum = 0;
@@ -1683,7 +1781,7 @@ void usb_event_poll(void)
/* an interrupt happens */
-static int hc_interrupt (void)
+static int hc_interrupt(void)
{
ohci_t *ohci = &gohci;
struct ohci_regs *regs = ohci->regs;
@@ -1691,69 +1789,74 @@ static int hc_interrupt (void)
int stat = -1;
if ((ohci->hcca->done_head != 0) &&
- !(m32_swap (ohci->hcca->done_head) & 0x01)) {
+ !(m32_swap(ohci->hcca->done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
- } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
- ohci->disabled++;
- err ("%s device removed!", ohci->slot_name);
- return -1;
- } else if ((ints &= readl (&regs->intrenable)) == 0) {
- dbg("hc_interrupt: returning..\n");
- return 0xff;
+ } else {
+ ints = readl(&regs->intrstatus);
+ if (ints == ~(u32)0) {
+ ohci->disabled++;
+ err("%s device removed!", ohci->slot_name);
+ return -1;
+ } else {
+ ints &= readl(&regs->intrenable);
+ if (ints == 0) {
+ dbg("hc_interrupt: returning..\n");
+ return 0xff;
+ }
+ }
}
- /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+ /* dbg("Interrupt: %x frame: %x", ints,
+ le16_to_cpu(ohci->hcca->frame_no)); */
- if (ints & OHCI_INTR_RHSC) {
- got_rhsc = 1;
+ if (ints & OHCI_INTR_RHSC)
stat = 0xff;
- }
if (ints & OHCI_INTR_UE) {
ohci->disabled++;
- err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+ err("OHCI Unrecoverable Error, controller usb-%s disabled",
ohci->slot_name);
/* e.g. due to PCI Master/Target Abort */
#ifdef DEBUG
- ohci_dump (ohci, 1);
+ ohci_dump(ohci, 1);
#else
- wait_ms(1);
+ wait_ms(1);
#endif
/* FIXME: be optimistic, hope that bug won't repeat often. */
/* Make some non-interrupt context restart the controller. */
/* Count and limit the retries though; either hardware or */
/* software errors can go forever... */
- hc_reset (ohci);
+ hc_reset(ohci);
return -1;
}
if (ints & OHCI_INTR_WDH) {
wait_ms(1);
- writel (OHCI_INTR_WDH, &regs->intrdisable);
- (void)readl (&regs->intrdisable); /* flush */
- stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
- writel (OHCI_INTR_WDH, &regs->intrenable);
- (void)readl (&regs->intrdisable); /* flush */
+ writel(OHCI_INTR_WDH, &regs->intrdisable);
+ (void)readl(&regs->intrdisable); /* flush */
+ stat = dl_done_list(&gohci);
+ writel(OHCI_INTR_WDH, &regs->intrenable);
+ (void)readl(&regs->intrdisable); /* flush */
}
if (ints & OHCI_INTR_SO) {
dbg("USB Schedule overrun\n");
- writel (OHCI_INTR_SO, &regs->intrenable);
+ writel(OHCI_INTR_SO, &regs->intrenable);
stat = -1;
}
/* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
if (ints & OHCI_INTR_SF) {
- unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
+ unsigned int frame = m16_swap(ohci->hcca->frame_no) & 1;
wait_ms(1);
- writel (OHCI_INTR_SF, &regs->intrdisable);
+ writel(OHCI_INTR_SF, &regs->intrdisable);
if (ohci->ed_rm_list[frame] != NULL)
- writel (OHCI_INTR_SF, &regs->intrenable);
+ writel(OHCI_INTR_SF, &regs->intrenable);
stat = 0xff;
}
- writel (ints, &regs->intrstatus);
+ writel(ints, &regs->intrstatus);
return stat;
}
@@ -1763,12 +1866,12 @@ static int hc_interrupt (void)
/* De-allocate all resources.. */
-static void hc_release_ohci (ohci_t *ohci)
+static void hc_release_ohci(ohci_t *ohci)
{
- dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+ dbg("USB HC release ohci usb-%s", ohci->slot_name);
if (!ohci->disabled)
- hc_reset (ohci);
+ hc_reset(ohci);
}
/*-------------------------------------------------------------------------*/
@@ -1784,18 +1887,18 @@ int usb_lowlevel_init(void)
pci_dev_t pdev;
#endif
-#ifdef CFG_USB_OHCI_CPU_INIT
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
/* cpu dependant init */
- if(usb_cpu_init())
+ if (usb_cpu_init())
return -1;
#endif
-#ifdef CFG_USB_OHCI_BOARD_INIT
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
/* board dependant init */
- if(usb_board_init())
+ if (usb_board_init())
return -1;
#endif
- memset (&gohci, 0, sizeof (ohci_t));
+ memset(&gohci, 0, sizeof(ohci_t));
/* align the storage */
if ((__u32)&ghcca[0] & 0xff) {
@@ -1816,7 +1919,7 @@ int usb_lowlevel_init(void)
}
ptd = gtd;
gohci.hcca = phcca;
- memset (phcca, 0, sizeof (struct ohci_hcca));
+ memset(phcca, 0, sizeof(struct ohci_hcca));
gohci.disabled = 1;
gohci.sleeping = 0;
@@ -1838,40 +1941,37 @@ int usb_lowlevel_init(void)
} else
return -1;
#else
- gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE;
+ gohci.regs = (struct ohci_regs *)CONFIG_SYS_USB_OHCI_REGS_BASE;
#endif
gohci.flags = 0;
- gohci.slot_name = CFG_USB_OHCI_SLOT_NAME;
+ gohci.slot_name = CONFIG_SYS_USB_OHCI_SLOT_NAME;
if (hc_reset (&gohci) < 0) {
hc_release_ohci (&gohci);
err ("can't reset usb-%s", gohci.slot_name);
-#ifdef CFG_USB_OHCI_BOARD_INIT
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
/* board dependant cleanup */
usb_board_init_fail();
#endif
-#ifdef CFG_USB_OHCI_CPU_INIT
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
/* cpu dependant cleanup */
usb_cpu_init_fail();
#endif
return -1;
}
- /* FIXME this is a second HC reset; why?? */
- /* writel(gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
- wait_ms(10); */
- if (hc_start (&gohci) < 0) {
- err ("can't start usb-%s", gohci.slot_name);
- hc_release_ohci (&gohci);
+ if (hc_start(&gohci) < 0) {
+ err("can't start usb-%s", gohci.slot_name);
+ hc_release_ohci(&gohci);
/* Initialization failed */
-#ifdef CFG_USB_OHCI_BOARD_INIT
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
/* board dependant cleanup */
usb_board_stop();
#endif
-#ifdef CFG_USB_OHCI_CPU_INIT
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
/* cpu dependant cleanup */
usb_cpu_stop();
#endif
@@ -1879,7 +1979,7 @@ int usb_lowlevel_init(void)
}
#ifdef DEBUG
- ohci_dump (&gohci, 1);
+ ohci_dump(&gohci, 1);
#else
wait_ms(1);
#endif
@@ -1895,20 +1995,21 @@ int usb_lowlevel_stop(void)
return 0;
/* TODO release any interrupts, etc. */
/* call hc_release_ohci() here ? */
- hc_reset (&gohci);
+ hc_reset(&gohci);
-#ifdef CFG_USB_OHCI_BOARD_INIT
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
/* board dependant cleanup */
- if(usb_board_stop())
+ if (usb_board_stop())
return -1;
#endif
-#ifdef CFG_USB_OHCI_CPU_INIT
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
/* cpu dependant cleanup */
- if(usb_cpu_stop())
+ if (usb_cpu_stop())
return -1;
#endif
-
+ /* This driver is no longer initialised. It needs a new low-level
+ * init (board/cpu) before it can be used again. */
+ ohci_inited = 0;
return 0;
}
-#endif /* CONFIG_USB_OHCI_NEW */
diff --git a/drivers/usb/usb_ohci.h b/drivers/usb/usb_ohci.h
index 380cb4c..a547337 100644
--- a/drivers/usb/usb_ohci.h
+++ b/drivers/usb/usb_ohci.h
@@ -38,6 +38,41 @@ static int cc_to_error[16] = {
/* Not Access */ -1
};
+static const char *cc_to_string[16] = {
+ "No Error",
+ "CRC: Last data packet from endpoint contained a CRC error.",
+ "BITSTUFFING: Last data packet from endpoint contained a bit " \
+ "stuffing violation",
+ "DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
+ "that did not match the expected value.",
+ "STALL: TD was moved to the Done Queue because the endpoint returned" \
+ " a STALL PID",
+ "DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
+ "not provide a handshake (OUT)",
+ "PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
+ "(IN) or handshake (OUT)",
+ "UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
+ "value is not defined.",
+ "DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
+ "either the size of the maximum data packet allowed\n" \
+ "from the endpoint (found in MaximumPacketSize field\n" \
+ "of ED) or the remaining buffer size.",
+ "DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
+ "and that amount was not sufficient to fill the\n" \
+ "specified buffer",
+ "reserved1",
+ "reserved2",
+ "BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
+ "than it could be written to system memory",
+ "BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
+ "system memory fast enough to keep up with data USB " \
+ "data rate.",
+ "NOT ACCESSED: This code is set by software before the TD is placed" \
+ "on a list to be processed by the HC.(1)",
+ "NOT ACCESSED: This code is set by software before the TD is placed" \
+ "on a list to be processed by the HC.(2)",
+};
+
/* ED States */
#define ED_NEW 0x00
@@ -155,8 +190,8 @@ struct ohci_hcca {
/*
* Maximum number of root hub ports.
*/
-#ifndef CFG_USB_OHCI_MAX_ROOT_PORTS
-# error "CFG_USB_OHCI_MAX_ROOT_PORTS undefined!"
+#ifndef CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS
+# error "CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS undefined!"
#endif
/*
@@ -191,10 +226,13 @@ struct ohci_regs {
__u32 a;
__u32 b;
__u32 status;
- __u32 portstatus[CFG_USB_OHCI_MAX_ROOT_PORTS];
+ __u32 portstatus[CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS];
} roothub;
} __attribute((aligned(32)));
+/* Some EHCI controls */
+#define EHCI_USBCMD_OFF 0x20
+#define EHCI_USBCMD_HCRESET (1 << 1)
/* OHCI CONTROL AND STATUS REGISTER MASKS */
diff --git a/drivers/usb/usbdcore_ep0.c b/drivers/usb/usbdcore_ep0.c
index cf3f382..f6e017d 100644
--- a/drivers/usb/usbdcore_ep0.c
+++ b/drivers/usb/usbdcore_ep0.c
@@ -51,8 +51,6 @@
*/
#include <common.h>
-
-#if defined(CONFIG_USB_DEVICE)
#include "usbdcore.h"
#if 0
@@ -597,5 +595,3 @@ int ep0_recv_setup (struct urb *urb)
}
return -1;
}
-
-#endif
diff --git a/drivers/usb/usbdcore_mpc8xx.c b/drivers/usb/usbdcore_mpc8xx.c
index 122793c..0e311ad 100644
--- a/drivers/usb/usbdcore_mpc8xx.c
+++ b/drivers/usb/usbdcore_mpc8xx.c
@@ -58,8 +58,6 @@
*/
#include <common.h>
#include <config.h>
-
-#if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE)
#include <commproc.h>
#include "usbdcore.h"
#include "usbdcore_mpc8xx.h"
@@ -133,7 +131,7 @@ static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid);
int udc_init (void)
{
/* Init various pointers */
- immr = (immap_t *) CFG_IMMR;
+ immr = (immap_t *) CONFIG_SYS_IMMR;
cp = (cpm8xx_t *) & (immr->im_cpm);
usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]);
usbp = (usb_t *) & (cp->cp_scc[0]);
@@ -752,7 +750,7 @@ static short mpc8xx_udc_handle_txerr ()
static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid)
{
if ((*rx_cbdp)->cbd_sc & RX_BD_W) {
- *rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CFG_IMMR);
+ *rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CONFIG_SYS_IMMR);
} else {
(*rx_cbdp)++;
@@ -780,7 +778,7 @@ static void mpc8xx_udc_flush_tx_fifo (int epid)
usbp->uscom = 0x40 | 0;
/* reset ring */
- tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CFG_IMMR);
+ tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CONFIG_SYS_IMMR);
tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W);
@@ -886,7 +884,7 @@ static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
}
ep = epi->endpoint_address & 0x03;
- tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR);
+ tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR);
if (tx_cbdp->cbd_sc & TX_BD_R || usbp->usber & USB_E_TXB) {
mpc8xx_udc_flush_tx_fifo (ep);
@@ -903,7 +901,7 @@ static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
return -1;
}
- tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR);
+ tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR);
while (tx_cbdp->cbd_sc & TX_BD_R) {
};
tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc & TX_BD_W);
@@ -1187,10 +1185,10 @@ static void mpc8xx_udc_clock_init (volatile immap_t * immr,
volatile cpm8xx_t * cp)
{
-#if defined(CFG_USB_EXTC_CLK)
+#if defined(CONFIG_SYS_USB_EXTC_CLK)
/* This has been tested with a 48MHz crystal on CLK6 */
- switch (CFG_USB_EXTC_CLK) {
+ switch (CONFIG_SYS_USB_EXTC_CLK) {
case 1:
immr->im_ioport.iop_papar |= 0x0100;
immr->im_ioport.iop_padir &= ~0x0100;
@@ -1216,7 +1214,7 @@ static void mpc8xx_udc_clock_init (volatile immap_t * immr,
break;
}
-#elif defined(CFG_USB_BRGCLK)
+#elif defined(CONFIG_SYS_USB_BRGCLK)
/* This has been tested with brgclk == 50MHz */
int divisor = 0;
@@ -1227,13 +1225,13 @@ static void mpc8xx_udc_clock_init (volatile immap_t * immr,
return;
}
- /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz)
+ /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48MHz)
* but, can /probably/ live with close-ish alternative rates.
*/
divisor = (gd->cpu_clk / 48000000L) - 1;
cp->cp_sicr &= ~0x0000003F;
- switch (CFG_USB_BRGCLK) {
+ switch (CONFIG_SYS_USB_BRGCLK) {
case 1:
cp->cp_brgc1 |= (divisor | CPM_BRG_EN);
cp->cp_sicr &= ~0x2F;
@@ -1256,7 +1254,7 @@ static void mpc8xx_udc_clock_init (volatile immap_t * immr,
}
#else
-#error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined"
+#error "CONFIG_SYS_USB_EXTC_CLK or CONFIG_SYS_USB_BRGCLK must be defined"
#endif
}
@@ -1398,5 +1396,3 @@ static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment)
return retaddr;
}
-
-#endif /* CONFIG_MPC885_FAMILY && CONFIG_USB_DEVICE) */
diff --git a/drivers/usb/usbdcore_omap1510.c b/drivers/usb/usbdcore_omap1510.c
index 4e3239f..6b7b61b 100644
--- a/drivers/usb/usbdcore_omap1510.c
+++ b/drivers/usb/usbdcore_omap1510.c
@@ -27,9 +27,6 @@
*/
#include <common.h>
-
-#if ((defined(CONFIG_OMAP1510) || defined(CONFIG_OMAP1610)) && defined(CONFIG_USB_DEVICE))
-
#include <asm/io.h>
#ifdef CONFIG_OMAP_SX1
#include <i2c.h>
@@ -1064,7 +1061,7 @@ void omap1510_udc_noniso_irq (void)
*/
/* Called to start packet transmission. */
-void udc_endpoint_write (struct usb_endpoint_instance *endpoint)
+int udc_endpoint_write (struct usb_endpoint_instance *endpoint)
{
unsigned short epnum =
endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
@@ -1081,6 +1078,8 @@ void udc_endpoint_write (struct usb_endpoint_instance *endpoint)
/* deselect the endpoint FIFO */
outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
}
+
+ return 0;
}
/* Start to initialize h/w stuff */
@@ -1566,4 +1565,3 @@ void udc_unset_nak (int epid)
{
/* TODO: implement this functionality in omap1510 */
}
-#endif
diff --git a/drivers/video/ati_radeon_fb.c b/drivers/video/ati_radeon_fb.c
index 650380b..9ebb0b0 100644
--- a/drivers/video/ati_radeon_fb.c
+++ b/drivers/video/ati_radeon_fb.c
@@ -653,7 +653,7 @@ void *video_hw_init(void)
tmp = 0;
- videomode = CFG_DEFAULT_VIDEO_MODE;
+ videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
/* get video mode via environment */
if ((penv = getenv ("videomode")) != NULL) {
/* deceide if it is a string */
@@ -672,7 +672,7 @@ void *video_hw_init(void)
break;
}
if (i == VESA_MODES_COUNT) {
- printf ("no VESA Mode found, switching to mode 0x%x ", CFG_DEFAULT_VIDEO_MODE);
+ printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
i = 0;
}
res_mode = (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].resindex];
@@ -732,7 +732,7 @@ void *video_hw_init(void)
break;
}
- pGD->isaBase = CFG_ISA_IO_BASE_ADDRESS;
+ pGD->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS;
pGD->pciBase = rinfo->fb_base_phys;
pGD->frameAdrs = rinfo->fb_base_phys;
pGD->memSize = 64 * 1024 * 1024;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index b332a82..3a51cc7 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -24,7 +24,6 @@
#include <common.h>
#include <asm/io.h>
-#include <asm/arch/hardware.h>
#include <asm/arch/gpio.h>
#include <asm/arch/clk.h>
#include <lcd.h>
@@ -108,10 +107,7 @@ void lcd_ctrl_init(void *lcdbase)
if (panel_info.vl_tft)
value |= ATMEL_LCDC_DISTYPE_TFT;
- if (!(panel_info.vl_sync & ATMEL_LCDC_INVLINE_INVERTED))
- value |= ATMEL_LCDC_INVLINE_INVERTED;
- if (!(panel_info.vl_sync & ATMEL_LCDC_INVFRAME_INVERTED))
- value |= ATMEL_LCDC_INVFRAME_INVERTED;
+ value |= panel_info.vl_sync;
value |= (panel_info.vl_bpix << 5);
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON2, value);
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 79562ec..779aa4b 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -61,7 +61,7 @@
CONFIG_CONSOLE_CURSOR - on/off drawing cursor is done with delay
loop in VIDEO_TSTC_FCT (i8042)
- CFG_CONSOLE_BLINK_COUNT - value for delay loop - blink rate
+ CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate
CONFIG_CONSOLE_TIME - display time/date in upper right corner,
needs CONFIG_CMD_DATE and CONFIG_CONSOLE_CURSOR
CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner
@@ -314,10 +314,10 @@ void console_cursor (int state);
#else
#define SWAP16(x) (x)
#define SWAP32(x) (x)
-#if !defined(VIDEO_FB_16BPP_PIXEL_SWAP)
-#define SHORTSWAP32(x) (x)
-#else
+#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
#define SHORTSWAP32(x) ( ((x) >> 16) | ((x) << 16) )
+#else
+#define SHORTSWAP32(x) (x)
#endif
#endif
@@ -824,19 +824,19 @@ int video_display_bitmap (ulong bmp_image, int x, int y)
/*
* Could be a gzipped bmp image, try to decrompress...
*/
- len = CFG_VIDEO_LOGO_MAX_SIZE;
- dst = malloc(CFG_VIDEO_LOGO_MAX_SIZE);
+ len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
+ dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
if (dst == NULL) {
printf("Error: malloc in gunzip failed!\n");
return(1);
}
- if (gunzip(dst, CFG_VIDEO_LOGO_MAX_SIZE, (uchar *)bmp_image, &len) != 0) {
+ if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)bmp_image, &len) != 0) {
printf ("Error: no valid bmp or bmp.gz image at %lx\n", bmp_image);
free(dst);
return 1;
}
- if (len == CFG_VIDEO_LOGO_MAX_SIZE) {
- printf("Image could be truncated (increase CFG_VIDEO_LOGO_MAX_SIZE)!\n");
+ if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
+ printf("Image could be truncated (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
}
/*
@@ -932,12 +932,12 @@ int video_display_bitmap (ulong bmp_image, int x, int y)
xcount = width;
while (xcount--) {
cte = bmp->color_table[*bmap++];
-#if !defined(VIDEO_FB_16BPP_PIXEL_SWAP)
- FILL_15BIT_555RGB (cte.red, cte.green, cte.blue);
-#else
+#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
fill_555rgb_pswap (fb, xpos++, cte.red,
cte.green, cte.blue);
fb += 2;
+#else
+ FILL_15BIT_555RGB (cte.red, cte.green, cte.blue);
#endif
}
bmap += padded_line;
@@ -1006,12 +1006,12 @@ int video_display_bitmap (ulong bmp_image, int x, int y)
WATCHDOG_RESET ();
xcount = width;
while (xcount--) {
-#if !defined(VIDEO_FB_16BPP_PIXEL_SWAP)
- FILL_15BIT_555RGB (bmap[2], bmap[1], bmap[0]);
-#else
+#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
fill_555rgb_pswap (fb, xpos++, bmap[2],
bmap[1], bmap[0]);
fb += 2;
+#else
+ FILL_15BIT_555RGB (bmap[2], bmap[1], bmap[0]);
#endif
bmap += 3;
}
@@ -1136,11 +1136,11 @@ void logo_plot (void *screen, int width, int x, int y)
*dest = ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
break;
case GDF_15BIT_555RGB:
-#if !defined(VIDEO_FB_16BPP_PIXEL_SWAP)
+#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
+ fill_555rgb_pswap (dest, xpos++, r, g, b);
+#else
*(unsigned short *) dest =
SWAP16 ((unsigned short) (((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)));
-#else
- fill_555rgb_pswap (dest, xpos++, r, g, b);
#endif
break;
case GDF_16BIT_565RGB:
diff --git a/drivers/video/ct69000.c b/drivers/video/ct69000.c
index cae662e..ae219cc 100644
--- a/drivers/video/ct69000.c
+++ b/drivers/video/ct69000.c
@@ -1107,7 +1107,7 @@ video_hw_init (void)
pGD->gdfIndex = GDF_24BIT_888RGB;
break;
}
- pGD->isaBase = CFG_ISA_IO_BASE_ADDRESS;
+ pGD->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS;
pGD->pciBase = pci_mem_base;
pGD->frameAdrs = pci_mem_base;
pGD->memSize = chips_param->max_mem;
diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c
index 6c14b0d..22a85d1 100644
--- a/drivers/video/mb862xx.c
+++ b/drivers/video/mb862xx.c
@@ -357,7 +357,8 @@ void *video_hw_init (void)
board_disp_init();
#endif
-#if defined(CONFIG_LWMON5) && !(CONFIG_POST & CFG_POST_SYSMON)
+#if (defined(CONFIG_LWMON5) || \
+ defined(CONFIG_SOCRATES)) && !(CONFIG_POST & CONFIG_SYS_POST_SYSMON)
/* Lamp on */
board_backlight_switch (1);
#endif
diff --git a/drivers/video/smiLynxEM.c b/drivers/video/smiLynxEM.c
index 390dd56..59b43ef 100644
--- a/drivers/video/smiLynxEM.c
+++ b/drivers/video/smiLynxEM.c
@@ -596,7 +596,7 @@ void *video_hw_init (void)
tmp = 0;
- videomode = CFG_DEFAULT_VIDEO_MODE;
+ videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
/* get video mode via environment */
if ((penv = getenv ("videomode")) != NULL) {
/* deceide if it is a string */
@@ -615,7 +615,7 @@ void *video_hw_init (void)
break;
}
if (i == VESA_MODES_COUNT) {
- printf ("no VESA Mode found, switching to mode 0x%x ", CFG_DEFAULT_VIDEO_MODE);
+ printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
i = 0;
}
res_mode =
@@ -669,7 +669,7 @@ void *video_hw_init (void)
break;
}
- pGD->isaBase = CFG_ISA_IO;
+ pGD->isaBase = CONFIG_SYS_ISA_IO;
pGD->pciBase = pci_mem_base;
pGD->dprBase = (pci_mem_base + 0x400000 + 0x8000);
pGD->vprBase = (pci_mem_base + 0x400000 + 0xc000);
diff --git a/drivers/video/videomodes.c b/drivers/video/videomodes.c
index c81e5bc..d27ce1d 100644
--- a/drivers/video/videomodes.c
+++ b/drivers/video/videomodes.c
@@ -23,7 +23,7 @@
/************************************************************************
Get Parameters for the video mode:
- The default video mode can be defined in CFG_DEFAULT_VIDEO_MODE.
+ The default video mode can be defined in CONFIG_SYS_DEFAULT_VIDEO_MODE.
If undefined, default video mode is set to 0x301
Parameters can be set via the variable "videomode" in the environment.
2 diferent ways are possible:
diff --git a/drivers/video/videomodes.h b/drivers/video/videomodes.h
index e2dffe7..0d7c335 100644
--- a/drivers/video/videomodes.h
+++ b/drivers/video/videomodes.h
@@ -22,8 +22,8 @@
*/
-#ifndef CFG_DEFAULT_VIDEO_MODE
-#define CFG_DEFAULT_VIDEO_MODE 0x301
+#ifndef CONFIG_SYS_DEFAULT_VIDEO_MODE
+#define CONFIG_SYS_DEFAULT_VIDEO_MODE 0x301
#endif
/* Some mode definitions */