summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bios_emulator/atibios.c161
-rw-r--r--drivers/bios_emulator/include/x86emu/debug.h2
-rw-r--r--drivers/bios_emulator/x86emu/ops.c2
-rw-r--r--drivers/block/ahci.c20
-rw-r--r--drivers/core/device-remove.c16
-rw-r--r--drivers/core/device.c121
-rw-r--r--drivers/core/root.c8
-rw-r--r--drivers/core/uclass.c34
-rw-r--r--drivers/crypto/Kconfig1
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/fsl/Kconfig6
-rw-r--r--drivers/crypto/fsl/Makefile2
-rw-r--r--drivers/crypto/fsl/fsl_rsa.c60
-rw-r--r--drivers/crypto/fsl/jobdesc.c28
-rw-r--r--drivers/crypto/fsl/jobdesc.h5
-rw-r--r--drivers/crypto/fsl/rsa_caam.h28
-rw-r--r--drivers/crypto/fsl/sec.c184
-rw-r--r--drivers/crypto/rsa_mod_exp/Kconfig5
-rw-r--r--drivers/crypto/rsa_mod_exp/Makefile7
-rw-r--r--drivers/crypto/rsa_mod_exp/mod_exp_sw.c39
-rw-r--r--drivers/crypto/rsa_mod_exp/mod_exp_uclass.c31
-rw-r--r--drivers/ddr/fsl/fsl_ddr_gen4.c8
-rw-r--r--drivers/ddr/mvebu/Makefile14
-rw-r--r--drivers/ddr/mvebu/ddr3_axp.h510
-rw-r--r--drivers/ddr/mvebu/ddr3_axp_config.h146
-rw-r--r--drivers/ddr/mvebu/ddr3_axp_mc_static.h284
-rw-r--r--drivers/ddr/mvebu/ddr3_axp_training_static.h770
-rw-r--r--drivers/ddr/mvebu/ddr3_axp_vars.h226
-rw-r--r--drivers/ddr/mvebu/ddr3_dfs.c1552
-rw-r--r--drivers/ddr/mvebu/ddr3_dqs.c1374
-rw-r--r--drivers/ddr/mvebu/ddr3_hw_training.c1115
-rw-r--r--drivers/ddr/mvebu/ddr3_hw_training.h392
-rw-r--r--drivers/ddr/mvebu/ddr3_init.c1219
-rw-r--r--drivers/ddr/mvebu/ddr3_init.h143
-rw-r--r--drivers/ddr/mvebu/ddr3_patterns_64bit.h924
-rw-r--r--drivers/ddr/mvebu/ddr3_pbs.c1592
-rw-r--r--drivers/ddr/mvebu/ddr3_read_leveling.c1214
-rw-r--r--drivers/ddr/mvebu/ddr3_sdram.c669
-rw-r--r--drivers/ddr/mvebu/ddr3_spd.c1300
-rw-r--r--drivers/ddr/mvebu/ddr3_write_leveling.c1366
-rw-r--r--drivers/ddr/mvebu/xor.c436
-rw-r--r--drivers/ddr/mvebu/xor.h70
-rw-r--r--drivers/ddr/mvebu/xor_regs.h103
-rw-r--r--drivers/demo/demo-shape.c71
-rw-r--r--drivers/demo/demo-uclass.c20
-rw-r--r--drivers/fpga/fpga.c2
-rw-r--r--drivers/fpga/xilinx.c22
-rw-r--r--drivers/gpio/gpio-uclass.c396
-rw-r--r--drivers/gpio/s5p_gpio.c13
-rw-r--r--drivers/gpio/sandbox.c20
-rw-r--r--drivers/gpio/tegra_gpio.c18
-rw-r--r--drivers/i2c/Kconfig22
-rw-r--r--drivers/i2c/Makefile3
-rw-r--r--drivers/i2c/i2c-uclass-compat.c108
-rw-r--r--drivers/i2c/i2c-uclass.c81
-rw-r--r--drivers/i2c/i2c-uniphier-f.c367
-rw-r--r--drivers/i2c/i2c-uniphier.c227
-rw-r--r--drivers/i2c/s3c24x0_i2c.c237
-rw-r--r--drivers/i2c/sandbox_i2c.c30
-rw-r--r--drivers/i2c/tegra_i2c.c18
-rw-r--r--drivers/misc/cros_ec.c34
-rw-r--r--drivers/misc/cros_ec_i2c.c82
-rw-r--r--drivers/misc/cros_ec_spi.c70
-rw-r--r--drivers/mmc/Kconfig9
-rw-r--r--drivers/mmc/Makefile2
-rw-r--r--drivers/mmc/mmc.c307
-rw-r--r--drivers/mmc/omap_hsmmc.c4
-rw-r--r--drivers/mmc/pci_mmc.c42
-rw-r--r--drivers/mmc/s5p_sdhci.c20
-rw-r--r--drivers/mmc/sh_sdhi.c695
-rw-r--r--drivers/mmc/sunxi_mmc.c32
-rw-r--r--drivers/mmc/tegra_mmc.c36
-rw-r--r--drivers/mmc/zynq_sdhci.c4
-rw-r--r--drivers/mtd/nand/atmel_nand.c9
-rw-r--r--drivers/mtd/nand/atmel_nand_ecc.h20
-rw-r--r--drivers/mtd/nand/nand_base.c5
-rw-r--r--drivers/mtd/nand/tegra_nand.c9
-rw-r--r--drivers/mtd/spi/sandbox.c12
-rw-r--r--drivers/mtd/spi/sf_probe.c3
-rw-r--r--drivers/mtd/ubi/build.c8
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/designware.c4
-rw-r--r--drivers/net/e1000.c31
-rw-r--r--drivers/net/fm/eth.c30
-rw-r--r--drivers/net/fm/t1040.c3
-rw-r--r--drivers/net/mpc5xxx_fec.c5
-rw-r--r--drivers/net/mvgbe.c4
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/aquantia.c156
-rw-r--r--drivers/net/phy/micrel.c58
-rw-r--r--drivers/net/phy/phy.c3
-rw-r--r--drivers/net/smc91111.h31
-rw-r--r--drivers/net/tsec.c2
-rw-r--r--drivers/net/vsc9953.c497
-rw-r--r--drivers/net/xilinx_ll_temac.c2
-rw-r--r--drivers/net/zynq_gem.c5
-rw-r--r--drivers/pci/pci.c43
-rw-r--r--drivers/pci/pci_auto.c28
-rw-r--r--drivers/pci/pci_rom.c74
-rw-r--r--drivers/pci/pci_tegra.c5
-rw-r--r--drivers/power/Kconfig10
-rw-r--r--drivers/power/as3722.c6
-rw-r--r--drivers/power/axp209.c14
-rw-r--r--drivers/power/axp221.c37
-rw-r--r--drivers/power/tps6586x.c4
-rw-r--r--drivers/rtc/mc146818.c121
-rw-r--r--drivers/serial/serial-uclass.c1
-rw-r--r--drivers/serial/serial_zynq.c30
-rw-r--r--drivers/spi/cadence_qspi.c1
-rw-r--r--drivers/spi/designware_spi.c1
-rw-r--r--drivers/spi/exynos_spi.c1
-rw-r--r--drivers/spi/ich.c66
-rw-r--r--drivers/spi/ich.h11
-rw-r--r--drivers/spi/sandbox_spi.c1
-rw-r--r--drivers/spi/soft_spi.c72
-rw-r--r--drivers/spi/spi-uclass.c95
-rw-r--r--drivers/spi/tegra114_spi.c1
-rw-r--r--drivers/spi/tegra20_sflash.c1
-rw-r--r--drivers/spi/tegra20_slink.c1
-rw-r--r--drivers/usb/eth/asix88179.c14
-rw-r--r--drivers/usb/gadget/composite.c8
-rw-r--r--drivers/usb/gadget/f_dfu.c8
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c4
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-exynos.c10
-rw-r--r--drivers/usb/host/ehci-hcd.c4
-rw-r--r--drivers/usb/host/ehci-pci.c53
-rw-r--r--drivers/usb/host/ehci-tegra.c38
-rw-r--r--drivers/usb/host/xhci-exynos5.c10
-rw-r--r--drivers/usb/host/xhci-pci.c60
-rw-r--r--drivers/usb/musb-new/Makefile1
-rw-r--r--drivers/usb/musb-new/musb_host.c12
-rw-r--r--drivers/usb/musb-new/musb_host.h1
-rw-r--r--drivers/usb/musb-new/musb_regs.h92
-rw-r--r--drivers/usb/musb-new/musb_uboot.c178
-rw-r--r--drivers/usb/musb-new/sunxi.c279
-rw-r--r--drivers/usb/musb-new/usb-compat.h1
-rw-r--r--drivers/video/Kconfig88
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/atmel_hlcdfb.c13
-rw-r--r--drivers/video/atmel_lcdfb.c53
-rw-r--r--drivers/video/cfb_console.c29
-rw-r--r--drivers/video/exynos_fb.c9
-rw-r--r--drivers/video/hitachi_tx18d42vm_lcd.c81
-rw-r--r--drivers/video/hitachi_tx18d42vm_lcd.h9
-rw-r--r--drivers/video/mpc8xx_lcd.c29
-rw-r--r--drivers/video/pxa_lcd.c6
-rw-r--r--drivers/video/sed13806.c5
-rw-r--r--drivers/video/ssd2828.c436
-rw-r--r--drivers/video/ssd2828.h128
-rw-r--r--drivers/video/sunxi_display.c213
-rw-r--r--drivers/video/tegra.c54
-rw-r--r--drivers/video/vesa_fb.c67
-rw-r--r--drivers/video/x86_fb.c38
-rw-r--r--drivers/watchdog/at91sam9_wdt.c4
155 files changed, 21757 insertions, 986 deletions
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
index 93b815c..7ea5fa6 100644
--- a/drivers/bios_emulator/atibios.c
+++ b/drivers/bios_emulator/atibios.c
@@ -62,40 +62,158 @@ static u32 saveBaseAddress14;
static u32 saveBaseAddress18;
static u32 saveBaseAddress20;
-static void atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
- struct vbe_mode_info *mode_info)
+/* Addres im memory of VBE region */
+const int vbe_offset = 0x2000;
+
+static const void *bios_ptr(const void *buf, BE_VGAInfo *vga_info,
+ u32 x86_dword_ptr)
+{
+ u32 seg_ofs, flat;
+
+ seg_ofs = le32_to_cpu(x86_dword_ptr);
+ flat = ((seg_ofs & 0xffff0000) >> 12) | (seg_ofs & 0xffff);
+ if (flat >= 0xc0000)
+ return vga_info->BIOSImage + flat - 0xc0000;
+ else
+ return buf + (flat - vbe_offset);
+}
+
+static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
+ int vesa_mode, struct vbe_mode_info *mode_info)
+{
+ void *buffer = (void *)(M.mem_base + vbe_offset);
+ u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
+ u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
+ struct vesa_mode_info *vm;
+ struct vbe_info *info;
+ const u16 *modes_bios, *ptr;
+ u16 *modes;
+ int size;
+
+ debug("VBE: Getting information\n");
+ regs->e.eax = VESA_GET_INFO;
+ regs->e.esi = buffer_seg;
+ regs->e.edi = buffer_adr;
+ info = buffer;
+ memset(info, '\0', sizeof(*info));
+ strcpy(info->signature, "VBE2");
+ BE_int86(0x10, regs, regs);
+ if (regs->e.eax != 0x4f) {
+ debug("VESA_GET_INFO: error %x\n", regs->e.eax);
+ return -ENOSYS;
+ }
+ debug("version %x\n", le16_to_cpu(info->version));
+ debug("oem '%s'\n", (char *)bios_ptr(buffer, vga_info,
+ info->oem_string_ptr));
+ debug("vendor '%s'\n", (char *)bios_ptr(buffer, vga_info,
+ info->vendor_name_ptr));
+ debug("product '%s'\n", (char *)bios_ptr(buffer, vga_info,
+ info->product_name_ptr));
+ debug("rev '%s'\n", (char *)bios_ptr(buffer, vga_info,
+ info->product_rev_ptr));
+ modes_bios = bios_ptr(buffer, vga_info, info->modes_ptr);
+ debug("Modes: ");
+ for (ptr = modes_bios; *ptr != 0xffff; ptr++)
+ debug("%x ", le16_to_cpu(*ptr));
+ debug("\nmemory %dMB\n", le16_to_cpu(info->total_memory) >> 4);
+ size = (ptr - modes_bios) * sizeof(u16) + 2;
+ modes = malloc(size);
+ if (!modes)
+ return -ENOMEM;
+ memcpy(modes, modes_bios, size);
+
+ regs->e.eax = VESA_GET_CUR_MODE;
+ BE_int86(0x10, regs, regs);
+ if (regs->e.eax != 0x4f) {
+ debug("VESA_GET_CUR_MODE: error %x\n", regs->e.eax);
+ return -ENOSYS;
+ }
+ debug("Current mode %x\n", regs->e.ebx);
+
+ for (ptr = modes; *ptr != 0xffff; ptr++) {
+ int mode = le16_to_cpu(*ptr);
+ bool linear_ok;
+ int attr;
+
+ break;
+ debug("Mode %x: ", mode);
+ memset(buffer, '\0', sizeof(struct vbe_mode_info));
+ regs->e.eax = VESA_GET_MODE_INFO;
+ regs->e.ebx = 0;
+ regs->e.ecx = mode;
+ regs->e.edx = 0;
+ regs->e.esi = buffer_seg;
+ regs->e.edi = buffer_adr;
+ BE_int86(0x10, regs, regs);
+ if (regs->e.eax != 0x4f) {
+ debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
+ continue;
+ }
+ memcpy(mode_info->mode_info_block, buffer,
+ sizeof(struct vesa_mode_info));
+ mode_info->valid = true;
+ vm = &mode_info->vesa;
+ attr = le16_to_cpu(vm->mode_attributes);
+ linear_ok = attr & 0x80;
+ debug("res %d x %d, %d bpp, mm %d, (Linear %s, attr %02x)\n",
+ le16_to_cpu(vm->x_resolution),
+ le16_to_cpu(vm->y_resolution),
+ vm->bits_per_pixel, vm->memory_model,
+ linear_ok ? "OK" : "not available",
+ attr);
+ debug("\tRGB pos=%d,%d,%d, size=%d,%d,%d\n",
+ vm->red_mask_pos, vm->green_mask_pos, vm->blue_mask_pos,
+ vm->red_mask_size, vm->green_mask_size,
+ vm->blue_mask_size);
+ }
+
+ return 0;
+}
+
+static int atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
+ struct vbe_mode_info *mode_info)
{
+ void *buffer = (void *)(M.mem_base + vbe_offset);
+ u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
+ u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
+ struct vesa_mode_info *vm;
+
debug("VBE: Setting VESA mode %#04x\n", vesa_mode);
- /* request linear framebuffer mode */
- vesa_mode |= (1 << 14);
- /* request clearing of framebuffer */
- vesa_mode &= ~(1 << 15);
regs->e.eax = VESA_SET_MODE;
regs->e.ebx = vesa_mode;
+ /* request linear framebuffer mode and don't clear display */
+ regs->e.ebx |= (1 << 14) | (1 << 15);
BE_int86(0x10, regs, regs);
+ if (regs->e.eax != 0x4f) {
+ debug("VESA_SET_MODE: error %x\n", regs->e.eax);
+ return -ENOSYS;
+ }
- int offset = 0x2000;
- void *buffer = (void *)(M.mem_base + offset);
-
- u16 buffer_seg = (((unsigned long)offset) >> 4) & 0xff00;
- u16 buffer_adr = ((unsigned long)offset) & 0xffff;
+ memset(buffer, '\0', sizeof(struct vbe_mode_info));
+ debug("VBE: Geting info for VESA mode %#04x\n", vesa_mode);
regs->e.eax = VESA_GET_MODE_INFO;
- regs->e.ebx = 0;
regs->e.ecx = vesa_mode;
- regs->e.edx = 0;
regs->e.esi = buffer_seg;
regs->e.edi = buffer_adr;
BE_int86(0x10, regs, regs);
+ if (regs->e.eax != 0x4f) {
+ debug("VESA_GET_MODE_INFO: error %x\n", regs->e.eax);
+ return -ENOSYS;
+ }
+
memcpy(mode_info->mode_info_block, buffer,
- sizeof(struct vbe_mode_info));
+ sizeof(struct vesa_mode_info));
mode_info->valid = true;
+ mode_info->video_mode = vesa_mode;
+ vm = &mode_info->vesa;
+ vm->x_resolution = le16_to_cpu(vm->x_resolution);
+ vm->y_resolution = le16_to_cpu(vm->y_resolution);
+ vm->bytes_per_scanline = le16_to_cpu(vm->bytes_per_scanline);
+ vm->phys_base_ptr = le32_to_cpu(vm->phys_base_ptr);
+ vm->mode_attributes = le16_to_cpu(vm->mode_attributes);
+ debug("VBE: Init complete\n");
- vesa_mode |= (1 << 14);
- /* request clearing of framebuffer */
- vesa_mode &= ~(1 << 15);
- regs->e.eax = VESA_SET_MODE;
- regs->e.ebx = vesa_mode;
- BE_int86(0x10, regs, regs);
+ return 0;
}
/****************************************************************************
@@ -132,6 +250,9 @@ static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo *vga_info,
/*Cleanup and exit*/
BE_getVGA(vga_info);
+ /* Useful for debugging */
+ if (0)
+ atibios_debug_mode(vga_info, &regs, vesa_mode, mode_info);
if (vesa_mode != -1)
atibios_set_vesa_mode(&regs, vesa_mode, mode_info);
}
diff --git a/drivers/bios_emulator/include/x86emu/debug.h b/drivers/bios_emulator/include/x86emu/debug.h
index 304b2bf..4962a2a 100644
--- a/drivers/bios_emulator/include/x86emu/debug.h
+++ b/drivers/bios_emulator/include/x86emu/debug.h
@@ -102,7 +102,7 @@
# define ERR_PRINTF(x) printf(x)
# define ERR_PRINTF2(x, y) printf(x, y)
-#ifdef CONFIG_X86EMU_DEBUG103
+#ifdef CONFIG_X86EMU_DEBUG
# define DECODE_PRINTF(x) if (DEBUG_DECODE()) \
diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c
index 2bb5e2d..5752fee 100644
--- a/drivers/bios_emulator/x86emu/ops.c
+++ b/drivers/bios_emulator/x86emu/ops.c
@@ -179,7 +179,7 @@ void x86emuOp_illegal_op(
{
START_OF_INSTR();
if (M.x86.R_SP != 0) {
- ERR_PRINTF("ILLEGAL X86 OPCODE\n");
+ DB(printf("ILLEGAL X86 OPCODE\n"));
TRACE_REGS();
DB( printk("%04x:%04x: %02X ILLEGAL X86 OPCODE!\n",
M.x86.R_CS, M.x86.R_IP-1,op1));
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 37d2d2a..c908fab 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -513,6 +513,20 @@ static void ahci_set_feature(u8 port)
}
#endif
+static int wait_spinup(volatile u8 *port_mmio)
+{
+ ulong start;
+ u32 tf_data;
+
+ start = get_timer(0);
+ do {
+ tf_data = readl(port_mmio + PORT_TFDATA);
+ if (!(tf_data & ATA_BUSY))
+ return 0;
+ } while (get_timer(start) < WAIT_MS_SPINUP);
+
+ return -ETIMEDOUT;
+}
static int ahci_port_start(u8 port)
{
@@ -579,7 +593,11 @@ static int ahci_port_start(u8 port)
debug("Exit start port %d\n", port);
- return 0;
+ /*
+ * Make sure interface is not busy based on error and status
+ * information from task file data register before proceeding
+ */
+ return wait_spinup(port_mmio);
}
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 8fc6b71..3a5f48d 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -88,6 +88,14 @@ int device_unbind(struct udevice *dev)
if (ret)
return ret;
+ if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+ free(dev->platdata);
+ dev->platdata = NULL;
+ }
+ if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev->parent_platdata);
+ dev->parent_platdata = NULL;
+ }
ret = uclass_unbind_device(dev);
if (ret)
return ret;
@@ -111,10 +119,6 @@ void device_free(struct udevice *dev)
free(dev->priv);
dev->priv = NULL;
}
- if (dev->flags & DM_FLAG_ALLOC_PDATA) {
- free(dev->platdata);
- dev->platdata = NULL;
- }
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
if (size) {
free(dev->uclass_priv);
@@ -122,6 +126,10 @@ void device_free(struct udevice *dev)
}
if (dev->parent) {
size = dev->parent->driver->per_child_auto_alloc_size;
+ if (!size) {
+ size = dev->parent->uclass->uc_drv->
+ per_child_auto_alloc_size;
+ }
if (size) {
free(dev->parent_priv);
dev->parent_priv = NULL;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 963b16f..b73d3b8 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -53,27 +53,47 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
dev->driver = drv;
dev->uclass = uc;
- /*
- * For some devices, such as a SPI or I2C bus, the 'reg' property
- * is a reasonable indicator of the sequence number. But if there is
- * an alias, we use that in preference. In any case, this is just
- * a 'requested' sequence, and will be resolved (and ->seq updated)
- * when the device is probed.
- */
dev->seq = -1;
+ dev->req_seq = -1;
#ifdef CONFIG_OF_CONTROL
- dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
- if (!IS_ERR_VALUE(dev->req_seq))
- dev->req_seq &= INT_MAX;
- if (uc->uc_drv->name && of_offset != -1) {
- fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
- &dev->req_seq);
+ /*
+ * Some devices, such as a SPI bus, I2C bus and serial ports are
+ * numbered using aliases.
+ *
+ * This is just a 'requested' sequence, and will be
+ * resolved (and ->seq updated) when the device is probed.
+ */
+ if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
+ if (uc->uc_drv->name && of_offset != -1) {
+ fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name,
+ of_offset, &dev->req_seq);
+ }
}
-#else
- dev->req_seq = -1;
#endif
- if (!dev->platdata && drv->platdata_auto_alloc_size)
+ if (!dev->platdata && drv->platdata_auto_alloc_size) {
dev->flags |= DM_FLAG_ALLOC_PDATA;
+ dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
+ if (!dev->platdata) {
+ ret = -ENOMEM;
+ goto fail_alloc1;
+ }
+ }
+ if (parent) {
+ int size = parent->driver->per_child_platdata_auto_alloc_size;
+
+ if (!size) {
+ size = parent->uclass->uc_drv->
+ per_child_platdata_auto_alloc_size;
+ }
+ if (size) {
+ dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
+ dev->parent_platdata = calloc(1, size);
+ if (!dev->parent_platdata) {
+ ret = -ENOMEM;
+ goto fail_alloc2;
+ }
+ }
+ }
/* put dev into parent's successor list */
if (parent)
@@ -81,28 +101,51 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
ret = uclass_bind_device(dev);
if (ret)
- goto fail_bind;
+ goto fail_uclass_bind;
/* if we fail to bind we remove device from successors and free it */
if (drv->bind) {
ret = drv->bind(dev);
- if (ret) {
- if (uclass_unbind_device(dev)) {
- dm_warn("Failed to unbind dev '%s' on error path\n",
- dev->name);
- }
+ if (ret)
goto fail_bind;
- }
}
+ if (parent && parent->driver->child_post_bind) {
+ ret = parent->driver->child_post_bind(dev);
+ if (ret)
+ goto fail_child_post_bind;
+ }
+
if (parent)
dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
*devp = dev;
return 0;
+fail_child_post_bind:
+ if (drv->unbind && drv->unbind(dev)) {
+ dm_warn("unbind() method failed on dev '%s' on error path\n",
+ dev->name);
+ }
+
fail_bind:
+ if (uclass_unbind_device(dev)) {
+ dm_warn("Failed to unbind dev '%s' on error path\n",
+ dev->name);
+ }
+fail_uclass_bind:
list_del(&dev->sibling_node);
+ if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev->parent_platdata);
+ dev->parent_platdata = NULL;
+ }
+fail_alloc2:
+ if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+ free(dev->platdata);
+ dev->platdata = NULL;
+ }
+fail_alloc1:
free(dev);
+
return ret;
}
@@ -137,7 +180,7 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
drv = dev->driver;
assert(drv);
- /* Allocate private data and platdata if requested */
+ /* Allocate private data if requested */
if (drv->priv_auto_alloc_size) {
dev->priv = calloc(1, drv->priv_auto_alloc_size);
if (!dev->priv) {
@@ -146,13 +189,6 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
}
}
/* Allocate private data if requested */
- if (dev->flags & DM_FLAG_ALLOC_PDATA) {
- dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
- if (!dev->platdata) {
- ret = -ENOMEM;
- goto fail;
- }
- }
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
if (size) {
dev->uclass_priv = calloc(1, size);
@@ -165,6 +201,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
/* Ensure all parents are probed */
if (dev->parent) {
size = dev->parent->driver->per_child_auto_alloc_size;
+ if (!size) {
+ size = dev->parent->uclass->uc_drv->
+ per_child_auto_alloc_size;
+ }
if (size) {
dev->parent_priv = calloc(1, size);
if (!dev->parent_priv) {
@@ -187,6 +227,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
}
dev->seq = seq;
+ ret = uclass_pre_probe_child(dev);
+ if (ret)
+ goto fail;
+
if (dev->parent && dev->parent->driver->child_pre_probe) {
ret = dev->parent->driver->child_pre_probe(dev);
if (ret)
@@ -241,6 +285,16 @@ void *dev_get_platdata(struct udevice *dev)
return dev->platdata;
}
+void *dev_get_parent_platdata(struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device", __func__);
+ return NULL;
+ }
+
+ return dev->parent_platdata;
+}
+
void *dev_get_priv(struct udevice *dev)
{
if (!dev) {
@@ -390,3 +444,8 @@ ulong dev_get_of_data(struct udevice *dev)
{
return dev->of_id->data;
}
+
+enum uclass_id device_get_uclass_id(struct udevice *dev)
+{
+ return dev->uclass->uc_drv->id;
+}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 47b3acf..73e3c72 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <errno.h>
+#include <fdtdec.h>
#include <malloc.h>
#include <libfdt.h>
#include <dm/device.h>
@@ -49,6 +50,9 @@ int dm_init(void)
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
if (ret)
return ret;
+#ifdef CONFIG_OF_CONTROL
+ DM_ROOT_NON_CONST->of_offset = 0;
+#endif
ret = device_probe(DM_ROOT_NON_CONST);
if (ret)
return ret;
@@ -89,6 +93,10 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
if (pre_reloc_only &&
!fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
continue;
+ if (!fdtdec_get_is_enabled(blob, offset)) {
+ dm_dbg(" - ignoring disabled device\n");
+ continue;
+ }
err = lists_bind_fdt(parent, blob, offset, NULL);
if (err && !ret)
ret = err;
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 901b06e..289a5d2 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -319,18 +319,29 @@ int uclass_bind_device(struct udevice *dev)
int ret;
uc = dev->uclass;
-
list_add_tail(&dev->uclass_node, &uc->dev_head);
+ if (dev->parent) {
+ struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
+
+ if (uc_drv->child_post_bind) {
+ ret = uc_drv->child_post_bind(dev);
+ if (ret)
+ goto err;
+ }
+ }
if (uc->uc_drv->post_bind) {
ret = uc->uc_drv->post_bind(dev);
- if (ret) {
- list_del(&dev->uclass_node);
- return ret;
- }
+ if (ret)
+ goto err;
}
return 0;
+err:
+ /* There is no need to undo the parent's post_bind call */
+ list_del(&dev->uclass_node);
+
+ return ret;
}
int uclass_unbind_device(struct udevice *dev)
@@ -380,6 +391,19 @@ int uclass_resolve_seq(struct udevice *dev)
return seq;
}
+int uclass_pre_probe_child(struct udevice *dev)
+{
+ struct uclass_driver *uc_drv;
+
+ if (!dev->parent)
+ return 0;
+ uc_drv = dev->parent->uclass->uc_drv;
+ if (uc_drv->child_pre_probe)
+ return uc_drv->child_pre_probe(dev);
+
+ return 0;
+}
+
int uclass_post_probe_device(struct udevice *dev)
{
struct uclass_driver *uc_drv = dev->uclass->uc_drv;
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index e69de29..bd26a2b 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -0,0 +1 @@
+source drivers/crypto/fsl/Kconfig
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 7b79237..fb8c10b 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -6,4 +6,5 @@
#
obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o
+obj-y += rsa_mod_exp/
obj-y += fsl/
diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
new file mode 100644
index 0000000..86b2f2f
--- /dev/null
+++ b/drivers/crypto/fsl/Kconfig
@@ -0,0 +1,6 @@
+config FSL_CAAM
+ bool "Freescale Crypto Driver Support"
+ help
+ Enables the Freescale's Cryptographic Accelerator and Assurance
+ Module (CAAM), also known as the SEC version 4 (SEC4). The driver uses
+ Job Ring as interface to communicate with CAAM.
diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile
index cb13d2e..c0cf642 100644
--- a/drivers/crypto/fsl/Makefile
+++ b/drivers/crypto/fsl/Makefile
@@ -6,5 +6,7 @@
# Version 2 as published by the Free Software Foundation.
#
+obj-y += sec.o
obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
obj-$(CONFIG_CMD_BLOB) += fsl_blob.o
+obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
diff --git a/drivers/crypto/fsl/fsl_rsa.c b/drivers/crypto/fsl/fsl_rsa.c
new file mode 100644
index 0000000..cf1c4c1
--- /dev/null
+++ b/drivers/crypto/fsl/fsl_rsa.c
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc.
+ * Author: Ruchika Gupta <ruchika.gupta@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <asm/types.h>
+#include <malloc.h>
+#include "jobdesc.h"
+#include "desc.h"
+#include "jr.h"
+#include "rsa_caam.h"
+#include <u-boot/rsa-mod-exp.h>
+
+int fsl_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+ struct key_prop *prop, uint8_t *out)
+{
+ uint32_t keylen;
+ struct pk_in_params pkin;
+ uint32_t desc[MAX_CAAM_DESCSIZE];
+ int ret;
+
+ /* Length in bytes */
+ keylen = prop->num_bits / 8;
+
+ pkin.a = sig;
+ pkin.a_siz = sig_len;
+ pkin.n = prop->modulus;
+ pkin.n_siz = keylen;
+ pkin.e = prop->public_exponent;
+ pkin.e_siz = prop->exp_len;
+
+ inline_cnstr_jobdesc_pkha_rsaexp(desc, &pkin, out, sig_len);
+
+ ret = run_descriptor_jr(desc);
+ if (ret) {
+ debug("%s: RSA failed to verify: %d\n", __func__, ret);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static const struct mod_exp_ops fsl_mod_exp_ops = {
+ .mod_exp = fsl_mod_exp,
+};
+
+U_BOOT_DRIVER(fsl_rsa_mod_exp) = {
+ .name = "fsl_rsa_mod_exp",
+ .id = UCLASS_MOD_EXP,
+ .ops = &fsl_mod_exp_ops,
+};
+
+U_BOOT_DEVICE(fsl_rsa) = {
+ .name = "fsl_rsa_mod_exp",
+};
diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c
index 1386bae..cc0dced 100644
--- a/drivers/crypto/fsl/jobdesc.c
+++ b/drivers/crypto/fsl/jobdesc.c
@@ -11,6 +11,7 @@
#include <common.h>
#include "desc_constr.h"
#include "jobdesc.h"
+#include "rsa_caam.h"
#define KEY_BLOB_SIZE 32
#define MAC_SIZE 16
@@ -123,3 +124,30 @@ void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc)
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
OP_ALG_RNG4_SK);
}
+
+/* Change key size to bytes form bits in calling function*/
+void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
+ struct pk_in_params *pkin, uint8_t *out,
+ uint32_t out_siz)
+{
+ dma_addr_t dma_addr_e, dma_addr_a, dma_addr_n, dma_addr_out;
+
+ dma_addr_e = virt_to_phys((void *)pkin->e);
+ dma_addr_a = virt_to_phys((void *)pkin->a);
+ dma_addr_n = virt_to_phys((void *)pkin->n);
+ dma_addr_out = virt_to_phys((void *)out);
+
+ init_job_desc(desc, 0);
+ append_key(desc, dma_addr_e, pkin->e_siz, KEY_DEST_PKHA_E | CLASS_1);
+
+ append_fifo_load(desc, dma_addr_a,
+ pkin->a_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_A);
+
+ append_fifo_load(desc, dma_addr_n,
+ pkin->n_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_N);
+
+ append_operation(desc, OP_TYPE_PK | OP_ALG_PK | OP_ALG_PKMODE_MOD_EXPO);
+
+ append_fifo_store(desc, dma_addr_out, out_siz,
+ LDST_CLASS_1_CCB | FIFOST_TYPE_PKHA_B);
+}
diff --git a/drivers/crypto/fsl/jobdesc.h b/drivers/crypto/fsl/jobdesc.h
index 3cf7226..84b3edd 100644
--- a/drivers/crypto/fsl/jobdesc.h
+++ b/drivers/crypto/fsl/jobdesc.h
@@ -10,6 +10,7 @@
#include <common.h>
#include <asm/io.h>
+#include "rsa_caam.h"
#define KEY_IDNFR_SZ_BYTES 16
@@ -26,4 +27,8 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
uint32_t out_sz);
void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc);
+
+void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
+ struct pk_in_params *pkin, uint8_t *out,
+ uint32_t out_siz);
#endif
diff --git a/drivers/crypto/fsl/rsa_caam.h b/drivers/crypto/fsl/rsa_caam.h
new file mode 100644
index 0000000..4ff87ef
--- /dev/null
+++ b/drivers/crypto/fsl/rsa_caam.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __RSA_CAAM_H
+#define __RSA_CAAM_H
+
+#include <common.h>
+
+/**
+ * struct pk_in_params - holder for input to PKHA block in CAAM
+ * These parameters are required to perform Modular Exponentiation
+ * using PKHA Block in CAAM
+ */
+struct pk_in_params {
+ const uint8_t *e; /* public exponent as byte array */
+ uint32_t e_siz; /* size of e[] in number of bytes */
+ const uint8_t *n; /* modulus as byte array */
+ uint32_t n_siz; /* size of n[] in number of bytes */
+ const uint8_t *a; /* Signature as byte array */
+ uint32_t a_siz; /* size of a[] in number of bytes */
+ uint8_t *b; /* Result exp. modulus in number of bytes */
+ uint32_t b_siz; /* size of b[] in number of bytes */
+};
+
+#endif
diff --git a/drivers/crypto/fsl/sec.c b/drivers/crypto/fsl/sec.c
new file mode 100644
index 0000000..443ee96
--- /dev/null
+++ b/drivers/crypto/fsl/sec.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#if CONFIG_SYS_FSL_SEC_COMPAT == 2 || CONFIG_SYS_FSL_SEC_COMPAT >= 4
+#include <fsl_sec.h>
+#endif
+
+/*
+ * update crypto node properties to a specified revision of the SEC
+ * called with sec_rev == 0 if not on an E processor
+ */
+#if CONFIG_SYS_FSL_SEC_COMPAT == 2 /* SEC 2.x/3.x */
+void fdt_fixup_crypto_node(void *blob, int sec_rev)
+{
+ static const struct sec_rev_prop {
+ u32 sec_rev;
+ u32 num_channels;
+ u32 channel_fifo_len;
+ u32 exec_units_mask;
+ u32 descriptor_types_mask;
+ } sec_rev_prop_list[] = {
+ { 0x0200, 4, 24, 0x07e, 0x01010ebf }, /* SEC 2.0 */
+ { 0x0201, 4, 24, 0x0fe, 0x012b0ebf }, /* SEC 2.1 */
+ { 0x0202, 1, 24, 0x04c, 0x0122003f }, /* SEC 2.2 */
+ { 0x0204, 4, 24, 0x07e, 0x012b0ebf }, /* SEC 2.4 */
+ { 0x0300, 4, 24, 0x9fe, 0x03ab0ebf }, /* SEC 3.0 */
+ { 0x0301, 4, 24, 0xbfe, 0x03ab0ebf }, /* SEC 3.1 */
+ { 0x0303, 4, 24, 0x97c, 0x03a30abf }, /* SEC 3.3 */
+ };
+ static char compat_strlist[ARRAY_SIZE(sec_rev_prop_list) *
+ sizeof("fsl,secX.Y")];
+ int crypto_node, sec_idx, err;
+ char *p;
+ u32 val;
+
+ /* locate crypto node based on lowest common compatible */
+ crypto_node = fdt_node_offset_by_compatible(blob, -1, "fsl,sec2.0");
+ if (crypto_node == -FDT_ERR_NOTFOUND)
+ return;
+
+ /* delete it if not on an E-processor */
+ if (crypto_node > 0 && !sec_rev) {
+ fdt_del_node(blob, crypto_node);
+ return;
+ }
+
+ /* else we got called for possible uprev */
+ for (sec_idx = 0; sec_idx < ARRAY_SIZE(sec_rev_prop_list); sec_idx++)
+ if (sec_rev_prop_list[sec_idx].sec_rev == sec_rev)
+ break;
+
+ if (sec_idx == ARRAY_SIZE(sec_rev_prop_list)) {
+ puts("warning: unknown SEC revision number\n");
+ return;
+ }
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].num_channels);
+ err = fdt_setprop(blob, crypto_node, "fsl,num-channels", &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].descriptor_types_mask);
+ err = fdt_setprop(blob, crypto_node, "fsl,descriptor-types-mask",
+ &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].exec_units_mask);
+ err = fdt_setprop(blob, crypto_node, "fsl,exec-units-mask", &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].channel_fifo_len);
+ err = fdt_setprop(blob, crypto_node, "fsl,channel-fifo-len", &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = 0;
+ while (sec_idx >= 0) {
+ p = compat_strlist + val;
+ val += sprintf(p, "fsl,sec%d.%d",
+ (sec_rev_prop_list[sec_idx].sec_rev & 0xff00) >> 8,
+ sec_rev_prop_list[sec_idx].sec_rev & 0x00ff) + 1;
+ sec_idx--;
+ }
+ err = fdt_setprop(blob, crypto_node, "compatible", &compat_strlist,
+ val);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+}
+#elif CONFIG_SYS_FSL_SEC_COMPAT >= 4 /* SEC4 */
+static u8 caam_get_era(void)
+{
+ static const struct {
+ u16 ip_id;
+ u8 maj_rev;
+ u8 era;
+ } caam_eras[] = {
+ {0x0A10, 1, 1},
+ {0x0A10, 2, 2},
+ {0x0A12, 1, 3},
+ {0x0A14, 1, 3},
+ {0x0A14, 2, 4},
+ {0x0A16, 1, 4},
+ {0x0A10, 3, 4},
+ {0x0A11, 1, 4},
+ {0x0A18, 1, 4},
+ {0x0A11, 2, 5},
+ {0x0A12, 2, 5},
+ {0x0A13, 1, 5},
+ {0x0A1C, 1, 5}
+ };
+
+ ccsr_sec_t __iomem *sec = (void __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
+ u32 secvid_ms = sec_in32(&sec->secvid_ms);
+ u32 ccbvid = sec_in32(&sec->ccbvid);
+ u16 ip_id = (secvid_ms & SEC_SECVID_MS_IPID_MASK) >>
+ SEC_SECVID_MS_IPID_SHIFT;
+ u8 maj_rev = (secvid_ms & SEC_SECVID_MS_MAJ_REV_MASK) >>
+ SEC_SECVID_MS_MAJ_REV_SHIFT;
+ u8 era = (ccbvid & SEC_CCBVID_ERA_MASK) >> SEC_CCBVID_ERA_SHIFT;
+
+ int i;
+
+ if (era) /* This is '0' prior to CAAM ERA-6 */
+ return era;
+
+ for (i = 0; i < ARRAY_SIZE(caam_eras); i++)
+ if (caam_eras[i].ip_id == ip_id &&
+ caam_eras[i].maj_rev == maj_rev)
+ return caam_eras[i].era;
+
+ return 0;
+}
+
+static void fdt_fixup_crypto_era(void *blob, u32 era)
+{
+ int err;
+ int crypto_node;
+
+ crypto_node = fdt_path_offset(blob, "crypto");
+ if (crypto_node < 0) {
+ printf("WARNING: Missing crypto node\n");
+ return;
+ }
+
+ err = fdt_setprop(blob, crypto_node, "fsl,sec-era", &era,
+ sizeof(era));
+ if (err < 0) {
+ printf("ERROR: could not set fsl,sec-era property: %s\n",
+ fdt_strerror(err));
+ }
+}
+
+void fdt_fixup_crypto_node(void *blob, int sec_rev)
+{
+ u8 era;
+
+ if (!sec_rev) {
+ fdt_del_node_and_alias(blob, "crypto");
+ return;
+ }
+
+ /* Add SEC ERA information in compatible */
+ era = caam_get_era();
+ if (era) {
+ fdt_fixup_crypto_era(blob, era);
+ } else {
+ printf("WARNING: Unable to get ERA for CAAM rev: %d\n",
+ sec_rev);
+ }
+}
+#endif
diff --git a/drivers/crypto/rsa_mod_exp/Kconfig b/drivers/crypto/rsa_mod_exp/Kconfig
new file mode 100644
index 0000000..6dcb39a
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/Kconfig
@@ -0,0 +1,5 @@
+config DM_MOD_EXP
+ bool "Enable Driver Model for RSA Modular Exponentiation"
+ depends on DM
+ help
+ If you want to use driver model for RSA Modular Exponentiation, say Y.
diff --git a/drivers/crypto/rsa_mod_exp/Makefile b/drivers/crypto/rsa_mod_exp/Makefile
new file mode 100644
index 0000000..915b751
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2014 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_RSA) += mod_exp_uclass.o mod_exp_sw.o
diff --git a/drivers/crypto/rsa_mod_exp/mod_exp_sw.c b/drivers/crypto/rsa_mod_exp/mod_exp_sw.c
new file mode 100644
index 0000000..dc6c064
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/mod_exp_sw.c
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc.
+ * Author: Ruchika Gupta <ruchika.gupta@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <u-boot/rsa-mod-exp.h>
+
+int mod_exp_sw(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+ struct key_prop *prop, uint8_t *out)
+{
+ int ret = 0;
+
+ ret = rsa_mod_exp_sw(sig, sig_len, prop, out);
+ if (ret) {
+ debug("%s: RSA failed to verify: %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct mod_exp_ops mod_exp_ops_sw = {
+ .mod_exp = mod_exp_sw,
+};
+
+U_BOOT_DRIVER(mod_exp_sw) = {
+ .name = "mod_exp_sw",
+ .id = UCLASS_MOD_EXP,
+ .ops = &mod_exp_ops_sw,
+};
+
+U_BOOT_DEVICE(mod_exp_sw) = {
+ .name = "mod_exp_sw",
+};
diff --git a/drivers/crypto/rsa_mod_exp/mod_exp_uclass.c b/drivers/crypto/rsa_mod_exp/mod_exp_uclass.c
new file mode 100644
index 0000000..266f094
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/mod_exp_uclass.c
@@ -0,0 +1,31 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc
+ * Author: Ruchika Gupta <ruchika.gupta@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <u-boot/rsa-mod-exp.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/list.h>
+
+int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+ struct key_prop *node, uint8_t *out)
+{
+ const struct mod_exp_ops *ops = device_get_ops(dev);
+
+ if (!ops->mod_exp)
+ return -ENOSYS;
+
+ return ops->mod_exp(dev, sig, sig_len, node, out);
+}
+
+UCLASS_DRIVER(mod_exp) = {
+ .id = UCLASS_MOD_EXP,
+ .name = "rsa_mod_exp",
+};
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index a3c01e7..4eef047 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -171,6 +171,14 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->debug[i], regs->debug[i]);
}
}
+#ifdef CONFIG_SYS_FSL_ERRATUM_A008378
+ /* Erratum applies when accumulated ECC is used, or DBI is enabled */
+#define IS_ACC_ECC_EN(v) ((v) & 0x4)
+#define IS_DBI(v) ((((v) >> 12) & 0x3) == 0x2)
+ if (IS_ACC_ECC_EN(regs->ddr_sdram_cfg) ||
+ IS_DBI(regs->ddr_sdram_cfg_3))
+ ddr_setbits32(ddr->debug[28], 0x9 << 20);
+#endif
/*
* For RDIMMs, JEDEC spec requires clocks to be stable before reset is
diff --git a/drivers/ddr/mvebu/Makefile b/drivers/ddr/mvebu/Makefile
new file mode 100644
index 0000000..50a69ea
--- /dev/null
+++ b/drivers/ddr/mvebu/Makefile
@@ -0,0 +1,14 @@
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD) += ddr3_dfs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_dqs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_hw_training.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_init.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_pbs.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_read_leveling.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_sdram.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_spd.o
+obj-$(CONFIG_SPL_BUILD) += ddr3_write_leveling.o
+obj-$(CONFIG_SPL_BUILD) += xor.o
diff --git a/drivers/ddr/mvebu/ddr3_axp.h b/drivers/ddr/mvebu/ddr3_axp.h
new file mode 100644
index 0000000..bf65f6b
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp.h
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_AXP_H
+#define __DDR3_AXP_H
+
+#define MV_78XX0_Z1_REV 0x0
+#define MV_78XX0_A0_REV 0x1
+#define MV_78XX0_B0_REV 0x2
+
+#define SAR_DDR3_FREQ_MASK 0xFE00000
+#define SAR_CPU_FAB_GET(cpu, fab) (((cpu & 0x7) << 21) | ((fab & 0xF) << 24))
+
+#define MAX_CS 4
+
+#define MIN_DIMM_ADDR 0x50
+#define FAR_END_DIMM_ADDR 0x50
+#define MAX_DIMM_ADDR 0x60
+
+#ifndef CONFIG_DDR_FIXED_SIZE
+#define SDRAM_CS_SIZE 0xFFFFFFF
+#else
+#define SDRAM_CS_SIZE (CONFIG_DDR_FIXED_SIZE - 1)
+#endif
+#define SDRAM_CS_BASE 0x0
+#define SDRAM_DIMM_SIZE 0x80000000
+
+#define CPU_CONFIGURATION_REG(id) (0x21800 + (id * 0x100))
+#define CPU_MRVL_ID_OFFSET 0x10
+#define SAR1_CPU_CORE_MASK 0x00000018
+#define SAR1_CPU_CORE_OFFSET 3
+
+#define ECC_SUPPORT
+#define NEW_FABRIC_TWSI_ADDR 0x4E
+#ifdef DB_784MP_GP
+#define BUS_WIDTH_ECC_TWSI_ADDR 0x4E
+#else
+#define BUS_WIDTH_ECC_TWSI_ADDR 0x4F
+#endif
+#define MV_MAX_DDR3_STATIC_SIZE 50
+#define MV_DDR3_MODES_NUMBER 30
+
+#define RESUME_RL_PATTERNS_ADDR (0xFE0000)
+#define RESUME_RL_PATTERNS_SIZE (0x100)
+#define RESUME_TRAINING_VALUES_ADDR (RESUME_RL_PATTERNS_ADDR + RESUME_RL_PATTERNS_SIZE)
+#define RESUME_TRAINING_VALUES_MAX (0xCD0)
+#define BOOT_INFO_ADDR (RESUME_RL_PATTERNS_ADDR + 0x1000)
+#define CHECKSUM_RESULT_ADDR (BOOT_INFO_ADDR + 0x1000)
+#define NUM_OF_REGISTER_ADDR (CHECKSUM_RESULT_ADDR + 4)
+#define SUSPEND_MAGIC_WORD (0xDEADB002)
+#define REGISTER_LIST_END (0xFFFFFFFF)
+
+/*
+ * Registers offset
+ */
+
+#define REG_SAMPLE_RESET_LOW_ADDR 0x18230
+#define REG_SAMPLE_RESET_HIGH_ADDR 0x18234
+#define REG_SAMPLE_RESET_CPU_FREQ_OFFS 21
+#define REG_SAMPLE_RESET_CPU_FREQ_MASK 0x00E00000
+#define REG_SAMPLE_RESET_FAB_OFFS 24
+#define REG_SAMPLE_RESET_FAB_MASK 0xF000000
+#define REG_SAMPLE_RESET_TCLK_OFFS 28
+#define REG_SAMPLE_RESET_CPU_ARCH_OFFS 31
+#define REG_SAMPLE_RESET_HIGH_CPU_FREQ_OFFS 20
+
+/* MISC */
+/*
+ * In mainline U-Boot we're re-configuring the mvebu base address
+ * register to 0xf1000000. So need to use this value for the DDR
+ * training code as well.
+ */
+#define INTER_REGS_BASE SOC_REGS_PHY_BASE
+
+/* DDR */
+#define REG_SDRAM_CONFIG_ADDR 0x1400
+#define REG_SDRAM_CONFIG_MASK 0x9FFFFFFF
+#define REG_SDRAM_CONFIG_RFRS_MASK 0x3FFF
+#define REG_SDRAM_CONFIG_WIDTH_OFFS 15
+#define REG_SDRAM_CONFIG_REGDIMM_OFFS 17
+#define REG_SDRAM_CONFIG_ECC_OFFS 18
+#define REG_SDRAM_CONFIG_IERR_OFFS 19
+#define REG_SDRAM_CONFIG_PUPRSTDIV_OFFS 28
+#define REG_SDRAM_CONFIG_RSTRD_OFFS 30
+
+#define REG_DUNIT_CTRL_LOW_ADDR 0x1404
+#define REG_DUNIT_CTRL_LOW_2T_OFFS 3
+#define REG_DUNIT_CTRL_LOW_2T_MASK 0x3
+#define REG_DUNIT_CTRL_LOW_DPDE_OFFS 14
+
+#define REG_SDRAM_TIMING_LOW_ADDR 0x1408
+
+#define REG_SDRAM_TIMING_HIGH_ADDR 0x140C
+#define REG_SDRAM_TIMING_H_R2R_OFFS 7
+#define REG_SDRAM_TIMING_H_R2R_MASK 0x3
+#define REG_SDRAM_TIMING_H_R2W_W2R_OFFS 9
+#define REG_SDRAM_TIMING_H_R2W_W2R_MASK 0x3
+#define REG_SDRAM_TIMING_H_W2W_OFFS 11
+#define REG_SDRAM_TIMING_H_W2W_MASK 0x1F
+#define REG_SDRAM_TIMING_H_R2R_H_OFFS 19
+#define REG_SDRAM_TIMING_H_R2R_H_MASK 0x7
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS 22
+#define REG_SDRAM_TIMING_H_R2W_W2R_H_MASK 0x7
+
+#define REG_SDRAM_ADDRESS_CTRL_ADDR 0x1410
+#define REG_SDRAM_ADDRESS_SIZE_OFFS 2
+#define REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS 18
+#define REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS 4
+
+#define REG_SDRAM_OPEN_PAGES_ADDR 0x1414
+#define REG_SDRAM_OPERATION_CS_OFFS 8
+
+#define REG_SDRAM_OPERATION_ADDR 0x1418
+#define REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS 24
+#define REG_SDRAM_OPERATION_CWA_DATA_OFFS 20
+#define REG_SDRAM_OPERATION_CWA_DATA_MASK 0xF
+#define REG_SDRAM_OPERATION_CWA_RC_OFFS 16
+#define REG_SDRAM_OPERATION_CWA_RC_MASK 0xF
+#define REG_SDRAM_OPERATION_CMD_MR0 0xF03
+#define REG_SDRAM_OPERATION_CMD_MR1 0xF04
+#define REG_SDRAM_OPERATION_CMD_MR2 0xF08
+#define REG_SDRAM_OPERATION_CMD_MR3 0xF09
+#define REG_SDRAM_OPERATION_CMD_RFRS 0xF02
+#define REG_SDRAM_OPERATION_CMD_CWA 0xF0E
+#define REG_SDRAM_OPERATION_CMD_RFRS_DONE 0xF
+#define REG_SDRAM_OPERATION_CMD_MASK 0xF
+#define REG_SDRAM_OPERATION_CS_OFFS 8
+
+#define REG_OUDDR3_TIMING_ADDR 0x142C
+
+#define REG_SDRAM_MODE_ADDR 0x141C
+
+#define REG_SDRAM_EXT_MODE_ADDR 0x1420
+
+#define REG_DDR_CONT_HIGH_ADDR 0x1424
+
+#define REG_ODT_TIME_LOW_ADDR 0x1428
+#define REG_ODT_ON_CTL_RD_OFFS 12
+#define REG_ODT_OFF_CTL_RD_OFFS 16
+#define REG_SDRAM_ERROR_ADDR 0x1454
+#define REG_SDRAM_AUTO_PWR_SAVE_ADDR 0x1474
+#define REG_ODT_TIME_HIGH_ADDR 0x147C
+
+#define REG_SDRAM_INIT_CTRL_ADDR 0x1480
+#define REG_SDRAM_INIT_CTRL_OFFS 0
+#define REG_SDRAM_INIT_CKE_ASSERT_OFFS 2
+#define REG_SDRAM_INIT_RESET_DEASSERT_OFFS 3
+
+#define REG_SDRAM_ODT_CTRL_LOW_ADDR 0x1494
+
+#define REG_SDRAM_ODT_CTRL_HIGH_ADDR 0x1498
+/*#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK 0xFFFFFF55 */
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK 0x0
+#define REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA 0x3
+
+#define REG_DUNIT_ODT_CTRL_ADDR 0x149C
+#define REG_DUNIT_ODT_CTRL_OVRD_OFFS 8
+#define REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS 9
+
+#define REG_DRAM_FIFO_CTRL_ADDR 0x14A0
+
+#define REG_DRAM_AXI_CTRL_ADDR 0x14A8
+#define REG_DRAM_AXI_CTRL_AXIDATABUSWIDTH_OFFS 0
+
+#define REG_METAL_MASK_ADDR 0x14B0
+#define REG_METAL_MASK_MASK 0xDFFFFFFF
+#define REG_METAL_MASK_RETRY_OFFS 0
+
+#define REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR 0x14C0
+
+#define REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR 0x14C4
+#define REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR 0x14c8
+#define REG_DRAM_MAIN_PADS_CAL_ADDR 0x14CC
+
+#define REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR 0x17c8
+
+#define REG_CS_SIZE_SCRATCH_ADDR 0x1504
+#define REG_DYNAMIC_POWER_SAVE_ADDR 0x1520
+#define REG_DDR_IO_ADDR 0x1524
+#define REG_DDR_IO_CLK_RATIO_OFFS 15
+
+#define REG_DFS_ADDR 0x1528
+#define REG_DFS_DLLNEXTSTATE_OFFS 0
+#define REG_DFS_BLOCK_OFFS 1
+#define REG_DFS_SR_OFFS 2
+#define REG_DFS_ATSR_OFFS 3
+#define REG_DFS_RECONF_OFFS 4
+#define REG_DFS_CL_NEXT_STATE_OFFS 8
+#define REG_DFS_CL_NEXT_STATE_MASK 0xF
+#define REG_DFS_CWL_NEXT_STATE_OFFS 12
+#define REG_DFS_CWL_NEXT_STATE_MASK 0x7
+
+#define REG_READ_DATA_SAMPLE_DELAYS_ADDR 0x1538
+#define REG_READ_DATA_SAMPLE_DELAYS_MASK 0x1F
+#define REG_READ_DATA_SAMPLE_DELAYS_OFFS 8
+
+#define REG_READ_DATA_READY_DELAYS_ADDR 0x153C
+#define REG_READ_DATA_READY_DELAYS_MASK 0x1F
+#define REG_READ_DATA_READY_DELAYS_OFFS 8
+
+#define START_BURST_IN_ADDR 1
+
+#define REG_DRAM_TRAINING_SHADOW_ADDR 0x18488
+#define REG_DRAM_TRAINING_ADDR 0x15B0
+#define REG_DRAM_TRAINING_LOW_FREQ_OFFS 0
+#define REG_DRAM_TRAINING_PATTERNS_OFFS 4
+#define REG_DRAM_TRAINING_MED_FREQ_OFFS 2
+#define REG_DRAM_TRAINING_WL_OFFS 3
+#define REG_DRAM_TRAINING_RL_OFFS 6
+#define REG_DRAM_TRAINING_DQS_RX_OFFS 15
+#define REG_DRAM_TRAINING_DQS_TX_OFFS 16
+#define REG_DRAM_TRAINING_CS_OFFS 20
+#define REG_DRAM_TRAINING_RETEST_OFFS 24
+#define REG_DRAM_TRAINING_DFS_FREQ_OFFS 27
+#define REG_DRAM_TRAINING_DFS_REQ_OFFS 29
+#define REG_DRAM_TRAINING_ERROR_OFFS 30
+#define REG_DRAM_TRAINING_AUTO_OFFS 31
+#define REG_DRAM_TRAINING_RETEST_PAR 0x3
+#define REG_DRAM_TRAINING_RETEST_MASK 0xF8FFFFFF
+#define REG_DRAM_TRAINING_CS_MASK 0xFF0FFFFF
+#define REG_DRAM_TRAINING_PATTERNS_MASK 0xFF0F0000
+
+#define REG_DRAM_TRAINING_1_ADDR 0x15B4
+#define REG_DRAM_TRAINING_1_TRNBPOINT_OFFS 16
+
+#define REG_DRAM_TRAINING_2_ADDR 0x15B8
+#define REG_DRAM_TRAINING_2_OVERRUN_OFFS 17
+#define REG_DRAM_TRAINING_2_FIFO_RST_OFFS 4
+#define REG_DRAM_TRAINING_2_RL_MODE_OFFS 3
+#define REG_DRAM_TRAINING_2_WL_MODE_OFFS 2
+#define REG_DRAM_TRAINING_2_ECC_MUX_OFFS 1
+#define REG_DRAM_TRAINING_2_SW_OVRD_OFFS 0
+
+#define REG_DRAM_TRAINING_PATTERN_BASE_ADDR 0x15BC
+#define REG_DRAM_TRAINING_PATTERN_BASE_OFFS 3
+
+#define REG_TRAINING_DEBUG_2_ADDR 0x15C4
+#define REG_TRAINING_DEBUG_2_OFFS 16
+#define REG_TRAINING_DEBUG_2_MASK 0x3
+
+#define REG_TRAINING_DEBUG_3_ADDR 0x15C8
+#define REG_TRAINING_DEBUG_3_OFFS 3
+#define REG_TRAINING_DEBUG_3_MASK 0x7
+
+#define MR_CS_ADDR_OFFS 4
+
+#define REG_DDR3_MR0_ADDR 0x15D0
+#define REG_DDR3_MR0_CS_ADDR 0x1870
+#define REG_DDR3_MR0_CL_MASK 0x74
+#define REG_DDR3_MR0_CL_OFFS 2
+#define REG_DDR3_MR0_CL_HIGH_OFFS 3
+#define CL_MASK 0xF
+
+#define REG_DDR3_MR1_ADDR 0x15D4
+#define REG_DDR3_MR1_CS_ADDR 0x1874
+#define REG_DDR3_MR1_RTT_MASK 0xFFFFFDBB
+#define REG_DDR3_MR1_DLL_ENA_OFFS 0
+#define REG_DDR3_MR1_RTT_DISABLED 0x0
+#define REG_DDR3_MR1_RTT_RZQ2 0x40
+#define REG_DDR3_MR1_RTT_RZQ4 0x2
+#define REG_DDR3_MR1_RTT_RZQ6 0x42
+#define REG_DDR3_MR1_RTT_RZQ8 0x202
+#define REG_DDR3_MR1_RTT_RZQ12 0x4
+#define REG_DDR3_MR1_OUTBUF_WL_MASK 0xFFFFEF7F /* WL-disabled,OB-enabled */
+#define REG_DDR3_MR1_OUTBUF_DIS_OFFS 12 /* Output Buffer Disabled */
+#define REG_DDR3_MR1_WL_ENA_OFFS 7
+#define REG_DDR3_MR1_WL_ENA 0x80 /* WL Enabled */
+#define REG_DDR3_MR1_ODT_MASK 0xFFFFFDBB
+
+#define REG_DDR3_MR2_ADDR 0x15D8
+#define REG_DDR3_MR2_CS_ADDR 0x1878
+#define REG_DDR3_MR2_CWL_OFFS 3
+#define REG_DDR3_MR2_CWL_MASK 0x7
+#define REG_DDR3_MR2_ODT_MASK 0xFFFFF9FF
+#define REG_DDR3_MR3_ADDR 0x15DC
+#define REG_DDR3_MR3_CS_ADDR 0x187C
+
+#define REG_DDR3_RANK_CTRL_ADDR 0x15E0
+#define REG_DDR3_RANK_CTRL_CS_ENA_MASK 0xF
+#define REG_DDR3_RANK_CTRL_MIRROR_OFFS 4
+
+#define REG_ZQC_CONF_ADDR 0x15E4
+
+#define REG_DRAM_PHY_CONFIG_ADDR 0x15EC
+#define REG_DRAM_PHY_CONFIG_MASK 0x3FFFFFFF
+
+#define REG_ODPG_CNTRL_ADDR 0x1600
+#define REG_ODPG_CNTRL_OFFS 21
+
+#define REG_PHY_LOCK_MASK_ADDR 0x1670
+#define REG_PHY_LOCK_MASK_MASK 0xFFFFF000
+
+#define REG_PHY_LOCK_STATUS_ADDR 0x1674
+#define REG_PHY_LOCK_STATUS_LOCK_OFFS 9
+#define REG_PHY_LOCK_STATUS_LOCK_MASK 0xFFF
+#define REG_PHY_LOCK_APLL_ADLL_STATUS_MASK 0x7FF
+
+#define REG_PHY_REGISTRY_FILE_ACCESS_ADDR 0x16A0
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_WR 0xC0000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_RD 0x80000000
+#define REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE 0x80000000
+#define REG_PHY_BC_OFFS 27
+#define REG_PHY_CNTRL_OFFS 26
+#define REG_PHY_CS_OFFS 16
+#define REG_PHY_DQS_REF_DLY_OFFS 10
+#define REG_PHY_PHASE_OFFS 8
+#define REG_PHY_PUP_OFFS 22
+
+#define REG_TRAINING_WL_ADDR 0x16AC
+#define REG_TRAINING_WL_CS_MASK 0xFFFFFFFC
+#define REG_TRAINING_WL_UPD_OFFS 2
+#define REG_TRAINING_WL_CS_DONE_OFFS 3
+#define REG_TRAINING_WL_RATIO_MASK 0xFFFFFF0F
+#define REG_TRAINING_WL_1TO1 0x50
+#define REG_TRAINING_WL_2TO1 0x10
+#define REG_TRAINING_WL_DELAYEXP_MASK 0x20000000
+#define REG_TRAINING_WL_RESULTS_MASK 0x000001FF
+#define REG_TRAINING_WL_RESULTS_OFFS 20
+
+#define REG_REGISTERED_DRAM_CTRL_ADDR 0x16D0
+#define REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS 15
+#define REG_REGISTERED_DRAM_CTRL_PARITY_MASK 0x3F
+/* DLB*/
+#define REG_STATIC_DRAM_DLB_CONTROL 0x1700
+#define DLB_BUS_OPTIMIZATION_WEIGHTS_REG 0x1704
+#define DLB_AGING_REGISTER 0x1708
+#define DLB_EVICTION_CONTROL_REG 0x170c
+#define DLB_EVICTION_TIMERS_REGISTER_REG 0x1710
+
+#define DLB_ENABLE 0x1
+#define DLB_WRITE_COALESING (0x1 << 2)
+#define DLB_AXI_PREFETCH_EN (0x1 << 3)
+#define DLB_MBUS_PREFETCH_EN (0x1 << 4)
+#define PREFETCH_NLNSZTR (0x1 << 6)
+
+/* CPU */
+#define REG_BOOTROM_ROUTINE_ADDR 0x182D0
+#define REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS 12
+
+#define REG_DRAM_INIT_CTRL_STATUS_ADDR 0x18488
+#define REG_DRAM_INIT_CTRL_TRN_CLK_OFFS 16
+#define REG_CPU_DIV_CLK_CTRL_0_NEW_RATIO 0x000200FF
+#define REG_DRAM_INIT_CTRL_STATUS_2_ADDR 0x1488
+
+#define REG_CPU_DIV_CLK_CTRL_0_ADDR 0x18700
+
+#define REG_CPU_DIV_CLK_CTRL_1_ADDR 0x18704
+#define REG_CPU_DIV_CLK_CTRL_2_ADDR 0x18708
+
+#define REG_CPU_DIV_CLK_CTRL_3_ADDR 0x1870C
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK 0xFFFFC0FF
+#define REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS 8
+
+#define REG_CPU_DIV_CLK_CTRL_4_ADDR 0x18710
+
+#define REG_CPU_DIV_CLK_STATUS_0_ADDR 0x18718
+#define REG_CPU_DIV_CLK_ALL_STABLE_OFFS 8
+
+#define REG_CPU_PLL_CTRL_0_ADDR 0x1871C
+#define REG_CPU_PLL_STATUS_0_ADDR 0x18724
+#define REG_CORE_DIV_CLK_CTRL_ADDR 0x18740
+#define REG_CORE_DIV_CLK_STATUS_ADDR 0x18744
+#define REG_DDRPHY_APLL_CTRL_ADDR 0x18780
+
+#define REG_DDRPHY_APLL_CTRL_2_ADDR 0x18784
+
+#define REG_SFABRIC_CLK_CTRL_ADDR 0x20858
+#define REG_SFABRIC_CLK_CTRL_SMPL_OFFS 8
+
+/* DRAM Windows */
+#define REG_XBAR_WIN_19_CTRL_ADDR 0x200e8
+#define REG_XBAR_WIN_4_CTRL_ADDR 0x20040
+#define REG_XBAR_WIN_4_BASE_ADDR 0x20044
+#define REG_XBAR_WIN_4_REMAP_ADDR 0x20048
+#define REG_FASTPATH_WIN_0_CTRL_ADDR 0x20184
+#define REG_XBAR_WIN_7_REMAP_ADDR 0x20078
+
+/* SRAM */
+#define REG_CDI_CONFIG_ADDR 0x20220
+#define REG_SRAM_WINDOW_0_ADDR 0x20240
+#define REG_SRAM_WINDOW_0_ENA_OFFS 0
+#define REG_SRAM_WINDOW_1_ADDR 0x20244
+#define REG_SRAM_L2_ENA_ADDR 0x8500
+#define REG_SRAM_CLEAN_BY_WAY_ADDR 0x87BC
+
+/* PMU */
+#define REG_PMU_I_F_CTRL_ADDR 0x1C090
+#define REG_PMU_DUNIT_BLK_OFFS 16
+#define REG_PMU_DUNIT_RFRS_OFFS 20
+#define REG_PMU_DUNIT_ACK_OFFS 24
+
+/* MBUS*/
+#define MBUS_UNITS_PRIORITY_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x420)
+#define FABRIC_UNITS_PRIORITY_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x424)
+#define MBUS_UNITS_PREFETCH_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x428)
+#define FABRIC_UNITS_PREFETCH_CONTROL_REG (MV_MBUS_REGS_OFFSET + 0x42c)
+
+#define REG_PM_STAT_MASK_ADDR 0x2210C
+#define REG_PM_STAT_MASK_CPU0_IDLE_MASK_OFFS 16
+
+#define REG_PM_EVENT_STAT_MASK_ADDR 0x22120
+#define REG_PM_EVENT_STAT_MASK_DFS_DONE_OFFS 17
+
+#define REG_PM_CTRL_CONFIG_ADDR 0x22104
+#define REG_PM_CTRL_CONFIG_DFS_REQ_OFFS 18
+
+#define REG_FABRIC_LOCAL_IRQ_MASK_ADDR 0x218C4
+#define REG_FABRIC_LOCAL_IRQ_PMU_MASK_OFFS 18
+
+/* Controller revision info */
+#define PCI_CLASS_CODE_AND_REVISION_ID 0x008
+#define PCCRIR_REVID_OFFS 0 /* Revision ID */
+#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS)
+
+/* Power Management Clock Gating Control Register */
+#define MV_PEX_IF_REGS_OFFSET(if) \
+ (if < 8 ? (0x40000 + ((if) / 4) * 0x40000 + ((if) % 4) * 0x4000) \
+ : (0x42000 + ((if) % 8) * 0x40000))
+#define MV_PEX_IF_REGS_BASE(unit) (MV_PEX_IF_REGS_OFFSET(unit))
+#define POWER_MNG_CTRL_REG 0x18220
+#define PEX_DEVICE_AND_VENDOR_ID 0x000
+#define PEX_CFG_DIRECT_ACCESS(if, reg) (MV_PEX_IF_REGS_BASE(if) + (reg))
+#define PMC_PEXSTOPCLOCK_OFFS(port) ((port) < 8 ? (5 + (port)) : (18 + (port)))
+#define PMC_PEXSTOPCLOCK_MASK(port) (1 << PMC_PEXSTOPCLOCK_OFFS(port))
+#define PMC_PEXSTOPCLOCK_EN(port) (1 << PMC_PEXSTOPCLOCK_OFFS(port))
+#define PMC_PEXSTOPCLOCK_STOP(port) (0 << PMC_PEXSTOPCLOCK_OFFS(port))
+
+/* TWSI */
+#define TWSI_DATA_ADDR_MASK 0x7
+#define TWSI_DATA_ADDR_OFFS 1
+
+/* General */
+#define MAX_CS 4
+
+/* Frequencies */
+#define FAB_OPT 21
+#define CLK_CPU 12
+#define CLK_VCO (2 * CLK_CPU)
+#define CLK_DDR 12
+
+/* Cpu Frequencies: */
+#define CLK_CPU_1000 0
+#define CLK_CPU_1066 1
+#define CLK_CPU_1200 2
+#define CLK_CPU_1333 3
+#define CLK_CPU_1500 4
+#define CLK_CPU_1666 5
+#define CLK_CPU_1800 6
+#define CLK_CPU_2000 7
+#define CLK_CPU_600 8
+#define CLK_CPU_667 9
+#define CLK_CPU_800 0xa
+
+/* Extra Cpu Frequencies: */
+#define CLK_CPU_1600 11
+#define CLK_CPU_2133 12
+#define CLK_CPU_2200 13
+#define CLK_CPU_2400 14
+
+/* DDR3 Frequencies: */
+#define DDR_100 0
+#define DDR_300 1
+#define DDR_333 1
+#define DDR_360 2
+#define DDR_400 3
+#define DDR_444 4
+#define DDR_500 5
+#define DDR_533 6
+#define DDR_600 7
+#define DDR_640 8
+#define DDR_666 8
+#define DDR_720 9
+#define DDR_750 9
+#define DDR_800 10
+#define DDR_833 11
+#define DDR_HCLK 20
+#define DDR_S 12
+#define DDR_S_1TO1 13
+#define MARGIN_FREQ DDR_400
+#define DFS_MARGIN DDR_100
+
+#define ODT_OPT 16
+#define ODT20 0x200
+#define ODT30 0x204
+#define ODT40 0x44
+#define ODT120 0x40
+#define ODT120D 0x400
+
+#define MRS_DELAY 100
+
+#define SDRAM_WL_SW_OFFS 0x100
+#define SDRAM_RL_OFFS 0x0
+#define SDRAM_PBS_I_OFFS 0x140
+#define SDRAM_PBS_II_OFFS 0x180
+#define SDRAM_PBS_NEXT_OFFS (SDRAM_PBS_II_OFFS - SDRAM_PBS_I_OFFS)
+#define SDRAM_PBS_TX_OFFS 0x180
+#define SDRAM_PBS_TX_DM_OFFS 576
+#define SDRAM_DQS_RX_OFFS 1024
+#define SDRAM_DQS_TX_OFFS 2048
+#define SDRAM_DQS_RX_SPECIAL_OFFS 5120
+
+#define LEN_STD_PATTERN 16
+#define LEN_KILLER_PATTERN 128
+#define LEN_SPECIAL_PATTERN 128
+#define LEN_PBS_PATTERN 16
+
+#endif /* __DDR3_AXP_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_config.h b/drivers/ddr/mvebu/ddr3_axp_config.h
new file mode 100644
index 0000000..800d2d1
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_config.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_AXP_CONFIG_H
+#define __DDR3_AXP_CONFIG_H
+
+/*
+ * DDR3_LOG_LEVEL Information
+ *
+ * Level 0: Provides an error code in a case of failure, RL, WL errors
+ * and other algorithm failure
+ * Level 1: Provides the D-Unit setup (SPD/Static configuration)
+ * Level 2: Provides the windows margin as a results of DQS centeralization
+ * Level 3: Provides the windows margin of each DQ as a results of DQS
+ * centeralization
+ */
+#ifdef CONFIG_DDR_LOG_LEVEL
+#define DDR3_LOG_LEVEL CONFIG_DDR_LOG_LEVEL
+#else
+#define DDR3_LOG_LEVEL 0
+#endif
+
+#define DDR3_PBS 1
+
+/* This flag allows the execution of SW WL/RL upon HW failure */
+#define DDR3_RUN_SW_WHEN_HW_FAIL 1
+
+/*
+ * General Configurations
+ *
+ * The following parameters are required for proper setup:
+ *
+ * DDR_TARGET_FABRIC - Set desired fabric configuration
+ * (for sample@Reset fabfreq parameter)
+ * DRAM_ECC - Set ECC support 1/0
+ * BUS_WIDTH - 64/32 bit
+ * CONFIG_SPD_EEPROM - Enables auto detection of DIMMs and their timing values
+ * DQS_CLK_ALIGNED - Set this if CLK and DQS signals are aligned on board
+ * MIXED_DIMM_STATIC - Mixed DIMM + On board devices support (ODT registers
+ * values are taken statically)
+ * DDR3_TRAINING_DEBUG - Debug prints of internal code
+ */
+#define DDR_TARGET_FABRIC 5
+#define DRAM_ECC 0
+
+#ifdef MV_DDR_32BIT
+#define BUS_WIDTH 32
+#else
+#define BUS_WIDTH 64
+#endif
+
+#undef DQS_CLK_ALIGNED
+#undef MIXED_DIMM_STATIC
+#define DDR3_TRAINING_DEBUG 0
+#define REG_DIMM_SKIP_WL 0
+
+/* Marvell boards specific configurations */
+#if defined(DB_78X60_PCAC)
+#undef CONFIG_SPD_EEPROM
+#define STATIC_TRAINING
+#endif
+
+#if defined(DB_78X60_AMC)
+#undef CONFIG_SPD_EEPROM
+#undef DRAM_ECC
+#define DRAM_ECC 1
+#endif
+
+#ifdef CONFIG_SPD_EEPROM
+/*
+ * DIMM support parameters:
+ * DRAM_2T - Set Desired 2T Mode - 0 - 1T, 0x1 - 2T, 0x2 - 3T
+ * DIMM_CS_BITMAP - bitmap representing the optional CS in DIMMs
+ * (0xF=CS0+CS1+CS2+CS3, 0xC=CS2+CS3...)
+ */
+#define DRAM_2T 0x0
+#define DIMM_CS_BITMAP 0xF
+#define DUNIT_SPD
+#endif
+
+#ifdef DRAM_ECC
+/*
+ * ECC support parameters:
+ *
+ * U_BOOT_START_ADDR, U_BOOT_SCRUB_SIZE - relevant when using ECC and need
+ * to configure the scrubbing area
+ */
+#define TRAINING_SIZE 0x20000
+#define U_BOOT_START_ADDR 0
+#define U_BOOT_SCRUB_SIZE 0x1000000 /* TRAINING_SIZE */
+#endif
+
+/*
+ * Registered DIMM Support - In case registered DIMM is attached,
+ * please supply the following values:
+ * (see JEDEC - JESD82-29A "Definition of the SSTE32882 Registering Clock
+ * Driver with Parity and Quad Chip
+ * Selects for DDR3/DDR3L/DDR3U RDIMM 1.5 V/1.35 V/1.25 V Applications")
+ * RC0: Global Features Control Word
+ * RC1: Clock Driver Enable Control Word
+ * RC2: Timing Control Word
+ * RC3-RC5 - taken from SPD
+ * RC8: Additional IBT Setting Control Word
+ * RC9: Power Saving Settings Control Word
+ * RC10: Encoding for RDIMM Operating Speed
+ * RC11: Operating Voltage VDD and VREFCA Control Word
+ */
+#define RDIMM_RC0 0
+#define RDIMM_RC1 0
+#define RDIMM_RC2 0
+#define RDIMM_RC8 0
+#define RDIMM_RC9 0
+#define RDIMM_RC10 0x2
+#define RDIMM_RC11 0x0
+
+#if defined(MIXED_DIMM_STATIC) || !defined(CONFIG_SPD_EEPROM)
+#define DUNIT_STATIC
+#endif
+
+#if defined(MIXED_DIMM_STATIC) || defined(CONFIG_SPD_EEPROM)
+/*
+ * This flag allows the user to change the dram refresh cycle in ps,
+ * only in case of SPD or MIX DIMM topology
+ */
+#define TREFI_USER_EN
+
+#ifdef TREFI_USER_EN
+#define TREFI_USER 3900000
+#endif
+#endif
+
+#ifdef CONFIG_SPD_EEPROM
+/*
+ * AUTO_DETECTION_SUPPORT - relevant ONLY for Marvell DB boards.
+ * Enables I2C auto detection different options
+ */
+#if defined(CONFIG_DB_88F78X60) || defined(CONFIG_DB_88F78X60_REV2) || \
+ defined(CONFIG_DB_784MP_GP)
+#define AUTO_DETECTION_SUPPORT
+#endif
+#endif
+
+#endif /* __DDR3_AXP_CONFIG_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_mc_static.h b/drivers/ddr/mvebu/ddr3_axp_mc_static.h
new file mode 100644
index 0000000..2c0e9075
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_mc_static.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __AXP_MC_STATIC_H
+#define __AXP_MC_STATIC_H
+
+MV_DRAM_MC_INIT ddr3_A0_db_667[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x7301c924}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7301CA28}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630b800}, /*Dunit Control Low Register */
+ {0x00001408, 0x43149775}, /*DDR SDRAM Timing (Low) Register */
+ /* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+ {0x0000140C, 0x38d83fe0}, /*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+ {0x00001410, 0x040F0001}, /*DDR SDRAM Address Control Register */
+#else
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Open Pages Control Register */
+#endif
+
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0000D3FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000F8830}, /*Dunit Control High Register */
+ {0x0000142C, 0x214C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x0000c671},
+
+ {0x000014a0, 0x000002A9},
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192434e9}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0x092434e9}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ /* {0x00001524, 0x0000C800}, */
+ {0x00001538, 0x0000000b}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000d}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000640}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000010}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQC Configuration Register */
+ {0x000015EC, 0xd800aa25}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_A0_AMC_667[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x7301c924}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7301CA28}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630b800}, /*Dunit Control Low Register */
+ {0x00001408, 0x43149775}, /*DDR SDRAM Timing (Low) Register */
+ /* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+ {0x0000140C, 0x38d83fe0}, /*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+ {0x00001410, 0x040F0001}, /*DDR SDRAM Address Control Register */
+#else
+ {0x00001410, 0x040F000C}, /*DDR SDRAM Open Pages Control Register */
+#endif
+
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0000D3FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000F8830}, /*Dunit Control High Register */
+ {0x0000142C, 0x214C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x0000c671},
+
+ {0x000014a0, 0x000002A9},
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192434e9}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0x092434e9}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x3FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ /* {0x00001524, 0x0000C800}, */
+ {0x00001538, 0x0000000b}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000d}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000640}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000010}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQC Configuration Register */
+ {0x000015EC, 0xd800aa25}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_A0_db_400[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x73004C30}, /*DDR SDRAM Configuration Register */
+#else /* MV_DDR_64BIT */
+ {0x00001400, 0x7300CC30}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630B840}, /*Dunit Control Low Register */
+ {0x00001408, 0x33137663}, /*DDR SDRAM Timing (Low) Register */
+ {0x0000140C, 0x38000C55}, /*DDR SDRAM Timing (High) Register */
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Address Control Register */
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x0000141C, 0x00000672}, /*DDR SDRAM Mode Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0100D3FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000D6720}, /*Dunit Control High Register */
+ {0x0000142C, 0x014C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x00006571},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014a0, 0x000002A9},
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x000014C0, 0x192424C8}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0xEFB24C8}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000630}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000008}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQDS Configuration Register */
+ /* {0x000015EC, 0xDE000025}, *//*DDR PHY */
+ {0x000015EC, 0xF800AA25}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_Z1_db_600[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x73014A28}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7301CA28}, /*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630B040}, /*Dunit Control Low Register */
+ {0x00001408, 0x44149887}, /*DDR SDRAM Timing (Low) Register */
+ /* {0x0000140C, 0x38000C6A}, *//*DDR SDRAM Timing (High) Register */
+ {0x0000140C, 0x38D83FE0}, /*DDR SDRAM Timing (High) Register */
+
+#ifdef DB_78X60_PCAC
+ {0x00001410, 0x040F0001}, /*DDR SDRAM Address Control Register */
+#else
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Open Pages Control Register */
+#endif
+
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0100D1FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000F8830}, /*Dunit Control High Register */
+ {0x0000142C, 0x214C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x0000c671},
+
+ {0x000014a8, 0x00000101}, /*2:1 */
+ {0x00020220, 0x00000007},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192424C8}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0xEFB24C8}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ /* {0x00001524, 0x0000C800}, */
+ {0x00001538, 0x0000000b}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000d}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000650}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000010}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQC Configuration Register */
+ {0x000015EC, 0xDE000025}, /*DDR PHY */
+ {0x0, 0x0}
+};
+
+MV_DRAM_MC_INIT ddr3_Z1_db_300[MV_MAX_DDR3_STATIC_SIZE] = {
+#ifdef MV_DDR_32BIT
+ {0x00001400, 0x73004C30}, /*DDR SDRAM Configuration Register */
+#else /*MV_DDR_64BIT */
+ {0x00001400, 0x7300CC30}, /*DDR SDRAM Configuration Register */
+ /*{0x00001400, 0x7304CC30}, *//*DDR SDRAM Configuration Register */
+#endif
+ {0x00001404, 0x3630B840}, /*Dunit Control Low Register */
+ {0x00001408, 0x33137663}, /*DDR SDRAM Timing (Low) Register */
+ {0x0000140C, 0x38000C55}, /*DDR SDRAM Timing (High) Register */
+ {0x00001410, 0x040F0000}, /*DDR SDRAM Address Control Register */
+ {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */
+ {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */
+ {0x0000141C, 0x00000672}, /*DDR SDRAM Mode Register */
+ {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */
+ {0x00001424, 0x0100F1FF}, /*Dunit Control High Register */
+ {0x00001428, 0x000D6720}, /*Dunit Control High Register */
+ {0x0000142C, 0x014C2F38}, /*Dunit Control High Register */
+ {0x0000147C, 0x00006571},
+
+ {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */
+ {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */
+ {0x0000149C, 0x00000301}, /*DDR Dunit ODT Control Register */
+
+ {0x000014C0, 0x192424C8}, /* DRAM address and Control Driving Strenght */
+ {0x000014C4, 0xEFB24C8}, /* DRAM Data and DQS Driving Strenght */
+
+ {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence */
+ {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */
+
+ {0x0001504, 0x7FFFFFF1}, /* CS0 Size */
+ {0x000150C, 0x00000000}, /* CS1 Size */
+ {0x0001514, 0x00000000}, /* CS2 Size */
+ {0x000151C, 0x00000000}, /* CS3 Size */
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ {0x000015D0, 0x00000630}, /*MR0 */
+ {0x000015D4, 0x00000046}, /*MR1 */
+ {0x000015D8, 0x00000008}, /*MR2 */
+ {0x000015DC, 0x00000000}, /*MR3 */
+
+ {0x000015E4, 0x00203c18}, /*ZQDS Configuration Register */
+ {0x000015EC, 0xDE000025}, /*DDR PHY */
+
+ {0x0, 0x0}
+};
+
+#endif /* __AXP_MC_STATIC_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_training_static.h b/drivers/ddr/mvebu/ddr3_axp_training_static.h
new file mode 100644
index 0000000..4e61547
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_training_static.h
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __AXP_TRAINING_STATIC_H
+#define __AXP_TRAINING_STATIC_H
+
+/*
+ * STATIC_TRAINING - Set only if static parameters for training are set and
+ * required
+ */
+
+MV_DRAM_TRAINING_INIT ddr3_db_rev2_667[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC002011A},
+ /*1 */
+ {0x000016A0, 0xC0420100},
+ /*2 */
+ {0x000016A0, 0xC082020A},
+ /*3 */
+ {0x000016A0, 0xC0C20017},
+ /*4 */
+ {0x000016A0, 0xC1020113},
+ /*5 */
+ {0x000016A0, 0xC1420107},
+ /*6 */
+ {0x000016A0, 0xC182011F},
+ /*7 */
+ {0x000016A0, 0xC1C2001C},
+ /*8 */
+ {0x000016A0, 0xC202010D},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0004A06},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0806A0D},
+ /*3 */
+ {0x000016A0, 0xC0C0A01B},
+ /*4 */
+ {0x000016A0, 0xC1003A01},
+ /*5 */
+ {0x000016A0, 0xC1408113},
+ /*6 */
+ {0x000016A0, 0xC1805609},
+ /*7 */
+ {0x000016A0, 0xC1C04504},
+ /*8 */
+ {0x000016A0, 0xC2009518},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_rev2_800[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020301},
+ /*1 */
+ {0x000016A0, 0xC0420202},
+ /*2 */
+ {0x000016A0, 0xC0820314},
+ /*3 */
+ {0x000016A0, 0xC0C20117},
+ /*4 */
+ {0x000016A0, 0xC1020219},
+ /*5 */
+ {0x000016A0, 0xC142020B},
+ /*6 */
+ {0x000016A0, 0xC182030A},
+ /*7 */
+ {0x000016A0, 0xC1C2011D},
+ /*8 */
+ {0x000016A0, 0xC2020212},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0007A12},
+ /*1 */
+ {0x000016A0, 0xC0408D16},
+ /*2 */
+ {0x000016A0, 0xC0809E1B},
+ /*3 */
+ {0x000016A0, 0xC0C0AC1F},
+ /*4 */
+ {0x000016A0, 0xC1005E0A},
+ /*5 */
+ {0x000016A0, 0xC140A91D},
+ /*6 */
+ {0x000016A0, 0xC1808E17},
+ /*7 */
+ {0x000016A0, 0xC1C05509},
+ /*8 */
+ {0x000016A0, 0xC2003A01},
+
+ /* PBS Leveling */
+ /*0 */
+ {0x000016A0, 0xC0007A12},
+ /*1 */
+ {0x000016A0, 0xC0408D16},
+ /*2 */
+ {0x000016A0, 0xC0809E1B},
+ /*3 */
+ {0x000016A0, 0xC0C0AC1F},
+ /*4 */
+ {0x000016A0, 0xC1005E0A},
+ /*5 */
+ {0x000016A0, 0xC140A91D},
+ /*6 */
+ {0x000016A0, 0xC1808E17},
+ /*7 */
+ {0x000016A0, 0xC1C05509},
+ /*8 */
+ {0x000016A0, 0xC2003A01},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000B},
+
+ {0x00001538, 0x0000000D}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x00000011}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_400[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 4 15 */
+ {0x000016A0, 0xC002010C},
+ /*1 2 4 2 */
+ {0x000016A0, 0xC042001C},
+ /*2 2 4 27 */
+ {0x000016A0, 0xC0820115},
+ /*3 2 4 0 */
+ {0x000016A0, 0xC0C20019},
+ /*4 2 4 13 */
+ {0x000016A0, 0xC1020108},
+ /*5 2 4 5 */
+ {0x000016A0, 0xC1420100},
+ /*6 2 4 19 */
+ {0x000016A0, 0xC1820111},
+ /*7 2 4 0 */
+ {0x000016A0, 0xC1C2001B},
+ /*8 2 4 10 */
+ /*{0x000016A0, 0xC2020117}, */
+ {0x000016A0, 0xC202010C},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0005508},
+ /*1 */
+ {0x000016A0, 0xC0409819},
+ /*2 */
+ {0x000016A0, 0xC080650C},
+ /*3 */
+ {0x000016A0, 0xC0C0700F},
+ /*4 */
+ {0x000016A0, 0xC1004103},
+ /*5 */
+ {0x000016A0, 0xC140A81D},
+ /*6 */
+ {0x000016A0, 0xC180650C},
+ /*7 */
+ {0x000016A0, 0xC1C08013},
+ /*8 */
+ {0x000016A0, 0xC2005508},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_533[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 4 15 */
+ {0x000016A0, 0xC002040C},
+ /*1 2 4 2 */
+ {0x000016A0, 0xC0420117},
+ /*2 2 4 27 */
+ {0x000016A0, 0xC082041B},
+ /*3 2 4 0 */
+ {0x000016A0, 0xC0C20117},
+ /*4 2 4 13 */
+ {0x000016A0, 0xC102040A},
+ /*5 2 4 5 */
+ {0x000016A0, 0xC1420117},
+ /*6 2 4 19 */
+ {0x000016A0, 0xC1820419},
+ /*7 2 4 0 */
+ {0x000016A0, 0xC1C20117},
+ /*8 2 4 10 */
+ {0x000016A0, 0xC2020117},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0008113},
+ /*1 */
+ {0x000016A0, 0xC0404504},
+ /*2 */
+ {0x000016A0, 0xC0808514},
+ /*3 */
+ {0x000016A0, 0xC0C09418},
+ /*4 */
+ {0x000016A0, 0xC1006D0E},
+ /*5 */
+ {0x000016A0, 0xC1405508},
+ /*6 */
+ {0x000016A0, 0xC1807D12},
+ /*7 */
+ {0x000016A0, 0xC1C0b01F},
+ /*8 */
+ {0x000016A0, 0xC2005D0A},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x00000008}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000A}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_600[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020104},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420010},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820112},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20009},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC102001F},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420014},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C2000C},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0009919},
+ /*1 */
+ {0x000016A0, 0xC0405508},
+ /*2 */
+ {0x000016A0, 0xC0809919},
+ /*3 */
+ {0x000016A0, 0xC0C09C1A},
+ /*4 */
+ {0x000016A0, 0xC1008113},
+ /*5 */
+ {0x000016A0, 0xC140650C},
+ /*6 */
+ {0x000016A0, 0xC1809518},
+ /*7 */
+ {0x000016A0, 0xC1C04103},
+ /*8 */
+ {0x000016A0, 0xC2006D0E},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_667[MV_MAX_DDR3_STATIC_SIZE] = {
+
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020103},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420012},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820113},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20012},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC1020100},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420016},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C20010},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC000b11F},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C0a81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC180ad1e},
+ /*7 */
+ {0x000016A0, 0xC1C04d06},
+ /*8 */
+ {0x000016A0, 0xC2008514},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_800[MV_MAX_DDR3_STATIC_SIZE] = {
+
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020213},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420108},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820210},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20108},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC102011A},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420300},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820204},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C20106},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC000620B},
+ /*1 */
+ {0x000016A0, 0xC0408D16},
+ /*2 */
+ {0x000016A0, 0xC0806A0D},
+ /*3 */
+ {0x000016A0, 0xC0C03D02},
+ /*4 */
+ {0x000016A0, 0xC1004a05},
+ /*5 */
+ {0x000016A0, 0xC140A11B},
+ /*6 */
+ {0x000016A0, 0xC1805E0A},
+ /*7 */
+ {0x000016A0, 0xC1C06D0E},
+ /*8 */
+ {0x000016A0, 0xC200AD1E},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000C}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000E}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_0[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC002010E},
+ /*1 */
+ {0x000016A0, 0xC042001E},
+ /*2 */
+ {0x000016A0, 0xC0820118},
+ /*3 */
+ {0x000016A0, 0xC0C2001E},
+ /*4 */
+ {0x000016A0, 0xC102010C},
+ /*5 */
+ {0x000016A0, 0xC1420102},
+ /*6 */
+ {0x000016A0, 0xC1820111},
+ /*7 */
+ {0x000016A0, 0xC1C2001C},
+ /*8 */
+ {0x000016A0, 0xC2020109},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0805207},
+ /*3 */
+ {0x000016A0, 0xC0C0A81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC1803E02},
+ /*7 */
+ {0x000016A0, 0xC1C05107},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_1[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020106},
+ /*1 */
+ {0x000016A0, 0xC0420016},
+ /*2 */
+ {0x000016A0, 0xC0820117},
+ /*3 */
+ {0x000016A0, 0xC0C2000F},
+ /*4 */
+ {0x000016A0, 0xC1020105},
+ /*5 */
+ {0x000016A0, 0xC142001B},
+ /*6 */
+ {0x000016A0, 0xC182010C},
+ /*7 */
+ {0x000016A0, 0xC1C20011},
+ /*8 */
+ {0x000016A0, 0xC2020101},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC0406D0E},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C04504},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC1803600},
+ /*7 */
+ {0x000016A0, 0xC1C0610B},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_2[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC002010C},
+ /*1 */
+ {0x000016A0, 0xC042001B},
+ /*2 */
+ {0x000016A0, 0xC082011D},
+ /*3 */
+ {0x000016A0, 0xC0C20015},
+ /*4 */
+ {0x000016A0, 0xC102010B},
+ /*5 */
+ {0x000016A0, 0xC1420101},
+ /*6 */
+ {0x000016A0, 0xC1820113},
+ /*7 */
+ {0x000016A0, 0xC1C20017},
+ /*8 */
+ {0x000016A0, 0xC2020107},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC0406D0E},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C04504},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC180B11F},
+ /*7 */
+ {0x000016A0, 0xC1C0610B},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_db_667_M[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /* CS 0 */
+ /*0 2 3 1 */
+ {0x000016A0, 0xC0020103},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0420012},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0820113},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C20012},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC1020100},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1420016},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1820109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C20010},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC000b11F},
+ /*1 */
+ {0x000016A0, 0xC040690D},
+ /*2 */
+ {0x000016A0, 0xC0803600},
+ /*3 */
+ {0x000016A0, 0xC0C0a81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC180ad1e},
+ /*7 */
+ {0x000016A0, 0xC1C04d06},
+ /*8 */
+ {0x000016A0, 0xC2008514},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ /* CS 1 */
+
+ {0x000016A0, 0xC0060103},
+ /*1 2 2 6 */
+ {0x000016A0, 0xC0460012},
+ /*2 2 3 16 */
+ {0x000016A0, 0xC0860113},
+ /*3 2 1 26 */
+ {0x000016A0, 0xC0C60012},
+ /*4 2 2 29 */
+ {0x000016A0, 0xC1060100},
+ /*5 2 2 13 */
+ {0x000016A0, 0xC1460016},
+ /*6 2 3 6 */
+ {0x000016A0, 0xC1860109},
+ /*7 2 1 31 */
+ {0x000016A0, 0xC1C60010},
+ /*8 2 2 22 */
+ {0x000016A0, 0xC2060112},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC004b11F},
+ /*1 */
+ {0x000016A0, 0xC044690D},
+ /*2 */
+ {0x000016A0, 0xC0843600},
+ /*3 */
+ {0x000016A0, 0xC0C4a81D},
+ /*4 */
+ {0x000016A0, 0xC1049919},
+ /*5 */
+ {0x000016A0, 0xC1447911},
+ /*6 */
+ {0x000016A0, 0xC184ad1e},
+ /*7 */
+ {0x000016A0, 0xC1C44d06},
+ /*8 */
+ {0x000016A0, 0xC2048514},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC807000F},
+
+ /* Both CS */
+
+ {0x00001538, 0x00000B0B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x00000F0F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_rd_667_3[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020118},
+ /*1 */
+ {0x000016A0, 0xC0420108},
+ /*2 */
+ {0x000016A0, 0xC0820202},
+ /*3 */
+ {0x000016A0, 0xC0C20108},
+ /*4 */
+ {0x000016A0, 0xC1020117},
+ /*5 */
+ {0x000016A0, 0xC142010C},
+ /*6 */
+ {0x000016A0, 0xC182011B},
+ /*7 */
+ {0x000016A0, 0xC1C20107},
+ /*8 */
+ {0x000016A0, 0xC2020113},
+
+ /* Write Leveling */
+ /*0 */
+ {0x000016A0, 0xC0003600},
+ /*1 */
+ {0x000016A0, 0xC0406D0E},
+ /*2 */
+ {0x000016A0, 0xC0805207},
+ /*3 */
+ {0x000016A0, 0xC0C0A81D},
+ /*4 */
+ {0x000016A0, 0xC1009919},
+ /*5 */
+ {0x000016A0, 0xC1407911},
+ /*6 */
+ {0x000016A0, 0xC1803E02},
+ /*7 */
+ {0x000016A0, 0xC1C04D06},
+ /*8 */
+ {0x000016A0, 0xC2008113},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+
+ {0x00001538, 0x0000000B}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000F}, /*Read Data Ready Delay Register */
+
+ /*init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+MV_DRAM_TRAINING_INIT ddr3_pcac_600[MV_MAX_DDR3_STATIC_SIZE] = {
+ /* Read Leveling */
+ /*PUP RdSampleDly (+CL) Phase RL ADLL value */
+ /*0 */
+ {0x000016A0, 0xC0020404},
+ /* 1 2 2 6 */
+ {0x000016A0, 0xC042031E},
+ /* 2 2 3 16 */
+ {0x000016A0, 0xC0820411},
+ /* 3 2 1 26 */
+ {0x000016A0, 0xC0C20400},
+ /* 4 2 2 29 */
+ {0x000016A0, 0xC1020404},
+ /* 5 2 2 13 */
+ {0x000016A0, 0xC142031D},
+ /* 6 2 3 6 */
+ {0x000016A0, 0xC182040C},
+ /* 7 2 1 31 */
+ {0x000016A0, 0xC1C2031B},
+ /* 8 2 2 22 */
+ {0x000016A0, 0xC2020112},
+
+ /* Write Leveling */
+ /* 0 */
+ {0x000016A0, 0xC0004905},
+ /* 1 */
+ {0x000016A0, 0xC040A81D},
+ /* 2 */
+ {0x000016A0, 0xC0804504},
+ /* 3 */
+ {0x000016A0, 0xC0C08013},
+ /* 4 */
+ {0x000016A0, 0xC1004504},
+ /* 5 */
+ {0x000016A0, 0xC140A81D},
+ /* 6 */
+ {0x000016A0, 0xC1805909},
+ /* 7 */
+ {0x000016A0, 0xC1C09418},
+ /* 8 */
+ {0x000016A0, 0xC2006D0E},
+
+ /*center DQS on read cycle */
+ {0x000016A0, 0xC803000F},
+ {0x00001538, 0x00000009}, /*Read Data Sample Delays Register */
+ {0x0000153C, 0x0000000D}, /*Read Data Ready Delay Register */
+ /* init DRAM */
+ {0x00001480, 0x00000001},
+ {0x0, 0x0}
+};
+
+#endif /* __AXP_TRAINING_STATIC_H */
diff --git a/drivers/ddr/mvebu/ddr3_axp_vars.h b/drivers/ddr/mvebu/ddr3_axp_vars.h
new file mode 100644
index 0000000..1b0ab56
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_axp_vars.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __AXP_VARS_H
+#define __AXP_VARS_H
+
+#include "ddr3_axp_config.h"
+#include "ddr3_axp_mc_static.h"
+#include "ddr3_axp_training_static.h"
+
+MV_DRAM_MODES ddr_modes[MV_DDR3_MODES_NUMBER] = {
+ /* Conf name CPUFreq FabFreq Chip ID Chip/Board MC regs Training Values */
+ /* db board values: */
+ {"db_800-400", 0xA, 0x5, 0x0, A0, ddr3_A0_db_400, NULL},
+ {"db_1200-300", 0x2, 0xC, 0x0, A0, ddr3_A0_db_400, NULL},
+ {"db_1200-600", 0x2, 0x5, 0x0, A0, NULL, NULL},
+ {"db_1333-667", 0x3, 0x5, 0x0, A0, ddr3_A0_db_667, ddr3_db_rev2_667},
+ {"db_1600-800", 0xB, 0x5, 0x0, A0, ddr3_A0_db_667, ddr3_db_rev2_800},
+ {"amc_1333-667", 0x3, 0x5, 0x0, A0_AMC, ddr3_A0_AMC_667, NULL},
+ {"db_667-667", 0x9, 0x13, 0x0, Z1, ddr3_Z1_db_600, ddr3_db_667},
+ {"db_800-400", 0xA, 0x1, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_400},
+ {"db_1066-533", 0x1, 0x1, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_533},
+ {"db_1200-300", 0x2, 0xC, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_667},
+ {"db_1200-600", 0x2, 0x5, 0x0, Z1, ddr3_Z1_db_600, NULL},
+ {"db_1333-333", 0x3, 0xC, 0x0, Z1, ddr3_Z1_db_300, ddr3_db_400},
+ {"db_1333-667", 0x3, 0x5, 0x0, Z1, ddr3_Z1_db_600, ddr3_db_667},
+ /* pcac board values (Z1 device): */
+ {"pcac_1200-600", 0x2, 0x5, 0x0, Z1_PCAC, ddr3_Z1_db_600,
+ ddr3_pcac_600},
+ /* rd board values (Z1 device): */
+ {"rd_667_0", 0x3, 0x5, 0x0, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_0},
+ {"rd_667_1", 0x3, 0x5, 0x1, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_1},
+ {"rd_667_2", 0x3, 0x5, 0x2, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_2},
+ {"rd_667_3", 0x3, 0x5, 0x3, Z1_RD_SLED, ddr3_Z1_db_600, ddr3_rd_667_3}
+};
+
+/* ODT settings - if needed update the following tables: (ODT_OPT - represents the CS configuration bitmap) */
+
+u16 odt_static[ODT_OPT][MAX_CS] = { /* NearEnd/FarEnd */
+ {0, 0, 0, 0}, /* 0000 0/0 - Not supported */
+ {ODT40, 0, 0, 0}, /* 0001 0/1 */
+ {0, 0, 0, 0}, /* 0010 0/0 - Not supported */
+ {ODT40, ODT40, 0, 0}, /* 0011 0/2 */
+ {0, 0, ODT40, 0}, /* 0100 1/0 */
+ {ODT30, 0, ODT30, 0}, /* 0101 1/1 */
+ {0, 0, 0, 0}, /* 0110 0/0 - Not supported */
+ {ODT120, ODT20, ODT20, 0}, /* 0111 1/2 */
+ {0, 0, 0, 0}, /* 1000 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1001 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1010 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1011 0/0 - Not supported */
+ {0, 0, ODT40, 0}, /* 1100 2/0 */
+ {ODT20, 0, ODT120, ODT20}, /* 1101 2/1 */
+ {0, 0, 0, 0}, /* 1110 0/0 - Not supported */
+ {ODT120, ODT30, ODT120, ODT30} /* 1111 2/2 */
+};
+
+u16 odt_dynamic[ODT_OPT][MAX_CS] = { /* NearEnd/FarEnd */
+ {0, 0, 0, 0}, /* 0000 0/0 */
+ {0, 0, 0, 0}, /* 0001 0/1 */
+ {0, 0, 0, 0}, /* 0010 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 0011 0/2 */
+ {0, 0, 0, 0}, /* 0100 1/0 */
+ {ODT120D, 0, ODT120D, 0}, /* 0101 1/1 */
+ {0, 0, 0, 0}, /* 0110 0/0 - Not supported */
+ {0, 0, ODT120D, 0}, /* 0111 1/2 */
+ {0, 0, 0, 0}, /* 1000 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1001 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1010 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1011 0/0 - Not supported */
+ {0, 0, 0, 0}, /* 1100 2/0 */
+ {ODT120D, 0, 0, 0}, /* 1101 2/1 */
+ {0, 0, 0, 0}, /* 1110 0/0 - Not supported */
+ {0, 0, 0, 0} /* 1111 2/2 */
+};
+
+u32 odt_config[ODT_OPT] = {
+ 0, 0x00010000, 0, 0x00030000, 0x04000000, 0x05050104, 0, 0x07430340, 0,
+ 0, 0, 0,
+ 0x30000, 0x1C0D100C, 0, 0x3CC330C0
+};
+
+/*
+ * User can manually set SPD values (in case SPD is not available on
+ * DIMM/System).
+ * SPD Values can simplify calculating the DUNIT registers values
+ */
+u8 spd_data[SPD_SIZE] = {
+ /* AXP DB Board DIMM SPD Values - manually set */
+ 0x92, 0x10, 0x0B, 0x2, 0x3, 0x19, 0x0, 0x9, 0x09, 0x52, 0x1, 0x8, 0x0C,
+ 0x0, 0x7E, 0x0, 0x69, 0x78,
+ 0x69, 0x30, 0x69, 0x11, 0x20, 0x89, 0x0, 0x5, 0x3C, 0x3C, 0x0, 0xF0,
+ 0x82, 0x5, 0x80, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0F, 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x80, 0x2C, 0x1, 0x10, 0x23, 0x35, 0x28, 0xEB, 0xCA, 0x19, 0x8F
+};
+
+/*
+ * Controller Specific configurations Starts Here - DO NOT MODIFY
+ */
+
+/* Frequency - values are 1/HCLK in ps */
+u32 cpu_fab_clk_to_hclk[FAB_OPT][CLK_CPU] =
+/* CPU Frequency:
+ 1000 1066 1200 1333 1500 1666 1800 2000 600 667 800 1600 Fabric */
+{
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 2500, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 4500, 3750, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 2500, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {4000, 3750, 3333, 3000, 2666, 2400, 0, 0, 0, 0, 5000, 2500},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {2500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 5000, 0, 4000, 0, 0, 0, 0, 0, 0, 3750},
+ {5000, 0, 0, 3750, 3333, 0, 0, 0, 0, 0, 0, 3125},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 3330, 3000, 0, 0, 0, 0, 0, 0, 0, 2500},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3750},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 3000, 2500, 0},
+ {3000, 0, 2500, 0, 0, 0, 0, 0, 0, 0, 3750, 0}
+};
+
+u32 cpu_ddr_ratios[FAB_OPT][CLK_CPU] =
+/* CPU Frequency:
+ 1000 1066 1200 1333 1500 1666 1800 2000 600 667 800 1600 Fabric */
+{
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_333, DDR_400, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_444, DDR_533, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, DDR_400, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {DDR_500, DDR_533, DDR_600, DDR_666, DDR_750, DDR_833, 0, 0, 0, 0,
+ DDR_400, DDR_800},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_333, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {DDR_400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, DDR_400, 0, DDR_500, 0, 0, 0, 0, 0, 0, DDR_533},
+ {DDR_400, 0, 0, DDR_533, DDR_600, 0, 0, 0, 0, 0, 0, DDR_640},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, DDR_300, DDR_333, 0, 0, 0, 0, 0, 0, 0, DDR_400},
+ {0, 0, 0, 0, 0, 0, DDR_600, DDR_666, 0, 0, 0, DDR_533},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, DDR_666, DDR_800, 0},
+ {DDR_666, 0, DDR_800, 0, 0, 0, 0, 0, 0, 0, DDR_533, 0}
+};
+
+u8 div_ratio1to1[CLK_VCO][CLK_DDR] =
+/* DDR Frequency:
+ 100 300 360 400 444 500 533 600 666 750 800 833 */
+{ {0xA, 3, 0, 3, 0, 2, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1000 */
+{0xB, 3, 0, 3, 0, 0, 2, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1066 */
+{0xC, 4, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1200 */
+{0xD, 4, 0, 4, 0, 0, 0, 0, 2, 0, 0, 0}, /* 1:1 CLK_CPU_1333 */
+{0xF, 5, 0, 4, 0, 3, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1500 */
+{0x11, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1666 */
+{0x12, 6, 5, 4, 0, 0, 0, 3, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1800 */
+{0x14, 7, 0, 5, 0, 4, 0, 0, 3, 0, 0, 0}, /* 1:1 CLK_CPU_2000 */
+{0x6, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_600 */
+{0x6, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_667 */
+{0x8, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_800 */
+{0x10, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1600 */
+{0x14, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1000 VCO_2000 */
+{0x15, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1066 VCO_2133 */
+{0x18, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1200 VCO_2400 */
+{0x1A, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1333 VCO_2666 */
+{0x1E, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1500 VCO_3000 */
+{0x21, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1666 VCO_3333 */
+{0x24, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_1800 VCO_3600 */
+{0x28, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_2000 VCO_4000 */
+{0xC, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_600 VCO_1200 */
+{0xD, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_667 VCO_1333 */
+{0x10, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1:1 CLK_CPU_800 VCO_1600 */
+{0x20, 10, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0} /* 1:1 CLK_CPU_1600 VCO_3200 */
+};
+
+u8 div_ratio2to1[CLK_VCO][CLK_DDR] =
+/* DDR Frequency:
+ 100 300 360 400 444 500 533 600 666 750 800 833 */
+{ {0, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0}, /* 2:1 CLK_CPU_1000 */
+{0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1066 */
+{0, 0, 0, 3, 5, 0, 0, 2, 0, 0, 3, 3}, /* 2:1 CLK_CPU_1200 */
+{0, 0, 0, 0, 0, 0, 5, 0, 2, 0, 3, 0}, /* 2:1 CLK_CPU_1333 */
+{0, 0, 0, 0, 0, 3, 0, 5, 0, 2, 0, 0}, /* 2:1 CLK_CPU_1500 */
+{0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 2}, /* 2:1 CLK_CPU_1666 */
+{0, 0, 0, 0, 0, 0, 0, 3, 0, 5, 0, 0}, /* 2:1 CLK_CPU_1800 */
+{0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 5}, /* 2:1 CLK_CPU_2000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_600 */
+{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, /* 2:1 CLK_CPU_667 */
+{0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0}, /* 2:1 CLK_CPU_800 */
+{0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0}, /* 2:1 CLK_CPU_1600 */
+{0, 0, 0, 5, 0, 0, 0, 0, 3, 0, 0, 0}, /* 2:1 CLK_CPU_1000 VCO_2000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1066 VCO_2133 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0}, /* 2:1 CLK_CPU_1200 VCO_2400 */
+{0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1333 VCO_2666 */
+{0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1500 VCO_3000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1666 VCO_3333 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_1800 VCO_3600 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_2000 VCO_4000 */
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_600 VCO_1200 */
+{0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_667 VCO_1333 */
+{0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0}, /* 2:1 CLK_CPU_800 VCO_1600 */
+{0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0} /* 2:1 CLK_CPU_1600 VCO_3200 */
+};
+
+#endif /* __AXP_VARS_H */
diff --git a/drivers/ddr/mvebu/ddr3_dfs.c b/drivers/ddr/mvebu/ddr3_dfs.c
new file mode 100644
index 0000000..9347773
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_dfs.c
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_DFS_C(s, d, l) \
+ DEBUG_DFS_S(s); DEBUG_DFS_D(d, l); DEBUG_DFS_S("\n")
+#define DEBUG_DFS_FULL_C(s, d, l) \
+ DEBUG_DFS_FULL_S(s); DEBUG_DFS_FULL_D(d, l); DEBUG_DFS_FULL_S("\n")
+
+#ifdef MV_DEBUG_DFS
+#define DEBUG_DFS_S(s) puts(s)
+#define DEBUG_DFS_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DFS_S(s)
+#define DEBUG_DFS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_DFS_FULL
+#define DEBUG_DFS_FULL_S(s) puts(s)
+#define DEBUG_DFS_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DFS_FULL_S(s)
+#define DEBUG_DFS_FULL_D(d, l)
+#endif
+
+#if defined(MV88F672X)
+extern u8 div_ratio[CLK_VCO][CLK_DDR];
+extern void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+#else
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+extern u8 div_ratio1to1[CLK_CPU][CLK_DDR];
+extern u8 div_ratio2to1[CLK_CPU][CLK_DDR];
+#endif
+extern u16 odt_static[ODT_OPT][MAX_CS];
+
+extern u32 cpu_fab_clk_to_hclk[FAB_OPT][CLK_CPU];
+
+extern u32 ddr3_get_vco_freq(void);
+
+u32 ddr3_get_freq_parameter(u32 target_freq, int ratio_2to1);
+
+#ifdef MV_DEBUG_DFS
+static inline void dfs_reg_write(u32 addr, u32 val)
+{
+ printf("\n write reg 0x%08x = 0x%08x", addr, val);
+ writel(val, INTER_REGS_BASE + addr);
+}
+#else
+static inline void dfs_reg_write(u32 addr, u32 val)
+{
+ writel(val, INTER_REGS_BASE + addr);
+}
+#endif
+
+static void wait_refresh_op_complete(void)
+{
+ u32 reg;
+
+ /* Poll - Wait for Refresh operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ REG_SDRAM_OPERATION_CMD_RFRS_DONE;
+ } while (reg); /* Wait for '0' */
+}
+
+/*
+ * Name: ddr3_get_freq_parameter
+ * Desc: Finds CPU/DDR frequency ratio according to Sample@reset and table.
+ * Args: target_freq - target frequency
+ * Notes:
+ * Returns: freq_par - the ratio parameter
+ */
+u32 ddr3_get_freq_parameter(u32 target_freq, int ratio_2to1)
+{
+ u32 ui_vco_freq, freq_par;
+
+ ui_vco_freq = ddr3_get_vco_freq();
+
+#if defined(MV88F672X)
+ freq_par = div_ratio[ui_vco_freq][target_freq];
+#else
+ /* Find the ratio between PLL frequency and ddr-clk */
+ if (ratio_2to1)
+ freq_par = div_ratio2to1[ui_vco_freq][target_freq];
+ else
+ freq_par = div_ratio1to1[ui_vco_freq][target_freq];
+#endif
+
+ return freq_par;
+}
+
+/*
+ * Name: ddr3_dfs_high_2_low
+ * Desc:
+ * Args: freq - target frequency
+ * Notes:
+ * Returns: MV_OK - success, MV_FAIL - fail
+ */
+int ddr3_dfs_high_2_low(u32 freq, MV_DRAM_INFO *dram_info)
+{
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* This Flow is relevant for ArmadaXP A0 */
+ u32 reg, freq_par, tmp;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - 100MHz */
+ freq_par = ddr3_get_freq_parameter(freq, 0);
+
+#if defined(MV88F672X)
+ u32 hclk;
+ u32 cpu_freq = ddr3_get_cpu_freq();
+ get_target_freq(cpu_freq, &tmp, &hclk);
+#endif
+
+ /* Configure - DRAM DLL final state after DFS is complete - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ /* [0] - DfsDllNextState - Disable */
+ reg |= (1 << REG_DFS_DLLNEXTSTATE_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable internal
+ * access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Disable */
+ reg &= ~(1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* Configure - Block new external transactions - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Registered DIMM support */
+ if (dram_info->reg_dimm) {
+ /*
+ * Configure - Disable Register DIMM CKE Power
+ * Down mode - CWA_RC
+ */
+ reg = (0x9 & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+ REG_SDRAM_OPERATION_CWA_RC_OFFS;
+ /*
+ * Configure - Disable Register DIMM CKE Power
+ * Down mode - CWA_DATA
+ */
+ reg |= ((0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+
+ /*
+ * Configure - Disable Register DIMM CKE Power
+ * Down mode - Set Delay - tMRD
+ */
+ reg |= (0 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+
+ /* Configure - Issue CWA command with the above parameters */
+ reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for CWA operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ (REG_SDRAM_OPERATION_CMD_MASK);
+ } while (reg);
+
+ /* Configure - Disable outputs floating during Self Refresh */
+ reg = reg_read(REG_REGISTERED_DRAM_CTRL_ADDR);
+ /* [15] - SRFloatEn - Disable */
+ reg &= ~(1 << REG_REGISTERED_DRAM_CTRL_SR_FLOAT_OFFS);
+ /* 0x16D0 - DDR3 Registered DRAM Control */
+ dfs_reg_write(REG_REGISTERED_DRAM_CTRL_ADDR, reg);
+ }
+
+ /* Optional - Configure - DDR3_Rtt_nom_CS# */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS));
+ reg &= REG_DDR3_MR1_RTT_MASK;
+ dfs_reg_write(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* Configure - Move DRAM into Self Refresh */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_SR_OFFS); /* [2] - DfsSR - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Poll - Wait for Self Refresh indication */
+ do {
+ reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+ } while (reg == 0x0); /* 0x1528 [3] - DfsAtSR - Wait for '1' */
+
+ /* Start of clock change procedure (PLL) */
+#if defined(MV88F672X)
+ /* avantaLP */
+ /* Configure cpupll_clkdiv_reset_mask */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL0_MASK;
+ /* 0xE8264[7:0] 0xff CPU Clock Dividers Reset mask */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, (reg + 0xFF));
+
+ /* Configure cpu_clkdiv_reload_smooth */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELOAD_SMOOTH_MASK;
+ /* 0xE8260 [15:8] 0x2 CPU Clock Dividers Reload Smooth enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ (reg + (2 << CPU_PLL_CNTRL0_RELOAD_SMOOTH_OFFS)));
+
+ /* Configure cpupll_clkdiv_relax_en */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELAX_EN_MASK;
+ /* 0xE8260 [31:24] 0x2 Relax Enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ (reg + (2 << CPU_PLL_CNTRL0_RELAX_EN_OFFS)));
+
+ /* Configure cpupll_clkdiv_ddr_clk_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL1);
+ /*
+ * 0xE8268 [13:8] N Set Training clock:
+ * APLL Out Clock (VCO freq) / N = 100 MHz
+ */
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL1_MASK;
+ reg |= (freq_par << 8); /* full Integer ratio from PLL-out to ddr-clk */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL1, reg);
+
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x1 CPU Clock Dividers Reload Ratio trigger set */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0,
+ (reg + (1 << CPU_PLL_CLOCK_RELOAD_RATIO_OFFS)));
+
+ udelay(1);
+
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x0 CPU Clock Dividers Reload Ratio trigger clear */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, reg);
+
+ udelay(5);
+
+#else
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8] and
+ * force reserved bits[7:0].
+ */
+ reg = 0x0000FDFF;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel
+ * (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18704 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_2_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+
+ /* full Integer ratio from PLL-out to ddr-clk */
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_2_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+
+ /* Clock is not shut off gracefully - keep it running */
+ reg = 0x000FFF02;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==>
+ * only DDR Phy (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ reg = 0x0102FDFF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1); /* Wait 1usec */
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks
+ * are active - 0x18718 [8]
+ */
+ do {
+ reg = (reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR)) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests
+ * of ratio modifications.
+ */
+ reg = 0x000000FF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(5);
+#endif
+ /* End of clock change procedure (PLL) */
+
+ /* Configure - Select normal clock for the DDR PHY - Enable */
+ reg = reg_read(REG_DRAM_INIT_CTRL_STATUS_ADDR);
+ /* [16] - ddr_phy_trn_clk_sel - Enable */
+ reg |= (1 << REG_DRAM_INIT_CTRL_TRN_CLK_OFFS);
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+ /* Configure - Set Correct Ratio - 1:1 */
+ /* [15] - Phy2UnitClkRatio = 0 - Set 1:1 Ratio between Dunit and Phy */
+
+ reg = reg_read(REG_DDR_IO_ADDR) & ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Register */
+
+ /* Configure - 2T Mode - Restore original configuration */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ /* [3:4] 2T - 1T Mode - low freq */
+ reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+ /* 0x1404 - DDR Controller Control Low Register */
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* Configure - Restore CL and CWL - MRS Commands */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(REG_DFS_CL_NEXT_STATE_MASK << REG_DFS_CL_NEXT_STATE_OFFS);
+ reg &= ~(REG_DFS_CWL_NEXT_STATE_MASK << REG_DFS_CWL_NEXT_STATE_OFFS);
+ /* [8] - DfsCLNextState - MRS CL=6 after DFS (due to DLL-off mode) */
+ reg |= (0x4 << REG_DFS_CL_NEXT_STATE_OFFS);
+ /* [12] - DfsCWLNextState - MRS CWL=6 after DFS (due to DLL-off mode) */
+ reg |= (0x1 << REG_DFS_CWL_NEXT_STATE_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Poll - Wait for APLL + ADLLs lock on new frequency */
+ do {
+ reg = (reg_read(REG_PHY_LOCK_STATUS_ADDR)) &
+ REG_PHY_LOCK_APLL_ADLL_STATUS_MASK;
+ /* 0x1674 [10:0] - Phy lock status Register */
+ } while (reg != REG_PHY_LOCK_APLL_ADLL_STATUS_MASK);
+
+ /* Configure - Reset the PHY Read FIFO and Write channels - Set Reset */
+ reg = (reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK);
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /*
+ * Configure - DRAM Data PHY Read [30], Write [29] path
+ * reset - Release Reset
+ */
+ reg = (reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK);
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Registered DIMM support */
+ if (dram_info->reg_dimm) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (below 400MHz) - CWA_RC
+ */
+ reg = (0xA & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+ REG_SDRAM_OPERATION_CWA_RC_OFFS;
+
+ /*
+ * Configure - Change register DRAM operating speed
+ * (below 400MHz) - CWA_DATA
+ */
+ reg |= ((0x0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+
+ /* Configure - Set Delay - tSTAB */
+ reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+
+ /* Configure - Issue CWA command with the above parameters */
+ reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for CWA operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ (REG_SDRAM_OPERATION_CMD_MASK);
+ } while (reg);
+ }
+
+ /* Configure - Exit Self Refresh */
+ /* [2] - DfsSR */
+ reg = (reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS));
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll - DFS Register - 0x1528 [3] - DfsAtSR - All DRAM devices
+ * on all ranks are NOT in self refresh mode
+ */
+ do {
+ reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+ } while (reg); /* Wait for '0' */
+
+ /* Configure - Issue Refresh command */
+ /* [3-0] = 0x2 - Refresh Command, [11-8] - enabled Cs */
+ reg = REG_SDRAM_OPERATION_CMD_RFRS;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs))
+ reg &= ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ }
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Configure - Block new external transactions - Disable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Disable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable
+ * internal access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Enable */
+ reg |= (1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ /* Configure - Set CL */
+ reg = reg_read(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS)) &
+ ~REG_DDR3_MR0_CL_MASK;
+ tmp = 0x4; /* CL=6 - 0x4 */
+ reg |= ((tmp & 0x1) << REG_DDR3_MR0_CL_OFFS);
+ reg |= ((tmp & 0xE) << REG_DDR3_MR0_CL_HIGH_OFFS);
+ dfs_reg_write(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+
+ /* Configure - Set CWL */
+ reg = reg_read(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS))
+ & ~(REG_DDR3_MR2_CWL_MASK << REG_DDR3_MR2_CWL_OFFS);
+ /* CWL=6 - 0x1 */
+ reg |= ((0x1) << REG_DDR3_MR2_CWL_OFFS);
+ dfs_reg_write(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Ended successfuly - new Frequency - ",
+ freq, 1);
+
+ return MV_OK;
+#else
+ /* This Flow is relevant for Armada370 A0 and ArmadaXP Z1 */
+
+ u32 reg, freq_par;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - 100MHz */
+ freq_par = ddr3_get_freq_parameter(freq, 0);
+
+ reg = 0x0000FF00;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ /* 0x1600 - ODPG_CNTRL_Control */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ /* [21] = 1 - auto refresh disable */
+ reg |= (1 << REG_ODPG_CNTRL_OFFS);
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg &= REG_PHY_LOCK_MASK_MASK; /* [11:0] = 0 */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ reg = reg_read(REG_DFS_ADDR); /* 0x1528 - DFS register */
+
+ /* Disable reconfig */
+ reg &= ~0x10; /* [4] - Enable reconfig MR registers after DFS_ERG */
+ reg |= 0x1; /* [0] - DRAM DLL disabled after DFS */
+
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ reg = reg_read(REG_METAL_MASK_ADDR) & ~(1 << 0); /* [0] - disable */
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* [1] - DFS Block enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* [2] - DFS Self refresh enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - 0x1528 [3] - DfsAtSR -
+ * All DRAM devices on all ranks are in self refresh mode -
+ * DFS can be executed afterwards
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg == 0x0); /* Wait for '1' */
+
+ /* Disable ODT on DLL-off mode */
+ dfs_reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR,
+ REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK);
+
+ /* [11:0] = 0 */
+ reg = (reg_read(REG_PHY_LOCK_MASK_ADDR) & REG_PHY_LOCK_MASK_MASK);
+ /* 0x1670 - PHY lock mask register */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ /* Add delay between entering SR and start ratio modification */
+ udelay(1);
+
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8] and
+ * force reserved bits[7:0].
+ */
+ reg = 0x0000FDFF;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_3_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+ /* Full Integer ratio from PLL-out to ddr-clk */
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_3_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+
+ /* Clock is not shut off gracefully - keep it running */
+ reg = 0x000FFF02;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+ * (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ reg = 0x0102FDFF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1); /* Wait 1usec */
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks
+ * are active - 0x18718 [8]
+ */
+ do {
+ reg = (reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR)) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests of
+ * ratio modifications.
+ */
+ reg = 0x000000FF;
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(5);
+
+ /* Switch HCLK Mux to training clk (100Mhz), keep DFS request bit */
+ reg = 0x20050000;
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+ reg = reg_read(REG_DDR_IO_ADDR) & ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ /* [15] = 0 - Set 1:1 Ratio between Dunit and Phy */
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Regist */
+
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30]] - reset pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ reg = (reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK);
+ /* [31:30] - normal pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ udelay(1); /* Wait 1usec */
+
+ /* 0x1404 */
+ reg = (reg_read(REG_DUNIT_CTRL_LOW_ADDR) & 0xFFFFFFE7);
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* Poll Phy lock status register - APLL lock indication - 0x1674 */
+ do {
+ reg = (reg_read(REG_PHY_LOCK_STATUS_ADDR)) &
+ REG_PHY_LOCK_STATUS_LOCK_MASK;
+ } while (reg != REG_PHY_LOCK_STATUS_LOCK_MASK); /* Wait for '0xFFF' */
+
+ reg = (reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK);
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ udelay(1000); /* Wait 1msec */
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Config CL and CWL with MR0 and MR2 registers */
+ reg = reg_read(REG_DDR3_MR0_ADDR);
+ reg &= ~0x74; /* CL [3:0]; [6:4],[2] */
+ reg |= (1 << 5); /* CL = 4, CAS is 6 */
+ dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+ reg = REG_SDRAM_OPERATION_CMD_MR0 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ reg = reg_read(REG_DDR3_MR2_ADDR);
+ reg &= ~0x38; /* CWL [5:3] */
+ reg |= (1 << 3); /* CWL = 1, CWL is 6 */
+ dfs_reg_write(REG_DDR3_MR2_ADDR, reg);
+
+ reg = REG_SDRAM_OPERATION_CMD_MR2 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg |= (5 << (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+ /* Set current rd_ready_delay */
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((6) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ }
+ }
+
+ /* [2] - DFS Self refresh disable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* [1] - DFS Block enable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - 0x1528 [3] - DfsAtSR -
+ * All DRAM devices on all ranks are in self refresh mode - DFS can
+ * be executed afterwards
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg); /* Wait for '1' */
+
+ reg = (reg_read(REG_METAL_MASK_ADDR) | (1 << 0));
+ /* [0] - Enable Dunit to crossbar retry */
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* 0x1600 - PHY lock mask register */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ reg &= ~(1 << REG_ODPG_CNTRL_OFFS); /* [21] = 0 */
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg |= ~REG_PHY_LOCK_MASK_MASK; /* [11:0] = FFF */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ DEBUG_DFS_C("DDR3 - DFS - High To Low - Ended successfuly - new Frequency - ",
+ freq, 1);
+
+ return MV_OK;
+#endif
+}
+
+/*
+ * Name: ddr3_dfs_low_2_high
+ * Desc:
+ * Args: freq - target frequency
+ * Notes:
+ * Returns: MV_OK - success, MV_FAIL - fail
+ */
+int ddr3_dfs_low_2_high(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* This Flow is relevant for ArmadaXP A0 */
+ u32 reg, freq_par, tmp;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - freq */
+ freq_par = ddr3_get_freq_parameter(freq, ratio_2to1);
+
+#if defined(MV88F672X)
+ u32 hclk;
+ u32 cpu_freq = ddr3_get_cpu_freq();
+ get_target_freq(cpu_freq, &tmp, &hclk);
+#endif
+
+ /* Configure - DRAM DLL final state after DFS is complete - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ /* [0] - DfsDllNextState - Enable */
+ reg &= ~(1 << REG_DFS_DLLNEXTSTATE_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable
+ * internal access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Disable */
+ reg &= ~(1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* Configure - Block new external transactions - Enable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Configure - Move DRAM into Self Refresh */
+ reg = reg_read(REG_DFS_ADDR);
+ reg |= (1 << REG_DFS_SR_OFFS); /* [2] - DfsSR - Enable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Poll - Wait for Self Refresh indication */
+ do {
+ reg = ((reg_read(REG_DFS_ADDR)) & (1 << REG_DFS_ATSR_OFFS));
+ } while (reg == 0x0); /* 0x1528 [3] - DfsAtSR - Wait for '1' */
+
+ /* Start of clock change procedure (PLL) */
+#if defined(MV88F672X)
+ /* avantaLP */
+ /* Configure cpupll_clkdiv_reset_mask */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL0_MASK;
+ /* 0xE8264[7:0] 0xff CPU Clock Dividers Reset mask */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, (reg + 0xFF));
+
+ /* Configure cpu_clkdiv_reload_smooth */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELOAD_SMOOTH_MASK;
+ /* 0xE8260 [15:8] 0x2 CPU Clock Dividers Reload Smooth enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ reg + (2 << CPU_PLL_CNTRL0_RELOAD_SMOOTH_OFFS));
+
+ /* Configure cpupll_clkdiv_relax_en */
+ reg = reg_read(CPU_PLL_CNTRL0);
+ reg &= CPU_PLL_CNTRL0_RELAX_EN_MASK;
+ /* 0xE8260 [31:24] 0x2 Relax Enable */
+ dfs_reg_write(CPU_PLL_CNTRL0,
+ reg + (2 << CPU_PLL_CNTRL0_RELAX_EN_OFFS));
+
+ /* Configure cpupll_clkdiv_ddr_clk_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL1);
+ /*
+ * 0xE8268 [13:8] N Set Training clock:
+ * APLL Out Clock (VCO freq) / N = 100 MHz
+ */
+ reg &= CPU_PLL_CLOCK_DIVIDER_CNTRL1_MASK;
+ reg |= (freq_par << 8); /* full Integer ratio from PLL-out to ddr-clk */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL1, reg);
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x1 CPU Clock Dividers Reload Ratio trigger set */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0,
+ reg + (1 << CPU_PLL_CLOCK_RELOAD_RATIO_OFFS));
+
+ udelay(1);
+
+ /* Configure cpupll_clkdiv_reload_ratio */
+ reg = reg_read(CPU_PLL_CLOCK_DIVIDER_CNTRL0);
+ reg &= CPU_PLL_CLOCK_RELOAD_RATIO_MASK;
+ /* 0xE8264 [8]=0x0 CPU Clock Dividers Reload Ratio trigger clear */
+ dfs_reg_write(CPU_PLL_CLOCK_DIVIDER_CNTRL0, reg);
+
+ udelay(5);
+
+#else
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8]
+ * and force reserved bits[7:0].
+ */
+ reg = 0x0000FFFF;
+
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18704 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_2_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* full Integer ratio from PLL-out to ddr-clk */
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_2_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+ reg = 0x000FFF02;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ reg = 0x0102FDFF;
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+ * (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1);
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks
+ * are active - 0x18718 [8]
+ */
+ do {
+ reg = reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ reg = 0x000000FF;
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests
+ * of ratio modifications.
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+#endif
+ /* End of clock change procedure (PLL) */
+
+ if (ratio_2to1) {
+ /* Configure - Select normal clock for the DDR PHY - Disable */
+ reg = reg_read(REG_DRAM_INIT_CTRL_STATUS_ADDR);
+ /* [16] - ddr_phy_trn_clk_sel - Disable */
+ reg &= ~(1 << REG_DRAM_INIT_CTRL_TRN_CLK_OFFS);
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+ }
+
+ /*
+ * Configure - Set Correct Ratio - according to target ratio
+ * parameter - 2:1/1:1
+ */
+ if (ratio_2to1) {
+ /*
+ * [15] - Phy2UnitClkRatio = 1 - Set 2:1 Ratio between
+ * Dunit and Phy
+ */
+ reg = reg_read(REG_DDR_IO_ADDR) |
+ (1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ } else {
+ /*
+ * [15] - Phy2UnitClkRatio = 0 - Set 1:1 Ratio between
+ * Dunit and Phy
+ */
+ reg = reg_read(REG_DDR_IO_ADDR) &
+ ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ }
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Register */
+
+ /* Configure - 2T Mode - Restore original configuration */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ /* [3:4] 2T - Restore value */
+ reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+ reg |= ((dram_info->mode_2t & REG_DUNIT_CTRL_LOW_2T_MASK) <<
+ REG_DUNIT_CTRL_LOW_2T_OFFS);
+ /* 0x1404 - DDR Controller Control Low Register */
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* Configure - Restore CL and CWL - MRS Commands */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(REG_DFS_CL_NEXT_STATE_MASK << REG_DFS_CL_NEXT_STATE_OFFS);
+ reg &= ~(REG_DFS_CWL_NEXT_STATE_MASK << REG_DFS_CWL_NEXT_STATE_OFFS);
+
+ if (freq == DDR_400) {
+ if (dram_info->target_frequency == 0x8)
+ tmp = ddr3_cl_to_valid_cl(5);
+ else
+ tmp = ddr3_cl_to_valid_cl(6);
+ } else {
+ tmp = ddr3_cl_to_valid_cl(dram_info->cl);
+ }
+
+ /* [8] - DfsCLNextState */
+ reg |= ((tmp & REG_DFS_CL_NEXT_STATE_MASK) << REG_DFS_CL_NEXT_STATE_OFFS);
+ if (freq == DDR_400) {
+ /* [12] - DfsCWLNextState */
+ reg |= (((0) & REG_DFS_CWL_NEXT_STATE_MASK) <<
+ REG_DFS_CWL_NEXT_STATE_OFFS);
+ } else {
+ /* [12] - DfsCWLNextState */
+ reg |= (((dram_info->cwl) & REG_DFS_CWL_NEXT_STATE_MASK) <<
+ REG_DFS_CWL_NEXT_STATE_OFFS);
+ }
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Optional - Configure - DDR3_Rtt_nom_CS# */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS));
+ reg &= REG_DDR3_MR1_RTT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ dfs_reg_write(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* Configure - Reset ADLLs - Set Reset */
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30]] - reset pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config Register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ /* Configure - Reset ADLLs - Release Reset */
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30] - normal pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ /* Poll - Wait for APLL + ADLLs lock on new frequency */
+ do {
+ reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+ REG_PHY_LOCK_APLL_ADLL_STATUS_MASK;
+ /* 0x1674 [10:0] - Phy lock status Register */
+ } while (reg != REG_PHY_LOCK_APLL_ADLL_STATUS_MASK);
+
+ /* Configure - Reset the PHY SDR clock divider */
+ if (ratio_2to1) {
+ /* Pup Reset Divider B - Set Reset */
+ /* [28] - DataPupRdRST = 0 */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) &
+ ~(1 << REG_SDRAM_CONFIG_PUPRSTDIV_OFFS);
+ /* [28] - DataPupRdRST = 1 */
+ tmp = reg_read(REG_SDRAM_CONFIG_ADDR) |
+ (1 << REG_SDRAM_CONFIG_PUPRSTDIV_OFFS);
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Pup Reset Divider B - Release Reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, tmp);
+ }
+
+ /* Configure - Reset the PHY Read FIFO and Write channels - Set Reset */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /*
+ * Configure - DRAM Data PHY Read [30], Write [29] path reset -
+ * Release Reset
+ */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Registered DIMM support */
+ if (dram_info->reg_dimm) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1333 / DDR3-1600) - CWA_RC
+ */
+ reg = (0xA & REG_SDRAM_OPERATION_CWA_RC_MASK) <<
+ REG_SDRAM_OPERATION_CWA_RC_OFFS;
+ if (freq <= DDR_400) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-800) - CWA_DATA
+ */
+ reg |= ((0x0 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ } else if ((freq > DDR_400) && (freq <= DDR_533)) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1066) - CWA_DATA
+ */
+ reg |= ((0x1 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ } else if ((freq > DDR_533) && (freq <= DDR_666)) {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1333) - CWA_DATA
+ */
+ reg |= ((0x2 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ } else {
+ /*
+ * Configure - Change register DRAM operating speed
+ * (DDR3-1600) - CWA_DATA
+ */
+ reg |= ((0x3 & REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ }
+
+ /* Configure - Set Delay - tSTAB */
+ reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+ /* Configure - Issue CWA command with the above parameters */
+ reg |= (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for CWA operation completion */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ REG_SDRAM_OPERATION_CMD_MASK;
+ } while (reg);
+ }
+
+ /* Configure - Exit Self Refresh */
+ /* [2] - DfsSR */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll - DFS Register - 0x1528 [3] - DfsAtSR - All DRAM
+ * devices on all ranks are NOT in self refresh mode
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Configure - Issue Refresh command */
+ /* [3-0] = 0x2 - Refresh Command, [11-8] - enabled Cs */
+ reg = REG_SDRAM_OPERATION_CMD_RFRS;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs))
+ reg &= ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ }
+
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Configure - Block new external transactions - Disable */
+ reg = reg_read(REG_DFS_ADDR);
+ reg &= ~(1 << REG_DFS_BLOCK_OFFS); /* [1] - DfsBlock - Disable */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Configure - XBAR Retry response during Block to enable
+ * internal access - Disable
+ */
+ reg = reg_read(REG_METAL_MASK_ADDR);
+ /* [0] - RetryMask - Enable */
+ reg |= (1 << REG_METAL_MASK_RETRY_OFFS);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ /* Configure - Set CL */
+ reg = reg_read(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS)) &
+ ~REG_DDR3_MR0_CL_MASK;
+ if (freq == DDR_400)
+ tmp = ddr3_cl_to_valid_cl(6);
+ else
+ tmp = ddr3_cl_to_valid_cl(dram_info->cl);
+ reg |= ((tmp & 0x1) << REG_DDR3_MR0_CL_OFFS);
+ reg |= ((tmp & 0xE) << REG_DDR3_MR0_CL_HIGH_OFFS);
+ dfs_reg_write(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+
+ /* Configure - Set CWL */
+ reg = reg_read(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS)) &
+ ~(REG_DDR3_MR2_CWL_MASK << REG_DDR3_MR2_CWL_OFFS);
+ if (freq == DDR_400)
+ reg |= ((0) << REG_DDR3_MR2_CWL_OFFS);
+ else
+ reg |= ((dram_info->cwl) << REG_DDR3_MR2_CWL_OFFS);
+ dfs_reg_write(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Ended successfuly - new Frequency - ",
+ freq, 1);
+
+ return MV_OK;
+
+#else
+
+ /* This Flow is relevant for Armada370 A0 and ArmadaXP Z1 */
+
+ u32 reg, freq_par, tmp;
+ u32 cs = 0;
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Starting DFS procedure to Frequency - ",
+ freq, 1);
+
+ /* target frequency - freq */
+ freq_par = ddr3_get_freq_parameter(freq, ratio_2to1);
+
+ reg = 0x0000FF00;
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ /* 0x1600 - PHY lock mask register */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ reg |= (1 << REG_ODPG_CNTRL_OFFS); /* [21] = 1 */
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg &= REG_PHY_LOCK_MASK_MASK; /* [11:0] = 0 */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ /* Enable reconfig MR Registers after DFS */
+ reg = reg_read(REG_DFS_ADDR); /* 0x1528 - DFS register */
+ /* [4] - Disable - reconfig MR registers after DFS_ERG */
+ reg &= ~0x11;
+ /* [0] - Enable - DRAM DLL after DFS */
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Disable DRAM Controller to crossbar retry */
+ /* [0] - disable */
+ reg = reg_read(REG_METAL_MASK_ADDR) & ~(1 << 0);
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ /* Enable DRAM Blocking */
+ /* [1] - DFS Block enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Enable Self refresh */
+ /* [2] - DFS Self refresh enable */
+ reg = reg_read(REG_DFS_ADDR) | (1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - All DRAM devices on all ranks are in
+ * self refresh mode - DFS can be executed afterwards
+ */
+ /* 0x1528 [3] - DfsAtSR */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg == 0x0); /* Wait for '1' */
+
+ /*
+ * Set Correct Ratio - if freq>MARGIN_FREQ use 2:1 ratio
+ * else use 1:1 ratio
+ */
+ if (ratio_2to1) {
+ /* [15] = 1 - Set 2:1 Ratio between Dunit and Phy */
+ reg = reg_read(REG_DDR_IO_ADDR) |
+ (1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ } else {
+ /* [15] = 0 - Set 1:1 Ratio between Dunit and Phy */
+ reg = reg_read(REG_DDR_IO_ADDR) &
+ ~(1 << REG_DDR_IO_CLK_RATIO_OFFS);
+ }
+ dfs_reg_write(REG_DDR_IO_ADDR, reg); /* 0x1524 - DDR IO Register */
+
+ /* Switch HCLK Mux from (100Mhz) [16]=0, keep DFS request bit */
+ reg = 0x20040000;
+ /*
+ * [29] - training logic request DFS, [28:27] -
+ * preload patterns frequency [18]
+ */
+
+ /* 0x18488 - DRAM Init control status register */
+ dfs_reg_write(REG_DRAM_INIT_CTRL_STATUS_ADDR, reg);
+
+ /* Add delay between entering SR and start ratio modification */
+ udelay(1);
+
+ /*
+ * Initial Setup - assure that the "load new ratio" is clear (bit 24)
+ * and in the same chance, block reassertions of reset [15:8] and
+ * force reserved bits[7:0].
+ */
+ reg = 0x0000FFFF;
+ /* 0x18700 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ /*
+ * RelaX whenever reset is asserted to that channel (good for any case)
+ */
+ reg = 0x0000FF00;
+ /* 0x18704 - CPU Div CLK control 0 */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_1_ADDR, reg);
+
+ reg = reg_read(REG_CPU_DIV_CLK_CTRL_3_ADDR) &
+ REG_CPU_DIV_CLK_CTRL_3_FREQ_MASK;
+ reg |= (freq_par << REG_CPU_DIV_CLK_CTRL_3_FREQ_OFFS);
+ /* Full Integer ratio from PLL-out to ddr-clk */
+ /* 0x1870C - CPU Div CLK control 3 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_3_ADDR, reg);
+
+ /*
+ * Shut off clock enable to the DDRPHY clock channel (this is the "D").
+ * All the rest are kept as is (forced, but could be read-modify-write).
+ * This is done now by RMW above.
+ */
+
+ reg = 0x000FFF02;
+
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_4_ADDR, reg);
+
+ /* Wait before replacing the clock on the DDR Phy Channel. */
+ udelay(1);
+
+ reg = 0x0102FDFF;
+ /*
+ * This for triggering the frequency update. Bit[24] is the
+ * central control
+ * bits [23:16] == which channels to change ==2 ==> only DDR Phy
+ * (smooth transition)
+ * bits [15:8] == mask reset reassertion due to clock modification
+ * to these channels.
+ * bits [7:0] == not in use
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(1);
+
+ /*
+ * Poll Div CLK status 0 register - indication that the clocks are
+ * active - 0x18718 [8]
+ */
+ do {
+ reg = reg_read(REG_CPU_DIV_CLK_STATUS_0_ADDR) &
+ (1 << REG_CPU_DIV_CLK_ALL_STABLE_OFFS);
+ } while (reg == 0);
+
+ reg = 0x000000FF;
+ /*
+ * Clean the CTRL0, to be ready for next resets and next requests of
+ * ratio modifications.
+ */
+ /* 0x18700 - CPU Div CLK control 0 register */
+ dfs_reg_write(REG_CPU_DIV_CLK_CTRL_0_ADDR, reg);
+
+ udelay(5);
+
+ if (ratio_2to1) {
+ /* Pup Reset Divider B - Set Reset */
+ /* [28] = 0 - Pup Reset Divider B */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) & ~(1 << 28);
+ /* [28] = 1 - Pup Reset Divider B */
+ tmp = reg_read(REG_SDRAM_CONFIG_ADDR) | (1 << 28);
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Pup Reset Divider B - Release Reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, tmp);
+ }
+
+ /* DRAM Data PHYs ADLL Reset - Set Reset */
+ reg = (reg_read(REG_DRAM_PHY_CONFIG_ADDR) & REG_DRAM_PHY_CONFIG_MASK);
+ /* [31:30]] - reset pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config Register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ udelay(25);
+
+ /* APLL lock indication - Poll Phy lock status Register - 0x1674 [9] */
+ do {
+ reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+ (1 << REG_PHY_LOCK_STATUS_LOCK_OFFS);
+ } while (reg == 0);
+
+ /* DRAM Data PHYs ADLL Reset - Release Reset */
+ reg = reg_read(REG_DRAM_PHY_CONFIG_ADDR) | ~REG_DRAM_PHY_CONFIG_MASK;
+ /* [31:30] - normal pup data ctrl ADLL */
+ /* 0x15EC - DRAM PHY Config register */
+ dfs_reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+ udelay(10000); /* Wait 10msec */
+
+ /*
+ * APLL lock indication - Poll Phy lock status Register - 0x1674 [11:0]
+ */
+ do {
+ reg = reg_read(REG_PHY_LOCK_STATUS_ADDR) &
+ REG_PHY_LOCK_STATUS_LOCK_MASK;
+ } while (reg != REG_PHY_LOCK_STATUS_LOCK_MASK);
+
+ /* DRAM Data PHY Read [30], Write [29] path reset - Set Reset */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) & REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = 0 - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* DRAM Data PHY Read [30], Write [29] path reset - Release Reset */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) | ~REG_SDRAM_CONFIG_MASK;
+ /* [30:29] = '11' - Data Pup R/W path reset */
+ /* 0x1400 - SDRAM Configuration register */
+ dfs_reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /* Disable DFS Reconfig */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << 4);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* [2] - DFS Self refresh disable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_SR_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /*
+ * Poll DFS Register - 0x1528 [3] - DfsAtSR - All DRAM devices on
+ * all ranks are NOT in self refresh mode
+ */
+ do {
+ reg = reg_read(REG_DFS_ADDR) & (1 << REG_DFS_ATSR_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* 0x1404 */
+ reg = (reg_read(REG_DUNIT_CTRL_LOW_ADDR) & 0xFFFFFFE7) | 0x2;
+
+ /* Configure - 2T Mode - Restore original configuration */
+ /* [3:4] 2T - Restore value */
+ reg &= ~(REG_DUNIT_CTRL_LOW_2T_MASK << REG_DUNIT_CTRL_LOW_2T_OFFS);
+ reg |= ((dram_info->mode_2t & REG_DUNIT_CTRL_LOW_2T_MASK) <<
+ REG_DUNIT_CTRL_LOW_2T_OFFS);
+ dfs_reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ udelay(1); /* Wait 1us */
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = (reg_read(REG_DDR3_MR1_ADDR));
+ /* DLL Enable */
+ reg &= ~(1 << REG_DDR3_MR1_DLL_ENA_OFFS);
+ dfs_reg_write(REG_DDR3_MR1_ADDR, reg);
+
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* DLL Reset - MR0 */
+ reg = reg_read(REG_DDR3_MR0_ADDR);
+ dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR0 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ reg = reg_read(REG_DDR3_MR0_ADDR);
+ reg &= ~0x74; /* CL [3:0]; [6:4],[2] */
+
+ if (freq == DDR_400)
+ tmp = ddr3_cl_to_valid_cl(6) & 0xF;
+ else
+ tmp = ddr3_cl_to_valid_cl(dram_info->cl) & 0xF;
+
+ reg |= ((tmp & 0x1) << 2);
+ reg |= ((tmp >> 1) << 4); /* to bit 4 */
+ dfs_reg_write(REG_DDR3_MR0_ADDR, reg);
+
+ reg = REG_SDRAM_OPERATION_CMD_MR0 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ reg = reg_read(REG_DDR3_MR2_ADDR);
+ reg &= ~0x38; /* CWL [5:3] */
+ /* CWL = 0 ,for 400 MHg is 5 */
+ if (freq != DDR_400)
+ reg |= dram_info->cwl << REG_DDR3_MR2_CWL_OFFS;
+ dfs_reg_write(REG_DDR3_MR2_ADDR, reg);
+ reg = REG_SDRAM_OPERATION_CMD_MR2 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /* 0x1418 - SDRAM Operation Register */
+ dfs_reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /* Poll - Wait for Refresh operation completion */
+ wait_refresh_op_complete();
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg |= (dram_info->cl <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+ /* Set current rd_ready_delay */
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((dram_info->cl + 1) <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ dfs_reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ }
+ }
+
+ /* Enable ODT on DLL-on mode */
+ dfs_reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, 0);
+
+ /* [1] - DFS Block disable */
+ reg = reg_read(REG_DFS_ADDR) & ~(1 << REG_DFS_BLOCK_OFFS);
+ dfs_reg_write(REG_DFS_ADDR, reg); /* 0x1528 - DFS register */
+
+ /* Change DDR frequency to 100MHz procedure: */
+ /* 0x1600 - PHY lock mask register */
+ reg = reg_read(REG_ODPG_CNTRL_ADDR);
+ reg &= ~(1 << REG_ODPG_CNTRL_OFFS); /* [21] = 0 */
+ dfs_reg_write(REG_ODPG_CNTRL_ADDR, reg);
+
+ /* Change DDR frequency to 100MHz procedure: */
+ /* 0x1670 - PHY lock mask register */
+ reg = reg_read(REG_PHY_LOCK_MASK_ADDR);
+ reg |= ~REG_PHY_LOCK_MASK_MASK; /* [11:0] = FFF */
+ dfs_reg_write(REG_PHY_LOCK_MASK_ADDR, reg);
+
+ reg = reg_read(REG_METAL_MASK_ADDR) | (1 << 0); /* [0] - disable */
+ /* 0x14B0 - Dunit MMask Register */
+ dfs_reg_write(REG_METAL_MASK_ADDR, reg);
+
+ DEBUG_DFS_C("DDR3 - DFS - Low To High - Ended successfuly - new Frequency - ",
+ freq, 1);
+ return MV_OK;
+#endif
+}
diff --git a/drivers/ddr/mvebu/ddr3_dqs.c b/drivers/ddr/mvebu/ddr3_dqs.c
new file mode 100644
index 0000000..71a986d
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_dqs.c
@@ -0,0 +1,1374 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_DQS_C(s, d, l) \
+ DEBUG_DQS_S(s); DEBUG_DQS_D(d, l); DEBUG_DQS_S("\n")
+#define DEBUG_DQS_FULL_C(s, d, l) \
+ DEBUG_DQS_FULL_S(s); DEBUG_DQS_FULL_D(d, l); DEBUG_DQS_FULL_S("\n")
+#define DEBUG_DQS_RESULTS_C(s, d, l) \
+ DEBUG_DQS_RESULTS_S(s); DEBUG_DQS_RESULTS_D(d, l); DEBUG_DQS_RESULTS_S("\n")
+#define DEBUG_PER_DQ_C(s, d, l) \
+ puts(s); printf("%x", d); puts("\n")
+
+#define DEBUG_DQS_RESULTS_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_DQS_RESULTS_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+
+#define DEBUG_PER_DQ_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%s", s)
+#define DEBUG_PER_DQ_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%x", d)
+#define DEBUG_PER_DQ_DD(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_3, "%d", d)
+
+#ifdef MV_DEBUG_DQS
+#define DEBUG_DQS_S(s) puts(s)
+#define DEBUG_DQS_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DQS_S(s)
+#define DEBUG_DQS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_DQS_FULL
+#define DEBUG_DQS_FULL_S(s) puts(s)
+#define DEBUG_DQS_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_DQS_FULL_S(s)
+#define DEBUG_DQS_FULL_D(d, l)
+#endif
+
+/* State machine for centralization - find low & high limit */
+enum {
+ PUP_ADLL_LIMITS_STATE_FAIL,
+ PUP_ADLL_LIMITS_STATE_PASS,
+ PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS,
+};
+
+/* Hold centralization low results */
+static int centralization_low_limit[MAX_PUP_NUM] = { 0 };
+/* Hold centralization high results */
+static int centralization_high_limit[MAX_PUP_NUM] = { 0 };
+
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx);
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+ int *size_valid);
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx);
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup);
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup);
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx);
+
+#ifdef MV88F78X60
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern u32 killer_pattern_64b[DQ_NUM][LEN_SPECIAL_PATTERN];
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#else
+extern u32 killer_pattern[DQ_NUM][LEN_16BIT_KILLER_PATTERN];
+extern u32 killer_pattern_32b[DQ_NUM][LEN_SPECIAL_PATTERN];
+#if defined(MV88F672X)
+extern int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#endif
+#endif
+extern u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN];
+
+static u32 *ddr3_dqs_choose_pattern(MV_DRAM_INFO *dram_info, u32 victim_dq)
+{
+ u32 *pattern_ptr;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&killer_pattern_64b[victim_dq];
+ break;
+#endif
+ default:
+#if defined(MV88F78X60)
+ pattern_ptr = (u32 *)&killer_pattern_32b[victim_dq];
+#else
+ pattern_ptr = (u32 *)&killer_pattern[victim_dq];
+#endif
+ break;
+ }
+
+ return pattern_ptr;
+}
+
+/*
+ * Name: ddr3_dqs_centralization_rx
+ * Desc: Execute the DQS centralization RX phase.
+ * Args: dram_info
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_rx(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, ecc, reg;
+ int status;
+
+ DEBUG_DQS_S("DDR3 - DQS Centralization RX - Starting procedure\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_DQS_S("DDR3 - DQS Centralization RX - SW Override Enabled\n");
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Centralization RX - CS - ",
+ (u32) cs, 1);
+
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Enabled\n");
+ else
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - ECC Mux Disabled\n");
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Find all limits\n");
+
+ status = ddr3_find_adll_limits(dram_info, cs,
+ ecc, 0);
+ if (MV_OK != status)
+ return status;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization RX - Start calculating center\n");
+
+ status = ddr3_center_calc(dram_info, cs, ecc,
+ 0);
+ if (MV_OK != status)
+ return status;
+ }
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_dqs_centralization_tx
+ * Desc: Execute the DQS centralization TX phase.
+ * Args: dram_info
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dqs_centralization_tx(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, ecc, reg;
+ int status;
+
+ DEBUG_DQS_S("DDR3 - DQS Centralization TX - Starting procedure\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_DQS_S("DDR3 - DQS Centralization TX - SW Override Enabled\n");
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Centralization TX - CS - ",
+ (u32) cs, 1);
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Enabled\n");
+ else
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - ECC Mux Disabled\n");
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Find all limits\n");
+
+ status = ddr3_find_adll_limits(dram_info, cs,
+ ecc, 1);
+ if (MV_OK != status)
+ return status;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Centralization TX - Start calculating center\n");
+
+ status = ddr3_center_calc(dram_info, cs, ecc,
+ 1);
+ if (MV_OK != status)
+ return status;
+ }
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_find_adll_limits
+ * Desc: Execute the Find ADLL limits phase.
+ * Args: dram_info
+ * cs
+ * ecc_ena
+ * is_tx Indicate whether Rx or Tx
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_find_adll_limits(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc, int is_tx)
+{
+ u32 victim_dq, pup, tmp;
+ u32 adll_addr;
+ u32 max_pup; /* maximal pup index */
+ u32 pup_mask = 0;
+ u32 unlock_pup; /* bit array of un locked pups */
+ u32 new_unlock_pup; /* bit array of compare failed pups */
+ u32 curr_adll;
+ u32 adll_start_val; /* adll start loop value - for rx or tx limit */
+ u32 high_limit; /* holds found High Limit */
+ u32 low_limit; /* holds found Low Limit */
+ int win_valid;
+ int update_win;
+ u32 sdram_offset;
+ u32 uj, cs_count, cs_tmp, ii;
+ u32 *pattern_ptr;
+ u32 dq;
+ u32 adll_end_val; /* adll end of loop val - for rx or tx limit */
+ u8 analog_pbs[DQ_NUM][MAX_PUP_NUM][DQ_NUM][2];
+ u8 analog_pbs_sum[MAX_PUP_NUM][DQ_NUM][2];
+ int pup_adll_limit_state[MAX_PUP_NUM]; /* hold state of each pup */
+
+ adll_addr = ((is_tx == 1) ? PUP_DQS_WR : PUP_DQS_RD);
+ adll_end_val = ((is_tx == 1) ? ADLL_MIN : ADLL_MAX);
+ adll_start_val = ((is_tx == 1) ? ADLL_MAX : ADLL_MIN);
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - Starting Find ADLL Limits\n");
+
+ /* init the array */
+ for (pup = 0; pup < max_pup; pup++) {
+ centralization_low_limit[pup] = ADLL_MIN;
+ centralization_high_limit[pup] = ADLL_MAX;
+ }
+
+ /* Killer Pattern */
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+ sdram_offset = cs_count * (SDRAM_CS_SIZE + 1);
+ sdram_offset += ((is_tx == 1) ?
+ SDRAM_DQS_TX_OFFS : SDRAM_DQS_RX_OFFS);
+
+ /* Prepare pup masks */
+ for (pup = 0; pup < max_pup; pup++)
+ pup_mask |= (1 << pup);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ analog_pbs_sum[pup][dq][0] = adll_start_val;
+ analog_pbs_sum[pup][dq][1] = adll_end_val;
+ }
+ }
+
+ /* Loop - use different pattern for each victim_dq */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Victim DQ - ",
+ (u32)victim_dq, 1);
+ /*
+ * The pups 3 bit arrays represent state machine. with
+ * 3 stages for each pup.
+ * 1. fail and didn't get pass in earlier compares.
+ * 2. pass compare
+ * 3. fail after pass - end state.
+ * The window limits are the adll values where the adll
+ * was in the pass stage.
+ */
+
+ /* Set all states to Fail (1st state) */
+ for (pup = 0; pup < max_pup; pup++)
+ pup_adll_limit_state[pup] = PUP_ADLL_LIMITS_STATE_FAIL;
+
+ /* Set current valid pups */
+ unlock_pup = pup_mask;
+
+ /* Set ADLL to start value */
+ curr_adll = adll_start_val;
+
+#if defined(MV88F78X60)
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ analog_pbs[victim_dq][pup][dq][0] =
+ adll_start_val;
+ analog_pbs[victim_dq][pup][dq][1] =
+ adll_end_val;
+ per_bit_data[pup][dq] = 0;
+ }
+ }
+#endif
+
+ for (uj = 0; uj < ADLL_MAX; uj++) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Setting ADLL to ",
+ curr_adll, 2);
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ tmp = ((is_tx == 1) ? curr_adll +
+ dram_info->wl_val[cs]
+ [pup * (1 - ecc) + ecc * ECC_PUP]
+ [D] : curr_adll);
+ ddr3_write_pup_reg(adll_addr, cs, pup +
+ (ecc * ECC_PUP), 0, tmp);
+ }
+ }
+
+ /* Choose pattern */
+ pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+ victim_dq);
+
+ /* '1' - means pup failed, '0' - means pup pass */
+ new_unlock_pup = 0;
+
+ /* Read and compare results for Victim_DQ# */
+ for (ii = 0; ii < 3; ii++) {
+ u32 tmp = 0;
+ if (MV_OK != ddr3_sdram_dqs_compare(dram_info,
+ unlock_pup, &tmp,
+ pattern_ptr,
+ LEN_KILLER_PATTERN,
+ sdram_offset +
+ LEN_KILLER_PATTERN *
+ 4 * victim_dq,
+ is_tx, 0, NULL,
+ 0))
+ return MV_DDR3_TRAINING_ERR_DRAM_COMPARE;
+
+ new_unlock_pup |= tmp;
+ }
+
+ pup = 0;
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - UnlockPup: ",
+ unlock_pup, 2);
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - NewUnlockPup: ",
+ new_unlock_pup, 2);
+
+ /* Update pup state */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 0) {
+ DEBUG_DQS_FULL_C("DDR3 - DQS Find Limits - Skipping pup ",
+ pup, 1);
+ continue;
+ }
+
+ /*
+ * Still didn't find the window limit of the pup
+ */
+ if (IS_PUP_ACTIVE(new_unlock_pup, pup) == 1) {
+ /* Current compare result == fail */
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_PASS) {
+ /*
+ * If now it failed but passed
+ * earlier
+ */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - PASS to FAIL: CS - ");
+ DEBUG_DQS_D(cs, 1);
+ DEBUG_DQS_S(", DQ - ");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", Pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(", ADLL - ");
+ DEBUG_DQS_D(curr_adll, 2);
+ DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if ((analog_pbs[victim_dq][pup][dq][0] != adll_start_val)
+ && (analog_pbs[victim_dq][pup]
+ [dq][1] == adll_end_val))
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [1] =
+ curr_adll;
+ }
+#endif
+ win_valid = 1;
+ update_win = 0;
+
+ /* Keep min / max limit value */
+ if (is_tx == 0) {
+ /* RX - found upper limit */
+ if (centralization_high_limit[pup] >
+ (curr_adll - 1)) {
+ high_limit =
+ curr_adll - 1;
+ low_limit =
+ centralization_low_limit[pup];
+ update_win = 1;
+ }
+ } else {
+ /* TX - found lower limit */
+ if (centralization_low_limit[pup] < (curr_adll + 1)) {
+ high_limit =
+ centralization_high_limit
+ [pup];
+ low_limit =
+ curr_adll + 1;
+ update_win =
+ 1;
+ }
+ }
+
+ if (update_win == 1) {
+ /*
+ * Before updating
+ * window limits we need
+ * to check that the
+ * limits are valid
+ */
+ if (MV_OK !=
+ ddr3_check_window_limits
+ (pup, high_limit,
+ low_limit, is_tx,
+ &win_valid))
+ return MV_DDR3_TRAINING_ERR_WIN_LIMITS;
+
+ if (win_valid == 1) {
+ /*
+ * Window limits
+ * should be
+ * updated
+ */
+ centralization_low_limit
+ [pup] =
+ low_limit;
+ centralization_high_limit
+ [pup] =
+ high_limit;
+ }
+ }
+
+ if (win_valid == 1) {
+ /* Found end of window - lock the pup */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_FAIL_AFTER_PASS;
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Probably false pass - reset status */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_FAIL;
+
+#if defined(MV88F78X60)
+ /* Clear logging array of win size (per Dq) */
+ for (dq = 0;
+ dq < DQ_NUM;
+ dq++) {
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [0] =
+ adll_start_val;
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [1] =
+ adll_end_val;
+ per_bit_data
+ [pup][dq]
+ = 0;
+ }
+#endif
+ }
+ }
+ } else {
+ /* Current compare result == pass */
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_FAIL) {
+ /* If now it passed but failed earlier */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - FAIL to PASS: CS - ");
+ DEBUG_DQS_D(cs, 1);
+ DEBUG_DQS_S(", DQ - ");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", Pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(", ADLL - ");
+ DEBUG_DQS_D(curr_adll, 2);
+ DEBUG_DQS_S("\n");
+
+#if defined(MV88F78X60)
+ for (dq = 0; dq < DQ_NUM;
+ dq++) {
+ if (analog_pbs[victim_dq][pup][dq][0] == adll_start_val)
+ analog_pbs
+ [victim_dq]
+ [pup][dq]
+ [0] =
+ curr_adll;
+ }
+#endif
+ /* Found start of window */
+ pup_adll_limit_state[pup] =
+ PUP_ADLL_LIMITS_STATE_PASS;
+
+ /* Keep min / max limit value */
+ if (is_tx == 0) {
+ /* RX - found low limit */
+ if (centralization_low_limit[pup] <= curr_adll)
+ centralization_low_limit
+ [pup] =
+ curr_adll;
+ } else {
+ /* TX - found high limit */
+ if (centralization_high_limit[pup] >= curr_adll)
+ centralization_high_limit
+ [pup] =
+ curr_adll;
+ }
+ }
+ }
+ }
+
+ if (unlock_pup == 0) {
+ /* Found limit to all pups */
+ DEBUG_DQS_FULL_S("DDR3 - DQS Find Limits - found PUP limit\n");
+ break;
+ }
+
+ /*
+ * Increment / decrement (Move to right / left
+ * one phase - ADLL) dqs RX / TX delay (for all un
+ * lock pups
+ */
+ if (is_tx == 0)
+ curr_adll++;
+ else
+ curr_adll--;
+ }
+
+ if (unlock_pup != 0) {
+ /*
+ * Found pups that didn't reach to the end of the
+ * state machine
+ */
+ DEBUG_DQS_C("DDR3 - DQS Find Limits - Pups that didn't reached end of the state machine: ",
+ unlock_pup, 1);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ if (pup_adll_limit_state[pup] ==
+ PUP_ADLL_LIMITS_STATE_FAIL) {
+ /* ERROR - found fail for all window size */
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - Got FAIL for the complete range on pup - ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_C(" victim DQ ",
+ victim_dq, 1);
+
+ /* For debug - set min limit to illegal limit */
+ centralization_low_limit[pup]
+ = ADLL_ERROR;
+ /*
+ * In case the pup is in mode
+ * PASS - the limit is the min
+ * / max adll, no need to
+ * update because of the results
+ * array default value
+ */
+ return MV_DDR3_TRAINING_ERR_PUP_RANGE;
+ }
+ }
+ }
+ }
+ }
+
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - DQ values per victim results:\n");
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ for (pup = 0; pup < max_pup; pup++) {
+ DEBUG_DQS_S("Victim DQ-");
+ DEBUG_DQS_D(victim_dq, 1);
+ DEBUG_DQS_S(", PUP-");
+ DEBUG_DQS_D(pup, 1);
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S(",S-");
+ DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+ [0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs[victim_dq][pup][dq]
+ [1], 2);
+
+ if (is_tx == 0) {
+ if (analog_pbs[victim_dq][pup][dq][0]
+ > analog_pbs_sum[pup][dq][0])
+ analog_pbs_sum[pup][dq][0] =
+ analog_pbs[victim_dq][pup]
+ [dq][0];
+ if (analog_pbs[victim_dq][pup][dq][1]
+ < analog_pbs_sum[pup][dq][1])
+ analog_pbs_sum[pup][dq][1] =
+ analog_pbs[victim_dq][pup]
+ [dq][1];
+ } else {
+ if (analog_pbs[victim_dq][pup][dq][0]
+ < analog_pbs_sum[pup][dq][0])
+ analog_pbs_sum[pup][dq][0] =
+ analog_pbs[victim_dq][pup]
+ [dq][0];
+ if (analog_pbs[victim_dq][pup][dq][1]
+ > analog_pbs_sum[pup][dq][1])
+ analog_pbs_sum[pup][dq][1] =
+ analog_pbs[victim_dq][pup]
+ [dq][1];
+ }
+ }
+ DEBUG_DQS_S("\n");
+ }
+ }
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_3) {
+ u32 dq;
+
+ DEBUG_PER_DQ_S("\n########## LOG LEVEL 3(Windows margins per-DQ) ##########\n");
+ if (is_tx) {
+ DEBUG_PER_DQ_C("DDR3 - TX CS: ", cs, 1);
+ } else {
+ DEBUG_PER_DQ_C("DDR3 - RX CS: ", cs, 1);
+ }
+
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("\n DATA RESULTS:\n");
+ } else {
+ DEBUG_PER_DQ_S("\n ECC RESULTS:\n");
+ }
+
+ /* Since all dq has the same value we take 0 as representive */
+ dq = 0;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("\nBYTE:");
+ DEBUG_PER_DQ_D(pup, 1);
+ DEBUG_PER_DQ_S("\n");
+ } else {
+ DEBUG_PER_DQ_S("\nECC BYTE:\n");
+ }
+ DEBUG_PER_DQ_S(" DQ's LOW HIGH WIN-SIZE\n");
+ DEBUG_PER_DQ_S("============================================\n");
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ if (ecc == 0) {
+ DEBUG_PER_DQ_S("DQ[");
+ DEBUG_PER_DQ_DD((victim_dq +
+ DQ_NUM * pup), 2);
+ DEBUG_PER_DQ_S("]");
+ } else {
+ DEBUG_PER_DQ_S("CB[");
+ DEBUG_PER_DQ_DD(victim_dq, 2);
+ DEBUG_PER_DQ_S("]");
+ }
+ if (is_tx) {
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1], 2); /* low value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2); /* high value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0] - analog_pbs[victim_dq][pup][dq][1], 2); /* win-size */
+ } else {
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][0], 2); /* low value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D((analog_pbs[victim_dq][pup][dq][1] - 1), 2); /* high value */
+ DEBUG_PER_DQ_S(" 0x");
+ DEBUG_PER_DQ_D(analog_pbs[victim_dq][pup][dq][1] - analog_pbs[victim_dq][pup][dq][0], 2); /* win-size */
+ }
+ DEBUG_PER_DQ_S("\n");
+ }
+ }
+ DEBUG_PER_DQ_S("\n");
+ }
+
+ if (is_tx) {
+ DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ DEBUG_DQS_S("PUP-");
+ DEBUG_DQS_D(pup, 1);
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S(",S-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+ }
+ DEBUG_DQS_S("\n");
+ }
+
+ if (is_tx) {
+ DEBUG_DQS_S("DDR3 - DQS TX - Find Limits - DQ values Summary:\n");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS RX - Find Limits - DQ values Summary:\n");
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (max_pup == 1) {
+ /* For ECC PUP */
+ DEBUG_DQS_S("DDR3 - DQS8");
+ } else {
+ DEBUG_DQS_S("DDR3 - DQS");
+ DEBUG_DQS_D(pup, 1);
+ }
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ DEBUG_DQS_S(", DQ-");
+ DEBUG_DQS_D(dq, 1);
+ DEBUG_DQS_S("::S-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][0], 2);
+ DEBUG_DQS_S(",E-");
+ DEBUG_DQS_D(analog_pbs_sum[pup][dq][1], 2);
+ }
+ DEBUG_DQS_S("\n");
+ }
+
+ DEBUG_DQS_S("DDR3 - DQS Find Limits - Ended\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_check_window_limits
+ * Desc: Check window High & Low limits.
+ * Args: pup pup index
+ * high_limit window high limit
+ * low_limit window low limit
+ * is_tx Indicate whether Rx or Tx
+ * size_valid Indicate whether window size is valid
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_check_window_limits(u32 pup, int high_limit, int low_limit, int is_tx,
+ int *size_valid)
+{
+ DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Starting\n");
+
+ if (low_limit > high_limit) {
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(" Low Limit grater than High Limit\n");
+ *size_valid = 0;
+ return MV_OK;
+ }
+
+ /*
+ * Check that window size is valid, if not it was probably false pass
+ * before
+ */
+ if ((high_limit - low_limit) < MIN_WIN_SIZE) {
+ /*
+ * Since window size is too small probably there was false
+ * pass
+ */
+ *size_valid = 0;
+
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S(" Window size is smaller than MIN_WIN_SIZE\n");
+
+ } else if ((high_limit - low_limit) > ADLL_MAX) {
+ *size_valid = 0;
+
+ DEBUG_DQS_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_D(pup, 1);
+ DEBUG_DQS_S
+ (" Window size is bigger than max ADLL taps (31) Exiting.\n");
+
+ return MV_FAIL;
+
+ } else {
+ *size_valid = 1;
+
+ DEBUG_DQS_FULL_S("DDR3 - DQS Check Win Limits - Pup ");
+ DEBUG_DQS_FULL_D(pup, 1);
+ DEBUG_DQS_FULL_C(" window size is ", (high_limit - low_limit),
+ 2);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_center_calc
+ * Desc: Execute the calculate the center of windows phase.
+ * Args: pDram Info
+ * is_tx Indicate whether Rx or Tx
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_center_calc(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx)
+{
+ /* bit array of pups that need specail search */
+ u32 special_pattern_i_pup = 0;
+ u32 special_pattern_ii_pup = 0;
+ u32 pup;
+ u32 max_pup;
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ if (is_tx == 0) {
+ /* Check special pattern I */
+ /*
+ * Special pattern Low limit search - relevant only
+ * for Rx, win size < threshold and low limit = 0
+ */
+ if (((centralization_high_limit[pup] -
+ centralization_low_limit[pup]) < VALID_WIN_THRS)
+ && (centralization_low_limit[pup] == MIN_DELAY))
+ special_pattern_i_pup |= (1 << pup);
+
+ /* Check special pattern II */
+ /*
+ * Special pattern High limit search - relevant only
+ * for Rx, win size < threshold and high limit = 31
+ */
+ if (((centralization_high_limit[pup] -
+ centralization_low_limit[pup]) < VALID_WIN_THRS)
+ && (centralization_high_limit[pup] == MAX_DELAY))
+ special_pattern_ii_pup |= (1 << pup);
+ }
+ }
+
+ /* Run special pattern Low limit search - for relevant pup */
+ if (special_pattern_i_pup != 0) {
+ DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern I for Low limit search\n");
+ if (MV_OK !=
+ ddr3_special_pattern_i_search(dram_info, cs, ecc, is_tx,
+ special_pattern_i_pup))
+ return MV_DDR3_TRAINING_ERR_DQS_LOW_LIMIT_SEARCH;
+ }
+
+ /* Run special pattern High limit search - for relevant pup */
+ if (special_pattern_ii_pup != 0) {
+ DEBUG_DQS_S("DDR3 - DQS Center Calc - Entering special pattern II for High limit search\n");
+ if (MV_OK !=
+ ddr3_special_pattern_ii_search(dram_info, cs, ecc, is_tx,
+ special_pattern_ii_pup))
+ return MV_DDR3_TRAINING_ERR_DQS_HIGH_LIMIT_SEARCH;
+ }
+
+ /* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+ return ddr3_set_dqs_centralization_results(dram_info, cs, ecc, is_tx);
+}
+
+/*
+ * Name: ddr3_special_pattern_i_search
+ * Desc: Execute special pattern low limit search.
+ * Args:
+ * special_pattern_pup The pups that need the special search
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_i_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup)
+{
+ u32 victim_dq; /* loop index - victim DQ */
+ u32 adll_idx;
+ u32 pup;
+ u32 unlock_pup; /* bit array of the unlock pups */
+ u32 first_fail; /* bit array - of pups that get first fail */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 pass_pup; /* bit array of compare pass pup */
+ u32 sdram_offset;
+ u32 max_pup;
+ u32 comp_val;
+ u32 special_res[MAX_PUP_NUM]; /* hold tmp results */
+
+ DEBUG_DQS_S("DDR3 - DQS - Special Pattern I Search - Starting\n");
+
+ max_pup = ecc + (1 - ecc) * dram_info->num_of_std_pups;
+
+ /* Init the temporary results to max ADLL value */
+ for (pup = 0; pup < max_pup; pup++)
+ special_res[pup] = ADLL_MAX;
+
+ /* Run special pattern for all DQ - use the same pattern */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ unlock_pup = special_pattern_pup;
+ first_fail = 0;
+
+ sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS +
+ LEN_KILLER_PATTERN * 4 * victim_dq;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Set adll value per PUP. adll = high limit per pup */
+ if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+ /* only for pups that need special search */
+ ddr3_write_pup_reg(PUP_DQS_RD, cs,
+ pup + (ecc * ECC_PUP), 0,
+ centralization_high_limit
+ [pup]);
+ }
+ }
+
+ adll_idx = 0;
+ do {
+ /*
+ * Perform read and compare simultaneously for all
+ * un-locked MC use the special pattern mask
+ */
+ new_lockup_pup = 0;
+
+ if (MV_OK !=
+ ddr3_sdram_dqs_compare(dram_info, unlock_pup,
+ &new_lockup_pup,
+ special_pattern
+ [victim_dq],
+ LEN_SPECIAL_PATTERN,
+ sdram_offset, 0,
+ 0, NULL, 1))
+ return MV_FAIL;
+
+ DEBUG_DQS_S("DDR3 - DQS - Special I - ADLL value is: ");
+ DEBUG_DQS_D(adll_idx, 2);
+ DEBUG_DQS_S(", UnlockPup: ");
+ DEBUG_DQS_D(unlock_pup, 2);
+ DEBUG_DQS_S(", NewLockPup: ");
+ DEBUG_DQS_D(new_lockup_pup, 2);
+ DEBUG_DQS_S("\n");
+
+ if (unlock_pup != new_lockup_pup)
+ DEBUG_DQS_S("DDR3 - DQS - Special I - Some Pup passed!\n");
+
+ /* Search for pups with passed compare & already fail */
+ pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+ first_fail |= new_lockup_pup;
+ unlock_pup &= ~pass_pup;
+
+ /* Get pass pups */
+ if (pass_pup != 0) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) ==
+ 1) {
+ /* If pup passed and has first fail = 1 */
+ /* keep min value of ADLL max value - current adll */
+ /* (centralization_high_limit[pup] + adll_idx) = current adll !!! */
+ comp_val =
+ (ADLL_MAX -
+ (centralization_high_limit
+ [pup] + adll_idx));
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special I - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" comp_val = ",
+ comp_val, 2);
+
+ if (comp_val <
+ special_res[pup]) {
+ special_res[pup] =
+ comp_val;
+ centralization_low_limit
+ [pup] =
+ (-1) *
+ comp_val;
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special I - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" Changed Low limit to ",
+ centralization_low_limit
+ [pup], 2);
+ }
+ }
+ }
+ }
+
+ /*
+ * Did all PUP found missing window?
+ * Check for each pup if adll (different for each pup)
+ * reach maximum if reach max value - lock the pup
+ * if not - increment (Move to right one phase - ADLL)
+ * dqs RX delay
+ */
+ adll_idx++;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ /* Check only unlocked pups */
+ if ((centralization_high_limit[pup] +
+ adll_idx) >= ADLL_MAX) {
+ /* reach maximum - lock the pup */
+ DEBUG_DQS_C("DDR3 - DQS - Special I - reach maximum - lock pup ",
+ pup, 1);
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Didn't reach maximum - increment ADLL */
+ ddr3_write_pup_reg(PUP_DQS_RD,
+ cs,
+ pup +
+ (ecc *
+ ECC_PUP), 0,
+ (centralization_high_limit
+ [pup] +
+ adll_idx));
+ }
+ }
+ }
+ } while (unlock_pup != 0);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_special_pattern_ii_search
+ * Desc: Execute special pattern high limit search.
+ * Args:
+ * special_pattern_pup The pups that need the special search
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_special_pattern_ii_search(MV_DRAM_INFO *dram_info, u32 cs, u32 ecc,
+ int is_tx, u32 special_pattern_pup)
+{
+ u32 victim_dq; /* loop index - victim DQ */
+ u32 adll_idx;
+ u32 pup;
+ u32 unlock_pup; /* bit array of the unlock pups */
+ u32 first_fail; /* bit array - of pups that get first fail */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 pass_pup; /* bit array of compare pass pup */
+ u32 sdram_offset;
+ u32 max_pup;
+ u32 comp_val;
+ u32 special_res[MAX_PUP_NUM]; /* hold tmp results */
+
+ DEBUG_DQS_S("DDR3 - DQS - Special Pattern II Search - Starting\n");
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ /* init the tmporary results to max ADLL value */
+ for (pup = 0; pup < max_pup; pup++)
+ special_res[pup] = ADLL_MAX;
+
+ sdram_offset = cs * SDRAM_CS_SIZE + SDRAM_DQS_RX_OFFS;
+
+ /* run special pattern for all DQ - use the same pattern */
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ unlock_pup = special_pattern_pup;
+ first_fail = 0;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Set adll value per PUP. adll = 0 */
+ if (IS_PUP_ACTIVE(unlock_pup, pup)) {
+ /* Only for pups that need special search */
+ ddr3_write_pup_reg(PUP_DQS_RD, cs,
+ pup + (ecc * ECC_PUP), 0,
+ ADLL_MIN);
+ }
+ }
+
+ adll_idx = 0;
+ do {
+ /*
+ * Perform read and compare simultaneously for all
+ * un-locked MC use the special pattern mask
+ */
+ new_lockup_pup = 0;
+
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, unlock_pup, &new_lockup_pup,
+ special_pattern[victim_dq],
+ LEN_SPECIAL_PATTERN,
+ sdram_offset, 0, 0, NULL, 0))
+ return MV_FAIL;
+
+ DEBUG_DQS_S("DDR3 - DQS - Special II - ADLL value is ");
+ DEBUG_DQS_D(adll_idx, 2);
+ DEBUG_DQS_S("unlock_pup ");
+ DEBUG_DQS_D(unlock_pup, 1);
+ DEBUG_DQS_S("new_lockup_pup ");
+ DEBUG_DQS_D(new_lockup_pup, 1);
+ DEBUG_DQS_S("\n");
+
+ if (unlock_pup != new_lockup_pup) {
+ DEBUG_DQS_S("DDR3 - DQS - Special II - Some Pup passed!\n");
+ }
+
+ /* Search for pups with passed compare & already fail */
+ pass_pup = first_fail & ~new_lockup_pup & unlock_pup;
+ first_fail |= new_lockup_pup;
+ unlock_pup &= ~pass_pup;
+
+ /* Get pass pups */
+ if (pass_pup != 0) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) ==
+ 1) {
+ /* If pup passed and has first fail = 1 */
+ /* keep min value of ADLL max value - current adll */
+ /* (adll_idx) = current adll !!! */
+ comp_val = adll_idx;
+
+ DEBUG_DQS_C("DDR3 - DQS - Special II - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C(" comp_val = ",
+ comp_val, 1);
+
+ if (comp_val <
+ special_res[pup]) {
+ special_res[pup] =
+ comp_val;
+ centralization_high_limit
+ [pup] =
+ ADLL_MAX +
+ comp_val;
+
+ DEBUG_DQS_C
+ ("DDR3 - DQS - Special II - Pup - ",
+ pup, 1);
+ DEBUG_DQS_C
+ (" Changed High limit to ",
+ centralization_high_limit
+ [pup], 2);
+ }
+ }
+ }
+ }
+
+ /*
+ * Did all PUP found missing window?
+ * Check for each pup if adll (different for each pup)
+ * reach maximum if reach max value - lock the pup
+ * if not - increment (Move to right one phase - ADLL)
+ * dqs RX delay
+ */
+ adll_idx++;
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ /* Check only unlocked pups */
+ if ((adll_idx) >= ADLL_MAX) {
+ /* Reach maximum - lock the pup */
+ DEBUG_DQS_C("DDR3 - DQS - Special II - reach maximum - lock pup ",
+ pup, 1);
+ unlock_pup &= ~(1 << pup);
+ } else {
+ /* Didn't reach maximum - increment ADLL */
+ ddr3_write_pup_reg(PUP_DQS_RD,
+ cs,
+ pup +
+ (ecc *
+ ECC_PUP), 0,
+ (adll_idx));
+ }
+ }
+ }
+ } while (unlock_pup != 0);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_set_dqs_centralization_results
+ * Desc: Set to HW the DQS centralization phase results.
+ * Args:
+ * is_tx Indicates whether to set Tx or RX results
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_set_dqs_centralization_results(MV_DRAM_INFO *dram_info, u32 cs,
+ u32 ecc, int is_tx)
+{
+ u32 pup, pup_num;
+ int addl_val;
+ u32 max_pup;
+
+ max_pup = (ecc + (1 - ecc) * dram_info->num_of_std_pups);
+
+ DEBUG_DQS_RESULTS_S("\n############ LOG LEVEL 2(Windows margins) ############\n");;
+
+ if (is_tx) {
+ DEBUG_DQS_RESULTS_C("DDR3 - DQS TX - Set Dqs Centralization Results - CS: ",
+ cs, 1);
+ } else {
+ DEBUG_DQS_RESULTS_C("DDR3 - DQS RX - Set Dqs Centralization Results - CS: ",
+ cs, 1);
+ }
+
+ /* Set adll to center = (General_High_limit + General_Low_limit)/2 */
+ DEBUG_DQS_RESULTS_S("\nDQS LOW HIGH WIN-SIZE Set\n");
+ DEBUG_DQS_RESULTS_S("==============================================\n");
+ for (pup = 0; pup < max_pup; pup++) {
+ addl_val = (centralization_high_limit[pup] +
+ centralization_low_limit[pup]) / 2;
+
+ pup_num = pup * (1 - ecc) + ecc * ECC_PUP;
+
+ DEBUG_DQS_RESULTS_D(pup_num, 1);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_low_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_high_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(centralization_high_limit[pup] -
+ centralization_low_limit[pup], 2);
+ DEBUG_DQS_RESULTS_S(" 0x");
+ DEBUG_DQS_RESULTS_D(addl_val, 2);
+ DEBUG_DQS_RESULTS_S("\n");
+
+ if (addl_val < ADLL_MIN) {
+ addl_val = ADLL_MIN;
+ DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MIN (since it was lower than 0)\n");
+ }
+
+ if (addl_val > ADLL_MAX) {
+ addl_val = ADLL_MAX;
+ DEBUG_DQS_RESULTS_S("DDR3 - DQS - Setting ADLL value for Pup to MAX (since it was higher than 31)\n");
+ }
+
+ if (is_tx) {
+ ddr3_write_pup_reg(PUP_DQS_WR, cs, pup_num, 0,
+ addl_val +
+ dram_info->wl_val[cs][pup_num][D]);
+ } else {
+ ddr3_write_pup_reg(PUP_DQS_RD, cs, pup_num, 0,
+ addl_val);
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, cs_count, cs_tmp, victim_dq;
+ u32 sdram_addr;
+ u32 *pattern_ptr;
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+
+ /* Init killer pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_DQS_RX_OFFS);
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ pattern_ptr = ddr3_dqs_choose_pattern(dram_info,
+ victim_dq);
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, (u32)NULL, NULL,
+ pattern_ptr, LEN_KILLER_PATTERN,
+ sdram_addr + LEN_KILLER_PATTERN *
+ 4 * victim_dq, 1, 0, NULL,
+ 0))
+ return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+ }
+
+ /* Init special-killer pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_DQS_RX_SPECIAL_OFFS);
+ for (victim_dq = 0; victim_dq < DQ_NUM; victim_dq++) {
+ if (MV_OK != ddr3_sdram_dqs_compare(
+ dram_info, (u32)NULL, NULL,
+ special_pattern[victim_dq],
+ LEN_KILLER_PATTERN, sdram_addr +
+ LEN_KILLER_PATTERN * 4 * victim_dq,
+ 1, 0, NULL, 0))
+ return MV_DDR3_TRAINING_ERR_DQS_PATTERN;
+ }
+ }
+ }
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/mvebu/ddr3_hw_training.c b/drivers/ddr/mvebu/ddr3_hw_training.c
new file mode 100644
index 0000000..a8c5e6a
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_hw_training.c
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+#include "ddr3_hw_training.h"
+#include "xor.h"
+
+#ifdef MV88F78X60
+#include "ddr3_patterns_64bit.h"
+#else
+#include "ddr3_patterns_16bit.h"
+#if defined(MV88F672X)
+#include "ddr3_patterns_16bit.h"
+#endif
+#endif
+
+/*
+ * Debug
+ */
+
+#define DEBUG_MAIN_C(s, d, l) \
+ DEBUG_MAIN_S(s); DEBUG_MAIN_D(d, l); DEBUG_MAIN_S("\n")
+#define DEBUG_MAIN_FULL_C(s, d, l) \
+ DEBUG_MAIN_FULL_S(s); DEBUG_MAIN_FULL_D(d, l); DEBUG_MAIN_FULL_S("\n")
+
+#ifdef MV_DEBUG_MAIN
+#define DEBUG_MAIN_S(s) puts(s)
+#define DEBUG_MAIN_D(d, l) printf("%x", d)
+#else
+#define DEBUG_MAIN_S(s)
+#define DEBUG_MAIN_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_MAIN_FULL
+#define DEBUG_MAIN_FULL_S(s) puts(s)
+#define DEBUG_MAIN_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_MAIN_FULL_S(s)
+#define DEBUG_MAIN_FULL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_SUSPEND_RESUME
+#define DEBUG_SUSPEND_RESUME_S(s) puts(s)
+#define DEBUG_SUSPEND_RESUME_D(d, l) printf("%x", d)
+#else
+#define DEBUG_SUSPEND_RESUME_S(s)
+#define DEBUG_SUSPEND_RESUME_D(d, l)
+#endif
+
+static u32 ddr3_sw_wl_rl_debug;
+static u32 ddr3_run_pbs = 1;
+
+void ddr3_print_version(void)
+{
+ puts("DDR3 Training Sequence - Ver 5.7.");
+}
+
+void ddr3_set_sw_wl_rl_debug(u32 val)
+{
+ ddr3_sw_wl_rl_debug = val;
+}
+
+void ddr3_set_pbs(u32 val)
+{
+ ddr3_run_pbs = val;
+}
+
+int ddr3_hw_training(u32 target_freq, u32 ddr_width, int xor_bypass,
+ u32 scrub_offs, u32 scrub_size, int dqs_clk_aligned,
+ int debug_mode, int reg_dimm_skip_wl)
+{
+ /* A370 has no PBS mechanism */
+ __maybe_unused u32 first_loop_flag = 0;
+ u32 freq, reg;
+ MV_DRAM_INFO dram_info;
+ int ratio_2to1 = 0;
+ int tmp_ratio = 1;
+ int status;
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 1\n");
+
+ memset(&dram_info, 0, sizeof(dram_info));
+ dram_info.num_cs = ddr3_get_cs_num_from_reg();
+ dram_info.cs_ena = ddr3_get_cs_ena_from_reg();
+ dram_info.target_frequency = target_freq;
+ dram_info.ddr_width = ddr_width;
+ dram_info.num_of_std_pups = ddr_width / PUP_SIZE;
+ dram_info.rl400_bug = 0;
+ dram_info.multi_cs_mr_support = 0;
+#ifdef MV88F67XX
+ dram_info.rl400_bug = 1;
+#endif
+
+ /* Ignore ECC errors - if ECC is enabled */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if (reg & (1 << REG_SDRAM_CONFIG_ECC_OFFS)) {
+ dram_info.ecc_ena = 1;
+ reg |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+ } else {
+ dram_info.ecc_ena = 0;
+ }
+
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if (reg & (1 << REG_SDRAM_CONFIG_REGDIMM_OFFS))
+ dram_info.reg_dimm = 1;
+ else
+ dram_info.reg_dimm = 0;
+
+ dram_info.num_of_total_pups = ddr_width / PUP_SIZE + dram_info.ecc_ena;
+
+ /* Get target 2T value */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ dram_info.mode_2t = (reg >> REG_DUNIT_CTRL_LOW_2T_OFFS) &
+ REG_DUNIT_CTRL_LOW_2T_MASK;
+
+ /* Get target CL value */
+#ifdef MV88F67XX
+ reg = reg_read(REG_DDR3_MR0_ADDR) >> 2;
+#else
+ reg = reg_read(REG_DDR3_MR0_CS_ADDR) >> 2;
+#endif
+
+ reg = (((reg >> 1) & 0xE) | (reg & 0x1)) & 0xF;
+ dram_info.cl = ddr3_valid_cl_to_cl(reg);
+
+ /* Get target CWL value */
+#ifdef MV88F67XX
+ reg = reg_read(REG_DDR3_MR2_ADDR) >> REG_DDR3_MR2_CWL_OFFS;
+#else
+ reg = reg_read(REG_DDR3_MR2_CS_ADDR) >> REG_DDR3_MR2_CWL_OFFS;
+#endif
+
+ reg &= REG_DDR3_MR2_CWL_MASK;
+ dram_info.cwl = reg;
+#if !defined(MV88F67XX)
+ /* A370 has no PBS mechanism */
+#if defined(MV88F78X60)
+ if ((dram_info.target_frequency > DDR_400) && (ddr3_run_pbs))
+ first_loop_flag = 1;
+#else
+ /* first_loop_flag = 1; skip mid freq at ALP/A375 */
+ if ((dram_info.target_frequency > DDR_400) && (ddr3_run_pbs) &&
+ (mv_ctrl_revision_get() >= UMC_A0))
+ first_loop_flag = 1;
+ else
+ first_loop_flag = 0;
+#endif
+#endif
+
+ freq = dram_info.target_frequency;
+
+ /* Set ODT to always on */
+ ddr3_odt_activate(1);
+
+ /* Init XOR */
+ mv_sys_xor_init(&dram_info);
+
+ /* Get DRAM/HCLK ratio */
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ ratio_2to1 = 1;
+
+ /*
+ * Xor Bypass - ECC support in AXP is currently available for 1:1
+ * modes frequency modes.
+ * Not all frequency modes support the ddr3 training sequence
+ * (Only 1200/300).
+ * Xor Bypass allows using the Xor initializations and scrubbing
+ * inside the ddr3 training sequence without running the training
+ * itself.
+ */
+ if (xor_bypass == 0) {
+ if (ddr3_run_pbs) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - Run with PBS.\n");
+ } else {
+ DEBUG_MAIN_S("DDR3 Training Sequence - Run without PBS.\n");
+ }
+
+ if (dram_info.target_frequency > DFS_MARGIN) {
+ tmp_ratio = 0;
+ freq = DDR_100;
+
+ if (dram_info.reg_dimm == 1)
+ freq = DDR_300;
+
+ if (MV_OK != ddr3_dfs_high_2_low(freq, &dram_info)) {
+ /* Set low - 100Mhz DDR Frequency by HW */
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs High2Low)\n");
+ return MV_DDR3_TRAINING_ERR_DFS_H2L;
+ }
+
+ if ((dram_info.reg_dimm == 1) &&
+ (reg_dimm_skip_wl == 0)) {
+ if (MV_OK !=
+ ddr3_write_leveling_hw_reg_dimm(freq,
+ &dram_info))
+ DEBUG_MAIN_S("DDR3 Training Sequence - Registered DIMM Low WL - SKIP\n");
+ }
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_1)
+ ddr3_print_freq(freq);
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 2\n");
+ } else {
+ if (!dqs_clk_aligned) {
+#ifdef MV88F67XX
+ /*
+ * If running training sequence without DFS,
+ * we must run Write leveling before writing
+ * the patterns
+ */
+
+ /*
+ * ODT - Multi CS system use SW WL,
+ * Single CS System use HW WL
+ */
+ if (dram_info.cs_ena > 1) {
+ if (MV_OK !=
+ ddr3_write_leveling_sw(
+ freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ if (MV_OK !=
+ ddr3_write_leveling_hw(freq,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+#else
+ if (MV_OK != ddr3_write_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ if (ddr3_sw_wl_rl_debug) {
+ if (MV_OK !=
+ ddr3_write_leveling_sw(
+ freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+#endif
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 3\n");
+ }
+
+ if (MV_OK != ddr3_load_patterns(&dram_info, 0)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Loading Patterns)\n");
+ return MV_DDR3_TRAINING_ERR_LOAD_PATTERNS;
+ }
+
+ /*
+ * TODO:
+ * The mainline U-Boot port of the bin_hdr DDR training code
+ * needs a delay of minimum 20ms here (10ms is a bit too short
+ * and the CPU hangs). The bin_hdr code doesn't have this delay.
+ * To be save here, lets add a delay of 50ms here.
+ *
+ * Tested on the Marvell DB-MV784MP-GP board
+ */
+ mdelay(50);
+
+ do {
+ freq = dram_info.target_frequency;
+ tmp_ratio = ratio_2to1;
+ DEBUG_MAIN_FULL_S("DDR3 Training Sequence - DEBUG - 4\n");
+
+#if defined(MV88F78X60)
+ /*
+ * There is a difference on the DFS frequency at the
+ * first iteration of this loop
+ */
+ if (first_loop_flag) {
+ freq = DDR_400;
+ tmp_ratio = 0;
+ }
+#endif
+
+ if (MV_OK != ddr3_dfs_low_2_high(freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs Low2High)\n");
+ return MV_DDR3_TRAINING_ERR_DFS_H2L;
+ }
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_1) {
+ ddr3_print_freq(freq);
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 5\n");
+
+ /* Write leveling */
+ if (!dqs_clk_aligned) {
+#ifdef MV88F67XX
+ /*
+ * ODT - Multi CS system that not support Multi
+ * CS MRS commands must use SW WL
+ */
+ if (dram_info.cs_ena > 1) {
+ if (MV_OK != ddr3_write_leveling_sw(
+ freq, tmp_ratio, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ if (MV_OK != ddr3_write_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+#else
+ if ((dram_info.reg_dimm == 1) &&
+ (freq == DDR_400)) {
+ if (reg_dimm_skip_wl == 0) {
+ if (MV_OK != ddr3_write_leveling_hw_reg_dimm(
+ freq, &dram_info))
+ DEBUG_MAIN_S("DDR3 Training Sequence - Registered DIMM WL - SKIP\n");
+ }
+ } else {
+ if (MV_OK != ddr3_write_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ if (ddr3_sw_wl_rl_debug) {
+ if (MV_OK != ddr3_write_leveling_sw(
+ freq, tmp_ratio, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+ }
+#endif
+ if (debug_mode)
+ DEBUG_MAIN_S
+ ("DDR3 Training Sequence - DEBUG - 6\n");
+ }
+
+ /* Read Leveling */
+ /*
+ * Armada 370 - Support for HCLK @ 400MHZ - must use
+ * SW read leveling
+ */
+ if (freq == DDR_400 && dram_info.rl400_bug) {
+ status = ddr3_read_leveling_sw(freq, tmp_ratio,
+ &dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S
+ ("DDR3 Training Sequence - FAILED (Read Leveling Sw)\n");
+ return status;
+ }
+ } else {
+ if (MV_OK != ddr3_read_leveling_hw(
+ freq, &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Hw)\n");
+ if (ddr3_sw_wl_rl_debug) {
+ if (MV_OK != ddr3_read_leveling_sw(
+ freq, tmp_ratio,
+ &dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Sw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_SW;
+ }
+ } else {
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 7\n");
+
+ if (MV_OK != ddr3_wl_supplement(&dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hi-Freq Sup)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HI_FREQ;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 8\n");
+#if !defined(MV88F67XX)
+ /* A370 has no PBS mechanism */
+#if defined(MV88F78X60) || defined(MV88F672X)
+ if (first_loop_flag == 1) {
+ first_loop_flag = 0;
+
+ status = MV_OK;
+ status = ddr3_pbs_rx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (PBS RX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 9\n");
+
+ status = ddr3_pbs_tx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (PBS TX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 10\n");
+ }
+#endif
+#endif
+ } while (freq != dram_info.target_frequency);
+
+ status = ddr3_dqs_centralization_rx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (DQS Centralization RX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 11\n");
+
+ status = ddr3_dqs_centralization_tx(&dram_info);
+ if (MV_OK != status) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (DQS Centralization TX)\n");
+ return status;
+ }
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 12\n");
+ }
+
+ ddr3_set_performance_params(&dram_info);
+
+ if (dram_info.ecc_ena) {
+ /* Need to SCRUB the DRAM memory area to load U-boot */
+ mv_sys_xor_finish();
+ dram_info.num_cs = 1;
+ dram_info.cs_ena = 1;
+ mv_sys_xor_init(&dram_info);
+ mv_xor_mem_init(0, scrub_offs, scrub_size, 0xdeadbeef,
+ 0xdeadbeef);
+
+ /* Wait for previous transfer completion */
+ while (mv_xor_state_get(0) != MV_IDLE)
+ ;
+
+ if (debug_mode)
+ DEBUG_MAIN_S("DDR3 Training Sequence - DEBUG - 13\n");
+ }
+
+ /* Return XOR State */
+ mv_sys_xor_finish();
+
+#if defined(MV88F78X60)
+ /* Save training results in memeory for resume state */
+ ddr3_save_training(&dram_info);
+#endif
+ /* Clear ODT always on */
+ ddr3_odt_activate(0);
+
+ /* Configure Dynamic read ODT */
+ ddr3_odt_read_dynamic_config(&dram_info);
+
+ return MV_OK;
+}
+
+void ddr3_set_performance_params(MV_DRAM_INFO *dram_info)
+{
+ u32 twr2wr, trd2rd, trd2wr_wr2rd;
+ u32 tmp1, tmp2, reg;
+
+ DEBUG_MAIN_FULL_C("Max WL Phase: ", dram_info->wl_max_phase, 2);
+ DEBUG_MAIN_FULL_C("Min WL Phase: ", dram_info->wl_min_phase, 2);
+ DEBUG_MAIN_FULL_C("Max RL Phase: ", dram_info->rl_max_phase, 2);
+ DEBUG_MAIN_FULL_C("Min RL Phase: ", dram_info->rl_min_phase, 2);
+
+ if (dram_info->wl_max_phase < 2)
+ twr2wr = 0x2;
+ else
+ twr2wr = 0x3;
+
+ trd2rd = 0x1 + (dram_info->rl_max_phase + 1) / 2 +
+ (dram_info->rl_max_phase + 1) % 2;
+
+ tmp1 = (dram_info->rl_max_phase - dram_info->wl_min_phase) / 2 +
+ (((dram_info->rl_max_phase - dram_info->wl_min_phase) % 2) >
+ 0 ? 1 : 0);
+ tmp2 = (dram_info->wl_max_phase - dram_info->rl_min_phase) / 2 +
+ ((dram_info->wl_max_phase - dram_info->rl_min_phase) % 2 >
+ 0 ? 1 : 0);
+ trd2wr_wr2rd = (tmp1 >= tmp2) ? tmp1 : tmp2;
+
+ trd2wr_wr2rd += 2;
+ trd2rd += 2;
+ twr2wr += 2;
+
+ DEBUG_MAIN_FULL_C("WR 2 WR: ", twr2wr, 2);
+ DEBUG_MAIN_FULL_C("RD 2 RD: ", trd2rd, 2);
+ DEBUG_MAIN_FULL_C("RD 2 WR / WR 2 RD: ", trd2wr_wr2rd, 2);
+
+ reg = reg_read(REG_SDRAM_TIMING_HIGH_ADDR);
+
+ reg &= ~(REG_SDRAM_TIMING_H_W2W_MASK << REG_SDRAM_TIMING_H_W2W_OFFS);
+ reg |= ((twr2wr & REG_SDRAM_TIMING_H_W2W_MASK) <<
+ REG_SDRAM_TIMING_H_W2W_OFFS);
+
+ reg &= ~(REG_SDRAM_TIMING_H_R2R_MASK << REG_SDRAM_TIMING_H_R2R_OFFS);
+ reg &= ~(REG_SDRAM_TIMING_H_R2R_H_MASK <<
+ REG_SDRAM_TIMING_H_R2R_H_OFFS);
+ reg |= ((trd2rd & REG_SDRAM_TIMING_H_R2R_MASK) <<
+ REG_SDRAM_TIMING_H_R2R_OFFS);
+ reg |= (((trd2rd >> 2) & REG_SDRAM_TIMING_H_R2R_H_MASK) <<
+ REG_SDRAM_TIMING_H_R2R_H_OFFS);
+
+ reg &= ~(REG_SDRAM_TIMING_H_R2W_W2R_MASK <<
+ REG_SDRAM_TIMING_H_R2W_W2R_OFFS);
+ reg &= ~(REG_SDRAM_TIMING_H_R2W_W2R_H_MASK <<
+ REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS);
+ reg |= ((trd2wr_wr2rd & REG_SDRAM_TIMING_H_R2W_W2R_MASK) <<
+ REG_SDRAM_TIMING_H_R2W_W2R_OFFS);
+ reg |= (((trd2wr_wr2rd >> 2) & REG_SDRAM_TIMING_H_R2W_W2R_H_MASK) <<
+ REG_SDRAM_TIMING_H_R2W_W2R_H_OFFS);
+
+ reg_write(REG_SDRAM_TIMING_HIGH_ADDR, reg);
+}
+
+/*
+ * Perform DDR3 PUP Indirect Write
+ */
+void ddr3_write_pup_reg(u32 mode, u32 cs, u32 pup, u32 phase, u32 delay)
+{
+ u32 reg = 0;
+
+ if (pup == PUP_BC)
+ reg |= (1 << REG_PHY_BC_OFFS);
+ else
+ reg |= (pup << REG_PHY_PUP_OFFS);
+
+ reg |= ((0x4 * cs + mode) << REG_PHY_CS_OFFS);
+ reg |= (phase << REG_PHY_PHASE_OFFS) | delay;
+
+ if (mode == PUP_WL_MODE)
+ reg |= ((INIT_WL_DELAY + delay) << REG_PHY_DQS_REF_DLY_OFFS);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+
+ /* If read Leveling mode - need to write to register 3 separetly */
+ if (mode == PUP_RL_MODE) {
+ reg = 0;
+
+ if (pup == PUP_BC)
+ reg |= (1 << REG_PHY_BC_OFFS);
+ else
+ reg |= (pup << REG_PHY_PUP_OFFS);
+
+ reg |= ((0x4 * cs + mode + 1) << REG_PHY_CS_OFFS);
+ reg |= (INIT_RL_DELAY);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg);
+ }
+}
+
+/*
+ * Perform DDR3 PUP Indirect Read
+ */
+u32 ddr3_read_pup_reg(u32 mode, u32 cs, u32 pup)
+{
+ u32 reg;
+
+ reg = (pup << REG_PHY_PUP_OFFS) |
+ ((0x4 * cs + mode) << REG_PHY_CS_OFFS);
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_RD;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+
+ return reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR); /* 0x16A0 */
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_patterns(MV_DRAM_INFO *dram_info, int resume)
+{
+ u32 reg;
+
+ /* Enable SW override - Required for the ECC Pup */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ if (resume == 0) {
+#if defined(MV88F78X60) || defined(MV88F672X)
+ ddr3_load_pbs_patterns(dram_info);
+#endif
+ ddr3_load_dqs_patterns(dram_info);
+ }
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ /* Set Base Addr */
+#if defined(MV88F67XX)
+ reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR, 0);
+#else
+ if (resume == 0)
+ reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR, 0);
+ else
+ reg_write(REG_DRAM_TRAINING_PATTERN_BASE_ADDR,
+ RESUME_RL_PATTERNS_ADDR);
+#endif
+
+ /* Set Patterns */
+ if (resume == 0) {
+ reg = (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS) |
+ (1 << REG_DRAM_TRAINING_PATTERNS_OFFS);
+ } else {
+ reg = (0x1 << REG_DRAM_TRAINING_CS_OFFS) |
+ (1 << REG_DRAM_TRAINING_PATTERNS_OFFS);
+ }
+
+ reg |= (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ udelay(100);
+
+ /* Check if Successful */
+ if (reg_read(REG_DRAM_TRAINING_ADDR) &
+ (1 << REG_DRAM_TRAINING_ERROR_OFFS))
+ return MV_OK;
+ else
+ return MV_FAIL;
+}
+
+#if !defined(MV88F67XX)
+/*
+ * Name: ddr3_save_training(MV_DRAM_INFO *dram_info)
+ * Desc: saves the training results to memeory (RL,WL,PBS,Rx/Tx
+ * Centeralization)
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_save_training(MV_DRAM_INFO *dram_info)
+{
+ u32 val, pup, tmp_cs, cs, i, dq;
+ u32 crc = 0;
+ u32 regs = 0;
+ u32 *sdram_offset = (u32 *)RESUME_TRAINING_VALUES_ADDR;
+ u32 mode_config[MAX_TRAINING_MODE];
+
+ mode_config[DQS_WR_MODE] = PUP_DQS_WR;
+ mode_config[WL_MODE_] = PUP_WL_MODE;
+ mode_config[RL_MODE_] = PUP_RL_MODE;
+ mode_config[DQS_RD_MODE] = PUP_DQS_RD;
+ mode_config[PBS_TX_DM_MODE] = PUP_PBS_TX_DM;
+ mode_config[PBS_TX_MODE] = PUP_PBS_TX;
+ mode_config[PBS_RX_MODE] = PUP_PBS_RX;
+
+ /* num of training modes */
+ for (i = 0; i < MAX_TRAINING_MODE; i++) {
+ tmp_cs = dram_info->cs_ena;
+ /* num of CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (tmp_cs & (1 << cs)) {
+ /* num of PUPs */
+ for (pup = 0; pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups &&
+ dram_info->ecc_ena)
+ pup = ECC_PUP;
+ if (i == PBS_TX_DM_MODE) {
+ /*
+ * Change CS bitmask because
+ * PBS works only with CS0
+ */
+ tmp_cs = 0x1;
+ val = ddr3_read_pup_reg(
+ mode_config[i], CS0, pup);
+ } else if (i == PBS_TX_MODE ||
+ i == PBS_RX_MODE) {
+ /*
+ * Change CS bitmask because
+ * PBS works only with CS0
+ */
+ tmp_cs = 0x1;
+ for (dq = 0; dq <= DQ_NUM;
+ dq++) {
+ val = ddr3_read_pup_reg(
+ mode_config[i] + dq,
+ CS0,
+ pup);
+ (*sdram_offset) = val;
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ }
+ continue;
+ } else {
+ val = ddr3_read_pup_reg(
+ mode_config[i], cs, pup);
+ }
+
+ *sdram_offset = val;
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ }
+ }
+ }
+ }
+
+ *sdram_offset = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ *sdram_offset = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ crc += *sdram_offset;
+ sdram_offset++;
+ regs++;
+ sdram_offset = (u32 *)NUM_OF_REGISTER_ADDR;
+ *sdram_offset = regs;
+ DEBUG_SUSPEND_RESUME_S("Training Results CheckSum write= ");
+ DEBUG_SUSPEND_RESUME_D(crc, 8);
+ DEBUG_SUSPEND_RESUME_S("\n");
+ sdram_offset = (u32 *)CHECKSUM_RESULT_ADDR;
+ *sdram_offset = crc;
+}
+
+/*
+ * Name: ddr3_read_training_results()
+ * Desc: Reads the training results from memeory (RL,WL,PBS,Rx/Tx
+ * Centeralization)
+ * and writes them to the relevant registers
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: None.
+ */
+int ddr3_read_training_results(void)
+{
+ u32 val, reg, idx, dqs_wr_idx = 0, crc = 0;
+ u32 *sdram_offset = (u32 *)RESUME_TRAINING_VALUES_ADDR;
+ u32 training_val[RESUME_TRAINING_VALUES_MAX] = { 0 };
+ u32 regs = *((u32 *)NUM_OF_REGISTER_ADDR);
+
+ /*
+ * Read Training results & Dunit registers from memory and write
+ * it to an array
+ */
+ for (idx = 0; idx < regs; idx++) {
+ training_val[idx] = *sdram_offset;
+ crc += *sdram_offset;
+ sdram_offset++;
+ }
+
+ sdram_offset = (u32 *)CHECKSUM_RESULT_ADDR;
+
+ if ((*sdram_offset) == crc) {
+ DEBUG_SUSPEND_RESUME_S("Training Results CheckSum read PASS= ");
+ DEBUG_SUSPEND_RESUME_D(crc, 8);
+ DEBUG_SUSPEND_RESUME_S("\n");
+ } else {
+ DEBUG_MAIN_S("Wrong Training Results CheckSum\n");
+ return MV_FAIL;
+ }
+
+ /*
+ * We iterate through all the registers except for the last 2 since
+ * they are Dunit registers (and not PHY registers)
+ */
+ for (idx = 0; idx < (regs - 2); idx++) {
+ val = training_val[idx];
+ reg = (val >> REG_PHY_CS_OFFS) & 0x3F; /*read the phy address */
+
+ /* Check if the values belongs to the DQS WR */
+ if (reg == PUP_WL_MODE) {
+ /* bit[5:0] in DQS_WR are delay */
+ val = (training_val[dqs_wr_idx++] & 0x3F);
+ /*
+ * bit[15:10] are DQS_WR delay & bit[9:0] are
+ * WL phase & delay
+ */
+ val = (val << REG_PHY_DQS_REF_DLY_OFFS) |
+ (training_val[idx] & 0x3C003FF);
+ /* Add Request pending and write operation bits */
+ val |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ } else if (reg == PUP_DQS_WR) {
+ /*
+ * Do nothing since DQS_WR will be done in PUP_WL_MODE
+ */
+ continue;
+ }
+
+ val |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, val);
+ do {
+ val = (reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR)) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (val); /* Wait for '0' to mark the end of the transaction */
+ }
+
+ /* write last 2 Dunit configurations */
+ val = training_val[idx];
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, val); /* reg 0x1538 */
+ val = training_val[idx + 1];
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, val); /* reg 0x153c */
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_check_if_resume_mode()
+ * Desc: Reads the address (0x3000) of the Resume Magic word (0xDEADB002)
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: return (magic_word == SUSPEND_MAGIC_WORD)
+ */
+int ddr3_check_if_resume_mode(MV_DRAM_INFO *dram_info, u32 freq)
+{
+ u32 magic_word;
+ u32 *sdram_offset = (u32 *)BOOT_INFO_ADDR;
+
+ if (dram_info->reg_dimm != 1) {
+ /*
+ * Perform write levleling in order initiate the phy with
+ * low frequency
+ */
+ if (MV_OK != ddr3_write_leveling_hw(freq, dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Write Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+ }
+
+ if (MV_OK != ddr3_load_patterns(dram_info, 1)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Loading Patterns)\n");
+ return MV_DDR3_TRAINING_ERR_LOAD_PATTERNS;
+ }
+
+ /* Enable CS0 only for RL */
+ dram_info->cs_ena = 0x1;
+
+ /* Perform Read levleling in order to get stable memory */
+ if (MV_OK != ddr3_read_leveling_hw(freq, dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Read Leveling Hw)\n");
+ return MV_DDR3_TRAINING_ERR_WR_LVL_HW;
+ }
+
+ /* Back to relevant CS */
+ dram_info->cs_ena = ddr3_get_cs_ena_from_reg();
+
+ magic_word = *sdram_offset;
+ return magic_word == SUSPEND_MAGIC_WORD;
+}
+
+/*
+ * Name: ddr3_training_suspend_resume()
+ * Desc: Execute the Resume state
+ * Args: MV_DRAM_INFO *dram_info
+ * Notes:
+ * Returns: return (magic_word == SUSPEND_MAGIC_WORD)
+ */
+int ddr3_training_suspend_resume(MV_DRAM_INFO *dram_info)
+{
+ u32 freq, reg;
+ int tmp_ratio;
+
+ /* Configure DDR */
+ if (MV_OK != ddr3_read_training_results())
+ return MV_FAIL;
+
+ /* Reset read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+
+ /* Start Auto Read Leveling procedure */
+ reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+
+ /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ udelay(2);
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Clear Auto Read Leveling procedure */
+ reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Return to target frequency */
+ freq = dram_info->target_frequency;
+ tmp_ratio = 1;
+ if (MV_OK != ddr3_dfs_low_2_high(freq, tmp_ratio, dram_info)) {
+ DEBUG_MAIN_S("DDR3 Training Sequence - FAILED (Dfs Low2High)\n");
+ return MV_DDR3_TRAINING_ERR_DFS_H2L;
+ }
+
+ if (dram_info->ecc_ena) {
+ /* Scabbling the RL area pattern and the training area */
+ mv_sys_xor_finish();
+ dram_info->num_cs = 1;
+ dram_info->cs_ena = 1;
+ mv_sys_xor_init(dram_info);
+ mv_xor_mem_init(0, RESUME_RL_PATTERNS_ADDR,
+ RESUME_RL_PATTERNS_SIZE, 0xFFFFFFFF, 0xFFFFFFFF);
+
+ /* Wait for previous transfer completion */
+
+ while (mv_xor_state_get(0) != MV_IDLE)
+ ;
+
+ /* Return XOR State */
+ mv_sys_xor_finish();
+ }
+
+ return MV_OK;
+}
+#endif
+
+void ddr3_print_freq(u32 freq)
+{
+ u32 tmp_freq;
+
+ switch (freq) {
+ case 0:
+ tmp_freq = 100;
+ break;
+ case 1:
+ tmp_freq = 300;
+ break;
+ case 2:
+ tmp_freq = 360;
+ break;
+ case 3:
+ tmp_freq = 400;
+ break;
+ case 4:
+ tmp_freq = 444;
+ break;
+ case 5:
+ tmp_freq = 500;
+ break;
+ case 6:
+ tmp_freq = 533;
+ break;
+ case 7:
+ tmp_freq = 600;
+ break;
+ case 8:
+ tmp_freq = 666;
+ break;
+ case 9:
+ tmp_freq = 720;
+ break;
+ case 10:
+ tmp_freq = 800;
+ break;
+ default:
+ tmp_freq = 100;
+ }
+
+ printf("Current frequency is: %dMHz\n", tmp_freq);
+}
+
+int ddr3_get_min_max_read_sample_delay(u32 cs_enable, u32 reg, u32 *min,
+ u32 *max, u32 *cs_max)
+{
+ u32 cs, delay;
+
+ *min = 0xFFFFFFFF;
+ *max = 0x0;
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if ((cs_enable & (1 << cs)) == 0)
+ continue;
+
+ delay = ((reg >> (cs * 8)) & 0x1F);
+
+ if (delay < *min)
+ *min = delay;
+
+ if (delay > *max) {
+ *max = delay;
+ *cs_max = cs;
+ }
+ }
+
+ return MV_OK;
+}
+
+int ddr3_get_min_max_rl_phase(MV_DRAM_INFO *dram_info, u32 *min, u32 *max,
+ u32 cs)
+{
+ u32 pup, reg, phase;
+
+ *min = 0xFFFFFFFF;
+ *max = 0x0;
+
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ reg = ddr3_read_pup_reg(PUP_RL_MODE, cs, pup);
+ phase = ((reg >> 8) & 0x7);
+
+ if (phase < *min)
+ *min = phase;
+
+ if (phase > *max)
+ *max = phase;
+ }
+
+ return MV_OK;
+}
+
+int ddr3_odt_activate(int activate)
+{
+ u32 reg, mask;
+
+ mask = (1 << REG_DUNIT_ODT_CTRL_OVRD_OFFS) |
+ (1 << REG_DUNIT_ODT_CTRL_OVRD_VAL_OFFS);
+ /* {0x0000149C} - DDR Dunit ODT Control Register */
+ reg = reg_read(REG_DUNIT_ODT_CTRL_ADDR);
+ if (activate)
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ reg_write(REG_DUNIT_ODT_CTRL_ADDR, reg);
+
+ return MV_OK;
+}
+
+int ddr3_odt_read_dynamic_config(MV_DRAM_INFO *dram_info)
+{
+ u32 min_read_sample_delay, max_read_sample_delay, max_rl_phase;
+ u32 min, max, cs_max;
+ u32 cs_ena, reg;
+
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ cs_ena = ddr3_get_cs_ena_from_reg();
+
+ /* Get minimum and maximum of read sample delay of all CS */
+ ddr3_get_min_max_read_sample_delay(cs_ena, reg, &min_read_sample_delay,
+ &max_read_sample_delay, &cs_max);
+
+ /*
+ * Get minimum and maximum read leveling phase which belongs to the
+ * maximal read sample delay
+ */
+ ddr3_get_min_max_rl_phase(dram_info, &min, &max, cs_max);
+ max_rl_phase = max;
+
+ /* DDR ODT Timing (Low) Register calculation */
+ reg = reg_read(REG_ODT_TIME_LOW_ADDR);
+ reg &= ~(0x1FF << REG_ODT_ON_CTL_RD_OFFS);
+ reg |= (((min_read_sample_delay - 1) & 0xF) << REG_ODT_ON_CTL_RD_OFFS);
+ reg |= (((max_read_sample_delay + 4 + (((max_rl_phase + 1) / 2) + 1)) &
+ 0x1F) << REG_ODT_OFF_CTL_RD_OFFS);
+ reg_write(REG_ODT_TIME_LOW_ADDR, reg);
+
+ return MV_OK;
+}
diff --git a/drivers/ddr/mvebu/ddr3_hw_training.h b/drivers/ddr/mvebu/ddr3_hw_training.h
new file mode 100644
index 0000000..cffa7c4
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_hw_training.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_TRAINING_H
+#define __DDR3_TRAINING_H
+
+#include "ddr3_init.h"
+
+#ifdef MV88F78X60
+#include "ddr3_axp.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375.h"
+#endif
+
+/* The following is a list of Marvell status */
+#define MV_ERROR (-1)
+#define MV_OK (0x00) /* Operation succeeded */
+#define MV_FAIL (0x01) /* Operation failed */
+#define MV_BAD_VALUE (0x02) /* Illegal value (general) */
+#define MV_OUT_OF_RANGE (0x03) /* The value is out of range */
+#define MV_BAD_PARAM (0x04) /* Illegal parameter in function called */
+#define MV_BAD_PTR (0x05) /* Illegal pointer value */
+#define MV_BAD_SIZE (0x06) /* Illegal size */
+#define MV_BAD_STATE (0x07) /* Illegal state of state machine */
+#define MV_SET_ERROR (0x08) /* Set operation failed */
+#define MV_GET_ERROR (0x09) /* Get operation failed */
+#define MV_CREATE_ERROR (0x0A) /* Fail while creating an item */
+#define MV_NOT_FOUND (0x0B) /* Item not found */
+#define MV_NO_MORE (0x0C) /* No more items found */
+#define MV_NO_SUCH (0x0D) /* No such item */
+#define MV_TIMEOUT (0x0E) /* Time Out */
+#define MV_NO_CHANGE (0x0F) /* Parameter(s) is already in this value */
+#define MV_NOT_SUPPORTED (0x10) /* This request is not support */
+#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented*/
+#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized */
+#define MV_NO_RESOURCE (0x13) /* Resource not available (memory ...) */
+#define MV_FULL (0x14) /* Item is full (Queue or table etc...) */
+#define MV_EMPTY (0x15) /* Item is empty (Queue or table etc...) */
+#define MV_INIT_ERROR (0x16) /* Error occured while INIT process */
+#define MV_HW_ERROR (0x17) /* Hardware error */
+#define MV_TX_ERROR (0x18) /* Transmit operation not succeeded */
+#define MV_RX_ERROR (0x19) /* Recieve operation not succeeded */
+#define MV_NOT_READY (0x1A) /* The other side is not ready yet */
+#define MV_ALREADY_EXIST (0x1B) /* Tried to create existing item */
+#define MV_OUT_OF_CPU_MEM (0x1C) /* Cpu memory allocation failed. */
+#define MV_NOT_STARTED (0x1D) /* Not started yet */
+#define MV_BUSY (0x1E) /* Item is busy. */
+#define MV_TERMINATE (0x1F) /* Item terminates it's work. */
+#define MV_NOT_ALIGNED (0x20) /* Wrong alignment */
+#define MV_NOT_ALLOWED (0x21) /* Operation NOT allowed */
+#define MV_WRITE_PROTECT (0x22) /* Write protected */
+
+#define MV_INVALID (int)(-1)
+
+/*
+ * Debug (Enable/Disable modules) and Error report
+ */
+
+#ifdef BASIC_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS_RESULTS
+#endif
+
+#ifdef FULL_DEBUG
+#define MV_DEBUG_WL
+#define MV_DEBUG_RL
+#define MV_DEBUG_DQS
+
+#define MV_DEBUG_PBS
+#define MV_DEBUG_DFS
+#define MV_DEBUG_MAIN_FULL
+#define MV_DEBUG_DFS_FULL
+#define MV_DEBUG_DQS_FULL
+#define MV_DEBUG_RL_FULL
+#define MV_DEBUG_WL_FULL
+#endif
+
+/*
+ * General Consts
+ */
+
+#define SDRAM_READ_WRITE_LEN_IN_WORDS 16
+#define SDRAM_READ_WRITE_LEN_IN_DOUBLE_WORDS 8
+#define CACHE_LINE_SIZE 0x20
+
+#define SDRAM_CS_BASE 0x0
+
+#define SRAM_BASE 0x40000000
+#define SRAM_SIZE 0xFFF
+
+#define LEN_64BIT_STD_PATTERN 16
+#define LEN_64BIT_KILLER_PATTERN 128
+#define LEN_64BIT_SPECIAL_PATTERN 128
+#define LEN_64BIT_PBS_PATTERN 16
+#define LEN_WL_SUP_PATTERN 32
+
+#define LEN_16BIT_STD_PATTERN 4
+#define LEN_16BIT_KILLER_PATTERN 128
+#define LEN_16BIT_SPECIAL_PATTERN 128
+#define LEN_16BIT_PBS_PATTERN 4
+
+#define CMP_BYTE_SHIFT 8
+#define CMP_BYTE_MASK 0xFF
+#define PUP_SIZE 8
+
+#define S 0
+#define C 1
+#define P 2
+#define D 3
+#define DQS 6
+#define PS 2
+#define DS 3
+#define PE 4
+#define DE 5
+
+#define CS0 0
+#define MAX_DIMM_NUM 2
+#define MAX_DELAY 0x1F
+
+/*
+ * Invertion limit and phase1 limit are WA for the RL @ 1:1 design bug -
+ * Armada 370 & AXP Z1
+ */
+#define MAX_DELAY_INV_LIMIT 0x5
+#define MIN_DELAY_PHASE_1_LIMIT 0x10
+
+#define MAX_DELAY_INV (0x3F - MAX_DELAY_INV_LIMIT)
+#define MIN_DELAY 0
+#define MAX_PUP_NUM 9
+#define ECC_PUP 8
+#define DQ_NUM 8
+#define DQS_DQ_NUM 8
+#define INIT_WL_DELAY 13
+#define INIT_RL_DELAY 15
+#define TWLMRD_DELAY 20
+#define TCLK_3_DELAY 3
+#define ECC_BIT 8
+#define DMA_SIZE 64
+#define MV_DMA_0 0
+#define MAX_TRAINING_RETRY 10
+
+#define PUP_RL_MODE 0x2
+#define PUP_WL_MODE 0
+#define PUP_PBS_TX 0x10
+#define PUP_PBS_TX_DM 0x1A
+#define PUP_PBS_RX 0x30
+#define PUP_DQS_WR 0x1
+#define PUP_DQS_RD 0x3
+#define PUP_BC 10
+#define PUP_DELAY_MASK 0x1F
+#define PUP_PHASE_MASK 0x7
+#define PUP_NUM_64BIT 8
+#define PUP_NUM_32BIT 4
+#define PUP_NUM_16BIT 2
+
+/* control PHY registers */
+#define CNTRL_PUP_DESKEW 0x10
+
+/* WL */
+#define COUNT_WL_HI_FREQ 2
+#define COUNT_WL 2
+#define COUNT_WL_RFRS 9
+#define WL_HI_FREQ_SHIFT 2
+#define WL_HI_FREQ_STATE 1
+#define COUNT_HW_WL 2
+
+/* RL */
+/*
+ * RL_MODE - this define uses the RL mode SW RL instead of the functional
+ * window SW RL
+ */
+#define RL_MODE
+#define RL_WINDOW_WA
+#define MAX_PHASE_1TO1 2
+#define MAX_PHASE_2TO1 4
+
+#define MAX_PHASE_RL_UL_1TO1 0
+#define MAX_PHASE_RL_L_1TO1 4
+#define MAX_PHASE_RL_UL_2TO1 3
+#define MAX_PHASE_RL_L_2TO1 7
+
+#define RL_UNLOCK_STATE 0
+#define RL_WINDOW_STATE 1
+#define RL_FINAL_STATE 2
+#define RL_RETRY_COUNT 2
+#define COUNT_HW_RL 2
+
+/* PBS */
+#define MAX_PBS 31
+#define MIN_PBS 0
+#define COUNT_PBS_PATTERN 2
+#define COUNT_PBS_STARTOVER 2
+#define COUNT_PBS_REPEAT 3
+#define COUNT_PBS_COMP_RETRY_NUM 2
+#define PBS_DIFF_LIMIT 31
+#define PATTERN_PBS_TX_A 0x55555555
+#define PATTERN_PBS_TX_B 0xAAAAAAAA
+
+/* DQS */
+#define ADLL_ERROR 0x55
+#define ADLL_MAX 31
+#define ADLL_MIN 0
+#define MIN_WIN_SIZE 4
+#define VALID_WIN_THRS MIN_WIN_SIZE
+
+#define MODE_2TO1 1
+#define MODE_1TO1 0
+
+/*
+ * Macros
+ */
+#define IS_PUP_ACTIVE(_data_, _pup_) (((_data_) >> (_pup_)) & 0x1)
+
+/*
+ * Internal ERROR codes
+ */
+#define MV_DDR3_TRAINING_ERR_WR_LVL_HW 0xDD302001
+#define MV_DDR3_TRAINING_ERR_LOAD_PATTERNS 0xDD302002
+#define MV_DDR3_TRAINING_ERR_WR_LVL_HI_FREQ 0xDD302003
+#define MV_DDR3_TRAINING_ERR_DFS_H2L 0xDD302004
+#define MV_DDR3_TRAINING_ERR_DRAM_COMPARE 0xDD302005
+#define MV_DDR3_TRAINING_ERR_WIN_LIMITS 0xDD302006
+#define MV_DDR3_TRAINING_ERR_PUP_RANGE 0xDD302025
+#define MV_DDR3_TRAINING_ERR_DQS_LOW_LIMIT_SEARCH 0xDD302007
+#define MV_DDR3_TRAINING_ERR_DQS_HIGH_LIMIT_SEARCH 0xDD302008
+#define MV_DDR3_TRAINING_ERR_DQS_PATTERN 0xDD302009
+#define MV_DDR3_TRAINING_ERR_PBS_ADLL_SHR_1PHASE 0xDD302010
+#define MV_DDR3_TRAINING_ERR_PBS_TX_MAX_VAL 0xDD302011
+#define MV_DDR3_TRAINING_ERR_PBS_RX_PER_BIT 0xDD302012
+#define MV_DDR3_TRAINING_ERR_PBS_TX_PER_BIT 0xDD302013
+#define MV_DDR3_TRAINING_ERR_PBS_RX_MAX_VAL 0xDD302014
+#define MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP 0xDD302015
+#define MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_MAX_VAL 0xDD302016
+#define MV_DDR3_TRAINING_ERR_RD_LVL_RL_PATTERN 0xDD302017
+#define MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK 0xDD302018
+#define MV_DDR3_TRAINING_ERR_RD_LVL_PUP_UNLOCK 0xDD302019
+#define MV_DDR3_TRAINING_ERR_WR_LVL_SW 0xDD302020
+#define MV_DDR3_TRAINING_ERR_PRBS_RX 0xDD302021
+#define MV_DDR3_TRAINING_ERR_DQS_RX 0xDD302022
+#define MV_DDR3_TRAINING_ERR_PRBS_TX 0xDD302023
+#define MV_DDR3_TRAINING_ERR_DQS_TX 0xDD302024
+
+/*
+ * DRAM information structure
+ */
+typedef struct dram_info {
+ u32 num_cs;
+ u32 cs_ena;
+ u32 num_of_std_pups; /* Q value = ddrWidth/8 - Without ECC!! */
+ u32 num_of_total_pups; /* numOfStdPups + eccEna */
+ u32 target_frequency; /* DDR Frequency */
+ u32 ddr_width; /* 32/64 Bit or 16/32 Bit */
+ u32 ecc_ena; /* 0/1 */
+ u32 wl_val[MAX_CS][MAX_PUP_NUM][7];
+ u32 rl_val[MAX_CS][MAX_PUP_NUM][7];
+ u32 rl_max_phase;
+ u32 rl_min_phase;
+ u32 wl_max_phase;
+ u32 wl_min_phase;
+ u32 rd_smpl_dly;
+ u32 rd_rdy_dly;
+ u32 cl;
+ u32 cwl;
+ u32 mode_2t;
+ int rl400_bug;
+ int multi_cs_mr_support;
+ int reg_dimm;
+} MV_DRAM_INFO;
+
+enum training_modes {
+ DQS_WR_MODE,
+ WL_MODE_,
+ RL_MODE_,
+ DQS_RD_MODE,
+ PBS_TX_DM_MODE,
+ PBS_TX_MODE,
+ PBS_RX_MODE,
+ MAX_TRAINING_MODE,
+};
+
+typedef struct dram_training_init {
+ u32 reg_addr;
+ u32 reg_value;
+} MV_DRAM_TRAINING_INIT;
+
+typedef struct dram_mv_init {
+ u32 reg_addr;
+ u32 reg_value;
+} MV_DRAM_MC_INIT;
+
+/* Board/Soc revisions define */
+enum board_rev {
+ Z1,
+ Z1_PCAC,
+ Z1_RD_SLED,
+ A0,
+ A0_AMC
+};
+
+typedef struct dram_modes {
+ char *mode_name;
+ u8 cpu_freq;
+ u8 fab_freq;
+ u8 chip_id;
+ int chip_board_rev;
+ MV_DRAM_MC_INIT *regs;
+ MV_DRAM_TRAINING_INIT *vals;
+} MV_DRAM_MODES;
+
+/*
+ * Function Declarations
+ */
+
+u32 cache_inv(u32 addr);
+void flush_l1_v7(u32 line);
+void flush_l1_v6(u32 line);
+
+u32 ddr3_cl_to_valid_cl(u32 cl);
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl);
+
+void ddr3_write_pup_reg(u32 mode, u32 cs, u32 pup, u32 phase, u32 delay);
+u32 ddr3_read_pup_reg(u32 mode, u32 cs, u32 pup);
+
+int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked, int is_tx,
+ u32 pbs_pattern_idx, u32 pbs_curr_val,
+ u32 pbs_lock_val, u32 *skew_array,
+ u8 *unlock_pup_dq_array, u32 ecc);
+
+int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern, int b_special_compare);
+
+int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern, u32 pattern_len,
+ u32 sdram_offset, int write, int mask,
+ u32 *mask_pattern, int b_special_compare);
+
+int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern);
+
+int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 sdram_offset);
+int ddr3_dram_sram_read(u32 src, u32 dst, u32 len);
+int ddr3_load_patterns(MV_DRAM_INFO *dram_info, int resume);
+
+int ddr3_read_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_read_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+
+int ddr3_write_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_write_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+int ddr3_write_leveling_hw_reg_dimm(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_wl_supplement(MV_DRAM_INFO *dram_info);
+
+int ddr3_dfs_high_2_low(u32 freq, MV_DRAM_INFO *dram_info);
+int ddr3_dfs_low_2_high(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info);
+
+int ddr3_pbs_tx(MV_DRAM_INFO *dram_info);
+int ddr3_pbs_rx(MV_DRAM_INFO *dram_info);
+int ddr3_load_pbs_patterns(MV_DRAM_INFO *dram_info);
+
+int ddr3_dqs_centralization_rx(MV_DRAM_INFO *dram_info);
+int ddr3_dqs_centralization_tx(MV_DRAM_INFO *dram_info);
+int ddr3_load_dqs_patterns(MV_DRAM_INFO *dram_info);
+
+void ddr3_static_training_init(void);
+
+u8 ddr3_get_eprom_fabric(void);
+void ddr3_set_performance_params(MV_DRAM_INFO *dram_info);
+int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len);
+void ddr3_save_training(MV_DRAM_INFO *dram_info);
+int ddr3_read_training_results(void);
+int ddr3_training_suspend_resume(MV_DRAM_INFO *dram_info);
+int ddr3_get_min_max_read_sample_delay(u32 cs_enable, u32 reg, u32 *min,
+ u32 *max, u32 *cs_max);
+int ddr3_get_min_max_rl_phase(MV_DRAM_INFO *dram_info, u32 *min, u32 *max,
+ u32 cs);
+int ddr3_odt_activate(int activate);
+int ddr3_odt_read_dynamic_config(MV_DRAM_INFO *dram_info);
+void ddr3_print_freq(u32 freq);
+void ddr3_reset_phy_read_fifo(void);
+
+#endif /* __DDR3_TRAINING_H */
diff --git a/drivers/ddr/mvebu/ddr3_init.c b/drivers/ddr/mvebu/ddr3_init.c
new file mode 100644
index 0000000..11b8591
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_init.c
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#if defined(MV88F78X60)
+#include "ddr3_axp_vars.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370_vars.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375_vars.h"
+#endif
+
+#ifdef STATIC_TRAINING
+static void ddr3_static_training_init(void);
+#endif
+#ifdef DUNIT_STATIC
+static void ddr3_static_mc_init(void);
+#endif
+#if defined(DUNIT_STATIC) || defined(STATIC_TRAINING)
+MV_DRAM_MODES *ddr3_get_static_ddr_mode(void);
+#endif
+#if defined(MV88F672X)
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps);
+#endif
+u32 mv_board_id_get(void);
+extern void ddr3_set_sw_wl_rl_debug(u32);
+extern void ddr3_set_pbs(u32);
+extern void ddr3_set_log_level(u32 val);
+
+static u32 log_level = DDR3_LOG_LEVEL;
+
+static u32 ddr3_init_main(void);
+
+/*
+ * Name: ddr3_set_log_level
+ * Desc: This routine initialize the log_level acording to nLogLevel
+ * which getting from user
+ * Args: nLogLevel
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_set_log_level(u32 val)
+{
+ log_level = val;
+}
+
+/*
+ * Name: ddr3_get_log_level
+ * Desc: This routine returns the log level
+ * Args: none
+ * Notes:
+ * Returns: log level.
+ */
+u32 ddr3_get_log_level(void)
+{
+ return log_level;
+}
+
+static void debug_print_reg(u32 reg)
+{
+ printf("0x%08x = 0x%08x\n", reg, reg_read(reg));
+}
+
+static void print_dunit_setup(void)
+{
+ puts("\n########### LOG LEVEL 1 (D-UNIT SETUP)###########\n");
+
+#ifdef DUNIT_STATIC
+ puts("\nStatic D-UNIT Setup:\n");
+#endif
+#ifdef DUNIT_SPD
+ puts("\nDynamic(using SPD) D-UNIT Setup:\n");
+#endif
+ debug_print_reg(REG_SDRAM_CONFIG_ADDR);
+ debug_print_reg(REG_DUNIT_CTRL_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_TIMING_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_TIMING_HIGH_ADDR);
+ debug_print_reg(REG_SDRAM_ADDRESS_CTRL_ADDR);
+ debug_print_reg(REG_SDRAM_OPEN_PAGES_ADDR);
+ debug_print_reg(REG_SDRAM_OPERATION_ADDR);
+ debug_print_reg(REG_SDRAM_MODE_ADDR);
+ debug_print_reg(REG_SDRAM_EXT_MODE_ADDR);
+ debug_print_reg(REG_DDR_CONT_HIGH_ADDR);
+ debug_print_reg(REG_ODT_TIME_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_ERROR_ADDR);
+ debug_print_reg(REG_SDRAM_AUTO_PWR_SAVE_ADDR);
+ debug_print_reg(REG_OUDDR3_TIMING_ADDR);
+ debug_print_reg(REG_ODT_TIME_HIGH_ADDR);
+ debug_print_reg(REG_SDRAM_ODT_CTRL_LOW_ADDR);
+ debug_print_reg(REG_SDRAM_ODT_CTRL_HIGH_ADDR);
+ debug_print_reg(REG_DUNIT_ODT_CTRL_ADDR);
+#ifndef MV88F67XX
+ debug_print_reg(REG_DRAM_FIFO_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_AXI_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR);
+ debug_print_reg(REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR);
+ debug_print_reg(REG_DRAM_VER_CAL_MACHINE_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_MAIN_PADS_CAL_ADDR);
+ debug_print_reg(REG_DRAM_HOR_CAL_MACHINE_CTRL_ADDR);
+ debug_print_reg(REG_CS_SIZE_SCRATCH_ADDR);
+ debug_print_reg(REG_DYNAMIC_POWER_SAVE_ADDR);
+ debug_print_reg(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ debug_print_reg(REG_READ_DATA_READY_DELAYS_ADDR);
+ debug_print_reg(REG_DDR3_MR0_ADDR);
+ debug_print_reg(REG_DDR3_MR1_ADDR);
+ debug_print_reg(REG_DDR3_MR2_ADDR);
+ debug_print_reg(REG_DDR3_MR3_ADDR);
+ debug_print_reg(REG_DDR3_RANK_CTRL_ADDR);
+ debug_print_reg(REG_DRAM_PHY_CONFIG_ADDR);
+ debug_print_reg(REG_STATIC_DRAM_DLB_CONTROL);
+ debug_print_reg(DLB_BUS_OPTIMIZATION_WEIGHTS_REG);
+ debug_print_reg(DLB_AGING_REGISTER);
+ debug_print_reg(DLB_EVICTION_CONTROL_REG);
+ debug_print_reg(DLB_EVICTION_TIMERS_REGISTER_REG);
+#if defined(MV88F672X)
+ debug_print_reg(REG_FASTPATH_WIN_CTRL_ADDR(0));
+ debug_print_reg(REG_FASTPATH_WIN_BASE_ADDR(0));
+ debug_print_reg(REG_FASTPATH_WIN_CTRL_ADDR(1));
+ debug_print_reg(REG_FASTPATH_WIN_BASE_ADDR(1));
+#else
+ debug_print_reg(REG_FASTPATH_WIN_0_CTRL_ADDR);
+#endif
+ debug_print_reg(REG_CDI_CONFIG_ADDR);
+#endif
+}
+
+#if !defined(STATIC_TRAINING)
+static void ddr3_restore_and_set_final_windows(u32 *win_backup)
+{
+ u32 ui, reg, cs;
+ u32 win_ctrl_reg, num_of_win_regs;
+ u32 cs_ena = ddr3_get_cs_ena_from_reg();
+
+#if defined(MV88F672X)
+ if (DDR3_FAST_PATH_EN == 0)
+ return;
+#endif
+
+#if defined(MV88F672X)
+ win_ctrl_reg = REG_XBAR_WIN_16_CTRL_ADDR;
+ num_of_win_regs = 8;
+#else
+ win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+ num_of_win_regs = 16;
+#endif
+
+ /* Return XBAR windows 4-7 or 16-19 init configuration */
+ for (ui = 0; ui < num_of_win_regs; ui++)
+ reg_write((win_ctrl_reg + 0x4 * ui), win_backup[ui]);
+
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - Switching XBAR Window to FastPath Window\n");
+
+#if defined(MV88F672X)
+ /* Set L2 filtering to 1G */
+ reg_write(0x8c04, 0x40000000);
+
+ /* Open fast path windows */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ /* set fast path window control for the cs */
+ reg = 0x1FFFFFE1;
+ reg |= (cs << 2);
+ reg |= (SDRAM_CS_SIZE & 0xFFFF0000);
+ /* Open fast path Window */
+ reg_write(REG_FASTPATH_WIN_CTRL_ADDR(cs), reg);
+ /* set fast path window base address for the cs */
+ reg = (((SDRAM_CS_SIZE + 1) * cs) & 0xFFFF0000);
+ /* Set base address */
+ reg_write(REG_FASTPATH_WIN_BASE_ADDR(cs), reg);
+ }
+ }
+#else
+ reg = 0x1FFFFFE1;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg |= (cs << 2);
+ break;
+ }
+ }
+
+ /* Open fast path Window to - 0.5G */
+ reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, reg);
+#endif
+}
+
+static void ddr3_save_and_set_training_windows(u32 *win_backup)
+{
+ u32 cs_ena = ddr3_get_cs_ena_from_reg();
+ u32 reg, tmp_count, cs, ui;
+ u32 win_ctrl_reg, win_base_reg, win_remap_reg;
+ u32 num_of_win_regs, win_jump_index;
+
+#if defined(MV88F672X)
+ /* Disable L2 filtering */
+ reg_write(0x8c04, 0);
+
+ win_ctrl_reg = REG_XBAR_WIN_16_CTRL_ADDR;
+ win_base_reg = REG_XBAR_WIN_16_BASE_ADDR;
+ win_remap_reg = REG_XBAR_WIN_16_REMAP_ADDR;
+ win_jump_index = 0x8;
+ num_of_win_regs = 8;
+#else
+ win_ctrl_reg = REG_XBAR_WIN_4_CTRL_ADDR;
+ win_base_reg = REG_XBAR_WIN_4_BASE_ADDR;
+ win_remap_reg = REG_XBAR_WIN_4_REMAP_ADDR;
+ win_jump_index = 0x10;
+ num_of_win_regs = 16;
+#endif
+
+ /* Close XBAR Window 19 - Not needed */
+ /* {0x000200e8} - Open Mbus Window - 2G */
+ reg_write(REG_XBAR_WIN_19_CTRL_ADDR, 0);
+
+ /* Save XBAR Windows 4-19 init configurations */
+ for (ui = 0; ui < num_of_win_regs; ui++)
+ win_backup[ui] = reg_read(win_ctrl_reg + 0x4 * ui);
+
+ /* Open XBAR Windows 4-7 or 16-19 for other CS */
+ reg = 0;
+ tmp_count = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ switch (cs) {
+ case 0:
+ reg = 0x0E00;
+ break;
+ case 1:
+ reg = 0x0D00;
+ break;
+ case 2:
+ reg = 0x0B00;
+ break;
+ case 3:
+ reg = 0x0700;
+ break;
+ }
+ reg |= (1 << 0);
+ reg |= (SDRAM_CS_SIZE & 0xFFFF0000);
+
+ reg_write(win_ctrl_reg + win_jump_index * tmp_count,
+ reg);
+ reg = ((SDRAM_CS_SIZE + 1) * (tmp_count)) & 0xFFFF0000;
+ reg_write(win_base_reg + win_jump_index * tmp_count,
+ reg);
+
+ if (win_remap_reg <= REG_XBAR_WIN_7_REMAP_ADDR) {
+ reg_write(win_remap_reg +
+ win_jump_index * tmp_count, 0);
+ }
+
+ tmp_count++;
+ }
+ }
+}
+#endif /* !defined(STATIC_TRAINING) */
+
+/*
+ * Name: ddr3_init - Main DDR3 Init function
+ * Desc: This routine initialize the DDR3 MC and runs HW training.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+int ddr3_init(void)
+{
+ unsigned int status;
+
+ ddr3_set_pbs(DDR3_PBS);
+ ddr3_set_sw_wl_rl_debug(DDR3_RUN_SW_WHEN_HW_FAIL);
+
+ status = ddr3_init_main();
+ if (status == MV_DDR3_TRAINING_ERR_BAD_SAR)
+ DEBUG_INIT_S("DDR3 Training Error: Bad sample at reset");
+ if (status == MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP)
+ DEBUG_INIT_S("DDR3 Training Error: Bad DIMM setup");
+ if (status == MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT)
+ DEBUG_INIT_S("DDR3 Training Error: Max CS limit");
+ if (status == MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT)
+ DEBUG_INIT_S("DDR3 Training Error: Max enable CS limit");
+ if (status == MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP)
+ DEBUG_INIT_S("DDR3 Training Error: Bad R-DIMM setup");
+ if (status == MV_DDR3_TRAINING_ERR_TWSI_FAIL)
+ DEBUG_INIT_S("DDR3 Training Error: TWSI failure");
+ if (status == MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH)
+ DEBUG_INIT_S("DDR3 Training Error: DIMM type no match");
+ if (status == MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE)
+ DEBUG_INIT_S("DDR3 Training Error: TWSI bad type");
+ if (status == MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH)
+ DEBUG_INIT_S("DDR3 Training Error: bus width no match");
+ if (status > MV_DDR3_TRAINING_ERR_HW_FAIL_BASE)
+ DEBUG_INIT_C("DDR3 Training Error: HW Failure 0x", status, 8);
+
+ return status;
+}
+
+static void print_ddr_target_freq(u32 cpu_freq, u32 fab_opt)
+{
+ puts("\nDDR3 Training Sequence - Run DDR3 at ");
+
+ switch (cpu_freq) {
+#if defined(MV88F672X)
+ case 21:
+ puts("533 Mhz\n");
+ break;
+#else
+ case 1:
+ puts("533 Mhz\n");
+ break;
+ case 2:
+ if (fab_opt == 5)
+ puts("600 Mhz\n");
+ if (fab_opt == 9)
+ puts("400 Mhz\n");
+ break;
+ case 3:
+ puts("667 Mhz\n");
+ break;
+ case 4:
+ if (fab_opt == 5)
+ puts("750 Mhz\n");
+ if (fab_opt == 9)
+ puts("500 Mhz\n");
+ break;
+ case 0xa:
+ puts("400 Mhz\n");
+ break;
+ case 0xb:
+ if (fab_opt == 5)
+ puts("800 Mhz\n");
+ if (fab_opt == 9)
+ puts("553 Mhz\n");
+ if (fab_opt == 0xA)
+ puts("640 Mhz\n");
+ break;
+#endif
+ default:
+ puts("NOT DEFINED FREQ\n");
+ }
+}
+
+static u32 ddr3_init_main(void)
+{
+ u32 target_freq;
+ u32 reg = 0;
+ u32 cpu_freq, fab_opt, hclk_time_ps, soc_num;
+ __maybe_unused u32 ecc = DRAM_ECC;
+ __maybe_unused int dqs_clk_aligned = 0;
+ __maybe_unused u32 scrub_offs, scrub_size;
+ __maybe_unused u32 ddr_width = BUS_WIDTH;
+ __maybe_unused int status;
+ __maybe_unused u32 win_backup[16];
+
+ /* SoC/Board special Initializtions */
+ fab_opt = ddr3_get_fab_opt();
+
+#ifdef CONFIG_SPD_EEPROM
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+
+ ddr3_print_version();
+ DEBUG_INIT_S("4\n");
+ /* Lib version 5.5.4 */
+
+ fab_opt = ddr3_get_fab_opt();
+
+ /* Switching CPU to MRVL ID */
+ soc_num = (reg_read(REG_SAMPLE_RESET_HIGH_ADDR) & SAR1_CPU_CORE_MASK) >>
+ SAR1_CPU_CORE_OFFSET;
+ switch (soc_num) {
+ case 0x3:
+ reg_bit_set(CPU_CONFIGURATION_REG(3), CPU_MRVL_ID_OFFSET);
+ reg_bit_set(CPU_CONFIGURATION_REG(2), CPU_MRVL_ID_OFFSET);
+ case 0x1:
+ reg_bit_set(CPU_CONFIGURATION_REG(1), CPU_MRVL_ID_OFFSET);
+ case 0x0:
+ reg_bit_set(CPU_CONFIGURATION_REG(0), CPU_MRVL_ID_OFFSET);
+ default:
+ break;
+ }
+
+ /* Power down deskew PLL */
+#if !defined(MV88F672X)
+ /* 0x18780 [25] */
+ reg = (reg_read(REG_DDRPHY_APLL_CTRL_ADDR) & ~(1 << 25));
+ reg_write(REG_DDRPHY_APLL_CTRL_ADDR, reg);
+#endif
+
+ /*
+ * Stage 0 - Set board configuration
+ */
+ cpu_freq = ddr3_get_cpu_freq();
+ if (fab_opt > FAB_OPT)
+ fab_opt = FAB_OPT - 1;
+
+ if (ddr3_get_log_level() > 0)
+ print_ddr_target_freq(cpu_freq, fab_opt);
+
+#if defined(MV88F672X)
+ get_target_freq(cpu_freq, &target_freq, &hclk_time_ps);
+#else
+ target_freq = cpu_ddr_ratios[fab_opt][cpu_freq];
+ hclk_time_ps = cpu_fab_clk_to_hclk[fab_opt][cpu_freq];
+#endif
+ if ((target_freq == 0) || (hclk_time_ps == 0)) {
+ DEBUG_INIT_S("DDR3 Training Sequence - FAILED - Wrong Sample at Reset Configurations\n");
+ if (target_freq == 0) {
+ DEBUG_INIT_C("target_freq", target_freq, 2);
+ DEBUG_INIT_C("fab_opt", fab_opt, 2);
+ DEBUG_INIT_C("cpu_freq", cpu_freq, 2);
+ } else if (hclk_time_ps == 0) {
+ DEBUG_INIT_C("hclk_time_ps", hclk_time_ps, 2);
+ DEBUG_INIT_C("fab_opt", fab_opt, 2);
+ DEBUG_INIT_C("cpu_freq", cpu_freq, 2);
+ }
+
+ return MV_DDR3_TRAINING_ERR_BAD_SAR;
+ }
+
+#if defined(ECC_SUPPORT)
+ scrub_offs = U_BOOT_START_ADDR;
+ scrub_size = U_BOOT_SCRUB_SIZE;
+#else
+ scrub_offs = 0;
+ scrub_size = 0;
+#endif
+
+#if defined(ECC_SUPPORT) && defined(AUTO_DETECTION_SUPPORT)
+ ecc = DRAM_ECC;
+#endif
+
+#if defined(ECC_SUPPORT) && defined(AUTO_DETECTION_SUPPORT)
+ ecc = 0;
+ if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_ECC))
+ ecc = 1;
+#endif
+
+#ifdef DQS_CLK_ALIGNED
+ dqs_clk_aligned = 1;
+#endif
+
+ /* Check if DRAM is already initialized */
+ if (reg_read(REG_BOOTROM_ROUTINE_ADDR) &
+ (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) {
+ DEBUG_INIT_S("DDR3 Training Sequence - 2nd boot - Skip\n");
+ return MV_OK;
+ }
+
+ /*
+ * Stage 1 - Dunit Setup
+ */
+
+#ifdef DUNIT_STATIC
+ /*
+ * For Static D-Unit Setup use must set the correct static values
+ * at the ddr3_*soc*_vars.h file
+ */
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - Static MC Init\n");
+ ddr3_static_mc_init();
+
+#ifdef ECC_SUPPORT
+ ecc = DRAM_ECC;
+ if (ecc) {
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ reg |= (1 << REG_SDRAM_CONFIG_ECC_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+ }
+#endif
+#endif
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+#if defined(AUTO_DETECTION_SUPPORT)
+ /*
+ * Configurations for both static and dynamic MC setups
+ *
+ * Dynamically Set 32Bit and ECC for AXP (Relevant only for
+ * Marvell DB boards)
+ */
+ if (ddr3_check_config(BUS_WIDTH_ECC_TWSI_ADDR, CONFIG_BUS_WIDTH)) {
+ ddr_width = 32;
+ DEBUG_INIT_S("DDR3 Training Sequence - DRAM bus width 32Bit\n");
+ }
+#endif
+
+#if defined(MV88F672X)
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if ((reg >> 15) & 1)
+ ddr_width = 32;
+ else
+ ddr_width = 16;
+#endif
+#endif
+
+#ifdef DUNIT_SPD
+ status = ddr3_dunit_setup(ecc, hclk_time_ps, &ddr_width);
+ if (MV_OK != status) {
+ DEBUG_INIT_S("DDR3 Training Sequence - FAILED (ddr3 Dunit Setup)\n");
+ return status;
+ }
+#endif
+
+ /* Fix read ready phases for all SOC in reg 0x15C8 */
+ reg = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK);
+ reg |= 0x4; /* Phase 0 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << REG_TRAINING_DEBUG_3_OFFS);
+ reg |= (0x4 << (1 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 1 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (3 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (3 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 3 */
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (4 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (4 * REG_TRAINING_DEBUG_3_OFFS));
+ reg &= ~(REG_TRAINING_DEBUG_3_MASK << (5 * REG_TRAINING_DEBUG_3_OFFS));
+ reg |= (0x6 << (5 * REG_TRAINING_DEBUG_3_OFFS));
+ reg_write(REG_TRAINING_DEBUG_3_ADDR, reg);
+
+#if defined(MV88F672X)
+ /*
+ * AxiBrespMode[8] = Compliant,
+ * AxiAddrDecodeCntrl[11] = Internal,
+ * AxiDataBusWidth[0] = 128bit
+ */
+ /* 0x14A8 - AXI Control Register */
+ reg_write(REG_DRAM_AXI_CTRL_ADDR, 0);
+#else
+ /* 0x14A8 - AXI Control Register */
+ reg_write(REG_DRAM_AXI_CTRL_ADDR, 0x00000100);
+ reg_write(REG_CDI_CONFIG_ADDR, 0x00000006);
+
+ if ((ddr_width == 64) && (reg_read(REG_DDR_IO_ADDR) &
+ (1 << REG_DDR_IO_CLK_RATIO_OFFS))) {
+ /* 0x14A8 - AXI Control Register */
+ reg_write(REG_DRAM_AXI_CTRL_ADDR, 0x00000101);
+ reg_write(REG_CDI_CONFIG_ADDR, 0x00000007);
+ }
+#endif
+
+#if !defined(MV88F67XX)
+ /*
+ * ARMADA-370 activate DLB later at the u-boot,
+ * Armada38x - No DLB activation at this time
+ */
+ reg_write(DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0x18C01E);
+
+#if defined(MV88F78X60)
+ /* WA according to eratta GL-8672902*/
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV)
+ reg_write(DLB_BUS_OPTIMIZATION_WEIGHTS_REG, 0xc19e);
+#endif
+
+ reg_write(DLB_AGING_REGISTER, 0x0f7f007f);
+ reg_write(DLB_EVICTION_CONTROL_REG, 0x0);
+ reg_write(DLB_EVICTION_TIMERS_REGISTER_REG, 0x00FF3C1F);
+
+ reg_write(MBUS_UNITS_PRIORITY_CONTROL_REG, 0x55555555);
+ reg_write(FABRIC_UNITS_PRIORITY_CONTROL_REG, 0xAA);
+ reg_write(MBUS_UNITS_PREFETCH_CONTROL_REG, 0xffff);
+ reg_write(FABRIC_UNITS_PREFETCH_CONTROL_REG, 0xf0f);
+
+#if defined(MV88F78X60)
+ /* WA according to eratta GL-8672902 */
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV) {
+ reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+ reg |= DLB_ENABLE;
+ reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+ }
+#endif /* end defined(MV88F78X60) */
+#endif /* end !defined(MV88F67XX) */
+
+ if (ddr3_get_log_level() >= MV_LOG_LEVEL_1)
+ print_dunit_setup();
+
+ /*
+ * Stage 2 - Training Values Setup
+ */
+#ifdef STATIC_TRAINING
+ /*
+ * DRAM Init - After all the D-unit values are set, its time to init
+ * the D-unit
+ */
+ /* Wait for '0' */
+ reg_write(REG_SDRAM_INIT_CTRL_ADDR, 0x1);
+ do {
+ reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+ (1 << REG_SDRAM_INIT_CTRL_OFFS);
+ } while (reg);
+
+ /* ddr3 init using static parameters - HW training is disabled */
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - Static Training Parameters\n");
+ ddr3_static_training_init();
+
+#if defined(MV88F78X60)
+ /*
+ * If ECC is enabled, need to scrub the U-Boot area memory region -
+ * Run training function with Xor bypass just to scrub the memory
+ */
+ status = ddr3_hw_training(target_freq, ddr_width,
+ 1, scrub_offs, scrub_size,
+ dqs_clk_aligned, DDR3_TRAINING_DEBUG,
+ REG_DIMM_SKIP_WL);
+ if (MV_OK != status) {
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - FAILED\n");
+ return status;
+ }
+#endif
+#else
+ /* Set X-BAR windows for the training sequence */
+ ddr3_save_and_set_training_windows(win_backup);
+
+ /* Run DDR3 Training Sequence */
+ /* DRAM Init */
+ reg_write(REG_SDRAM_INIT_CTRL_ADDR, 0x1);
+ do {
+ reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+ (1 << REG_SDRAM_INIT_CTRL_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* ddr3 init using DDR3 HW training procedure */
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - HW Training Procedure\n");
+ status = ddr3_hw_training(target_freq, ddr_width,
+ 0, scrub_offs, scrub_size,
+ dqs_clk_aligned, DDR3_TRAINING_DEBUG,
+ REG_DIMM_SKIP_WL);
+ if (MV_OK != status) {
+ DEBUG_INIT_FULL_S("DDR3 Training Sequence - FAILED\n");
+ return status;
+ }
+#endif
+
+ /*
+ * Stage 3 - Finish
+ */
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* Disable ECC Ignore bit */
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR) &
+ ~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+#endif
+
+#if !defined(STATIC_TRAINING)
+ /* Restore and set windows */
+ ddr3_restore_and_set_final_windows(win_backup);
+#endif
+
+ /* Update DRAM init indication in bootROM register */
+ reg = reg_read(REG_BOOTROM_ROUTINE_ADDR);
+ reg_write(REG_BOOTROM_ROUTINE_ADDR,
+ reg | (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS));
+
+#if !defined(MV88F67XX)
+#if defined(MV88F78X60)
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV) {
+ reg = reg_read(REG_SDRAM_CONFIG_ADDR);
+ if (ecc == 0)
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg | (1 << 19));
+ }
+#endif /* end defined(MV88F78X60) */
+
+ reg_write(DLB_EVICTION_CONTROL_REG, 0x9);
+
+ reg = reg_read(REG_STATIC_DRAM_DLB_CONTROL);
+ reg |= (DLB_ENABLE | DLB_WRITE_COALESING | DLB_AXI_PREFETCH_EN |
+ DLB_MBUS_PREFETCH_EN | PREFETCH_NLNSZTR);
+ reg_write(REG_STATIC_DRAM_DLB_CONTROL, reg);
+#endif /* end !defined(MV88F67XX) */
+
+#ifdef STATIC_TRAINING
+ DEBUG_INIT_S("DDR3 Training Sequence - Ended Successfully (S)\n");
+#else
+ DEBUG_INIT_S("DDR3 Training Sequence - Ended Successfully\n");
+#endif
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_get_cpu_freq
+ * Desc: read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+
+u32 ddr3_get_cpu_freq(void)
+{
+ u32 reg, cpu_freq;
+
+#if defined(MV88F672X)
+ /* Read sample at reset setting */
+ reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR); /* 0xE8200 */
+ cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+ REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+#else
+ /* Read sample at reset setting */
+ reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR); /* 0x18230 [23:21] */
+#if defined(MV88F78X60)
+ cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+ REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+ reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR); /* 0x18234 [20] */
+ cpu_freq |= (((reg >> REG_SAMPLE_RESET_HIGH_CPU_FREQ_OFFS) & 0x1) << 3);
+#elif defined(MV88F67XX)
+ cpu_freq = (reg & REG_SAMPLE_RESET_CPU_FREQ_MASK) >>
+ REG_SAMPLE_RESET_CPU_FREQ_OFFS;
+#endif
+#endif
+
+ return cpu_freq;
+}
+
+/*
+ * Name: ddr3_get_fab_opt
+ * Desc: read S@R and return CPU frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_get_fab_opt(void)
+{
+ __maybe_unused u32 reg, fab_opt;
+
+#if defined(MV88F672X)
+ return 0; /* No fabric */
+#else
+ /* Read sample at reset setting */
+ reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR);
+ fab_opt = (reg & REG_SAMPLE_RESET_FAB_MASK) >>
+ REG_SAMPLE_RESET_FAB_OFFS;
+
+#if defined(MV88F78X60)
+ reg = reg_read(REG_SAMPLE_RESET_HIGH_ADDR);
+ fab_opt |= (((reg >> 19) & 0x1) << 4);
+#endif
+
+ return fab_opt;
+#endif
+}
+
+/*
+ * Name: ddr3_get_vco_freq
+ * Desc: read S@R and return VCO frequency
+ * Args:
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_get_vco_freq(void)
+{
+ u32 fab, cpu_freq, ui_vco_freq;
+
+ fab = ddr3_get_fab_opt();
+ cpu_freq = ddr3_get_cpu_freq();
+
+ if (fab == 2 || fab == 3 || fab == 7 || fab == 8 || fab == 10 ||
+ fab == 15 || fab == 17 || fab == 20)
+ ui_vco_freq = cpu_freq + CLK_CPU;
+ else
+ ui_vco_freq = cpu_freq;
+
+ return ui_vco_freq;
+}
+
+#ifdef STATIC_TRAINING
+/*
+ * Name: ddr3_static_training_init - Init DDR3 Training with
+ * static parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_static_training_init(void)
+{
+ MV_DRAM_MODES *ddr_mode;
+ u32 reg;
+ int j;
+
+ ddr_mode = ddr3_get_static_ddr_mode();
+
+ j = 0;
+ while (ddr_mode->vals[j].reg_addr != 0) {
+ udelay(10); /* haim want to delay each write */
+ reg_write(ddr_mode->vals[j].reg_addr,
+ ddr_mode->vals[j].reg_value);
+
+ if (ddr_mode->vals[j].reg_addr ==
+ REG_PHY_REGISTRY_FILE_ACCESS_ADDR)
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg);
+ j++;
+ }
+}
+#endif
+
+/*
+ * Name: ddr3_get_static_mc_value - Init Memory controller with static
+ * parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1, u32 offset2,
+ u32 mask2)
+{
+ u32 reg, tmp;
+
+ reg = reg_read(reg_addr);
+
+ tmp = (reg >> offset1) & mask1;
+ if (mask2)
+ tmp |= (reg >> offset2) & mask2;
+
+ return tmp;
+}
+
+/*
+ * Name: ddr3_get_static_ddr_mode - Init Memory controller with static
+ * parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+__weak MV_DRAM_MODES *ddr3_get_static_ddr_mode(void)
+{
+ u32 chip_board_rev, i;
+ u32 size;
+
+ /* Do not modify this code. relevant only for marvell Boards */
+#if defined(DB_78X60_PCAC)
+ chip_board_rev = Z1_PCAC;
+#elif defined(DB_78X60_AMC)
+ chip_board_rev = A0_AMC;
+#elif defined(DB_88F6710_PCAC)
+ chip_board_rev = A0_PCAC;
+#elif defined(RD_88F6710)
+ chip_board_rev = A0_RD;
+#elif defined(MV88F672X)
+ chip_board_rev = mv_board_id_get();
+#else
+ chip_board_rev = A0;
+#endif
+
+ size = sizeof(ddr_modes) / sizeof(MV_DRAM_MODES);
+ for (i = 0; i < size; i++) {
+ if ((ddr3_get_cpu_freq() == ddr_modes[i].cpu_freq) &&
+ (ddr3_get_fab_opt() == ddr_modes[i].fab_freq) &&
+ (chip_board_rev == ddr_modes[i].chip_board_rev))
+ return &ddr_modes[i];
+ }
+
+ return &ddr_modes[0];
+}
+
+#ifdef DUNIT_STATIC
+/*
+ * Name: ddr3_static_mc_init - Init Memory controller with static parameters
+ * Desc: Use this routine to init the controller without the HW training
+ * procedure
+ * User must provide compatible header file with registers data.
+ * Args: None.
+ * Notes:
+ * Returns: None.
+ */
+void ddr3_static_mc_init(void)
+{
+ MV_DRAM_MODES *ddr_mode;
+ u32 reg;
+ int j;
+
+ ddr_mode = ddr3_get_static_ddr_mode();
+ j = 0;
+ while (ddr_mode->regs[j].reg_addr != 0) {
+ reg_write(ddr_mode->regs[j].reg_addr,
+ ddr_mode->regs[j].reg_value);
+ if (ddr_mode->regs[j].reg_addr ==
+ REG_PHY_REGISTRY_FILE_ACCESS_ADDR)
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg);
+ j++;
+ }
+}
+#endif
+
+/*
+ * Name: ddr3_check_config - Check user configurations: ECC/MultiCS
+ * Desc:
+ * Args: twsi Address
+ * Notes: Only Available for ArmadaXP/Armada 370 DB boards
+ * Returns: None.
+ */
+int ddr3_check_config(u32 twsi_addr, MV_CONFIG_TYPE config_type)
+{
+#ifdef AUTO_DETECTION_SUPPORT
+ u8 data = 0;
+ int ret;
+ int offset;
+
+ if ((config_type == CONFIG_ECC) || (config_type == CONFIG_BUS_WIDTH))
+ offset = 1;
+ else
+ offset = 0;
+
+ ret = i2c_read(twsi_addr, offset, 1, (u8 *)&data, 1);
+ if (!ret) {
+ switch (config_type) {
+ case CONFIG_ECC:
+ if (data & 0x2)
+ return 1;
+ break;
+ case CONFIG_BUS_WIDTH:
+ if (data & 0x1)
+ return 1;
+ break;
+#ifdef DB_88F6710
+ case CONFIG_MULTI_CS:
+ if (CFG_MULTI_CS_MODE(data))
+ return 1;
+ break;
+#else
+ case CONFIG_MULTI_CS:
+ break;
+#endif
+ }
+ }
+#endif
+
+ return 0;
+}
+
+#if defined(DB_88F78X60_REV2)
+/*
+ * Name: ddr3_get_eprom_fabric - Get Fabric configuration from EPROM
+ * Desc:
+ * Args: twsi Address
+ * Notes: Only Available for ArmadaXP DB Rev2 boards
+ * Returns: None.
+ */
+u8 ddr3_get_eprom_fabric(void)
+{
+#ifdef AUTO_DETECTION_SUPPORT
+ u8 data = 0;
+ int ret;
+
+ ret = i2c_read(NEW_FABRIC_TWSI_ADDR, 1, 1, (u8 *)&data, 1);
+ if (!ret)
+ return data & 0x1F;
+#endif
+
+ return 0;
+}
+
+#endif
+
+/*
+ * Name: ddr3_cl_to_valid_cl - this return register matching CL value
+ * Desc:
+ * Args: clValue - the value
+
+ * Notes:
+ * Returns: required CL value
+ */
+u32 ddr3_cl_to_valid_cl(u32 cl)
+{
+ switch (cl) {
+ case 5:
+ return 2;
+ break;
+ case 6:
+ return 4;
+ break;
+ case 7:
+ return 6;
+ break;
+ case 8:
+ return 8;
+ break;
+ case 9:
+ return 10;
+ break;
+ case 10:
+ return 12;
+ break;
+ case 11:
+ return 14;
+ break;
+ case 12:
+ return 1;
+ break;
+ case 13:
+ return 3;
+ break;
+ case 14:
+ return 5;
+ break;
+ default:
+ return 2;
+ }
+}
+
+/*
+ * Name: ddr3_cl_to_valid_cl - this return register matching CL value
+ * Desc:
+ * Args: clValue - the value
+ * Notes:
+ * Returns: required CL value
+ */
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl)
+{
+ switch (ui_valid_cl) {
+ case 1:
+ return 12;
+ break;
+ case 2:
+ return 5;
+ break;
+ case 3:
+ return 13;
+ break;
+ case 4:
+ return 6;
+ break;
+ case 5:
+ return 14;
+ break;
+ case 6:
+ return 7;
+ break;
+ case 8:
+ return 8;
+ break;
+ case 10:
+ return 9;
+ break;
+ case 12:
+ return 10;
+ break;
+ case 14:
+ return 11;
+ break;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Name: ddr3_get_cs_num_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_num_from_reg(void)
+{
+ u32 cs_ena = ddr3_get_cs_ena_from_reg();
+ u32 cs_count = 0;
+ u32 cs;
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs))
+ cs_count++;
+ }
+
+ return cs_count;
+}
+
+/*
+ * Name: ddr3_get_cs_ena_from_reg
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_cs_ena_from_reg(void)
+{
+ return reg_read(REG_DDR3_RANK_CTRL_ADDR) &
+ REG_DDR3_RANK_CTRL_CS_ENA_MASK;
+}
+
+/*
+ * mv_ctrl_rev_get - Get Marvell controller device revision number
+ *
+ * DESCRIPTION:
+ * This function returns 8bit describing the device revision as defined
+ * in PCI Express Class Code and Revision ID Register.
+ *
+ * INPUT:
+ * None.
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * 8bit desscribing Marvell controller revision number
+ *
+ */
+#if !defined(MV88F672X)
+u8 mv_ctrl_rev_get(void)
+{
+ u8 rev_num;
+
+#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
+ /* Check pex power state */
+ u32 pex_power;
+ pex_power = mv_ctrl_pwr_clck_get(PEX_UNIT_ID, 0);
+ if (pex_power == 0)
+ mv_ctrl_pwr_clck_set(PEX_UNIT_ID, 0, 1);
+#endif
+ rev_num = (u8)reg_read(PEX_CFG_DIRECT_ACCESS(0,
+ PCI_CLASS_CODE_AND_REVISION_ID));
+
+#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
+ /* Return to power off state */
+ if (pex_power == 0)
+ mv_ctrl_pwr_clck_set(PEX_UNIT_ID, 0, 0);
+#endif
+
+ return (rev_num & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS;
+}
+
+#endif
+
+#if defined(MV88F672X)
+void get_target_freq(u32 freq_mode, u32 *ddr_freq, u32 *hclk_ps)
+{
+ u32 tmp, hclk;
+
+ switch (freq_mode) {
+ case CPU_333MHz_DDR_167MHz_L2_167MHz:
+ hclk = 84;
+ tmp = DDR_100;
+ break;
+ case CPU_266MHz_DDR_266MHz_L2_133MHz:
+ case CPU_333MHz_DDR_222MHz_L2_167MHz:
+ case CPU_400MHz_DDR_200MHz_L2_200MHz:
+ case CPU_400MHz_DDR_267MHz_L2_200MHz:
+ case CPU_533MHz_DDR_267MHz_L2_267MHz:
+ case CPU_500MHz_DDR_250MHz_L2_250MHz:
+ case CPU_600MHz_DDR_300MHz_L2_300MHz:
+ case CPU_800MHz_DDR_267MHz_L2_400MHz:
+ case CPU_900MHz_DDR_300MHz_L2_450MHz:
+ tmp = DDR_300;
+ hclk = 150;
+ break;
+ case CPU_333MHz_DDR_333MHz_L2_167MHz:
+ case CPU_500MHz_DDR_334MHz_L2_250MHz:
+ case CPU_666MHz_DDR_333MHz_L2_333MHz:
+ tmp = DDR_333;
+ hclk = 165;
+ break;
+ case CPU_533MHz_DDR_356MHz_L2_267MHz:
+ tmp = DDR_360;
+ hclk = 180;
+ break;
+ case CPU_400MHz_DDR_400MHz_L2_200MHz:
+ case CPU_600MHz_DDR_400MHz_L2_300MHz:
+ case CPU_800MHz_DDR_400MHz_L2_400MHz:
+ case CPU_400MHz_DDR_400MHz_L2_400MHz:
+ tmp = DDR_400;
+ hclk = 200;
+ break;
+ case CPU_666MHz_DDR_444MHz_L2_333MHz:
+ case CPU_900MHz_DDR_450MHz_L2_450MHz:
+ tmp = DDR_444;
+ hclk = 222;
+ break;
+ case CPU_500MHz_DDR_500MHz_L2_250MHz:
+ case CPU_1000MHz_DDR_500MHz_L2_500MHz:
+ case CPU_1000MHz_DDR_500MHz_L2_333MHz:
+ tmp = DDR_500;
+ hclk = 250;
+ break;
+ case CPU_533MHz_DDR_533MHz_L2_267MHz:
+ case CPU_800MHz_DDR_534MHz_L2_400MHz:
+ case CPU_1100MHz_DDR_550MHz_L2_550MHz:
+ tmp = DDR_533;
+ hclk = 267;
+ break;
+ case CPU_600MHz_DDR_600MHz_L2_300MHz:
+ case CPU_900MHz_DDR_600MHz_L2_450MHz:
+ case CPU_1200MHz_DDR_600MHz_L2_600MHz:
+ tmp = DDR_600;
+ hclk = 300;
+ break;
+ case CPU_666MHz_DDR_666MHz_L2_333MHz:
+ case CPU_1000MHz_DDR_667MHz_L2_500MHz:
+ tmp = DDR_666;
+ hclk = 333;
+ break;
+ default:
+ *ddr_freq = 0;
+ *hclk_ps = 0;
+ break;
+ }
+
+ *ddr_freq = tmp; /* DDR freq define */
+ *hclk_ps = 1000000 / hclk; /* values are 1/HCLK in ps */
+
+ return;
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_init.h b/drivers/ddr/mvebu/ddr3_init.h
new file mode 100644
index 0000000..b259e09
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_init.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_INIT_H
+#define __DDR3_INIT_H
+
+/*
+ * Debug
+ */
+
+/*
+ * MV_DEBUG_INIT need to be defines, otherwise the output of the
+ * DDR2 training code is not complete and misleading
+ */
+#define MV_DEBUG_INIT
+
+#ifdef MV_DEBUG_INIT
+#define DEBUG_INIT_S(s) puts(s)
+#define DEBUG_INIT_D(d, l) printf("%x", d)
+#define DEBUG_INIT_D_10(d, l) printf("%d", d)
+#else
+#define DEBUG_INIT_S(s)
+#define DEBUG_INIT_D(d, l)
+#define DEBUG_INIT_D_10(d, l)
+#endif
+
+#ifdef MV_DEBUG_INIT_FULL
+#define DEBUG_INIT_FULL_S(s) puts(s)
+#define DEBUG_INIT_FULL_D(d, l) printf("%x", d)
+#define DEBUG_INIT_FULL_D_10(d, l) printf("%d", d)
+#define DEBUG_WR_REG(reg, val) \
+ { DEBUG_INIT_S("Write Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+ DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#define DEBUG_RD_REG(reg, val) \
+ { DEBUG_INIT_S("Read Reg: 0x"); DEBUG_INIT_D((reg), 8); \
+ DEBUG_INIT_S("= "); DEBUG_INIT_D((val), 8); DEBUG_INIT_S("\n"); }
+#else
+#define DEBUG_INIT_FULL_S(s)
+#define DEBUG_INIT_FULL_D(d, l)
+#define DEBUG_INIT_FULL_D_10(d, l)
+#define DEBUG_WR_REG(reg, val)
+#define DEBUG_RD_REG(reg, val)
+#endif
+
+#define DEBUG_INIT_FULL_C(s, d, l) \
+ { DEBUG_INIT_FULL_S(s); DEBUG_INIT_FULL_D(d, l); DEBUG_INIT_FULL_S("\n"); }
+#define DEBUG_INIT_C(s, d, l) \
+ { DEBUG_INIT_S(s); DEBUG_INIT_D(d, l); DEBUG_INIT_S("\n"); }
+
+#define MV_MBUS_REGS_OFFSET (0x20000)
+
+#include "ddr3_hw_training.h"
+
+#define MAX_DIMM_NUM 2
+#define SPD_SIZE 128
+
+#ifdef MV88F78X60
+#include "ddr3_axp.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370.h"
+#elif defined(MV88F672X)
+#include "ddr3_a375.h"
+#endif
+
+/* DRR training Error codes */
+/* Stage 0 errors */
+#define MV_DDR3_TRAINING_ERR_BAD_SAR 0xDD300001
+/* Stage 1 errors */
+#define MV_DDR3_TRAINING_ERR_TWSI_FAIL 0xDD301001
+#define MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH 0xDD301001
+#define MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE 0xDD301003
+#define MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH 0xDD301004
+#define MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP 0xDD301005
+#define MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT 0xDD301006
+#define MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT 0xDD301007
+#define MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP 0xDD301008
+/* Stage 2 errors */
+#define MV_DDR3_TRAINING_ERR_HW_FAIL_BASE 0xDD302000
+
+typedef enum config_type {
+ CONFIG_ECC,
+ CONFIG_MULTI_CS,
+ CONFIG_BUS_WIDTH
+} MV_CONFIG_TYPE;
+
+enum log_level {
+ MV_LOG_LEVEL_0,
+ MV_LOG_LEVEL_1,
+ MV_LOG_LEVEL_2,
+ MV_LOG_LEVEL_3
+};
+
+int ddr3_hw_training(u32 target_freq, u32 ddr_width,
+ int xor_bypass, u32 scrub_offs, u32 scrub_size,
+ int dqs_clk_aligned, int debug_mode, int reg_dimm_skip_wl);
+
+void ddr3_print_version(void);
+void fix_pll_val(u8 target_fab);
+u8 ddr3_get_eprom_fabric(void);
+u32 ddr3_get_fab_opt(void);
+u32 ddr3_get_cpu_freq(void);
+u32 ddr3_get_vco_freq(void);
+int ddr3_check_config(u32 addr, MV_CONFIG_TYPE config_type);
+u32 ddr3_get_static_mc_value(u32 reg_addr, u32 offset1, u32 mask1, u32 offset2,
+ u32 mask2);
+u32 ddr3_cl_to_valid_cl(u32 cl);
+u32 ddr3_valid_cl_to_cl(u32 ui_valid_cl);
+u32 ddr3_get_cs_num_from_reg(void);
+u32 ddr3_get_cs_ena_from_reg(void);
+u8 mv_ctrl_rev_get(void);
+
+u32 ddr3_get_log_level(void);
+
+/* SPD */
+int ddr3_dunit_setup(u32 ecc_ena, u32 hclk_time, u32 *ddr_width);
+
+/*
+ * Accessor functions for the registers
+ */
+static inline void reg_write(u32 addr, u32 val)
+{
+ writel(val, INTER_REGS_BASE + addr);
+}
+
+static inline u32 reg_read(u32 addr)
+{
+ return readl(INTER_REGS_BASE + addr);
+}
+
+static inline void reg_bit_set(u32 addr, u32 mask)
+{
+ setbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+static inline void reg_bit_clr(u32 addr, u32 mask)
+{
+ clrbits_le32(INTER_REGS_BASE + addr, mask);
+}
+
+#endif /* __DDR3_INIT_H */
diff --git a/drivers/ddr/mvebu/ddr3_patterns_64bit.h b/drivers/ddr/mvebu/ddr3_patterns_64bit.h
new file mode 100644
index 0000000..1b57328
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_patterns_64bit.h
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __DDR3_PATTERNS_64_H
+#define __DDR3_PATTERNS_64_H
+
+/*
+ * Patterns Declerations
+ */
+
+u32 wl_sup_pattern[LEN_WL_SUP_PATTERN] __aligned(32) = {
+ 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d,
+ 0x14131211, 0x18171615, 0x1c1b1a19, 0x201f1e1d,
+ 0x24232221, 0x28272625, 0x2c2b2a29, 0x302f2e2d,
+ 0x34333231, 0x38373635, 0x3c3b3a39, 0x403f3e3d,
+ 0x44434241, 0x48474645, 0x4c4b4a49, 0x504f4e4d,
+ 0x54535251, 0x58575655, 0x5c5b5a59, 0x605f5e5d,
+ 0x64636261, 0x68676665, 0x6c6b6a69, 0x706f6e6d,
+ 0x74737271, 0x78777675, 0x7c7b7a79, 0x807f7e7d
+};
+
+u32 pbs_pattern_32b[2][LEN_PBS_PATTERN] __aligned(32) = {
+ {
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555,
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555,
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555,
+ 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x55555555
+ },
+ {
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA,
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA,
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA,
+ 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA
+ }
+};
+
+u32 pbs_pattern_64b[2][LEN_PBS_PATTERN] __aligned(32) = {
+ {
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555
+ },
+ {
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA
+ }
+};
+
+u32 rl_pattern[LEN_STD_PATTERN] __aligned(32) = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0x01010101, 0x01010101
+};
+
+u32 killer_pattern_32b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+ {
+ 0x01010101, 0x00000000, 0x01010101, 0xFFFFFFFF,
+ 0x01010101, 0x00000000, 0x01010101, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE,
+ 0x01010101, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0x01010101, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, 0x00000000,
+ 0xFEFEFEFE, 0x01010101, 0xFEFEFEFE, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x01010101,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x01010101,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0x00000000, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFEFEFEFE, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0x00000000, 0xFEFEFEFE, 0x00000000,
+ 0xFEFEFEFE, 0x00000000, 0xFEFEFEFE, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x00000000,
+ 0x01010101, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE
+ },
+ {
+ 0x02020202, 0x00000000, 0x02020202, 0xFFFFFFFF,
+ 0x02020202, 0x00000000, 0x02020202, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD,
+ 0x02020202, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0x02020202, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, 0x00000000,
+ 0xFDFDFDFD, 0x02020202, 0xFDFDFDFD, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x02020202,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x02020202,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0x00000000, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFDFDFDFD, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0x00000000, 0xFDFDFDFD, 0x00000000,
+ 0xFDFDFDFD, 0x00000000, 0xFDFDFDFD, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x00000000,
+ 0x02020202, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD
+ },
+ {
+ 0x04040404, 0x00000000, 0x04040404, 0xFFFFFFFF,
+ 0x04040404, 0x00000000, 0x04040404, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB,
+ 0x04040404, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0x04040404, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, 0x00000000,
+ 0xFBFBFBFB, 0x04040404, 0xFBFBFBFB, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x04040404,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x04040404,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0x00000000, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFBFBFBFB, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0x00000000, 0xFBFBFBFB, 0x00000000,
+ 0xFBFBFBFB, 0x00000000, 0xFBFBFBFB, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x00000000,
+ 0x04040404, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB
+ },
+ {
+ 0x08080808, 0x00000000, 0x08080808, 0xFFFFFFFF,
+ 0x08080808, 0x00000000, 0x08080808, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7,
+ 0x08080808, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0x08080808, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, 0x00000000,
+ 0xF7F7F7F7, 0x08080808, 0xF7F7F7F7, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x08080808,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x08080808,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0x00000000, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xF7F7F7F7, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0x00000000, 0xF7F7F7F7, 0x00000000,
+ 0xF7F7F7F7, 0x00000000, 0xF7F7F7F7, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x00000000,
+ 0x08080808, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7
+ },
+ {
+ 0x10101010, 0x00000000, 0x10101010, 0xFFFFFFFF,
+ 0x10101010, 0x00000000, 0x10101010, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF,
+ 0x10101010, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0x10101010, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, 0x00000000,
+ 0xEFEFEFEF, 0x10101010, 0xEFEFEFEF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x10101010,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x10101010,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0x00000000, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xEFEFEFEF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0x00000000, 0xEFEFEFEF, 0x00000000,
+ 0xEFEFEFEF, 0x00000000, 0xEFEFEFEF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x00000000,
+ 0x10101010, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF
+ },
+ {
+ 0x20202020, 0x00000000, 0x20202020, 0xFFFFFFFF,
+ 0x20202020, 0x00000000, 0x20202020, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF,
+ 0x20202020, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0x20202020, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, 0x00000000,
+ 0xDFDFDFDF, 0x20202020, 0xDFDFDFDF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x20202020,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x20202020,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0x00000000, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xDFDFDFDF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0x00000000, 0xDFDFDFDF, 0x00000000,
+ 0xDFDFDFDF, 0x00000000, 0xDFDFDFDF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x00000000,
+ 0x20202020, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF
+ },
+ {
+ 0x40404040, 0x00000000, 0x40404040, 0xFFFFFFFF,
+ 0x40404040, 0x00000000, 0x40404040, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF,
+ 0x40404040, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0x40404040, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, 0x00000000,
+ 0xBFBFBFBF, 0x40404040, 0xBFBFBFBF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x40404040,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x40404040,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0x00000000, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xBFBFBFBF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0x00000000, 0xBFBFBFBF, 0x00000000,
+ 0xBFBFBFBF, 0x00000000, 0xBFBFBFBF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x00000000,
+ 0x40404040, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF
+ },
+ {
+ 0x80808080, 0x00000000, 0x80808080, 0xFFFFFFFF,
+ 0x80808080, 0x00000000, 0x80808080, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F,
+ 0x80808080, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x80808080, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, 0x00000000,
+ 0x7F7F7F7F, 0x80808080, 0x7F7F7F7F, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x80808080,
+ 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x80808080,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0x00000000, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x7F7F7F7F, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x00000000, 0x7F7F7F7F, 0x00000000,
+ 0x7F7F7F7F, 0x00000000, 0x7F7F7F7F, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x00000000,
+ 0x80808080, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F
+ }
+};
+
+u32 killer_pattern_64b[DQ_NUM][LEN_KILLER_PATTERN] __aligned(32) = {
+ {
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE
+ },
+ {
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD
+ },
+ {
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB
+ },
+ {
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7
+ },
+ {
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF
+ },
+ {
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF
+ },
+ {
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF
+ },
+ {
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F
+ }
+};
+
+u32 special_pattern[DQ_NUM][LEN_SPECIAL_PATTERN] __aligned(32) = {
+ {
+ 0x00000000, 0x00000000, 0x01010101, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x01010101, 0x01010101,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x01010101, 0x01010101, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x01010101, 0x01010101, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x01010101, 0x01010101, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x01010101, 0x01010101,
+ 0x00000000, 0x00000000, 0x01010101, 0x01010101,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFEFEFE, 0xFEFEFEFE,
+ 0xFEFEFEFE, 0xFEFEFEFE, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x02020202, 0x02020202, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x02020202, 0x02020202, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x02020202, 0x02020202, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x02020202, 0x02020202,
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFDFDFDFD, 0xFDFDFDFD,
+ 0xFDFDFDFD, 0xFDFDFDFD, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x04040404, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x04040404, 0x04040404,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x04040404, 0x04040404, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x04040404, 0x04040404, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x04040404, 0x04040404, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x04040404, 0x04040404,
+ 0x00000000, 0x00000000, 0x04040404, 0x04040404,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFBFBFBFB, 0xFBFBFBFB,
+ 0xFBFBFBFB, 0xFBFBFBFB, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x08080808, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x08080808, 0x08080808,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x08080808, 0x08080808, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x08080808, 0x08080808, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x08080808, 0x08080808, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x08080808, 0x08080808,
+ 0x00000000, 0x00000000, 0x08080808, 0x08080808,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xF7F7F7F7, 0xF7F7F7F7,
+ 0xF7F7F7F7, 0xF7F7F7F7, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x10101010, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x10101010, 0x10101010,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x10101010, 0x10101010, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x10101010, 0x10101010, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x10101010, 0x10101010, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x10101010, 0x10101010,
+ 0x00000000, 0x00000000, 0x10101010, 0x10101010,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xEFEFEFEF, 0xEFEFEFEF,
+ 0xEFEFEFEF, 0xEFEFEFEF, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x20202020, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x20202020, 0x20202020,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x20202020, 0x20202020, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x20202020, 0x20202020, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x20202020, 0x20202020, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x20202020, 0x20202020,
+ 0x00000000, 0x00000000, 0x20202020, 0x20202020,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF,
+ 0xDFDFDFDF, 0xDFDFDFDF, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x40404040, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x40404040, 0x40404040,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x40404040, 0x40404040, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x40404040, 0x40404040, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x40404040, 0x40404040, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x40404040, 0x40404040,
+ 0x00000000, 0x00000000, 0x40404040, 0x40404040,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xBFBFBFBF, 0xBFBFBFBF,
+ 0xBFBFBFBF, 0xBFBFBFBF, 0x00000000, 0x00000000
+ },
+ {
+ 0x00000000, 0x00000000, 0x80808080, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x80808080, 0x80808080,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x80808080, 0x80808080, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x80808080, 0x80808080, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x80808080, 0x80808080, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x80808080, 0x80808080,
+ 0x00000000, 0x00000000, 0x80808080, 0x80808080,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x7F7F7F7F, 0x7F7F7F7F,
+ 0x7F7F7F7F, 0x7F7F7F7F, 0x00000000, 0x00000000
+ }
+};
+
+/* Fabric ratios table */
+u32 fabric_ratio[FAB_OPT] = {
+ 0x04010204,
+ 0x04020202,
+ 0x08020306,
+ 0x08020303,
+ 0x04020303,
+ 0x04020204,
+ 0x04010202,
+ 0x08030606,
+ 0x08030505,
+ 0x04020306,
+ 0x0804050A,
+ 0x04030606,
+ 0x04020404,
+ 0x04030306,
+ 0x04020505,
+ 0x08020505,
+ 0x04010303,
+ 0x08050A0A,
+ 0x04030408,
+ 0x04010102,
+ 0x08030306
+};
+
+u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM] = {
+ {3, 2, 5, 7, 1, 0, 6, 4},
+ {2, 3, 6, 7, 1, 0, 4, 5},
+ {1, 3, 5, 6, 0, 2, 4, 7},
+ {0, 2, 4, 7, 1, 3, 5, 6},
+ {3, 0, 4, 6, 1, 2, 5, 7},
+ {0, 3, 5, 7, 1, 2, 4, 6},
+ {2, 3, 5, 7, 1, 0, 4, 6},
+ {0, 2, 5, 4, 1, 3, 6, 7},
+ {2, 3, 4, 7, 0, 1, 5, 6}
+};
+
+#endif /* __DDR3_PATTERNS_64_H */
diff --git a/drivers/ddr/mvebu/ddr3_pbs.c b/drivers/ddr/mvebu/ddr3_pbs.c
new file mode 100644
index 0000000..00ea3fd
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_pbs.c
@@ -0,0 +1,1592 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_PBS_FULL_C(s, d, l) \
+ DEBUG_PBS_FULL_S(s); DEBUG_PBS_FULL_D(d, l); DEBUG_PBS_FULL_S("\n")
+#define DEBUG_PBS_C(s, d, l) \
+ DEBUG_PBS_S(s); DEBUG_PBS_D(d, l); DEBUG_PBS_S("\n")
+
+#ifdef MV_DEBUG_PBS
+#define DEBUG_PBS_S(s) puts(s)
+#define DEBUG_PBS_D(d, l) printf("%x", d)
+#else
+#define DEBUG_PBS_S(s)
+#define DEBUG_PBS_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_FULL_PBS
+#define DEBUG_PBS_FULL_S(s) puts(s)
+#define DEBUG_PBS_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_PBS_FULL_S(s)
+#define DEBUG_PBS_FULL_D(d, l)
+#endif
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+
+/* Temp array for skew data storage */
+static u32 skew_array[(MAX_PUP_NUM) * DQ_NUM] = { 0 };
+
+/* PBS locked dq (per pup) */
+extern u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM];
+extern u32 pbs_locked_dm[MAX_PUP_NUM];
+extern u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM];
+
+#if defined(MV88F672X)
+extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+#else
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
+#endif
+
+extern u32 pbs_dq_mapping[PUP_NUM_64BIT + 1][DQ_NUM];
+
+static int ddr3_tx_shift_dqs_adll_step_before_fail(MV_DRAM_INFO *dram_info,
+ u32 cur_pup, u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_rx_shift_dqs_to_first_fail(MV_DRAM_INFO *dram_info, u32 cur_pup,
+ u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_pbs_per_bit(MV_DRAM_INFO *dram_info, int *start_over, int is_tx,
+ u32 *pcur_pup, u32 pbs_pattern_idx, u32 ecc);
+static int ddr3_set_pbs_results(MV_DRAM_INFO *dram_info, int is_tx);
+static void ddr3_pbs_write_pup_dqs_reg(u32 cs, u32 pup, u32 dqs_delay);
+
+/*
+ * Name: ddr3_pbs_tx
+ * Desc: Execute the PBS TX phase.
+ * Args: dram_info ddr3 training information struct
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_pbs_tx(MV_DRAM_INFO *dram_info)
+{
+ /* Array of Deskew results */
+
+ /*
+ * Array to hold the total sum of skew from all iterations
+ * (for average purpose)
+ */
+ u32 skew_sum_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ /*
+ * Array to hold the total average skew from both patterns
+ * (for average purpose)
+ */
+ u32 pattern_skew_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ u32 pbs_rep_time = 0; /* counts number of loop in case of fail */
+ /* bit array for unlock pups - used to repeat on the RX operation */
+ u32 cur_pup;
+ u32 max_pup;
+ u32 pbs_retry;
+ u32 pup, dq, pups, cur_max_pup, valid_pup, reg;
+ u32 pattern_idx;
+ u32 ecc;
+ /* indicates whether we need to start the loop again */
+ int start_over;
+
+ DEBUG_PBS_S("DDR3 - PBS TX - Starting PBS TX procedure\n");
+
+ pups = dram_info->num_of_total_pups;
+ max_pup = dram_info->num_of_total_pups;
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_PBS_S("DDR3 - PBS RX - SW Override Enabled\n");
+
+ reg = 1 << REG_DRAM_TRAINING_AUTO_OFFS;
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Running twice for 2 different patterns. each patterns - 3 times */
+ for (pattern_idx = 0; pattern_idx < COUNT_PBS_PATTERN; pattern_idx++) {
+ DEBUG_PBS_C("DDR3 - PBS TX - Working with pattern - ",
+ pattern_idx, 1);
+
+ /* Reset sum array */
+ for (pup = 0; pup < pups; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_sum_array[pup][dq] = 0;
+ }
+
+ /*
+ * Perform PBS several of times (3 for each pattern).
+ * At the end, we'll use the average
+ */
+ /* If there is ECC, do each PBS again with mux change */
+ for (pbs_retry = 0; pbs_retry < COUNT_PBS_REPEAT; pbs_retry++) {
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+
+ /*
+ * This parameter stores the current PUP
+ * num - ecc mode dependent - 4-8 / 1 pups
+ */
+ cur_max_pup = (1 - ecc) *
+ dram_info->num_of_std_pups + ecc;
+
+ if (ecc) {
+ /* Only 1 pup in this case */
+ valid_pup = 0x1;
+ } else if (cur_max_pup > 4) {
+ /* 64 bit - 8 pups */
+ valid_pup = 0xFF;
+ } else if (cur_max_pup == 4) {
+ /* 32 bit - 4 pups */
+ valid_pup = 0xF;
+ } else {
+ /* 16 bit - 2 pups */
+ valid_pup = 0x3;
+ }
+
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena * ecc <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_PBS_S("DDR3 - PBS Tx - ECC Mux Enabled\n");
+ else
+ DEBUG_PBS_S("DDR3 - PBS Tx - ECC Mux Disabled\n");
+
+ /* Init iteration values */
+ /* Clear the locked DQs */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pbs_locked_dq[
+ pup + ecc *
+ (max_pup - 1)][dq] =
+ 0;
+ }
+ }
+
+ pbs_rep_time = 0;
+ cur_pup = valid_pup;
+ start_over = 0;
+
+ /*
+ * Run loop On current Pattern and current
+ * pattern iteration (just to cover the false
+ * fail problem)
+ */
+ do {
+ DEBUG_PBS_S("DDR3 - PBS Tx - Pbs Rep Loop is ");
+ DEBUG_PBS_D(pbs_rep_time, 1);
+ DEBUG_PBS_S(", for Retry No.");
+ DEBUG_PBS_D(pbs_retry, 1);
+ DEBUG_PBS_S("\n");
+
+ /* Set all PBS values to MIN (0) */
+ DEBUG_PBS_S("DDR3 - PBS Tx - Set all PBS values to MIN\n");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ ddr3_write_pup_reg(
+ PUP_PBS_TX +
+ pbs_dq_mapping[pup *
+ (1 - ecc) +
+ ecc * ECC_PUP]
+ [dq], CS0, (1 - ecc) *
+ PUP_BC + ecc * ECC_PUP, 0,
+ 0);
+ }
+
+ /*
+ * Shift DQ ADLL right, One step before
+ * fail
+ */
+ DEBUG_PBS_S("DDR3 - PBS Tx - ADLL shift right one phase before fail\n");
+
+ if (MV_OK != ddr3_tx_shift_dqs_adll_step_before_fail
+ (dram_info, cur_pup, pattern_idx,
+ ecc))
+ return MV_DDR3_TRAINING_ERR_PBS_ADLL_SHR_1PHASE;
+
+ /* PBS For each bit */
+ DEBUG_PBS_S("DDR3 - PBS Tx - perform PBS for each bit\n");
+
+ /*
+ * In this stage - start_over = 0
+ */
+ if (MV_OK != ddr3_pbs_per_bit(
+ dram_info, &start_over, 1,
+ &cur_pup, pattern_idx, ecc))
+ return MV_DDR3_TRAINING_ERR_PBS_TX_PER_BIT;
+
+ } while ((start_over == 1) &&
+ (++pbs_rep_time < COUNT_PBS_STARTOVER));
+
+ if (pbs_rep_time == COUNT_PBS_STARTOVER &&
+ start_over == 1) {
+ DEBUG_PBS_S("DDR3 - PBS Tx - FAIL - Adll reach max value\n");
+ return MV_DDR3_TRAINING_ERR_PBS_TX_MAX_VAL;
+ }
+
+ DEBUG_PBS_FULL_C("DDR3 - PBS TX - values for iteration - ",
+ pbs_retry, 1);
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc
+ * from pbs value the min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D((pup + (ecc * ECC_PUP)), 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew -
+ * last / first failing bit
+ * Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_array
+ [((pup) * DQ_NUM) +
+ dq], 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /*
+ * Collect the results we got on this trial
+ * of PBS
+ */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ skew_sum_array[pup + (ecc * (max_pup - 1))]
+ [dq] += skew_array
+ [((pup) * DQ_NUM) + dq];
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ }
+ }
+
+ DEBUG_PBS_C("DDR3 - PBS TX - values for current pattern - ",
+ pattern_idx, 1);
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the
+ * min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* set skew value for all dq */
+ /* Bit# Deskew <- Bit# Deskew - last / first failing bit Deskew For all bits (per PUP) (minimize delay elements) */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT, 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /*
+ * Calculate the average skew for current pattern for each
+ * pup and each bit
+ */
+ DEBUG_PBS_C("DDR3 - PBS TX - Average for pattern - ",
+ pattern_idx, 1);
+
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * FOR ECC only :: found min and max value for current
+ * pattern skew array
+ */
+ /* Loop for all dqs */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pattern_skew_array[pup][dq] +=
+ (skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT);
+ }
+ }
+ }
+
+ /* Calculate the average skew */
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_array[((pup) * DQ_NUM) + dq] =
+ pattern_skew_array[pup][dq] / COUNT_PBS_PATTERN;
+ }
+
+ DEBUG_PBS_S("DDR3 - PBS TX - Average for all patterns:\n");
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the min
+ * pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_array[(pup * DQ_NUM) + dq], 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /* Return ADLL to default value */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (pup == (max_pup - 1) && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ ddr3_pbs_write_pup_dqs_reg(CS0, pup, INIT_WL_DELAY);
+ }
+
+ /* Set averaged PBS results */
+ ddr3_set_pbs_results(dram_info, 1);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ DEBUG_PBS_S("DDR3 - PBS Tx - PBS TX ended successfuly\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_tx_shift_dqs_adll_step_before_fail
+ * Desc: Execute the Tx shift DQ phase.
+ * Args: dram_info ddr3 training information struct
+ * cur_pup bit array of the function active pups.
+ * pbs_pattern_idx Index of PBS pattern
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_tx_shift_dqs_adll_step_before_fail(MV_DRAM_INFO *dram_info,
+ u32 cur_pup,
+ u32 pbs_pattern_idx, u32 ecc)
+{
+ u32 unlock_pup; /* bit array of unlock pups */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 adll_val = 4; /* INIT_WL_DELAY */
+ u32 cur_max_pup, pup;
+ u32 dqs_dly_set[MAX_PUP_NUM] = { 0 };
+ u32 *pattern_ptr;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ /* Set current pup number */
+ if (cur_pup == 0x1) /* Ecc mode */
+ cur_max_pup = 1;
+ else
+ cur_max_pup = dram_info->num_of_std_pups;
+
+ unlock_pup = cur_pup; /* '1' for each unlocked pup */
+
+ /* Loop on all ADLL Vaules */
+ do {
+ /* Loop until found first fail */
+ adll_val++;
+
+ /*
+ * Increment (Move to right - ADLL) DQ TX delay
+ * (broadcast to all Data PUPs)
+ */
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_pbs_write_pup_dqs_reg(CS0,
+ pup * (1 - ecc) +
+ ECC_PUP * ecc, adll_val);
+
+ /*
+ * Write and Read, compare results (read was already verified)
+ */
+ /* 0 - all locked */
+ new_lockup_pup = 0;
+
+ if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup,
+ &new_lockup_pup,
+ pattern_ptr, LEN_PBS_PATTERN,
+ SDRAM_PBS_TX_OFFS, 1, 0,
+ NULL,
+ 0))
+ return MV_FAIL;
+
+ unlock_pup &= ~new_lockup_pup;
+
+ DEBUG_PBS_FULL_S("Shift DQS by 2 steps for PUPs: ");
+ DEBUG_PBS_FULL_D(unlock_pup, 2);
+ DEBUG_PBS_FULL_C(", Set ADLL value = ", adll_val, 2);
+
+ /* If any PUP failed there is '1' to mark the PUP */
+ if (new_lockup_pup != 0) {
+ /*
+ * Decrement (Move Back to Left two steps - ADLL)
+ * DQ TX delay for current failed pups and save
+ */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (((new_lockup_pup >> pup) & 0x1) &&
+ dqs_dly_set[pup] == 0)
+ dqs_dly_set[pup] = adll_val - 1;
+ }
+ }
+ } while ((unlock_pup != 0) && (adll_val != ADLL_MAX));
+
+ if (unlock_pup != 0) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Tx - Shift DQ - Adll value reached maximum\n");
+
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (((unlock_pup >> pup) & 0x1) &&
+ dqs_dly_set[pup] == 0)
+ dqs_dly_set[pup] = adll_val - 1;
+ }
+ }
+
+ DEBUG_PBS_FULL_C("PBS TX one step before fail last pups locked Adll ",
+ adll_val - 2, 2);
+
+ /* Set the PUP DQS DLY Values */
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_pbs_write_pup_dqs_reg(CS0, pup * (1 - ecc) + ECC_PUP * ecc,
+ dqs_dly_set[pup]);
+
+ /* Found one phase before fail */
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_pbs_rx
+ * Desc: Execute the PBS RX phase.
+ * Args: dram_info ddr3 training information struct
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_pbs_rx(MV_DRAM_INFO *dram_info)
+{
+ /*
+ * Array to hold the total sum of skew from all iterations
+ * (for average purpose)
+ */
+ u32 skew_sum_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ /*
+ * Array to hold the total average skew from both patterns
+ * (for average purpose)
+ */
+ u32 pattern_skew_array[MAX_PUP_NUM][DQ_NUM] = { {0} };
+
+ u32 pbs_rep_time = 0; /* counts number of loop in case of fail */
+ /* bit array for unlock pups - used to repeat on the RX operation */
+ u32 cur_pup;
+ u32 max_pup;
+ u32 pbs_retry;
+ u32 pup, dq, pups, cur_max_pup, valid_pup, reg;
+ u32 pattern_idx;
+ u32 ecc;
+ /* indicates whether we need to start the loop again */
+ int start_over;
+ int status;
+
+ DEBUG_PBS_S("DDR3 - PBS RX - Starting PBS RX procedure\n");
+
+ pups = dram_info->num_of_total_pups;
+ max_pup = dram_info->num_of_total_pups;
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - SW Override Enabled\n");
+
+ reg = 1 << REG_DRAM_TRAINING_AUTO_OFFS;
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ /* Running twice for 2 different patterns. each patterns - 3 times */
+ for (pattern_idx = 0; pattern_idx < COUNT_PBS_PATTERN; pattern_idx++) {
+ DEBUG_PBS_FULL_C("DDR3 - PBS RX - Working with pattern - ",
+ pattern_idx, 1);
+
+ /* Reset sum array */
+ for (pup = 0; pup < pups; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_sum_array[pup][dq] = 0;
+ }
+
+ /*
+ * Perform PBS several of times (3 for each pattern).
+ * At the end, we'll use the average
+ */
+ /* If there is ECC, do each PBS again with mux change */
+ for (pbs_retry = 0; pbs_retry < COUNT_PBS_REPEAT; pbs_retry++) {
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1); ecc++) {
+ /*
+ * This parameter stores the current PUP
+ * num - ecc mode dependent - 4-8 / 1 pups
+ */
+ cur_max_pup = (1 - ecc) *
+ dram_info->num_of_std_pups + ecc;
+
+ if (ecc) {
+ /* Only 1 pup in this case */
+ valid_pup = 0x1;
+ } else if (cur_max_pup > 4) {
+ /* 64 bit - 8 pups */
+ valid_pup = 0xFF;
+ } else if (cur_max_pup == 4) {
+ /* 32 bit - 4 pups */
+ valid_pup = 0xF;
+ } else {
+ /* 16 bit - 2 pups */
+ valid_pup = 0x3;
+ }
+
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena * ecc <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - ECC Mux Enabled\n");
+ else
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - ECC Mux Disabled\n");
+
+ /* Init iteration values */
+ /* Clear the locked DQs */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pbs_locked_dq[
+ pup + ecc * (max_pup - 1)][dq] =
+ 0;
+ }
+ }
+
+ pbs_rep_time = 0;
+ cur_pup = valid_pup;
+ start_over = 0;
+
+ /*
+ * Run loop On current Pattern and current
+ * pattern iteration (just to cover the false
+ * fail problem
+ */
+ do {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Pbs Rep Loop is ");
+ DEBUG_PBS_FULL_D(pbs_rep_time, 1);
+ DEBUG_PBS_FULL_S(", for Retry No.");
+ DEBUG_PBS_FULL_D(pbs_retry, 1);
+ DEBUG_PBS_FULL_S("\n");
+
+ /* Set all PBS values to MAX (31) */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ ddr3_write_pup_reg(
+ PUP_PBS_RX +
+ pbs_dq_mapping[
+ pup * (1 - ecc)
+ + ecc * ECC_PUP]
+ [dq], CS0,
+ pup + ecc * ECC_PUP,
+ 0, MAX_PBS);
+ }
+
+ /* Set all DQS PBS values to MIN (0) */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ ddr3_write_pup_reg(PUP_PBS_RX +
+ DQ_NUM, CS0,
+ pup +
+ ecc *
+ ECC_PUP, 0,
+ 0);
+ }
+
+ /* Shift DQS, To first Fail */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Shift RX DQS to first fail\n");
+
+ status = ddr3_rx_shift_dqs_to_first_fail
+ (dram_info, cur_pup,
+ pattern_idx, ecc);
+ if (MV_OK != status) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - ddr3_rx_shift_dqs_to_first_fail failed.\n");
+ DEBUG_PBS_D(status, 8);
+ DEBUG_PBS_S("\nDDR3 - PBS Rx - SKIP.\n");
+
+ /* Reset read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Start Auto Read Leveling procedure */
+ reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS)
+ + (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+ /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR))
+ & (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Clear Auto Read Leveling procedure */
+ reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ /* Set ADLL to 15 */
+ for (pup = 0; pup < max_pup;
+ pup++) {
+ ddr3_write_pup_reg
+ (PUP_DQS_RD, CS0,
+ pup +
+ (ecc * ECC_PUP), 0,
+ 15);
+ }
+
+ /* Set all PBS values to MIN (0) */
+ for (pup = 0; pup < cur_max_pup;
+ pup++) {
+ for (dq = 0;
+ dq < DQ_NUM; dq++)
+ ddr3_write_pup_reg
+ (PUP_PBS_RX +
+ pbs_dq_mapping
+ [pup * (1 - ecc) +
+ ecc * ECC_PUP]
+ [dq], CS0,
+ pup + ecc * ECC_PUP,
+ 0, MIN_PBS);
+ }
+
+ return MV_OK;
+ }
+
+ /* PBS For each bit */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - perform PBS for each bit\n");
+ /* in this stage - start_over = 0; */
+ if (MV_OK != ddr3_pbs_per_bit(
+ dram_info, &start_over,
+ 0, &cur_pup,
+ pattern_idx, ecc)) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - ddr3_pbs_per_bit failed.");
+ return MV_DDR3_TRAINING_ERR_PBS_RX_PER_BIT;
+ }
+
+ } while ((start_over == 1) &&
+ (++pbs_rep_time < COUNT_PBS_STARTOVER));
+
+ if (pbs_rep_time == COUNT_PBS_STARTOVER &&
+ start_over == 1) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - FAIL - Algorithm failed doing RX PBS\n");
+ return MV_DDR3_TRAINING_ERR_PBS_RX_MAX_VAL;
+ }
+
+ /* Return DQS ADLL to default value - 15 */
+ /* Set all DQS PBS values to MIN (0) */
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+ pup + ecc * ECC_PUP,
+ 0, INIT_RL_DELAY);
+
+ DEBUG_PBS_FULL_C("DDR3 - PBS RX - values for iteration - ",
+ pbs_retry, 1);
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from
+ * pbs value the min pbs val
+ */
+ DEBUG_PBS_FULL_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_FULL_D((pup +
+ (ecc * ECC_PUP)), 1);
+ DEBUG_PBS_FULL_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew -
+ * last / first failing bit
+ * Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_FULL_S("DQ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S("-");
+ DEBUG_PBS_FULL_D(skew_array
+ [((pup) *
+ DQ_NUM) +
+ dq], 2);
+ DEBUG_PBS_FULL_S(", ");
+ }
+ DEBUG_PBS_FULL_S("\n");
+ }
+
+ /*
+ * Collect the results we got on this trial
+ * of PBS
+ */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ skew_sum_array
+ [pup + (ecc * (max_pup - 1))]
+ [dq] +=
+ skew_array[((pup) * DQ_NUM) + dq];
+ }
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ }
+ }
+
+ /*
+ * Calculate the average skew for current pattern for each
+ * pup and each bit
+ */
+ DEBUG_PBS_FULL_C("DDR3 - PBS RX - Average for pattern - ",
+ pattern_idx, 1);
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * FOR ECC only :: found min and max value for
+ * current pattern skew array
+ */
+ /* Loop for all dqs */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ pattern_skew_array[pup][dq] +=
+ (skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT);
+ }
+ }
+
+ DEBUG_PBS_C("DDR3 - PBS RX - values for current pattern - ",
+ pattern_idx, 1);
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the
+ * min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS RX - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_sum_array[pup][dq] /
+ COUNT_PBS_REPEAT, 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+ }
+
+ /* Calculate the average skew */
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ skew_array[((pup) * DQ_NUM) + dq] =
+ pattern_skew_array[pup][dq] / COUNT_PBS_PATTERN;
+ }
+
+ DEBUG_PBS_S("DDR3 - PBS RX - Average for all patterns:\n");
+ for (pup = 0; pup < max_pup; pup++) {
+ /*
+ * To minimize delay elements, inc from pbs value the
+ * min pbs val
+ */
+ DEBUG_PBS_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_D(pup, 1);
+ DEBUG_PBS_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+ DEBUG_PBS_S("DQ");
+ DEBUG_PBS_D(dq, 1);
+ DEBUG_PBS_S("-");
+ DEBUG_PBS_D(skew_array[(pup * DQ_NUM) + dq], 2);
+ DEBUG_PBS_S(", ");
+ }
+ DEBUG_PBS_S("\n");
+ }
+
+ /* Return ADLL to default value */
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0, PUP_BC, 0, INIT_RL_DELAY);
+
+ /* Set averaged PBS results */
+ ddr3_set_pbs_results(dram_info, 0);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - ended successfuly\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_rx_shift_dqs_to_first_fail
+ * Desc: Execute the Rx shift DQ phase.
+ * Args: dram_info ddr3 training information struct
+ * cur_pup bit array of the function active pups.
+ * pbs_pattern_idx Index of PBS pattern
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_rx_shift_dqs_to_first_fail(MV_DRAM_INFO *dram_info, u32 cur_pup,
+ u32 pbs_pattern_idx, u32 ecc)
+{
+ u32 unlock_pup; /* bit array of unlock pups */
+ u32 new_lockup_pup; /* bit array of compare failed pups */
+ u32 adll_val = MAX_DELAY;
+ u32 dqs_deskew_val = 0; /* current value of DQS PBS deskew */
+ u32 cur_max_pup, pup, pass_pup;
+ u32 *pattern_ptr;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ /* Set current pup number */
+ if (cur_pup == 0x1) /* Ecc mode */
+ cur_max_pup = 1;
+ else
+ cur_max_pup = dram_info->num_of_std_pups;
+
+ unlock_pup = cur_pup; /* '1' for each unlocked pup */
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Starting...\n");
+
+ /* Set DQS ADLL to MAX */
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Set DQS ADLL to Max for all PUPs\n");
+ for (pup = 0; pup < cur_max_pup; pup++)
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0, pup + ecc * ECC_PUP, 0,
+ MAX_DELAY);
+
+ /* Loop on all ADLL Vaules */
+ do {
+ /* Loop until found fail for all pups */
+ new_lockup_pup = 0;
+ if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup,
+ &new_lockup_pup,
+ pattern_ptr, LEN_PBS_PATTERN,
+ SDRAM_PBS_I_OFFS +
+ pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS,
+ 0, 0, NULL, 0)) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP(ddr3_sdram_compare)\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+ }
+
+ if ((new_lockup_pup != 0) && (dqs_deskew_val <= 1)) {
+ /* Fail on start with first deskew value */
+ /* Decrement DQS ADLL */
+ --adll_val;
+ if (adll_val == ADLL_MIN) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - fail on start with first deskew value\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+ }
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0, pup + ecc * ECC_PUP,
+ 0, adll_val);
+ continue;
+ }
+
+ /* Update all new locked pups */
+ unlock_pup &= ~new_lockup_pup;
+
+ if ((unlock_pup == 0) || (dqs_deskew_val == MAX_PBS)) {
+ if (dqs_deskew_val == MAX_PBS) {
+ /*
+ * Reach max value of dqs deskew or get fail
+ * for all pups
+ */
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - DQS deskew reached maximum value\n");
+ }
+ break;
+ }
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - Inc DQS deskew for PUPs: ");
+ DEBUG_PBS_FULL_D(unlock_pup, 2);
+ DEBUG_PBS_FULL_C(", deskew = ", dqs_deskew_val, 2);
+
+ /* Increment DQS deskew elements - Only for unlocked pups */
+ dqs_deskew_val++;
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ ddr3_write_pup_reg(PUP_PBS_RX + DQS_DQ_NUM, CS0,
+ pup + ecc * ECC_PUP, 0,
+ dqs_deskew_val);
+ }
+ }
+ } while (1);
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS RX - Shift DQS - ADLL shift one step before fail\n");
+ /* Continue to ADLL shift one step before fail */
+ unlock_pup = cur_pup;
+ do {
+ /* Loop until pass compare for all pups */
+ new_lockup_pup = 0;
+ /* Read and compare results */
+ if (MV_OK != ddr3_sdram_compare(dram_info, unlock_pup, &new_lockup_pup,
+ pattern_ptr, LEN_PBS_PATTERN,
+ SDRAM_PBS_I_OFFS +
+ pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS,
+ 1, 0, NULL, 0)) {
+ DEBUG_PBS_S("DDR3 - PBS Rx - Shift DQS - MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP(ddr3_sdram_compare)\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_SRAM_CMP;
+ }
+
+ /*
+ * Get mask for pup which passed so their adll will be
+ * changed to 2 steps before fails
+ */
+ pass_pup = unlock_pup & ~new_lockup_pup;
+
+ DEBUG_PBS_FULL_S("Shift DQS by 2 steps for PUPs: ");
+ DEBUG_PBS_FULL_D(pass_pup, 2);
+ DEBUG_PBS_FULL_C(", Set ADLL value = ", (adll_val - 2), 2);
+
+ /* Only for pass pups */
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pass_pup, pup) == 1) {
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+ pup + ecc * ECC_PUP, 0,
+ (adll_val - 2));
+ }
+ }
+
+ /* Locked pups that compare success */
+ unlock_pup &= new_lockup_pup;
+
+ if (unlock_pup == 0) {
+ /* All pups locked */
+ break;
+ }
+
+ /* Found error */
+ if (adll_val == 0) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Rx - Shift DQS - Adll reach min value\n");
+ return MV_DDR3_TRAINING_ERR_PBS_SHIFT_QDS_MAX_VAL;
+ }
+
+ /*
+ * Decrement (Move Back to Left one phase - ADLL) dqs RX delay
+ */
+ adll_val--;
+ for (pup = 0; pup < cur_max_pup; pup++) {
+ if (IS_PUP_ACTIVE(unlock_pup, pup) == 1) {
+ ddr3_write_pup_reg(PUP_DQS_RD, CS0,
+ pup + ecc * ECC_PUP, 0,
+ adll_val);
+ }
+ }
+ } while (1);
+
+ return MV_OK;
+}
+
+/*
+ * lock_pups() extracted from ddr3_pbs_per_bit(). This just got too
+ * much indented making it hard to read / edit.
+ */
+static void lock_pups(u32 pup, u32 *pup_locked, u8 *unlock_pup_dq_array,
+ u32 pbs_curr_val, u32 start_pbs, u32 ecc, int is_tx)
+{
+ u32 dq;
+ int idx;
+
+ /* Lock PBS value for all remaining PUPs bits */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Lock PBS value for all remaining PUPs bits, pup ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_C(" pbs value ", pbs_curr_val, 2);
+
+ idx = pup * (1 - ecc) + ecc * ECC_PUP;
+ *pup_locked &= ~(1 << pup);
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if (IS_PUP_ACTIVE(unlock_pup_dq_array[dq], pup) == 1) {
+ int offs;
+
+ /* Lock current dq */
+ unlock_pup_dq_array[dq] &= ~(1 << pup);
+ skew_array[(pup * DQ_NUM) + dq] = pbs_curr_val;
+
+ if (is_tx == 1)
+ offs = PUP_PBS_TX;
+ else
+ offs = PUP_PBS_RX;
+
+ ddr3_write_pup_reg(offs +
+ pbs_dq_mapping[idx][dq], CS0,
+ idx, 0, start_pbs);
+ }
+ }
+}
+
+/*
+ * Name: ddr3_pbs_per_bit
+ * Desc: Execute the Per Bit Skew phase.
+ * Args: start_over Return whether need to start over the algorithm
+ * is_tx Indicate whether Rx or Tx
+ * pcur_pup bit array of the function active pups. return the
+ * pups that need to repeat on the PBS
+ * pbs_pattern_idx Index of PBS pattern
+ *
+ * Notes: Current implementation supports double activation of this function.
+ * i.e. in order to activate this function (using start_over) more than
+ * twice, the implementation should change.
+ * imlementation limitation are marked using
+ * ' CHIP-ONLY! - Implementation Limitation '
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_pbs_per_bit(MV_DRAM_INFO *dram_info, int *start_over, int is_tx,
+ u32 *pcur_pup, u32 pbs_pattern_idx, u32 ecc)
+{
+ /*
+ * Bit array to indicate if we already get fail on bit per pup & dq bit
+ */
+ u8 unlock_pup_dq_array[DQ_NUM] = {
+ *pcur_pup, *pcur_pup, *pcur_pup, *pcur_pup, *pcur_pup,
+ *pcur_pup, *pcur_pup, *pcur_pup
+ };
+
+ u8 cmp_unlock_pup_dq_array[COUNT_PBS_COMP_RETRY_NUM][DQ_NUM];
+ u32 pup, dq;
+ /* value of pbs is according to RX or TX */
+ u32 start_pbs, last_pbs;
+ u32 pbs_curr_val;
+ /* bit array that indicates all dq of the pup locked */
+ u32 pup_locked;
+ u32 first_fail[MAX_PUP_NUM] = { 0 }; /* count first fail per pup */
+ /* indicates whether we get first fail per pup */
+ int first_failed[MAX_PUP_NUM] = { 0 };
+ /* bit array that indicates pup already get fail */
+ u32 sum_pup_fail;
+ /* use to calculate diff between curr pbs to first fail pbs */
+ u32 calc_pbs_diff;
+ u32 pbs_cmp_retry;
+ u32 max_pup;
+
+ /* Set init values for retry array - 8 retry */
+ for (pbs_cmp_retry = 0; pbs_cmp_retry < COUNT_PBS_COMP_RETRY_NUM;
+ pbs_cmp_retry++) {
+ for (dq = 0; dq < DQ_NUM; dq++)
+ cmp_unlock_pup_dq_array[pbs_cmp_retry][dq] = *pcur_pup;
+ }
+
+ memset(&skew_array, 0, MAX_PUP_NUM * DQ_NUM * sizeof(u32));
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Started\n");
+
+ /* The pbs value depends if rx or tx */
+ if (is_tx == 1) {
+ start_pbs = MIN_PBS;
+ last_pbs = MAX_PBS;
+ } else {
+ start_pbs = MAX_PBS;
+ last_pbs = MIN_PBS;
+ }
+
+ pbs_curr_val = start_pbs;
+ pup_locked = *pcur_pup;
+
+ /* Set current pup number */
+ if (pup_locked == 0x1) /* Ecc mode */
+ max_pup = 1;
+ else
+ max_pup = dram_info->num_of_std_pups;
+
+ do {
+ /* Increment/ decrement PBS for un-lock bits only */
+ if (is_tx == 1)
+ pbs_curr_val++;
+ else
+ pbs_curr_val--;
+
+ /* Set Current PBS delay */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Check DQ bits to see if locked in all pups */
+ if (unlock_pup_dq_array[dq] == 0) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - All pups are locked for DQ ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S("\n");
+ continue;
+ }
+
+ for (pup = 0; pup < max_pup; pup++) {
+ int idx;
+
+ idx = pup * (1 - ecc) + ecc * ECC_PUP;
+
+ if (IS_PUP_ACTIVE(unlock_pup_dq_array[dq], pup)
+ == 0)
+ continue;
+
+ if (is_tx == 1)
+ ddr3_write_pup_reg(
+ PUP_PBS_TX + pbs_dq_mapping[idx][dq],
+ CS0, idx, 0, pbs_curr_val);
+ else
+ ddr3_write_pup_reg(
+ PUP_PBS_RX + pbs_dq_mapping[idx][dq],
+ CS0, idx, 0, pbs_curr_val);
+ }
+ }
+
+ /*
+ * Write Read and compare results - run the test
+ * DDR_PBS_COMP_RETRY_NUM times
+ */
+ /* Run number of read and write to verify */
+ for (pbs_cmp_retry = 0;
+ pbs_cmp_retry < COUNT_PBS_COMP_RETRY_NUM;
+ pbs_cmp_retry++) {
+
+ if (MV_OK !=
+ ddr3_sdram_pbs_compare(dram_info, pup_locked, is_tx,
+ pbs_pattern_idx,
+ pbs_curr_val, start_pbs,
+ skew_array,
+ cmp_unlock_pup_dq_array
+ [pbs_cmp_retry], ecc))
+ return MV_FAIL;
+
+ for (pup = 0; pup < max_pup; pup++) {
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if ((IS_PUP_ACTIVE(unlock_pup_dq_array[dq],
+ pup) == 1)
+ && (IS_PUP_ACTIVE(cmp_unlock_pup_dq_array
+ [pbs_cmp_retry][dq],
+ pup) == 0)) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - PbsCurrVal: ");
+ DEBUG_PBS_FULL_D(pbs_curr_val, 2);
+ DEBUG_PBS_FULL_S(" PUP: ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_S(" DQ: ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S(" - failed\n");
+ }
+ }
+ }
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ unlock_pup_dq_array[dq] &=
+ cmp_unlock_pup_dq_array[pbs_cmp_retry][dq];
+ }
+ }
+
+ pup_locked = 0;
+ sum_pup_fail = *pcur_pup;
+
+ /* Check which DQ is failed */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ /* Summarize the locked pup */
+ pup_locked |= unlock_pup_dq_array[dq];
+
+ /* Check if get fail */
+ sum_pup_fail &= unlock_pup_dq_array[dq];
+ }
+
+ /* If all PUPS are locked in all DQ - Break */
+ if (pup_locked == 0) {
+ /* All pups are locked */
+ *start_over = 0;
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - All bit in all pups are successfully locked\n");
+ break;
+ }
+
+ /* PBS deskew elements reach max ? */
+ if (pbs_curr_val == last_pbs) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - PBS deskew elements reach max\n");
+ /* CHIP-ONLY! - Implementation Limitation */
+ *start_over = (sum_pup_fail != 0) && (!(*start_over));
+ *pcur_pup = pup_locked;
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - StartOver: ");
+ DEBUG_PBS_FULL_D(*start_over, 1);
+ DEBUG_PBS_FULL_S(" pup_locked: ");
+ DEBUG_PBS_FULL_D(pup_locked, 2);
+ DEBUG_PBS_FULL_S(" sum_pup_fail: ");
+ DEBUG_PBS_FULL_D(sum_pup_fail, 2);
+ DEBUG_PBS_FULL_S("\n");
+
+ /* Lock PBS value for all remaining bits */
+ for (pup = 0; pup < max_pup; pup++) {
+ /* Check if current pup already received error */
+ if (IS_PUP_ACTIVE(pup_locked, pup) == 1) {
+ /* Valid pup for current function */
+ if (IS_PUP_ACTIVE(sum_pup_fail, pup) ==
+ 1 && (*start_over == 1)) {
+ DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - skipping lock of pup (first loop of pbs)",
+ pup, 1);
+ continue;
+ } else
+ if (IS_PUP_ACTIVE(sum_pup_fail, pup)
+ == 1) {
+ DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - Locking pup %d (even though it wasn't supposed to be locked)",
+ pup, 1);
+ }
+
+ /* Already got fail on the PUP */
+ /* Lock PBS value for all remaining bits */
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Locking remaning DQs for pup - ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_S(": ");
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if (IS_PUP_ACTIVE
+ (unlock_pup_dq_array[dq],
+ pup) == 1) {
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S(",");
+ /* set current PBS */
+ skew_array[((pup) *
+ DQ_NUM) +
+ dq] =
+ pbs_curr_val;
+ }
+ }
+
+ if (*start_over == 1) {
+ /*
+ * Reset this pup bit - when
+ * restart the PBS, ignore this
+ * pup
+ */
+ *pcur_pup &= ~(1 << pup);
+ }
+ DEBUG_PBS_FULL_S("\n");
+ } else {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - Pup ");
+ DEBUG_PBS_FULL_D(pup, 1);
+ DEBUG_PBS_FULL_C(" is not set in puplocked - ",
+ pup_locked, 1);
+ }
+ }
+
+ /* Need to start the PBS again */
+ if (*start_over == 1) {
+ DEBUG_PBS_FULL_S("DDR3 - PBS Per bit - false fail - returning to start\n");
+ return MV_OK;
+ }
+ break;
+ }
+
+ /* Diff Check */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (IS_PUP_ACTIVE(pup_locked, pup) == 1) {
+ /* pup is not locked */
+ if (first_failed[pup] == 0) {
+ /* No first fail until now */
+ if (IS_PUP_ACTIVE(sum_pup_fail, pup) ==
+ 0) {
+ /* Get first fail */
+ DEBUG_PBS_FULL_C("DDR3 - PBS Per bit - First fail in pup ",
+ pup, 1);
+ first_failed[pup] = 1;
+ first_fail[pup] = pbs_curr_val;
+ }
+ } else {
+ /* Already got first fail */
+ if (is_tx == 1) {
+ /* TX - inc pbs */
+ calc_pbs_diff = pbs_curr_val -
+ first_fail[pup];
+ } else {
+ /* RX - dec pbs */
+ calc_pbs_diff = first_fail[pup] -
+ pbs_curr_val;
+ }
+
+ if (calc_pbs_diff >= PBS_DIFF_LIMIT) {
+ lock_pups(pup, &pup_locked,
+ unlock_pup_dq_array,
+ pbs_curr_val,
+ start_pbs, ecc, is_tx);
+ }
+ }
+ }
+ }
+ } while (1);
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_set_pbs_results
+ * Desc: Set to HW the PBS phase results.
+ * Args: is_tx Indicates whether to set Tx or RX results
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static int ddr3_set_pbs_results(MV_DRAM_INFO *dram_info, int is_tx)
+{
+ u32 pup, phys_pup, dq;
+ u32 max_pup; /* number of valid pups */
+ u32 pbs_min; /* minimal pbs val per pup */
+ u32 pbs_max; /* maximum pbs val per pup */
+ u32 val[9];
+
+ max_pup = dram_info->num_of_total_pups;
+ DEBUG_PBS_FULL_S("DDR3 - PBS - ddr3_set_pbs_results:\n");
+
+ /* Loop for all dqs & pups */
+ for (pup = 0; pup < max_pup; pup++) {
+ if (pup == (max_pup - 1) && dram_info->ecc_ena)
+ phys_pup = ECC_PUP;
+ else
+ phys_pup = pup;
+
+ /*
+ * To minimize delay elements, inc from pbs value the min
+ * pbs val
+ */
+ pbs_min = MAX_PBS;
+ pbs_max = 0;
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ if (pbs_min > skew_array[(pup * DQ_NUM) + dq])
+ pbs_min = skew_array[(pup * DQ_NUM) + dq];
+
+ if (pbs_max < skew_array[(pup * DQ_NUM) + dq])
+ pbs_max = skew_array[(pup * DQ_NUM) + dq];
+ }
+
+ pbs_max -= pbs_min;
+
+ DEBUG_PBS_FULL_S("DDR3 - PBS - PUP");
+ DEBUG_PBS_FULL_D(phys_pup, 1);
+ DEBUG_PBS_FULL_S(": Min Val = ");
+ DEBUG_PBS_FULL_D(pbs_min, 2);
+ DEBUG_PBS_FULL_C(", Max Val = ", pbs_max, 2);
+
+ val[pup] = 0;
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ int idx;
+ int offs;
+
+ /* Set skew value for all dq */
+ /*
+ * Bit# Deskew <- Bit# Deskew - last / first
+ * failing bit Deskew For all bits (per PUP)
+ * (minimize delay elements)
+ */
+
+ DEBUG_PBS_FULL_S("DQ");
+ DEBUG_PBS_FULL_D(dq, 1);
+ DEBUG_PBS_FULL_S("-");
+ DEBUG_PBS_FULL_D((skew_array[(pup * DQ_NUM) + dq] -
+ pbs_min), 2);
+ DEBUG_PBS_FULL_S(", ");
+
+ idx = (pup * DQ_NUM) + dq;
+
+ if (is_tx == 1)
+ offs = PUP_PBS_TX;
+ else
+ offs = PUP_PBS_RX;
+
+ ddr3_write_pup_reg(offs + pbs_dq_mapping[phys_pup][dq],
+ CS0, phys_pup, 0,
+ skew_array[idx] - pbs_min);
+
+ if (is_tx == 1)
+ val[pup] += skew_array[idx] - pbs_min;
+ }
+
+ DEBUG_PBS_FULL_S("\n");
+
+ /* Set the DQS the half of the Max PBS of the DQs */
+ if (is_tx == 1) {
+ ddr3_write_pup_reg(PUP_PBS_TX + 8, CS0, phys_pup, 0,
+ pbs_max / 2);
+ ddr3_write_pup_reg(PUP_PBS_TX + 0xa, CS0, phys_pup, 0,
+ val[pup] / 8);
+ } else
+ ddr3_write_pup_reg(PUP_PBS_RX + 8, CS0, phys_pup, 0,
+ pbs_max / 2);
+ }
+
+ return MV_OK;
+}
+
+static void ddr3_pbs_write_pup_dqs_reg(u32 cs, u32 pup, u32 dqs_delay)
+{
+ u32 reg, delay;
+
+ reg = (ddr3_read_pup_reg(PUP_WL_MODE, cs, pup) & 0x3FF);
+ delay = reg & PUP_DELAY_MASK;
+ reg |= ((dqs_delay + delay) << REG_PHY_DQS_REF_DLY_OFFS);
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg |= (pup << REG_PHY_PUP_OFFS);
+ reg |= ((0x4 * cs + PUP_WL_MODE) << REG_PHY_CS_OFFS);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ do {
+ reg = reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+
+ udelay(10);
+}
+
+/*
+ * Set training patterns
+ */
+int ddr3_load_pbs_patterns(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, cs_count, cs_tmp;
+ u32 sdram_addr;
+ u32 *pattern_ptr0, *pattern_ptr1;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr0 = (u32 *)&pbs_pattern[0];
+ pattern_ptr1 = (u32 *)&pbs_pattern[1];
+ break;
+#endif
+ case 32:
+ pattern_ptr0 = (u32 *)&pbs_pattern_32b[0];
+ pattern_ptr1 = (u32 *)&pbs_pattern_32b[1];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr0 = (u32 *)&pbs_pattern_64b[0];
+ pattern_ptr1 = (u32 *)&pbs_pattern_64b[1];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ /* Loop for each CS */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ cs_count = 0;
+ for (cs_tmp = 0; cs_tmp < cs; cs_tmp++) {
+ if (dram_info->cs_ena & (1 << cs_tmp))
+ cs_count++;
+ }
+
+ /* Init PBS I pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_PBS_I_OFFS);
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, (u32) NULL, NULL,
+ pattern_ptr0, LEN_STD_PATTERN,
+ sdram_addr, 1, 0, NULL,
+ 0))
+ return MV_FAIL;
+
+ /* Init PBS II pattern */
+ sdram_addr = (cs_count * (SDRAM_CS_SIZE + 1) +
+ SDRAM_PBS_II_OFFS);
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, (u32) NULL, NULL,
+ pattern_ptr1, LEN_STD_PATTERN,
+ sdram_addr, 1, 0, NULL,
+ 0))
+ return MV_FAIL;
+ }
+ }
+
+ return MV_OK;
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_read_leveling.c b/drivers/ddr/mvebu/ddr3_read_leveling.c
new file mode 100644
index 0000000..4662bde
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_read_leveling.c
@@ -0,0 +1,1214 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_RL_C(s, d, l) \
+ DEBUG_RL_S(s); DEBUG_RL_D(d, l); DEBUG_RL_S("\n")
+#define DEBUG_RL_FULL_C(s, d, l) \
+ DEBUG_RL_FULL_S(s); DEBUG_RL_FULL_D(d, l); DEBUG_RL_FULL_S("\n")
+
+#ifdef MV_DEBUG_RL
+#define DEBUG_RL_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_RL_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+#else
+#define DEBUG_RL_S(s)
+#define DEBUG_RL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_RL_FULL
+#define DEBUG_RL_FULL_S(s) puts(s)
+#define DEBUG_RL_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_RL_FULL_S(s)
+#define DEBUG_RL_FULL_D(d, l)
+#endif
+
+extern u32 rl_pattern[LEN_STD_PATTERN];
+
+#ifdef RL_MODE
+static int ddr3_read_leveling_single_cs_rl_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info);
+#else
+static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info);
+#endif
+
+/*
+ * Name: ddr3_read_leveling_hw
+ * Desc: Execute the Read leveling phase by HW
+ * Args: dram_info - main struct
+ * freq - current sequence frequency
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_read_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info)
+{
+ u32 reg;
+
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_RL_S("DDR3 - Read Leveling - Starting HW RL procedure\n");
+
+ /* Start Auto Read Leveling procedure */
+ reg = 1 << REG_DRAM_TRAINING_RL_OFFS;
+ /* Config the retest number */
+ reg |= (COUNT_HW_RL << REG_DRAM_TRAINING_RETEST_OFFS);
+
+ /* Enable CS in the automatic process */
+ reg |= (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS);
+
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+ /* Wait */
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Check if Successful */
+ if (reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+ u32 delay, phase, pup, cs;
+
+ dram_info->rl_max_phase = 0;
+ dram_info->rl_min_phase = 10;
+
+ /* Read results to arrays */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ reg =
+ ddr3_read_pup_reg(PUP_RL_MODE, cs,
+ pup);
+ phase = (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ delay = reg & PUP_DELAY_MASK;
+ dram_info->rl_val[cs][pup][P] = phase;
+ if (phase > dram_info->rl_max_phase)
+ dram_info->rl_max_phase = phase;
+ if (phase < dram_info->rl_min_phase)
+ dram_info->rl_min_phase = phase;
+ dram_info->rl_val[cs][pup][D] = delay;
+ dram_info->rl_val[cs][pup][S] =
+ RL_FINAL_STATE;
+ reg =
+ ddr3_read_pup_reg(PUP_RL_MODE + 0x1,
+ cs, pup);
+ dram_info->rl_val[cs][pup][DQS] =
+ (reg & 0x3F);
+ }
+#ifdef MV_DEBUG_RL
+ /* Print results */
+ DEBUG_RL_C("DDR3 - Read Leveling - Results for CS - ",
+ (u32) cs, 1);
+
+ for (pup = 0;
+ pup < (dram_info->num_of_total_pups);
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ DEBUG_RL_S("DDR3 - Read Leveling - PUP: ");
+ DEBUG_RL_D((u32) pup, 1);
+ DEBUG_RL_S(", Phase: ");
+ DEBUG_RL_D((u32) dram_info->
+ rl_val[cs][pup][P], 1);
+ DEBUG_RL_S(", Delay: ");
+ DEBUG_RL_D((u32) dram_info->
+ rl_val[cs][pup][D], 2);
+ DEBUG_RL_S("\n");
+ }
+#endif
+ }
+ }
+
+ dram_info->rd_rdy_dly =
+ reg_read(REG_READ_DATA_READY_DELAYS_ADDR) &
+ REG_READ_DATA_SAMPLE_DELAYS_MASK;
+ dram_info->rd_smpl_dly =
+ reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR) &
+ REG_READ_DATA_READY_DELAYS_MASK;
+#ifdef MV_DEBUG_RL
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Sample Delay: ",
+ dram_info->rd_smpl_dly, 2);
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Ready Delay: ",
+ dram_info->rd_rdy_dly, 2);
+ DEBUG_RL_S("DDR3 - Read Leveling - HW RL Ended Successfully\n");
+#endif
+ return MV_OK;
+
+ } else {
+ DEBUG_RL_S("DDR3 - Read Leveling - HW RL Error\n");
+ return MV_FAIL;
+ }
+}
+
+/*
+ * Name: ddr3_read_leveling_sw
+ * Desc: Execute the Read leveling phase by SW
+ * Args: dram_info - main struct
+ * freq - current sequence frequency
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_read_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, cs, ecc, pup_num, phase, delay, pup;
+ int status;
+
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_RL_S("DDR3 - Read Leveling - Starting SW RL procedure\n");
+
+ /* Enable SW Read Leveling */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_RL_MODE_OFFS);
+ /* [0]=1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+#ifdef RL_MODE
+ reg = (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+#endif
+
+ /* Loop for each CS */
+ for (cs = 0; cs < dram_info->num_cs; cs++) {
+ DEBUG_RL_C("DDR3 - Read Leveling - CS - ", (u32) cs, 1);
+
+ for (ecc = 0; ecc <= (dram_info->ecc_ena); ecc++) {
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg |= (dram_info->ecc_ena *
+ ecc << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ if (ecc)
+ DEBUG_RL_S("DDR3 - Read Leveling - ECC Mux Enabled\n");
+ else
+ DEBUG_RL_S("DDR3 - Read Leveling - ECC Mux Disabled\n");
+
+ /* Set current sample delays */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg |= (dram_info->cl <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+
+ /* Set current Ready delay */
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ reg |= ((dram_info->cl + 1) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ } else {
+ /* 2:1 mode */
+ reg |= ((dram_info->cl + 2) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ }
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+
+ /* Read leveling Single CS[cs] */
+#ifdef RL_MODE
+ status =
+ ddr3_read_leveling_single_cs_rl_mode(cs, freq,
+ ratio_2to1,
+ ecc,
+ dram_info);
+ if (MV_OK != status)
+ return status;
+#else
+ status =
+ ddr3_read_leveling_single_cs_window_mode(cs, freq,
+ ratio_2to1,
+ ecc,
+ dram_info)
+ if (MV_OK != status)
+ return status;
+#endif
+ }
+
+ /* Print results */
+ DEBUG_RL_C("DDR3 - Read Leveling - Results for CS - ", (u32) cs,
+ 1);
+
+ for (pup = 0;
+ pup < (dram_info->num_of_std_pups + dram_info->ecc_ena);
+ pup++) {
+ DEBUG_RL_S("DDR3 - Read Leveling - PUP: ");
+ DEBUG_RL_D((u32) pup, 1);
+ DEBUG_RL_S(", Phase: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][P], 1);
+ DEBUG_RL_S(", Delay: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][D], 2);
+ DEBUG_RL_S("\n");
+ }
+
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Sample Delay: ",
+ dram_info->rd_smpl_dly, 2);
+ DEBUG_RL_C("DDR3 - Read Leveling - Read Ready Delay: ",
+ dram_info->rd_rdy_dly, 2);
+
+ /* Configure PHY with average of 3 locked leveling settings */
+ for (pup = 0;
+ pup < (dram_info->num_of_std_pups + dram_info->ecc_ena);
+ pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ? ECC_BIT : pup;
+
+ /* For now, set last cnt result */
+ phase = dram_info->rl_val[cs][pup][P];
+ delay = dram_info->rl_val[cs][pup][D];
+ ddr3_write_pup_reg(PUP_RL_MODE, cs, pup_num, phase,
+ delay);
+ }
+ }
+
+ /* Reset PHY read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* ECC Support - Switch ECC Mux off ecc=0 */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+#ifdef RL_MODE
+ reg_write(REG_DRAM_TRAINING_ADDR, 0); /* 0x15B0 - Training Register */
+#endif
+
+ /* Disable SW Read Leveling */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 0 - Disable SW override */
+ reg = (reg | (0x1 << REG_DRAM_TRAINING_2_RL_MODE_OFFS));
+ /* [3] = 1 - Disable RL MODE */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ DEBUG_RL_S("DDR3 - Read Leveling - Finished RL procedure for all CS\n");
+ return MV_OK;
+}
+
+#ifdef RL_MODE
+/*
+ * overrun() extracted from ddr3_read_leveling_single_cs_rl_mode().
+ * This just got too much indented making it hard to read / edit.
+ */
+static void overrun(u32 cs, MV_DRAM_INFO *info, u32 pup, u32 locked_pups,
+ u32 *locked_sum, u32 ecc, int *first_octet_locked,
+ int *counter_in_progress, int final_delay, u32 delay,
+ u32 phase)
+{
+ /* If no OverRun */
+ if (((~locked_pups >> pup) & 0x1) && (final_delay == 0)) {
+ int idx;
+
+ idx = pup + ecc * ECC_BIT;
+
+ /* PUP passed, start examining */
+ if (info->rl_val[cs][idx][S] == RL_UNLOCK_STATE) {
+ /* Must be RL_UNLOCK_STATE */
+ /* Match expected value ? - Update State Machine */
+ if (info->rl_val[cs][idx][C] < RL_RETRY_COUNT) {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have no overrun and a match on pup: ",
+ (u32)pup, 1);
+ info->rl_val[cs][idx][C]++;
+
+ /* If pup got to last state - lock the delays */
+ if (info->rl_val[cs][idx][C] == RL_RETRY_COUNT) {
+ info->rl_val[cs][idx][C] = 0;
+ info->rl_val[cs][idx][DS] = delay;
+ info->rl_val[cs][idx][PS] = phase;
+
+ /* Go to Final State */
+ info->rl_val[cs][idx][S] = RL_FINAL_STATE;
+ *locked_sum = *locked_sum + 1;
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have locked pup: ",
+ (u32)pup, 1);
+
+ /*
+ * If first lock - need to lock delays
+ */
+ if (*first_octet_locked == 0) {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got first lock on pup: ",
+ (u32)pup, 1);
+ *first_octet_locked = 1;
+ }
+
+ /*
+ * If pup is in not in final state but
+ * there was match - dont increment
+ * counter
+ */
+ } else {
+ *counter_in_progress = 1;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Name: ddr3_read_leveling_single_cs_rl_mode
+ * Desc: Execute Read leveling for single Chip select
+ * Args: cs - current chip select
+ * freq - current sequence frequency
+ * ecc - ecc iteration indication
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_read_leveling_single_cs_rl_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info)
+{
+ u32 reg, delay, phase, pup, rd_sample_delay, add, locked_pups,
+ repeat_max_cnt, sdram_offset, locked_sum;
+ u32 phase_min, ui_max_delay;
+ int all_locked, first_octet_locked, counter_in_progress;
+ int final_delay = 0;
+
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - Single CS - ", (u32) cs, 1);
+
+ /* Init values */
+ phase = 0;
+ delay = 0;
+ rd_sample_delay = dram_info->cl;
+ all_locked = 0;
+ first_octet_locked = 0;
+ repeat_max_cnt = 0;
+ locked_sum = 0;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++)
+ dram_info->rl_val[cs][pup + ecc * ECC_BIT][S] = 0;
+
+ /* Main loop */
+ while (!all_locked) {
+ counter_in_progress = 0;
+
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - RdSmplDly = ");
+ DEBUG_RL_FULL_D(rd_sample_delay, 2);
+ DEBUG_RL_FULL_S(", RdRdyDly = ");
+ DEBUG_RL_FULL_D(dram_info->rd_rdy_dly, 2);
+ DEBUG_RL_FULL_S(", Phase = ");
+ DEBUG_RL_FULL_D(phase, 1);
+ DEBUG_RL_FULL_S(", Delay = ");
+ DEBUG_RL_FULL_D(delay, 2);
+ DEBUG_RL_FULL_S("\n");
+
+ /*
+ * Broadcast to all PUPs current RL delays: DQS phase,
+ * leveling delay
+ */
+ ddr3_write_pup_reg(PUP_RL_MODE, cs, PUP_BC, phase, delay);
+
+ /* Reset PHY read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Read pattern from SDRAM */
+ sdram_offset = cs * (SDRAM_CS_SIZE + 1) + SDRAM_RL_OFFS;
+ locked_pups = 0;
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, 0xFF, &locked_pups,
+ rl_pattern, LEN_STD_PATTERN,
+ sdram_offset, 0, 0, NULL, 0))
+ return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PATTERN;
+
+ /* Octet evaluation */
+ /* pup_num = Q or 1 for ECC */
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+ /* Check Overrun */
+ if (!((reg_read(REG_DRAM_TRAINING_2_ADDR) >>
+ (REG_DRAM_TRAINING_2_OVERRUN_OFFS + pup)) & 0x1)) {
+ overrun(cs, dram_info, pup, locked_pups,
+ &locked_sum, ecc, &first_octet_locked,
+ &counter_in_progress, final_delay,
+ delay, phase);
+ } else {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got overrun on pup: ",
+ (u32)pup, 1);
+ }
+ }
+
+ if (locked_sum == (dram_info->num_of_std_pups *
+ (1 - ecc) + ecc)) {
+ all_locked = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Single Cs - All pups locked\n");
+ }
+
+ /*
+ * This is a fix for unstable condition where pups are
+ * toggling between match and no match
+ */
+ /*
+ * If some of the pups is >1 <3, check if we did it too
+ * many times
+ */
+ if (counter_in_progress == 1) {
+ /* Notify at least one Counter is >=1 and < 3 */
+ if (repeat_max_cnt < RL_RETRY_COUNT) {
+ repeat_max_cnt++;
+ counter_in_progress = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Counter is >=1 and <3\n");
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - So we will not increment the delay to see if locked again\n");
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - repeat_max_cnt reached max so now we will increment the delay\n");
+ counter_in_progress = 0;
+ }
+ }
+
+ /*
+ * Check some of the pups are in the middle of state machine
+ * and don't increment the delays
+ */
+ if (!counter_in_progress && !all_locked) {
+ int idx;
+
+ idx = pup + ecc * ECC_BIT;
+
+ repeat_max_cnt = 0;
+ /* if 1:1 mode */
+ if ((!ratio_2to1) && ((phase == 0) || (phase == 4)))
+ ui_max_delay = MAX_DELAY_INV;
+ else
+ ui_max_delay = MAX_DELAY;
+
+ /* Increment Delay */
+ if (delay < ui_max_delay) {
+ delay++;
+ /*
+ * Mark the last delay/pahse place for
+ * window final place
+ */
+ if (delay == ui_max_delay) {
+ if ((!ratio_2to1 && phase ==
+ MAX_PHASE_RL_L_1TO1)
+ || (ratio_2to1 && phase ==
+ MAX_PHASE_RL_L_2TO1))
+ final_delay = 1;
+ }
+ } else {
+ /* Phase+CL Incrementation */
+ delay = 0;
+
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ if (first_octet_locked) {
+ /* some Pup was Locked */
+ if (phase < MAX_PHASE_RL_L_1TO1) {
+ if (phase == 1) {
+ phase = 4;
+ } else {
+ phase++;
+ delay = MIN_DELAY_PHASE_1_LIMIT;
+ }
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ DEBUG_RL_S("1)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked n");
+ return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK;
+ }
+ } else {
+ /* NO Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_1TO1) {
+ phase++;
+ delay =
+ MIN_DELAY_PHASE_1_LIMIT;
+ } else {
+ phase = 0;
+ }
+ }
+ } else {
+ /* 2:1 mode */
+ if (first_octet_locked) {
+ /* some Pup was Locked */
+ if (phase < MAX_PHASE_RL_L_2TO1) {
+ phase++;
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ DEBUG_RL_S("2)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+ /* pup_num = Q or 1 for ECC */
+ if (dram_info->rl_val[cs][idx][S]
+ == 0) {
+ DEBUG_RL_C("Failed byte is = ",
+ pup, 1);
+ }
+ }
+ return MV_DDR3_TRAINING_ERR_RD_LVL_RL_PUP_UNLOCK;
+ }
+ } else {
+ /* No Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_2TO1)
+ phase++;
+ else
+ phase = 0;
+ }
+ }
+
+ /*
+ * If we finished a full Phases cycle (so now
+ * phase = 0, need to increment rd_sample_dly
+ */
+ if (phase == 0 && first_octet_locked == 0) {
+ rd_sample_delay++;
+ if (rd_sample_delay == 0x10) {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ DEBUG_RL_S("3)DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc); pup++) {
+ /* pup_num = Q or 1 for ECC */
+ if (dram_info->
+ rl_val[cs][idx][S] == 0) {
+ DEBUG_RL_C("Failed byte is = ",
+ pup, 1);
+ }
+ }
+ return MV_DDR3_TRAINING_ERR_RD_LVL_PUP_UNLOCK;
+ }
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK
+ << (REG_READ_DATA_SAMPLE_DELAYS_OFFS
+ * cs));
+ reg |= (rd_sample_delay <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS *
+ cs));
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR,
+ reg);
+ }
+
+ /*
+ * Set current rdReadyDelay according to the
+ * hash table (Need to do this in every phase
+ * change)
+ */
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase) {
+ case 0:
+ add = (add >>
+ REG_TRAINING_DEBUG_2_OFFS);
+ break;
+ case 1:
+ add = (add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 3));
+ break;
+ case 4:
+ add = (add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 6));
+ break;
+ case 5:
+ add = (add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 9));
+ break;
+ }
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ } else {
+ /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >>
+ (phase *
+ REG_TRAINING_DEBUG_3_OFFS));
+ add &= REG_TRAINING_DEBUG_3_MASK;
+ }
+
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((rd_sample_delay + add) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_smpl_dly = rd_sample_delay;
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+ }
+
+ /* Reset counters for pups with states<RD_STATE_COUNT */
+ for (pup = 0; pup <
+ (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++) {
+ if (dram_info->rl_val[cs][idx][C] < RL_RETRY_COUNT)
+ dram_info->rl_val[cs][idx][C] = 0;
+ }
+ }
+ }
+
+ phase_min = 10;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups); pup++) {
+ if (dram_info->rl_val[cs][pup][PS] < phase_min)
+ phase_min = dram_info->rl_val[cs][pup][PS];
+ }
+
+ /*
+ * Set current rdReadyDelay according to the hash table (Need to
+ * do this in every phase change)
+ */
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase_min) {
+ case 0:
+ add = (add >> REG_TRAINING_DEBUG_2_OFFS);
+ break;
+ case 1:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 3));
+ break;
+ case 4:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 6));
+ break;
+ case 5:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 9));
+ break;
+ }
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ } else {
+ /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >> (phase_min * REG_TRAINING_DEBUG_3_OFFS));
+ add &= REG_TRAINING_DEBUG_3_MASK;
+ }
+
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((rd_sample_delay + add) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+
+ for (cs = 0; cs < dram_info->num_cs; cs++) {
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ reg = ddr3_read_pup_reg(PUP_RL_MODE + 0x1, cs, pup);
+ dram_info->rl_val[cs][pup][DQS] = (reg & 0x3F);
+ }
+ }
+
+ return MV_OK;
+}
+
+#else
+
+/*
+ * Name: ddr3_read_leveling_single_cs_window_mode
+ * Desc: Execute Read leveling for single Chip select
+ * Args: cs - current chip select
+ * freq - current sequence frequency
+ * ecc - ecc iteration indication
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
+ int ratio_2to1, u32 ecc,
+ MV_DRAM_INFO *dram_info)
+{
+ u32 reg, delay, phase, sum, pup, rd_sample_delay, add, locked_pups,
+ repeat_max_cnt, sdram_offset, final_sum, locked_sum;
+ u32 delay_s, delay_e, tmp, phase_min, ui_max_delay;
+ int all_locked, first_octet_locked, counter_in_progress;
+ int final_delay = 0;
+
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - Single CS - ", (u32) cs, 1);
+
+ /* Init values */
+ phase = 0;
+ delay = 0;
+ rd_sample_delay = dram_info->cl;
+ all_locked = 0;
+ first_octet_locked = 0;
+ repeat_max_cnt = 0;
+ sum = 0;
+ final_sum = 0;
+ locked_sum = 0;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++)
+ dram_info->rl_val[cs][pup + ecc * ECC_BIT][S] = 0;
+
+ /* Main loop */
+ while (!all_locked) {
+ counter_in_progress = 0;
+
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - RdSmplDly = ");
+ DEBUG_RL_FULL_D(rd_sample_delay, 2);
+ DEBUG_RL_FULL_S(", RdRdyDly = ");
+ DEBUG_RL_FULL_D(dram_info->rd_rdy_dly, 2);
+ DEBUG_RL_FULL_S(", Phase = ");
+ DEBUG_RL_FULL_D(phase, 1);
+ DEBUG_RL_FULL_S(", Delay = ");
+ DEBUG_RL_FULL_D(delay, 2);
+ DEBUG_RL_FULL_S("\n");
+
+ /*
+ * Broadcast to all PUPs current RL delays: DQS phase,leveling
+ * delay
+ */
+ ddr3_write_pup_reg(PUP_RL_MODE, cs, PUP_BC, phase, delay);
+
+ /* Reset PHY read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ /* Read pattern from SDRAM */
+ sdram_offset = cs * (SDRAM_CS_SIZE + 1) + SDRAM_RL_OFFS;
+ locked_pups = 0;
+ if (MV_OK !=
+ ddr3_sdram_compare(dram_info, 0xFF, &locked_pups,
+ rl_pattern, LEN_STD_PATTERN,
+ sdram_offset, 0, 0, NULL, 0))
+ return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PATTERN;
+
+ /* Octet evaluation */
+ for (pup = 0; pup < (dram_info->num_of_std_pups *
+ (1 - ecc) + ecc); pup++) {
+ /* pup_num = Q or 1 for ECC */
+ int idx;
+
+ idx = pup + ecc * ECC_BIT;
+
+ /* Check Overrun */
+ if (!((reg_read(REG_DRAM_TRAINING_2_ADDR) >>
+ (REG_DRAM_TRAINING_2_OVERRUN_OFFS +
+ pup)) & 0x1)) {
+ /* If no OverRun */
+
+ /* Inside the window */
+ if (dram_info->rl_val[cs][idx][S] == RL_WINDOW_STATE) {
+ /*
+ * Match expected value ? - Update
+ * State Machine
+ */
+ if (((~locked_pups >> pup) & 0x1)
+ && (final_delay == 0)) {
+ /* Match - Still inside the Window */
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got another match inside the window for pup: ",
+ (u32)pup, 1);
+
+ } else {
+ /* We got fail -> this is the end of the window */
+ dram_info->rl_val[cs][idx][DE] = delay;
+ dram_info->rl_val[cs][idx][PE] = phase;
+ /* Go to Final State */
+ dram_info->rl_val[cs][idx][S]++;
+ final_sum++;
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We finished the window for pup: ",
+ (u32)pup, 1);
+ }
+
+ /* Before the start of the window */
+ } else if (dram_info->rl_val[cs][idx][S] ==
+ RL_UNLOCK_STATE) {
+ /* Must be RL_UNLOCK_STATE */
+ /*
+ * Match expected value ? - Update
+ * State Machine
+ */
+ if (dram_info->rl_val[cs][idx][C] <
+ RL_RETRY_COUNT) {
+ if (((~locked_pups >> pup) & 0x1)) {
+ /* Match */
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have no overrun and a match on pup: ",
+ (u32)pup, 1);
+ dram_info->rl_val[cs][idx][C]++;
+
+ /* If pup got to last state - lock the delays */
+ if (dram_info->rl_val[cs][idx][C] ==
+ RL_RETRY_COUNT) {
+ dram_info->rl_val[cs][idx][C] = 0;
+ dram_info->rl_val[cs][idx][DS] =
+ delay;
+ dram_info->rl_val[cs][idx][PS] =
+ phase;
+ dram_info->rl_val[cs][idx][S]++; /* Go to Window State */
+ locked_sum++;
+ /* Will count the pups that got locked */
+
+ /* IF First lock - need to lock delays */
+ if (first_octet_locked == 0) {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got first lock on pup: ",
+ (u32)pup, 1);
+ first_octet_locked
+ =
+ 1;
+ }
+ }
+
+ /* if pup is in not in final state but there was match - dont increment counter */
+ else {
+ counter_in_progress
+ = 1;
+ }
+ }
+ }
+ }
+ } else {
+ DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got overrun on pup: ",
+ (u32)pup, 1);
+ counter_in_progress = 1;
+ }
+ }
+
+ if (final_sum == (dram_info->num_of_std_pups * (1 - ecc) + ecc)) {
+ all_locked = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Single Cs - All pups locked\n");
+ }
+
+ /*
+ * This is a fix for unstable condition where pups are
+ * toggling between match and no match
+ */
+ /*
+ * If some of the pups is >1 <3, check if we did it too many
+ * times
+ */
+ if (counter_in_progress == 1) {
+ if (repeat_max_cnt < RL_RETRY_COUNT) {
+ /* Notify at least one Counter is >=1 and < 3 */
+ repeat_max_cnt++;
+ counter_in_progress = 1;
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - Counter is >=1 and <3\n");
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - So we will not increment the delay to see if locked again\n");
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - repeat_max_cnt reached max so now we will increment the delay\n");
+ counter_in_progress = 0;
+ }
+ }
+
+ /*
+ * Check some of the pups are in the middle of state machine
+ * and don't increment the delays
+ */
+ if (!counter_in_progress && !all_locked) {
+ repeat_max_cnt = 0;
+ if (!ratio_2to1)
+ ui_max_delay = MAX_DELAY_INV;
+ else
+ ui_max_delay = MAX_DELAY;
+
+ /* Increment Delay */
+ if (delay < ui_max_delay) {
+ /* Delay Incrementation */
+ delay++;
+ if (delay == ui_max_delay) {
+ /*
+ * Mark the last delay/pahse place
+ * for window final place
+ */
+ if ((!ratio_2to1
+ && phase == MAX_PHASE_RL_L_1TO1)
+ || (ratio_2to1
+ && phase ==
+ MAX_PHASE_RL_L_2TO1))
+ final_delay = 1;
+ }
+ } else {
+ /* Phase+CL Incrementation */
+ delay = 0;
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ if (first_octet_locked) {
+ /* some pupet was Locked */
+ if (phase < MAX_PHASE_RL_L_1TO1) {
+#ifdef RL_WINDOW_WA
+ if (phase == 0)
+#else
+ if (phase == 1)
+#endif
+ phase = 4;
+ else
+ phase++;
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
+ }
+ } else {
+ /* No Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_1TO1) {
+#ifdef RL_WINDOW_WA
+ if (phase == 0)
+ phase = 4;
+#else
+ phase++;
+#endif
+ } else
+ phase = 0;
+ }
+ } else {
+ /* 2:1 mode */
+ if (first_octet_locked) {
+ /* Some Pup was Locked */
+ if (phase < MAX_PHASE_RL_L_2TO1) {
+ phase++;
+ } else {
+ DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
+ return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
+ }
+ } else {
+ /* No Pup was Locked */
+ if (phase < MAX_PHASE_RL_UL_2TO1)
+ phase++;
+ else
+ phase = 0;
+ }
+ }
+
+ /*
+ * If we finished a full Phases cycle (so
+ * now phase = 0, need to increment
+ * rd_sample_dly
+ */
+ if (phase == 0 && first_octet_locked == 0) {
+ rd_sample_delay++;
+
+ /* Set current rd_sample_delay */
+ reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS
+ * cs));
+ reg |= (rd_sample_delay <<
+ (REG_READ_DATA_SAMPLE_DELAYS_OFFS *
+ cs));
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR,
+ reg);
+ }
+
+ /*
+ * Set current rdReadyDelay according to the
+ * hash table (Need to do this in every phase
+ * change)
+ */
+ if (!ratio_2to1) {
+ /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase) {
+ case 0:
+ add = add >>
+ REG_TRAINING_DEBUG_2_OFFS;
+ break;
+ case 1:
+ add = add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 3);
+ break;
+ case 4:
+ add = add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 6);
+ break;
+ case 5:
+ add = add >>
+ (REG_TRAINING_DEBUG_2_OFFS
+ + 9);
+ break;
+ }
+ } else {
+ /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >> phase *
+ REG_TRAINING_DEBUG_3_OFFS);
+ }
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |= ((rd_sample_delay + add) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_smpl_dly = rd_sample_delay;
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+ }
+
+ /* Reset counters for pups with states<RD_STATE_COUNT */
+ for (pup = 0;
+ pup <
+ (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++) {
+ if (dram_info->rl_val[cs][idx][C] < RL_RETRY_COUNT)
+ dram_info->rl_val[cs][idx][C] = 0;
+ }
+ }
+ }
+
+ phase_min = 10;
+
+ for (pup = 0; pup < (dram_info->num_of_std_pups); pup++) {
+ DEBUG_RL_S("DDR3 - Read Leveling - Window info - PUP: ");
+ DEBUG_RL_D((u32) pup, 1);
+ DEBUG_RL_S(", PS: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PS], 1);
+ DEBUG_RL_S(", DS: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DS], 2);
+ DEBUG_RL_S(", PE: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PE], 1);
+ DEBUG_RL_S(", DE: ");
+ DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DE], 2);
+ DEBUG_RL_S("\n");
+ }
+
+ /* Find center of the window procedure */
+ for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
+ pup++) {
+#ifdef RL_WINDOW_WA
+ if (!ratio_2to1) { /* 1:1 mode */
+ if (dram_info->rl_val[cs][idx][PS] == 4)
+ dram_info->rl_val[cs][idx][PS] = 1;
+ if (dram_info->rl_val[cs][idx][PE] == 4)
+ dram_info->rl_val[cs][idx][PE] = 1;
+
+ delay_s = dram_info->rl_val[cs][idx][PS] *
+ MAX_DELAY_INV + dram_info->rl_val[cs][idx][DS];
+ delay_e = dram_info->rl_val[cs][idx][PE] *
+ MAX_DELAY_INV + dram_info->rl_val[cs][idx][DE];
+
+ tmp = (delay_e - delay_s) / 2 + delay_s;
+ phase = tmp / MAX_DELAY_INV;
+ if (phase == 1) /* 1:1 mode */
+ phase = 4;
+
+ if (phase < phase_min) /* for the read ready delay */
+ phase_min = phase;
+
+ dram_info->rl_val[cs][idx][P] = phase;
+ dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY_INV;
+
+ } else {
+ delay_s = dram_info->rl_val[cs][idx][PS] *
+ MAX_DELAY + dram_info->rl_val[cs][idx][DS];
+ delay_e = dram_info->rl_val[cs][idx][PE] *
+ MAX_DELAY + dram_info->rl_val[cs][idx][DE];
+
+ tmp = (delay_e - delay_s) / 2 + delay_s;
+ phase = tmp / MAX_DELAY;
+
+ if (phase < phase_min) /* for the read ready delay */
+ phase_min = phase;
+
+ dram_info->rl_val[cs][idx][P] = phase;
+ dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
+ }
+#else
+ if (!ratio_2to1) { /* 1:1 mode */
+ if (dram_info->rl_val[cs][idx][PS] > 1)
+ dram_info->rl_val[cs][idx][PS] -= 2;
+ if (dram_info->rl_val[cs][idx][PE] > 1)
+ dram_info->rl_val[cs][idx][PE] -= 2;
+ }
+
+ delay_s = dram_info->rl_val[cs][idx][PS] * MAX_DELAY +
+ dram_info->rl_val[cs][idx][DS];
+ delay_e = dram_info->rl_val[cs][idx][PE] * MAX_DELAY +
+ dram_info->rl_val[cs][idx][DE];
+
+ tmp = (delay_e - delay_s) / 2 + delay_s;
+ phase = tmp / MAX_DELAY;
+ if (!ratio_2to1 && phase > 1) /* 1:1 mode */
+ phase += 2;
+
+ if (phase < phase_min) /* for the read ready delay */
+ phase_min = phase;
+
+ dram_info->rl_val[cs][idx][P] = phase;
+ dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
+#endif
+ }
+
+ /* Set current rdReadyDelay according to the hash table (Need to do this in every phase change) */
+ if (!ratio_2to1) { /* 1:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
+ switch (phase_min) {
+ case 0:
+ add = (add >> REG_TRAINING_DEBUG_2_OFFS);
+ break;
+ case 1:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 3));
+ break;
+ case 4:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 6));
+ break;
+ case 5:
+ add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 9));
+ break;
+ }
+ } else { /* 2:1 mode */
+ add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
+ add = (add >> phase_min * REG_TRAINING_DEBUG_3_OFFS);
+ }
+
+ add &= REG_TRAINING_DEBUG_2_MASK;
+ reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
+ reg &=
+ ~(REG_READ_DATA_READY_DELAYS_MASK <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg |=
+ ((rd_sample_delay + add) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ dram_info->rd_rdy_dly = rd_sample_delay + add;
+
+ for (cs = 0; cs < dram_info->num_cs; cs++) {
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ reg = ddr3_read_pup_reg(PUP_RL_MODE + 0x1, cs, pup);
+ dram_info->rl_val[cs][pup][DQS] = (reg & 0x3F);
+ }
+ }
+
+ return MV_OK;
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_sdram.c b/drivers/ddr/mvebu/ddr3_sdram.c
new file mode 100644
index 0000000..50c1bf8
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_sdram.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+#include "xor.h"
+#include "xor_regs.h"
+
+static void ddr3_flush_l1_line(u32 line);
+
+extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
+extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
+#if defined(MV88F78X60)
+extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
+#endif
+extern u32 pbs_dq_mapping[PUP_NUM_64BIT][DQ_NUM];
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+/* PBS locked dq (per pup) */
+u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
+u32 pbs_locked_dm[MAX_PUP_NUM] = { 0 };
+u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
+
+int per_bit_data[MAX_PUP_NUM][DQ_NUM];
+#endif
+
+static u32 sdram_data[LEN_KILLER_PATTERN] __aligned(32) = { 0 };
+
+static struct crc_dma_desc dma_desc __aligned(32) = { 0 };
+
+#define XOR_TIMEOUT 0x8000000
+
+struct xor_channel_t {
+ struct crc_dma_desc *desc;
+ unsigned long desc_phys_addr;
+};
+
+#define XOR_CAUSE_DONE_MASK(chan) ((0x1 | 0x2) << (chan * 16))
+
+void xor_waiton_eng(int chan)
+{
+ int timeout;
+
+ timeout = 0;
+ while (!(reg_read(XOR_CAUSE_REG(XOR_UNIT(chan))) &
+ XOR_CAUSE_DONE_MASK(XOR_CHAN(chan)))) {
+ if (timeout > XOR_TIMEOUT)
+ goto timeout;
+
+ timeout++;
+ }
+
+ timeout = 0;
+ while (mv_xor_state_get(chan) != MV_IDLE) {
+ if (timeout > XOR_TIMEOUT)
+ goto timeout;
+
+ timeout++;
+ }
+
+ /* Clear int */
+ reg_write(XOR_CAUSE_REG(XOR_UNIT(chan)),
+ ~(XOR_CAUSE_DONE_MASK(XOR_CHAN(chan))));
+
+timeout:
+ return;
+}
+
+static int special_compare_pattern(u32 uj)
+{
+ if ((uj == 30) || (uj == 31) || (uj == 61) || (uj == 62) ||
+ (uj == 93) || (uj == 94) || (uj == 126) || (uj == 127))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Compare code extracted as its used by multiple functions. This
+ * reduces code-size and makes it easier to maintain it. Additionally
+ * the code is not indented that much and therefore easier to read.
+ */
+static void compare_pattern_v1(u32 uj, u32 *pup, u32 *pattern,
+ u32 pup_groups, int debug_dqs)
+{
+ u32 val;
+ u32 uk;
+ u32 var1;
+ u32 var2;
+ __maybe_unused u32 dq;
+
+ if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0xFF)) {
+ for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+ val = CMP_BYTE_SHIFT * uk;
+ var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
+ var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
+
+ if (var1 != var2) {
+ *pup |= (1 << (uk + (PUP_NUM_32BIT *
+ (uj % pup_groups))));
+
+#ifdef MV_DEBUG_DQS
+ if (!debug_dqs)
+ continue;
+
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ val = uk + (PUP_NUM_32BIT *
+ (uj % pup_groups));
+ if (((var1 >> dq) & 0x1) !=
+ ((var2 >> dq) & 0x1))
+ per_bit_data[val][dq] = 1;
+ else
+ per_bit_data[val][dq] = 0;
+ }
+#endif
+ }
+ }
+ }
+}
+
+static void compare_pattern_v2(u32 uj, u32 *pup, u32 *pattern)
+{
+ u32 val;
+ u32 uk;
+ u32 var1;
+ u32 var2;
+
+ if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0x3)) {
+ /* Found error */
+ for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+ val = CMP_BYTE_SHIFT * uk;
+ var1 = (sdram_data[uj] >> val) & CMP_BYTE_MASK;
+ var2 = (pattern[uj] >> val) & CMP_BYTE_MASK;
+ if (var1 != var2)
+ *pup |= (1 << (uk % PUP_NUM_16BIT));
+ }
+ }
+}
+
+/*
+ * Name: ddr3_sdram_compare
+ * Desc: Execute compare per PUP
+ * Args: unlock_pup Bit array of the unlock pups
+ * new_locked_pup Output bit array of the pups with failed compare
+ * pattern Pattern to compare
+ * pattern_len Length of pattern (in bytes)
+ * sdram_offset offset address to the SDRAM
+ * write write to the SDRAM before read
+ * mask compare pattern with mask;
+ * mask_pattern Mask to compare pattern
+ *
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern,
+ int special_compare)
+{
+ u32 uj;
+ __maybe_unused u32 pup_groups;
+ __maybe_unused u32 dq;
+
+#if !defined(MV88F67XX)
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+#endif
+
+ ddr3_reset_phy_read_fifo();
+
+ /* Check if need to write to sdram before read */
+ if (write == 1)
+ ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
+
+ ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
+
+ /* Compare read result to write */
+ for (uj = 0; uj < pattern_len; uj++) {
+ if (special_compare && special_compare_pattern(uj))
+ continue;
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+ compare_pattern_v1(uj, new_locked_pup, pattern, pup_groups, 1);
+#elif defined(MV88F67XX)
+ compare_pattern_v2(uj, new_locked_pup, pattern);
+#endif
+ }
+
+ return MV_OK;
+}
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+/*
+ * Name: ddr3_sdram_dm_compare
+ * Desc: Execute compare per PUP
+ * Args: unlock_pup Bit array of the unlock pups
+ * new_locked_pup Output bit array of the pups with failed compare
+ * pattern Pattern to compare
+ * pattern_len Length of pattern (in bytes)
+ * sdram_offset offset address to the SDRAM
+ * write write to the SDRAM before read
+ * mask compare pattern with mask;
+ * mask_pattern Mask to compare pattern
+ *
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 sdram_offset)
+{
+ u32 uj, uk, var1, var2, pup_groups;
+ u32 val;
+ u32 pup = 0;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ ddr3_dram_sram_burst((u32)pattern, SDRAM_PBS_TX_OFFS,
+ LEN_PBS_PATTERN);
+ ddr3_dram_sram_burst(SDRAM_PBS_TX_OFFS, (u32)sdram_data,
+ LEN_PBS_PATTERN);
+
+ /* Validate the correctness of the results */
+ for (uj = 0; uj < LEN_PBS_PATTERN; uj++)
+ compare_pattern_v1(uj, &pup, pattern, pup_groups, 0);
+
+ /* Test the DM Signals */
+ *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10) = 0x12345678;
+ *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14) = 0x12345678;
+
+ sdram_data[0] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10);
+ sdram_data[1] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14);
+
+ for (uj = 0; uj < 2; uj++) {
+ if (((sdram_data[uj]) != (pattern[uj])) &&
+ (*new_locked_pup != 0xFF)) {
+ for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
+ val = CMP_BYTE_SHIFT * uk;
+ var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
+ var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
+ if (var1 != var2) {
+ *new_locked_pup |= (1 << (uk +
+ (PUP_NUM_32BIT * (uj % pup_groups))));
+ *new_locked_pup |= pup;
+ }
+ }
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_sdram_pbs_compare
+ * Desc: Execute SRAM compare per PUP and DQ.
+ * Args: pup_locked bit array of locked pups
+ * is_tx Indicate whether Rx or Tx
+ * pbs_pattern_idx Index of PBS pattern
+ * pbs_curr_val The PBS value
+ * pbs_lock_val The value to set to locked PBS
+ * skew_array Global array to update with the compare results
+ * ai_unlock_pup_dq_array bit array of the locked / unlocked pups per dq.
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked,
+ int is_tx, u32 pbs_pattern_idx,
+ u32 pbs_curr_val, u32 pbs_lock_val,
+ u32 *skew_array, u8 *unlock_pup_dq_array,
+ u32 ecc)
+{
+ /* bit array failed dq per pup for current compare */
+ u32 pbs_write_pup[DQ_NUM] = { 0 };
+ u32 update_pup; /* pup as HW convention */
+ u32 max_pup; /* maximal pup index */
+ u32 pup_addr;
+ u32 ui, dq, pup;
+ int var1, var2;
+ u32 sdram_offset, pup_groups, tmp_pup;
+ u32 *pattern_ptr;
+ u32 val;
+
+ /* Choose pattern */
+ switch (dram_info->ddr_width) {
+#if defined(MV88F672X)
+ case 16:
+ pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
+ break;
+#endif
+ case 32:
+ pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
+ break;
+#if defined(MV88F78X60)
+ case 64:
+ pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
+ break;
+#endif
+ default:
+ return MV_FAIL;
+ }
+
+ max_pup = dram_info->num_of_std_pups;
+
+ sdram_offset = SDRAM_PBS_I_OFFS + pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ ddr3_reset_phy_read_fifo();
+
+ /* Check if need to write to sdram before read */
+ if (is_tx == 1) {
+ ddr3_dram_sram_burst((u32)pattern_ptr, sdram_offset,
+ LEN_PBS_PATTERN);
+ }
+
+ ddr3_dram_sram_read(sdram_offset, (u32)sdram_data, LEN_PBS_PATTERN);
+
+ /* Compare read result to write */
+ for (ui = 0; ui < LEN_PBS_PATTERN; ui++) {
+ if ((sdram_data[ui]) != (pattern_ptr[ui])) {
+ /* found error */
+ /* error in low pup group */
+ for (pup = 0; pup < PUP_NUM_32BIT; pup++) {
+ val = CMP_BYTE_SHIFT * pup;
+ var1 = ((sdram_data[ui] >> val) &
+ CMP_BYTE_MASK);
+ var2 = ((pattern_ptr[ui] >> val) &
+ CMP_BYTE_MASK);
+
+ if (var1 != var2) {
+ if (dram_info->ddr_width > 16) {
+ tmp_pup = (pup + PUP_NUM_32BIT *
+ (ui % pup_groups));
+ } else {
+ tmp_pup = (pup % PUP_NUM_16BIT);
+ }
+
+ update_pup = (1 << tmp_pup);
+ if (ecc && (update_pup != 0x1))
+ continue;
+
+ /*
+ * Pup is failed - Go over all DQs and
+ * look for failures
+ */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ val = tmp_pup * (1 - ecc) +
+ ecc * ECC_PUP;
+ if (((var1 >> dq) & 0x1) !=
+ ((var2 >> dq) & 0x1)) {
+ if (pbs_locked_dq[val][dq] == 1 &&
+ pbs_locked_value[val][dq] != pbs_curr_val)
+ continue;
+
+ /*
+ * Activate write to
+ * update PBS to
+ * pbs_lock_val
+ */
+ pbs_write_pup[dq] |=
+ update_pup;
+
+ /*
+ * Update the
+ * unlock_pup_dq_array
+ */
+ unlock_pup_dq_array[dq] &=
+ ~update_pup;
+
+ /*
+ * Lock PBS value for
+ * failed bits in
+ * compare operation
+ */
+ skew_array[tmp_pup * DQ_NUM + dq] =
+ pbs_curr_val;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pup_addr = (is_tx == 1) ? PUP_PBS_TX : PUP_PBS_RX;
+
+ /* Set last failed bits PBS to min / max pbs value */
+ for (dq = 0; dq < DQ_NUM; dq++) {
+ for (pup = 0; pup < max_pup; pup++) {
+ if (pbs_write_pup[dq] & (1 << pup)) {
+ val = pup * (1 - ecc) + ecc * ECC_PUP;
+ if (pbs_locked_dq[val][dq] == 1 &&
+ pbs_locked_value[val][dq] != pbs_curr_val)
+ continue;
+
+ /* Mark the dq as locked */
+ pbs_locked_dq[val][dq] = 1;
+ pbs_locked_value[val][dq] = pbs_curr_val;
+ ddr3_write_pup_reg(pup_addr +
+ pbs_dq_mapping[val][dq],
+ CS0, val, 0, pbs_lock_val);
+ }
+ }
+ }
+
+ return MV_OK;
+}
+#endif
+
+/*
+ * Name: ddr3_sdram_direct_compare
+ * Desc: Execute compare per PUP without DMA (no burst mode)
+ * Args: unlock_pup Bit array of the unlock pups
+ * new_locked_pup Output bit array of the pups with failed compare
+ * pattern Pattern to compare
+ * pattern_len Length of pattern (in bytes)
+ * sdram_offset offset address to the SDRAM
+ * write write to the SDRAM before read
+ * mask compare pattern with mask;
+ * auiMaskPatter Mask to compare pattern
+ *
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset,
+ int write, int mask, u32 *mask_pattern)
+{
+ u32 uj, uk, pup_groups;
+ u32 *sdram_addr; /* used to read from SDRAM */
+
+ sdram_addr = (u32 *)sdram_offset;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ /* Check if need to write before read */
+ if (write == 1) {
+ for (uk = 0; uk < pattern_len; uk++) {
+ *sdram_addr = pattern[uk];
+ sdram_addr++;
+ }
+ }
+
+ sdram_addr = (u32 *)sdram_offset;
+
+ for (uk = 0; uk < pattern_len; uk++) {
+ sdram_data[uk] = *sdram_addr;
+ sdram_addr++;
+ }
+
+ /* Compare read result to write */
+ for (uj = 0; uj < pattern_len; uj++) {
+ if (dram_info->ddr_width > 16) {
+ compare_pattern_v1(uj, new_locked_pup, pattern,
+ pup_groups, 0);
+ } else {
+ compare_pattern_v2(uj, new_locked_pup, pattern);
+ }
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_dram_sram_burst
+ * Desc: Read from the SDRAM in burst of 64 bytes
+ * Args: src
+ * dst
+ * Notes: Using the XOR mechanism
+ * Returns: MV_OK if success, other error code if fail.
+ */
+int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len)
+{
+ u32 chan, byte_count, cs_num, byte;
+ struct xor_channel_t channel;
+
+ chan = 0;
+ byte_count = len * 4;
+
+ /* Wait for previous transfer completion */
+ while (mv_xor_state_get(chan) != MV_IDLE)
+ ;
+
+ /* Build the channel descriptor */
+ channel.desc = &dma_desc;
+
+ /* Enable Address Override and set correct src and dst */
+ if (src < SRAM_BASE) {
+ /* src is DRAM CS, dst is SRAM */
+ cs_num = (src / (1 + SDRAM_CS_SIZE));
+ reg_write(XOR_ADDR_OVRD_REG(0, 0),
+ ((cs_num << 1) | (1 << 0)));
+ channel.desc->src_addr0 = (src % (1 + SDRAM_CS_SIZE));
+ channel.desc->dst_addr = dst;
+ } else {
+ /* src is SRAM, dst is DRAM CS */
+ cs_num = (dst / (1 + SDRAM_CS_SIZE));
+ reg_write(XOR_ADDR_OVRD_REG(0, 0),
+ ((cs_num << 25) | (1 << 24)));
+ channel.desc->src_addr0 = (src);
+ channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
+ channel.desc->src_addr0 = src;
+ channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
+ }
+
+ channel.desc->src_addr1 = 0;
+ channel.desc->byte_cnt = byte_count;
+ channel.desc->next_desc_ptr = 0;
+ channel.desc->status = 1 << 31;
+ channel.desc->desc_cmd = 0x0;
+ channel.desc_phys_addr = (unsigned long)&dma_desc;
+
+ ddr3_flush_l1_line((u32)&dma_desc);
+
+ /* Issue the transfer */
+ if (mv_xor_transfer(chan, MV_DMA, channel.desc_phys_addr) != MV_OK)
+ return MV_FAIL;
+
+ /* Wait for completion */
+ xor_waiton_eng(chan);
+
+ if (dst > SRAM_BASE) {
+ for (byte = 0; byte < byte_count; byte += 0x20)
+ cache_inv(dst + byte);
+ }
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_flush_l1_line
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns: MV_OK if success, other error code if fail.
+ */
+static void ddr3_flush_l1_line(u32 line)
+{
+ u32 reg;
+
+#if defined(MV88F672X)
+ reg = 1;
+#else
+ reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR) &
+ (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
+#ifdef MV88F67XX
+ reg = ~reg & (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
+#endif
+#endif
+
+ if (reg) {
+ /* V7 Arch mode */
+ flush_l1_v7(line);
+ flush_l1_v7(line + CACHE_LINE_SIZE);
+ } else {
+ /* V6 Arch mode */
+ flush_l1_v6(line);
+ flush_l1_v6(line + CACHE_LINE_SIZE);
+ }
+}
+
+int ddr3_dram_sram_read(u32 src, u32 dst, u32 len)
+{
+ u32 ui;
+ u32 *dst_ptr, *src_ptr;
+
+ dst_ptr = (u32 *)dst;
+ src_ptr = (u32 *)src;
+
+ for (ui = 0; ui < len; ui++) {
+ *dst_ptr = *src_ptr;
+ dst_ptr++;
+ src_ptr++;
+ }
+
+ return MV_OK;
+}
+
+int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
+ u32 *new_locked_pup, u32 *pattern,
+ u32 pattern_len, u32 sdram_offset, int write,
+ int mask, u32 *mask_pattern,
+ int special_compare)
+{
+ u32 uj, pup_groups;
+
+ if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
+ pup_groups = 2;
+ else
+ pup_groups = 1;
+
+ ddr3_reset_phy_read_fifo();
+
+ /* Check if need to write to sdram before read */
+ if (write == 1)
+ ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
+
+ ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
+
+ /* Compare read result to write */
+ for (uj = 0; uj < pattern_len; uj++) {
+ if (special_compare && special_compare_pattern(uj))
+ continue;
+
+ if (dram_info->ddr_width > 16) {
+ compare_pattern_v1(uj, new_locked_pup, pattern,
+ pup_groups, 1);
+ } else {
+ compare_pattern_v2(uj, new_locked_pup, pattern);
+ }
+ }
+
+ return MV_OK;
+}
+
+void ddr3_reset_phy_read_fifo(void)
+{
+ u32 reg;
+
+ /* reset read FIFO */
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Start Auto Read Leveling procedure */
+ reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
+
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
+
+ /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+
+ /* Clear Auto Read Leveling procedure */
+ reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
+
+ /* 0x15B0 - Training Register */
+ reg_write(REG_DRAM_TRAINING_ADDR, reg);
+}
diff --git a/drivers/ddr/mvebu/ddr3_spd.c b/drivers/ddr/mvebu/ddr3_spd.c
new file mode 100644
index 0000000..f4f94c5
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_spd.c
@@ -0,0 +1,1300 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_init.h"
+
+#if defined(MV88F78X60)
+#include "ddr3_axp_config.h"
+#elif defined(MV88F67XX)
+#include "ddr3_a370_config.h"
+#endif
+
+#if defined(MV88F672X)
+#include "ddr3_a375_config.h"
+#endif
+
+#ifdef DUNIT_SPD
+
+/* DIMM SPD offsets */
+#define SPD_DEV_TYPE_BYTE 2
+
+#define SPD_MODULE_TYPE_BYTE 3
+#define SPD_MODULE_MASK 0xf
+#define SPD_MODULE_TYPE_RDIMM 1
+#define SPD_MODULE_TYPE_UDIMM 2
+
+#define SPD_DEV_DENSITY_BYTE 4
+#define SPD_DEV_DENSITY_MASK 0xf
+
+#define SPD_ROW_NUM_BYTE 5
+#define SPD_ROW_NUM_MIN 12
+#define SPD_ROW_NUM_OFF 3
+#define SPD_ROW_NUM_MASK (7 << SPD_ROW_NUM_OFF)
+
+#define SPD_COL_NUM_BYTE 5
+#define SPD_COL_NUM_MIN 9
+#define SPD_COL_NUM_OFF 0
+#define SPD_COL_NUM_MASK (7 << SPD_COL_NUM_OFF)
+
+#define SPD_MODULE_ORG_BYTE 7
+#define SPD_MODULE_SDRAM_DEV_WIDTH_OFF 0
+#define SPD_MODULE_SDRAM_DEV_WIDTH_MASK (7 << SPD_MODULE_SDRAM_DEV_WIDTH_OFF)
+#define SPD_MODULE_BANK_NUM_MIN 1
+#define SPD_MODULE_BANK_NUM_OFF 3
+#define SPD_MODULE_BANK_NUM_MASK (7 << SPD_MODULE_BANK_NUM_OFF)
+
+#define SPD_BUS_WIDTH_BYTE 8
+#define SPD_BUS_WIDTH_OFF 0
+#define SPD_BUS_WIDTH_MASK (7 << SPD_BUS_WIDTH_OFF)
+#define SPD_BUS_ECC_OFF 3
+#define SPD_BUS_ECC_MASK (3 << SPD_BUS_ECC_OFF)
+
+#define SPD_MTB_DIVIDEND_BYTE 10
+#define SPD_MTB_DIVISOR_BYTE 11
+#define SPD_TCK_BYTE 12
+#define SPD_SUP_CAS_LAT_LSB_BYTE 14
+#define SPD_SUP_CAS_LAT_MSB_BYTE 15
+#define SPD_TAA_BYTE 16
+#define SPD_TWR_BYTE 17
+#define SPD_TRCD_BYTE 18
+#define SPD_TRRD_BYTE 19
+#define SPD_TRP_BYTE 20
+
+#define SPD_TRAS_MSB_BYTE 21
+#define SPD_TRAS_MSB_MASK 0xf
+
+#define SPD_TRC_MSB_BYTE 21
+#define SPD_TRC_MSB_MASK 0xf0
+
+#define SPD_TRAS_LSB_BYTE 22
+#define SPD_TRC_LSB_BYTE 23
+#define SPD_TRFC_LSB_BYTE 24
+#define SPD_TRFC_MSB_BYTE 25
+#define SPD_TWTR_BYTE 26
+#define SPD_TRTP_BYTE 27
+
+#define SPD_TFAW_MSB_BYTE 28
+#define SPD_TFAW_MSB_MASK 0xf
+
+#define SPD_TFAW_LSB_BYTE 29
+#define SPD_OPT_FEATURES_BYTE 30
+#define SPD_THERMAL_REFRESH_OPT_BYTE 31
+
+#define SPD_ADDR_MAP_BYTE 63
+#define SPD_ADDR_MAP_MIRROR_OFFS 0
+
+#define SPD_RDIMM_RC_BYTE 69
+#define SPD_RDIMM_RC_NIBBLE_MASK 0xF
+#define SPD_RDIMM_RC_NUM 16
+
+/* Dimm Memory Type values */
+#define SPD_MEM_TYPE_SDRAM 0x4
+#define SPD_MEM_TYPE_DDR1 0x7
+#define SPD_MEM_TYPE_DDR2 0x8
+#define SPD_MEM_TYPE_DDR3 0xB
+
+#define DIMM_MODULE_MANU_OFFS 64
+#define DIMM_MODULE_MANU_SIZE 8
+#define DIMM_MODULE_VEN_OFFS 73
+#define DIMM_MODULE_VEN_SIZE 25
+#define DIMM_MODULE_ID_OFFS 99
+#define DIMM_MODULE_ID_SIZE 18
+
+/* enumeration for voltage levels. */
+enum dimm_volt_if {
+ TTL_5V_TOLERANT,
+ LVTTL,
+ HSTL_1_5V,
+ SSTL_3_3V,
+ SSTL_2_5V,
+ VOLTAGE_UNKNOWN,
+};
+
+/* enumaration for SDRAM CAS Latencies. */
+enum dimm_sdram_cas {
+ SD_CL_1 = 1,
+ SD_CL_2,
+ SD_CL_3,
+ SD_CL_4,
+ SD_CL_5,
+ SD_CL_6,
+ SD_CL_7,
+ SD_FAULT
+};
+
+/* enumeration for memory types */
+enum memory_type {
+ MEM_TYPE_SDRAM,
+ MEM_TYPE_DDR1,
+ MEM_TYPE_DDR2,
+ MEM_TYPE_DDR3
+};
+
+/* DIMM information structure */
+typedef struct dimm_info {
+ /* DIMM dimensions */
+ u32 num_of_module_ranks;
+ u32 data_width;
+ u32 rank_capacity;
+ u32 num_of_devices;
+
+ u32 sdram_width;
+ u32 num_of_banks_on_each_device;
+ u32 sdram_capacity;
+
+ u32 num_of_row_addr;
+ u32 num_of_col_addr;
+
+ u32 addr_mirroring;
+
+ u32 err_check_type; /* ECC , PARITY.. */
+ u32 type_info; /* DDR2 only */
+
+ /* DIMM timing parameters */
+ u32 supported_cas_latencies;
+ u32 refresh_interval;
+ u32 min_cycle_time;
+ u32 min_row_precharge_time;
+ u32 min_row_active_to_row_active;
+ u32 min_ras_to_cas_delay;
+ u32 min_write_recovery_time; /* DDR3/2 only */
+ u32 min_write_to_read_cmd_delay; /* DDR3/2 only */
+ u32 min_read_to_prech_cmd_delay; /* DDR3/2 only */
+ u32 min_active_to_precharge;
+ u32 min_refresh_recovery; /* DDR3/2 only */
+ u32 min_cas_lat_time;
+ u32 min_four_active_win_delay;
+ u8 dimm_rc[SPD_RDIMM_RC_NUM];
+
+ /* DIMM vendor ID */
+ u32 vendor;
+} MV_DIMM_INFO;
+
+static int ddr3_spd_sum_init(MV_DIMM_INFO *info, MV_DIMM_INFO *sum_info,
+ u32 dimm);
+static u32 ddr3_get_max_val(u32 spd_val, u32 dimm_num, u32 static_val);
+static u32 ddr3_get_min_val(u32 spd_val, u32 dimm_num, u32 static_val);
+static int ddr3_spd_init(MV_DIMM_INFO *info, u32 dimm_addr, u32 dimm_width);
+static u32 ddr3_div(u32 val, u32 divider, u32 sub);
+
+extern u8 spd_data[SPD_SIZE];
+extern u32 odt_config[ODT_OPT];
+extern u16 odt_static[ODT_OPT][MAX_CS];
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+
+#if !(defined(DB_88F6710) || defined(DB_88F6710_PCAC) || defined(RD_88F6710))
+/*
+ * Name: ddr3_get_dimm_num - Find number of dimms and their addresses
+ * Desc:
+ * Args: dimm_addr - array of dimm addresses
+ * Notes:
+ * Returns: None.
+ */
+static u32 ddr3_get_dimm_num(u32 *dimm_addr)
+{
+ u32 dimm_cur_addr;
+ u8 data[3];
+ u32 dimm_num = 0;
+ int ret;
+
+ /* Read the dimm eeprom */
+ for (dimm_cur_addr = MAX_DIMM_ADDR; dimm_cur_addr > MIN_DIMM_ADDR;
+ dimm_cur_addr--) {
+ data[SPD_DEV_TYPE_BYTE] = 0;
+
+ /* Far-End DIMM must be connected */
+ if ((dimm_num == 0) && (dimm_cur_addr < FAR_END_DIMM_ADDR))
+ return 0;
+
+ ret = i2c_read(dimm_cur_addr, 0, 1, (uchar *)data, 3);
+ if (!ret) {
+ if (data[SPD_DEV_TYPE_BYTE] == SPD_MEM_TYPE_DDR3) {
+ dimm_addr[dimm_num] = dimm_cur_addr;
+ dimm_num++;
+ }
+ }
+ }
+
+ return dimm_num;
+}
+#endif
+
+/*
+ * Name: dimmSpdInit - Get the SPD parameters.
+ * Desc: Read the DIMM SPD parameters into given struct parameter.
+ * Args: dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
+ * info - DIMM information structure.
+ * Notes:
+ * Returns: MV_OK if function could read DIMM parameters, 0 otherwise.
+ */
+int ddr3_spd_init(MV_DIMM_INFO *info, u32 dimm_addr, u32 dimm_width)
+{
+ u32 tmp;
+ u32 time_base;
+ int ret;
+ __maybe_unused u32 rc;
+ __maybe_unused u8 vendor_high, vendor_low;
+
+ if (dimm_addr != 0) {
+ memset(spd_data, 0, SPD_SIZE * sizeof(u8));
+
+ ret = i2c_read(dimm_addr, 0, 1, (uchar *)spd_data, SPD_SIZE);
+ if (ret)
+ return MV_DDR3_TRAINING_ERR_TWSI_FAIL;
+ }
+
+ /* Check if DDR3 */
+ if (spd_data[SPD_DEV_TYPE_BYTE] != SPD_MEM_TYPE_DDR3)
+ return MV_DDR3_TRAINING_ERR_TWSI_BAD_TYPE;
+
+ /* Error Check Type */
+ /* No byte for error check in DDR3 SPD, use DDR2 convention */
+ info->err_check_type = 0;
+
+ /* Check if ECC */
+ if ((spd_data[SPD_BUS_WIDTH_BYTE] & 0x18) >> 3)
+ info->err_check_type = 1;
+
+ DEBUG_INIT_FULL_C("DRAM err_check_type ", info->err_check_type, 1);
+ switch (spd_data[SPD_MODULE_TYPE_BYTE]) {
+ case 1:
+ /* support RDIMM */
+ info->type_info = SPD_MODULE_TYPE_RDIMM;
+ break;
+ case 2:
+ /* support UDIMM */
+ info->type_info = SPD_MODULE_TYPE_UDIMM;
+ break;
+ case 11: /* LRDIMM current not supported */
+ default:
+ info->type_info = (spd_data[SPD_MODULE_TYPE_BYTE]);
+ break;
+ }
+
+ /* Size Calculations: */
+
+ /* Number Of Row Addresses - 12/13/14/15/16 */
+ info->num_of_row_addr =
+ (spd_data[SPD_ROW_NUM_BYTE] & SPD_ROW_NUM_MASK) >>
+ SPD_ROW_NUM_OFF;
+ info->num_of_row_addr += SPD_ROW_NUM_MIN;
+ DEBUG_INIT_FULL_C("DRAM num_of_row_addr ", info->num_of_row_addr, 2);
+
+ /* Number Of Column Addresses - 9/10/11/12 */
+ info->num_of_col_addr =
+ (spd_data[SPD_COL_NUM_BYTE] & SPD_COL_NUM_MASK) >>
+ SPD_COL_NUM_OFF;
+ info->num_of_col_addr += SPD_COL_NUM_MIN;
+ DEBUG_INIT_FULL_C("DRAM num_of_col_addr ", info->num_of_col_addr, 1);
+
+ /* Number Of Ranks = number of CS on Dimm - 1/2/3/4 Ranks */
+ info->num_of_module_ranks =
+ (spd_data[SPD_MODULE_ORG_BYTE] & SPD_MODULE_BANK_NUM_MASK) >>
+ SPD_MODULE_BANK_NUM_OFF;
+ info->num_of_module_ranks += SPD_MODULE_BANK_NUM_MIN;
+ DEBUG_INIT_FULL_C("DRAM numOfModuleBanks ", info->num_of_module_ranks,
+ 1);
+
+ /* Data Width - 8/16/32/64 bits */
+ info->data_width =
+ 1 << (3 + (spd_data[SPD_BUS_WIDTH_BYTE] & SPD_BUS_WIDTH_MASK));
+ DEBUG_INIT_FULL_C("DRAM data_width ", info->data_width, 1);
+
+ /* Number Of Banks On Each Device - 8/16/32/64 banks */
+ info->num_of_banks_on_each_device =
+ 1 << (3 + ((spd_data[SPD_DEV_DENSITY_BYTE] >> 4) & 0x7));
+ DEBUG_INIT_FULL_C("DRAM num_of_banks_on_each_device ",
+ info->num_of_banks_on_each_device, 1);
+
+ /* Total SDRAM capacity - 256Mb/512Mb/1Gb/2Gb/4Gb/8Gb/16Gb - MegaBits */
+ info->sdram_capacity =
+ spd_data[SPD_DEV_DENSITY_BYTE] & SPD_DEV_DENSITY_MASK;
+
+ /* Sdram Width - 4/8/16/32 bits */
+ info->sdram_width = 1 << (2 + (spd_data[SPD_MODULE_ORG_BYTE] &
+ SPD_MODULE_SDRAM_DEV_WIDTH_MASK));
+ DEBUG_INIT_FULL_C("DRAM sdram_width ", info->sdram_width, 1);
+
+ /* CS (Rank) Capacity - MB */
+ /*
+ * DDR3 device uiDensity val are: (device capacity/8) *
+ * (Module_width/Device_width)
+ */
+ /* Jedec SPD DDR3 - page 7, Save spd_data in Mb - 2048=2GB */
+ if (dimm_width == 32) {
+ info->rank_capacity =
+ ((1 << info->sdram_capacity) * 256 *
+ (info->data_width / info->sdram_width)) << 16;
+ /* CS size = CS size / 2 */
+ } else {
+ info->rank_capacity =
+ ((1 << info->sdram_capacity) * 256 *
+ (info->data_width / info->sdram_width) * 0x2) << 16;
+ /* 0x2 => 0x100000-1Mbit / 8-bit->byte / 0x10000 */
+ }
+ DEBUG_INIT_FULL_C("DRAM rank_capacity[31] ", info->rank_capacity, 1);
+
+ /* Number of devices includeing Error correction */
+ info->num_of_devices =
+ ((info->data_width / info->sdram_width) *
+ info->num_of_module_ranks) + info->err_check_type;
+ DEBUG_INIT_FULL_C("DRAM num_of_devices ", info->num_of_devices, 1);
+
+ /* Address Mapping from Edge connector to DRAM - mirroring option */
+ info->addr_mirroring =
+ spd_data[SPD_ADDR_MAP_BYTE] & (1 << SPD_ADDR_MAP_MIRROR_OFFS);
+
+ /* Timings - All in ps */
+
+ time_base = (1000 * spd_data[SPD_MTB_DIVIDEND_BYTE]) /
+ spd_data[SPD_MTB_DIVISOR_BYTE];
+
+ /* Minimum Cycle Time At Max CasLatancy */
+ info->min_cycle_time = spd_data[SPD_TCK_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM tCKmin ", info->min_cycle_time, 1);
+
+ /* Refresh Interval */
+ /* No byte for refresh interval in DDR3 SPD, use DDR2 convention */
+ /*
+ * JEDEC param are 0 <= Tcase <= 85: 7.8uSec, 85 <= Tcase
+ * <= 95: 3.9uSec
+ */
+ info->refresh_interval = 7800000; /* Set to 7.8uSec */
+ DEBUG_INIT_FULL_C("DRAM refresh_interval ", info->refresh_interval, 1);
+
+ /* Suported Cas Latencies - DDR 3: */
+
+ /*
+ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
+ *******-******-******-******-******-******-******-*******-*******
+ CAS = 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 *
+ *********************************************************-*******
+ *******-******-******-******-******-******-******-*******-*******
+ * bit15 |bit14 |bit13 |bit12 |bit11 |bit10 | bit9 | bit8 *
+ *******-******-******-******-******-******-******-*******-*******
+ CAS = TBD | 18 | 17 | 16 | 15 | 14 | 13 | 12 *
+ */
+
+ /* DDR3 include 2 byte of CAS support */
+ info->supported_cas_latencies =
+ (spd_data[SPD_SUP_CAS_LAT_MSB_BYTE] << 8) |
+ spd_data[SPD_SUP_CAS_LAT_LSB_BYTE];
+ DEBUG_INIT_FULL_C("DRAM supported_cas_latencies ",
+ info->supported_cas_latencies, 1);
+
+ /* Minimum Cycle Time At Max CasLatancy */
+ info->min_cas_lat_time = (spd_data[SPD_TAA_BYTE] * time_base);
+ /*
+ * This field divided by the cycleTime will give us the CAS latency
+ * to config
+ */
+
+ /*
+ * For DDR3 and DDR2 includes Write Recovery Time field.
+ * Other SDRAM ignore
+ */
+ info->min_write_recovery_time = spd_data[SPD_TWR_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_write_recovery_time ",
+ info->min_write_recovery_time, 1);
+
+ /* Mininmum Ras to Cas Delay */
+ info->min_ras_to_cas_delay = spd_data[SPD_TRCD_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_ras_to_cas_delay ",
+ info->min_ras_to_cas_delay, 1);
+
+ /* Minimum Row Active to Row Active Time */
+ info->min_row_active_to_row_active =
+ spd_data[SPD_TRRD_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_row_active_to_row_active ",
+ info->min_row_active_to_row_active, 1);
+
+ /* Minimum Row Precharge Delay Time */
+ info->min_row_precharge_time = spd_data[SPD_TRP_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_row_precharge_time ",
+ info->min_row_precharge_time, 1);
+
+ /* Minimum Active to Precharge Delay Time - tRAS ps */
+ info->min_active_to_precharge =
+ (spd_data[SPD_TRAS_MSB_BYTE] & SPD_TRAS_MSB_MASK) << 8;
+ info->min_active_to_precharge |= spd_data[SPD_TRAS_LSB_BYTE];
+ info->min_active_to_precharge *= time_base;
+ DEBUG_INIT_FULL_C("DRAM min_active_to_precharge ",
+ info->min_active_to_precharge, 1);
+
+ /* Minimum Refresh Recovery Delay Time - tRFC ps */
+ info->min_refresh_recovery = spd_data[SPD_TRFC_MSB_BYTE] << 8;
+ info->min_refresh_recovery |= spd_data[SPD_TRFC_LSB_BYTE];
+ info->min_refresh_recovery *= time_base;
+ DEBUG_INIT_FULL_C("DRAM min_refresh_recovery ",
+ info->min_refresh_recovery, 1);
+
+ /*
+ * For DDR3 and DDR2 includes Internal Write To Read Command Delay
+ * field.
+ */
+ info->min_write_to_read_cmd_delay = spd_data[SPD_TWTR_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_write_to_read_cmd_delay ",
+ info->min_write_to_read_cmd_delay, 1);
+
+ /*
+ * For DDR3 and DDR2 includes Internal Read To Precharge Command Delay
+ * field.
+ */
+ info->min_read_to_prech_cmd_delay = spd_data[SPD_TRTP_BYTE] * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_read_to_prech_cmd_delay ",
+ info->min_read_to_prech_cmd_delay, 1);
+
+ /*
+ * For DDR3 includes Minimum Activate to Activate/Refresh Command
+ * field
+ */
+ tmp = ((spd_data[SPD_TFAW_MSB_BYTE] & SPD_TFAW_MSB_MASK) << 8) |
+ spd_data[SPD_TFAW_LSB_BYTE];
+ info->min_four_active_win_delay = tmp * time_base;
+ DEBUG_INIT_FULL_C("DRAM min_four_active_win_delay ",
+ info->min_four_active_win_delay, 1);
+
+#if defined(MV88F78X60) || defined(MV88F672X)
+ /* Registered DIMM support */
+ if (info->type_info == SPD_MODULE_TYPE_RDIMM) {
+ for (rc = 2; rc < 6; rc += 2) {
+ tmp = spd_data[SPD_RDIMM_RC_BYTE + rc / 2];
+ info->dimm_rc[rc] =
+ spd_data[SPD_RDIMM_RC_BYTE + rc / 2] &
+ SPD_RDIMM_RC_NIBBLE_MASK;
+ info->dimm_rc[rc + 1] =
+ (spd_data[SPD_RDIMM_RC_BYTE + rc / 2] >> 4) &
+ SPD_RDIMM_RC_NIBBLE_MASK;
+ }
+
+ vendor_low = spd_data[66];
+ vendor_high = spd_data[65];
+ info->vendor = (vendor_high << 8) + vendor_low;
+ DEBUG_INIT_C("DDR3 Training Sequence - Registered DIMM vendor ID 0x",
+ info->vendor, 4);
+
+ info->dimm_rc[0] = RDIMM_RC0;
+ info->dimm_rc[1] = RDIMM_RC1;
+ info->dimm_rc[2] = RDIMM_RC2;
+ info->dimm_rc[8] = RDIMM_RC8;
+ info->dimm_rc[9] = RDIMM_RC9;
+ info->dimm_rc[10] = RDIMM_RC10;
+ info->dimm_rc[11] = RDIMM_RC11;
+ }
+#endif
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_spd_sum_init - Get the SPD parameters.
+ * Desc: Read the DIMM SPD parameters into given struct parameter.
+ * Args: dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
+ * info - DIMM information structure.
+ * Notes:
+ * Returns: MV_OK if function could read DIMM parameters, 0 otherwise.
+ */
+int ddr3_spd_sum_init(MV_DIMM_INFO *info, MV_DIMM_INFO *sum_info, u32 dimm)
+{
+ if (dimm == 0) {
+ memcpy(sum_info, info, sizeof(MV_DIMM_INFO));
+ return MV_OK;
+ }
+ if (sum_info->type_info != info->type_info) {
+ DEBUG_INIT_S("DDR3 Dimm Compare - DIMM type does not match - FAIL\n");
+ return MV_DDR3_TRAINING_ERR_DIMM_TYPE_NO_MATCH;
+ }
+ if (sum_info->err_check_type > info->err_check_type) {
+ sum_info->err_check_type = info->err_check_type;
+ DEBUG_INIT_S("DDR3 Dimm Compare - ECC does not match. ECC is disabled\n");
+ }
+ if (sum_info->data_width != info->data_width) {
+ DEBUG_INIT_S("DDR3 Dimm Compare - DRAM bus width does not match - FAIL\n");
+ return MV_DDR3_TRAINING_ERR_BUS_WIDTH_NOT_MATCH;
+ }
+ if (sum_info->min_cycle_time < info->min_cycle_time)
+ sum_info->min_cycle_time = info->min_cycle_time;
+ if (sum_info->refresh_interval < info->refresh_interval)
+ sum_info->refresh_interval = info->refresh_interval;
+ sum_info->supported_cas_latencies &= info->supported_cas_latencies;
+ if (sum_info->min_cas_lat_time < info->min_cas_lat_time)
+ sum_info->min_cas_lat_time = info->min_cas_lat_time;
+ if (sum_info->min_write_recovery_time < info->min_write_recovery_time)
+ sum_info->min_write_recovery_time =
+ info->min_write_recovery_time;
+ if (sum_info->min_ras_to_cas_delay < info->min_ras_to_cas_delay)
+ sum_info->min_ras_to_cas_delay = info->min_ras_to_cas_delay;
+ if (sum_info->min_row_active_to_row_active <
+ info->min_row_active_to_row_active)
+ sum_info->min_row_active_to_row_active =
+ info->min_row_active_to_row_active;
+ if (sum_info->min_row_precharge_time < info->min_row_precharge_time)
+ sum_info->min_row_precharge_time = info->min_row_precharge_time;
+ if (sum_info->min_active_to_precharge < info->min_active_to_precharge)
+ sum_info->min_active_to_precharge =
+ info->min_active_to_precharge;
+ if (sum_info->min_refresh_recovery < info->min_refresh_recovery)
+ sum_info->min_refresh_recovery = info->min_refresh_recovery;
+ if (sum_info->min_write_to_read_cmd_delay <
+ info->min_write_to_read_cmd_delay)
+ sum_info->min_write_to_read_cmd_delay =
+ info->min_write_to_read_cmd_delay;
+ if (sum_info->min_read_to_prech_cmd_delay <
+ info->min_read_to_prech_cmd_delay)
+ sum_info->min_read_to_prech_cmd_delay =
+ info->min_read_to_prech_cmd_delay;
+ if (sum_info->min_four_active_win_delay <
+ info->min_four_active_win_delay)
+ sum_info->min_four_active_win_delay =
+ info->min_four_active_win_delay;
+ if (sum_info->min_write_to_read_cmd_delay <
+ info->min_write_to_read_cmd_delay)
+ sum_info->min_write_to_read_cmd_delay =
+ info->min_write_to_read_cmd_delay;
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_dunit_setup
+ * Desc: Set the controller with the timing values.
+ * Args: ecc_ena - User ECC setup
+ * Notes:
+ * Returns:
+ */
+int ddr3_dunit_setup(u32 ecc_ena, u32 hclk_time, u32 *ddr_width)
+{
+ u32 reg, tmp, cwl;
+ u32 ddr_clk_time;
+ MV_DIMM_INFO dimm_info[2];
+ MV_DIMM_INFO sum_info;
+ u32 stat_val, spd_val;
+ u32 cs, cl, cs_num, cs_ena;
+ u32 dimm_num = 0;
+ int status;
+ u32 rc;
+ __maybe_unused u32 dimm_cnt, cs_count, dimm;
+ __maybe_unused u32 dimm_addr[2] = { 0, 0 };
+
+#if defined(DB_88F6710) || defined(DB_88F6710_PCAC) || defined(RD_88F6710)
+ /* Armada 370 - SPD is not available on DIMM */
+ /*
+ * Set MC registers according to Static SPD values Values -
+ * must be set manually
+ */
+ /*
+ * We only have one optional DIMM for the DB and we already got the
+ * SPD matching values
+ */
+ status = ddr3_spd_init(&dimm_info[0], 0, *ddr_width);
+ if (MV_OK != status)
+ return status;
+
+ dimm_num = 1;
+ /* Use JP8 to enable multiCS support for Armada 370 DB */
+ if (!ddr3_check_config(EEPROM_MODULE_ADDR, CONFIG_MULTI_CS))
+ dimm_info[0].num_of_module_ranks = 1;
+ status = ddr3_spd_sum_init(&dimm_info[0], &sum_info, 0);
+ if (MV_OK != status)
+ return status;
+#else
+ /* Dynamic D-Unit Setup - Read SPD values */
+#ifdef DUNIT_SPD
+ dimm_num = ddr3_get_dimm_num(dimm_addr);
+ if (dimm_num == 0) {
+#ifdef MIXED_DIMM_STATIC
+ DEBUG_INIT_S("DDR3 Training Sequence - No DIMMs detected\n");
+#else
+ DEBUG_INIT_S("DDR3 Training Sequence - FAILED (Wrong DIMMs Setup)\n");
+ return MV_DDR3_TRAINING_ERR_BAD_DIMM_SETUP;
+#endif
+ } else {
+ DEBUG_INIT_C("DDR3 Training Sequence - Number of DIMMs detected: ",
+ dimm_num, 1);
+ }
+
+ for (dimm = 0; dimm < dimm_num; dimm++) {
+ status = ddr3_spd_init(&dimm_info[dimm], dimm_addr[dimm],
+ *ddr_width);
+ if (MV_OK != status)
+ return status;
+ status = ddr3_spd_sum_init(&dimm_info[dimm], &sum_info, dimm);
+ if (MV_OK != status)
+ return status;
+ }
+#endif
+#endif
+
+ /* Set number of enabled CS */
+ cs_num = 0;
+#ifdef DUNIT_STATIC
+ cs_num = ddr3_get_cs_num_from_reg();
+#endif
+#ifdef DUNIT_SPD
+ for (dimm = 0; dimm < dimm_num; dimm++)
+ cs_num += dimm_info[dimm].num_of_module_ranks;
+#endif
+ if (cs_num > MAX_CS) {
+ DEBUG_INIT_C("DDR3 Training Sequence - Number of CS exceed limit - ",
+ MAX_CS, 1);
+ return MV_DDR3_TRAINING_ERR_MAX_CS_LIMIT;
+ }
+
+ /* Set bitmap of enabled CS */
+ cs_ena = 0;
+#ifdef DUNIT_STATIC
+ cs_ena = ddr3_get_cs_ena_from_reg();
+#endif
+#ifdef DUNIT_SPD
+ dimm = 0;
+
+ if (dimm_num) {
+ for (cs = 0; cs < MAX_CS; cs += 2) {
+ if (((1 << cs) & DIMM_CS_BITMAP) &&
+ !(cs_ena & (1 << cs))) {
+ if (dimm_info[dimm].num_of_module_ranks == 1)
+ cs_ena |= (0x1 << cs);
+ else if (dimm_info[dimm].num_of_module_ranks == 2)
+ cs_ena |= (0x3 << cs);
+ else if (dimm_info[dimm].num_of_module_ranks == 3)
+ cs_ena |= (0x7 << cs);
+ else if (dimm_info[dimm].num_of_module_ranks == 4)
+ cs_ena |= (0xF << cs);
+
+ dimm++;
+ if (dimm == dimm_num)
+ break;
+ }
+ }
+ }
+#endif
+
+ if (cs_ena > 0xF) {
+ DEBUG_INIT_C("DDR3 Training Sequence - Number of enabled CS exceed limit - ",
+ MAX_CS, 1);
+ return MV_DDR3_TRAINING_ERR_MAX_ENA_CS_LIMIT;
+ }
+
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - Number of CS = ", cs_num, 1);
+
+ /* Check Ratio - '1' - 2:1, '0' - 1:1 */
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ ddr_clk_time = hclk_time / 2;
+ else
+ ddr_clk_time = hclk_time;
+
+#ifdef DUNIT_STATIC
+ /* Get target CL value from set register */
+ reg = (reg_read(REG_DDR3_MR0_ADDR) >> 2);
+ reg = ((((reg >> 1) & 0xE)) | (reg & 0x1)) & 0xF;
+
+ cl = ddr3_get_max_val(ddr3_div(sum_info.min_cas_lat_time,
+ ddr_clk_time, 0),
+ dimm_num, ddr3_valid_cl_to_cl(reg));
+#else
+ cl = ddr3_div(sum_info.min_cas_lat_time, ddr_clk_time, 0);
+#endif
+ if (cl < 5)
+ cl = 5;
+
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - Cas Latency = ", cl, 1);
+
+ /* {0x00001400} - DDR SDRAM Configuration Register */
+ reg = 0x73004000;
+ stat_val = ddr3_get_static_mc_value(
+ REG_SDRAM_CONFIG_ADDR, REG_SDRAM_CONFIG_ECC_OFFS, 0x1, 0, 0);
+ if (ecc_ena && ddr3_get_min_val(sum_info.err_check_type, dimm_num,
+ stat_val)) {
+ reg |= (1 << REG_SDRAM_CONFIG_ECC_OFFS);
+ reg |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - ECC Enabled\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - ECC Disabled\n");
+ }
+
+ if (sum_info.type_info == SPD_MODULE_TYPE_RDIMM) {
+#ifdef DUNIT_STATIC
+ DEBUG_INIT_S("DDR3 Training Sequence - FAIL - Illegal R-DIMM setup\n");
+ return MV_DDR3_TRAINING_ERR_BAD_R_DIMM_SETUP;
+#endif
+ reg |= (1 << REG_SDRAM_CONFIG_REGDIMM_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - R-DIMM\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - U-DIMM\n");
+ }
+
+#ifndef MV88F67XX
+#ifdef DUNIT_STATIC
+ if (ddr3_get_min_val(sum_info.data_width, dimm_num, BUS_WIDTH) == 64) {
+#else
+ if (*ddr_width == 64) {
+#endif
+ reg |= (1 << REG_SDRAM_CONFIG_WIDTH_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 64Bits\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 32Bits\n");
+ }
+#else
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 16Bits\n");
+#endif
+
+#if defined(MV88F672X)
+ if (*ddr_width == 32) {
+ reg |= (1 << REG_SDRAM_CONFIG_WIDTH_OFFS);
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 32Bits\n");
+ } else {
+ DEBUG_INIT_FULL_S("DDR3 - DUNIT-SET - Datawidth - 16Bits\n");
+ }
+#endif
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_CONFIG_ADDR, 0,
+ REG_SDRAM_CONFIG_RFRS_MASK, 0, 0);
+ tmp = ddr3_get_min_val(sum_info.refresh_interval / hclk_time,
+ dimm_num, stat_val);
+
+#ifdef TREFI_USER_EN
+ tmp = min(TREFI_USER / hclk_time, tmp);
+#endif
+
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - RefreshInterval/Hclk = ", tmp, 4);
+ reg |= tmp;
+
+ if (cl != 3)
+ reg |= (1 << 16); /* If 2:1 need to set P2DWr */
+
+#if defined(MV88F672X)
+ reg |= (1 << 27); /* PhyRfRST = Disable */
+#endif
+ reg_write(REG_SDRAM_CONFIG_ADDR, reg);
+
+ /*{0x00001404} - DDR SDRAM Configuration Register */
+ reg = 0x3630B800;
+#ifdef DUNIT_SPD
+ reg |= (DRAM_2T << REG_DUNIT_CTRL_LOW_2T_OFFS);
+#endif
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+
+ /* {0x00001408} - DDR SDRAM Timing (Low) Register */
+ reg = 0x0;
+
+ /* tRAS - (0:3,20) */
+ spd_val = ddr3_div(sum_info.min_active_to_precharge,
+ ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 0, 0xF, 16, 0x10);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRAS-1 = ", tmp, 1);
+ reg |= (tmp & 0xF);
+ reg |= ((tmp & 0x10) << 16); /* to bit 20 */
+
+ /* tRCD - (4:7) */
+ spd_val = ddr3_div(sum_info.min_ras_to_cas_delay, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 4, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRCD-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 4);
+
+ /* tRP - (8:11) */
+ spd_val = ddr3_div(sum_info.min_row_precharge_time, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 8, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRP-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 8);
+
+ /* tWR - (12:15) */
+ spd_val = ddr3_div(sum_info.min_write_recovery_time, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 12, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tWR-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 12);
+
+ /* tWTR - (16:19) */
+ spd_val = ddr3_div(sum_info.min_write_to_read_cmd_delay, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 16, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tWTR-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 16);
+
+ /* tRRD - (24:27) */
+ spd_val = ddr3_div(sum_info.min_row_active_to_row_active, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 24, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRRD-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 24);
+
+ /* tRTP - (28:31) */
+ spd_val = ddr3_div(sum_info.min_read_to_prech_cmd_delay, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_LOW_ADDR,
+ 28, 0xF, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRTP-1 = ", tmp, 1);
+ reg |= ((tmp & 0xF) << 28);
+
+ if (cl < 7)
+ reg = 0x33137663;
+
+ reg_write(REG_SDRAM_TIMING_LOW_ADDR, reg);
+
+ /*{0x0000140C} - DDR SDRAM Timing (High) Register */
+ /* Add cycles to R2R W2W */
+ reg = 0x39F8FF80;
+
+ /* tRFC - (0:6,16:18) */
+ spd_val = ddr3_div(sum_info.min_refresh_recovery, ddr_clk_time, 1);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_TIMING_HIGH_ADDR,
+ 0, 0x7F, 9, 0x380);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tRFC-1 = ", tmp, 1);
+ reg |= (tmp & 0x7F);
+ reg |= ((tmp & 0x380) << 9); /* to bit 16 */
+ reg_write(REG_SDRAM_TIMING_HIGH_ADDR, reg);
+
+ /*{0x00001410} - DDR SDRAM Address Control Register */
+ reg = 0x000F0000;
+
+ /* tFAW - (24:28) */
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ tmp = sum_info.min_four_active_win_delay;
+ spd_val = ddr3_div(tmp, ddr_clk_time, 0);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_ADDRESS_CTRL_ADDR,
+ 24, 0x3F, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tFAW = ", tmp, 1);
+ reg |= ((tmp & 0x3F) << 24);
+#else
+ tmp = sum_info.min_four_active_win_delay -
+ 4 * (sum_info.min_row_active_to_row_active);
+ spd_val = ddr3_div(tmp, ddr_clk_time, 0);
+ stat_val = ddr3_get_static_mc_value(REG_SDRAM_ADDRESS_CTRL_ADDR,
+ 24, 0x1F, 0, 0);
+ tmp = ddr3_get_max_val(spd_val, dimm_num, stat_val);
+ DEBUG_INIT_FULL_C("DDR3 - DUNIT-SET - tFAW-4*tRRD = ", tmp, 1);
+ reg |= ((tmp & 0x1F) << 24);
+#endif
+
+ /* SDRAM device capacity */
+#ifdef DUNIT_STATIC
+ reg |= (reg_read(REG_SDRAM_ADDRESS_CTRL_ADDR) & 0xF0FFFF);
+#endif
+
+#ifdef DUNIT_SPD
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+ if (dimm_info[dimm_cnt].sdram_capacity < 0x3) {
+ reg |= ((dimm_info[dimm_cnt].sdram_capacity + 1) <<
+ (REG_SDRAM_ADDRESS_SIZE_OFFS +
+ (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs)));
+ } else if (dimm_info[dimm_cnt].sdram_capacity > 0x3) {
+ reg |= ((dimm_info[dimm_cnt].sdram_capacity & 0x3) <<
+ (REG_SDRAM_ADDRESS_SIZE_OFFS +
+ (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs)));
+ reg |= ((dimm_info[dimm_cnt].sdram_capacity & 0x4) <<
+ (REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS + cs));
+ }
+ }
+ }
+
+ /* SDRAM device structure */
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+ if (dimm_info[dimm_cnt].sdram_width == 16)
+ reg |= (1 << (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * cs));
+ }
+ }
+#endif
+ reg_write(REG_SDRAM_ADDRESS_CTRL_ADDR, reg);
+
+ /*{0x00001418} - DDR SDRAM Operation Register */
+ reg = 0xF00;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs))
+ reg &= ~(1 << (cs + REG_SDRAM_OPERATION_CS_OFFS));
+ }
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /*{0x00001420} - DDR SDRAM Extended Mode Register */
+ reg = 0x00000004;
+ reg_write(REG_SDRAM_EXT_MODE_ADDR, reg);
+
+ /*{0x00001424} - DDR Controller Control (High) Register */
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ reg = 0x0000D3FF;
+#else
+ reg = 0x0100D1FF;
+#endif
+ reg_write(REG_DDR_CONT_HIGH_ADDR, reg);
+
+ /*{0x0000142C} - DDR3 Timing Register */
+ reg = 0x014C2F38;
+#if defined(MV88F78X60) || defined(MV88F672X)
+ reg = 0x1FEC2F38;
+#endif
+ reg_write(0x142C, reg);
+
+ /*{0x00001484} - MBus CPU Block Register */
+#ifdef MV88F67XX
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ reg_write(REG_MBUS_CPU_BLOCK_ADDR, 0x0000E907);
+#endif
+
+ /*
+ * In case of mixed dimm and on-board devices setup paramters will
+ * be taken statically
+ */
+ /*{0x00001494} - DDR SDRAM ODT Control (Low) Register */
+ reg = odt_config[cs_ena];
+ reg_write(REG_SDRAM_ODT_CTRL_LOW_ADDR, reg);
+
+ /*{0x00001498} - DDR SDRAM ODT Control (High) Register */
+ reg = 0x00000000;
+ reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+ /*{0x0000149C} - DDR Dunit ODT Control Register */
+ reg = cs_ena;
+ reg_write(REG_DUNIT_ODT_CTRL_ADDR, reg);
+
+ /*{0x000014A0} - DDR Dunit ODT Control Register */
+#if defined(MV88F672X)
+ reg = 0x000006A9;
+ reg_write(REG_DRAM_FIFO_CTRL_ADDR, reg);
+#endif
+
+ /*{0x000014C0} - DRAM address and Control Driving Strenght */
+ reg_write(REG_DRAM_ADDR_CTRL_DRIVE_STRENGTH_ADDR, 0x192435e9);
+
+ /*{0x000014C4} - DRAM Data and DQS Driving Strenght */
+ reg_write(REG_DRAM_DATA_DQS_DRIVE_STRENGTH_ADDR, 0xB2C35E9);
+
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ /*{0x000014CC} - DRAM Main Pads Calibration Machine Control Register */
+ reg = reg_read(REG_DRAM_MAIN_PADS_CAL_ADDR);
+ reg_write(REG_DRAM_MAIN_PADS_CAL_ADDR, reg | (1 << 0));
+#endif
+
+#if defined(MV88F672X)
+ /* DRAM Main Pads Calibration Machine Control Register */
+ /* 0x14CC[4:3] - CalUpdateControl = IntOnly */
+ reg = reg_read(REG_DRAM_MAIN_PADS_CAL_ADDR);
+ reg &= 0xFFFFFFE7;
+ reg |= (1 << 3);
+ reg_write(REG_DRAM_MAIN_PADS_CAL_ADDR, reg);
+#endif
+
+#ifdef DUNIT_SPD
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if ((1 << cs) & DIMM_CS_BITMAP) {
+ if ((1 << cs) & cs_ena) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks ==
+ cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+ reg_write(REG_CS_SIZE_SCRATCH_ADDR + (cs * 0x8),
+ dimm_info[dimm_cnt].rank_capacity - 1);
+ } else {
+ reg_write(REG_CS_SIZE_SCRATCH_ADDR + (cs * 0x8), 0);
+ }
+ }
+ }
+#endif
+
+ /*{0x00020184} - Close FastPath - 2G */
+ reg_write(REG_FASTPATH_WIN_0_CTRL_ADDR, 0);
+
+ /*{0x00001538} - Read Data Sample Delays Register */
+ reg = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs))
+ reg |= (cl << (REG_READ_DATA_SAMPLE_DELAYS_OFFS * cs));
+ }
+
+ reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR, reg);
+ DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Read Data Sample Delays = ", reg,
+ 1);
+
+ /*{0x0000153C} - Read Data Ready Delay Register */
+ reg = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg |= ((cl + 2) <<
+ (REG_READ_DATA_READY_DELAYS_OFFS * cs));
+ }
+ }
+ reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
+ DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Read Data Ready Delays = ", reg, 1);
+
+ /* Set MR registers */
+ /* MR0 */
+ reg = 0x00000600;
+ tmp = ddr3_cl_to_valid_cl(cl);
+ reg |= ((tmp & 0x1) << 2);
+ reg |= ((tmp & 0xE) << 3); /* to bit 4 */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg_write(REG_DDR3_MR0_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* MR1 */
+ reg = 0x00000044 & REG_DDR3_MR1_ODT_MASK;
+ if (cs_num > 1)
+ reg = 0x00000046 & REG_DDR3_MR1_ODT_MASK;
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg |= odt_static[cs_ena][cs];
+ reg_write(REG_DDR3_MR1_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* MR2 */
+ if (reg_read(REG_DDR_IO_ADDR) & (1 << REG_DDR_IO_CLK_RATIO_OFFS))
+ tmp = hclk_time / 2;
+ else
+ tmp = hclk_time;
+
+ if (tmp >= 2500)
+ cwl = 5; /* CWL = 5 */
+ else if (tmp >= 1875 && tmp < 2500)
+ cwl = 6; /* CWL = 6 */
+ else if (tmp >= 1500 && tmp < 1875)
+ cwl = 7; /* CWL = 7 */
+ else if (tmp >= 1250 && tmp < 1500)
+ cwl = 8; /* CWL = 8 */
+ else if (tmp >= 1070 && tmp < 1250)
+ cwl = 9; /* CWL = 9 */
+ else if (tmp >= 935 && tmp < 1070)
+ cwl = 10; /* CWL = 10 */
+ else if (tmp >= 833 && tmp < 935)
+ cwl = 11; /* CWL = 11 */
+ else if (tmp >= 750 && tmp < 833)
+ cwl = 12; /* CWL = 12 */
+ else {
+ cwl = 12; /* CWL = 12 */
+ printf("Unsupported hclk %d MHz\n", tmp);
+ }
+
+ reg = ((cwl - 5) << REG_DDR3_MR2_CWL_OFFS);
+
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg &= REG_DDR3_MR2_ODT_MASK;
+ reg |= odt_dynamic[cs_ena][cs];
+ reg_write(REG_DDR3_MR2_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* MR3 */
+ reg = 0x00000000;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs)) {
+ reg_write(REG_DDR3_MR3_CS_ADDR +
+ (cs << MR_CS_ADDR_OFFS), reg);
+ }
+ }
+
+ /* {0x00001428} - DDR ODT Timing (Low) Register */
+ reg = 0;
+ reg |= (((cl - cwl + 1) & 0xF) << 4);
+ reg |= (((cl - cwl + 6) & 0xF) << 8);
+ reg |= ((((cl - cwl + 6) >> 4) & 0x1) << 21);
+ reg |= (((cl - 1) & 0xF) << 12);
+ reg |= (((cl + 6) & 0x1F) << 16);
+ reg_write(REG_ODT_TIME_LOW_ADDR, reg);
+
+ /* {0x0000147C} - DDR ODT Timing (High) Register */
+ reg = 0x00000071;
+ reg |= ((cwl - 1) << 8);
+ reg |= ((cwl + 5) << 12);
+ reg_write(REG_ODT_TIME_HIGH_ADDR, reg);
+
+#ifdef DUNIT_SPD
+ /*{0x000015E0} - DDR3 Rank Control Register */
+ reg = cs_ena;
+ cs_count = 0;
+ dimm_cnt = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (cs_ena & (1 << cs) & DIMM_CS_BITMAP) {
+ if (dimm_info[dimm_cnt].num_of_module_ranks == cs_count) {
+ dimm_cnt++;
+ cs_count = 0;
+ }
+ cs_count++;
+
+ if (dimm_info[dimm_cnt].addr_mirroring &&
+ (cs == 1 || cs == 3) &&
+ (sum_info.type_info != SPD_MODULE_TYPE_RDIMM)) {
+ reg |= (1 << (REG_DDR3_RANK_CTRL_MIRROR_OFFS + cs));
+ DEBUG_INIT_FULL_C("DDR3 - SPD-SET - Setting Address Mirroring for CS = ",
+ cs, 1);
+ }
+ }
+ }
+ reg_write(REG_DDR3_RANK_CTRL_ADDR, reg);
+#endif
+
+ /*{0xD00015E4} - ZQDS Configuration Register */
+ reg = 0x00203c18;
+ reg_write(REG_ZQC_CONF_ADDR, reg);
+
+ /* {0x00015EC} - DDR PHY */
+#if defined(MV88F78X60)
+ reg = 0xF800AAA5;
+ if (mv_ctrl_rev_get() == MV_78XX0_B0_REV)
+ reg = 0xF800A225;
+#else
+ reg = 0xDE000025;
+#if defined(MV88F672X)
+ reg = 0xF800A225;
+#endif
+#endif
+ reg_write(REG_DRAM_PHY_CONFIG_ADDR, reg);
+
+#if (defined(MV88F78X60) || defined(MV88F672X))
+ /* Registered DIMM support - supported only in AXP A0 devices */
+ /* Currently supported for SPD detection only */
+ /*
+ * Flow is according to the Registered DIMM chapter in the
+ * Functional Spec
+ */
+ if (sum_info.type_info == SPD_MODULE_TYPE_RDIMM) {
+ DEBUG_INIT_S("DDR3 Training Sequence - Registered DIMM detected\n");
+
+ /* Set commands parity completion */
+ reg = reg_read(REG_REGISTERED_DRAM_CTRL_ADDR);
+ reg &= ~REG_REGISTERED_DRAM_CTRL_PARITY_MASK;
+ reg |= 0x8;
+ reg_write(REG_REGISTERED_DRAM_CTRL_ADDR, reg);
+
+ /* De-assert M_RESETn and assert M_CKE */
+ reg_write(REG_SDRAM_INIT_CTRL_ADDR,
+ 1 << REG_SDRAM_INIT_CKE_ASSERT_OFFS);
+ do {
+ reg = (reg_read(REG_SDRAM_INIT_CTRL_ADDR)) &
+ (1 << REG_SDRAM_INIT_CKE_ASSERT_OFFS);
+ } while (reg);
+
+ for (rc = 0; rc < SPD_RDIMM_RC_NUM; rc++) {
+ if (rc != 6 && rc != 7) {
+ /* Set CWA Command */
+ reg = (REG_SDRAM_OPERATION_CMD_CWA &
+ ~(0xF << REG_SDRAM_OPERATION_CS_OFFS));
+ reg |= ((dimm_info[0].dimm_rc[rc] &
+ REG_SDRAM_OPERATION_CWA_DATA_MASK) <<
+ REG_SDRAM_OPERATION_CWA_DATA_OFFS);
+ reg |= rc << REG_SDRAM_OPERATION_CWA_RC_OFFS;
+ /* Configure - Set Delay - tSTAB/tMRD */
+ if (rc == 2 || rc == 10)
+ reg |= (0x1 << REG_SDRAM_OPERATION_CWA_DELAY_SEL_OFFS);
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ /*
+ * Poll the "cmd" field in the SDRAM OP
+ * register for 0x0
+ */
+ do {
+ reg = reg_read(REG_SDRAM_OPERATION_ADDR) &
+ (REG_SDRAM_OPERATION_CMD_MASK);
+ } while (reg);
+ }
+ }
+ }
+#endif
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_div - this function divides integers
+ * Desc:
+ * Args: val - the value
+ * divider - the divider
+ * sub - substruction value
+ * Notes:
+ * Returns: required value
+ */
+u32 ddr3_div(u32 val, u32 divider, u32 sub)
+{
+ return val / divider + (val % divider > 0 ? 1 : 0) - sub;
+}
+
+/*
+ * Name: ddr3_get_max_val
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_max_val(u32 spd_val, u32 dimm_num, u32 static_val)
+{
+#ifdef DUNIT_STATIC
+ if (dimm_num > 0) {
+ if (spd_val >= static_val)
+ return spd_val;
+ else
+ return static_val;
+ } else {
+ return static_val;
+ }
+#else
+ return spd_val;
+#endif
+}
+
+/*
+ * Name: ddr3_get_min_val
+ * Desc:
+ * Args:
+ * Notes:
+ * Returns:
+ */
+u32 ddr3_get_min_val(u32 spd_val, u32 dimm_num, u32 static_val)
+{
+#ifdef DUNIT_STATIC
+ if (dimm_num > 0) {
+ if (spd_val <= static_val)
+ return spd_val;
+ else
+ return static_val;
+ } else
+ return static_val;
+#else
+ return spd_val;
+#endif
+}
+#endif
diff --git a/drivers/ddr/mvebu/ddr3_write_leveling.c b/drivers/ddr/mvebu/ddr3_write_leveling.c
new file mode 100644
index 0000000..df3a3df
--- /dev/null
+++ b/drivers/ddr/mvebu/ddr3_write_leveling.c
@@ -0,0 +1,1366 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "ddr3_hw_training.h"
+
+/*
+ * Debug
+ */
+#define DEBUG_WL_C(s, d, l) \
+ DEBUG_WL_S(s); DEBUG_WL_D(d, l); DEBUG_WL_S("\n")
+#define DEBUG_WL_FULL_C(s, d, l) \
+ DEBUG_WL_FULL_S(s); DEBUG_WL_FULL_D(d, l); DEBUG_WL_FULL_S("\n")
+
+#ifdef MV_DEBUG_WL
+#define DEBUG_RL_S(s) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
+#define DEBUG_RL_D(d, l) \
+ debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
+#else
+#define DEBUG_WL_S(s)
+#define DEBUG_WL_D(d, l)
+#endif
+
+#ifdef MV_DEBUG_WL_FULL
+#define DEBUG_WL_FULL_S(s) puts(s)
+#define DEBUG_WL_FULL_D(d, l) printf("%x", d)
+#else
+#define DEBUG_WL_FULL_S(s)
+#define DEBUG_WL_FULL_D(d, l)
+#endif
+
+#define WL_SUP_EXPECTED_DATA 0x21
+#define WL_SUP_READ_DRAM_ENTRY 0x8
+
+static int ddr3_write_leveling_single_cs(u32 cs, u32 freq, int ratio_2to1,
+ u32 *result,
+ MV_DRAM_INFO *dram_info);
+static void ddr3_write_ctrl_pup_reg(int bc_acc, u32 pup, u32 reg_addr,
+ u32 data);
+
+extern u16 odt_static[ODT_OPT][MAX_CS];
+extern u16 odt_dynamic[ODT_OPT][MAX_CS];
+extern u32 wl_sup_pattern[LEN_WL_SUP_PATTERN];
+
+/*
+ * Name: ddr3_write_leveling_hw
+ * Desc: Execute Write leveling phase by HW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, phase, delay, cs, pup;
+#ifdef MV88F67XX
+ int dpde_flag = 0;
+#endif
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting HW WL procedure\n");
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ reg = 1 << REG_DRAM_TRAINING_WL_OFFS;
+ /* Config the retest number */
+ reg |= (COUNT_HW_WL << REG_DRAM_TRAINING_RETEST_OFFS);
+ reg |= (dram_info->cs_ena << (REG_DRAM_TRAINING_CS_OFFS));
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+ /* Wait */
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Check if Successful */
+ if (reg & (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+ /*
+ * Read results to arrays - Results are required for WL
+ * High freq Supplement and DQS Centralization
+ */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE, cs,
+ pup);
+ phase =
+ (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ delay = reg & PUP_DELAY_MASK;
+ dram_info->wl_val[cs][pup][P] = phase;
+ dram_info->wl_val[cs][pup][D] = delay;
+ dram_info->wl_val[cs][pup][S] =
+ WL_HI_FREQ_STATE - 1;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE + 0x1,
+ cs, pup);
+ dram_info->wl_val[cs][pup][DQS] =
+ (reg & 0x3F);
+ }
+
+#ifdef MV_DEBUG_WL
+ /* Debug message - Print res for cs[i]: cs,PUP,Phase,Delay */
+ DEBUG_WL_S("DDR3 - Write Leveling - Write Leveling Cs - ");
+ DEBUG_WL_D((u32) cs, 1);
+ DEBUG_WL_S(" Results:\n");
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ DEBUG_WL_S("DDR3 - Write Leveling - PUP: ");
+ DEBUG_WL_D((u32) pup, 1);
+ DEBUG_WL_S(", Phase: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [P], 1);
+ DEBUG_WL_S(", Delay: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [D], 2);
+ DEBUG_WL_S("\n");
+ }
+#endif
+ }
+ }
+
+ /* Dynamic pad issue (BTS669) during WL */
+#ifdef MV88F67XX
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+
+ return MV_OK;
+ } else {
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Error\n");
+ return MV_FAIL;
+ }
+}
+
+/*
+ * Name: ddr3_wl_supplement
+ * Desc: Write Leveling Supplement
+ * Args: dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_wl_supplement(MV_DRAM_INFO *dram_info)
+{
+ u32 cs, cnt, pup_num, sum, phase, delay, max_pup_num, pup, sdram_offset;
+ u32 tmp_count, ecc, reg;
+ u32 ddr_width, tmp_pup, idx;
+ u32 sdram_pup_val, uj;
+ u32 one_clk_err = 0, align_err = 0, no_err = 0, err = 0, err_n = 0;
+ u32 sdram_data[LEN_WL_SUP_PATTERN] __aligned(32) = { 0 };
+
+ ddr_width = dram_info->ddr_width;
+ no_err = 0;
+
+ DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - Starting\n");
+
+ switch (ddr_width) {
+ /* Data error from pos-adge to pos-adge */
+ case 16:
+ one_clk_err = 4;
+ align_err = 4;
+ break;
+ case 32:
+ one_clk_err = 8;
+ align_err = 8;
+ break;
+ case 64:
+ one_clk_err = 0x10;
+ align_err = 0x10;
+ break;
+ default:
+ DEBUG_WL_S("Error - bus width!!!\n");
+ return MV_FAIL;
+ }
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - SW Override Enabled\n");
+ reg = (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+ tmp_count = 0;
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ sum = 0;
+ /*
+ * 2 iterations loop: 1)actual WL results 2) fix WL
+ * if needed
+ */
+ for (cnt = 0; cnt < COUNT_WL_HI_FREQ; cnt++) {
+ DEBUG_WL_C("COUNT = ", cnt, 1);
+ for (ecc = 0; ecc < (dram_info->ecc_ena + 1);
+ ecc++) {
+ if (ecc) {
+ DEBUG_WL_S("ECC PUP:\n");
+ } else {
+ DEBUG_WL_S("DATA PUP:\n");
+ }
+
+ max_pup_num =
+ dram_info->num_of_std_pups * (1 -
+ ecc) +
+ ecc;
+ /* ECC Support - Switch ECC Mux on ecc=1 */
+ reg =
+ (reg_read(REG_DRAM_TRAINING_2_ADDR)
+ & ~(1 <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS));
+ reg |=
+ (dram_info->ecc_ena *
+ ecc <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS);
+ reg_write(REG_DRAM_TRAINING_2_ADDR,
+ reg);
+ ddr3_reset_phy_read_fifo();
+
+ /* Write to memory */
+ sdram_offset =
+ tmp_count * (SDRAM_CS_SIZE + 1) +
+ 0x200;
+ if (MV_OK != ddr3_dram_sram_burst((u32)
+ wl_sup_pattern,
+ sdram_offset,
+ LEN_WL_SUP_PATTERN))
+ return MV_FAIL;
+
+ /* Read from memory */
+ if (MV_OK !=
+ ddr3_dram_sram_burst(sdram_offset,
+ (u32)
+ sdram_data,
+ LEN_WL_SUP_PATTERN))
+ return MV_FAIL;
+
+ /* Print the buffer */
+ for (uj = 0; uj < LEN_WL_SUP_PATTERN;
+ uj++) {
+ if ((uj % 4 == 0) && (uj != 0)) {
+ DEBUG_WL_S("\n");
+ }
+ DEBUG_WL_D(sdram_data[uj],
+ 8);
+ DEBUG_WL_S(" ");
+ }
+
+ /* Check pup which DQS/DATA is error */
+ for (pup = 0; pup < max_pup_num; pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (ecc) ? ECC_PUP : pup;
+ if (pup < 4) { /* lower 32 bit */
+ tmp_pup = pup;
+ idx =
+ WL_SUP_READ_DRAM_ENTRY;
+ } else { /* higher 32 bit */
+ tmp_pup = pup - 4;
+ idx =
+ WL_SUP_READ_DRAM_ENTRY
+ + 1;
+ }
+ DEBUG_WL_S("\nCS: ");
+ DEBUG_WL_D((u32) cs, 1);
+ DEBUG_WL_S(" PUP: ");
+ DEBUG_WL_D((u32) pup_num, 1);
+ DEBUG_WL_S("\n");
+ sdram_pup_val =
+ ((sdram_data[idx] >>
+ ((tmp_pup) * 8)) & 0xFF);
+ DEBUG_WL_C("Actual Data = ",
+ sdram_pup_val, 2);
+ DEBUG_WL_C("Expected Data = ",
+ (WL_SUP_EXPECTED_DATA
+ + pup), 2);
+ /*
+ * ALINGHMENT: calculate
+ * expected data vs actual data
+ */
+ err =
+ (WL_SUP_EXPECTED_DATA +
+ pup) - sdram_pup_val;
+ /*
+ * CLOCK LONG: calculate
+ * expected data vs actual data
+ */
+ err_n =
+ sdram_pup_val -
+ (WL_SUP_EXPECTED_DATA +
+ pup);
+ DEBUG_WL_C("err = ", err, 2);
+ DEBUG_WL_C("err_n = ", err_n,
+ 2);
+ if (err == no_err) {
+ /* PUP is correct - increment State */
+ dram_info->wl_val[cs]
+ [pup_num]
+ [S] = 1;
+ } else if (err_n == one_clk_err) {
+ /* clock is longer than DQS */
+ phase =
+ ((dram_info->wl_val
+ [cs]
+ [pup_num][P] +
+ WL_HI_FREQ_SHIFT)
+ % MAX_PHASE_2TO1);
+ dram_info->wl_val[cs]
+ [pup_num]
+ [P] = phase;
+ delay =
+ dram_info->wl_val
+ [cs][pup_num]
+ [D];
+ DEBUG_WL_S("#### Clock is longer than DQS more than one clk cycle ####\n");
+ ddr3_write_pup_reg
+ (PUP_WL_MODE, cs,
+ pup * (1 - ecc) +
+ ECC_PUP * ecc,
+ phase, delay);
+ } else if (err == align_err) {
+ /* clock is align to DQS */
+ phase =
+ dram_info->wl_val
+ [cs][pup_num]
+ [P];
+ delay =
+ dram_info->wl_val
+ [cs][pup_num]
+ [D];
+ DEBUG_WL_S("#### Alignment PUPS problem ####\n");
+ if ((phase == 0)
+ || ((phase == 1)
+ && (delay <=
+ 0x10))) {
+ DEBUG_WL_S("#### Warning - Possible Layout Violation (DQS is longer than CLK)####\n");
+ }
+
+ phase = 0x0;
+ delay = 0x0;
+ dram_info->wl_val[cs]
+ [pup_num]
+ [P] = phase;
+ dram_info->wl_val[cs]
+ [pup_num]
+ [D] = delay;
+ ddr3_write_pup_reg
+ (PUP_WL_MODE, cs,
+ pup * (1 - ecc) +
+ ECC_PUP * ecc,
+ phase, delay);
+ }
+ /* Stop condition for ECC phase */
+ pup = (ecc) ? max_pup_num : pup;
+ }
+
+ /* ECC Support - Disable ECC MUX */
+ reg =
+ (reg_read(REG_DRAM_TRAINING_2_ADDR)
+ & ~(1 <<
+ REG_DRAM_TRAINING_2_ECC_MUX_OFFS));
+ reg_write(REG_DRAM_TRAINING_2_ADDR,
+ reg);
+ }
+ }
+
+ for (pup = 0; pup < dram_info->num_of_std_pups; pup++)
+ sum += dram_info->wl_val[cs][pup][S];
+
+ if (dram_info->ecc_ena)
+ sum += dram_info->wl_val[cs][ECC_PUP][S];
+
+ /* Checks if any pup is not locked after the change */
+ if (sum < (WL_HI_FREQ_STATE * (dram_info->num_of_total_pups))) {
+ DEBUG_WL_C("DDR3 - Write Leveling Hi-Freq Supplement - didn't work for Cs - ",
+ (u32) cs, 1);
+ return MV_FAIL;
+ }
+ tmp_count++;
+ }
+ }
+
+ dram_info->wl_max_phase = 0;
+ dram_info->wl_min_phase = 10;
+
+ /*
+ * Read results to arrays - Results are required for DQS Centralization
+ */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_PUP;
+ reg = ddr3_read_pup_reg(PUP_WL_MODE, cs, pup);
+ phase =
+ (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ if (phase > dram_info->wl_max_phase)
+ dram_info->wl_max_phase = phase;
+ if (phase < dram_info->wl_min_phase)
+ dram_info->wl_min_phase = phase;
+ }
+ }
+ }
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ reg = reg_read(REG_DRAM_TRAINING_1_ADDR) |
+ (1 << REG_DRAM_TRAINING_1_TRNBPOINT_OFFS);
+ reg_write(REG_DRAM_TRAINING_1_ADDR, reg);
+
+ DEBUG_WL_S("DDR3 - Write Leveling Hi-Freq Supplement - Ended Successfully\n");
+
+ return MV_OK;
+}
+
+/*
+ * Name: ddr3_write_leveling_hw_reg_dimm
+ * Desc: Execute Write leveling phase by HW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_hw_reg_dimm(u32 freq, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, phase, delay, cs, pup, pup_num;
+ __maybe_unused int dpde_flag = 0;
+
+ /* Debug message - Start Read leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting HW WL procedure\n");
+
+ if (dram_info->num_cs > 2) {
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+ return MV_NO_CHANGE;
+ }
+
+ /* If target freq = 400 move clock start point */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+ /* PUP_DELAY_MASK 0x1F */
+ /* reg = 0x0C10001F + (uj << 16); */
+ ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+ 0x1F);
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ reg = (1 << REG_DRAM_TRAINING_WL_OFFS);
+ /* Config the retest number */
+ reg |= (COUNT_HW_WL << REG_DRAM_TRAINING_RETEST_OFFS);
+ reg |= (dram_info->cs_ena << (REG_DRAM_TRAINING_CS_OFFS));
+ reg_write(REG_DRAM_TRAINING_ADDR, reg); /* 0x15B0 - Training Register */
+
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);
+
+ /* Wait */
+ do {
+ reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
+ (1 << REG_DRAM_TRAINING_AUTO_OFFS);
+ } while (reg); /* Wait for '0' */
+
+ reg = reg_read(REG_DRAM_TRAINING_ADDR);
+ /* Check if Successful */
+ if (reg & (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
+ /*
+ * Read results to arrays - Results are required for WL High
+ * freq Supplement and DQS Centralization
+ */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ if (pup == dram_info->num_of_std_pups
+ && dram_info->ecc_ena)
+ pup = ECC_BIT;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE, cs,
+ pup);
+ phase =
+ (reg >> REG_PHY_PHASE_OFFS) &
+ PUP_PHASE_MASK;
+ delay = reg & PUP_DELAY_MASK;
+ dram_info->wl_val[cs][pup][P] = phase;
+ dram_info->wl_val[cs][pup][D] = delay;
+ if ((phase == 1) && (delay >= 0x1D)) {
+ /*
+ * Need to do it here for
+ * uncorrect WL values
+ */
+ ddr3_write_pup_reg(PUP_WL_MODE,
+ cs, pup, 0,
+ 0);
+ dram_info->wl_val[cs][pup][P] =
+ 0;
+ dram_info->wl_val[cs][pup][D] =
+ 0;
+ }
+ dram_info->wl_val[cs][pup][S] =
+ WL_HI_FREQ_STATE - 1;
+ reg =
+ ddr3_read_pup_reg(PUP_WL_MODE + 0x1,
+ cs, pup);
+ dram_info->wl_val[cs][pup][DQS] =
+ (reg & 0x3F);
+ }
+#ifdef MV_DEBUG_WL
+ /*
+ * Debug message - Print res for cs[i]:
+ * cs,PUP,Phase,Delay
+ */
+ DEBUG_WL_S("DDR3 - Write Leveling - Write Leveling Cs - ");
+ DEBUG_WL_D((u32) cs, 1);
+ DEBUG_WL_S(" Results:\n");
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ DEBUG_WL_S
+ ("DDR3 - Write Leveling - PUP: ");
+ DEBUG_WL_D((u32) pup, 1);
+ DEBUG_WL_S(", Phase: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [P], 1);
+ DEBUG_WL_S(", Delay: ");
+ DEBUG_WL_D((u32)
+ dram_info->wl_val[cs][pup]
+ [D], 2);
+ DEBUG_WL_S("\n");
+ }
+#endif
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+
+ /* If target freq = 400 move clock back */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups;
+ pup++) {
+ ddr3_write_ctrl_pup_reg(1, pup,
+ CNTRL_PUP_DESKEW + pup, 0);
+ }
+ }
+
+ return MV_OK;
+ } else {
+ /* Configure Each PUP with locked leveling settings */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ for (pup = 0;
+ pup < dram_info->num_of_total_pups;
+ pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ?
+ ECC_BIT : pup;
+ ddr3_write_pup_reg(PUP_WL_MODE, cs,
+ pup_num, 0, 0);
+ }
+ }
+ }
+
+ reg_write(REG_DRAM_TRAINING_ADDR, 0);
+
+ /* If target freq = 400 move clock back */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups;
+ pup++) {
+ ddr3_write_ctrl_pup_reg(1, pup,
+ CNTRL_PUP_DESKEW + pup, 0);
+ }
+ }
+
+ DEBUG_WL_S("DDR3 - Write Leveling - HW WL Ended Successfully\n");
+ return MV_NO_CHANGE;
+ }
+}
+
+/*
+ * Name: ddr3_write_leveling_sw
+ * Desc: Execute Write leveling phase by SW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, cs, cnt, pup, max_pup_num;
+ u32 res[MAX_CS];
+ max_pup_num = dram_info->num_of_total_pups;
+ __maybe_unused int dpde_flag = 0;
+
+ /* Debug message - Start Write leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting SW WL procedure\n");
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ /* Set Output buffer-off to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+
+ /* 0x15D0 - DDR3 MR0 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Qoff and RTT Values are set for all Cs\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - SW Override Enabled\n");
+
+ /* Enable PHY write leveling mode */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* [2] = 0 - TrnWLMode - Enable */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ /* Reset WL results arry */
+ memset(dram_info->wl_val, 0, sizeof(u32) * MAX_CS * MAX_PUP_NUM * 7);
+
+ /* Loop for each cs */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Starting working with Cs - ",
+ (u32) cs, 1);
+ /* Refresh X9 current cs */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Refresh X9\n");
+ for (cnt = 0; cnt < COUNT_WL_RFRS; cnt++) {
+ reg =
+ REG_SDRAM_OPERATION_CMD_RFRS & ~(1 <<
+ (REG_SDRAM_OPERATION_CS_OFFS
+ + cs));
+ /* [3-0] = 0x2 - refresh, [11-8] - enable current cs */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg); /* 0x1418 - SDRAM Operation Register */
+
+ do {
+ reg =
+ ((reg_read
+ (REG_SDRAM_OPERATION_ADDR)) &
+ REG_SDRAM_OPERATION_CMD_RFRS_DONE);
+ } while (reg); /* Wait for '0' */
+ }
+
+ /* Configure MR1 in Cs[CsNum] - write leveling on, output buffer on */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Configure MR1 for current Cs: WL-on,OB-on\n");
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ /* Set ODT Values */
+ reg &= REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ /* Enable WL MODE */
+ reg |= (1 << REG_DDR3_MR1_WL_ENA_OFFS);
+ /* [7]=1, [12]=0 - Output Buffer and write leveling enabled */
+ reg_write(REG_DDR3_MR1_ADDR, reg); /* 0x15D4 - DDR3 MR1 Register */
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+
+ /* Write leveling cs[cs] */
+ if (MV_OK !=
+ ddr3_write_leveling_single_cs(cs, freq, ratio_2to1,
+ (u32 *)(res + cs),
+ dram_info)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling single Cs - FAILED - Cs - ",
+ (u32) cs, 1);
+ for (pup = 0; pup < max_pup_num; pup++) {
+ if (((res[cs] >> pup) & 0x1) == 0) {
+ DEBUG_WL_C("Failed Byte : ",
+ pup, 1);
+ }
+ }
+ return MV_FAIL;
+ }
+
+ /* Set TrnWLDeUpd - After each CS is done */
+ reg = reg_read(REG_TRAINING_WL_ADDR) |
+ (1 << REG_TRAINING_WL_CS_DONE_OFFS);
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /*
+ * Debug message - Finished Write leveling cs[cs] -
+ * each PUP Fail/Success
+ */
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Finished Cs - ", (u32) cs,
+ 1);
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - The Results: 1-PUP locked, 0-PUP failed -",
+ (u32) res[cs], 3);
+
+ /*
+ * Configure MR1 in cs[cs] - write leveling off (0),
+ * output buffer off (1)
+ */
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+ /* No need to sort ODT since it is same CS */
+ /* 0x15D4 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ /* Disable WL Mode */
+ /* [2]=1 - TrnWLMode - Disable */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= (1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Set Output buffer-on to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg &= REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+
+ /* 0x15D0 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Finished WL procedure for all Cs\n");
+
+ return MV_OK;
+}
+
+#if !defined(MV88F672X)
+/*
+ * Name: ddr3_write_leveling_sw
+ * Desc: Execute Write leveling phase by SW
+ * Args: freq - current sequence frequency
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+int ddr3_write_leveling_sw_reg_dimm(u32 freq, int ratio_2to1,
+ MV_DRAM_INFO *dram_info)
+{
+ u32 reg, cs, cnt, pup;
+ u32 res[MAX_CS];
+ __maybe_unused int dpde_flag = 0;
+
+ /* Debug message - Start Write leveling procedure */
+ DEBUG_WL_S("DDR3 - Write Leveling - Starting SW WL procedure\n");
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
+ if (reg & (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS)) {
+ dpde_flag = 1;
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR,
+ reg & ~(1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS));
+ }
+#endif
+
+ /* If target freq = 400 move clock start point */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+ /* PUP_DELAY_MASK 0x1F */
+ /* reg = 0x0C10001F + (uj << 16); */
+ ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+ 0x1F);
+ }
+ }
+
+ /* Set Output buffer-off to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+
+ /* 0x15D0 - DDR3 MR0 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Qoff and RTT Values are set for all Cs\n");
+
+ /* Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
+ (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* [0] = 1 - Enable SW override */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - SW Override Enabled\n");
+
+ /* Enable PHY write leveling mode */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
+ ~(1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* [2] = 0 - TrnWLMode - Enable */
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Loop for each cs */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Starting working with Cs - ",
+ (u32) cs, 1);
+
+ /* Refresh X9 current cs */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Refresh X9\n");
+ for (cnt = 0; cnt < COUNT_WL_RFRS; cnt++) {
+ reg =
+ REG_SDRAM_OPERATION_CMD_RFRS & ~(1 <<
+ (REG_SDRAM_OPERATION_CS_OFFS
+ + cs));
+ /* [3-0] = 0x2 - refresh, [11-8] - enable current cs */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg); /* 0x1418 - SDRAM Operation Register */
+
+ do {
+ reg =
+ ((reg_read
+ (REG_SDRAM_OPERATION_ADDR)) &
+ REG_SDRAM_OPERATION_CMD_RFRS_DONE);
+ } while (reg); /* Wait for '0' */
+ }
+
+ /*
+ * Configure MR1 in Cs[CsNum] - write leveling on,
+ * output buffer on
+ */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Configure MR1 for current Cs: WL-on,OB-on\n");
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ /* Set ODT Values */
+ reg &= REG_DDR3_MR1_ODT_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+ /* Enable WL MODE */
+ reg |= (1 << REG_DDR3_MR1_WL_ENA_OFFS);
+ /*
+ * [7]=1, [12]=0 - Output Buffer and write leveling
+ * enabled
+ */
+ /* 0x15D4 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+
+ /* Write leveling cs[cs] */
+ if (MV_OK !=
+ ddr3_write_leveling_single_cs(cs, freq, ratio_2to1,
+ (u32 *)(res + cs),
+ dram_info)) {
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling single Cs - FAILED - Cs - ",
+ (u32) cs, 1);
+ return MV_FAIL;
+ }
+
+ /* Set TrnWLDeUpd - After each CS is done */
+ reg = reg_read(REG_TRAINING_WL_ADDR) |
+ (1 << REG_TRAINING_WL_CS_DONE_OFFS);
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /*
+ * Debug message - Finished Write leveling cs[cs] -
+ * each PUP Fail/Success
+ */
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - Finished Cs - ", (u32) cs,
+ 1);
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling - The Results: 1-PUP locked, 0-PUP failed -",
+ (u32) res[cs], 3);
+
+ /* Configure MR1 in cs[cs] - write leveling off (0), output buffer off (1) */
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= (1 << REG_DDR3_MR1_OUTBUF_DIS_OFFS);
+ /* No need to sort ODT since it is same CS */
+ /* 0x15D4 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+ /* Disable WL Mode */
+ /* [2]=1 - TrnWLMode - Disable */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg |= (1 << REG_DRAM_TRAINING_2_WL_MODE_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Disable SW override - Must be in a different stage */
+ /* [0]=0 - Enable SW override */
+ reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
+ reg &= ~(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
+ /* 0x15B8 - Training SW 2 Register */
+ reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
+
+ /* Set Output buffer-on to all CS and correct ODT values */
+ for (cs = 0; cs < MAX_CS; cs++) {
+ if (dram_info->cs_ena & (1 << cs)) {
+ reg = reg_read(REG_DDR3_MR1_ADDR) &
+ REG_DDR3_MR1_ODT_MASK;
+ reg &= REG_DDR3_MR1_OUTBUF_WL_MASK;
+ reg |= odt_static[dram_info->cs_ena][cs];
+
+ /* 0x15D0 - DDR3 MR1 Register */
+ reg_write(REG_DDR3_MR1_ADDR, reg);
+ /* Issue MRS Command to current cs */
+ reg = REG_SDRAM_OPERATION_CMD_MR1 &
+ ~(1 << (REG_SDRAM_OPERATION_CS_OFFS + cs));
+ /*
+ * [3-0] = 0x4 - MR1 Command, [11-8] -
+ * enable current cs
+ */
+ /* 0x1418 - SDRAM Operation Register */
+ reg_write(REG_SDRAM_OPERATION_ADDR, reg);
+
+ udelay(MRS_DELAY);
+ }
+ }
+
+#ifdef MV88F67XX
+ /* Dynamic pad issue (BTS669) during WL */
+ if (dpde_flag) {
+ reg = reg_read(REG_DUNIT_CTRL_LOW_ADDR) |
+ (1 << REG_DUNIT_CTRL_LOW_DPDE_OFFS);
+ reg_write(REG_DUNIT_CTRL_LOW_ADDR, reg);
+ }
+#endif
+
+ /* If target freq = 400 move clock back */
+ /* Write to control PUP to Control Deskew Regs */
+ if (freq <= DDR_400) {
+ for (pup = 0; pup <= dram_info->num_of_total_pups; pup++) {
+ ddr3_write_ctrl_pup_reg(1, pup, CNTRL_PUP_DESKEW + pup,
+ 0);
+ }
+ }
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling - Finished WL procedure for all Cs\n");
+ return MV_OK;
+}
+#endif
+
+/*
+ * Name: ddr3_write_leveling_single_cs
+ * Desc: Execute Write leveling for single Chip select
+ * Args: cs - current chip select
+ * freq - current sequence frequency
+ * result - res array
+ * dram_info - main struct
+ * Notes:
+ * Returns: MV_OK if success, MV_FAIL if fail.
+ */
+static int ddr3_write_leveling_single_cs(u32 cs, u32 freq, int ratio_2to1,
+ u32 *result, MV_DRAM_INFO *dram_info)
+{
+ u32 reg, pup_num, delay, phase, phaseMax, max_pup_num, pup,
+ max_pup_mask;
+
+ max_pup_num = dram_info->num_of_total_pups;
+ *result = 0;
+ u32 flag[MAX_PUP_NUM] = { 0 };
+
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling Single Cs - WL for Cs - ",
+ (u32) cs, 1);
+
+ switch (max_pup_num) {
+ case 2:
+ max_pup_mask = 0x3;
+ break;
+ case 4:
+ max_pup_mask = 0xf;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ case 5:
+ max_pup_mask = 0x1f;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ case 8:
+ max_pup_mask = 0xff;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ case 9:
+ max_pup_mask = 0x1ff;
+ DEBUG_WL_C("max_pup_mask = ", max_pup_mask, 3);
+ break;
+ default:
+ DEBUG_WL_C("ddr3_write_leveling_single_cs wrong max_pup_num = ",
+ max_pup_num, 3);
+ return MV_FAIL;
+ }
+
+ /* CS ODT Override */
+ reg = reg_read(REG_SDRAM_ODT_CTRL_HIGH_ADDR) &
+ REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK;
+ reg |= (REG_SDRAM_ODT_CTRL_HIGH_OVRD_ENA << (2 * cs));
+ /* Set 0x3 - Enable ODT on the curent cs and disable on other cs */
+ /* 0x1498 - SDRAM ODT Control high */
+ reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - ODT Asserted for current Cs\n");
+
+ /* tWLMRD Delay */
+ /* Delay of minimum 40 Dram clock cycles - 20 Tclk cycles */
+ udelay(1);
+
+ /* [1:0] - current cs number */
+ reg = (reg_read(REG_TRAINING_WL_ADDR) & REG_TRAINING_WL_CS_MASK) | cs;
+ reg |= (1 << REG_TRAINING_WL_UPD_OFFS); /* [2] - trnWLCsUpd */
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /* Broadcast to all PUPs: Reset DQS phase, reset leveling delay */
+ ddr3_write_pup_reg(PUP_WL_MODE, cs, PUP_BC, 0, 0);
+
+ /* Seek Edge */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Current Cs\n");
+
+ /* Drive DQS high for one cycle - All data PUPs */
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Driving DQS high for one cycle\n");
+ if (!ratio_2to1) {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) | REG_TRAINING_WL_1TO1;
+ } else {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) | REG_TRAINING_WL_2TO1;
+ }
+ /* 0x16AC - Training Write leveling register */
+ reg_write(REG_TRAINING_WL_ADDR, reg);
+
+ /* Wait tWLdelay */
+ do {
+ /* [29] - trnWLDelayExp */
+ reg = (reg_read(REG_TRAINING_WL_ADDR)) &
+ REG_TRAINING_WL_DELAYEXP_MASK;
+ } while (reg == 0x0); /* Wait for '1' */
+
+ /* Read WL res */
+ reg = (reg_read(REG_TRAINING_WL_ADDR) >> REG_TRAINING_WL_RESULTS_OFFS) &
+ REG_TRAINING_WL_RESULTS_MASK;
+ /* [28:20] - TrnWLResult */
+
+ if (!ratio_2to1) /* Different phase options for 2:1 or 1:1 modes */
+ phaseMax = MAX_PHASE_1TO1;
+ else
+ phaseMax = MAX_PHASE_2TO1;
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge - Shift DQS + Octet Leveling\n");
+
+ /* Shift DQS + Octet leveling */
+ for (phase = 0; phase < phaseMax; phase++) {
+ for (delay = 0; delay < MAX_DELAY; delay++) {
+ /* Broadcast to all PUPs: DQS phase,leveling delay */
+ ddr3_write_pup_reg(PUP_WL_MODE, cs, PUP_BC, phase,
+ delay);
+
+ udelay(1); /* Delay of 3 Tclk cycles */
+
+ DEBUG_WL_FULL_S("DDR3 - Write Leveling Single Cs - Seek Edge: Phase = ");
+ DEBUG_WL_FULL_D((u32) phase, 1);
+ DEBUG_WL_FULL_S(", Delay = ");
+ DEBUG_WL_FULL_D((u32) delay, 1);
+ DEBUG_WL_FULL_S(", Counter = ");
+ DEBUG_WL_FULL_D((u32) i, 1);
+ DEBUG_WL_FULL_S("\n");
+
+ /* Drive DQS high for one cycle - All data PUPs */
+ if (!ratio_2to1) {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) |
+ REG_TRAINING_WL_1TO1;
+ } else {
+ reg = (reg_read(REG_TRAINING_WL_ADDR) &
+ REG_TRAINING_WL_RATIO_MASK) |
+ REG_TRAINING_WL_2TO1;
+ }
+ reg_write(REG_TRAINING_WL_ADDR, reg); /* 0x16AC */
+
+ /* Wait tWLdelay */
+ do {
+ reg = (reg_read(REG_TRAINING_WL_ADDR)) &
+ REG_TRAINING_WL_DELAYEXP_MASK;
+ } while (reg == 0x0); /* [29] Wait for '1' */
+
+ /* Read WL res */
+ reg = reg_read(REG_TRAINING_WL_ADDR);
+ reg = (reg >> REG_TRAINING_WL_RESULTS_OFFS) &
+ REG_TRAINING_WL_RESULTS_MASK; /* [28:20] */
+
+ DEBUG_WL_FULL_C("DDR3 - Write Leveling Single Cs - Seek Edge: Results = ",
+ (u32) reg, 3);
+
+ /* Update State machine */
+ for (pup = 0; pup < (max_pup_num); pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ?
+ ECC_BIT : pup;
+ if (dram_info->wl_val[cs][pup][S] == 0) {
+ /* Update phase to PUP */
+ dram_info->wl_val[cs][pup][P] = phase;
+ /* Update delay to PUP */
+ dram_info->wl_val[cs][pup][D] = delay;
+ }
+
+ if (((reg >> pup_num) & 0x1) == 0)
+ flag[pup_num] = 1;
+
+ if (((reg >> pup_num) & 0x1)
+ && (flag[pup_num] == 1)
+ && (dram_info->wl_val[cs][pup][S] == 0)) {
+ /*
+ * If the PUP is locked now and in last
+ * counter states
+ */
+ /* Go to next state */
+ dram_info->wl_val[cs][pup][S] = 1;
+ /* Set res */
+ *result = *result | (1 << pup_num);
+ }
+ }
+
+ /* If all locked - Break the loops - Finished */
+ if (*result == max_pup_mask) {
+ phase = phaseMax;
+ delay = MAX_DELAY;
+ DEBUG_WL_S("DDR3 - Write Leveling Single Cs - Seek Edge: All Locked\n");
+ }
+ }
+ }
+
+ /* Debug message - Print res for cs[i]: cs,PUP,Phase,Delay */
+ DEBUG_WL_C("DDR3 - Write Leveling - Results for CS - ", (u32) cs, 1);
+ for (pup = 0; pup < (max_pup_num); pup++) {
+ DEBUG_WL_S("DDR3 - Write Leveling - PUP: ");
+ DEBUG_WL_D((u32) pup, 1);
+ DEBUG_WL_S(", Phase: ");
+ DEBUG_WL_D((u32) dram_info->wl_val[cs][pup][P], 1);
+ DEBUG_WL_S(", Delay: ");
+ DEBUG_WL_D((u32) dram_info->wl_val[cs][pup][D], 2);
+ DEBUG_WL_S("\n");
+ }
+
+ /* Check if some not locked and return error */
+ if (*result != max_pup_mask) {
+ DEBUG_WL_S("DDR3 - Write Leveling - ERROR - not all PUPS were locked\n");
+ return MV_FAIL;
+ }
+
+ /* Configure Each PUP with locked leveling settings */
+ for (pup = 0; pup < (max_pup_num); pup++) {
+ /* ECC support - bit 8 */
+ pup_num = (pup == dram_info->num_of_std_pups) ? ECC_BIT : pup;
+ phase = dram_info->wl_val[cs][pup][P];
+ delay = dram_info->wl_val[cs][pup][D];
+ ddr3_write_pup_reg(PUP_WL_MODE, cs, pup_num, phase, delay);
+ }
+
+ /* CS ODT Override */
+ reg = reg_read(REG_SDRAM_ODT_CTRL_HIGH_ADDR) &
+ REG_SDRAM_ODT_CTRL_HIGH_OVRD_MASK;
+ /* 0x1498 - SDRAM ODT Control high */
+ reg_write(REG_SDRAM_ODT_CTRL_HIGH_ADDR, reg);
+
+ return MV_OK;
+}
+
+/*
+ * Perform DDR3 Control PUP Indirect Write
+ */
+static void ddr3_write_ctrl_pup_reg(int bc_acc, u32 pup, u32 reg_addr, u32 data)
+{
+ u32 reg = 0;
+
+ /* Store value for write */
+ reg = (data & 0xFFFF);
+
+ /* Set bit 26 for control PHY access */
+ reg |= (1 << REG_PHY_CNTRL_OFFS);
+
+ /* Configure BC or UC access to PHYs */
+ if (bc_acc == 1)
+ reg |= (1 << REG_PHY_BC_OFFS);
+ else
+ reg |= (pup << REG_PHY_PUP_OFFS);
+
+ /* Set PHY register address to write to */
+ reg |= (reg_addr << REG_PHY_CS_OFFS);
+
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+ reg |= REG_PHY_REGISTRY_FILE_ACCESS_OP_WR;
+ reg_write(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, reg); /* 0x16A0 */
+
+ do {
+ reg = (reg_read(REG_PHY_REGISTRY_FILE_ACCESS_ADDR)) &
+ REG_PHY_REGISTRY_FILE_ACCESS_OP_DONE;
+ } while (reg); /* Wait for '0' to mark the end of the transaction */
+}
diff --git a/drivers/ddr/mvebu/xor.c b/drivers/ddr/mvebu/xor.c
new file mode 100644
index 0000000..66c96ae
--- /dev/null
+++ b/drivers/ddr/mvebu/xor.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "xor.h"
+#include "xor_regs.h"
+
+static u32 xor_regs_ctrl_backup;
+static u32 xor_regs_base_backup[MAX_CS];
+static u32 xor_regs_mask_backup[MAX_CS];
+
+static void mv_xor_hal_init(u32 chan_num);
+static int mv_xor_cmd_set(u32 chan, int command);
+static int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl);
+
+void mv_sys_xor_init(MV_DRAM_INFO *dram_info)
+{
+ u32 reg, ui, base, cs_count;
+
+ xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
+ for (ui = 0; ui < MAX_CS; ui++)
+ xor_regs_base_backup[ui] = reg_read(XOR_BASE_ADDR_REG(0, ui));
+ for (ui = 0; ui < MAX_CS; ui++)
+ xor_regs_mask_backup[ui] = reg_read(XOR_SIZE_MASK_REG(0, ui));
+
+ reg = 0;
+ for (ui = 0; ui < (dram_info->num_cs + 1); ui++) {
+ /* Enable Window x for each CS */
+ reg |= (0x1 << (ui));
+ /* Enable Window x for each CS */
+ reg |= (0x3 << ((ui * 2) + 16));
+ }
+
+ reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg);
+
+ /* Last window - Base - 0x40000000, Attribute 0x1E - SRAM */
+ base = (SRAM_BASE & 0xFFFF0000) | 0x1E00;
+ reg_write(XOR_BASE_ADDR_REG(0, dram_info->num_cs), base);
+ /* Last window - Size - 64 MB */
+ reg_write(XOR_SIZE_MASK_REG(0, dram_info->num_cs), 0x03FF0000);
+
+ cs_count = 0;
+ for (ui = 0; ui < MAX_CS; ui++) {
+ if (dram_info->cs_ena & (1 << ui)) {
+ /*
+ * Window x - Base - 0x00000000, Attribute 0x0E - DRAM
+ */
+ base = 0;
+ switch (ui) {
+ case 0:
+ base |= 0xE00;
+ break;
+ case 1:
+ base |= 0xD00;
+ break;
+ case 2:
+ base |= 0xB00;
+ break;
+ case 3:
+ base |= 0x700;
+ break;
+ }
+
+ reg_write(XOR_BASE_ADDR_REG(0, cs_count), base);
+
+ /* Window x - Size - 256 MB */
+ reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x0FFF0000);
+ cs_count++;
+ }
+ }
+
+ mv_xor_hal_init(1);
+
+ return;
+}
+
+void mv_sys_xor_finish(void)
+{
+ u32 ui;
+
+ reg_write(XOR_WINDOW_CTRL_REG(0, 0), xor_regs_ctrl_backup);
+ for (ui = 0; ui < MAX_CS; ui++)
+ reg_write(XOR_BASE_ADDR_REG(0, ui), xor_regs_base_backup[ui]);
+ for (ui = 0; ui < MAX_CS; ui++)
+ reg_write(XOR_SIZE_MASK_REG(0, ui), xor_regs_mask_backup[ui]);
+
+ reg_write(XOR_ADDR_OVRD_REG(0, 0), 0);
+}
+
+/*
+ * mv_xor_hal_init - Initialize XOR engine
+ *
+ * DESCRIPTION:
+ * This function initialize XOR unit.
+ * INPUT:
+ * None.
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ */
+static void mv_xor_hal_init(u32 chan_num)
+{
+ u32 i;
+
+ /* Abort any XOR activity & set default configuration */
+ for (i = 0; i < chan_num; i++) {
+ mv_xor_cmd_set(i, MV_STOP);
+ mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) |
+ (4 << XEXCR_DST_BURST_LIMIT_OFFS) |
+ (4 << XEXCR_SRC_BURST_LIMIT_OFFS));
+ }
+}
+
+/*
+ * mv_xor_ctrl_set - Set XOR channel control registers
+ *
+ * DESCRIPTION:
+ *
+ * INPUT:
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ * NOTE:
+ * This function does not modify the OperationMode field of control register.
+ *
+ */
+static int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
+{
+ u32 val;
+
+ /* Update the XOR Engine [0..1] Configuration Registers (XExCR) */
+ val = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)))
+ & XEXCR_OPERATION_MODE_MASK;
+ xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
+ xor_ctrl |= val;
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl);
+
+ return MV_OK;
+}
+
+int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size, u32 init_val_high,
+ u32 init_val_low)
+{
+ u32 tmp;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN)
+ return MV_BAD_PARAM;
+
+ if (MV_ACTIVE == mv_xor_state_get(chan))
+ return MV_BUSY;
+
+ if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) ||
+ (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE))
+ return MV_BAD_PARAM;
+
+ /* Set the operation mode to Memory Init */
+ tmp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ tmp &= ~XEXCR_OPERATION_MODE_MASK;
+ tmp |= XEXCR_OPERATION_MODE_MEM_INIT;
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), tmp);
+
+ /*
+ * Update the start_ptr field in XOR Engine [0..1] Destination Pointer
+ * Register (XExDPR0)
+ */
+ reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
+
+ /*
+ * Update the BlockSize field in the XOR Engine[0..1] Block Size
+ * Registers (XExBSR)
+ */
+ reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ block_size);
+
+ /*
+ * Update the field InitValL in the XOR Engine Initial Value Register
+ * Low (XEIVRL)
+ */
+ reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low);
+
+ /*
+ * Update the field InitValH in the XOR Engine Initial Value Register
+ * High (XEIVRH)
+ */
+ reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high);
+
+ /* Start transfer */
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+
+ return MV_OK;
+}
+
+/*
+ * mv_xor_transfer - Transfer data from source to destination on one of
+ * three modes (XOR,CRC32,DMA)
+ *
+ * DESCRIPTION:
+ * This function initiates XOR channel, according to function parameters,
+ * in order to perform XOR or CRC32 or DMA transaction.
+ * To gain maximum performance the user is asked to keep the following
+ * restrictions:
+ * 1) Selected engine is available (not busy).
+ * 1) This module does not take into consideration CPU MMU issues.
+ * In order for the XOR engine to access the appropreate source
+ * and destination, address parameters must be given in system
+ * physical mode.
+ * 2) This API does not take care of cache coherency issues. The source,
+ * destination and in case of chain the descriptor list are assumed
+ * to be cache coherent.
+ * 4) Parameters validity. For example, does size parameter exceeds
+ * maximum byte count of descriptor mode (16M or 64K).
+ *
+ * INPUT:
+ * chan - XOR channel number. See MV_XOR_CHANNEL enumerator.
+ * xor_type - One of three: XOR, CRC32 and DMA operations.
+ * xor_chain_ptr - address of chain pointer
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURS:
+ * MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
+ *
+ */
+int mv_xor_transfer(u32 chan, int xor_type, u32 xor_chain_ptr)
+{
+ u32 tmp;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+ return MV_BAD_PARAM;
+ }
+
+ if (MV_ACTIVE == mv_xor_state_get(chan)) {
+ debug("%s: ERR. Channel is already active\n", __func__);
+ return MV_BUSY;
+ }
+
+ if (0x0 == xor_chain_ptr) {
+ debug("%s: ERR. xor_chain_ptr is NULL pointer\n", __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Read configuration register and mask the operation mode field */
+ tmp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ tmp &= ~XEXCR_OPERATION_MODE_MASK;
+
+ switch (xor_type) {
+ case MV_XOR:
+ if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_XOR_MASK)) {
+ debug("%s: ERR. Invalid chain pointer (bits [5:0] must be cleared)\n",
+ __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Set the operation mode to XOR */
+ tmp |= XEXCR_OPERATION_MODE_XOR;
+ break;
+
+ case MV_DMA:
+ if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_DMA_MASK)) {
+ debug("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
+ __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Set the operation mode to DMA */
+ tmp |= XEXCR_OPERATION_MODE_DMA;
+ break;
+
+ case MV_CRC32:
+ if (0 != (xor_chain_ptr & XEXDPR_DST_PTR_CRC_MASK)) {
+ debug("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
+ __func__);
+ return MV_BAD_PARAM;
+ }
+
+ /* Set the operation mode to CRC32 */
+ tmp |= XEXCR_OPERATION_MODE_CRC;
+ break;
+
+ default:
+ return MV_BAD_PARAM;
+ }
+
+ /* Write the operation mode to the register */
+ reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), tmp);
+
+ /*
+ * Update the NextDescPtr field in the XOR Engine [0..1] Next Descriptor
+ * Pointer Register (XExNDPR)
+ */
+ reg_write(XOR_NEXT_DESC_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ xor_chain_ptr);
+
+ /* Start transfer */
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+
+ return MV_OK;
+}
+
+/*
+ * mv_xor_state_get - Get XOR channel state.
+ *
+ * DESCRIPTION:
+ * XOR channel activity state can be active, idle, paused.
+ * This function retrunes the channel activity state.
+ *
+ * INPUT:
+ * chan - the channel number
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * XOR_CHANNEL_IDLE - If the engine is idle.
+ * XOR_CHANNEL_ACTIVE - If the engine is busy.
+ * XOR_CHANNEL_PAUSED - If the engine is paused.
+ * MV_UNDEFINED_STATE - If the engine state is undefind or there is no
+ * such engine
+ *
+ */
+int mv_xor_state_get(u32 chan)
+{
+ u32 state;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+ return MV_UNDEFINED_STATE;
+ }
+
+ /* Read the current state */
+ state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
+ state &= XEXACTR_XESTATUS_MASK;
+
+ /* Return the state */
+ switch (state) {
+ case XEXACTR_XESTATUS_IDLE:
+ return MV_IDLE;
+ case XEXACTR_XESTATUS_ACTIVE:
+ return MV_ACTIVE;
+ case XEXACTR_XESTATUS_PAUSED:
+ return MV_PAUSED;
+ }
+
+ return MV_UNDEFINED_STATE;
+}
+
+/*
+ * mv_xor_cmd_set - Set command of XOR channel
+ *
+ * DESCRIPTION:
+ * XOR channel can be started, idle, paused and restarted.
+ * Paused can be set only if channel is active.
+ * Start can be set only if channel is idle or paused.
+ * Restart can be set only if channel is paused.
+ * Stop can be set only if channel is active.
+ *
+ * INPUT:
+ * chan - The channel number
+ * command - The command type (start, stop, restart, pause)
+ *
+ * OUTPUT:
+ * None.
+ *
+ * RETURN:
+ * MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on
+ * undefind XOR engine mode
+ *
+ */
+static int mv_xor_cmd_set(u32 chan, int command)
+{
+ int state;
+
+ /* Parameter checking */
+ if (chan >= MV_XOR_MAX_CHAN) {
+ debug("%s: ERR. Invalid chan num %d\n", __func__, chan);
+ return MV_BAD_PARAM;
+ }
+
+ /* Get the current state */
+ state = mv_xor_state_get(chan);
+
+ /* Command is start and current state is idle */
+ if ((command == MV_START) && (state == MV_IDLE)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTART_MASK);
+ return MV_OK;
+ }
+ /* Command is stop and current state is active */
+ else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XESTOP_MASK);
+ return MV_OK;
+ }
+ /* Command is paused and current state is active */
+ else if ((command == MV_PAUSED) && (state == MV_ACTIVE)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XEPAUSE_MASK);
+ return MV_OK;
+ }
+ /* Command is restart and current state is paused */
+ else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
+ reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
+ XEXACTR_XERESTART_MASK);
+ return MV_OK;
+ }
+ /* Command is stop and current state is active */
+ else if ((command == MV_STOP) && (state == MV_IDLE))
+ return MV_OK;
+
+ /* Illegal command */
+ debug("%s: ERR. Illegal command\n", __func__);
+
+ return MV_BAD_PARAM;
+}
diff --git a/drivers/ddr/mvebu/xor.h b/drivers/ddr/mvebu/xor.h
new file mode 100644
index 0000000..3536487
--- /dev/null
+++ b/drivers/ddr/mvebu/xor.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __XOR_H
+#define __XOR_H
+
+#include "ddr3_hw_training.h"
+
+#define MV_XOR_MAX_CHAN 4 /* total channels for all units together */
+
+/*
+ * This enumerator describes the type of functionality the XOR channel
+ * can have while using the same data structures.
+ */
+enum xor_type {
+ MV_XOR, /* XOR channel functions as XOR accelerator */
+ MV_DMA, /* XOR channel functions as IDMA channel */
+ MV_CRC32 /* XOR channel functions as CRC 32 calculator */
+};
+
+/*
+ * This enumerator describes the set of commands that can be applied on
+ * an engine (e.g. IDMA, XOR). Appling a comman depends on the current
+ * status (see MV_STATE enumerator)
+ * Start can be applied only when status is IDLE
+ * Stop can be applied only when status is IDLE, ACTIVE or PAUSED
+ * Pause can be applied only when status is ACTIVE
+ * Restart can be applied only when status is PAUSED
+ */
+enum mv_command {
+ MV_START, /* Start */
+ MV_STOP, /* Stop */
+ MV_PAUSE, /* Pause */
+ MV_RESTART /* Restart */
+};
+
+/*
+ * This enumerator describes the set of state conditions.
+ * Moving from one state to other is stricted.
+ */
+enum mv_state {
+ MV_IDLE,
+ MV_ACTIVE,
+ MV_PAUSED,
+ MV_UNDEFINED_STATE
+};
+
+/* XOR descriptor structure for CRC and DMA descriptor */
+struct crc_dma_desc {
+ u32 status; /* Successful descriptor execution indication */
+ u32 crc32_result; /* Result of CRC-32 calculation */
+ u32 desc_cmd; /* type of operation to be carried out on the data */
+ u32 next_desc_ptr; /* Next descriptor address pointer */
+ u32 byte_cnt; /* Size of source block part represented by the descriptor */
+ u32 dst_addr; /* Destination Block address pointer (not used in CRC32 */
+ u32 src_addr0; /* Mode: Source Block address pointer */
+ u32 src_addr1; /* Mode: Source Block address pointer */
+} __packed;
+
+int mv_xor_state_get(u32 chan);
+void mv_sys_xor_init(MV_DRAM_INFO *dram_info);
+void mv_sys_xor_finish(void);
+int mv_xor_transfer(u32 chan, int xor_type, u32 xor_chain_ptr);
+int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size, u32 init_val_high,
+ u32 init_val_low);
+
+#endif /* __XOR_H */
diff --git a/drivers/ddr/mvebu/xor_regs.h b/drivers/ddr/mvebu/xor_regs.h
new file mode 100644
index 0000000..884aa15
--- /dev/null
+++ b/drivers/ddr/mvebu/xor_regs.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __XOR_REGS_H
+#define __XOR_REGS_H
+
+/*
+ * For controllers that have two XOR units, then chans 2 & 3 will be mapped
+ * to channels 0 & 1 of unit 1
+ */
+#define XOR_UNIT(chan) ((chan) >> 1)
+#define XOR_CHAN(chan) ((chan) & 1)
+
+#define MV_XOR_REGS_OFFSET(unit) (0x60900)
+#define MV_XOR_REGS_BASE(unit) (MV_XOR_REGS_OFFSET(unit))
+
+/* XOR Engine Control Register Map */
+#define XOR_CHANNEL_ARBITER_REG(unit) (MV_XOR_REGS_BASE(unit))
+#define XOR_CONFIG_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x10 + ((chan) * 4)))
+#define XOR_ACTIVATION_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x20 + ((chan) * 4)))
+
+/* XOR Engine Interrupt Register Map */
+#define XOR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x30)
+#define XOR_MASK_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x40)
+#define XOR_ERROR_CAUSE_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x50)
+#define XOR_ERROR_ADDR_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x60)
+
+/* XOR Engine Descriptor Register Map */
+#define XOR_NEXT_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x200 + ((chan) * 4)))
+#define XOR_CURR_DESC_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x210 + ((chan) * 4)))
+#define XOR_BYTE_COUNT_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x220 + ((chan) * 4)))
+
+#define XOR_DST_PTR_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x2B0 + ((chan) * 4)))
+#define XOR_BLOCK_SIZE_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x2C0 + ((chan) * 4)))
+#define XOR_TIMER_MODE_CTRL_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2D0)
+#define XOR_TIMER_MODE_INIT_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2D4)
+#define XOR_TIMER_MODE_CURR_VAL_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2D8)
+#define XOR_INIT_VAL_LOW_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2E0)
+#define XOR_INIT_VAL_HIGH_REG(unit) (MV_XOR_REGS_BASE(unit) + 0x2E4)
+
+/* XOR register fileds */
+
+/* XOR Engine [0..1] Configuration Registers (XExCR) */
+#define XEXCR_OPERATION_MODE_OFFS (0)
+#define XEXCR_OPERATION_MODE_MASK (7 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_XOR (0 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_CRC (1 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_DMA (2 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_ECC (3 << XEXCR_OPERATION_MODE_OFFS)
+#define XEXCR_OPERATION_MODE_MEM_INIT (4 << XEXCR_OPERATION_MODE_OFFS)
+
+#define XEXCR_SRC_BURST_LIMIT_OFFS (4)
+#define XEXCR_SRC_BURST_LIMIT_MASK (7 << XEXCR_SRC_BURST_LIMIT_OFFS)
+#define XEXCR_DST_BURST_LIMIT_OFFS (8)
+#define XEXCR_DST_BURST_LIMIT_MASK (7 << XEXCR_DST_BURST_LIMIT_OFFS)
+#define XEXCR_DRD_RES_SWP_OFFS (12)
+#define XEXCR_DRD_RES_SWP_MASK (1 << XEXCR_DRD_RES_SWP_OFFS)
+#define XEXCR_DWR_REQ_SWP_OFFS (13)
+#define XEXCR_DWR_REQ_SWP_MASK (1 << XEXCR_DWR_REQ_SWP_OFFS)
+#define XEXCR_DES_SWP_OFFS (14)
+#define XEXCR_DES_SWP_MASK (1 << XEXCR_DES_SWP_OFFS)
+#define XEXCR_REG_ACC_PROTECT_OFFS (15)
+#define XEXCR_REG_ACC_PROTECT_MASK (1 << XEXCR_REG_ACC_PROTECT_OFFS)
+
+/* XOR Engine [0..1] Activation Registers (XExACTR) */
+#define XEXACTR_XESTART_OFFS (0)
+#define XEXACTR_XESTART_MASK (1 << XEXACTR_XESTART_OFFS)
+#define XEXACTR_XESTOP_OFFS (1)
+#define XEXACTR_XESTOP_MASK (1 << XEXACTR_XESTOP_OFFS)
+#define XEXACTR_XEPAUSE_OFFS (2)
+#define XEXACTR_XEPAUSE_MASK (1 << XEXACTR_XEPAUSE_OFFS)
+#define XEXACTR_XERESTART_OFFS (3)
+#define XEXACTR_XERESTART_MASK (1 << XEXACTR_XERESTART_OFFS)
+#define XEXACTR_XESTATUS_OFFS (4)
+#define XEXACTR_XESTATUS_MASK (3 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_IDLE (0 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_ACTIVE (1 << XEXACTR_XESTATUS_OFFS)
+#define XEXACTR_XESTATUS_PAUSED (2 << XEXACTR_XESTATUS_OFFS)
+
+/* XOR Engine [0..1] Destination Pointer Register (XExDPR0) */
+#define XEXDPR_DST_PTR_OFFS (0)
+#define XEXDPR_DST_PTR_MASK (0xFFFFFFFF << XEXDPR_DST_PTR_OFFS)
+#define XEXDPR_DST_PTR_XOR_MASK (0x3F)
+#define XEXDPR_DST_PTR_DMA_MASK (0x1F)
+#define XEXDPR_DST_PTR_CRC_MASK (0x1F)
+
+/* XOR Engine[0..1] Block Size Registers (XExBSR) */
+#define XEXBSR_BLOCK_SIZE_OFFS (0)
+#define XEXBSR_BLOCK_SIZE_MASK (0xFFFFFFFF << XEXBSR_BLOCK_SIZE_OFFS)
+#define XEXBSR_BLOCK_SIZE_MIN_VALUE (128)
+#define XEXBSR_BLOCK_SIZE_MAX_VALUE (0xFFFFFFFF)
+
+/* XOR Engine Address Decoding Register Map */
+#define XOR_WINDOW_CTRL_REG(unit, chan) (MV_XOR_REGS_BASE(unit) + (0x240 + ((chan) * 4)))
+#define XOR_BASE_ADDR_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x250 + ((win) * 4)))
+#define XOR_SIZE_MASK_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x270 + ((win) * 4)))
+#define XOR_HIGH_ADDR_REMAP_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x290 + ((win) * 4)))
+#define XOR_ADDR_OVRD_REG(unit, win) (MV_XOR_REGS_BASE(unit) + (0x2A0 + ((win) * 4)))
+
+#endif /* __XOR_REGS_H */
diff --git a/drivers/demo/demo-shape.c b/drivers/demo/demo-shape.c
index 3fa9c59..d908736 100644
--- a/drivers/demo/demo-shape.c
+++ b/drivers/demo/demo-shape.c
@@ -11,6 +11,7 @@
#include <malloc.h>
#include <dm-demo.h>
#include <asm/io.h>
+#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -20,6 +21,8 @@ DECLARE_GLOBAL_DATA_PTR;
struct shape_data {
int num_chars; /* Number of non-space characters output so far */
+ struct gpio_desc gpio_desc[8];
+ int gpio_count;
};
/* Crazy little function to draw shapes on the console */
@@ -89,9 +92,52 @@ static int shape_status(struct udevice *dev, int *status)
return 0;
}
+static int set_light(struct udevice *dev, int light)
+{
+ struct shape_data *priv = dev_get_priv(dev);
+ struct gpio_desc *desc;
+ int ret;
+ int i;
+
+ desc = priv->gpio_desc;
+ for (i = 0; i < priv->gpio_count; i++, desc++) {
+ uint mask = 1 << i;
+
+ ret = dm_gpio_set_value(desc, light & mask);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int get_light(struct udevice *dev)
+{
+ struct shape_data *priv = dev_get_priv(dev);
+ struct gpio_desc *desc;
+ uint value = 0;
+ int ret;
+ int i;
+
+ desc = priv->gpio_desc;
+ for (i = 0; i < priv->gpio_count; i++, desc++) {
+ uint mask = 1 << i;
+
+ ret = dm_gpio_get_value(desc);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ value |= mask;
+ }
+
+ return value;
+}
+
static const struct demo_ops shape_ops = {
.hello = shape_hello,
.status = shape_status,
+ .get_light = get_light,
+ .set_light = set_light,
};
static int shape_ofdata_to_platdata(struct udevice *dev)
@@ -111,6 +157,29 @@ static int shape_ofdata_to_platdata(struct udevice *dev)
return 0;
}
+static int dm_shape_probe(struct udevice *dev)
+{
+ struct shape_data *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = gpio_request_list_by_name(dev, "light-gpios", priv->gpio_desc,
+ ARRAY_SIZE(priv->gpio_desc),
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret < 0)
+ return ret;
+ priv->gpio_count = ret;
+ debug("%s: %d GPIOs\n", __func__, priv->gpio_count);
+
+ return 0;
+}
+
+static int dm_shape_remove(struct udevice *dev)
+{
+ struct shape_data *priv = dev_get_priv(dev);
+
+ return gpio_free_list(dev, priv->gpio_desc, priv->gpio_count);
+}
+
static const struct udevice_id demo_shape_id[] = {
{ "demo-shape", 0 },
{ },
@@ -122,6 +191,8 @@ U_BOOT_DRIVER(demo_shape_drv) = {
.id = UCLASS_DEMO,
.ofdata_to_platdata = shape_ofdata_to_platdata,
.ops = &shape_ops,
+ .probe = dm_shape_probe,
+ .remove = dm_shape_remove,
.priv_auto_alloc_size = sizeof(struct shape_data),
.platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
};
diff --git a/drivers/demo/demo-uclass.c b/drivers/demo/demo-uclass.c
index f6510d6..725f068 100644
--- a/drivers/demo/demo-uclass.c
+++ b/drivers/demo/demo-uclass.c
@@ -43,6 +43,26 @@ int demo_status(struct udevice *dev, int *status)
return ops->status(dev, status);
}
+int demo_get_light(struct udevice *dev)
+{
+ const struct demo_ops *ops = device_get_ops(dev);
+
+ if (!ops->get_light)
+ return -ENOSYS;
+
+ return ops->get_light(dev);
+}
+
+int demo_set_light(struct udevice *dev, int light)
+{
+ const struct demo_ops *ops = device_get_ops(dev);
+
+ if (!ops->set_light)
+ return -ENOSYS;
+
+ return ops->set_light(dev, light);
+}
+
int demo_parse_dt(struct udevice *dev)
{
struct dm_demo_pdata *pdata = dev_get_platdata(dev);
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
index 37946d5..d94eb5c 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -38,7 +38,7 @@ static void fpga_no_sup(char *fn, char *msg)
/* fpga_get_desc
* map a device number to a descriptor
*/
-static const fpga_desc *const fpga_get_desc(int devnum)
+const fpga_desc *const fpga_get_desc(int devnum)
{
fpga_desc *desc = (fpga_desc *)NULL;
diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c
index adb4b8c..c765a74 100644
--- a/drivers/fpga/xilinx.c
+++ b/drivers/fpga/xilinx.c
@@ -139,6 +139,11 @@ int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize,
return FPGA_FAIL;
}
+ if (!desc->operations || !desc->operations->load) {
+ printf("%s: Missing load operation\n", __func__);
+ return FPGA_FAIL;
+ }
+
return desc->operations->load(desc, buf, bsize, bstype);
}
@@ -151,8 +156,10 @@ int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
return FPGA_FAIL;
}
- if (!desc->operations->loadfs)
+ if (!desc->operations || !desc->operations->loadfs) {
+ printf("%s: Missing loadfs operation\n", __func__);
return FPGA_FAIL;
+ }
return desc->operations->loadfs(desc, buf, bsize, fpga_fsinfo);
}
@@ -165,6 +172,11 @@ int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize)
return FPGA_FAIL;
}
+ if (!desc->operations || !desc->operations->dump) {
+ printf("%s: Missing dump operation\n", __func__);
+ return FPGA_FAIL;
+ }
+
return desc->operations->dump(desc, buf, bsize);
}
@@ -226,12 +238,14 @@ int xilinx_info(xilinx_desc *desc)
if (desc->name)
printf("Device name: \t%s\n", desc->name);
- if (desc->iface_fns) {
+ if (desc->iface_fns)
printf ("Device Function Table @ 0x%p\n", desc->iface_fns);
- desc->operations->info(desc);
- } else
+ else
printf ("No Device Function Table.\n");
+ if (desc->operations && desc->operations->info)
+ desc->operations->info(desc);
+
ret_val = FPGA_SUCCESS;
} else {
printf ("%s: Invalid device descriptor\n", __FUNCTION__);
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 255700a..a69bbd2 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -7,20 +7,25 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
+#include <fdtdec.h>
#include <malloc.h>
#include <asm/gpio.h>
#include <linux/ctype.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/**
* gpio_to_device() - Convert global GPIO number to device, number
- * gpio: The numeric representation of the GPIO
*
* Convert the GPIO number to an entry in the list of GPIOs
* or GPIO blocks registered with the GPIO controller. Returns
* entry on success, NULL on error.
+ *
+ * @gpio: The numeric representation of the GPIO
+ * @desc: Returns description (desc->flags will always be 0)
+ * @return 0 if found, -ENOENT if not found
*/
-static int gpio_to_device(unsigned int gpio, struct udevice **devp,
- unsigned int *offset)
+static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
{
struct gpio_dev_priv *uc_priv;
struct udevice *dev;
@@ -32,14 +37,15 @@ static int gpio_to_device(unsigned int gpio, struct udevice **devp,
uc_priv = dev->uclass_priv;
if (gpio >= uc_priv->gpio_base &&
gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
- *devp = dev;
- *offset = gpio - uc_priv->gpio_base;
+ desc->dev = dev;
+ desc->offset = gpio - uc_priv->gpio_base;
+ desc->flags = 0;
return 0;
}
}
/* No such GPIO */
- return ret ? ret : -EINVAL;
+ return ret ? ret : -ENOENT;
}
int gpio_lookup_name(const char *name, struct udevice **devp,
@@ -88,6 +94,57 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
return 0;
}
+static int gpio_find_and_xlate(struct gpio_desc *desc,
+ struct fdtdec_phandle_args *args)
+{
+ struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
+
+ /* Use the first argument as the offset by default */
+ if (args->args_count > 0)
+ desc->offset = args->args[0];
+ else
+ desc->offset = -1;
+ desc->flags = 0;
+
+ return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
+}
+
+static int dm_gpio_request(struct gpio_desc *desc, const char *label)
+{
+ struct udevice *dev = desc->dev;
+ struct gpio_dev_priv *uc_priv;
+ char *str;
+ int ret;
+
+ uc_priv = dev->uclass_priv;
+ if (uc_priv->name[desc->offset])
+ return -EBUSY;
+ str = strdup(label);
+ if (!str)
+ return -ENOMEM;
+ if (gpio_get_ops(dev)->request) {
+ ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
+ if (ret) {
+ free(str);
+ return ret;
+ }
+ }
+ uc_priv->name[desc->offset] = str;
+
+ return 0;
+}
+
+static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
+{
+ va_list args;
+ char buf[40];
+
+ va_start(args, fmt);
+ vscnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ return dm_gpio_request(desc, buf);
+}
+
/**
* gpio_request() - [COMPAT] Request GPIO
* gpio: GPIO number
@@ -102,32 +159,14 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
*/
int gpio_request(unsigned gpio, const char *label)
{
- struct gpio_dev_priv *uc_priv;
- unsigned int offset;
- struct udevice *dev;
- char *str;
+ struct gpio_desc desc;
int ret;
- ret = gpio_to_device(gpio, &dev, &offset);
+ ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
- uc_priv = dev->uclass_priv;
- if (uc_priv->name[offset])
- return -EBUSY;
- str = strdup(label);
- if (!str)
- return -ENOMEM;
- if (gpio_get_ops(dev)->request) {
- ret = gpio_get_ops(dev)->request(dev, offset, label);
- if (ret) {
- free(str);
- return ret;
- }
- }
- uc_priv->name[offset] = str;
-
- return 0;
+ return dm_gpio_request(&desc, label);
}
/**
@@ -151,25 +190,11 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...)
return gpio_request(gpio, buf);
}
-/**
- * gpio_free() - [COMPAT] Relinquish GPIO
- * gpio: GPIO number
- *
- * This function implements the API that's compatible with current
- * GPIO API used in U-Boot. The request is forwarded to particular
- * GPIO driver. Returns 0 on success, negative value on error.
- */
-int gpio_free(unsigned gpio)
+int _dm_gpio_free(struct udevice *dev, uint offset)
{
struct gpio_dev_priv *uc_priv;
- unsigned int offset;
- struct udevice *dev;
int ret;
- ret = gpio_to_device(gpio, &dev, &offset);
- if (ret)
- return ret;
-
uc_priv = dev->uclass_priv;
if (!uc_priv->name[offset])
return -ENXIO;
@@ -185,15 +210,35 @@ int gpio_free(unsigned gpio)
return 0;
}
-static int check_reserved(struct udevice *dev, unsigned offset,
- const char *func)
+/**
+ * gpio_free() - [COMPAT] Relinquish GPIO
+ * gpio: GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_free(unsigned gpio)
{
- struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_desc desc;
+ int ret;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+
+ return _dm_gpio_free(desc.dev, desc.offset);
+}
+
+static int check_reserved(struct gpio_desc *desc, const char *func)
+{
+ struct gpio_dev_priv *uc_priv = desc->dev->uclass_priv;
- if (!uc_priv->name[offset]) {
+ if (!uc_priv->name[desc->offset]) {
printf("%s: %s: error: gpio %s%d not reserved\n",
- dev->name, func,
- uc_priv->bank_name ? uc_priv->bank_name : "", offset);
+ desc->dev->name, func,
+ uc_priv->bank_name ? uc_priv->bank_name : "",
+ desc->offset);
return -EBUSY;
}
@@ -210,16 +255,17 @@ static int check_reserved(struct udevice *dev, unsigned offset,
*/
int gpio_direction_input(unsigned gpio)
{
- unsigned int offset;
- struct udevice *dev;
+ struct gpio_desc desc;
int ret;
- ret = gpio_to_device(gpio, &dev, &offset);
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+ ret = check_reserved(&desc, "dir_input");
if (ret)
return ret;
- ret = check_reserved(dev, offset, "dir_input");
- return ret ? ret : gpio_get_ops(dev)->direction_input(dev, offset);
+ return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
}
/**
@@ -233,17 +279,81 @@ int gpio_direction_input(unsigned gpio)
*/
int gpio_direction_output(unsigned gpio, int value)
{
- unsigned int offset;
- struct udevice *dev;
+ struct gpio_desc desc;
+ int ret;
+
+ ret = gpio_to_device(gpio, &desc);
+ if (ret)
+ return ret;
+ ret = check_reserved(&desc, "dir_output");
+ if (ret)
+ return ret;
+
+ return gpio_get_ops(desc.dev)->direction_output(desc.dev,
+ desc.offset, value);
+}
+
+int dm_gpio_get_value(struct gpio_desc *desc)
+{
+ int value;
+ int ret;
+
+ ret = check_reserved(desc, "get_value");
+ if (ret)
+ return ret;
+
+ value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
+
+ return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
+}
+
+int dm_gpio_set_value(struct gpio_desc *desc, int value)
+{
+ int ret;
+
+ ret = check_reserved(desc, "set_value");
+ if (ret)
+ return ret;
+
+ if (desc->flags & GPIOD_ACTIVE_LOW)
+ value = !value;
+ gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
+ return 0;
+}
+
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+{
+ struct udevice *dev = desc->dev;
+ struct dm_gpio_ops *ops = gpio_get_ops(dev);
int ret;
- ret = gpio_to_device(gpio, &dev, &offset);
+ ret = check_reserved(desc, "set_dir");
+ if (ret)
+ return ret;
+
+ if (flags & GPIOD_IS_OUT) {
+ int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+
+ if (flags & GPIOD_ACTIVE_LOW)
+ value = !value;
+ ret = ops->direction_output(dev, desc->offset, value);
+ } else if (flags & GPIOD_IS_IN) {
+ ret = ops->direction_input(dev, desc->offset);
+ }
if (ret)
return ret;
- ret = check_reserved(dev, offset, "dir_output");
+ /*
+ * Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in
+ * futures
+ */
+ desc->flags = flags;
+
+ return 0;
+}
- return ret ? ret :
- gpio_get_ops(dev)->direction_output(dev, offset, value);
+int dm_gpio_set_dir(struct gpio_desc *desc)
+{
+ return dm_gpio_set_dir_flags(desc, desc->flags);
}
/**
@@ -257,16 +367,14 @@ int gpio_direction_output(unsigned gpio, int value)
*/
int gpio_get_value(unsigned gpio)
{
- unsigned int offset;
- struct udevice *dev;
int ret;
- ret = gpio_to_device(gpio, &dev, &offset);
+ struct gpio_desc desc;
+
+ ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
- ret = check_reserved(dev, offset, "get_value");
-
- return ret ? ret : gpio_get_ops(dev)->get_value(dev, offset);
+ return dm_gpio_get_value(&desc);
}
/**
@@ -280,16 +388,13 @@ int gpio_get_value(unsigned gpio)
*/
int gpio_set_value(unsigned gpio, int value)
{
- unsigned int offset;
- struct udevice *dev;
+ struct gpio_desc desc;
int ret;
- ret = gpio_to_device(gpio, &dev, &offset);
+ ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
- ret = check_reserved(dev, offset, "set_value");
-
- return ret ? ret : gpio_get_ops(dev)->set_value(dev, offset, value);
+ return dm_gpio_set_value(&desc, value);
}
const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
@@ -409,6 +514,155 @@ unsigned gpio_get_values_as_int(const int *gpio_num_array)
return vector;
}
+static int _gpio_request_by_name_nodev(const void *blob, int node,
+ const char *list_name, int index,
+ struct gpio_desc *desc, int flags,
+ bool add_index)
+{
+ struct fdtdec_phandle_args args;
+ int ret;
+
+ desc->dev = NULL;
+ desc->offset = 0;
+ ret = fdtdec_parse_phandle_with_args(blob, node, list_name,
+ "#gpio-cells", 0, index, &args);
+ if (ret) {
+ debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__);
+ goto err;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_GPIO, args.node,
+ &desc->dev);
+ if (ret) {
+ debug("%s: uclass_get_device_by_of_offset failed\n", __func__);
+ goto err;
+ }
+ ret = gpio_find_and_xlate(desc, &args);
+ if (ret) {
+ debug("%s: gpio_find_and_xlate failed\n", __func__);
+ goto err;
+ }
+ ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s",
+ fdt_get_name(blob, node, NULL),
+ list_name, index);
+ if (ret) {
+ debug("%s: dm_gpio_requestf failed\n", __func__);
+ goto err;
+ }
+ ret = dm_gpio_set_dir_flags(desc, flags | desc->flags);
+ if (ret) {
+ debug("%s: dm_gpio_set_dir failed\n", __func__);
+ goto err;
+ }
+
+ return 0;
+err:
+ debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n",
+ __func__, fdt_get_name(blob, node, NULL), list_name, index, ret);
+ return ret;
+}
+
+int gpio_request_by_name_nodev(const void *blob, int node,
+ const char *list_name, int index,
+ struct gpio_desc *desc, int flags)
+{
+ return _gpio_request_by_name_nodev(blob, node, list_name, index, desc,
+ flags, index > 0);
+}
+
+int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
+ struct gpio_desc *desc, int flags)
+{
+ /*
+ * This isn't ideal since we don't use dev->name in the debug()
+ * calls in gpio_request_by_name(), but we can do this until
+ * gpio_request_by_name_nodev() can be dropped.
+ */
+ return gpio_request_by_name_nodev(gd->fdt_blob, dev->of_offset,
+ list_name, index, desc, flags);
+}
+
+int gpio_request_list_by_name_nodev(const void *blob, int node,
+ const char *list_name,
+ struct gpio_desc *desc, int max_count,
+ int flags)
+{
+ int count;
+ int ret;
+
+ for (count = 0; ; count++) {
+ if (count >= max_count) {
+ ret = -ENOSPC;
+ goto err;
+ }
+ ret = _gpio_request_by_name_nodev(blob, node, list_name, count,
+ &desc[count], flags, true);
+ if (ret == -ENOENT)
+ break;
+ else if (ret)
+ goto err;
+ }
+
+ /* We ran out of GPIOs in the list */
+ return count;
+
+err:
+ gpio_free_list_nodev(desc, count - 1);
+
+ return ret;
+}
+
+int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
+ struct gpio_desc *desc, int max_count,
+ int flags)
+{
+ /*
+ * This isn't ideal since we don't use dev->name in the debug()
+ * calls in gpio_request_by_name(), but we can do this until
+ * gpio_request_list_by_name_nodev() can be dropped.
+ */
+ return gpio_request_list_by_name_nodev(gd->fdt_blob, dev->of_offset,
+ list_name, desc, max_count,
+ flags);
+}
+
+int gpio_get_list_count(struct udevice *dev, const char *list_name)
+{
+ int ret;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
+ list_name, "#gpio-cells", 0, -1,
+ NULL);
+ if (ret) {
+ debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
+ __func__, dev->name, list_name, ret);
+ }
+
+ return ret;
+}
+
+int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
+{
+ /* For now, we don't do any checking of dev */
+ return _dm_gpio_free(desc->dev, desc->offset);
+}
+
+int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count)
+{
+ int i;
+
+ /* For now, we don't do any checking of dev */
+ for (i = 0; i < count; i++)
+ dm_gpio_free(dev, &desc[i]);
+
+ return 0;
+}
+
+int gpio_free_list_nodev(struct gpio_desc *desc, int count)
+{
+ return gpio_free_list(NULL, desc, count);
+}
+
/* We need to renumber the GPIOs when any driver is probed/removed */
static int gpio_renumber(struct udevice *removed_dev)
{
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 6c41a42..0a245ba 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -13,6 +13,7 @@
#include <asm/io.h>
#include <asm/gpio.h>
#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -275,12 +276,22 @@ static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_FUNC;
}
+static int exynos_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct fdtdec_phandle_args *args)
+{
+ desc->offset = args->args[0];
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
static const struct dm_gpio_ops gpio_exynos_ops = {
.direction_input = exynos_gpio_direction_input,
.direction_output = exynos_gpio_direction_output,
.get_value = exynos_gpio_get_value,
.set_value = exynos_gpio_set_value,
.get_function = exynos_gpio_get_function,
+ .xlate = exynos_gpio_xlate,
};
static int gpio_exynos_probe(struct udevice *dev)
@@ -342,7 +353,7 @@ static int gpio_exynos_bind(struct udevice *parent)
plat->bank_name, plat, -1, &dev);
if (ret)
return ret;
- dev->of_offset = parent->of_offset;
+ dev->of_offset = node;
}
return 0;
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index 53c80d5..d564c25 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -8,6 +8,7 @@
#include <fdtdec.h>
#include <malloc.h>
#include <asm/gpio.h>
+#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -130,12 +131,31 @@ static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_INPUT;
}
+static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct fdtdec_phandle_args *args)
+{
+ desc->offset = args->args[0];
+ if (args->args_count < 2)
+ return 0;
+ if (args->args[1] & GPIO_ACTIVE_LOW)
+ desc->flags |= GPIOD_ACTIVE_LOW;
+ if (args->args[1] & 2)
+ desc->flags |= GPIOD_IS_IN;
+ if (args->args[1] & 4)
+ desc->flags |= GPIOD_IS_OUT;
+ if (args->args[1] & 8)
+ desc->flags |= GPIOD_IS_OUT_ACTIVE;
+
+ return 0;
+}
+
static const struct dm_gpio_ops gpio_sandbox_ops = {
.direction_input = sb_gpio_direction_input,
.direction_output = sb_gpio_direction_output,
.get_value = sb_gpio_get_value,
.set_value = sb_gpio_set_value,
.get_function = sb_gpio_get_function,
+ .xlate = sb_gpio_xlate,
};
static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 88f7ef5..43928b8 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -21,6 +21,7 @@
#include <asm/arch/tegra.h>
#include <asm/gpio.h>
#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -251,6 +252,22 @@ static int tegra_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_INPUT;
}
+static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct fdtdec_phandle_args *args)
+{
+ int gpio, port, ret;
+
+ gpio = args->args[0];
+ port = gpio / TEGRA_GPIOS_PER_PORT;
+ ret = device_get_child(dev, port, &desc->dev);
+ if (ret)
+ return ret;
+ desc->offset = gpio % TEGRA_GPIOS_PER_PORT;
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
static const struct dm_gpio_ops gpio_tegra_ops = {
.request = tegra_gpio_request,
.direction_input = tegra_gpio_direction_input,
@@ -258,6 +275,7 @@ static const struct dm_gpio_ops gpio_tegra_ops = {
.get_value = tegra_gpio_get_value,
.set_value = tegra_gpio_set_value,
.get_function = tegra_gpio_get_function,
+ .xlate = tegra_gpio_xlate,
};
/**
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index e69de29..202ea5d 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -0,0 +1,22 @@
+config DM_I2C
+ bool "Enable Driver Model for I2C drivers"
+ depends on DM
+ help
+ If you want to use driver model for I2C drivers, say Y.
+ To use legacy I2C drivers, say N.
+
+config SYS_I2C_UNIPHIER
+ bool "UniPhier I2C driver"
+ depends on ARCH_UNIPHIER && DM_I2C
+ default y
+ help
+ Support for Panasonic UniPhier I2C controller driver. This I2C
+ controller is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs.
+
+config SYS_I2C_UNIPHIER_F
+ bool "UniPhier FIFO-builtin I2C driver"
+ depends on ARCH_UNIPHIER && DM_I2C
+ default y
+ help
+ Support for Panasonic UniPhier FIFO-builtin I2C controller driver.
+ This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 6f3c86c..774bc94 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -5,6 +5,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
+obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
@@ -31,4 +32,6 @@ obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
+obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
+obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
diff --git a/drivers/i2c/i2c-uclass-compat.c b/drivers/i2c/i2c-uclass-compat.c
new file mode 100644
index 0000000..223f238
--- /dev/null
+++ b/drivers/i2c/i2c-uclass-compat.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+
+static int cur_busnum;
+
+static int i2c_compat_get_device(uint chip_addr, int alen,
+ struct udevice **devp)
+{
+ struct dm_i2c_chip *chip;
+ int ret;
+
+ ret = i2c_get_chip_for_busnum(cur_busnum, chip_addr, alen, devp);
+ if (ret)
+ return ret;
+ chip = dev_get_parent_platdata(*devp);
+ if (chip->offset_len != alen) {
+ printf("I2C chip %x: requested alen %d does not match chip offset_len %d\n",
+ chip_addr, alen, chip->offset_len);
+ return -EADDRNOTAVAIL;
+ }
+
+ return 0;
+}
+
+int i2c_probe(uint8_t chip_addr)
+{
+ struct udevice *bus, *dev;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_I2C, cur_busnum, &bus);
+ if (ret) {
+ debug("Cannot find I2C bus %d: err=%d\n", cur_busnum, ret);
+ return ret;
+ }
+
+ if (!bus)
+ return -ENOENT;
+
+ return dm_i2c_probe(bus, chip_addr, 0, &dev);
+}
+
+int i2c_read(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
+ int len)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_compat_get_device(chip_addr, alen, &dev);
+ if (ret)
+ return ret;
+
+ return dm_i2c_read(dev, addr, buffer, len);
+}
+
+int i2c_write(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
+ int len)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = i2c_compat_get_device(chip_addr, alen, &dev);
+ if (ret)
+ return ret;
+
+ return dm_i2c_write(dev, addr, buffer, len);
+}
+
+int i2c_get_bus_num_fdt(int node)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_of_offset(UCLASS_I2C, node, &bus);
+ if (ret)
+ return ret;
+
+ return bus->seq;
+}
+
+unsigned int i2c_get_bus_num(void)
+{
+ return cur_busnum;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+ cur_busnum = bus;
+
+ return 0;
+}
+
+void i2c_init(int speed, int slaveaddr)
+{
+ /* Nothing to do here - the init happens through driver model */
+}
+
+void board_i2c_init(const void *blob)
+{
+ /* Nothing to do here - the init happens through driver model */
+}
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 005bf86..eafa457 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -50,7 +50,7 @@ static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
static int i2c_read_bytewise(struct udevice *dev, uint offset,
uint8_t *buffer, int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
@@ -79,7 +79,7 @@ static int i2c_read_bytewise(struct udevice *dev, uint offset,
static int i2c_write_bytewise(struct udevice *dev, uint offset,
const uint8_t *buffer, int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
@@ -100,9 +100,9 @@ static int i2c_write_bytewise(struct udevice *dev, uint offset,
return 0;
}
-int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
+int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
@@ -130,9 +130,10 @@ int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
return ops->xfer(bus, msg, msg_count);
}
-int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
+int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
+ int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
@@ -219,10 +220,10 @@ static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
return ops->xfer(bus, msg, 1);
}
-static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
+static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
- struct dm_i2c_chip chip;
+ struct dm_i2c_chip *chip;
char name[30], *str;
struct udevice *dev;
int ret;
@@ -235,11 +236,11 @@ static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
goto err_bind;
/* Tell the device what we know about it */
- memset(&chip, '\0', sizeof(chip));
- chip.chip_addr = chip_addr;
- chip.offset_len = 1; /* we assume */
- ret = device_probe_child(dev, &chip);
- debug("%s: device_probe_child: ret=%d\n", __func__, ret);
+ chip = dev_get_parent_platdata(dev);
+ chip->chip_addr = chip_addr;
+ chip->offset_len = offset_len;
+ ret = device_probe(dev);
+ debug("%s: device_probe: ret=%d\n", __func__, ret);
if (ret)
goto err_probe;
@@ -247,13 +248,18 @@ static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
return 0;
err_probe:
+ /*
+ * If the device failed to probe, unbind it. There is nothing there
+ * on the bus so we don't want to leave it lying around
+ */
device_unbind(dev);
err_bind:
free(str);
return ret;
}
-int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
+int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len,
+ struct udevice **devp)
{
struct udevice *dev;
@@ -261,15 +267,9 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
bus->name, chip_addr);
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
- struct dm_i2c_chip store;
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
int ret;
- if (!chip) {
- chip = &store;
- i2c_chip_ofdata_to_platdata(gd->fdt_blob,
- dev->of_offset, chip);
- }
if (chip->chip_addr == chip_addr) {
ret = device_probe(dev);
debug("found, ret=%d\n", ret);
@@ -280,10 +280,11 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
}
}
debug("not found\n");
- return i2c_bind_driver(bus, chip_addr, devp);
+ return i2c_bind_driver(bus, chip_addr, offset_len, devp);
}
-int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
+int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
+ struct udevice **devp)
{
struct udevice *bus;
int ret;
@@ -293,7 +294,7 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
debug("Cannot find I2C bus %d\n", busnum);
return ret;
}
- ret = i2c_get_chip(bus, chip_addr, devp);
+ ret = i2c_get_chip(bus, chip_addr, offset_len, devp);
if (ret) {
debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
busnum);
@@ -303,8 +304,8 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
return 0;
}
-int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
- struct udevice **devp)
+int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
+ struct udevice **devp)
{
int ret;
@@ -318,7 +319,7 @@ int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
return ret;
/* The chip was found, see if we have a driver, and probe it */
- ret = i2c_get_chip(bus, chip_addr, devp);
+ ret = i2c_get_chip(bus, chip_addr, 1, devp);
debug("%s: i2c_get_chip: ret=%d\n", __func__, ret);
return ret;
@@ -364,7 +365,7 @@ int i2c_get_bus_speed(struct udevice *bus)
int i2c_set_chip_flags(struct udevice *dev, uint flags)
{
struct udevice *bus = dev->parent;
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
int ret;
@@ -380,7 +381,7 @@ int i2c_set_chip_flags(struct udevice *dev, uint flags)
int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
*flagsp = chip->flags;
@@ -389,7 +390,7 @@ int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
if (offset_len > I2C_MAX_OFFSET_LEN)
return -EINVAL;
@@ -419,7 +420,8 @@ int i2c_deblock(struct udevice *bus)
int i2c_chip_ofdata_to_platdata(const void *blob, int node,
struct dm_i2c_chip *chip)
{
- chip->offset_len = 1; /* default */
+ chip->offset_len = fdtdec_get_int(gd->fdt_blob, node,
+ "u-boot,i2c-offset-len", 1);
chip->flags = 0;
chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
if (chip->chip_addr == -1) {
@@ -441,18 +443,31 @@ static int i2c_post_probe(struct udevice *dev)
return i2c_set_bus_speed(dev, i2c->speed_hz);
}
-int i2c_post_bind(struct udevice *dev)
+static int i2c_post_bind(struct udevice *dev)
{
/* Scan the bus for devices */
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
+static int i2c_child_post_bind(struct udevice *dev)
+{
+ struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
+
+ if (dev->of_offset == -1)
+ return 0;
+
+ return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
+}
+
UCLASS_DRIVER(i2c) = {
.id = UCLASS_I2C,
.name = "i2c",
- .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = i2c_post_bind,
.post_probe = i2c_post_probe,
+ .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+ .per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
+ .child_post_bind = i2c_child_post_bind,
};
UCLASS_DRIVER(i2c_generic) = {
diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c
new file mode 100644
index 0000000..6707edd
--- /dev/null
+++ b/drivers/i2c/i2c-uniphier-f.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ * Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <i2c.h>
+#include <fdtdec.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct uniphier_fi2c_regs {
+ u32 cr; /* control register */
+#define I2C_CR_MST (1 << 3) /* master mode */
+#define I2C_CR_STA (1 << 2) /* start condition */
+#define I2C_CR_STO (1 << 1) /* stop condition */
+#define I2C_CR_NACK (1 << 0) /* not ACK */
+ u32 dttx; /* send FIFO (write-only) */
+#define dtrx dttx /* receive FIFO (read-only) */
+#define I2C_DTTX_CMD (1 << 8) /* send command (slave addr) */
+#define I2C_DTTX_RD (1 << 0) /* read */
+ u32 __reserved; /* no register at offset 0x08 */
+ u32 slad; /* slave address */
+ u32 cyc; /* clock cycle control */
+ u32 lctl; /* clock low period control */
+ u32 ssut; /* restart/stop setup time control */
+ u32 dsut; /* data setup time control */
+ u32 intr; /* interrupt status */
+ u32 ie; /* interrupt enable */
+ u32 ic; /* interrupt clear */
+#define I2C_INT_TE (1 << 9) /* TX FIFO empty */
+#define I2C_INT_RB (1 << 4) /* received specified bytes */
+#define I2C_INT_NA (1 << 2) /* no answer */
+#define I2C_INT_AL (1 << 1) /* arbitration lost */
+ u32 sr; /* status register */
+#define I2C_SR_DB (1 << 12) /* device busy */
+#define I2C_SR_BB (1 << 8) /* bus busy */
+#define I2C_SR_RFF (1 << 3) /* Rx FIFO full */
+#define I2C_SR_RNE (1 << 2) /* Rx FIFO not empty */
+#define I2C_SR_TNF (1 << 1) /* Tx FIFO not full */
+#define I2C_SR_TFE (1 << 0) /* Tx FIFO empty */
+ u32 __reserved2; /* no register at offset 0x30 */
+ u32 rst; /* reset control */
+#define I2C_RST_TBRST (1 << 2) /* clear Tx FIFO */
+#define I2C_RST_RBRST (1 << 1) /* clear Rx FIFO */
+#define I2C_RST_RST (1 << 0) /* forcible bus reset */
+ u32 bm; /* bus monitor */
+ u32 noise; /* noise filter control */
+ u32 tbc; /* Tx byte count setting */
+ u32 rbc; /* Rx byte count setting */
+ u32 tbcm; /* Tx byte count monitor */
+ u32 rbcm; /* Rx byte count monitor */
+ u32 brst; /* bus reset */
+#define I2C_BRST_FOEN (1 << 1) /* normal operation */
+#define I2C_BRST_RSCLO (1 << 0) /* release SCL low fixing */
+};
+
+#define FIOCLK 50000000
+
+struct uniphier_fi2c_dev {
+ struct uniphier_fi2c_regs __iomem *regs; /* register base */
+ unsigned long fioclk; /* internal operation clock */
+ unsigned long timeout; /* time out (us) */
+};
+
+static int poll_status(u32 __iomem *reg, u32 flag)
+{
+ int wait = 1000000; /* 1 sec is long enough */
+
+ while (readl(reg) & flag) {
+ if (wait-- < 0)
+ return -EREMOTEIO;
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static int reset_bus(struct uniphier_fi2c_regs __iomem *regs)
+{
+ int ret;
+
+ /* bus forcible reset */
+ writel(I2C_RST_RST, &regs->rst);
+ ret = poll_status(&regs->rst, I2C_RST_RST);
+ if (ret < 0)
+ debug("error: fail to reset I2C controller\n");
+
+ return ret;
+}
+
+static int check_device_busy(struct uniphier_fi2c_regs __iomem *regs)
+{
+ int ret;
+
+ ret = poll_status(&regs->sr, I2C_SR_DB);
+ if (ret < 0) {
+ debug("error: device busy too long. reset...\n");
+ ret = reset_bus(regs);
+ }
+
+ return ret;
+}
+
+static int uniphier_fi2c_probe(struct udevice *dev)
+{
+ fdt_addr_t addr;
+ fdt_size_t size;
+ struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
+ int ret;
+
+ addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg",
+ &size);
+
+ priv->regs = map_sysmem(addr, size);
+
+ if (!priv->regs)
+ return -ENOMEM;
+
+ priv->fioclk = FIOCLK;
+
+ /* bus forcible reset */
+ ret = reset_bus(priv->regs);
+ if (ret < 0)
+ return ret;
+
+ writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &priv->regs->brst);
+
+ return 0;
+}
+
+static int uniphier_fi2c_remove(struct udevice *dev)
+{
+ struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
+
+ unmap_sysmem(priv->regs);
+
+ return 0;
+}
+
+static int wait_for_irq(struct uniphier_fi2c_dev *dev, u32 flags,
+ bool *stop)
+{
+ u32 irq;
+ unsigned long wait = dev->timeout;
+ int ret = -EREMOTEIO;
+
+ do {
+ udelay(1);
+ irq = readl(&dev->regs->intr);
+ } while (!(irq & flags) && wait--);
+
+ if (wait < 0) {
+ debug("error: time out\n");
+ return ret;
+ }
+
+ if (irq & I2C_INT_AL) {
+ debug("error: arbitration lost\n");
+ *stop = false;
+ return ret;
+ }
+
+ if (irq & I2C_INT_NA) {
+ debug("error: no answer\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int issue_stop(struct uniphier_fi2c_dev *dev, int old_ret)
+{
+ int ret;
+
+ debug("stop condition\n");
+ writel(I2C_CR_MST | I2C_CR_STO, &dev->regs->cr);
+
+ ret = poll_status(&dev->regs->sr, I2C_SR_DB);
+ if (ret < 0)
+ debug("error: device busy after operation\n");
+
+ return old_ret ? old_ret : ret;
+}
+
+static int uniphier_fi2c_transmit(struct uniphier_fi2c_dev *dev, uint addr,
+ uint len, const u8 *buf, bool *stop)
+{
+ int ret;
+ const u32 irq_flags = I2C_INT_TE | I2C_INT_NA | I2C_INT_AL;
+ struct uniphier_fi2c_regs __iomem *regs = dev->regs;
+
+ debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ writel(I2C_DTTX_CMD | addr << 1, &regs->dttx);
+
+ writel(irq_flags, &regs->ie);
+ writel(irq_flags, &regs->ic);
+
+ debug("start condition\n");
+ writel(I2C_CR_MST | I2C_CR_STA, &regs->cr);
+
+ ret = wait_for_irq(dev, irq_flags, stop);
+ if (ret < 0)
+ goto error;
+
+ while (len--) {
+ debug("sending %x\n", *buf);
+ writel(*buf++, &regs->dttx);
+
+ writel(irq_flags, &regs->ic);
+
+ ret = wait_for_irq(dev, irq_flags, stop);
+ if (ret < 0)
+ goto error;
+ }
+
+error:
+ writel(irq_flags, &regs->ic);
+
+ if (*stop)
+ ret = issue_stop(dev, ret);
+
+ return ret;
+}
+
+static int uniphier_fi2c_receive(struct uniphier_fi2c_dev *dev, uint addr,
+ uint len, u8 *buf, bool *stop)
+{
+ int ret = 0;
+ const u32 irq_flags = I2C_INT_RB | I2C_INT_NA | I2C_INT_AL;
+ struct uniphier_fi2c_regs __iomem *regs = dev->regs;
+
+ debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ /*
+ * In case 'len == 0', only the slave address should be sent
+ * for probing, which is covered by the transmit function.
+ */
+ if (len == 0)
+ return uniphier_fi2c_transmit(dev, addr, len, buf, stop);
+
+ writel(I2C_DTTX_CMD | I2C_DTTX_RD | addr << 1, &regs->dttx);
+
+ writel(0, &regs->rbc);
+ writel(irq_flags, &regs->ie);
+ writel(irq_flags, &regs->ic);
+
+ debug("start condition\n");
+ writel(I2C_CR_MST | I2C_CR_STA | (len == 1 ? I2C_CR_NACK : 0),
+ &regs->cr);
+
+ while (len--) {
+ ret = wait_for_irq(dev, irq_flags, stop);
+ if (ret < 0)
+ goto error;
+
+ *buf++ = readl(&regs->dtrx);
+ debug("received %x\n", *(buf - 1));
+
+ if (len == 1)
+ writel(I2C_CR_MST | I2C_CR_NACK, &regs->cr);
+
+ writel(irq_flags, &regs->ic);
+ }
+
+error:
+ writel(irq_flags, &regs->ic);
+
+ if (*stop)
+ ret = issue_stop(dev, ret);
+
+ return ret;
+}
+
+static int uniphier_fi2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ int ret;
+ struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
+ bool stop;
+
+ ret = check_device_busy(dev->regs);
+ if (ret < 0)
+ return ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ /* If next message is read, skip the stop condition */
+ stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
+
+ if (msg->flags & I2C_M_RD)
+ ret = uniphier_fi2c_receive(dev, msg->addr, msg->len,
+ msg->buf, &stop);
+ else
+ ret = uniphier_fi2c_transmit(dev, msg->addr, msg->len,
+ msg->buf, &stop);
+
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int uniphier_fi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ int ret;
+ unsigned int clk_count;
+ struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
+ struct uniphier_fi2c_regs __iomem *regs = dev->regs;
+
+ /* max supported frequency is 400 kHz */
+ if (speed > 400000)
+ return -EINVAL;
+
+ ret = check_device_busy(dev->regs);
+ if (ret < 0)
+ return ret;
+
+ /* make sure the bus is idle when changing the frequency */
+ writel(I2C_BRST_RSCLO, &regs->brst);
+
+ clk_count = dev->fioclk / speed;
+
+ writel(clk_count, &regs->cyc);
+ writel(clk_count / 2, &regs->lctl);
+ writel(clk_count / 2, &regs->ssut);
+ writel(clk_count / 16, &regs->dsut);
+
+ writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &regs->brst);
+
+ /*
+ * Theoretically, each byte can be transferred in
+ * 1000000 * 9 / speed usec.
+ * This time out value is long enough.
+ */
+ dev->timeout = 100000000L / speed;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops uniphier_fi2c_ops = {
+ .xfer = uniphier_fi2c_xfer,
+ .set_bus_speed = uniphier_fi2c_set_bus_speed,
+};
+
+static const struct udevice_id uniphier_fi2c_of_match[] = {
+ { .compatible = "panasonic,uniphier-fi2c" },
+ {},
+};
+
+U_BOOT_DRIVER(uniphier_fi2c) = {
+ .name = "uniphier-fi2c",
+ .id = UCLASS_I2C,
+ .of_match = uniphier_fi2c_of_match,
+ .probe = uniphier_fi2c_probe,
+ .remove = uniphier_fi2c_remove,
+ .priv_auto_alloc_size = sizeof(struct uniphier_fi2c_dev),
+ .ops = &uniphier_fi2c_ops,
+};
diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c
new file mode 100644
index 0000000..64a9ed8
--- /dev/null
+++ b/drivers/i2c/i2c-uniphier.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ * Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <i2c.h>
+#include <fdtdec.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct uniphier_i2c_regs {
+ u32 dtrm; /* data transmission */
+#define I2C_DTRM_STA (1 << 10)
+#define I2C_DTRM_STO (1 << 9)
+#define I2C_DTRM_NACK (1 << 8)
+#define I2C_DTRM_RD (1 << 0)
+ u32 drec; /* data reception */
+#define I2C_DREC_STS (1 << 12)
+#define I2C_DREC_LRB (1 << 11)
+#define I2C_DREC_LAB (1 << 9)
+ u32 myad; /* slave address */
+ u32 clk; /* clock frequency control */
+ u32 brst; /* bus reset */
+#define I2C_BRST_FOEN (1 << 1)
+#define I2C_BRST_BRST (1 << 0)
+ u32 hold; /* hold time control */
+ u32 bsts; /* bus status monitor */
+ u32 noise; /* noise filter control */
+ u32 setup; /* setup time control */
+};
+
+#define IOBUS_FREQ 100000000
+
+struct uniphier_i2c_dev {
+ struct uniphier_i2c_regs __iomem *regs; /* register base */
+ unsigned long input_clk; /* master clock (Hz) */
+ unsigned long wait_us; /* wait for every byte transfer (us) */
+};
+
+static int uniphier_i2c_probe(struct udevice *dev)
+{
+ fdt_addr_t addr;
+ fdt_size_t size;
+ struct uniphier_i2c_dev *priv = dev_get_priv(dev);
+
+ addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
+
+ priv->regs = map_sysmem(addr, size);
+
+ if (!priv->regs)
+ return -ENOMEM;
+
+ priv->input_clk = IOBUS_FREQ;
+
+ /* deassert reset */
+ writel(0x3, &priv->regs->brst);
+
+ return 0;
+}
+
+static int uniphier_i2c_remove(struct udevice *dev)
+{
+ struct uniphier_i2c_dev *priv = dev_get_priv(dev);
+
+ unmap_sysmem(priv->regs);
+
+ return 0;
+}
+
+static int send_and_recv_byte(struct uniphier_i2c_dev *dev, u32 dtrm)
+{
+ writel(dtrm, &dev->regs->dtrm);
+
+ /*
+ * This controller only provides interruption to inform the completion
+ * of each byte transfer. (No status register to poll it.)
+ * Unfortunately, U-Boot does not have a good support of interrupt.
+ * Wait for a while.
+ */
+ udelay(dev->wait_us);
+
+ return readl(&dev->regs->drec);
+}
+
+static int send_byte(struct uniphier_i2c_dev *dev, u32 dtrm, bool *stop)
+{
+ int ret = 0;
+ u32 drec;
+
+ drec = send_and_recv_byte(dev, dtrm);
+
+ if (drec & I2C_DREC_LAB) {
+ debug("uniphier_i2c: bus arbitration failed\n");
+ *stop = false;
+ ret = -EREMOTEIO;
+ }
+ if (drec & I2C_DREC_LRB) {
+ debug("uniphier_i2c: slave did not return ACK\n");
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+static int uniphier_i2c_transmit(struct uniphier_i2c_dev *dev, uint addr,
+ uint len, const u8 *buf, bool *stop)
+{
+ int ret;
+
+ debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop);
+ if (ret < 0)
+ goto fail;
+
+ while (len--) {
+ ret = send_byte(dev, I2C_DTRM_NACK | *buf++, stop);
+ if (ret < 0)
+ goto fail;
+ }
+
+fail:
+ if (*stop)
+ writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
+
+ return ret;
+}
+
+static int uniphier_i2c_receive(struct uniphier_i2c_dev *dev, uint addr,
+ uint len, u8 *buf, bool *stop)
+{
+ int ret;
+
+ debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+ ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK |
+ I2C_DTRM_RD | addr << 1, stop);
+ if (ret < 0)
+ goto fail;
+
+ while (len--)
+ *buf++ = send_and_recv_byte(dev, len ? 0 : I2C_DTRM_NACK);
+
+fail:
+ if (*stop)
+ writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
+
+ return ret;
+}
+
+static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ int ret = 0;
+ struct uniphier_i2c_dev *dev = dev_get_priv(bus);
+ bool stop;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ /* If next message is read, skip the stop condition */
+ stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
+
+ if (msg->flags & I2C_M_RD)
+ ret = uniphier_i2c_receive(dev, msg->addr, msg->len,
+ msg->buf, &stop);
+ else
+ ret = uniphier_i2c_transmit(dev, msg->addr, msg->len,
+ msg->buf, &stop);
+
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct uniphier_i2c_dev *priv = dev_get_priv(bus);
+
+ /* max supported frequency is 400 kHz */
+ if (speed > 400000)
+ return -EINVAL;
+
+ /* bus reset: make sure the bus is idle when change the frequency */
+ writel(0x1, &priv->regs->brst);
+
+ writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed),
+ &priv->regs->clk);
+
+ writel(0x3, &priv->regs->brst);
+
+ /*
+ * Theoretically, each byte can be transferred in
+ * 1000000 * 9 / speed usec. For safety, wait more than double.
+ */
+ priv->wait_us = 20000000 / speed;
+
+ return 0;
+}
+
+
+static const struct dm_i2c_ops uniphier_i2c_ops = {
+ .xfer = uniphier_i2c_xfer,
+ .set_bus_speed = uniphier_i2c_set_bus_speed,
+};
+
+static const struct udevice_id uniphier_i2c_of_match[] = {
+ { .compatible = "panasonic,uniphier-i2c" },
+ {},
+};
+
+U_BOOT_DRIVER(uniphier_i2c) = {
+ .name = "uniphier-i2c",
+ .id = UCLASS_I2C,
+ .of_match = uniphier_i2c_of_match,
+ .probe = uniphier_i2c_probe,
+ .remove = uniphier_i2c_remove,
+ .priv_auto_alloc_size = sizeof(struct uniphier_i2c_dev),
+ .ops = &uniphier_i2c_ops,
+};
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index fd328f0..0dd1abc 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -9,8 +9,9 @@
* as they seem to have the same I2C controller inside.
* The different address mapping is handled by the s3c24xx.h files below.
*/
-
#include <common.h>
+#include <errno.h>
+#include <dm.h>
#include <fdtdec.h>
#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
#include <asm/arch/clk.h>
@@ -121,13 +122,23 @@
#define CONFIG_MAX_I2C_NUM 1
#endif
+DECLARE_GLOBAL_DATA_PTR;
+
/*
* For SPL boot some boards need i2c before SDRAM is initialised so force
* variables to live in SRAM
*/
+#ifdef CONFIG_SYS_I2C
static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
__attribute__((section(".data")));
+#endif
+
+enum exynos_i2c_type {
+ EXYNOS_I2C_STD,
+ EXYNOS_I2C_HS,
+};
+#ifdef CONFIG_SYS_I2C
/**
* Get a pointer to the given bus index
*
@@ -147,6 +158,7 @@ static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx)
debug("Undefined bus: %d\n", bus_idx);
return NULL;
}
+#endif
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
static int GetI2CSDA(void)
@@ -251,6 +263,7 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c)
writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
}
+#ifdef CONFIG_SYS_I2C
static struct s3c24x0_i2c *get_base_i2c(int bus)
{
#ifdef CONFIG_EXYNOS4
@@ -267,6 +280,7 @@ static struct s3c24x0_i2c *get_base_i2c(int bus)
return s3c24x0_get_base_i2c();
#endif
}
+#endif
static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
{
@@ -326,7 +340,7 @@ static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus)
return 0;
}
}
- return -1;
+ return -EINVAL;
}
static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus)
@@ -398,18 +412,20 @@ static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus)
hsi2c_ch_init(i2c_bus);
}
+#ifdef CONFIG_SYS_I2C
static void s3c24x0_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
struct s3c24x0_i2c *i2c;
struct s3c24x0_i2c_bus *bus;
-
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
#endif
ulong start_time = get_timer(0);
- /* By default i2c channel 0 is the current bus */
i2c = get_base_i2c(adap->hwadapnr);
+ bus = &i2c_bus[adap->hwadapnr];
+ if (!bus)
+ return;
/*
* In case the previous transfer is still going, wait to give it a
@@ -470,12 +486,13 @@ static void s3c24x0_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
#endif
}
#endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */
+
i2c_ch_init(i2c, speed, slaveadd);
- bus = &i2c_bus[adap->hwadapnr];
bus->active = true;
bus->regs = i2c;
}
+#endif /* CONFIG_SYS_I2C */
/*
* Poll the appropriate bit of the fifo status register until the interface is
@@ -698,20 +715,27 @@ static int hsi2c_read(struct exynos5_hsi2c *i2c,
return rv;
}
+#ifdef CONFIG_SYS_I2C
static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap,
- unsigned int speed)
+ unsigned int speed)
+#else
+static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+#endif
{
struct s3c24x0_i2c_bus *i2c_bus;
+#ifdef CONFIG_SYS_I2C
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
- return -1;
-
+ return -EFAULT;
+#else
+ i2c_bus = dev_get_priv(dev);
+#endif
i2c_bus->clock_frequency = speed;
if (i2c_bus->is_highspeed) {
if (hsi2c_get_clk_details(i2c_bus))
- return -1;
+ return -EFAULT;
hsi2c_ch_init(i2c_bus);
} else {
i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
@@ -721,17 +745,6 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap,
return 0;
}
-#ifdef CONFIG_EXYNOS5
-static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
-{
- /* This will override the speed selected in the fdt for that port */
- debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
- if (i2c_set_bus_speed(speed))
- printf("i2c_init: failed to init bus %d for speed = %d\n",
- adap->hwadapnr, speed);
-}
-#endif
-
/*
* cmd_type is 0 for write, 1 for read.
*
@@ -844,15 +857,23 @@ bailout:
return result;
}
+#ifdef CONFIG_SYS_I2C
static int s3c24x0_i2c_probe(struct i2c_adapter *adap, uchar chip)
+#else
+static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
+#endif
{
struct s3c24x0_i2c_bus *i2c_bus;
uchar buf[1];
int ret;
+#ifdef CONFIG_SYS_I2C
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
- return -1;
+ return -EFAULT;
+#else
+ i2c_bus = dev_get_priv(dev);
+#endif
buf[0] = 0;
/*
@@ -871,6 +892,7 @@ static int s3c24x0_i2c_probe(struct i2c_adapter *adap, uchar chip)
return ret != I2C_OK;
}
+#ifdef CONFIG_SYS_I2C
static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
@@ -878,9 +900,13 @@ static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
uchar xaddr[4];
int ret;
+ i2c_bus = get_bus(adap->hwadapnr);
+ if (!i2c_bus)
+ return -EFAULT;
+
if (alen > 4) {
debug("I2C read: addr len %d not supported\n", alen);
- return 1;
+ return -EADDRNOTAVAIL;
}
if (alen > 0) {
@@ -906,10 +932,6 @@ static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
- i2c_bus = get_bus(adap->hwadapnr);
- if (!i2c_bus)
- return -1;
-
if (i2c_bus->is_highspeed)
ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen],
alen, buffer, len);
@@ -921,7 +943,7 @@ static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
if (i2c_bus->is_highspeed)
exynos5_i2c_reset(i2c_bus);
debug("I2c read failed %d\n", ret);
- return 1;
+ return -EIO;
}
return 0;
}
@@ -933,9 +955,13 @@ static int s3c24x0_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
uchar xaddr[4];
int ret;
+ i2c_bus = get_bus(adap->hwadapnr);
+ if (!i2c_bus)
+ return -EFAULT;
+
if (alen > 4) {
debug("I2C write: addr len %d not supported\n", alen);
- return 1;
+ return -EINVAL;
}
if (alen > 0) {
@@ -960,10 +986,6 @@ static int s3c24x0_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
- i2c_bus = get_bus(adap->hwadapnr);
- if (!i2c_bus)
- return -1;
-
if (i2c_bus->is_highspeed)
ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen],
alen, buffer, len, true);
@@ -985,7 +1007,7 @@ static void process_nodes(const void *blob, int node_list[], int count,
int is_highspeed)
{
struct s3c24x0_i2c_bus *bus;
- int i;
+ int i, flags;
for (i = 0; i < count; i++) {
int node = node_list[i];
@@ -997,12 +1019,15 @@ static void process_nodes(const void *blob, int node_list[], int count,
bus->active = true;
bus->is_highspeed = is_highspeed;
- if (is_highspeed)
+ if (is_highspeed) {
+ flags = PINMUX_FLAG_HS_MODE;
bus->hsregs = (struct exynos5_hsi2c *)
fdtdec_get_addr(blob, node, "reg");
- else
+ } else {
+ flags = 0;
bus->regs = (struct s3c24x0_i2c *)
fdtdec_get_addr(blob, node, "reg");
+ }
bus->id = pinmux_decode_periph_id(blob, node);
bus->clock_frequency = fdtdec_get_int(blob, node,
@@ -1010,7 +1035,7 @@ static void process_nodes(const void *blob, int node_list[], int count,
CONFIG_SYS_I2C_S3C24X0_SPEED);
bus->node = node;
bus->bus_num = i;
- exynos_pinmux_config(bus->id, 0);
+ exynos_pinmux_config(PERIPH_ID_I2C0 + bus->id, flags);
/* Mark position as used */
node_list[i] = -1;
@@ -1033,7 +1058,6 @@ void board_i2c_init(const void *blob)
COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
CONFIG_MAX_I2C_NUM);
process_nodes(blob, node_list, count, 1);
-
}
int i2c_get_bus_num_fdt(int node)
@@ -1046,7 +1070,7 @@ int i2c_get_bus_num_fdt(int node)
}
debug("%s: Can't find any matched I2C bus\n", __func__);
- return -1;
+ return -EINVAL;
}
int i2c_reset_port_fdt(const void *blob, int node)
@@ -1057,18 +1081,18 @@ int i2c_reset_port_fdt(const void *blob, int node)
bus = i2c_get_bus_num_fdt(node);
if (bus < 0) {
debug("could not get bus for node %d\n", node);
- return -1;
+ return bus;
}
i2c_bus = get_bus(bus);
if (!i2c_bus) {
- debug("get_bus() failed for node node %d\n", node);
- return -1;
+ debug("get_bus() failed for node %d\n", node);
+ return -EFAULT;
}
if (i2c_bus->is_highspeed) {
if (hsi2c_get_clk_details(i2c_bus))
- return -1;
+ return -EINVAL;
hsi2c_ch_init(i2c_bus);
} else {
i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
@@ -1077,7 +1101,17 @@ int i2c_reset_port_fdt(const void *blob, int node)
return 0;
}
-#endif
+#endif /* CONFIG_OF_CONTROL */
+
+#ifdef CONFIG_EXYNOS5
+static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+ /* This will override the speed selected in the fdt for that port */
+ debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
+ if (i2c_set_bus_speed(speed))
+ error("i2c_init: failed to init bus for speed = %d", speed);
+}
+#endif /* CONFIG_EXYNOS5 */
/*
* Register s3c24x0 i2c adapters
@@ -1247,3 +1281,120 @@ U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
#endif
+#endif /* CONFIG_SYS_I2C */
+
+#ifdef CONFIG_DM_I2C
+static int i2c_write_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
+ uchar *buffer, int len, bool end_with_repeated_start)
+{
+ int ret;
+
+ if (i2c_bus->is_highspeed) {
+ ret = hsi2c_write(i2c_bus->hsregs, chip, 0, 0,
+ buffer, len, true);
+ if (ret)
+ exynos5_i2c_reset(i2c_bus);
+ } else {
+ ret = i2c_transfer(i2c_bus->regs, I2C_WRITE,
+ chip << 1, 0, 0, buffer, len);
+ }
+
+ return ret != I2C_OK;
+}
+
+static int i2c_read_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
+ uchar *buffer, int len)
+{
+ int ret;
+
+ if (i2c_bus->is_highspeed) {
+ ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buffer, len);
+ if (ret)
+ exynos5_i2c_reset(i2c_bus);
+ } else {
+ ret = i2c_transfer(i2c_bus->regs, I2C_READ,
+ chip << 1, 0, 0, buffer, len);
+ }
+
+ return ret != I2C_OK;
+}
+
+static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ int ret;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+
+ if (msg->flags & I2C_M_RD) {
+ ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
+ msg->len);
+ } else {
+ ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
+ msg->len, next_is_read);
+ }
+ if (ret)
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
+{
+ const void *blob = gd->fdt_blob;
+ struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+ int node, flags;
+
+ i2c_bus->is_highspeed = dev->of_id->data;
+ node = dev->of_offset;
+
+ if (i2c_bus->is_highspeed) {
+ flags = PINMUX_FLAG_HS_MODE;
+ i2c_bus->hsregs = (struct exynos5_hsi2c *)
+ fdtdec_get_addr(blob, node, "reg");
+ } else {
+ flags = 0;
+ i2c_bus->regs = (struct s3c24x0_i2c *)
+ fdtdec_get_addr(blob, node, "reg");
+ }
+
+ i2c_bus->id = pinmux_decode_periph_id(blob, node);
+
+ i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
+ "clock-frequency",
+ CONFIG_SYS_I2C_S3C24X0_SPEED);
+ i2c_bus->node = node;
+ i2c_bus->bus_num = dev->seq;
+
+ exynos_pinmux_config(i2c_bus->id, flags);
+
+ i2c_bus->active = true;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops s3c_i2c_ops = {
+ .xfer = s3c24x0_i2c_xfer,
+ .probe_chip = s3c24x0_i2c_probe,
+ .set_bus_speed = s3c24x0_i2c_set_bus_speed,
+};
+
+static const struct udevice_id s3c_i2c_ids[] = {
+ { .compatible = "samsung,s3c2440-i2c", .data = EXYNOS_I2C_STD },
+ { .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_s3c) = {
+ .name = "i2c_s3c",
+ .id = UCLASS_I2C,
+ .of_match = s3c_i2c_ids,
+ .ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
+ .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+ .priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
+ .ops = &s3c_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
index f0e9f51..a943aa6 100644
--- a/drivers/i2c/sandbox_i2c.c
+++ b/drivers/i2c/sandbox_i2c.c
@@ -25,24 +25,24 @@ struct dm_sandbox_i2c_emul_priv {
static int get_emul(struct udevice *dev, struct udevice **devp,
struct dm_i2c_ops **opsp)
{
- struct dm_i2c_chip *priv;
+ struct dm_i2c_chip *plat;
int ret;
*devp = NULL;
*opsp = NULL;
- priv = dev_get_parentdata(dev);
- if (!priv->emul) {
+ plat = dev_get_parent_platdata(dev);
+ if (!plat->emul) {
ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset,
false);
if (ret)
return ret;
- ret = device_get_child(dev, 0, &priv->emul);
+ ret = device_get_child(dev, 0, &plat->emul);
if (ret)
return ret;
}
- *devp = priv->emul;
- *opsp = i2c_get_ops(priv->emul);
+ *devp = plat->emul;
+ *opsp = i2c_get_ops(plat->emul);
return 0;
}
@@ -60,7 +60,7 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
if (msg->addr == SANDBOX_I2C_TEST_ADDR)
return 0;
- ret = i2c_get_chip(bus, msg->addr, &dev);
+ ret = i2c_get_chip(bus, msg->addr, 1, &dev);
if (ret)
return ret;
@@ -82,20 +82,6 @@ static const struct dm_i2c_ops sandbox_i2c_ops = {
.xfer = sandbox_i2c_xfer,
};
-static int sandbox_i2c_child_pre_probe(struct udevice *dev)
-{
- struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
-
- /* Ignore our test address */
- if (i2c_chip->chip_addr == SANDBOX_I2C_TEST_ADDR)
- return 0;
- if (dev->of_offset == -1)
- return 0;
-
- return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
- i2c_chip);
-}
-
static const struct udevice_id sandbox_i2c_ids[] = {
{ .compatible = "sandbox,i2c" },
{ }
@@ -105,7 +91,5 @@ U_BOOT_DRIVER(i2c_sandbox) = {
.name = "i2c_sandbox",
.id = UCLASS_I2C,
.of_match = sandbox_i2c_ids,
- .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
- .child_pre_probe = sandbox_i2c_child_pre_probe,
.ops = &sandbox_i2c_ops,
};
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index 87290c3..f414287 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -484,21 +484,6 @@ static const struct dm_i2c_ops tegra_i2c_ops = {
.set_bus_speed = tegra_i2c_set_bus_speed,
};
-static int tegra_i2c_child_pre_probe(struct udevice *dev)
-{
- struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
-
- if (dev->of_offset == -1)
- return 0;
- return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
- i2c_chip);
-}
-
-static int tegra_i2c_ofdata_to_platdata(struct udevice *dev)
-{
- return 0;
-}
-
static const struct udevice_id tegra_i2c_ids[] = {
{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
{ .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
@@ -510,10 +495,7 @@ U_BOOT_DRIVER(i2c_tegra) = {
.name = "i2c_tegra",
.id = UCLASS_I2C,
.of_match = tegra_i2c_ids,
- .ofdata_to_platdata = tegra_i2c_ofdata_to_platdata,
.probe = tegra_i2c_probe,
- .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
- .child_pre_probe = tegra_i2c_child_pre_probe,
.priv_auto_alloc_size = sizeof(struct i2c_bus),
.ops = &tegra_i2c_ops,
};
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 9b4effb..5846e76 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -154,7 +154,9 @@ static int prepare_proto3_response_buffer(struct cros_ec_dev *dev, int din_len)
* @param dev CROS-EC device
* @param dinp Returns pointer to response data
* @param din_len Maximum size of response in bytes
- * @return number of bytes of response data, or <0 if error
+ * @return number of bytes of response data, or <0 if error. Note that error
+ * codes can be from errno.h or -ve EC_RES_INVALID_CHECKSUM values (and they
+ * overlap!)
*/
static int handle_proto3_response(struct cros_ec_dev *dev,
uint8_t **dinp, int din_len)
@@ -228,7 +230,7 @@ static int send_command_proto3(struct cros_ec_dev *dev,
#ifdef CONFIG_DM_CROS_EC
ops = dm_cros_ec_get_ops(dev->dev);
- rv = ops->packet(dev->dev, out_bytes, in_bytes);
+ rv = ops->packet ? ops->packet(dev->dev, out_bytes, in_bytes) : -ENOSYS;
#else
switch (dev->interface) {
#ifdef CONFIG_CROS_EC_SPI
@@ -320,7 +322,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
* If not NULL, it will be updated to point to the data
* and will always be double word aligned (64-bits)
* @param din_len Maximum size of response in bytes
- * @return number of bytes in response, or -1 on error
+ * @return number of bytes in response, or -ve on error
*/
static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
@@ -387,7 +389,7 @@ static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
* It not NULL, it is a place for ec_command() to copy the
* data to.
* @param din_len Maximum size of response in bytes
- * @return number of bytes in response, or -1 on error
+ * @return number of bytes in response, or -ve on error
*/
static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
const void *dout, int dout_len,
@@ -606,10 +608,10 @@ int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
int cros_ec_interrupt_pending(struct cros_ec_dev *dev)
{
/* no interrupt support : always poll */
- if (!fdt_gpio_isvalid(&dev->ec_int))
+ if (!dm_gpio_is_valid(&dev->ec_int))
return -ENOENT;
- return !gpio_get_value(dev->ec_int.gpio);
+ return dm_gpio_get_value(&dev->ec_int);
}
int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_mkbp_info *info)
@@ -1072,7 +1074,8 @@ static int cros_ec_decode_fdt(const void *blob, int node,
return -1;
}
- fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int);
+ gpio_request_by_name_nodev(blob, node, "ec-interrupt", 0, &dev->ec_int,
+ GPIOD_IS_IN);
dev->optimise_flash_write = fdtdec_get_bool(blob, node,
"optimise-flash-write");
*devp = dev;
@@ -1090,17 +1093,11 @@ int cros_ec_register(struct udevice *dev)
char id[MSG_BYTES];
cdev->dev = dev;
- fdtdec_decode_gpio(blob, node, "ec-interrupt", &cdev->ec_int);
+ gpio_request_by_name(dev, "ec-interrupt", 0, &cdev->ec_int,
+ GPIOD_IS_IN);
cdev->optimise_flash_write = fdtdec_get_bool(blob, node,
"optimise-flash-write");
- /* we will poll the EC interrupt line */
- fdtdec_setup_gpio(&cdev->ec_int);
- if (fdt_gpio_isvalid(&cdev->ec_int)) {
- gpio_request(cdev->ec_int.gpio, "cros-ec-irq");
- gpio_direction_input(cdev->ec_int.gpio);
- }
-
if (cros_ec_check_version(cdev)) {
debug("%s: Could not detect CROS-EC version\n", __func__);
return -CROS_EC_ERR_CHECK_VERSION;
@@ -1184,13 +1181,6 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
}
#endif
- /* we will poll the EC interrupt line */
- fdtdec_setup_gpio(&dev->ec_int);
- if (fdt_gpio_isvalid(&dev->ec_int)) {
- gpio_request(dev->ec_int.gpio, "cros-ec-irq");
- gpio_direction_input(dev->ec_int.gpio);
- }
-
if (cros_ec_check_version(dev)) {
debug("%s: Could not detect CROS-EC version\n", __func__);
return -CROS_EC_ERR_CHECK_VERSION;
diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c
index 513cdb1..f9bc975 100644
--- a/drivers/misc/cros_ec_i2c.c
+++ b/drivers/misc/cros_ec_i2c.c
@@ -14,6 +14,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <i2c.h>
#include <cros_ec.h>
@@ -23,11 +24,11 @@
#define debug_trace(fmt, b...)
#endif
-int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
- const uint8_t *dout, int dout_len,
- uint8_t **dinp, int din_len)
+static int cros_ec_i2c_command(struct udevice *udev, uint8_t cmd,
+ int cmd_version, const uint8_t *dout,
+ int dout_len, uint8_t **dinp, int din_len)
{
- int old_bus = 0;
+ struct cros_ec_dev *dev = udev->uclass_priv;
/* version8, cmd8, arglen8, out8[dout_len], csum8 */
int out_bytes = dout_len + 4;
/* response8, arglen8, in8[din_len], checksum8 */
@@ -37,8 +38,6 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
uint8_t *in_ptr;
int len, csum, ret;
- old_bus = i2c_get_bus_num();
-
/*
* Sanity-check I/O sizes given transaction overhead in internal
* buffers.
@@ -86,36 +85,24 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
*ptr++ = (uint8_t)
cros_ec_calc_checksum(dev->dout, dout_len + 3);
- /* Set to the proper i2c bus */
- if (i2c_set_bus_num(dev->bus_num)) {
- debug("%s: Cannot change to I2C bus %d\n", __func__,
- dev->bus_num);
- return -1;
- }
-
/* Send output data */
cros_ec_dump_data("out", -1, dev->dout, out_bytes);
- ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes);
+ ret = dm_i2c_write(udev, 0, dev->dout, out_bytes);
if (ret) {
- debug("%s: Cannot complete I2C write to 0x%x\n",
- __func__, dev->addr);
+ debug("%s: Cannot complete I2C write to %s\n", __func__,
+ udev->name);
ret = -1;
}
if (!ret) {
- ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes);
+ ret = dm_i2c_read(udev, 0, in_ptr, in_bytes);
if (ret) {
- debug("%s: Cannot complete I2C read from 0x%x\n",
- __func__, dev->addr);
+ debug("%s: Cannot complete I2C read from %s\n",
+ __func__, udev->name);
ret = -1;
}
}
- /* Return to original bus number */
- i2c_set_bus_num(old_bus);
- if (ret)
- return ret;
-
if (*in_ptr != EC_RES_SUCCESS) {
debug("%s: Received bad result code %d\n", __func__, *in_ptr);
return -(int)*in_ptr;
@@ -142,35 +129,24 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
return din_len;
}
-int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+static int cros_ec_probe(struct udevice *dev)
{
- /* Decode interface-specific FDT params */
- dev->max_frequency = fdtdec_get_int(blob, dev->node,
- "i2c-max-frequency", 100000);
- dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node);
- if (dev->bus_num == -1) {
- debug("%s: Failed to read bus number\n", __func__);
- return -1;
- }
- dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1);
- if (dev->addr == -1) {
- debug("%s: Failed to read device address\n", __func__);
- return -1;
- }
-
- return 0;
+ return cros_ec_register(dev);
}
-/**
- * Initialize I2C protocol.
- *
- * @param dev CROS_EC device
- * @param blob Device tree blob
- * @return 0 if ok, -1 on error
- */
-int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob)
-{
- i2c_init(dev->max_frequency, dev->addr);
-
- return 0;
-}
+static struct dm_cros_ec_ops cros_ec_ops = {
+ .command = cros_ec_i2c_command,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+ { .compatible = "google,cros-ec" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_i2c) = {
+ .name = "cros_ec",
+ .id = UCLASS_CROS_EC,
+ .of_match = cros_ec_ids,
+ .probe = cros_ec_probe,
+ .ops = &cros_ec_ops,
+};
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index e6dba29..9359c56 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -21,14 +21,9 @@
DECLARE_GLOBAL_DATA_PTR;
-#ifdef CONFIG_DM_CROS_EC
int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
{
struct cros_ec_dev *dev = udev->uclass_priv;
-#else
-int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
-{
-#endif
struct spi_slave *slave = dev_get_parentdata(dev->dev);
int rv;
@@ -67,18 +62,11 @@ int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
* @param din_len Maximum size of response in bytes
* @return number of bytes in response, or -1 on error
*/
-#ifdef CONFIG_DM_CROS_EC
int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
{
struct cros_ec_dev *dev = udev->uclass_priv;
-#else
-int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
- const uint8_t *dout, int dout_len,
- uint8_t **dinp, int din_len)
-{
-#endif
struct spi_slave *slave = dev_get_parentdata(dev->dev);
int in_bytes = din_len + 4; /* status, length, checksum, trailer */
uint8_t *out;
@@ -166,65 +154,12 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
return len;
}
-#ifndef CONFIG_DM_CROS_EC
-int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+static int cros_ec_probe(struct udevice *dev)
{
- /* Decode interface-specific FDT params */
- dev->max_frequency = fdtdec_get_int(blob, dev->node,
- "spi-max-frequency", 500000);
- dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0);
-
- return 0;
-}
-
-/**
- * Initialize SPI protocol.
- *
- * @param dev CROS_EC device
- * @param blob Device tree blob
- * @return 0 if ok, -1 on error
- */
-int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
-{
- int ret;
-
- ret = spi_setup_slave_fdt(blob, dev->node, dev->parent_node,
- &slave);
- if (ret) {
- debug("%s: Could not setup SPI slave\n", __func__);
- return ret;
- }
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_DM_CROS_EC
-int cros_ec_probe(struct udevice *dev)
-{
- struct spi_slave *slave = dev_get_parentdata(dev);
- int ret;
-
- /*
- * TODO(sjg@chromium.org)
- *
- * This is really horrible at present. It is an artifact of removing
- * the child_pre_probe() method for SPI. Everything here could go in
- * an automatic function, except that spi_get_bus_and_cs() wants to
- * set it up manually and call device_probe_child().
- *
- * The solution may be to re-enable the child_pre_probe() method for
- * SPI and have it do nothing if the child is already passed in via
- * device_probe_child().
- */
- slave->dev = dev;
- ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
- if (ret)
- return ret;
return cros_ec_register(dev);
}
-struct dm_cros_ec_ops cros_ec_ops = {
+static struct dm_cros_ec_ops cros_ec_ops = {
.packet = cros_ec_spi_packet,
.command = cros_ec_spi_command,
};
@@ -241,4 +176,3 @@ U_BOOT_DRIVER(cros_ec_spi) = {
.probe = cros_ec_probe,
.ops = &cros_ec_ops,
};
-#endif
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index e69de29..7ba85a2 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -0,0 +1,9 @@
+menu "MMC Host controller Support"
+
+config SH_SDHI
+ bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support"
+ depends on RMOBILE
+ help
+ Support for the on-chip SDHI host controller on SuperH/Renesas ARM SoCs platform
+
+endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 461d7d8..ed73687 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -24,12 +24,14 @@ obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o
obj-$(CONFIG_MXC_MMC) += mxcmmc.o
obj-$(CONFIG_MXS_MMC) += mxsmmc.o
obj-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
+obj-$(CONFIG_X86) += pci_mmc.o
obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
obj-$(CONFIG_SDHCI) += sdhci.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
+obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 1eb9c27..b8039cd 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -486,7 +486,7 @@ static int mmc_change_freq(struct mmc *mmc)
char cardtype;
int err;
- mmc->card_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
+ mmc->card_caps = 0;
if (mmc_host_is_spi(mmc))
return 0;
@@ -495,6 +495,8 @@ static int mmc_change_freq(struct mmc *mmc)
if (mmc->version < MMC_VERSION_4)
return 0;
+ mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+
err = mmc_send_ext_csd(mmc, ext_csd);
if (err)
@@ -605,6 +607,200 @@ int mmc_switch_part(int dev_num, unsigned int part_num)
return ret;
}
+int mmc_hwpart_config(struct mmc *mmc,
+ const struct mmc_hwpart_conf *conf,
+ enum mmc_hwpart_conf_mode mode)
+{
+ u8 part_attrs = 0;
+ u32 enh_size_mult;
+ u32 enh_start_addr;
+ u32 gp_size_mult[4];
+ u32 max_enh_size_mult;
+ u32 tot_enh_size_mult = 0;
+ u8 wr_rel_set;
+ int i, pidx, err;
+ ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+
+ if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
+ return -EINVAL;
+
+ if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
+ printf("eMMC >= 4.4 required for enhanced user data area\n");
+ return -EMEDIUMTYPE;
+ }
+
+ if (!(mmc->part_support & PART_SUPPORT)) {
+ printf("Card does not support partitioning\n");
+ return -EMEDIUMTYPE;
+ }
+
+ if (!mmc->hc_wp_grp_size) {
+ printf("Card does not define HC WP group size\n");
+ return -EMEDIUMTYPE;
+ }
+
+ /* check partition alignment and total enhanced size */
+ if (conf->user.enh_size) {
+ if (conf->user.enh_size % mmc->hc_wp_grp_size ||
+ conf->user.enh_start % mmc->hc_wp_grp_size) {
+ printf("User data enhanced area not HC WP group "
+ "size aligned\n");
+ return -EINVAL;
+ }
+ part_attrs |= EXT_CSD_ENH_USR;
+ enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
+ if (mmc->high_capacity) {
+ enh_start_addr = conf->user.enh_start;
+ } else {
+ enh_start_addr = (conf->user.enh_start << 9);
+ }
+ } else {
+ enh_size_mult = 0;
+ enh_start_addr = 0;
+ }
+ tot_enh_size_mult += enh_size_mult;
+
+ for (pidx = 0; pidx < 4; pidx++) {
+ if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
+ printf("GP%i partition not HC WP group size "
+ "aligned\n", pidx+1);
+ return -EINVAL;
+ }
+ gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
+ if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
+ part_attrs |= EXT_CSD_ENH_GP(pidx);
+ tot_enh_size_mult += gp_size_mult[pidx];
+ }
+ }
+
+ if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
+ printf("Card does not support enhanced attribute\n");
+ return -EMEDIUMTYPE;
+ }
+
+ err = mmc_send_ext_csd(mmc, ext_csd);
+ if (err)
+ return err;
+
+ max_enh_size_mult =
+ (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
+ (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
+ ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
+ if (tot_enh_size_mult > max_enh_size_mult) {
+ printf("Total enhanced size exceeds maximum (%u > %u)\n",
+ tot_enh_size_mult, max_enh_size_mult);
+ return -EMEDIUMTYPE;
+ }
+
+ /* The default value of EXT_CSD_WR_REL_SET is device
+ * dependent, the values can only be changed if the
+ * EXT_CSD_HS_CTRL_REL bit is set. The values can be
+ * changed only once and before partitioning is completed. */
+ wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
+ if (conf->user.wr_rel_change) {
+ if (conf->user.wr_rel_set)
+ wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
+ else
+ wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
+ }
+ for (pidx = 0; pidx < 4; pidx++) {
+ if (conf->gp_part[pidx].wr_rel_change) {
+ if (conf->gp_part[pidx].wr_rel_set)
+ wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
+ else
+ wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
+ }
+ }
+
+ if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
+ !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
+ puts("Card does not support host controlled partition write "
+ "reliability settings\n");
+ return -EMEDIUMTYPE;
+ }
+
+ if (ext_csd[EXT_CSD_PARTITION_SETTING] &
+ EXT_CSD_PARTITION_SETTING_COMPLETED) {
+ printf("Card already partitioned\n");
+ return -EPERM;
+ }
+
+ if (mode == MMC_HWPART_CONF_CHECK)
+ return 0;
+
+ /* Partitioning requires high-capacity size definitions */
+ if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ERASE_GROUP_DEF, 1);
+
+ if (err)
+ return err;
+
+ ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+
+ /* update erase group size to be high-capacity */
+ mmc->erase_grp_size =
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
+
+ }
+
+ /* all OK, write the configuration */
+ for (i = 0; i < 4; i++) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ENH_START_ADDR+i,
+ (enh_start_addr >> (i*8)) & 0xFF);
+ if (err)
+ return err;
+ }
+ for (i = 0; i < 3; i++) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ENH_SIZE_MULT+i,
+ (enh_size_mult >> (i*8)) & 0xFF);
+ if (err)
+ return err;
+ }
+ for (pidx = 0; pidx < 4; pidx++) {
+ for (i = 0; i < 3; i++) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_GP_SIZE_MULT+pidx*3+i,
+ (gp_size_mult[pidx] >> (i*8)) & 0xFF);
+ if (err)
+ return err;
+ }
+ }
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
+ if (err)
+ return err;
+
+ if (mode == MMC_HWPART_CONF_SET)
+ return 0;
+
+ /* The WR_REL_SET is a write-once register but shall be
+ * written before setting PART_SETTING_COMPLETED. As it is
+ * write-once we can only write it when completing the
+ * partitioning. */
+ if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_WR_REL_SET, wr_rel_set);
+ if (err)
+ return err;
+ }
+
+ /* Setting PART_SETTING_COMPLETED confirms the partition
+ * configuration but it only becomes effective after power
+ * cycle, so we do not adjust the partition related settings
+ * in the mmc struct. */
+
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PARTITION_SETTING,
+ EXT_CSD_PARTITION_SETTING_COMPLETED);
+ if (err)
+ return err;
+
+ return 0;
+}
+
int mmc_getcd(struct mmc *mmc)
{
int cd;
@@ -818,6 +1014,8 @@ static int mmc_startup(struct mmc *mmc)
ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
int timeout = 1000;
+ bool has_parts = false;
+ bool part_completed;
#ifdef CONFIG_MMC_SPI_CRC_ON
if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
@@ -970,7 +1168,9 @@ static int mmc_startup(struct mmc *mmc)
if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
/* check ext_csd version and capacity */
err = mmc_send_ext_csd(mmc, ext_csd);
- if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {
+ if (err)
+ return err;
+ if (ext_csd[EXT_CSD_REV] >= 2) {
/*
* According to the JEDEC Standard, the value of
* ext_csd's capacity is valid if the value is more
@@ -1006,13 +1206,70 @@ static int mmc_startup(struct mmc *mmc)
break;
}
+ /* The partition data may be non-zero but it is only
+ * effective if PARTITION_SETTING_COMPLETED is set in
+ * EXT_CSD, so ignore any data if this bit is not set,
+ * except for enabling the high-capacity group size
+ * definition (see below). */
+ part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
+ EXT_CSD_PARTITION_SETTING_COMPLETED);
+
+ /* store the partition info of emmc */
+ mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
+ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
+ ext_csd[EXT_CSD_BOOT_MULT])
+ mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+ if (part_completed &&
+ (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
+ mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
+
+ mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+
+ mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+
+ for (i = 0; i < 4; i++) {
+ int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
+ uint mult = (ext_csd[idx + 2] << 16) +
+ (ext_csd[idx + 1] << 8) + ext_csd[idx];
+ if (mult)
+ has_parts = true;
+ if (!part_completed)
+ continue;
+ mmc->capacity_gp[i] = mult;
+ mmc->capacity_gp[i] *=
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ mmc->capacity_gp[i] <<= 19;
+ }
+
+ if (part_completed) {
+ mmc->enh_user_size =
+ (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
+ (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
+ ext_csd[EXT_CSD_ENH_SIZE_MULT];
+ mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ mmc->enh_user_size <<= 19;
+ mmc->enh_user_start =
+ (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
+ (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
+ (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
+ ext_csd[EXT_CSD_ENH_START_ADDR];
+ if (mmc->high_capacity)
+ mmc->enh_user_start <<= 9;
+ }
+
/*
* Host needs to enable ERASE_GRP_DEF bit if device is
* partitioned. This bit will be lost every time after a reset
* or power off. This will affect erase size.
*/
+ if (part_completed)
+ has_parts = true;
if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
- (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) {
+ (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
+ has_parts = true;
+ if (has_parts) {
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_ERASE_GROUP_DEF, 1);
@@ -1020,19 +1277,18 @@ static int mmc_startup(struct mmc *mmc)
return err;
else
ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+ }
+ if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
/* Read out group size from ext_csd */
mmc->erase_grp_size =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
- MMC_MAX_BLOCK_LEN * 1024;
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
/*
* if high capacity and partition setting completed
* SEC_COUNT is valid even if it is smaller than 2 GiB
* JEDEC Standard JESD84-B45, 6.2.4
*/
- if (mmc->high_capacity &&
- (ext_csd[EXT_CSD_PARTITION_SETTING] &
- EXT_CSD_PARTITION_SETTING_COMPLETED)) {
+ if (mmc->high_capacity && part_completed) {
capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
@@ -1049,23 +1305,11 @@ static int mmc_startup(struct mmc *mmc)
* (erase_gmul + 1);
}
- /* store the partition info of emmc */
- if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
- ext_csd[EXT_CSD_BOOT_MULT])
- mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
-
- mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
-
- mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+ mmc->hc_wp_grp_size = 1024
+ * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+ * ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
- for (i = 0; i < 4; i++) {
- int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
- mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
- (ext_csd[idx + 1] << 8) + ext_csd[idx];
- mmc->capacity_gp[i] *=
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
- }
+ mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
}
err = mmc_set_capacity(mmc, mmc->part_num);
@@ -1107,7 +1351,8 @@ static int mmc_startup(struct mmc *mmc)
mmc->tran_speed = 50000000;
else
mmc->tran_speed = 25000000;
- } else {
+ } else if (mmc->version >= MMC_VERSION_4) {
+ /* Only version 4 of MMC supports wider bus widths */
int idx;
/* An array of possible bus widths in order of preference */
@@ -1139,6 +1384,18 @@ static int mmc_startup(struct mmc *mmc)
unsigned int caps = ext_to_hostcaps[extw];
/*
+ * If the bus width is still not changed,
+ * don't try to set the default again.
+ * Otherwise, recover from switch attempts
+ * by switching to 1-bit bus width.
+ */
+ if (extw == EXT_CSD_BUS_WIDTH_1 &&
+ mmc->bus_width == 1) {
+ err = 0;
+ break;
+ }
+
+ /*
* Check to make sure the card and controller support
* these capabilities
*/
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index c880ced..dc725cb 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -134,6 +134,10 @@ static unsigned char mmc_board_init(struct mmc *mmc)
pbias_lite = readl(&t2_base->pbias_lite);
pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
+#ifdef CONFIG_TARGET_OMAP3_CAIRO
+ /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */
+ pbias_lite &= ~PBIASLITEVMODE0;
+#endif
writel(pbias_lite, &t2_base->pbias_lite);
writel(pbias_lite | PBIASLITEPWRDNZ1 |
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
new file mode 100644
index 0000000..37171bf
--- /dev/null
+++ b/drivers/mmc/pci_mmc.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015, Google, Inc
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/pci.h>
+
+int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported,
+ int num_ids)
+{
+ struct sdhci_host *mmc_host;
+ pci_dev_t devbusfn;
+ u32 iobase;
+ int ret;
+ int i;
+
+ for (i = 0; i < num_ids; i++) {
+ devbusfn = pci_find_devices(mmc_supported, i);
+ if (devbusfn == -1)
+ return -ENODEV;
+
+ mmc_host = malloc(sizeof(struct sdhci_host));
+ if (!mmc_host)
+ return -ENOMEM;
+
+ mmc_host->name = (char *)name;
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &iobase);
+ mmc_host->ioaddr = (void *)iobase;
+ mmc_host->quirks = 0;
+ ret = add_sdhci(mmc_host, 0, 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index a5d3487..3899372 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -102,17 +102,14 @@ struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS];
static int do_sdhci_init(struct sdhci_host *host)
{
- char str[20];
int dev_id, flag;
int err = 0;
flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
dev_id = host->index + PERIPH_ID_SDMMC0;
- if (fdt_gpio_isvalid(&host->pwr_gpio)) {
- sprintf(str, "sdhci%d_power", host->index & 0xf);
- gpio_request(host->pwr_gpio.gpio, str);
- gpio_direction_output(host->pwr_gpio.gpio, 1);
+ if (dm_gpio_is_valid(&host->pwr_gpio)) {
+ dm_gpio_set_value(&host->pwr_gpio, 1);
err = exynos_pinmux_config(dev_id, flag);
if (err) {
debug("MMC not configured\n");
@@ -120,11 +117,8 @@ static int do_sdhci_init(struct sdhci_host *host)
}
}
- if (fdt_gpio_isvalid(&host->cd_gpio)) {
- sprintf(str, "sdhci%d_cd", host->index & 0xf);
- gpio_request(host->cd_gpio.gpio, str);
- gpio_direction_input(host->cd_gpio.gpio);
- if (gpio_get_value(host->cd_gpio.gpio))
+ if (dm_gpio_is_valid(&host->cd_gpio)) {
+ if (dm_gpio_get_value(&host->cd_gpio))
return -ENODEV;
err = exynos_pinmux_config(dev_id, flag);
@@ -166,8 +160,10 @@ static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host)
}
host->ioaddr = (void *)base;
- fdtdec_decode_gpio(blob, node, "pwr-gpios", &host->pwr_gpio);
- fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
+ gpio_request_by_name_nodev(blob, node, "pwr-gpios", 0, &host->pwr_gpio,
+ GPIOD_IS_OUT);
+ gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio,
+ GPIOD_IS_IN);
return 0;
}
diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c
new file mode 100644
index 0000000..cc62c89
--- /dev/null
+++ b/drivers/mmc/sh_sdhi.c
@@ -0,0 +1,695 @@
+/*
+ * drivers/mmc/sh_sdhi.c
+ *
+ * SD/MMC driver for Renesas rmobile ARM SoCs.
+ *
+ * Copyright (C) 2011,2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2008-2009 Renesas Solutions Corp.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/arch/rmobile.h>
+#include <asm/arch/sh_sdhi.h>
+
+#define DRIVER_NAME "sh-sdhi"
+
+struct sh_sdhi_host {
+ unsigned long addr;
+ int ch;
+ int bus_shift;
+ unsigned long quirks;
+ unsigned char wait_int;
+ unsigned char sd_error;
+ unsigned char detect_waiting;
+};
+static inline void sh_sdhi_writew(struct sh_sdhi_host *host, int reg, u16 val)
+{
+ writew(val, host->addr + (reg << host->bus_shift));
+}
+
+static inline u16 sh_sdhi_readw(struct sh_sdhi_host *host, int reg)
+{
+ return readw(host->addr + (reg << host->bus_shift));
+}
+
+static void *mmc_priv(struct mmc *mmc)
+{
+ return (void *)mmc->priv;
+}
+
+static void sh_sdhi_detect(struct sh_sdhi_host *host)
+{
+ sh_sdhi_writew(host, SDHI_OPTION,
+ OPT_BUS_WIDTH_1 | sh_sdhi_readw(host, SDHI_OPTION));
+
+ host->detect_waiting = 0;
+}
+
+static int sh_sdhi_intr(void *dev_id)
+{
+ struct sh_sdhi_host *host = dev_id;
+ int state1 = 0, state2 = 0;
+
+ state1 = sh_sdhi_readw(host, SDHI_INFO1);
+ state2 = sh_sdhi_readw(host, SDHI_INFO2);
+
+ debug("%s: state1 = %x, state2 = %x\n", __func__, state1, state2);
+
+ /* CARD Insert */
+ if (state1 & INFO1_CARD_IN) {
+ sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_IN);
+ if (!host->detect_waiting) {
+ host->detect_waiting = 1;
+ sh_sdhi_detect(host);
+ }
+ sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
+ INFO1M_ACCESS_END | INFO1M_CARD_IN |
+ INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
+ return -EAGAIN;
+ }
+ /* CARD Removal */
+ if (state1 & INFO1_CARD_RE) {
+ sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_RE);
+ if (!host->detect_waiting) {
+ host->detect_waiting = 1;
+ sh_sdhi_detect(host);
+ }
+ sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
+ INFO1M_ACCESS_END | INFO1M_CARD_RE |
+ INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
+ sh_sdhi_writew(host, SDHI_SDIO_INFO1_MASK, SDIO_INFO1M_ON);
+ sh_sdhi_writew(host, SDHI_SDIO_MODE, SDIO_MODE_OFF);
+ return -EAGAIN;
+ }
+
+ if (state2 & INFO2_ALL_ERR) {
+ sh_sdhi_writew(host, SDHI_INFO2,
+ (unsigned short)~(INFO2_ALL_ERR));
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ INFO2M_ALL_ERR |
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+ host->sd_error = 1;
+ host->wait_int = 1;
+ return 0;
+ }
+ /* Respons End */
+ if (state1 & INFO1_RESP_END) {
+ sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ INFO1M_RESP_END |
+ sh_sdhi_readw(host, SDHI_INFO1_MASK));
+ host->wait_int = 1;
+ return 0;
+ }
+ /* SD_BUF Read Enable */
+ if (state2 & INFO2_BRE_ENABLE) {
+ sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BRE_ENABLE);
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ |
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+ host->wait_int = 1;
+ return 0;
+ }
+ /* SD_BUF Write Enable */
+ if (state2 & INFO2_BWE_ENABLE) {
+ sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BWE_ENABLE);
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ INFO2_BWE_ENABLE | INFO2M_BUF_ILL_WRITE |
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+ host->wait_int = 1;
+ return 0;
+ }
+ /* Access End */
+ if (state1 & INFO1_ACCESS_END) {
+ sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_ACCESS_END);
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ INFO1_ACCESS_END |
+ sh_sdhi_readw(host, SDHI_INFO1_MASK));
+ host->wait_int = 1;
+ return 0;
+ }
+ return -EAGAIN;
+}
+
+static int sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host *host)
+{
+ int timeout = 10000000;
+
+ while (1) {
+ timeout--;
+ if (timeout < 0) {
+ debug(DRIVER_NAME": %s timeout\n", __func__);
+ return 0;
+ }
+
+ if (!sh_sdhi_intr(host))
+ break;
+
+ udelay(1); /* 1 usec */
+ }
+
+ return 1; /* Return value: NOT 0 = complete waiting */
+}
+
+static int sh_sdhi_clock_control(struct sh_sdhi_host *host, unsigned long clk)
+{
+ u32 clkdiv, i, timeout;
+
+ if (sh_sdhi_readw(host, SDHI_INFO2) & (1 << 14)) {
+ printf(DRIVER_NAME": Busy state ! Cannot change the clock\n");
+ return -EBUSY;
+ }
+
+ sh_sdhi_writew(host, SDHI_CLK_CTRL,
+ ~CLK_ENABLE & sh_sdhi_readw(host, SDHI_CLK_CTRL));
+
+ if (clk == 0)
+ return -EIO;
+
+ clkdiv = 0x80;
+ i = CONFIG_SH_SDHI_FREQ >> (0x8 + 1);
+ for (; clkdiv && clk >= (i << 1); (clkdiv >>= 1))
+ i <<= 1;
+
+ sh_sdhi_writew(host, SDHI_CLK_CTRL, clkdiv);
+
+ timeout = 100000;
+ /* Waiting for SD Bus busy to be cleared */
+ while (timeout--) {
+ if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
+ break;
+ }
+
+ if (timeout)
+ sh_sdhi_writew(host, SDHI_CLK_CTRL,
+ CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
+ else
+ return -EBUSY;
+
+ return 0;
+}
+
+static int sh_sdhi_sync_reset(struct sh_sdhi_host *host)
+{
+ u32 timeout;
+ sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_ON);
+ sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_OFF);
+ sh_sdhi_writew(host, SDHI_CLK_CTRL,
+ CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
+
+ timeout = 100000;
+ while (timeout--) {
+ if (!(sh_sdhi_readw(host, SDHI_INFO2) & INFO2_CBUSY))
+ break;
+ udelay(100);
+ }
+
+ if (!timeout)
+ return -EBUSY;
+
+ if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
+ sh_sdhi_writew(host, SDHI_HOST_MODE, 1);
+
+ return 0;
+}
+
+static int sh_sdhi_error_manage(struct sh_sdhi_host *host)
+{
+ unsigned short e_state1, e_state2;
+ int ret;
+
+ host->sd_error = 0;
+ host->wait_int = 0;
+
+ e_state1 = sh_sdhi_readw(host, SDHI_ERR_STS1);
+ e_state2 = sh_sdhi_readw(host, SDHI_ERR_STS2);
+ if (e_state2 & ERR_STS2_SYS_ERROR) {
+ if (e_state2 & ERR_STS2_RES_STOP_TIMEOUT)
+ ret = TIMEOUT;
+ else
+ ret = -EILSEQ;
+ debug("%s: ERR_STS2 = %04x\n",
+ DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS2));
+ sh_sdhi_sync_reset(host);
+
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
+ return ret;
+ }
+ if (e_state1 & ERR_STS1_CRC_ERROR || e_state1 & ERR_STS1_CMD_ERROR)
+ ret = -EILSEQ;
+ else
+ ret = TIMEOUT;
+
+ debug("%s: ERR_STS1 = %04x\n",
+ DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS1));
+ sh_sdhi_sync_reset(host);
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
+ return ret;
+}
+
+static int sh_sdhi_single_read(struct sh_sdhi_host *host, struct mmc_data *data)
+{
+ long time;
+ unsigned short blocksize, i;
+ unsigned short *p = (unsigned short *)data->dest;
+
+ if ((unsigned long)p & 0x00000001) {
+ debug(DRIVER_NAME": %s: The data pointer is unaligned.",
+ __func__);
+ return -EIO;
+ }
+
+ host->wait_int = 0;
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ ~INFO1M_ACCESS_END &
+ sh_sdhi_readw(host, SDHI_INFO1_MASK));
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (time == 0 || host->sd_error != 0)
+ return sh_sdhi_error_manage(host);
+
+ host->wait_int = 0;
+ blocksize = sh_sdhi_readw(host, SDHI_SIZE);
+ for (i = 0; i < blocksize / 2; i++)
+ *p++ = sh_sdhi_readw(host, SDHI_BUF0);
+
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (time == 0 || host->sd_error != 0)
+ return sh_sdhi_error_manage(host);
+
+ host->wait_int = 0;
+ return 0;
+}
+
+static int sh_sdhi_multi_read(struct sh_sdhi_host *host, struct mmc_data *data)
+{
+ long time;
+ unsigned short blocksize, i, sec;
+ unsigned short *p = (unsigned short *)data->dest;
+
+ if ((unsigned long)p & 0x00000001) {
+ debug(DRIVER_NAME": %s: The data pointer is unaligned.",
+ __func__);
+ return -EIO;
+ }
+
+ debug("%s: blocks = %d, blocksize = %d\n",
+ __func__, data->blocks, data->blocksize);
+
+ host->wait_int = 0;
+ for (sec = 0; sec < data->blocks; sec++) {
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (time == 0 || host->sd_error != 0)
+ return sh_sdhi_error_manage(host);
+
+ host->wait_int = 0;
+ blocksize = sh_sdhi_readw(host, SDHI_SIZE);
+ for (i = 0; i < blocksize / 2; i++)
+ *p++ = sh_sdhi_readw(host, SDHI_BUF0);
+ }
+
+ return 0;
+}
+
+static int sh_sdhi_single_write(struct sh_sdhi_host *host,
+ struct mmc_data *data)
+{
+ long time;
+ unsigned short blocksize, i;
+ const unsigned short *p = (const unsigned short *)data->src;
+
+ if ((unsigned long)p & 0x00000001) {
+ debug(DRIVER_NAME": %s: The data pointer is unaligned.",
+ __func__);
+ return -EIO;
+ }
+
+ debug("%s: blocks = %d, blocksize = %d\n",
+ __func__, data->blocks, data->blocksize);
+
+ host->wait_int = 0;
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ ~INFO1M_ACCESS_END &
+ sh_sdhi_readw(host, SDHI_INFO1_MASK));
+
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (time == 0 || host->sd_error != 0)
+ return sh_sdhi_error_manage(host);
+
+ host->wait_int = 0;
+ blocksize = sh_sdhi_readw(host, SDHI_SIZE);
+ for (i = 0; i < blocksize / 2; i++)
+ sh_sdhi_writew(host, SDHI_BUF0, *p++);
+
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (time == 0 || host->sd_error != 0)
+ return sh_sdhi_error_manage(host);
+
+ host->wait_int = 0;
+ return 0;
+}
+
+static int sh_sdhi_multi_write(struct sh_sdhi_host *host, struct mmc_data *data)
+{
+ long time;
+ unsigned short i, sec, blocksize;
+ const unsigned short *p = (const unsigned short *)data->src;
+
+ debug("%s: blocks = %d, blocksize = %d\n",
+ __func__, data->blocks, data->blocksize);
+
+ host->wait_int = 0;
+ for (sec = 0; sec < data->blocks; sec++) {
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (time == 0 || host->sd_error != 0)
+ return sh_sdhi_error_manage(host);
+
+ host->wait_int = 0;
+ blocksize = sh_sdhi_readw(host, SDHI_SIZE);
+ for (i = 0; i < blocksize / 2; i++)
+ sh_sdhi_writew(host, SDHI_BUF0, *p++);
+ }
+
+ return 0;
+}
+
+static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
+{
+ unsigned short i, j, cnt = 1;
+ unsigned short resp[8];
+ unsigned long *p1, *p2;
+
+ if (cmd->resp_type & MMC_RSP_136) {
+ cnt = 4;
+ resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
+ resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
+ resp[2] = sh_sdhi_readw(host, SDHI_RSP02);
+ resp[3] = sh_sdhi_readw(host, SDHI_RSP03);
+ resp[4] = sh_sdhi_readw(host, SDHI_RSP04);
+ resp[5] = sh_sdhi_readw(host, SDHI_RSP05);
+ resp[6] = sh_sdhi_readw(host, SDHI_RSP06);
+ resp[7] = sh_sdhi_readw(host, SDHI_RSP07);
+
+ /* SDHI REGISTER SPECIFICATION */
+ for (i = 7, j = 6; i > 0; i--) {
+ resp[i] = (resp[i] << 8) & 0xff00;
+ resp[i] |= (resp[j--] >> 8) & 0x00ff;
+ }
+ resp[0] = (resp[0] << 8) & 0xff00;
+
+ /* SDHI REGISTER SPECIFICATION */
+ p1 = ((unsigned long *)resp) + 3;
+
+ } else {
+ resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
+ resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
+
+ p1 = ((unsigned long *)resp);
+ }
+
+ p2 = (unsigned long *)cmd->response;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ for (i = 0; i < cnt; i++) {
+ *p2++ = ((*p1 >> 16) & 0x0000ffff) |
+ ((*p1 << 16) & 0xffff0000);
+ p1--;
+ }
+#else
+ for (i = 0; i < cnt; i++)
+ *p2++ = *p1--;
+#endif /* __BIG_ENDIAN_BITFIELD */
+}
+
+static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
+ struct mmc_data *data, unsigned short opc)
+{
+ switch (opc) {
+ case SD_CMD_APP_SEND_OP_COND:
+ case SD_CMD_APP_SEND_SCR:
+ opc |= SDHI_APP;
+ break;
+ case SD_CMD_APP_SET_BUS_WIDTH:
+ /* SD_APP_SET_BUS_WIDTH*/
+ if (!data)
+ opc |= SDHI_APP;
+ else /* SD_SWITCH */
+ opc = SDHI_SD_SWITCH;
+ break;
+ default:
+ break;
+ }
+ return opc;
+}
+
+static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
+ struct mmc_data *data, unsigned short opc)
+{
+ unsigned short ret;
+
+ switch (opc) {
+ case MMC_CMD_READ_MULTIPLE_BLOCK:
+ ret = sh_sdhi_multi_read(host, data);
+ break;
+ case MMC_CMD_WRITE_MULTIPLE_BLOCK:
+ ret = sh_sdhi_multi_write(host, data);
+ break;
+ case MMC_CMD_WRITE_SINGLE_BLOCK:
+ ret = sh_sdhi_single_write(host, data);
+ break;
+ case MMC_CMD_READ_SINGLE_BLOCK:
+ case SDHI_SD_APP_SEND_SCR:
+ case SDHI_SD_SWITCH: /* SD_SWITCH */
+ ret = sh_sdhi_single_read(host, data);
+ break;
+ default:
+ printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
+ struct mmc_data *data, struct mmc_cmd *cmd)
+{
+ long time;
+ unsigned short opc = cmd->cmdidx;
+ int ret = 0;
+ unsigned long timeout;
+
+ debug("opc = %d, arg = %x, resp_type = %x\n",
+ opc, cmd->cmdarg, cmd->resp_type);
+
+ if (opc == MMC_CMD_STOP_TRANSMISSION) {
+ /* SDHI sends the STOP command automatically by STOP reg */
+ sh_sdhi_writew(host, SDHI_INFO1_MASK, ~INFO1M_ACCESS_END &
+ sh_sdhi_readw(host, SDHI_INFO1_MASK));
+
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (time == 0 || host->sd_error != 0)
+ return sh_sdhi_error_manage(host);
+
+ sh_sdhi_get_response(host, cmd);
+ return 0;
+ }
+
+ if (data) {
+ if ((opc == MMC_CMD_READ_MULTIPLE_BLOCK) ||
+ opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
+ sh_sdhi_writew(host, SDHI_STOP, STOP_SEC_ENABLE);
+ sh_sdhi_writew(host, SDHI_SECCNT, data->blocks);
+ }
+ sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
+ }
+ opc = sh_sdhi_set_cmd(host, data, opc);
+
+ /*
+ * U-boot cannot use interrupt.
+ * So this flag may not be clear by timing
+ */
+ sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
+
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ INFO1M_RESP_END | sh_sdhi_readw(host, SDHI_INFO1_MASK));
+ sh_sdhi_writew(host, SDHI_ARG0,
+ (unsigned short)(cmd->cmdarg & ARG0_MASK));
+ sh_sdhi_writew(host, SDHI_ARG1,
+ (unsigned short)((cmd->cmdarg >> 16) & ARG1_MASK));
+
+ timeout = 100000;
+ /* Waiting for SD Bus busy to be cleared */
+ while (timeout--) {
+ if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
+ break;
+ }
+
+ sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(opc & CMD_MASK));
+
+ host->wait_int = 0;
+ sh_sdhi_writew(host, SDHI_INFO1_MASK,
+ ~INFO1M_RESP_END & sh_sdhi_readw(host, SDHI_INFO1_MASK));
+ sh_sdhi_writew(host, SDHI_INFO2_MASK,
+ ~(INFO2M_CMD_ERROR | INFO2M_CRC_ERROR |
+ INFO2M_END_ERROR | INFO2M_TIMEOUT |
+ INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
+ sh_sdhi_readw(host, SDHI_INFO2_MASK));
+
+ time = sh_sdhi_wait_interrupt_flag(host);
+ if (!time)
+ return sh_sdhi_error_manage(host);
+
+ if (host->sd_error) {
+ switch (cmd->cmdidx) {
+ case MMC_CMD_ALL_SEND_CID:
+ case MMC_CMD_SELECT_CARD:
+ case SD_CMD_SEND_IF_COND:
+ case MMC_CMD_APP_CMD:
+ ret = TIMEOUT;
+ break;
+ default:
+ debug(DRIVER_NAME": Cmd(d'%d) err\n", opc);
+ debug(DRIVER_NAME": cmdidx = %d\n", cmd->cmdidx);
+ ret = sh_sdhi_error_manage(host);
+ break;
+ }
+ host->sd_error = 0;
+ host->wait_int = 0;
+ return ret;
+ }
+ if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END)
+ return -EINVAL;
+
+ if (host->wait_int) {
+ sh_sdhi_get_response(host, cmd);
+ host->wait_int = 0;
+ }
+ if (data)
+ ret = sh_sdhi_data_trans(host, data, opc);
+
+ debug("ret = %d, resp = %08x, %08x, %08x, %08x\n",
+ ret, cmd->response[0], cmd->response[1],
+ cmd->response[2], cmd->response[3]);
+ return ret;
+}
+
+static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct sh_sdhi_host *host = mmc_priv(mmc);
+ int ret;
+
+ host->sd_error = 0;
+
+ ret = sh_sdhi_start_cmd(host, data, cmd);
+
+ return ret;
+}
+
+static void sh_sdhi_set_ios(struct mmc *mmc)
+{
+ int ret;
+ struct sh_sdhi_host *host = mmc_priv(mmc);
+
+ ret = sh_sdhi_clock_control(host, mmc->clock);
+ if (ret)
+ return;
+
+ if (mmc->bus_width == 4)
+ sh_sdhi_writew(host, SDHI_OPTION, ~OPT_BUS_WIDTH_1 &
+ sh_sdhi_readw(host, SDHI_OPTION));
+ else
+ sh_sdhi_writew(host, SDHI_OPTION, OPT_BUS_WIDTH_1 |
+ sh_sdhi_readw(host, SDHI_OPTION));
+
+ debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
+}
+
+static int sh_sdhi_initialize(struct mmc *mmc)
+{
+ struct sh_sdhi_host *host = mmc_priv(mmc);
+ int ret = sh_sdhi_sync_reset(host);
+
+ sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ sh_sdhi_writew(host, SDHI_EXT_SWAP, SET_SWAP);
+#endif
+
+ sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
+ INFO1M_ACCESS_END | INFO1M_CARD_RE |
+ INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
+
+ return ret;
+}
+
+static const struct mmc_ops sh_sdhi_ops = {
+ .send_cmd = sh_sdhi_send_cmd,
+ .set_ios = sh_sdhi_set_ios,
+ .init = sh_sdhi_initialize,
+};
+
+static struct mmc_config sh_sdhi_cfg = {
+ .name = DRIVER_NAME,
+ .ops = &sh_sdhi_ops,
+ .f_min = CLKDEV_INIT,
+ .f_max = CLKDEV_HS_DATA,
+ .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .host_caps = MMC_MODE_4BIT | MMC_MODE_HS,
+ .part_type = PART_TYPE_DOS,
+ .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
+};
+
+int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
+{
+ int ret = 0;
+ struct mmc *mmc;
+ struct sh_sdhi_host *host = NULL;
+
+ if (ch >= CONFIG_SYS_SH_SDHI_NR_CHANNEL)
+ return -ENODEV;
+
+ host = malloc(sizeof(struct sh_sdhi_host));
+ if (!host)
+ return -ENOMEM;
+
+ mmc = mmc_create(&sh_sdhi_cfg, host);
+ if (!mmc) {
+ ret = -1;
+ goto error;
+ }
+
+ host->ch = ch;
+ host->addr = addr;
+ host->quirks = quirks;
+
+ if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
+ host->bus_shift = 1;
+
+ return ret;
+error:
+ if (host)
+ free(host);
+ return ret;
+}
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 6234981..ebfec7c 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -89,8 +89,13 @@ static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz)
pll = CCM_MMC_CTRL_OSCM24;
pll_hz = 24000000;
} else {
+#ifdef CONFIG_MACH_SUN9I
+ pll = CCM_MMC_CTRL_PLL_PERIPH0;
+ pll_hz = clock_get_pll4_periph0();
+#else
pll = CCM_MMC_CTRL_PLL6;
pll_hz = clock_get_pll6();
+#endif
}
div = pll_hz / hz;
@@ -146,10 +151,16 @@ static int mmc_clk_io_on(int sdc_no)
/* config ahb clock */
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
-#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I)
+#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \
+ defined(CONFIG_MACH_SUN9I)
/* unassert reset */
setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
#endif
+#if defined(CONFIG_MACH_SUN9I)
+ /* sun9i has a mmc-common module, also set the gate and reset there */
+ writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
+ SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
+#endif
return mmc_set_mod_clk(mmchost, 24000000);
}
@@ -204,7 +215,7 @@ static int mmc_config_clock(struct mmc *mmc)
return 0;
}
-static void mmc_set_ios(struct mmc *mmc)
+static void sunxi_mmc_set_ios(struct mmc *mmc)
{
struct sunxi_mmc_host *mmchost = mmc->priv;
@@ -226,7 +237,7 @@ static void mmc_set_ios(struct mmc *mmc)
writel(0x0, &mmchost->reg->width);
}
-static int mmc_core_init(struct mmc *mmc)
+static int sunxi_mmc_core_init(struct mmc *mmc)
{
struct sunxi_mmc_host *mmchost = mmc->priv;
@@ -287,8 +298,8 @@ static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs,
return 0;
}
-static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
+static int sunxi_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
{
struct sunxi_mmc_host *mmchost = mmc->priv;
unsigned int cmdval = SUNXI_MMC_CMD_START;
@@ -355,7 +366,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
}
- error = mmc_rint_wait(mmc, 0xfffff, SUNXI_MMC_RINT_COMMAND_DONE, "cmd");
+ error = mmc_rint_wait(mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE, "cmd");
if (error)
goto out;
@@ -421,9 +432,9 @@ static int sunxi_mmc_getcd(struct mmc *mmc)
}
static const struct mmc_ops sunxi_mmc_ops = {
- .send_cmd = mmc_send_cmd,
- .set_ios = mmc_set_ios,
- .init = mmc_core_init,
+ .send_cmd = sunxi_mmc_send_cmd,
+ .set_ios = sunxi_mmc_set_ios,
+ .init = sunxi_mmc_core_init,
.getcd = sunxi_mmc_getcd,
};
@@ -439,7 +450,8 @@ struct mmc *sunxi_mmc_init(int sdc_no)
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
cfg->host_caps = MMC_MODE_4BIT;
cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
-#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || defined(CONFIG_MACH_SUN8I)
+#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
+ defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN9I)
cfg->host_caps |= MMC_MODE_HC;
#endif
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index 2bd36b0..2cd8cf1 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -515,8 +515,8 @@ static int tegra_mmc_getcd(struct mmc *mmc)
debug("tegra_mmc_getcd called\n");
- if (fdt_gpio_isvalid(&host->cd_gpio))
- return fdtdec_get_gpio(&host->cd_gpio);
+ if (dm_gpio_is_valid(&host->cd_gpio))
+ return dm_gpio_get_value(&host->cd_gpio);
return 1;
}
@@ -531,7 +531,6 @@ static const struct mmc_ops tegra_mmc_ops = {
static int do_mmc_init(int dev_index)
{
struct mmc_host *host;
- char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */
struct mmc *mmc;
/* DT should have been read & host config filled in */
@@ -539,27 +538,15 @@ static int do_mmc_init(int dev_index)
if (!host->enabled)
return -1;
- debug(" do_mmc_init: index %d, bus width %d "
- "pwr_gpio %d cd_gpio %d\n",
- dev_index, host->width,
- host->pwr_gpio.gpio, host->cd_gpio.gpio);
+ debug(" do_mmc_init: index %d, bus width %d pwr_gpio %d cd_gpio %d\n",
+ dev_index, host->width, gpio_get_number(&host->pwr_gpio),
+ gpio_get_number(&host->cd_gpio));
host->clock = 0;
clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
- if (fdt_gpio_isvalid(&host->pwr_gpio)) {
- sprintf(gpusage, "SD/MMC%d PWR", dev_index);
- gpio_request(host->pwr_gpio.gpio, gpusage);
- gpio_direction_output(host->pwr_gpio.gpio, 1);
- debug(" Power GPIO name = %s\n", host->pwr_gpio.name);
- }
-
- if (fdt_gpio_isvalid(&host->cd_gpio)) {
- sprintf(gpusage, "SD/MMC%d CD", dev_index);
- gpio_request(host->cd_gpio.gpio, gpusage);
- gpio_direction_input(host->cd_gpio.gpio);
- debug(" CD GPIO name = %s\n", host->cd_gpio.name);
- }
+ if (dm_gpio_is_valid(&host->pwr_gpio))
+ dm_gpio_set_value(&host->pwr_gpio, 1);
memset(&host->cfg, 0, sizeof(host->cfg));
@@ -626,9 +613,12 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
debug("%s: no sdmmc width found\n", __func__);
/* These GPIOs are optional */
- fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
- fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio);
- fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio);
+ gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio,
+ GPIOD_IS_IN);
+ gpio_request_by_name_nodev(blob, node, "wp-gpios", 0, &host->wp_gpio,
+ GPIOD_IS_IN);
+ gpio_request_by_name_nodev(blob, node, "power-gpios", 0,
+ &host->pwr_gpio, GPIOD_IS_OUT);
debug("%s: found controller at %p, width = %d, periph_id = %d\n",
__func__, host->reg, host->width, host->mmc_id);
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index fdce2c2..7887f11 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -13,7 +13,7 @@
#include <sdhci.h>
#include <asm/arch/sys_proto.h>
-int zynq_sdhci_init(u32 regbase)
+int zynq_sdhci_init(phys_addr_t regbase)
{
struct sdhci_host *host = NULL;
@@ -40,7 +40,7 @@ int zynq_sdhci_of_init(const void *blob)
{
int offset = 0;
u32 ret = 0;
- u32 reg;
+ phys_addr_t reg;
debug("ZYNQ SDHCI: Initialization\n");
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 620b6e8..b16e3aa 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -44,6 +44,7 @@ struct atmel_nand_host {
u8 pmecc_corr_cap;
u16 pmecc_sector_size;
u32 pmecc_index_table_offset;
+ u32 pmecc_version;
int pmecc_bytes_per_sector;
int pmecc_sector_number;
@@ -486,6 +487,10 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
int i, err_nbr, eccbytes;
uint8_t *buf_pos;
+ /* SAMA5D4 PMECC IP can correct errors for all 0xff page */
+ if (host->pmecc_version >= PMECC_VERSION_SAMA5D4)
+ goto normal_check;
+
eccbytes = nand_chip->ecc.bytes;
for (i = 0; i < eccbytes; i++)
if (ecc[i] != 0xff)
@@ -961,6 +966,10 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
nand->ecc.write_page = atmel_nand_pmecc_write_page;
nand->ecc.strength = cap;
+ /* Check the PMECC ip version */
+ host->pmecc_version = pmecc_readl(host->pmerrloc, version);
+ dev_dbg(host->dev, "PMECC IP version is: %x\n", host->pmecc_version);
+
atmel_pmecc_core_init(mtd);
return 0;
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
index eac860d..b2d2682 100644
--- a/drivers/mtd/nand/atmel_nand_ecc.h
+++ b/drivers/mtd/nand/atmel_nand_ecc.h
@@ -123,6 +123,20 @@ struct pmecc_errloc_regs {
u32 sigma[25]; /* 0x28-0x88 Error Location Sigma Registers */
u32 el[24]; /* 0x8C-0xE8 Error Location Registers */
u32 reserved1[5]; /* 0xEC-0xFC Reserved */
+
+ /*
+ * 0x100-0x1F8:
+ * Reserved for AT91SAM9X5, AT91SAM9N12.
+ * HSMC registers for SAMA5D3, SAMA5D4.
+ */
+ u32 reserved2[63];
+
+ /*
+ * 0x1FC:
+ * PMECC version for AT91SAM9X5, AT91SAM9N12.
+ * HSMC version for SAMA5D3, SAMA5D4. Can refer as PMECC version.
+ */
+ u32 version;
};
/* For Error Location Configuration Register */
@@ -137,6 +151,12 @@ struct pmecc_errloc_regs {
#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
#define PMERRLOC_CALC_DONE (1 << 0)
+/* PMECC IP version */
+#define PMECC_VERSION_SAMA5D4 0x113
+#define PMECC_VERSION_SAMA5D3 0x112
+#define PMECC_VERSION_AT91SAM9N12 0x102
+#define PMECC_VERSION_AT91SAM9X5 0x101
+
/* Galois field dimension */
#define PMECC_GF_DIMENSION_13 13
#define PMECC_GF_DIMENSION_14 14
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 63bdf65..6db6566 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1065,11 +1065,6 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
}
}
#endif
-#ifdef PPCHAMELON_NAND_TIMER_HACK
- time_start = get_timer(0);
- while (get_timer(time_start) < 10)
- ;
-#endif /* PPCHAMELON_NAND_TIMER_HACK */
led_trigger_event(nand_led_trigger, LED_OFF);
status = (int)chip->read_byte(mtd);
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
index 163cf29..b660f3b 100644
--- a/drivers/mtd/nand/tegra_nand.c
+++ b/drivers/mtd/nand/tegra_nand.c
@@ -79,7 +79,7 @@ enum {
struct fdt_nand {
struct nand_ctlr *reg;
int enabled; /* 1 to enable, 0 to disable */
- struct fdt_gpio_state wp_gpio; /* write-protect GPIO */
+ struct gpio_desc wp_gpio; /* write-protect GPIO */
s32 width; /* bit width, normally 8 */
u32 timing[FDT_NAND_TIMING_COUNT];
};
@@ -945,8 +945,8 @@ static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config)
config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg");
config->enabled = fdtdec_get_is_enabled(blob, node);
config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8);
- err = fdtdec_decode_gpio(blob, node, "nvidia,wp-gpios",
- &config->wp_gpio);
+ err = gpio_request_by_name_nodev(blob, node, "nvidia,wp-gpios", 0,
+ &config->wp_gpio, GPIOD_IS_OUT);
if (err)
return err;
err = fdtdec_get_int_array(blob, node, "nvidia,timing",
@@ -1009,8 +1009,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
/* Adjust timing for NAND device */
setup_timing(config->timing, info->reg);
- fdtdec_setup_gpio(&config->wp_gpio);
- gpio_direction_output(config->wp_gpio.gpio, 1);
+ dm_gpio_set_value(&config->wp_gpio, 1);
our_mtd = &nand_info[devnum];
our_mtd->priv = nand;
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index 3024b98..d576d31 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -141,8 +141,10 @@ static int sandbox_sf_probe(struct udevice *dev)
assert(bus->seq != -1);
if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS)
spec = state->spi[bus->seq][cs].spec;
- if (!spec)
- return -ENOENT;
+ if (!spec) {
+ ret = -ENOENT;
+ goto error;
+ }
file = strchr(spec, ':');
if (!file) {
@@ -196,6 +198,7 @@ static int sandbox_sf_probe(struct udevice *dev)
return 0;
error:
+ debug("%s: Got error %d\n", __func__, ret);
return ret;
}
@@ -587,6 +590,11 @@ int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,
void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs)
{
+ struct udevice *dev;
+
+ dev = state->spi[busnum][cs].emul;
+ device_remove(dev);
+ device_unbind(dev);
state->spi[busnum][cs].emul = NULL;
}
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index ce9987f..4103723 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -481,11 +481,12 @@ int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
int spi_flash_std_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parentdata(dev);
+ struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
struct spi_flash *flash;
flash = dev->uclass_priv;
flash->dev = dev;
- debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs);
+ debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs);
return spi_flash_probe_slave(slave, flash);
}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 584cf5f..290d524 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1358,6 +1358,10 @@ out_version:
out_class:
class_destroy(ubi_class);
out:
+#ifdef __UBOOT__
+ /* Reset any globals that the driver depends on being zeroed */
+ mtd_devs = 0;
+#endif
ubi_err("cannot initialize UBI, error %d", err);
return err;
}
@@ -1384,6 +1388,10 @@ void ubi_exit(void)
misc_deregister(&ubi_ctrl_cdev);
class_remove_file(ubi_class, &ubi_version);
class_destroy(ubi_class);
+#ifdef __UBOOT__
+ /* Reset any globals that the driver depends on being zeroed */
+ mtd_devs = 0;
+#endif
}
module_exit(ubi_exit);
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fb0cf8c..46c4ac6 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -66,3 +66,4 @@ obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \
xilinx_ll_temac_fifo.o xilinx_ll_temac_sdma.o
obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o
obj-$(CONFIG_FSL_MC_ENET) += fsl_mc/
+obj-$(CONFIG_VSC9953) += vsc9953.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 9ded895..c03e935 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -236,8 +236,10 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
start = get_timer(0);
while (readl(&dma_p->busmode) & DMAMAC_SRST) {
- if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT)
+ if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT) {
+ printf("DMA reset timeout\n");
return -1;
+ }
mdelay(100);
};
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 6531030..cd44222 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -4927,22 +4927,23 @@ void
fill_rx(struct e1000_hw *hw)
{
struct e1000_rx_desc *rd;
- uint32_t flush_start, flush_end;
+ unsigned long flush_start, flush_end;
rx_last = rx_tail;
rd = rx_base + rx_tail;
rx_tail = (rx_tail + 1) % 8;
memset(rd, 0, 16);
- rd->buffer_addr = cpu_to_le64((u32)packet);
+ rd->buffer_addr = cpu_to_le64((unsigned long)packet);
/*
* Make sure there are no stale data in WB over this area, which
* might get written into the memory while the e1000 also writes
* into the same memory area.
*/
- invalidate_dcache_range((u32)packet, (u32)packet + 4096);
+ invalidate_dcache_range((unsigned long)packet,
+ (unsigned long)packet + 4096);
/* Dump the DMA descriptor into RAM. */
- flush_start = ((u32)rd) & ~(ARCH_DMA_MINALIGN - 1);
+ flush_start = ((unsigned long)rd) & ~(ARCH_DMA_MINALIGN - 1);
flush_end = flush_start + roundup(sizeof(*rd), ARCH_DMA_MINALIGN);
flush_dcache_range(flush_start, flush_end);
@@ -4963,7 +4964,7 @@ e1000_configure_tx(struct e1000_hw *hw)
unsigned long tipg, tarc;
uint32_t ipgr1, ipgr2;
- E1000_WRITE_REG(hw, TDBAL, (u32) tx_base);
+ E1000_WRITE_REG(hw, TDBAL, (unsigned long)tx_base);
E1000_WRITE_REG(hw, TDBAH, 0);
E1000_WRITE_REG(hw, TDLEN, 128);
@@ -5107,7 +5108,7 @@ e1000_configure_rx(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
}
/* Setup the Base and Length of the Rx Descriptor Ring */
- E1000_WRITE_REG(hw, RDBAL, (u32) rx_base);
+ E1000_WRITE_REG(hw, RDBAL, (unsigned long)rx_base);
E1000_WRITE_REG(hw, RDBAH, 0);
E1000_WRITE_REG(hw, RDLEN, 128);
@@ -5138,14 +5139,14 @@ e1000_poll(struct eth_device *nic)
{
struct e1000_hw *hw = nic->priv;
struct e1000_rx_desc *rd;
- uint32_t inval_start, inval_end;
+ unsigned long inval_start, inval_end;
uint32_t len;
/* return true if there's an ethernet packet ready to read */
rd = rx_base + rx_last;
/* Re-load the descriptor from RAM. */
- inval_start = ((u32)rd) & ~(ARCH_DMA_MINALIGN - 1);
+ inval_start = ((unsigned long)rd) & ~(ARCH_DMA_MINALIGN - 1);
inval_end = inval_start + roundup(sizeof(*rd), ARCH_DMA_MINALIGN);
invalidate_dcache_range(inval_start, inval_end);
@@ -5154,8 +5155,9 @@ e1000_poll(struct eth_device *nic)
/*DEBUGOUT("recv: packet len=%d \n", rd->length); */
/* Packet received, make sure the data are re-loaded from RAM. */
len = le32_to_cpu(rd->length);
- invalidate_dcache_range((u32)packet,
- (u32)packet + roundup(len, ARCH_DMA_MINALIGN));
+ invalidate_dcache_range((unsigned long)packet,
+ (unsigned long)packet +
+ roundup(len, ARCH_DMA_MINALIGN));
NetReceive((uchar *)packet, len);
fill_rx(hw);
return 1;
@@ -5170,7 +5172,7 @@ static int e1000_transmit(struct eth_device *nic, void *txpacket, int length)
struct e1000_hw *hw = nic->priv;
struct e1000_tx_desc *txp;
int i = 0;
- uint32_t flush_start, flush_end;
+ unsigned long flush_start, flush_end;
txp = tx_base + tx_tail;
tx_tail = (tx_tail + 1) % 8;
@@ -5180,10 +5182,11 @@ static int e1000_transmit(struct eth_device *nic, void *txpacket, int length)
txp->upper.data = 0;
/* Dump the packet into RAM so e1000 can pick them. */
- flush_dcache_range((u32)nv_packet,
- (u32)nv_packet + roundup(length, ARCH_DMA_MINALIGN));
+ flush_dcache_range((unsigned long)nv_packet,
+ (unsigned long)nv_packet +
+ roundup(length, ARCH_DMA_MINALIGN));
/* Dump the descriptor into RAM as well. */
- flush_start = ((u32)txp) & ~(ARCH_DMA_MINALIGN - 1);
+ flush_start = ((unsigned long)txp) & ~(ARCH_DMA_MINALIGN - 1);
flush_end = flush_start + roundup(sizeof(*txp), ARCH_DMA_MINALIGN);
flush_dcache_range(flush_start, flush_end);
diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c
index f1e39b9..1d1089d 100644
--- a/drivers/net/fm/eth.c
+++ b/drivers/net/fm/eth.c
@@ -410,10 +410,15 @@ static int fm_eth_open(struct eth_device *dev, bd_t *bd)
fmc_tx_port_graceful_stop_disable(fm_eth);
#ifdef CONFIG_PHYLIB
- ret = phy_startup(fm_eth->phydev);
- if (ret) {
- printf("%s: Could not initialize\n", fm_eth->phydev->dev->name);
- return ret;
+ if (fm_eth->phydev) {
+ ret = phy_startup(fm_eth->phydev);
+ if (ret) {
+ printf("%s: Could not initialize\n",
+ fm_eth->phydev->dev->name);
+ return ret;
+ }
+ } else {
+ return 0;
}
#else
fm_eth->phydev->speed = SPEED_1000;
@@ -447,7 +452,8 @@ static void fm_eth_halt(struct eth_device *dev)
/* disable bmi Rx port */
bmi_rx_port_disable(fm_eth->rx_port);
- phy_shutdown(fm_eth->phydev);
+ if (fm_eth->phydev)
+ phy_shutdown(fm_eth->phydev);
}
static int fm_eth_send(struct eth_device *dev, void *buf, int len)
@@ -625,11 +631,12 @@ static int init_phy(struct eth_device *dev)
if (fm_eth->bus) {
phydev = phy_connect(fm_eth->bus, fm_eth->phyaddr, dev,
fm_eth->enet_if);
- }
-
- if (!phydev) {
- printf("Failed to connect\n");
- return -1;
+ if (!phydev) {
+ printf("Failed to connect\n");
+ return -1;
+ }
+ } else {
+ return 0;
}
if (fm_eth->type == FM_ETH_1G_E) {
@@ -711,8 +718,7 @@ int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info)
if (!fm_eth_startup(fm_eth))
return 0;
- if (init_phy(dev))
- return 0;
+ init_phy(dev);
/* clear the ethernet address */
for (i = 0; i < 6; i++)
diff --git a/drivers/net/fm/t1040.c b/drivers/net/fm/t1040.c
index d2a097e..0458366 100644
--- a/drivers/net/fm/t1040.c
+++ b/drivers/net/fm/t1040.c
@@ -50,7 +50,8 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
switch (port) {
case FM1_DTSEC1:
case FM1_DTSEC2:
- if (is_serdes_configured(QSGMII_SW1_A + port - FM1_DTSEC1))
+ if (is_serdes_configured(QSGMII_SW1_A + port - FM1_DTSEC1) ||
+ is_serdes_configured(SGMII_SW1_MAC1 + port - FM1_DTSEC1))
return PHY_INTERFACE_MODE_QSGMII;
case FM1_DTSEC3:
case FM1_DTSEC4:
diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c
index d9d6f4f..d2a8ae0 100644
--- a/drivers/net/mpc5xxx_fec.c
+++ b/drivers/net/mpc5xxx_fec.c
@@ -407,13 +407,8 @@ static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis)
*/
if (fec->xcv_type == SEVENWIRE) {
/* 10MBit with 7-wire operation */
-#if defined(CONFIG_TOTAL5200)
- /* 7-wire and USB2 on Ethernet */
- *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00030000;
-#else /* !CONFIG_TOTAL5200 */
/* 7-wire only */
*(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000;
-#endif /* CONFIG_TOTAL5200 */
} else {
/* 100MBit with MD operation */
*(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000;
diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c
index 6ef6cac..6b31a82 100644
--- a/drivers/net/mvgbe.c
+++ b/drivers/net/mvgbe.c
@@ -35,6 +35,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_MVGBE_PORTS
+# define CONFIG_MVGBE_PORTS {0, 0}
+#endif
+
#define MV_PHY_ADR_REQUEST 0xee
#define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi)
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index f46bf00..d096db8 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o
obj-$(CONFIG_PHYLIB) += phy.o
obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
+obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o
obj-$(CONFIG_PHY_ATHEROS) += atheros.o
obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
obj-$(CONFIG_PHY_CORTINA) += cortina.o
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
new file mode 100644
index 0000000..ef4da4e
--- /dev/null
+++ b/drivers/net/phy/aquantia.c
@@ -0,0 +1,156 @@
+/*
+ * Aquantia PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+#include <config.h>
+#include <common.h>
+#include <phy.h>
+
+#ifndef CONFIG_PHYLIB_10G
+#error The Aquantia PHY needs 10G support
+#endif
+
+#define AQUNTIA_10G_CTL 0x20
+#define AQUNTIA_VENDOR_P1 0xc400
+
+#define AQUNTIA_SPEED_LSB_MASK 0x2000
+#define AQUNTIA_SPEED_MSB_MASK 0x40
+
+int aquantia_config(struct phy_device *phydev)
+{
+ u32 val = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR);
+
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ /* 1000BASE-T mode */
+ phydev->advertising = SUPPORTED_1000baseT_Full;
+ phydev->supported = phydev->advertising;
+
+ val = (val & ~AQUNTIA_SPEED_LSB_MASK) | AQUNTIA_SPEED_MSB_MASK;
+ phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
+ } else if (phydev->interface == PHY_INTERFACE_MODE_XGMII) {
+ /* 10GBASE-T mode */
+ phydev->advertising = SUPPORTED_10000baseT_Full;
+ phydev->supported = phydev->advertising;
+
+ if (!(val & AQUNTIA_SPEED_LSB_MASK) ||
+ !(val & AQUNTIA_SPEED_MSB_MASK))
+ phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR,
+ AQUNTIA_SPEED_LSB_MASK |
+ AQUNTIA_SPEED_MSB_MASK);
+ } else if (phydev->interface == PHY_INTERFACE_MODE_SGMII_2500) {
+ /* 2.5GBASE-T mode */
+ phydev->advertising = SUPPORTED_1000baseT_Full;
+ phydev->supported = phydev->advertising;
+
+ phy_write(phydev, MDIO_MMD_AN, AQUNTIA_10G_CTL, 1);
+ phy_write(phydev, MDIO_MMD_AN, AQUNTIA_VENDOR_P1, 0x9440);
+ } else if (phydev->interface == PHY_INTERFACE_MODE_MII) {
+ /* 100BASE-TX mode */
+ phydev->advertising = SUPPORTED_100baseT_Full;
+ phydev->supported = phydev->advertising;
+
+ val = (val & ~AQUNTIA_SPEED_MSB_MASK) | AQUNTIA_SPEED_LSB_MASK;
+ phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
+ }
+ return 0;
+}
+
+int aquantia_startup(struct phy_device *phydev)
+{
+ u32 reg, speed;
+ int i = 0;
+
+ phydev->duplex = DUPLEX_FULL;
+
+ /* if the AN is still in progress, wait till timeout. */
+ phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
+ reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
+ if (!(reg & MDIO_AN_STAT1_COMPLETE)) {
+ printf("%s Waiting for PHY auto negotiation to complete",
+ phydev->dev->name);
+ do {
+ udelay(1000);
+ reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
+ if ((i++ % 500) == 0)
+ printf(".");
+ } while (!(reg & MDIO_AN_STAT1_COMPLETE) &&
+ i < (4 * PHY_ANEG_TIMEOUT));
+
+ if (i > PHY_ANEG_TIMEOUT)
+ printf(" TIMEOUT !\n");
+ }
+
+ /* Read twice because link state is latched and a
+ * read moves the current state into the register */
+ phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
+ reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
+ if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
+ phydev->link = 0;
+ else
+ phydev->link = 1;
+
+ speed = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR);
+ if (speed & AQUNTIA_SPEED_MSB_MASK) {
+ if (speed & AQUNTIA_SPEED_LSB_MASK)
+ phydev->speed = SPEED_10000;
+ else
+ phydev->speed = SPEED_1000;
+ } else {
+ if (speed & AQUNTIA_SPEED_LSB_MASK)
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_10;
+ }
+
+ return 0;
+}
+
+struct phy_driver aq1202_driver = {
+ .name = "Aquantia AQ1202",
+ .uid = 0x3a1b445,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
+struct phy_driver aq2104_driver = {
+ .name = "Aquantia AQ2104",
+ .uid = 0x3a1b460,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
+struct phy_driver aqr105_driver = {
+ .name = "Aquantia AQR105",
+ .uid = 0x3a1b4a2,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+int phy_aquantia_init(void)
+{
+ phy_register(&aq1202_driver);
+ phy_register(&aq2104_driver);
+ phy_register(&aqr105_driver);
+
+ return 0;
+}
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 507b9a3..1815b29 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -22,6 +22,63 @@ static struct phy_driver KSZ804_driver = {
.shutdown = &genphy_shutdown,
};
+/**
+ * KSZ8895
+ */
+
+static unsigned short smireg_to_phy(unsigned short reg)
+{
+ return ((reg & 0xc0) >> 3) + 0x06 + ((reg & 0x20) >> 5);
+}
+
+static unsigned short smireg_to_reg(unsigned short reg)
+{
+ return reg & 0x1F;
+}
+
+static void ksz8895_write_smireg(struct phy_device *phydev, int smireg, int val)
+{
+ phydev->bus->write(phydev->bus, smireg_to_phy(smireg), MDIO_DEVAD_NONE,
+ smireg_to_reg(smireg), val);
+}
+
+#if 0
+static int ksz8895_read_smireg(struct phy_device *phydev, int smireg)
+{
+ return phydev->bus->read(phydev->bus, smireg_to_phy(smireg),
+ MDIO_DEVAD_NONE, smireg_to_reg(smireg));
+}
+#endif
+
+int ksz8895_config(struct phy_device *phydev)
+{
+ /* we are connected directly to the switch without
+ * dedicated PHY. SCONF1 == 001 */
+ phydev->link = 1;
+ phydev->duplex = DUPLEX_FULL;
+ phydev->speed = SPEED_100;
+
+ /* Force the switch to start */
+ ksz8895_write_smireg(phydev, 1, 1);
+
+ return 0;
+}
+
+static int ksz8895_startup(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static struct phy_driver ksz8895_driver = {
+ .name = "Micrel KSZ8895/KSZ8864",
+ .uid = 0x221450,
+ .mask = 0xffffe1,
+ .features = PHY_BASIC_FEATURES,
+ .config = &ksz8895_config,
+ .startup = &ksz8895_startup,
+ .shutdown = &genphy_shutdown,
+};
+
#ifndef CONFIG_PHY_MICREL_KSZ9021
/*
* I can't believe Micrel used the exact same part number
@@ -221,5 +278,6 @@ int phy_micrel_init(void)
phy_register(&KS8721_driver);
#endif
phy_register(&ksz9031_driver);
+ phy_register(&ksz8895_driver);
return 0;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 5b04c85..df7e945 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -442,6 +442,9 @@ static LIST_HEAD(phy_drivers);
int phy_init(void)
{
+#ifdef CONFIG_PHY_AQUANTIA
+ phy_aquantia_init();
+#endif
#ifdef CONFIG_PHY_ATHEROS
phy_atheros_init();
#endif
diff --git a/drivers/net/smc91111.h b/drivers/net/smc91111.h
index d9135cb..e19c491 100644
--- a/drivers/net/smc91111.h
+++ b/drivers/net/smc91111.h
@@ -236,7 +236,36 @@ struct smc91111_priv{
*(__b2 + __i) = SMC_inb((a),(r)); \
}; \
}while(0)
-
+#elif defined(CONFIG_MS7206SE)
+#define SWAB7206(x) ({ word __x = x; ((__x << 8)|(__x >> 8)); })
+#define SMC_inw(a, r) *((volatile word*)((a)->iobase + (r)))
+#define SMC_inb(a, r) (*((volatile byte*)((a)->iobase + ((r) ^ 0x01))))
+#define SMC_insw(a, r, b, l) \
+ do { \
+ int __i; \
+ word *__b2 = (word *)(b); \
+ for (__i = 0; __i < (l); __i++) { \
+ *__b2++ = SWAB7206(SMC_inw(a, r)); \
+ } \
+ } while (0)
+#define SMC_outw(a, d, r) (*((volatile word *)((a)->iobase+(r))) = d)
+#define SMC_outb(a, d, r) ({ word __d = (byte)(d); \
+ word __w = SMC_inw((a), ((r)&(~1))); \
+ if (((r) & 1)) \
+ __w = (__w & 0x00ff) | (__d << 8); \
+ else \
+ __w = (__w & 0xff00) | (__d); \
+ SMC_outw((a), __w, ((r)&(~1))); \
+ })
+#define SMC_outsw(a, r, b, l) \
+ do { \
+ int __i; \
+ word *__b2 = (word *)(b); \
+ for (__i = 0; __i < (l); __i++) { \
+ SMC_outw(a, SWAB7206(*__b2), r); \
+ __b2++; \
+ } \
+ } while (0)
#else /* if not CONFIG_CPU_PXA25X and not CONFIG_LEON */
#ifndef CONFIG_SMC_USE_IOFUNCS /* these macros don't work on some boards */
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 79d6561..dcdba4e 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -597,6 +597,8 @@ static int init_phy(struct eth_device *dev)
tsec_configure_serdes(priv);
phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+ if (!phydev)
+ return 0;
phydev->supported &= supported;
phydev->advertising = phydev->supported;
diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c
new file mode 100644
index 0000000..9fc3c18
--- /dev/null
+++ b/drivers/net/vsc9953.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Driver for the Vitesse VSC9953 L2 Switch
+ */
+
+#include <asm/io.h>
+#include <asm/fsl_serdes.h>
+#include <fm_eth.h>
+#include <asm/fsl_memac.h>
+#include <vsc9953.h>
+
+static struct vsc9953_info vsc9953_l2sw = {
+ .port[0] = VSC9953_PORT_INFO_INITIALIZER(0),
+ .port[1] = VSC9953_PORT_INFO_INITIALIZER(1),
+ .port[2] = VSC9953_PORT_INFO_INITIALIZER(2),
+ .port[3] = VSC9953_PORT_INFO_INITIALIZER(3),
+ .port[4] = VSC9953_PORT_INFO_INITIALIZER(4),
+ .port[5] = VSC9953_PORT_INFO_INITIALIZER(5),
+ .port[6] = VSC9953_PORT_INFO_INITIALIZER(6),
+ .port[7] = VSC9953_PORT_INFO_INITIALIZER(7),
+ .port[8] = VSC9953_PORT_INFO_INITIALIZER(8),
+ .port[9] = VSC9953_PORT_INFO_INITIALIZER(9),
+};
+
+void vsc9953_port_info_set_mdio(int port, struct mii_dev *bus)
+{
+ if (!VSC9953_PORT_CHECK(port))
+ return;
+
+ vsc9953_l2sw.port[port].bus = bus;
+}
+
+void vsc9953_port_info_set_phy_address(int port, int address)
+{
+ if (!VSC9953_PORT_CHECK(port))
+ return;
+
+ vsc9953_l2sw.port[port].phyaddr = address;
+}
+
+void vsc9953_port_info_set_phy_int(int port, phy_interface_t phy_int)
+{
+ if (!VSC9953_PORT_CHECK(port))
+ return;
+
+ vsc9953_l2sw.port[port].enet_if = phy_int;
+}
+
+void vsc9953_port_enable(int port)
+{
+ if (!VSC9953_PORT_CHECK(port))
+ return;
+
+ vsc9953_l2sw.port[port].enabled = 1;
+}
+
+void vsc9953_port_disable(int port)
+{
+ if (!VSC9953_PORT_CHECK(port))
+ return;
+
+ vsc9953_l2sw.port[port].enabled = 0;
+}
+
+static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr,
+ int regnum, int value)
+{
+ int timeout = 50000;
+
+ out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
+ ((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
+ (0x1 << 1));
+ asm("sync");
+
+ while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
+ udelay(1);
+
+ if (timeout == 0)
+ debug("Timeout waiting for MDIO write\n");
+}
+
+static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr,
+ int regnum)
+{
+ int value = 0xFFFF;
+ int timeout = 50000;
+
+ while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout)
+ udelay(1);
+ if (timeout == 0) {
+ debug("Timeout waiting for MDIO operation to finish\n");
+ return value;
+ }
+
+ /* Put the address of the phy, and the register
+ * number into MIICMD
+ */
+ out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
+ ((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
+ (0x2 << 1));
+
+ timeout = 50000;
+ /* Wait for the the indication that the read is done */
+ while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
+ udelay(1);
+ if (timeout == 0)
+ debug("Timeout waiting for MDIO read\n");
+
+ /* Grab the value read from the PHY */
+ value = in_le32(&phyregs->miimdata);
+
+ if ((value & 0x00030000) == 0)
+ return value & 0x0000ffff;
+
+ return value;
+}
+
+static int init_phy(struct eth_device *dev)
+{
+ struct vsc9953_port_info *l2sw_port = dev->priv;
+ struct phy_device *phydev = NULL;
+
+#ifdef CONFIG_PHYLIB
+ if (!l2sw_port->bus)
+ return 0;
+ phydev = phy_connect(l2sw_port->bus, l2sw_port->phyaddr, dev,
+ l2sw_port->enet_if);
+ if (!phydev) {
+ printf("Failed to connect\n");
+ return -1;
+ }
+
+ phydev->supported &= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full;
+ phydev->advertising = phydev->supported;
+
+ l2sw_port->phydev = phydev;
+
+ phy_config(phydev);
+#endif
+
+ return 0;
+}
+
+static int vsc9953_port_init(int port)
+{
+ struct eth_device *dev;
+
+ /* Internal ports never have a PHY */
+ if (VSC9953_INTERNAL_PORT_CHECK(port))
+ return 0;
+
+ /* alloc eth device */
+ dev = (struct eth_device *)calloc(1, sizeof(struct eth_device));
+ if (!dev)
+ return 1;
+
+ sprintf(dev->name, "SW@PORT%d", port);
+ dev->priv = &vsc9953_l2sw.port[port];
+ dev->init = NULL;
+ dev->halt = NULL;
+ dev->send = NULL;
+ dev->recv = NULL;
+
+ if (init_phy(dev)) {
+ free(dev);
+ return 1;
+ }
+
+ return 0;
+}
+
+void vsc9953_init(bd_t *bis)
+{
+ u32 i, hdx_cfg = 0, phy_addr = 0;
+ int timeout;
+ struct vsc9953_system_reg *l2sys_reg;
+ struct vsc9953_qsys_reg *l2qsys_reg;
+ struct vsc9953_dev_gmii *l2dev_gmii_reg;
+ struct vsc9953_analyzer *l2ana_reg;
+ struct vsc9953_devcpu_gcb *l2dev_gcb;
+
+ l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET +
+ VSC9953_DEV_GMII_OFFSET);
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
+ VSC9953_SYS_OFFSET);
+
+ l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
+ VSC9953_QSYS_OFFSET);
+
+ l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET +
+ VSC9953_DEVCPU_GCB);
+
+ out_le32(&l2dev_gcb->chip_regs.soft_rst,
+ CONFIG_VSC9953_SOFT_SWC_RST_ENA);
+ timeout = 50000;
+ while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) &
+ CONFIG_VSC9953_SOFT_SWC_RST_ENA) && --timeout)
+ udelay(1); /* busy wait for vsc9953 soft reset */
+ if (timeout == 0)
+ debug("Timeout waiting for VSC9953 to reset\n");
+
+ out_le32(&l2sys_reg->sys.reset_cfg, CONFIG_VSC9953_MEM_ENABLE |
+ CONFIG_VSC9953_MEM_INIT);
+
+ timeout = 50000;
+ while ((in_le32(&l2sys_reg->sys.reset_cfg) &
+ CONFIG_VSC9953_MEM_INIT) && --timeout)
+ udelay(1); /* busy wait for vsc9953 memory init */
+ if (timeout == 0)
+ debug("Timeout waiting for VSC9953 memory to initialize\n");
+
+ out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg)
+ | CONFIG_VSC9953_CORE_ENABLE));
+
+ /* VSC9953 Setting to be done once only */
+ out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00);
+
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (vsc9953_port_init(i))
+ printf("Failed to initialize l2switch port %d\n", i);
+
+ /* Enable VSC9953 GMII Ports Port ID 0 - 7 */
+ if (VSC9953_INTERNAL_PORT_CHECK(i)) {
+ out_le32(&l2ana_reg->pfc[i].pfc_cfg,
+ CONFIG_VSC9953_PFC_FC_QSGMII);
+ out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
+ CONFIG_VSC9953_MAC_FC_CFG_QSGMII);
+ } else {
+ out_le32(&l2ana_reg->pfc[i].pfc_cfg,
+ CONFIG_VSC9953_PFC_FC);
+ out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
+ CONFIG_VSC9953_MAC_FC_CFG);
+ }
+ out_le32(&l2dev_gmii_reg->port_mode.clock_cfg,
+ CONFIG_VSC9953_CLOCK_CFG);
+ out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg,
+ CONFIG_VSC9953_MAC_ENA_CFG);
+ out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg,
+ CONFIG_VSC9953_MAC_MODE_CFG);
+ out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg,
+ CONFIG_VSC9953_MAC_IFG_CFG);
+ /* mac_hdx_cfg varies with port id*/
+ hdx_cfg = (CONFIG_VSC9953_MAC_HDX_CFG | (i << 16));
+ out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg);
+ out_le32(&l2sys_reg->sys.front_port_mode[i],
+ CONFIG_VSC9953_FRONT_PORT_MODE);
+ out_le32(&l2qsys_reg->sys.switch_port_mode[i],
+ CONFIG_VSC9953_PORT_ENA);
+ out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg,
+ CONFIG_VSC9953_MAC_MAX_LEN);
+ out_le32(&l2sys_reg->pause_cfg.pause_cfg[i],
+ CONFIG_VSC9953_PAUSE_CFG);
+ /* WAIT FOR 2 us*/
+ udelay(2);
+
+ l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(
+ (char *)l2dev_gmii_reg
+ + T1040_SWITCH_GMII_DEV_OFFSET);
+
+ /* Initialize Lynx PHY Wrappers */
+ phy_addr = 0;
+ if (vsc9953_l2sw.port[i].enet_if ==
+ PHY_INTERFACE_MODE_QSGMII)
+ phy_addr = (i + 0x4) & 0x1F;
+ else if (vsc9953_l2sw.port[i].enet_if ==
+ PHY_INTERFACE_MODE_SGMII)
+ phy_addr = (i + 1) & 0x1F;
+
+ if (phy_addr) {
+ /* SGMII IF mode + AN enable */
+ vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
+ 0x14, PHY_SGMII_IF_MODE_AN |
+ PHY_SGMII_IF_MODE_SGMII);
+ /* Dev ability according to SGMII specification */
+ vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
+ 0x4, PHY_SGMII_DEV_ABILITY_SGMII);
+ /* Adjust link timer for SGMII
+ * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40
+ */
+ vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
+ 0x13, 0x0003);
+ vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
+ 0x12, 0x0d40);
+ /* Restart AN */
+ vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
+ 0x0, PHY_SGMII_CR_DEF_VAL |
+ PHY_SGMII_CR_RESET_AN);
+
+ timeout = 50000;
+ while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0],
+ phy_addr, 0x01) & 0x0020) && --timeout)
+ udelay(1); /* wait for AN to complete */
+ if (timeout == 0)
+ debug("Timeout waiting for AN to complete\n");
+ }
+ }
+
+ printf("VSC9953 L2 switch initialized\n");
+ return;
+}
+
+#ifdef CONFIG_VSC9953_CMD
+/* Enable/disable status of a VSC9953 port */
+static void vsc9953_port_status_set(int port_nr, u8 enabled)
+{
+ u32 val;
+ struct vsc9953_qsys_reg *l2qsys_reg;
+
+ /* Administrative down */
+ if (vsc9953_l2sw.port[port_nr].enabled == 0)
+ return;
+
+ l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
+ VSC9953_QSYS_OFFSET);
+
+ val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_nr]);
+ if (enabled == 1)
+ val |= (1 << 13);
+ else
+ val &= ~(1 << 13);
+
+ out_le32(&l2qsys_reg->sys.switch_port_mode[port_nr], val);
+}
+
+/* Set all VSC9953 ports' status */
+static void vsc9953_port_all_status_set(u8 enabled)
+{
+ int i;
+
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_port_status_set(i, enabled);
+}
+
+/* Start autonegotiation for a VSC9953 PHY */
+static void vsc9953_phy_autoneg(int port_nr)
+{
+ if (!vsc9953_l2sw.port[port_nr].phydev)
+ return;
+
+ if (vsc9953_l2sw.port[port_nr].phydev->drv->startup(
+ vsc9953_l2sw.port[port_nr].phydev))
+ printf("Failed to start PHY for port %d\n", port_nr);
+}
+
+/* Start autonegotiation for all VSC9953 PHYs */
+static void vsc9953_phy_all_autoneg(void)
+{
+ int i;
+
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_phy_autoneg(i);
+}
+
+/* Print a VSC9953 port's configuration */
+static void vsc9953_port_config_show(int port)
+{
+ int speed;
+ int duplex;
+ int link;
+ u8 enabled;
+ u32 val;
+ struct vsc9953_qsys_reg *l2qsys_reg;
+
+ l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
+ VSC9953_QSYS_OFFSET);
+
+ val = in_le32(&l2qsys_reg->sys.switch_port_mode[port]);
+ enabled = vsc9953_l2sw.port[port].enabled &
+ ((val & 0x00002000) >> 13);
+
+ /* internal ports (8 and 9) are fixed */
+ if (VSC9953_INTERNAL_PORT_CHECK(port)) {
+ link = 1;
+ speed = SPEED_2500;
+ duplex = DUPLEX_FULL;
+ } else {
+ if (vsc9953_l2sw.port[port].phydev) {
+ link = vsc9953_l2sw.port[port].phydev->link;
+ speed = vsc9953_l2sw.port[port].phydev->speed;
+ duplex = vsc9953_l2sw.port[port].phydev->duplex;
+ } else {
+ link = -1;
+ speed = -1;
+ duplex = -1;
+ }
+ }
+
+ printf("%8d ", port);
+ printf("%8s ", enabled == 1 ? "enabled" : "disabled");
+ printf("%8s ", link == 1 ? "up" : "down");
+
+ switch (speed) {
+ case SPEED_10:
+ printf("%8d ", 10);
+ break;
+ case SPEED_100:
+ printf("%8d ", 100);
+ break;
+ case SPEED_1000:
+ printf("%8d ", 1000);
+ break;
+ case SPEED_2500:
+ printf("%8d ", 2500);
+ break;
+ case SPEED_10000:
+ printf("%8d ", 10000);
+ break;
+ default:
+ printf("%8s ", "-");
+ }
+
+ printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half");
+}
+
+/* Print VSC9953 ports' configuration */
+static void vsc9953_port_all_config_show(void)
+{
+ int i;
+
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_port_config_show(i);
+}
+
+/* function to interpret commands starting with "ethsw " */
+static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u8 enable;
+ u32 port;
+
+ if (argc < 4)
+ return -1;
+
+ if (strcmp(argv[1], "port"))
+ return -1;
+
+ if (!strcmp(argv[3], "show")) {
+ if (!strcmp(argv[2], "all")) {
+ vsc9953_phy_all_autoneg();
+ printf("%8s %8s %8s %8s %8s\n",
+ "Port", "Status", "Link", "Speed",
+ "Duplex");
+ vsc9953_port_all_config_show();
+ return 0;
+ } else {
+ port = simple_strtoul(argv[2], NULL, 10);
+ if (!VSC9953_PORT_CHECK(port))
+ return -1;
+ vsc9953_phy_autoneg(port);
+ printf("%8s %8s %8s %8s %8s\n",
+ "Port", "Status", "Link", "Speed",
+ "Duplex");
+ vsc9953_port_config_show(port);
+ return 0;
+ }
+ } else if (!strcmp(argv[3], "enable")) {
+ enable = 1;
+ } else if (!strcmp(argv[3], "disable")) {
+ enable = 0;
+ } else {
+ return -1;
+ }
+
+ if (!strcmp(argv[2], "all")) {
+ vsc9953_port_all_status_set(enable);
+ return 0;
+ } else {
+ port = simple_strtoul(argv[2], NULL, 10);
+ if (!VSC9953_PORT_CHECK(port))
+ return -1;
+ vsc9953_port_status_set(port, enable);
+ return 0;
+ }
+
+ return -1;
+}
+
+U_BOOT_CMD(ethsw, 5, 0, do_ethsw,
+ "vsc9953 l2 switch commands",
+ "port <port_nr> enable|disable\n"
+ " - enable/disable an l2 switch port\n"
+ " port_nr=0..9; use \"all\" for all ports\n"
+ "ethsw port <port_nr> show\n"
+ " - show an l2 switch port's configuration\n"
+ " port_nr=0..9; use \"all\" for all ports\n"
+);
+#endif /* CONFIG_VSC9953_CMD */
diff --git a/drivers/net/xilinx_ll_temac.c b/drivers/net/xilinx_ll_temac.c
index dab78d0..7cc8657 100644
--- a/drivers/net/xilinx_ll_temac.c
+++ b/drivers/net/xilinx_ll_temac.c
@@ -231,7 +231,7 @@ static int ll_temac_init(struct eth_device *dev, bd_t *bis)
struct ll_temac *ll_temac = dev->priv;
int ret;
- printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08X.\n",
+ printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08lx.\n",
dev->name, dev->index, dev->iobase);
if (!ll_temac_setup_ctrl(dev))
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 3cadd23..430e228 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -489,7 +489,8 @@ static int zynq_gem_miiphy_write(const char *devname, uchar addr,
return phywrite(dev, addr, reg, val);
}
-int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio)
+int zynq_gem_initialize(bd_t *bis, phys_addr_t base_addr,
+ int phy_addr, u32 emio)
{
struct eth_device *dev;
struct zynq_gem_priv *priv;
@@ -521,7 +522,7 @@ int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio)
priv->phyaddr = phy_addr;
priv->emio = emio;
- sprintf(dev->name, "Gem.%x", base_addr);
+ sprintf(dev->name, "Gem.%lx", base_addr);
dev->iobase = base_addr;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 950a247..e1296ca 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -15,6 +15,7 @@
#include <common.h>
#include <command.h>
+#include <errno.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <pci.h>
@@ -236,6 +237,48 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
return -1;
}
+pci_dev_t pci_find_class(uint find_class, int index)
+{
+ int bus;
+ int devnum;
+ pci_dev_t bdf;
+ uint32_t class;
+
+ for (bus = 0; bus <= pci_last_busno(); bus++) {
+ for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
+ pci_read_config_dword(PCI_BDF(bus, devnum, 0),
+ PCI_CLASS_REVISION, &class);
+ if (class >> 16 == 0xffff)
+ continue;
+
+ for (bdf = PCI_BDF(bus, devnum, 0);
+ bdf <= PCI_BDF(bus, devnum,
+ PCI_MAX_PCI_FUNCTIONS - 1);
+ bdf += PCI_BDF(0, 0, 1)) {
+ pci_read_config_dword(bdf, PCI_CLASS_REVISION,
+ &class);
+ class >>= 8;
+
+ if (class != find_class)
+ continue;
+ /*
+ * Decrement the index. We want to return the
+ * correct device, so index is 0 for the first
+ * matching device, 1 for the second, etc.
+ */
+ if (index) {
+ index--;
+ continue;
+ }
+ /* Return index'th controller. */
+ return bdf;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
{
struct pci_device_id ids[2] = { {}, {0, 0} };
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index 44470fa..ed92857 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -11,7 +11,7 @@
*/
#include <common.h>
-
+#include <errno.h>
#include <pci.h>
#undef DEBUG
@@ -191,6 +191,32 @@ void pciauto_setup_device(struct pci_controller *hose,
pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
}
+int pciauto_setup_rom(struct pci_controller *hose, pci_dev_t dev)
+{
+ pci_addr_t bar_value;
+ pci_size_t bar_size;
+ u32 bar_response;
+ u16 cmdstat = 0;
+
+ pci_hose_write_config_dword(hose, dev, PCI_ROM_ADDRESS, 0xfffffffe);
+ pci_hose_read_config_dword(hose, dev, PCI_ROM_ADDRESS, &bar_response);
+ if (!bar_response)
+ return -ENOENT;
+
+ bar_size = -(bar_response & ~1);
+ DEBUGF("PCI Autoconfig: ROM, size=%#x, ", bar_size);
+ if (pciauto_region_allocate(hose->pci_mem, bar_size, &bar_value) == 0) {
+ pci_hose_write_config_dword(hose, dev, PCI_ROM_ADDRESS,
+ bar_value);
+ }
+ DEBUGF("\n");
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat);
+ cmdstat |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat);
+
+ return 0;
+}
+
void pciauto_prescan_setup_bridge(struct pci_controller *hose,
pci_dev_t dev, int sub_bus)
{
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index 7d25cc9..48c0a77 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -66,6 +66,7 @@ static int pci_rom_probe(pci_dev_t dev, uint class,
struct pci_rom_header *rom_header;
struct pci_rom_data *rom_data;
u16 vendor, device;
+ u16 rom_vendor, rom_device;
u32 vendev;
u32 mapped_vendev;
u32 rom_address;
@@ -80,7 +81,12 @@ static int pci_rom_probe(pci_dev_t dev, uint class,
#ifdef CONFIG_X86_OPTION_ROM_ADDR
rom_address = CONFIG_X86_OPTION_ROM_ADDR;
#else
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, (u32)PCI_ROM_ADDRESS_MASK);
+
+ if (pciauto_setup_rom(pci_bus_to_hose(PCI_BUS(dev)), dev)) {
+ debug("Cannot find option ROM\n");
+ return -ENOENT;
+ }
+
pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_address);
if (rom_address == 0x00000000 || rom_address == 0xffffffff) {
debug("%s: rom_address=%x\n", __func__, rom_address);
@@ -92,29 +98,31 @@ static int pci_rom_probe(pci_dev_t dev, uint class,
rom_address | PCI_ROM_ADDRESS_ENABLE);
#endif
debug("Option ROM address %x\n", rom_address);
- rom_header = (struct pci_rom_header *)rom_address;
+ rom_header = (struct pci_rom_header *)(unsigned long)rom_address;
debug("PCI expansion ROM, signature %#04x, INIT size %#04x, data ptr %#04x\n",
- le32_to_cpu(rom_header->signature),
- rom_header->size * 512, le32_to_cpu(rom_header->data));
+ le16_to_cpu(rom_header->signature),
+ rom_header->size * 512, le16_to_cpu(rom_header->data));
- if (le32_to_cpu(rom_header->signature) != PCI_ROM_HDR) {
+ if (le16_to_cpu(rom_header->signature) != PCI_ROM_HDR) {
printf("Incorrect expansion ROM header signature %04x\n",
- le32_to_cpu(rom_header->signature));
+ le16_to_cpu(rom_header->signature));
return -EINVAL;
}
- rom_data = (((void *)rom_header) + le32_to_cpu(rom_header->data));
+ rom_data = (((void *)rom_header) + le16_to_cpu(rom_header->data));
+ rom_vendor = le16_to_cpu(rom_data->vendor);
+ rom_device = le16_to_cpu(rom_data->device);
debug("PCI ROM image, vendor ID %04x, device ID %04x,\n",
- rom_data->vendor, rom_data->device);
+ rom_vendor, rom_device);
/* If the device id is mapped, a mismatch is expected */
- if ((vendor != rom_data->vendor || device != rom_data->device) &&
+ if ((vendor != rom_vendor || device != rom_device) &&
(vendev == mapped_vendev)) {
printf("ID mismatch: vendor ID %04x, device ID %04x\n",
- rom_data->vendor, rom_data->device);
- return -EPERM;
+ rom_vendor, rom_device);
+ /* Continue anyway */
}
debug("PCI ROM image, Class Code %04x%02x, Code Type %02x\n",
@@ -144,17 +152,23 @@ int pci_rom_load(uint16_t class, struct pci_rom_header *rom_header,
image_size);
rom_data = (struct pci_rom_data *)((void *)rom_header +
- le32_to_cpu(rom_header->data));
+ le16_to_cpu(rom_header->data));
- image_size = le32_to_cpu(rom_data->ilen) * 512;
- } while ((rom_data->type != 0) && (rom_data->indicator != 0));
+ image_size = le16_to_cpu(rom_data->ilen) * 512;
+ } while ((rom_data->type != 0) && (rom_data->indicator == 0));
if (rom_data->type != 0)
return -EACCES;
rom_size = rom_header->size * 512;
+#ifdef PCI_VGA_RAM_IMAGE_START
target = (void *)PCI_VGA_RAM_IMAGE_START;
+#else
+ target = (void *)malloc(rom_size);
+ if (!target)
+ return -ENOMEM;
+#endif
if (target != rom_header) {
ulong start = get_timer(0);
@@ -214,11 +228,12 @@ int vbe_get_video_info(struct graphic_device *gdev)
#endif
}
-int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate)
+int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), int exec_method)
{
struct pci_rom_header *rom, *ram;
int vesa_mode = -1;
uint16_t class;
+ bool emulate;
int ret;
/* Only execute VGA ROMs */
@@ -248,6 +263,29 @@ int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate)
vesa_mode = CONFIG_FRAMEBUFFER_VESA_MODE;
#endif
debug("Selected vesa mode %#x\n", vesa_mode);
+
+ if (exec_method & PCI_ROM_USE_NATIVE) {
+#ifdef CONFIG_X86
+ emulate = false;
+#else
+ if (!(exec_method & PCI_ROM_ALLOW_FALLBACK)) {
+ printf("BIOS native execution is only available on x86\n");
+ return -ENOSYS;
+ }
+ emulate = true;
+#endif
+ } else {
+#ifdef CONFIG_BIOSEMU
+ emulate = true;
+#else
+ if (!(exec_method & PCI_ROM_ALLOW_FALLBACK)) {
+ printf("BIOS emulation not available - see CONFIG_BIOSEMU\n");
+ return -ENOSYS;
+ }
+ emulate = false;
+#endif
+ }
+
if (emulate) {
#ifdef CONFIG_BIOSEMU
BE_VGAInfo *info;
@@ -260,9 +298,6 @@ int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate)
vesa_mode, &mode_info);
if (ret)
return ret;
-#else
- printf("BIOS emulation not available - see CONFIG_BIOSEMU\n");
- return -ENOSYS;
#endif
} else {
#ifdef CONFIG_X86
@@ -270,9 +305,6 @@ int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate)
bios_run_on_x86(dev, (unsigned long)ram, vesa_mode,
&mode_info);
-#else
- printf("BIOS native execution is only available on x86\n");
- return -ENOSYS;
#endif
}
debug("Final vesa mode %#x\n", mode_info.video_mode);
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index f9e05ad..67b5fdf 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -459,7 +459,6 @@ static int tegra_pcie_parse_port_info(const void *fdt, int node,
unsigned int *lanes)
{
struct fdt_pci_addr addr;
- pci_dev_t bdf;
int err;
err = fdtdec_get_int(fdt, node, "nvidia,num-lanes", 0);
@@ -470,13 +469,13 @@ static int tegra_pcie_parse_port_info(const void *fdt, int node,
*lanes = err;
- err = fdtdec_get_pci_bdf(fdt, node, &addr, &bdf);
+ err = fdtdec_get_pci_addr(fdt, node, 0, "reg", &addr);
if (err < 0) {
error("failed to parse \"reg\" property");
return err;
}
- *index = PCI_DEV(bdf) - 1;
+ *index = PCI_DEV(addr.phys_hi) - 1;
return 0;
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index e68e16b..f8f0239 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -63,3 +63,13 @@ config AXP221_ALDO3_VOLT
Set the voltage (mV) to program the axp221 aldo3 at, set to 0 to
disable aldo3. This is typically connected to VCC-PLL and AVCC and
must be set to 3V.
+
+config AXP221_ELDO3_VOLT
+ int "axp221 eldo3 voltage"
+ depends on AXP221_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp221 eldo3 at, set to 0 to
+ disable eldo3. On some A31(s) tablets it might be used to supply
+ 1.2V for the SSD2828 chip (converter of parallel LCD interface
+ into MIPI DSI).
diff --git a/drivers/power/as3722.c b/drivers/power/as3722.c
index 4c6de79..a60bb5f 100644
--- a/drivers/power/as3722.c
+++ b/drivers/power/as3722.c
@@ -31,7 +31,7 @@ static int as3722_read(struct udevice *pmic, u8 reg, u8 *value)
{
int err;
- err = i2c_read(pmic, reg, value, 1);
+ err = dm_i2c_read(pmic, reg, value, 1);
if (err < 0)
return err;
@@ -42,7 +42,7 @@ static int as3722_write(struct udevice *pmic, u8 reg, u8 value)
{
int err;
- err = i2c_write(pmic, reg, &value, 1);
+ err = dm_i2c_write(pmic, reg, &value, 1);
if (err < 0)
return err;
@@ -242,7 +242,7 @@ int as3722_init(struct udevice **devp)
const unsigned int address = 0x40;
int err;
- err = i2c_get_chip_for_busnum(bus, address, &pmic);
+ err = i2c_get_chip_for_busnum(bus, address, 1, &pmic);
if (err)
return err;
err = as3722_read_id(pmic, &id, &revision);
diff --git a/drivers/power/axp209.c b/drivers/power/axp209.c
index 3b1a6a7..4565398 100644
--- a/drivers/power/axp209.c
+++ b/drivers/power/axp209.c
@@ -16,6 +16,11 @@ enum axp209_reg {
AXP209_DCDC3_VOLTAGE = 0x27,
AXP209_LDO24_VOLTAGE = 0x28,
AXP209_LDO3_VOLTAGE = 0x29,
+ AXP209_IRQ_ENABLE1 = 0x40,
+ AXP209_IRQ_ENABLE2 = 0x41,
+ AXP209_IRQ_ENABLE3 = 0x42,
+ AXP209_IRQ_ENABLE4 = 0x43,
+ AXP209_IRQ_ENABLE5 = 0x44,
AXP209_IRQ_STATUS5 = 0x4c,
AXP209_SHUTDOWN = 0x32,
AXP209_GPIO0_CTRL = 0x90,
@@ -143,7 +148,7 @@ int axp209_set_ldo4(int mvolt)
int axp209_init(void)
{
u8 ver;
- int rc;
+ int i, rc;
rc = axp209_read(AXP209_CHIP_VERSION, &ver);
if (rc)
@@ -155,6 +160,13 @@ int axp209_init(void)
if (ver != 0x1)
return -1;
+ /* Mask all interrupts */
+ for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
+ rc = axp209_write(i, 0);
+ if (rc)
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/power/axp221.c b/drivers/power/axp221.c
index 4c86f09..3e07f23 100644
--- a/drivers/power/axp221.c
+++ b/drivers/power/axp221.c
@@ -29,9 +29,7 @@ static int pmic_bus_init(void)
#else
int ret;
- rsb_init();
-
- ret = rsb_set_device_mode(AXP223_DEVICE_MODE_DATA);
+ ret = rsb_init();
if (ret)
return ret;
@@ -302,6 +300,39 @@ int axp221_set_aldo3(unsigned int mvolt)
AXP221_OUTPUT_CTRL3_ALDO3_EN);
}
+int axp221_set_eldo(int eldo_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+ u8 addr, bits;
+
+ switch (eldo_num) {
+ case 3:
+ addr = AXP221_ELDO3_CTRL;
+ bits = AXP221_OUTPUT_CTRL2_ELDO3_EN;
+ break;
+ case 2:
+ addr = AXP221_ELDO2_CTRL;
+ bits = AXP221_OUTPUT_CTRL2_ELDO2_EN;
+ break;
+ case 1:
+ addr = AXP221_ELDO1_CTRL;
+ bits = AXP221_OUTPUT_CTRL2_ELDO1_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL2, bits);
+
+ ret = pmic_bus_write(addr, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2, bits);
+}
+
int axp221_init(void)
{
/* This cannot be 0 because it is used in SPL before BSS is ready */
diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c
index 29bab4c..8650983 100644
--- a/drivers/power/tps6586x.c
+++ b/drivers/power/tps6586x.c
@@ -37,7 +37,7 @@ static int tps6586x_read(int reg)
int retval = -1;
for (i = 0; i < MAX_I2C_RETRY; ++i) {
- if (!i2c_read(tps6586x_dev, reg, &data, 1)) {
+ if (!dm_i2c_read(tps6586x_dev, reg, &data, 1)) {
retval = (int)data;
goto exit;
}
@@ -60,7 +60,7 @@ static int tps6586x_write(int reg, uchar *data, uint len)
int retval = -1;
for (i = 0; i < MAX_I2C_RETRY; ++i) {
- if (!i2c_write(tps6586x_dev, reg, data, len)) {
+ if (!dm_i2c_write(tps6586x_dev, reg, data, len)) {
retval = 0;
goto exit;
}
diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c
index 39e6041..c9d318c 100644
--- a/drivers/rtc/mc146818.c
+++ b/drivers/rtc/mc146818.c
@@ -27,9 +27,6 @@
/* Set this to 1 to clear the CMOS RAM */
#define CLEAR_CMOS 0
-static uchar rtc_read (uchar reg);
-static void rtc_write (uchar reg, uchar val);
-
#define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70
#define RTC_SECONDS 0x00
#define RTC_SECONDS_ALARM 0x01
@@ -60,24 +57,24 @@ int rtc_get (struct rtc_time *tmp)
{
uchar sec, min, hour, mday, wday, mon, year;
/* here check if rtc can be accessed */
- while((rtc_read(RTC_CONFIG_A)&0x80)==0x80);
- sec = rtc_read (RTC_SECONDS);
- min = rtc_read (RTC_MINUTES);
- hour = rtc_read (RTC_HOURS);
- mday = rtc_read (RTC_DATE_OF_MONTH);
- wday = rtc_read (RTC_DAY_OF_WEEK);
- mon = rtc_read (RTC_MONTH);
- year = rtc_read (RTC_YEAR);
+ while ((rtc_read8(RTC_CONFIG_A) & 0x80) == 0x80);
+ sec = rtc_read8(RTC_SECONDS);
+ min = rtc_read8(RTC_MINUTES);
+ hour = rtc_read8(RTC_HOURS);
+ mday = rtc_read8(RTC_DATE_OF_MONTH);
+ wday = rtc_read8(RTC_DAY_OF_WEEK);
+ mon = rtc_read8(RTC_MONTH);
+ year = rtc_read8(RTC_YEAR);
#ifdef RTC_DEBUG
printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
"hr: %02x min: %02x sec: %02x\n",
year, mon, mday, wday,
hour, min, sec );
printf ( "Alarms: month: %02x hour: %02x min: %02x sec: %02x\n",
- rtc_read (RTC_CONFIG_D) & 0x3F,
- rtc_read (RTC_HOURS_ALARM),
- rtc_read (RTC_MINUTES_ALARM),
- rtc_read (RTC_SECONDS_ALARM) );
+ rtc_read8(RTC_CONFIG_D) & 0x3F,
+ rtc_read8(RTC_HOURS_ALARM),
+ rtc_read8(RTC_MINUTES_ALARM),
+ rtc_read8(RTC_SECONDS_ALARM));
#endif
tmp->tm_sec = bcd2bin (sec & 0x7F);
tmp->tm_min = bcd2bin (min & 0x7F);
@@ -108,80 +105,108 @@ int rtc_set (struct rtc_time *tmp)
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
#endif
- rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
+ rtc_write8(RTC_CONFIG_B, 0x82); /* disable the RTC to update the regs */
- rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100));
- rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon));
- rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday));
- rtc_write (RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday));
- rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour));
- rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min ));
- rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec ));
- rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
+ rtc_write8(RTC_YEAR, bin2bcd(tmp->tm_year % 100));
+ rtc_write8(RTC_MONTH, bin2bcd(tmp->tm_mon));
+ rtc_write8(RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday));
+ rtc_write8(RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday));
+ rtc_write8(RTC_HOURS, bin2bcd(tmp->tm_hour));
+ rtc_write8(RTC_MINUTES, bin2bcd(tmp->tm_min));
+ rtc_write8(RTC_SECONDS, bin2bcd(tmp->tm_sec));
+ rtc_write8(RTC_CONFIG_B, 0x02); /* enable the RTC to update the regs */
return 0;
}
void rtc_reset (void)
{
- rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
- rtc_write(RTC_CONFIG_A,0x20); /* Normal OP */
- rtc_write(RTC_CONFIG_B,0x00);
- rtc_write(RTC_CONFIG_B,0x00);
- rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
+ rtc_write8(RTC_CONFIG_B, 0x82); /* disable the RTC to update the regs */
+ rtc_write8(RTC_CONFIG_A, 0x20); /* Normal OP */
+ rtc_write8(RTC_CONFIG_B, 0x00);
+ rtc_write8(RTC_CONFIG_B, 0x00);
+ rtc_write8(RTC_CONFIG_B, 0x02); /* enable the RTC to update the regs */
}
/* ------------------------------------------------------------------------- */
-#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
/*
* use direct memory access
*/
-static uchar rtc_read (uchar reg)
+int rtc_read8(int reg)
{
+#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
return in8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg);
+#else
+ int ofs = 0;
+
+ if (reg >= 128) {
+ ofs = 2;
+ reg -= 128;
+ }
+ out8(RTC_PORT_MC146818 + ofs, reg);
+
+ return in8(RTC_PORT_MC146818 + ofs + 1);
+#endif
}
-static void rtc_write (uchar reg, uchar val)
+void rtc_write8(int reg, uchar val)
{
+#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
out8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg, val);
-}
#else
-static uchar rtc_read (uchar reg)
+ int ofs = 0;
+
+ if (reg >= 128) {
+ ofs = 2;
+ reg -= 128;
+ }
+ out8(RTC_PORT_MC146818 + ofs, reg);
+ out8(RTC_PORT_MC146818 + ofs + 1, val);
+#endif
+}
+
+u32 rtc_read32(int reg)
{
- out8(RTC_PORT_MC146818,reg);
- return in8(RTC_PORT_MC146818 + 1);
+ u32 value = 0;
+ int i;
+
+ for (i = 0; i < sizeof(value); i++)
+ value |= rtc_read8(reg + i) << (i << 3);
+
+ return value;
}
-static void rtc_write (uchar reg, uchar val)
+void rtc_write32(int reg, u32 value)
{
- out8(RTC_PORT_MC146818,reg);
- out8(RTC_PORT_MC146818+1, val);
+ int i;
+
+ for (i = 0; i < sizeof(value); i++)
+ rtc_write8(reg + i, (value >> (i << 3)) & 0xff);
}
-#endif
void rtc_init(void)
{
#if CLEAR_CMOS
int i;
- rtc_write(RTC_SECONDS_ALARM, 0);
- rtc_write(RTC_MINUTES_ALARM, 0);
- rtc_write(RTC_HOURS_ALARM, 0);
+ rtc_write8(RTC_SECONDS_ALARM, 0);
+ rtc_write8(RTC_MINUTES_ALARM, 0);
+ rtc_write8(RTC_HOURS_ALARM, 0);
for (i = RTC_CONFIG_A; i < RTC_REG_SIZE; i++)
- rtc_write(i, 0);
+ rtc_write8(i, 0);
printf("RTC: zeroing CMOS RAM\n");
#endif
/* Setup the real time clock */
- rtc_write(RTC_CONFIG_B, RTC_CONFIG_B_24H);
+ rtc_write8(RTC_CONFIG_B, RTC_CONFIG_B_24H);
/* Setup the frequency it operates at */
- rtc_write(RTC_CONFIG_A, RTC_CONFIG_A_REF_CLCK_32KHZ |
+ rtc_write8(RTC_CONFIG_A, RTC_CONFIG_A_REF_CLCK_32KHZ |
RTC_CONFIG_A_RATE_1024HZ);
/* Ensure all reserved bits are 0 in register D */
- rtc_write(RTC_CONFIG_D, RTC_CONFIG_D_VALID_RAM_AND_TIME);
+ rtc_write8(RTC_CONFIG_D, RTC_CONFIG_D_VALID_RAM_AND_TIME);
/* Clear any pending interrupts */
- rtc_read(RTC_CONFIG_C);
+ rtc_read8(RTC_CONFIG_C);
}
#endif
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index d1b5777..9131a8f 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -297,6 +297,7 @@ static int serial_pre_remove(struct udevice *dev)
UCLASS_DRIVER(serial) = {
.id = UCLASS_SERIAL,
.name = "serial",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
.post_probe = serial_post_probe,
.pre_remove = serial_pre_remove,
.per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c
index 1ff27d5..3e2b8dc 100644
--- a/drivers/serial/serial_zynq.c
+++ b/drivers/serial/serial_zynq.c
@@ -27,14 +27,14 @@ DECLARE_GLOBAL_DATA_PTR;
#define ZYNQ_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */
struct uart_zynq {
- u32 control; /* Control Register [8:0] */
- u32 mode; /* Mode Register [10:0] */
+ u32 control; /* 0x0 - Control Register [8:0] */
+ u32 mode; /* 0x4 - Mode Register [10:0] */
u32 reserved1[4];
- u32 baud_rate_gen; /* Baud Rate Generator [15:0] */
+ u32 baud_rate_gen; /* 0x18 - Baud Rate Generator [15:0] */
u32 reserved2[4];
- u32 channel_sts; /* Channel Status [11:0] */
- u32 tx_rx_fifo; /* FIFO [15:0] or [7:0] */
- u32 baud_rate_divider; /* Baud Rate Divider [7:0] */
+ u32 channel_sts; /* 0x2c - Channel Status [11:0] */
+ u32 tx_rx_fifo; /* 0x30 - FIFO [15:0] or [7:0] */
+ u32 baud_rate_divider; /* 0x34 - Baud Rate Divider [7:0] */
};
static struct uart_zynq *uart_zynq_ports[2] = {
@@ -42,29 +42,13 @@ static struct uart_zynq *uart_zynq_ports[2] = {
[1] = (struct uart_zynq *)ZYNQ_SERIAL_BASEADDR1,
};
-#if !defined(CONFIG_ZYNQ_SERIAL_BAUDRATE0)
-# define CONFIG_ZYNQ_SERIAL_BAUDRATE0 CONFIG_BAUDRATE
-#endif
-#if !defined(CONFIG_ZYNQ_SERIAL_BAUDRATE1)
-# define CONFIG_ZYNQ_SERIAL_BAUDRATE1 CONFIG_BAUDRATE
-#endif
-
-struct uart_zynq_params {
- u32 baudrate;
-};
-
-static struct uart_zynq_params uart_zynq_ports_param[2] = {
- [0].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE0,
- [1].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE1,
-};
-
/* Set up the baud rate in gd struct */
static void uart_zynq_serial_setbrg(const int port)
{
/* Calculation results. */
unsigned int calc_bauderror, bdiv, bgen;
unsigned long calc_baud = 0;
- unsigned long baud = uart_zynq_ports_param[port].baudrate;
+ unsigned long baud = gd->baudrate;
unsigned long clock = get_uart_clk(port);
struct uart_zynq *regs = uart_zynq_ports[port];
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 98ae3b8..a75fc46 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -340,6 +340,5 @@ U_BOOT_DRIVER(cadence_spi) = {
.ofdata_to_platdata = cadence_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct cadence_spi_platdata),
.priv_auto_alloc_size = sizeof(struct cadence_spi_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = cadence_spi_probe,
};
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 700f616..2624844 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -421,6 +421,5 @@ U_BOOT_DRIVER(dw_spi) = {
.ofdata_to_platdata = dw_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct dw_spi_platdata),
.priv_auto_alloc_size = sizeof(struct dw_spi_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = dw_spi_probe,
};
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index f078973..a46d8c1 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -425,6 +425,5 @@ U_BOOT_DRIVER(exynos_spi) = {
.ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
.priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = exynos_spi_probe,
};
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 0379444..194e882 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -7,6 +7,7 @@
*/
#include <common.h>
+#include <errno.h>
#include <malloc.h>
#include <spi.h>
#include <pci.h>
@@ -21,6 +22,7 @@
struct ich_ctlr {
pci_dev_t dev; /* PCI device number */
int ich_version; /* Controller version, 7 or 9 */
+ bool use_sbase; /* Use SBASE instead of RCB */
int ichspi_lock;
int locked;
uint8_t *opmenu;
@@ -145,7 +147,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
* ICH 7 SPI controller only supports array read command
* and byte program command for SST flash
*/
- if (ctlr.ich_version == 7) {
+ if (ctlr.ich_version == 7 || ctlr.use_sbase) {
ich->slave.op_mode_rx = SPI_OPM_RX_AS;
ich->slave.op_mode_tx = SPI_OPM_TX_BP;
}
@@ -153,6 +155,13 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return &ich->slave;
}
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
+ int spi_node)
+{
+ /* We only support a single SPI at present */
+ return spi_setup_slave(0, 0, 20000000, 0);
+}
+
void spi_free_slave(struct spi_slave *slave)
{
struct ich_spi_slave *ich = to_ich_spi(slave);
@@ -168,13 +177,15 @@ void spi_free_slave(struct spi_slave *slave)
static int get_ich_version(uint16_t device_id)
{
if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC ||
- device_id == PCI_DEVICE_ID_INTEL_ITC_LPC)
+ device_id == PCI_DEVICE_ID_INTEL_ITC_LPC ||
+ device_id == PCI_DEVICE_ID_INTEL_QRK_ILB)
return 7;
if ((device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX) ||
(device_id >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN &&
- device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX))
+ device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX) ||
+ device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC)
return 9;
return 0;
@@ -197,14 +208,14 @@ static int ich9_can_do_33mhz(pci_dev_t dev)
return speed == 1;
}
-static int ich_find_spi_controller(pci_dev_t *devp, int *ich_versionp)
+static int ich_find_spi_controller(struct ich_ctlr *ich)
{
int last_bus = pci_last_busno();
int bus;
if (last_bus == -1) {
debug("No PCI busses?\n");
- return -1;
+ return -ENODEV;
}
for (bus = 0; bus <= last_bus; bus++) {
@@ -218,24 +229,33 @@ static int ich_find_spi_controller(pci_dev_t *devp, int *ich_versionp)
device_id = ids >> 16;
if (vendor_id == PCI_VENDOR_ID_INTEL) {
- *devp = dev;
- *ich_versionp = get_ich_version(device_id);
- return 0;
+ ich->dev = dev;
+ ich->ich_version = get_ich_version(device_id);
+ if (device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC)
+ ich->use_sbase = true;
+ return ich->ich_version == 0 ? -ENODEV : 0;
}
}
debug("ICH SPI: No ICH found.\n");
- return -1;
+ return -ENODEV;
}
static int ich_init_controller(struct ich_ctlr *ctlr)
{
uint8_t *rcrb; /* Root Complex Register Block */
uint32_t rcba; /* Root Complex Base Address */
+ uint32_t sbase_addr;
+ uint8_t *sbase;
pci_read_config_dword(ctlr->dev, 0xf0, &rcba);
/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */
rcrb = (uint8_t *)(rcba & 0xffffc000);
+
+ /* SBASE is similar */
+ pci_read_config_dword(ctlr->dev, 0x54, &sbase_addr);
+ sbase = (uint8_t *)(sbase_addr & 0xfffffe00);
+
if (ctlr->ich_version == 7) {
struct ich7_spi_regs *ich7_spi;
@@ -255,7 +275,10 @@ static int ich_init_controller(struct ich_ctlr *ctlr)
} else if (ctlr->ich_version == 9) {
struct ich9_spi_regs *ich9_spi;
- ich9_spi = (struct ich9_spi_regs *)(rcrb + 0x3800);
+ if (ctlr->use_sbase)
+ ich9_spi = (struct ich9_spi_regs *)sbase;
+ else
+ ich9_spi = (struct ich9_spi_regs *)(rcrb + 0x3800);
ctlr->ichspi_lock = ich_readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
ctlr->opmenu = ich9_spi->opmenu;
ctlr->menubytes = sizeof(ich9_spi->opmenu);
@@ -275,12 +298,13 @@ static int ich_init_controller(struct ich_ctlr *ctlr)
ctlr->ich_version);
return -1;
}
- debug("ICH SPI: Version %d detected\n", ctlr->ich_version);
/* Work out the maximum speed we can support */
ctlr->max_speed = 20000000;
if (ctlr->ich_version == 9 && ich9_can_do_33mhz(ctlr->dev))
ctlr->max_speed = 33000000;
+ debug("ICH SPI: Version %d detected at %p, speed %ld\n",
+ ctlr->ich_version, ctlr->base, ctlr->max_speed);
ich_set_bbar(ctlr, 0);
@@ -291,7 +315,7 @@ void spi_init(void)
{
uint8_t bios_cntl;
- if (ich_find_spi_controller(&ctlr.dev, &ctlr.ich_version)) {
+ if (ich_find_spi_controller(&ctlr)) {
printf("ICH SPI: Cannot find device\n");
return;
}
@@ -305,10 +329,20 @@ void spi_init(void)
* Disable the BIOS write protect so write commands are allowed. On
* v9, deassert SMM BIOS Write Protect Disable.
*/
- pci_read_config_byte(ctlr.dev, 0xdc, &bios_cntl);
- if (ctlr.ich_version == 9)
- bios_cntl &= ~(1 << 5);
- pci_write_config_byte(ctlr.dev, 0xdc, bios_cntl | 0x1);
+ if (ctlr.use_sbase) {
+ struct ich9_spi_regs *ich9_spi;
+
+ ich9_spi = (struct ich9_spi_regs *)ctlr.base;
+ bios_cntl = ich_readb(&ich9_spi->bcr);
+ bios_cntl &= ~(1 << 5); /* clear Enable InSMM_STS (EISS) */
+ bios_cntl |= 1; /* Write Protect Disable (WPD) */
+ ich_writeb(bios_cntl, &ich9_spi->bcr);
+ } else {
+ pci_read_config_byte(ctlr.dev, 0xdc, &bios_cntl);
+ if (ctlr.ich_version == 9)
+ bios_cntl &= ~(1 << 5);
+ pci_write_config_byte(ctlr.dev, 0xdc, bios_cntl | 0x1);
+ }
}
int spi_claim_bus(struct spi_slave *slave)
diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h
index d2e4b85..1419b23 100644
--- a/drivers/spi/ich.h
+++ b/drivers/spi/ich.h
@@ -37,18 +37,19 @@ struct ich9_spi_regs {
uint8_t opmenu[8]; /* 0x98 */
uint32_t bbar;
uint8_t _reserved3[12];
- uint32_t fdoc;
+ uint32_t fdoc; /* 0xb0 */
uint32_t fdod;
uint8_t _reserved4[8];
- uint32_t afc;
+ uint32_t afc; /* 0xc0 */
uint32_t lvscc;
uint32_t uvscc;
uint8_t _reserved5[4];
- uint32_t fpb;
+ uint32_t fpb; /* 0xd0 */
uint8_t _reserved6[28];
- uint32_t srdl;
+ uint32_t srdl; /* 0xf0 */
uint32_t srdc;
- uint32_t srd;
+ uint32_t scs;
+ uint32_t bcr;
} __packed;
enum {
diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c
index e717424..bad5660 100644
--- a/drivers/spi/sandbox_spi.c
+++ b/drivers/spi/sandbox_spi.c
@@ -160,6 +160,5 @@ U_BOOT_DRIVER(spi_sandbox) = {
.name = "spi_sandbox",
.id = UCLASS_SPI,
.of_match = sandbox_spi_ids,
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.ops = &sandbox_spi_ops,
};
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index 5588036..6ae45f5 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -21,10 +21,10 @@
DECLARE_GLOBAL_DATA_PTR;
struct soft_spi_platdata {
- struct fdt_gpio_state cs;
- struct fdt_gpio_state sclk;
- struct fdt_gpio_state mosi;
- struct fdt_gpio_state miso;
+ struct gpio_desc cs;
+ struct gpio_desc sclk;
+ struct gpio_desc mosi;
+ struct gpio_desc miso;
int spi_delay_us;
};
@@ -35,9 +35,8 @@ struct soft_spi_priv {
static int soft_spi_scl(struct udevice *dev, int bit)
{
struct soft_spi_platdata *plat = dev->platdata;
- struct soft_spi_priv *priv = dev_get_priv(dev);
- gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL ? bit : !bit);
+ dm_gpio_set_value(&plat->sclk, bit);
return 0;
}
@@ -46,7 +45,7 @@ static int soft_spi_sda(struct udevice *dev, int bit)
{
struct soft_spi_platdata *plat = dev->platdata;
- gpio_set_value(plat->mosi.gpio, bit);
+ dm_gpio_set_value(&plat->mosi, bit);
return 0;
}
@@ -54,11 +53,10 @@ static int soft_spi_sda(struct udevice *dev, int bit)
static int soft_spi_cs_activate(struct udevice *dev)
{
struct soft_spi_platdata *plat = dev->platdata;
- struct soft_spi_priv *priv = dev_get_priv(dev);
- gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
- gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL);
- gpio_set_value(plat->cs.gpio, priv->mode & SPI_CS_HIGH);
+ dm_gpio_set_value(&plat->cs, 0);
+ dm_gpio_set_value(&plat->sclk, 0);
+ dm_gpio_set_value(&plat->cs, 1);
return 0;
}
@@ -66,9 +64,8 @@ static int soft_spi_cs_activate(struct udevice *dev)
static int soft_spi_cs_deactivate(struct udevice *dev)
{
struct soft_spi_platdata *plat = dev->platdata;
- struct soft_spi_priv *priv = dev_get_priv(dev);
- gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
+ dm_gpio_set_value(&plat->cs, 0);
return 0;
}
@@ -109,7 +106,6 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
uchar tmpdout = 0;
const u8 *txd = dout;
u8 *rxd = din;
- int cpol = priv->mode & SPI_CPOL;
int cpha = priv->mode & SPI_CPHA;
unsigned int j;
@@ -137,19 +133,19 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
}
if (!cpha)
- soft_spi_scl(dev, !cpol);
+ soft_spi_scl(dev, 0);
soft_spi_sda(dev, tmpdout & 0x80);
udelay(plat->spi_delay_us);
if (cpha)
- soft_spi_scl(dev, !cpol);
+ soft_spi_scl(dev, 0);
else
- soft_spi_scl(dev, cpol);
+ soft_spi_scl(dev, 1);
tmpdin <<= 1;
- tmpdin |= gpio_get_value(plat->miso.gpio);
+ tmpdin |= dm_gpio_get_value(&plat->miso);
tmpdout <<= 1;
udelay(plat->spi_delay_us);
if (cpha)
- soft_spi_scl(dev, cpol);
+ soft_spi_scl(dev, 1);
}
/*
* If the number of bits isn't a multiple of 8, shift the last
@@ -183,14 +179,6 @@ static int soft_spi_set_mode(struct udevice *dev, unsigned int mode)
return 0;
}
-static int soft_spi_child_pre_probe(struct udevice *dev)
-{
- struct spi_slave *slave = dev_get_parentdata(dev);
-
- slave->dev = dev;
- return spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
-}
-
static const struct dm_spi_ops soft_spi_ops = {
.claim_bus = soft_spi_claim_bus,
.release_bus = soft_spi_release_bus,
@@ -205,11 +193,6 @@ static int soft_spi_ofdata_to_platdata(struct udevice *dev)
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
- if (fdtdec_decode_gpio(blob, node, "cs-gpio", &plat->cs) ||
- fdtdec_decode_gpio(blob, node, "sclk-gpio", &plat->sclk) ||
- fdtdec_decode_gpio(blob, node, "mosi-gpio", &plat->mosi) ||
- fdtdec_decode_gpio(blob, node, "miso-gpio", &plat->miso))
- return -EINVAL;
plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0);
return 0;
@@ -219,16 +202,19 @@ static int soft_spi_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parentdata(dev);
struct soft_spi_platdata *plat = dev->platdata;
-
- gpio_request(plat->cs.gpio, "soft_spi_cs");
- gpio_request(plat->sclk.gpio, "soft_spi_sclk");
- gpio_request(plat->mosi.gpio, "soft_spi_mosi");
- gpio_request(plat->miso.gpio, "soft_spi_miso");
-
- gpio_direction_output(plat->sclk.gpio, slave->mode & SPI_CPOL);
- gpio_direction_output(plat->mosi.gpio, 1);
- gpio_direction_input(plat->miso.gpio);
- gpio_direction_output(plat->cs.gpio, !(slave->mode & SPI_CS_HIGH));
+ int cs_flags, clk_flags;
+
+ cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
+ clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
+ if (gpio_request_by_name(dev, "cs-gpio", 0, &plat->cs,
+ GPIOD_IS_OUT | cs_flags) ||
+ gpio_request_by_name(dev, "sclk-gpio", 0, &plat->sclk,
+ GPIOD_IS_OUT | clk_flags) ||
+ gpio_request_by_name(dev, "mosi-gpio", 0, &plat->mosi,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE) ||
+ gpio_request_by_name(dev, "miso-gpio", 0, &plat->miso,
+ GPIOD_IS_IN))
+ return -EINVAL;
return 0;
}
@@ -246,7 +232,5 @@ U_BOOT_DRIVER(soft_spi) = {
.ofdata_to_platdata = soft_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct soft_spi_platdata),
.priv_auto_alloc_size = sizeof(struct soft_spi_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = soft_spi_probe,
- .child_pre_probe = soft_spi_child_pre_probe,
};
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 7a57bce..63a6217 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -98,21 +98,51 @@ int spi_post_bind(struct udevice *dev)
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
-int spi_post_probe(struct udevice *dev)
+int spi_child_post_bind(struct udevice *dev)
{
- struct dm_spi_bus *spi = dev->uclass_priv;
+ struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
- spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ if (dev->of_offset == -1)
+ return 0;
+
+ return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
+}
+
+int spi_post_probe(struct udevice *bus)
+{
+ struct dm_spi_bus *spi = bus->uclass_priv;
+
+ spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"spi-max-frequency", 0);
return 0;
}
-int spi_chip_select(struct udevice *dev)
+int spi_child_pre_probe(struct udevice *dev)
{
+ struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
struct spi_slave *slave = dev_get_parentdata(dev);
- return slave ? slave->cs : -ENOENT;
+ /*
+ * This is needed because we pass struct spi_slave around the place
+ * instead slave->dev (a struct udevice). So we have to have some
+ * way to access the slave udevice given struct spi_slave. Once we
+ * change the SPI API to use udevice instead of spi_slave, we can
+ * drop this.
+ */
+ slave->dev = dev;
+
+ slave->max_hz = plat->max_hz;
+ slave->mode = plat->mode;
+
+ return 0;
+}
+
+int spi_chip_select(struct udevice *dev)
+{
+ struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
+
+ return plat ? plat->cs : -ENOENT;
}
int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
@@ -121,17 +151,11 @@ int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
- struct spi_slave store;
- struct spi_slave *slave = dev_get_parentdata(dev);
+ struct dm_spi_slave_platdata *plat;
- if (!slave) {
- slave = &store;
- spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
- slave);
- }
- debug("%s: slave=%p, cs=%d\n", __func__, slave,
- slave ? slave->cs : -1);
- if (slave && slave->cs == cs) {
+ plat = dev_get_parent_platdata(dev);
+ debug("%s: plat=%p, cs=%d\n", __func__, plat, plat->cs);
+ if (plat->cs == cs) {
*devp = dev;
return 0;
}
@@ -215,7 +239,6 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
struct udevice **busp, struct spi_slave **devp)
{
struct udevice *bus, *dev;
- struct spi_slave *slave;
bool created = false;
int ret;
@@ -232,11 +255,17 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
* SPI flash chip - we will bind to the correct driver.
*/
if (ret == -ENODEV && drv_name) {
+ struct dm_spi_slave_platdata *plat;
+
debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
__func__, dev_name, busnum, cs, drv_name);
ret = device_bind_driver(bus, drv_name, dev_name, &dev);
if (ret)
return ret;
+ plat = dev_get_parent_platdata(dev);
+ plat->cs = cs;
+ plat->max_hz = speed;
+ plat->mode = mode;
created = true;
} else if (ret) {
printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs,
@@ -245,23 +274,13 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
}
if (!device_active(dev)) {
- slave = (struct spi_slave *)calloc(1,
- sizeof(struct spi_slave));
- if (!slave) {
- ret = -ENOMEM;
- goto err;
- }
+ struct spi_slave *slave;
- ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
- slave);
+ ret = device_probe(dev);
if (ret)
goto err;
- slave->cs = cs;
+ slave = dev_get_parentdata(dev);
slave->dev = dev;
- ret = device_probe_child(dev, slave);
- free(slave);
- if (ret)
- goto err;
}
ret = spi_set_speed_mode(bus, speed, mode);
@@ -275,6 +294,8 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
return 0;
err:
+ debug("%s: Error path, credted=%d, device '%s'\n", __func__,
+ created, dev->name);
if (created) {
device_remove(dev);
device_unbind(dev);
@@ -321,13 +342,13 @@ void spi_free_slave(struct spi_slave *slave)
slave->dev = NULL;
}
-int spi_ofdata_to_platdata(const void *blob, int node,
- struct spi_slave *spi)
+int spi_slave_ofdata_to_platdata(const void *blob, int node,
+ struct dm_spi_slave_platdata *plat)
{
int mode = 0;
- spi->cs = fdtdec_get_int(blob, node, "reg", -1);
- spi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
+ plat->cs = fdtdec_get_int(blob, node, "reg", -1);
+ plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
if (fdtdec_get_bool(blob, node, "spi-cpol"))
mode |= SPI_CPOL;
if (fdtdec_get_bool(blob, node, "spi-cpha"))
@@ -336,7 +357,7 @@ int spi_ofdata_to_platdata(const void *blob, int node,
mode |= SPI_CS_HIGH;
if (fdtdec_get_bool(blob, node, "spi-half-duplex"))
mode |= SPI_PREAMBLE;
- spi->mode = mode;
+ plat->mode = mode;
return 0;
}
@@ -344,9 +365,15 @@ int spi_ofdata_to_platdata(const void *blob, int node,
UCLASS_DRIVER(spi) = {
.id = UCLASS_SPI,
.name = "spi",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = spi_post_bind,
.post_probe = spi_post_probe,
+ .child_pre_probe = spi_child_pre_probe,
.per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
+ .per_child_auto_alloc_size = sizeof(struct spi_slave),
+ .per_child_platdata_auto_alloc_size =
+ sizeof(struct dm_spi_slave_platdata),
+ .child_post_bind = spi_child_post_bind,
};
UCLASS_DRIVER(spi_generic) = {
diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c
index 2d97625..53ff9ea 100644
--- a/drivers/spi/tegra114_spi.c
+++ b/drivers/spi/tegra114_spi.c
@@ -407,6 +407,5 @@ U_BOOT_DRIVER(tegra114_spi) = {
.ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = tegra114_spi_probe,
};
diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c
index 7d0d0f3..78c74cd 100644
--- a/drivers/spi/tegra20_sflash.c
+++ b/drivers/spi/tegra20_sflash.c
@@ -348,6 +348,5 @@ U_BOOT_DRIVER(tegra20_sflash) = {
.ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = tegra20_sflash_probe,
};
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index 213fa5f..597d6ad 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -361,6 +361,5 @@ U_BOOT_DRIVER(tegra30_spi) = {
.ofdata_to_platdata = tegra30_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra30_spi_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = tegra30_spi_probe,
};
diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c
index b8ca720..0ef85db 100644
--- a/drivers/usb/eth/asix88179.c
+++ b/drivers/usb/eth/asix88179.c
@@ -271,6 +271,19 @@ static int asix_read_mac(struct eth_device *eth)
return 0;
}
+static int asix_write_mac(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ int ret;
+
+ ret = asix_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
+ ETH_ALEN, eth->enetaddr);
+ if (ret < 0)
+ debug("Failed to set MAC address: %02x\n", ret);
+
+ return ret;
+}
+
static int asix_basic_reset(struct ueth_data *dev)
{
struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
@@ -686,6 +699,7 @@ int ax88179_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
eth->send = asix_send;
eth->recv = asix_recv;
eth->halt = asix_halt;
+ eth->write_hwaddr = asix_write_mac;
eth->priv = ss;
if (asix_basic_reset(ss))
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index a4c5606..98c2da6 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -761,6 +761,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (value >= 0)
value = min(w_length, (u16) value);
break;
+ case USB_DT_BOS:
+ /*
+ * The USB compliance test (USB 2.0 Command Verifier)
+ * issues this request. We should not run into the
+ * default path here. But return for now until
+ * the superspeed support is added.
+ */
+ break;
default:
goto unknown;
}
diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c
index ead71eb..77a1567 100644
--- a/drivers/usb/gadget/f_dfu.c
+++ b/drivers/usb/gadget/f_dfu.c
@@ -780,6 +780,13 @@ static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
return 0;
}
+static int __dfu_get_alt(struct usb_function *f, unsigned intf)
+{
+ struct f_dfu *f_dfu = func_to_dfu(f);
+
+ return f_dfu->altsetting;
+}
+
/* TODO: is this really what we need here? */
static void dfu_disable(struct usb_function *f)
{
@@ -806,6 +813,7 @@ static int dfu_bind_config(struct usb_configuration *c)
f_dfu->usb_function.bind = dfu_bind;
f_dfu->usb_function.unbind = dfu_unbind;
f_dfu->usb_function.set_alt = dfu_set_alt;
+ f_dfu->usb_function.get_alt = __dfu_get_alt;
f_dfu->usb_function.disable = dfu_disable;
f_dfu->usb_function.strings = dfu_generic_strings;
f_dfu->usb_function.setup = dfu_handle;
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 8945c5b..d4460b2 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -1950,11 +1950,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
dev->watchdog.period = 5000 * CONFIG_SYS_HZ / 1000000; /* 5 ms */
dev->watchdog.function = udc_watchdog;
+ dev->mach = &mach_info;
+
udc_disable(dev);
udc_reinit(dev);
- dev->mach = &mach_info;
-
dev->gadget.name = "pxa2xx_udc";
retval = driver->bind(&dev->gadget);
if (retval) {
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index c11b551..66d6e9a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o
obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o
obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
+obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
# designware
obj-$(CONFIG_USB_DWC2) += dwc2.o
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 6fdbf57..f3c077d 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -31,7 +31,7 @@ DECLARE_GLOBAL_DATA_PTR;
struct exynos_ehci {
struct exynos_usb_phy *usb;
struct ehci_hccr *hcd;
- struct fdt_gpio_state vbus_gpio;
+ struct gpio_desc vbus_gpio;
};
static struct exynos_ehci exynos;
@@ -61,7 +61,8 @@ static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
exynos->hcd = (struct ehci_hccr *)addr;
/* Vbus gpio */
- fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
+ gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
+ &exynos->vbus_gpio, GPIOD_IS_OUT);
depth = 0;
node = fdtdec_next_compatible_subnode(blob, node,
@@ -236,9 +237,8 @@ int ehci_hcd_init(int index, enum usb_init_type init,
#ifdef CONFIG_OF_CONTROL
/* setup the Vbus gpio here */
- if (fdt_gpio_isvalid(&ctx->vbus_gpio) &&
- !fdtdec_setup_gpio(&ctx->vbus_gpio))
- gpio_direction_output(ctx->vbus_gpio.gpio, 1);
+ if (dm_gpio_is_valid(&ctx->vbus_gpio))
+ dm_gpio_set_value(&ctx->vbus_gpio, 1);
#endif
setup_usb_phy(ctx->usb);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index bc76066..f1fb190 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1148,7 +1148,7 @@ disable_periodic(struct ehci_ctrl *ctrl)
struct int_queue *
create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
- int elementsize, void *buffer)
+ int elementsize, void *buffer, int interval)
{
struct ehci_ctrl *ctrl = dev->controller;
struct int_queue *result = NULL;
@@ -1398,7 +1398,7 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
dev, pipe, buffer, length, interval);
- queue = create_int_queue(dev, pipe, 1, length, buffer);
+ queue = create_int_queue(dev, pipe, 1, length, buffer, interval);
if (!queue)
return -1;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 991b199..b9eabc5 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -34,57 +34,6 @@ static struct pci_device_id ehci_pci_ids[] = {
{0, 0}
};
#else
-static pci_dev_t ehci_find_class(int index)
-{
- int bus;
- int devnum;
- pci_dev_t bdf;
- uint32_t class;
-
- for (bus = 0; bus <= pci_last_busno(); bus++) {
- for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) {
- pci_read_config_dword(PCI_BDF(bus, devnum, 0),
- PCI_CLASS_REVISION, &class);
- if (class >> 16 == 0xffff)
- continue;
-
- for (bdf = PCI_BDF(bus, devnum, 0);
- bdf <= PCI_BDF(bus, devnum,
- PCI_MAX_PCI_FUNCTIONS - 1);
- bdf += PCI_BDF(0, 0, 1)) {
- pci_read_config_dword(bdf, PCI_CLASS_REVISION,
- &class);
- class >>= 8;
- /*
- * Here be dragons! In case we have multiple
- * PCI EHCI controllers, this function will
- * be called multiple times as well. This
- * function will scan the PCI busses, always
- * starting from bus 0, device 0, function 0,
- * until it finds an USB controller. The USB
- * stack gives us an 'index' of a controller
- * that is currently being registered, which
- * is a number, starting from 0 and growing
- * in ascending order as controllers are added.
- * To avoid probing the same controller in tne
- * subsequent runs of this function, we will
- * skip 'index - 1' detected controllers and
- * report the index'th controller.
- */
- if (class != PCI_CLASS_SERIAL_USB_EHCI)
- continue;
- if (index) {
- index--;
- continue;
- }
- /* Return index'th controller. */
- return bdf;
- }
- }
- }
-
- return -ENODEV;
-}
#endif
/*
@@ -102,7 +51,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
#ifdef CONFIG_PCI_EHCI_DEVICE
pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
#else
- pdev = ehci_find_class(index);
+ pdev = pci_find_class(PCI_CLASS_SERIAL_USB_EHCI, index);
#endif
if (pdev < 0) {
printf("EHCI host controller not found\n");
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 5f0a98e..b5ad1e3 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -72,8 +72,8 @@ struct fdt_usb {
enum usb_init_type init_type;
enum dr_mode dr_mode; /* dual role mode */
enum periph_id periph_id;/* peripheral id */
- struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */
- struct fdt_gpio_state phy_reset_gpio; /* GPIO to reset ULPI phy */
+ struct gpio_desc vbus_gpio; /* GPIO for vbus enable */
+ struct gpio_desc phy_reset_gpio; /* GPIO to reset ULPI phy */
};
static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */
@@ -252,17 +252,14 @@ static void set_up_vbus(struct fdt_usb *config, enum usb_init_type init)
return;
}
- if (fdt_gpio_isvalid(&config->vbus_gpio)) {
+ if (dm_gpio_is_valid(&config->vbus_gpio)) {
int vbus_value;
- fdtdec_setup_gpio(&config->vbus_gpio);
+ vbus_value = (init == USB_INIT_HOST);
+ dm_gpio_set_value(&config->vbus_gpio, vbus_value);
- vbus_value = (init == USB_INIT_HOST) ^
- !!(config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW);
- gpio_direction_output(config->vbus_gpio.gpio, vbus_value);
-
- debug("set_up_vbus: GPIO %d %d\n", config->vbus_gpio.gpio,
- vbus_value);
+ debug("set_up_vbus: GPIO %d %d\n",
+ gpio_get_number(&config->vbus_gpio), vbus_value);
}
}
@@ -360,7 +357,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
* mux must be switched to actually use a_sess_vld threshold.
*/
if (config->dr_mode == DR_MODE_OTG &&
- fdt_gpio_isvalid(&config->vbus_gpio))
+ dm_gpio_is_valid(&config->vbus_gpio))
clrsetbits_le32(&usbctlr->usb1_legacy_ctrl,
VBUS_SENSE_CTL_MASK,
VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT);
@@ -569,11 +566,10 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK);
/* reset ULPI phy */
- if (fdt_gpio_isvalid(&config->phy_reset_gpio)) {
- fdtdec_setup_gpio(&config->phy_reset_gpio);
- gpio_direction_output(config->phy_reset_gpio.gpio, 0);
+ if (dm_gpio_is_valid(&config->phy_reset_gpio)) {
+ dm_gpio_set_value(&config->phy_reset_gpio, 0);
mdelay(5);
- gpio_set_value(config->phy_reset_gpio.gpio, 1);
+ dm_gpio_set_value(&config->phy_reset_gpio, 1);
}
/* Reset the usb controller */
@@ -685,14 +681,16 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
debug("%s: Missing/invalid peripheral ID\n", __func__);
return -FDT_ERR_NOTFOUND;
}
- fdtdec_decode_gpio(blob, node, "nvidia,vbus-gpio", &config->vbus_gpio);
- fdtdec_decode_gpio(blob, node, "nvidia,phy-reset-gpio",
- &config->phy_reset_gpio);
+ gpio_request_by_name_nodev(blob, node, "nvidia,vbus-gpio", 0,
+ &config->vbus_gpio, GPIOD_IS_OUT);
+ gpio_request_by_name_nodev(blob, node, "nvidia,phy-reset-gpio", 0,
+ &config->phy_reset_gpio, GPIOD_IS_OUT);
debug("enabled=%d, legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, "
"vbus=%d, phy_reset=%d, dr_mode=%d\n",
config->enabled, config->has_legacy_mode, config->utmi,
- config->ulpi, config->periph_id, config->vbus_gpio.gpio,
- config->phy_reset_gpio.gpio, config->dr_mode);
+ config->ulpi, config->periph_id,
+ gpio_get_number(&config->vbus_gpio),
+ gpio_get_number(&config->phy_reset_gpio), config->dr_mode);
return 0;
}
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index b4946a3..a77c8bc 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -40,7 +40,7 @@ struct exynos_xhci {
struct exynos_usb3_phy *usb3_phy;
struct xhci_hccr *hcd;
struct dwc3 *dwc3_reg;
- struct fdt_gpio_state vbus_gpio;
+ struct gpio_desc vbus_gpio;
};
static struct exynos_xhci exynos;
@@ -69,7 +69,8 @@ static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
exynos->hcd = (struct xhci_hccr *)addr;
/* Vbus gpio */
- fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
+ gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
+ &exynos->vbus_gpio, GPIOD_IS_OUT);
depth = 0;
node = fdtdec_next_compatible_subnode(blob, node,
@@ -298,9 +299,8 @@ int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
#ifdef CONFIG_OF_CONTROL
/* setup the Vbus gpio here */
- if (fdt_gpio_isvalid(&ctx->vbus_gpio) &&
- !fdtdec_setup_gpio(&ctx->vbus_gpio))
- gpio_direction_output(ctx->vbus_gpio.gpio, 1);
+ if (dm_gpio_is_valid(&ctx->vbus_gpio))
+ dm_gpio_set_value(&ctx->vbus_gpio, 1);
#endif
ret = exynos_xhci_core_init(ctx);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
new file mode 100644
index 0000000..361fcce
--- /dev/null
+++ b/drivers/usb/host/xhci-pci.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <pci.h>
+#include <usb.h>
+
+#include "xhci.h"
+
+/*
+ * Create the appropriate control structures to manage a new XHCI host
+ * controller.
+ */
+int xhci_hcd_init(int index, struct xhci_hccr **ret_hccr,
+ struct xhci_hcor **ret_hcor)
+{
+ struct xhci_hccr *hccr;
+ struct xhci_hcor *hcor;
+ pci_dev_t pdev;
+ uint32_t cmd;
+ int len;
+
+ pdev = pci_find_class(PCI_CLASS_SERIAL_USB_XHCI, index);
+ if (pdev < 0) {
+ printf("XHCI host controller not found\n");
+ return -1;
+ }
+
+ hccr = (struct xhci_hccr *)pci_map_bar(pdev,
+ PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ len = HC_LENGTH(xhci_readl(&hccr->cr_capbase));
+ hcor = (struct xhci_hcor *)((uint32_t)hccr + len);
+
+ debug("XHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
+ (uint32_t)hccr, (uint32_t)hcor, len);
+
+ *ret_hccr = hccr;
+ *ret_hcor = hcor;
+
+ /* enable busmaster */
+ pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pci_write_config_dword(pdev, PCI_COMMAND, cmd);
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding * to the XHCI host
+ * controller
+ */
+void xhci_hcd_stop(int index)
+{
+}
diff --git a/drivers/usb/musb-new/Makefile b/drivers/usb/musb-new/Makefile
index 3facf0f..9edeece 100644
--- a/drivers/usb/musb-new/Makefile
+++ b/drivers/usb/musb-new/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_MUSB_HOST) += musb_host.o musb_core.o musb_uboot.o
obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
+obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
ccflags-y := $(call cc-option,-Wno-unused-variable) \
$(call cc-option,-Wno-unused-but-set-variable) \
diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c
index bbcee88..437309c 100644
--- a/drivers/usb/musb-new/musb_host.c
+++ b/drivers/usb/musb-new/musb_host.c
@@ -2130,8 +2130,6 @@ done:
return ret;
}
-
-#ifndef __UBOOT__
/*
* abort a transfer that's at the head of a hardware queue.
* called with controller locked, irqs blocked
@@ -2195,7 +2193,14 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
return status;
}
-static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+#ifndef __UBOOT__
+static int musb_urb_dequeue(
+#else
+int musb_urb_dequeue(
+#endif
+ struct usb_hcd *hcd,
+ struct urb *urb,
+ int status)
{
struct musb *musb = hcd_to_musb(hcd);
struct musb_qh *qh;
@@ -2253,6 +2258,7 @@ done:
return ret;
}
+#ifndef __UBOOT__
/* disable an endpoint */
static void
musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
diff --git a/drivers/usb/musb-new/musb_host.h b/drivers/usb/musb-new/musb_host.h
index ebebe0c..546b4a2 100644
--- a/drivers/usb/musb-new/musb_host.h
+++ b/drivers/usb/musb-new/musb_host.h
@@ -110,5 +110,6 @@ static inline struct urb *next_urb(struct musb_qh *qh)
#ifdef __UBOOT__
int musb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
#endif
#endif /* _MUSB_HOST_H */
diff --git a/drivers/usb/musb-new/musb_regs.h b/drivers/usb/musb-new/musb_regs.h
index 03f2655..27e4ed4 100644
--- a/drivers/usb/musb-new/musb_regs.h
+++ b/drivers/usb/musb-new/musb_regs.h
@@ -216,6 +216,9 @@
#ifndef CONFIG_BLACKFIN
+/* SUNXI has different reg addresses, but identical r/w functions */
+#ifndef CONFIG_ARCH_SUNXI
+
/*
* Common USB registers
*/
@@ -318,6 +321,85 @@
#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
(0x80 + (8*(_epnum)) + (_offset))
+#else /* CONFIG_ARCH_SUNXI */
+
+/*
+ * Common USB registers
+ */
+
+#define MUSB_FADDR 0x0098
+#define MUSB_POWER 0x0040
+
+#define MUSB_INTRTX 0x0044
+#define MUSB_INTRRX 0x0046
+#define MUSB_INTRTXE 0x0048
+#define MUSB_INTRRXE 0x004A
+#define MUSB_INTRUSB 0x004C
+#define MUSB_INTRUSBE 0x0050
+#define MUSB_FRAME 0x0054
+#define MUSB_INDEX 0x0042
+#define MUSB_TESTMODE 0x007C
+
+/* Get offset for a given FIFO from musb->mregs */
+#define MUSB_FIFO_OFFSET(epnum) (0x00 + ((epnum) * 4))
+
+/*
+ * Additional Control Registers
+ */
+
+#define MUSB_DEVCTL 0x0041
+
+/* These are always controlled through the INDEX register */
+#define MUSB_TXFIFOSZ 0x0090
+#define MUSB_RXFIFOSZ 0x0094
+#define MUSB_TXFIFOADD 0x0092
+#define MUSB_RXFIFOADD 0x0096
+
+#define MUSB_EPINFO 0x0078
+#define MUSB_RAMINFO 0x0079
+#define MUSB_LINKINFO 0x007A
+#define MUSB_VPLEN 0x007B
+#define MUSB_HS_EOF1 0x007C
+#define MUSB_FS_EOF1 0x007D
+#define MUSB_LS_EOF1 0x007E
+
+/* Offsets to endpoint registers */
+#define MUSB_TXMAXP 0x0080
+#define MUSB_TXCSR 0x0082
+#define MUSB_CSR0 0x0082
+#define MUSB_RXMAXP 0x0084
+#define MUSB_RXCSR 0x0086
+#define MUSB_RXCOUNT 0x0088
+#define MUSB_COUNT0 0x0088
+#define MUSB_TXTYPE 0x008C
+#define MUSB_TYPE0 0x008C
+#define MUSB_TXINTERVAL 0x008D
+#define MUSB_NAKLIMIT0 0x008D
+#define MUSB_RXTYPE 0x008E
+#define MUSB_RXINTERVAL 0x008F
+
+#define MUSB_CONFIGDATA 0x00b0 /* musb_read_configdata adds 0x10 ! */
+#define MUSB_FIFOSIZE 0x0090
+
+/* Offsets to endpoint registers in indexed model (using INDEX register) */
+#define MUSB_INDEXED_OFFSET(_epnum, _offset) (_offset)
+
+#define MUSB_TXCSR_MODE 0x2000
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MUSB_TXFUNCADDR 0x0098
+#define MUSB_TXHUBADDR 0x009A
+#define MUSB_TXHUBPORT 0x009B
+
+#define MUSB_RXFUNCADDR 0x009C
+#define MUSB_RXHUBADDR 0x009E
+#define MUSB_RXHUBPORT 0x009F
+
+/* Endpoint is selected with MUSB_INDEX. */
+#define MUSB_BUSCTL_OFFSET(_epnum, _offset) (_offset)
+
+#endif /* CONFIG_ARCH_SUNXI */
+
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
{
musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
@@ -340,7 +422,9 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
{
+#ifndef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
musb_writeb(mbase, MUSB_ULPI_BUSCONTROL, val);
+#endif
}
static inline u8 musb_read_txfifosz(void __iomem *mbase)
@@ -365,7 +449,11 @@ static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
{
+#ifdef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
+ return 0;
+#else
return musb_readb(mbase, MUSB_ULPI_BUSCONTROL);
+#endif
}
static inline u8 musb_read_configdata(void __iomem *mbase)
@@ -376,7 +464,11 @@ static inline u8 musb_read_configdata(void __iomem *mbase)
static inline u16 musb_read_hwvers(void __iomem *mbase)
{
+#ifdef CONFIG_ARCH_SUNXI
+ return 0; /* Unknown version */
+#else
return musb_readw(mbase, MUSB_HWVERS);
+#endif
}
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index 2676f09..6e58ddf 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -12,6 +12,11 @@
#include "musb_gadget.h"
#ifdef CONFIG_MUSB_HOST
+struct int_queue {
+ struct usb_host_endpoint hep;
+ struct urb urb;
+};
+
static struct musb *host;
static struct usb_hcd hcd;
static enum usb_device_speed host_speed;
@@ -25,45 +30,42 @@ static void musb_host_complete_urb(struct urb *urb)
static struct usb_host_endpoint hep;
static struct urb urb;
-static struct urb *construct_urb(struct usb_device *dev, int endpoint_type,
- unsigned long pipe, void *buffer, int len,
- struct devrequest *setup, int interval)
+static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
+ struct usb_device *dev, int endpoint_type,
+ unsigned long pipe, void *buffer, int len,
+ struct devrequest *setup, int interval)
{
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
- memset(&urb, 0, sizeof(struct urb));
- memset(&hep, 0, sizeof(struct usb_host_endpoint));
- INIT_LIST_HEAD(&hep.urb_list);
- INIT_LIST_HEAD(&urb.urb_list);
- urb.ep = &hep;
- urb.complete = musb_host_complete_urb;
- urb.status = -EINPROGRESS;
- urb.dev = dev;
- urb.pipe = pipe;
- urb.transfer_buffer = buffer;
- urb.transfer_dma = (unsigned long)buffer;
- urb.transfer_buffer_length = len;
- urb.setup_packet = (unsigned char *)setup;
-
- urb.ep->desc.wMaxPacketSize =
+ memset(urb, 0, sizeof(struct urb));
+ memset(hep, 0, sizeof(struct usb_host_endpoint));
+ INIT_LIST_HEAD(&hep->urb_list);
+ INIT_LIST_HEAD(&urb->urb_list);
+ urb->ep = hep;
+ urb->complete = musb_host_complete_urb;
+ urb->status = -EINPROGRESS;
+ urb->dev = dev;
+ urb->pipe = pipe;
+ urb->transfer_buffer = buffer;
+ urb->transfer_dma = (unsigned long)buffer;
+ urb->transfer_buffer_length = len;
+ urb->setup_packet = (unsigned char *)setup;
+
+ urb->ep->desc.wMaxPacketSize =
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
dev->epmaxpacketout[epnum]);
- urb.ep->desc.bmAttributes = endpoint_type;
- urb.ep->desc.bEndpointAddress =
+ urb->ep->desc.bmAttributes = endpoint_type;
+ urb->ep->desc.bEndpointAddress =
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
- urb.ep->desc.bInterval = interval;
-
- return &urb;
+ urb->ep->desc.bInterval = interval;
}
-#define MUSB_HOST_TIMEOUT 0x3ffffff
-
static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
{
struct musb *host = hcd->hcd_priv;
int ret;
- int timeout;
+ unsigned long timeout;
ret = musb_urb_enqueue(hcd, urb, 0);
if (ret < 0) {
@@ -71,12 +73,16 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
return ret;
}
- timeout = MUSB_HOST_TIMEOUT;
+ timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe);
do {
if (ctrlc())
return -EIO;
host->isr(0, host);
- } while ((urb->dev->status & USB_ST_NOT_PROC) && --timeout);
+ } while (urb->status == -EINPROGRESS &&
+ get_timer(0) < timeout);
+
+ if (urb->status == -EINPROGRESS)
+ musb_urb_dequeue(hcd, urb, -ETIME);
return urb->status;
}
@@ -84,38 +90,117 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len, struct devrequest *setup)
{
- struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_CONTROL, pipe,
- buffer, len, setup, 0);
+ construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe,
+ buffer, len, setup, 0);
/* Fix speed for non hub-attached devices */
if (!dev->parent)
dev->speed = host_speed;
- return submit_urb(&hcd, urb);
+ return submit_urb(&hcd, &urb);
}
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len)
{
- struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_BULK, pipe,
- buffer, len, NULL, 0);
- return submit_urb(&hcd, urb);
+ construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_BULK, pipe,
+ buffer, len, NULL, 0);
+ return submit_urb(&hcd, &urb);
}
int submit_int_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int len, int interval)
{
- struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_INT, pipe,
- buffer, len, NULL, interval);
- return submit_urb(&hcd, urb);
+ construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_INT, pipe,
+ buffer, len, NULL, interval);
+ return submit_urb(&hcd, &urb);
}
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
+ int queuesize, int elementsize, void *buffer, int interval)
+{
+ struct int_queue *queue;
+ int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
+
+ if (queuesize != 1) {
+ printf("ERROR musb int-queues only support queuesize 1\n");
+ return NULL;
+ }
+
+ if (dev->int_pending & (1 << index)) {
+ printf("ERROR int-urb is already pending on pipe %lx\n", pipe);
+ return NULL;
+ }
+
+ queue = malloc(sizeof(*queue));
+ if (!queue)
+ return NULL;
+
+ construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
+ pipe, buffer, elementsize, NULL, interval);
+
+ ret = musb_urb_enqueue(&hcd, &queue->urb, 0);
+ if (ret < 0) {
+ printf("Failed to enqueue URB to controller\n");
+ free(queue);
+ return NULL;
+ }
+
+ dev->int_pending |= 1 << index;
+ return queue;
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+ int index = usb_pipein(queue->urb.pipe) * 16 +
+ usb_pipeendpoint(queue->urb.pipe);
+
+ if (queue->urb.status == -EINPROGRESS)
+ musb_urb_dequeue(&hcd, &queue->urb, -ETIME);
+
+ dev->int_pending &= ~(1 << index);
+ free(queue);
+ return 0;
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
{
+ if (queue->urb.status != -EINPROGRESS)
+ return NULL; /* URB has already completed in a prev. poll */
+
+ host->isr(0, host);
+
+ if (queue->urb.status != -EINPROGRESS)
+ return queue->urb.transfer_buffer; /* Done */
+
+ return NULL; /* URB still pending */
+}
+
+void usb_reset_root_port(void)
+{
+ void *mbase = host->mregs;
u8 power;
+
+ power = musb_readb(mbase, MUSB_POWER);
+ power &= 0xf0;
+ musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
+ mdelay(50);
+ power = musb_readb(mbase, MUSB_POWER);
+ musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
+ host->isr(0, host);
+ host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
+ USB_SPEED_HIGH :
+ (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
+ USB_SPEED_FULL : USB_SPEED_LOW;
+ mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
void *mbase;
- int timeout = MUSB_HOST_TIMEOUT;
+ /* USB spec says it may take up to 1 second for a device to connect */
+ unsigned long timeout = get_timer(0) + 1000;
if (!host) {
printf("MUSB host is not registered\n");
@@ -127,20 +212,11 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
do {
if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
break;
- } while (--timeout);
- if (!timeout)
+ } while (get_timer(0) < timeout);
+ if (get_timer(0) >= timeout)
return -ENODEV;
- power = musb_readb(mbase, MUSB_POWER);
- musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
- udelay(30000);
- power = musb_readb(mbase, MUSB_POWER);
- musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
- host->isr(0, host);
- host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
- USB_SPEED_HIGH :
- (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
- USB_SPEED_FULL : USB_SPEED_LOW;
+ usb_reset_root_port();
host->is_active = 1;
hcd.hcd_priv = host;
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
new file mode 100644
index 0000000..778916d
--- /dev/null
+++ b/drivers/usb/musb-new/sunxi.c
@@ -0,0 +1,279 @@
+/*
+ * Allwinner SUNXI "glue layer"
+ *
+ * Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
+ * Based on the sw_usb "Allwinner OTG Dual Role Controller" code.
+ * Copyright 2007-2012 (C) Allwinner Technology Co., Ltd.
+ * javen <javen@allwinnertech.com>
+ *
+ * Based on the DA8xx "glue layer" code.
+ * Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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 <common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/usbc.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+
+/******************************************************************************
+ ******************************************************************************
+ * From the Allwinner driver
+ ******************************************************************************
+ ******************************************************************************/
+
+/******************************************************************************
+ * From include/sunxi_usb_bsp.h
+ ******************************************************************************/
+
+/* reg offsets */
+#define USBC_REG_o_ISCR 0x0400
+#define USBC_REG_o_PHYCTL 0x0404
+#define USBC_REG_o_PHYBIST 0x0408
+#define USBC_REG_o_PHYTUNE 0x040c
+
+#define USBC_REG_o_VEND0 0x0043
+
+/* Interface Status and Control */
+#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30
+#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29
+#define USBC_BP_ISCR_EXT_ID_STATUS 28
+#define USBC_BP_ISCR_EXT_DM_STATUS 27
+#define USBC_BP_ISCR_EXT_DP_STATUS 26
+#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25
+#define USBC_BP_ISCR_MERGED_ID_STATUS 24
+
+#define USBC_BP_ISCR_ID_PULLUP_EN 17
+#define USBC_BP_ISCR_DPDM_PULLUP_EN 16
+#define USBC_BP_ISCR_FORCE_ID 14
+#define USBC_BP_ISCR_FORCE_VBUS_VALID 12
+#define USBC_BP_ISCR_VBUS_VALID_SRC 10
+
+#define USBC_BP_ISCR_HOSC_EN 7
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6
+#define USBC_BP_ISCR_ID_CHANGE_DETECT 5
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4
+#define USBC_BP_ISCR_IRQ_ENABLE 3
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2
+#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0
+
+/******************************************************************************
+ * From usbc/usbc.c
+ ******************************************************************************/
+
+static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val)
+{
+ u32 temp = reg_val;
+
+ temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
+
+ return temp;
+}
+
+static void USBC_EnableIdPullUp(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val |= (1 << USBC_BP_ISCR_ID_PULLUP_EN);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_DisableIdPullUp(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val &= ~(1 << USBC_BP_ISCR_ID_PULLUP_EN);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_EnableDpDmPullUp(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_DisableDpDmPullUp(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceIdToLow(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceIdToHigh(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceVbusValidDisable(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceVbusValidToHigh(__iomem void *base)
+{
+ u32 reg_val;
+
+ reg_val = musb_readl(base, USBC_REG_o_ISCR);
+ reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ConfigFIFO_Base(void)
+{
+ u32 reg_value;
+
+ /* config usb fifo, 8kb mode */
+ reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
+ reg_value &= ~(0x03 << 0);
+ reg_value |= (1 << 0);
+ writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
+}
+
+/******************************************************************************
+ * MUSB Glue code
+ ******************************************************************************/
+
+static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
+{
+ struct musb *musb = __hci;
+ irqreturn_t retval = IRQ_NONE;
+
+ /* read and flush interrupts */
+ musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+ if (musb->int_usb)
+ musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
+ musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+ if (musb->int_tx)
+ musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
+ musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+ if (musb->int_rx)
+ musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
+
+ if (musb->int_usb || musb->int_tx || musb->int_rx)
+ retval |= musb_interrupt(musb);
+
+ return retval;
+}
+
+static void sunxi_musb_enable(struct musb *musb)
+{
+ pr_debug("%s():\n", __func__);
+
+ /* select PIO mode */
+ musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
+
+ if (is_host_enabled(musb)) {
+ /* port power on */
+ sunxi_usbc_vbus_enable(0);
+ }
+}
+
+static void sunxi_musb_disable(struct musb *musb)
+{
+ pr_debug("%s():\n", __func__);
+
+ /* Put the controller back in a pristane state for "usb reset" */
+ if (musb->is_active) {
+ sunxi_usbc_disable(0);
+ sunxi_usbc_enable(0);
+ musb->is_active = 0;
+ }
+}
+
+static int sunxi_musb_init(struct musb *musb)
+{
+ int err;
+
+ pr_debug("%s():\n", __func__);
+
+ err = sunxi_usbc_request_resources(0);
+ if (err)
+ return err;
+
+ musb->isr = sunxi_musb_interrupt;
+ sunxi_usbc_enable(0);
+
+ USBC_ConfigFIFO_Base();
+ USBC_EnableDpDmPullUp(musb->mregs);
+ USBC_EnableIdPullUp(musb->mregs);
+
+ if (is_host_enabled(musb)) {
+ /* Host mode */
+ USBC_ForceIdToLow(musb->mregs);
+ USBC_ForceVbusValidToHigh(musb->mregs);
+ } else {
+ /* Peripheral mode */
+ USBC_ForceIdToHigh(musb->mregs);
+ USBC_ForceVbusValidDisable(musb->mregs);
+ }
+
+ return 0;
+}
+
+static int sunxi_musb_exit(struct musb *musb)
+{
+ pr_debug("%s():\n", __func__);
+
+ USBC_DisableDpDmPullUp(musb->mregs);
+ USBC_DisableIdPullUp(musb->mregs);
+ sunxi_usbc_vbus_disable(0);
+ sunxi_usbc_disable(0);
+
+ return sunxi_usbc_free_resources(0);
+}
+
+const struct musb_platform_ops sunxi_musb_ops = {
+ .init = sunxi_musb_init,
+ .exit = sunxi_musb_exit,
+
+ .enable = sunxi_musb_enable,
+ .disable = sunxi_musb_disable,
+};
diff --git a/drivers/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h
index 27f656f..50bad37 100644
--- a/drivers/usb/musb-new/usb-compat.h
+++ b/drivers/usb/musb-new/usb-compat.h
@@ -48,6 +48,7 @@ struct urb {
list_add_tail(&urb->urb_list, &urb->ep->urb_list); \
ret; })
#define usb_hcd_unlink_urb_from_ep(hcd, urb) list_del_init(&urb->urb_list)
+#define usb_hcd_check_unlink_urb(hdc, urb, status) 0
static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd,
struct urb *urb,
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index fdbf3f6..51728b3 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1,8 +1,90 @@
-config VIDEO_X86
- bool "Enable x86 video driver support"
+config VIDEO_VESA
+ bool "Enable VESA video driver support"
depends on X86
default n
help
Turn on this option to enable a very simple driver which uses vesa
to discover the video mode and then provides a frame buffer for use
- by U-Boot.
+ by U-Boot. This can in principle be used with any platform that
+ supports PCI and video cards that support VESA BIOS Extension (VBE).
+
+config VIDEO_LCD_SSD2828
+ bool "SSD2828 bridge chip"
+ default n
+ ---help---
+ Support for the SSD2828 bridge chip, which can take pixel data coming
+ from a parallel LCD interface and translate it on the fly into MIPI DSI
+ interface for driving a MIPI compatible LCD panel. It uses SPI for
+ configuration.
+
+config VIDEO_LCD_SSD2828_TX_CLK
+ int "SSD2828 TX_CLK frequency (in MHz)"
+ depends on VIDEO_LCD_SSD2828
+ default 0
+ ---help---
+ The frequency of the crystal, which is clocking SSD2828. It may be
+ anything in the 8MHz-30MHz range and the exact value should be
+ retrieved from the board schematics. Or in the case of Allwinner
+ hardware, it can be usually found as 'lcd_xtal_freq' variable in
+ FEX files. It can be also set to 0 for selecting PCLK from the
+ parallel LCD interface instead of TX_CLK as the PLL clock source.
+
+config VIDEO_LCD_SSD2828_RESET
+ string "RESET pin of SSD2828"
+ depends on VIDEO_LCD_SSD2828
+ default ""
+ ---help---
+ The reset pin of SSD2828 chip. This takes a string in the format
+ understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H.
+
+config VIDEO_LCD_HITACHI_TX18D42VM
+ bool "Hitachi tx18d42vm LVDS LCD panel support"
+ depends on VIDEO
+ default n
+ ---help---
+ Support for Hitachi tx18d42vm LVDS LCD panels, these panels have a
+ lcd controller which needs to be initialized over SPI, once that is
+ done they work like a regular LVDS panel.
+
+config VIDEO_LCD_SPI_CS
+ string "SPI CS pin for LCD related config job"
+ depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM
+ default ""
+ ---help---
+ This is one of the SPI communication pins, involved in setting up a
+ working LCD configuration. The exact role of SPI may differ for
+ different hardware setups. The option takes a string in the format
+ understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H.
+
+config VIDEO_LCD_SPI_SCLK
+ string "SPI SCLK pin for LCD related config job"
+ depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM
+ default ""
+ ---help---
+ This is one of the SPI communication pins, involved in setting up a
+ working LCD configuration. The exact role of SPI may differ for
+ different hardware setups. The option takes a string in the format
+ understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H.
+
+config VIDEO_LCD_SPI_MOSI
+ string "SPI MOSI pin for LCD related config job"
+ depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM
+ default ""
+ ---help---
+ This is one of the SPI communication pins, involved in setting up a
+ working LCD configuration. The exact role of SPI may differ for
+ different hardware setups. The option takes a string in the format
+ understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H.
+
+config VIDEO_LCD_SPI_MISO
+ string "SPI MISO pin for LCD related config job (optional)"
+ depends on VIDEO_LCD_SSD2828
+ default ""
+ ---help---
+ This is one of the SPI communication pins, involved in setting up a
+ working LCD configuration. The exact role of SPI may differ for
+ different hardware setups. If wired up, this pin may provide additional
+ useful functionality. Such as bi-directional communication with the
+ hardware and LCD panel id retrieval (if the panel can report it). The
+ option takes a string in the format understood by 'name_to_gpio'
+ function, e.g. PH1 for pin 1 of port H.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 42b1eaa..af2d47b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_VIDEO_COREBOOT) += coreboot_fb.o
obj-$(CONFIG_VIDEO_CT69000) += ct69000.o videomodes.o
obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o
obj-$(CONFIG_VIDEO_IMX25LCDC) += imx25lcdc.o videomodes.o
+obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
+obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
obj-$(CONFIG_VIDEO_MB86R0xGDC) += mb86r0xgdc.o videomodes.o
obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
@@ -42,7 +44,7 @@ obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o videomodes.o
obj-$(CONFIG_VIDEO_TEGRA) += tegra.o
obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
-obj-$(CONFIG_VIDEO_X86) += x86_fb.o
+obj-$(CONFIG_VIDEO_VESA) += vesa_fb.o
obj-$(CONFIG_FORMIKE) += formike.o
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
obj-$(CONFIG_VIDEO_PARADE) += parade.o
diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
index 935ae42..0ce2370 100644
--- a/drivers/video/atmel_hlcdfb.c
+++ b/drivers/video/atmel_hlcdfb.c
@@ -13,6 +13,10 @@
#include <lcd.h>
#include <atmel_hlcdc.h>
+#if defined(CONFIG_LCD_LOGO)
+#include <bmp_logo.h>
+#endif
+
/* configurable parameters */
#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
#define ATMEL_LCDC_DMA_BURST_LEN 8
@@ -37,6 +41,15 @@ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
panel_info.mmio + ATMEL_LCDC_LUT(regno));
}
+ushort *configuration_get_cmap(void)
+{
+#if defined(CONFIG_LCD_LOGO)
+ return bmp_logo_palette;
+#else
+ return NULL;
+#endif
+}
+
void lcd_ctrl_init(void *lcdbase)
{
unsigned long value;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 3cf008c..4ed3a49 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -11,6 +11,7 @@
#include <asm/arch/gpio.h>
#include <asm/arch/clk.h>
#include <lcd.h>
+#include <bmp_layout.h>
#include <atmel_lcdc.h>
/* configurable parameters */
@@ -20,7 +21,7 @@
#define ATMEL_LCDC_GUARD_TIME 1
#endif
-#if defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91CAP9)
+#if defined(CONFIG_AT91SAM9263)
#define ATMEL_LCDC_FIFO_SIZE 2048
#else
#define ATMEL_LCDC_FIFO_SIZE 512
@@ -29,6 +30,46 @@
#define lcdc_readl(mmio, reg) __raw_readl((mmio)+(reg))
#define lcdc_writel(mmio, reg, val) __raw_writel((val), (mmio)+(reg))
+ushort *configuration_get_cmap(void)
+{
+ return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0));
+}
+
+#if defined(CONFIG_BMP_16BPP) && defined(CONFIG_ATMEL_LCD_BGR555)
+void fb_put_word(uchar **fb, uchar **from)
+{
+ *(*fb)++ = (((*from)[0] & 0x1f) << 2) | ((*from)[1] & 0x03);
+ *(*fb)++ = ((*from)[0] & 0xe0) | (((*from)[1] & 0x7c) >> 2);
+ *from += 2;
+}
+#endif
+
+#ifdef CONFIG_LCD_LOGO
+#include <bmp_logo.h>
+void lcd_logo_set_cmap(void)
+{
+ int i;
+ uint lut_entry;
+ ushort colreg;
+ uint *cmap = (uint *)configuration_get_cmap();
+
+ for (i = 0; i < BMP_LOGO_COLORS; ++i) {
+ colreg = bmp_logo_palette[i];
+#ifdef CONFIG_ATMEL_LCD_BGR555
+ lut_entry = ((colreg & 0x000F) << 11) |
+ ((colreg & 0x00F0) << 2) |
+ ((colreg & 0x0F00) >> 7);
+#else
+ lut_entry = ((colreg & 0x000F) << 1) |
+ ((colreg & 0x00F0) << 3) |
+ ((colreg & 0x0F00) << 4);
+#endif
+ *(cmap + BMP_LOGO_OFFSET) = lut_entry;
+ cmap++;
+ }
+}
+#endif
+
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
{
#if defined(CONFIG_ATMEL_LCD_BGR555)
@@ -40,6 +81,16 @@ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
#endif
}
+void lcd_set_cmap(bmp_image_t *bmp, unsigned colors)
+{
+ int i;
+
+ for (i = 0; i < colors; ++i) {
+ bmp_color_table_entry_t cte = bmp->color_table[i];
+ lcd_setcolreg(i, cte.red, cte.green, cte.blue);
+ }
+}
+
void lcd_ctrl_init(void *lcdbase)
{
unsigned long value;
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index cbe6b9f..a81affa 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -117,10 +117,7 @@
* Defines for the SED13806 driver
*/
#ifdef CONFIG_VIDEO_SED13806
-
-#ifndef CONFIG_TOTAL5200
#define VIDEO_FB_LITTLE_ENDIAN
-#endif
#define VIDEO_HW_RECTFILL
#define VIDEO_HW_BITBLT
#endif
@@ -302,7 +299,11 @@ void console_cursor(int state);
#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE)
#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
-#define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+
+/* By default we scroll by a single line */
+#ifndef CONFIG_CONSOLE_SCROLL_LINES
+#define CONFIG_CONSOLE_SCROLL_LINES 1
+#endif
/* Macros */
#ifdef VIDEO_FB_LITTLE_ENDIAN
@@ -743,26 +744,33 @@ static void console_clear_line(int line, int begin, int end)
static void console_scrollup(void)
{
+ const int rows = CONFIG_CONSOLE_SCROLL_LINES;
+ int i;
+
/* copy up rows ignoring the first one */
#ifdef VIDEO_HW_BITBLT
video_hw_bitblt(VIDEO_PIXEL_SIZE, /* bytes per pixel */
0, /* source pos x */
video_logo_height +
- VIDEO_FONT_HEIGHT, /* source pos y */
+ VIDEO_FONT_HEIGHT * rows, /* source pos y */
0, /* dest pos x */
video_logo_height, /* dest pos y */
VIDEO_VISIBLE_COLS, /* frame width */
VIDEO_VISIBLE_ROWS
- video_logo_height
- - VIDEO_FONT_HEIGHT /* frame height */
+ - VIDEO_FONT_HEIGHT * rows /* frame height */
);
#else
- memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND,
- CONSOLE_SCROLL_SIZE >> 2);
+ memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_FIRST + rows * CONSOLE_ROW_SIZE,
+ (CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows) >> 2);
#endif
/* clear the last one */
- console_clear_line(CONSOLE_ROWS - 1, 0, CONSOLE_COLS - 1);
+ for (i = 1; i <= rows; i++)
+ console_clear_line(CONSOLE_ROWS - i, 0, CONSOLE_COLS - 1);
+
+ /* Decrement row number */
+ console_row -= rows;
}
static void console_back(void)
@@ -874,9 +882,6 @@ static void console_newline(int n)
if (console_row >= CONSOLE_ROWS) {
/* Scroll everything up */
console_scrollup();
-
- /* Decrement row number */
- console_row = CONSOLE_ROWS - 1;
}
}
diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c
index be35b98..c5d7330 100644
--- a/drivers/video/exynos_fb.c
+++ b/drivers/video/exynos_fb.c
@@ -37,6 +37,15 @@ vidinfo_t panel_info = {
};
#endif
+ushort *configuration_get_cmap(void)
+{
+#if defined(CONFIG_LCD_LOGO)
+ return bmp_logo_palette;
+#else
+ return NULL;
+#endif
+}
+
static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid)
{
unsigned long palette_size;
diff --git a/drivers/video/hitachi_tx18d42vm_lcd.c b/drivers/video/hitachi_tx18d42vm_lcd.c
new file mode 100644
index 0000000..1ce4a8c
--- /dev/null
+++ b/drivers/video/hitachi_tx18d42vm_lcd.c
@@ -0,0 +1,81 @@
+/*
+ * Hitachi tx18d42vm LVDS LCD panel driver
+ *
+ * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <asm/gpio.h>
+#include <errno.h>
+
+/*
+ * Very simple write only SPI support, this does not use the generic SPI infra
+ * because that assumes R/W SPI, requiring a MISO pin. Also the necessary glue
+ * code alone would be larger then this minimal version.
+ */
+static void lcd_panel_spi_write(int cs, int clk, int mosi,
+ unsigned int data, int bits)
+{
+ int i, offset;
+
+ gpio_direction_output(cs, 0);
+ for (i = 0; i < bits; i++) {
+ gpio_direction_output(clk, 0);
+ offset = (bits - 1) - i;
+ gpio_direction_output(mosi, (data >> offset) & 1);
+ udelay(2);
+ gpio_direction_output(clk, 1);
+ udelay(2);
+ }
+ gpio_direction_output(cs, 1);
+ udelay(2);
+}
+
+int hitachi_tx18d42vm_init(void)
+{
+ const u16 init_data[] = {
+ 0x0029, /* reset */
+ 0x0025, /* standby */
+ 0x0840, /* enable normally black */
+ 0x0430, /* enable FRC/dither */
+ 0x385f, /* enter test mode(1) */
+ 0x3ca4, /* enter test mode(2) */
+ 0x3409, /* enable SDRRS, enlarge OE width */
+ 0x4041, /* adopt 2 line / 1 dot */
+ };
+ int i, cs, clk, mosi, ret = 0;
+
+ cs = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS);
+ clk = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK);
+ mosi = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI);
+
+ if (cs == -1 || clk == -1 || mosi == 1) {
+ printf("Error tx18d42vm spi gpio config is invalid\n");
+ return -EINVAL;
+ }
+
+ if (gpio_request(cs, "tx18d42vm-spi-cs") != 0 ||
+ gpio_request(clk, "tx18d42vm-spi-clk") != 0 ||
+ gpio_request(mosi, "tx18d42vm-spi-mosi") != 0) {
+ printf("Error cannot request tx18d42vm spi gpios\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(init_data); i++)
+ lcd_panel_spi_write(cs, clk, mosi, init_data[i], 16);
+
+ mdelay(50); /* All the tx18d42vm drivers have a delay here ? */
+
+ lcd_panel_spi_write(cs, clk, mosi, 0x00ad, 16); /* display on */
+
+out:
+ gpio_free(mosi);
+ gpio_free(clk);
+ gpio_free(cs);
+
+ return ret;
+}
diff --git a/drivers/video/hitachi_tx18d42vm_lcd.h b/drivers/video/hitachi_tx18d42vm_lcd.h
new file mode 100644
index 0000000..1b72800
--- /dev/null
+++ b/drivers/video/hitachi_tx18d42vm_lcd.h
@@ -0,0 +1,9 @@
+/*
+ * Hitachi tx18d42vm LVDS LCD panel driver
+ *
+ * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+void hitachi_tx18d42vm_init(void);
diff --git a/drivers/video/mpc8xx_lcd.c b/drivers/video/mpc8xx_lcd.c
index add7215..faa58c0 100644
--- a/drivers/video/mpc8xx_lcd.c
+++ b/drivers/video/mpc8xx_lcd.c
@@ -357,6 +357,35 @@ lcd_setcolreg (ushort regno, ushort red, ushort green, ushort blue)
/*----------------------------------------------------------------------*/
+ushort *configuration_get_cmap(void)
+{
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ cpm8xx_t *cp = &(immr->im_cpm);
+ return (ushort *)&(cp->lcd_cmap[255 * sizeof(ushort)]);
+}
+
+#if defined(CONFIG_MPC823)
+void fb_put_byte(uchar **fb, uchar **from)
+{
+ *(*fb)++ = (255 - *(*from)++);
+}
+#endif
+
+#ifdef CONFIG_LCD_LOGO
+#include <bmp_logo.h>
+void lcd_logo_set_cmap(void)
+{
+ int i;
+ ushort *cmap;
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ cpm8xx_t *cp = &(immr->im_cpm);
+ cmap = (ushort *)&(cp->lcd_cmap[BMP_LOGO_OFFSET * sizeof(ushort)]);
+
+ for (i = 0; i < BMP_LOGO_COLORS; ++i)
+ *cmap++ = bmp_logo_palette[i];
+}
+#endif
+
void lcd_enable (void)
{
volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
diff --git a/drivers/video/pxa_lcd.c b/drivers/video/pxa_lcd.c
index f66f615..04105d4 100644
--- a/drivers/video/pxa_lcd.c
+++ b/drivers/video/pxa_lcd.c
@@ -342,6 +342,12 @@ static int pxafb_init (vidinfo_t *vid);
/* --------------- PXA chipset specific functions ------------------- */
/************************************************************************/
+ushort *configuration_get_cmap(void)
+{
+ struct pxafb_info *fbi = &panel_info.pxa;
+ return (ushort *)fbi->palette;
+}
+
void lcd_ctrl_init (void *lcdbase)
{
pxafb_init_mem(lcdbase, &panel_info);
diff --git a/drivers/video/sed13806.c b/drivers/video/sed13806.c
index da653c0..cd7fac6 100644
--- a/drivers/video/sed13806.c
+++ b/drivers/video/sed13806.c
@@ -18,13 +18,8 @@
#define writeByte(ptrReg,value) \
*(volatile unsigned char *)(sed13806.isaBase + ptrReg) = value
-#ifdef CONFIG_TOTAL5200
-#define writeWord(ptrReg,value) \
- (*(volatile unsigned short *)(sed13806.isaBase + ptrReg) = value)
-#else
#define writeWord(ptrReg,value) \
(*(volatile unsigned short *)(sed13806.isaBase + ptrReg) = ((value >> 8 ) & 0xff) | ((value << 8) & 0xff00))
-#endif
GraphicDevice sed13806;
diff --git a/drivers/video/ssd2828.c b/drivers/video/ssd2828.c
new file mode 100644
index 0000000..8b09082
--- /dev/null
+++ b/drivers/video/ssd2828.c
@@ -0,0 +1,436 @@
+/*
+ * (C) 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Support for the SSD2828 bridge chip, which can take pixel data coming
+ * from a parallel LCD interface and translate it on the flight into MIPI DSI
+ * interface for driving a MIPI compatible TFT display.
+ */
+
+#include <common.h>
+#include <mipi_display.h>
+#include <asm/arch/gpio.h>
+#include <asm/gpio.h>
+
+#include "videomodes.h"
+#include "ssd2828.h"
+
+#define SSD2828_DIR 0xB0
+#define SSD2828_VICR1 0xB1
+#define SSD2828_VICR2 0xB2
+#define SSD2828_VICR3 0xB3
+#define SSD2828_VICR4 0xB4
+#define SSD2828_VICR5 0xB5
+#define SSD2828_VICR6 0xB6
+#define SSD2828_CFGR 0xB7
+#define SSD2828_VCR 0xB8
+#define SSD2828_PCR 0xB9
+#define SSD2828_PLCR 0xBA
+#define SSD2828_CCR 0xBB
+#define SSD2828_PSCR1 0xBC
+#define SSD2828_PSCR2 0xBD
+#define SSD2828_PSCR3 0xBE
+#define SSD2828_PDR 0xBF
+#define SSD2828_OCR 0xC0
+#define SSD2828_MRSR 0xC1
+#define SSD2828_RDCR 0xC2
+#define SSD2828_ARSR 0xC3
+#define SSD2828_LCR 0xC4
+#define SSD2828_ICR 0xC5
+#define SSD2828_ISR 0xC6
+#define SSD2828_ESR 0xC7
+#define SSD2828_DAR1 0xC9
+#define SSD2828_DAR2 0xCA
+#define SSD2828_DAR3 0xCB
+#define SSD2828_DAR4 0xCC
+#define SSD2828_DAR5 0xCD
+#define SSD2828_DAR6 0xCE
+#define SSD2828_HTTR1 0xCF
+#define SSD2828_HTTR2 0xD0
+#define SSD2828_LRTR1 0xD1
+#define SSD2828_LRTR2 0xD2
+#define SSD2828_TSR 0xD3
+#define SSD2828_LRR 0xD4
+#define SSD2828_PLLR 0xD5
+#define SSD2828_TR 0xD6
+#define SSD2828_TECR 0xD7
+#define SSD2828_ACR1 0xD8
+#define SSD2828_ACR2 0xD9
+#define SSD2828_ACR3 0xDA
+#define SSD2828_ACR4 0xDB
+#define SSD2828_IOCR 0xDC
+#define SSD2828_VICR7 0xDD
+#define SSD2828_LCFR 0xDE
+#define SSD2828_DAR7 0xDF
+#define SSD2828_PUCR1 0xE0
+#define SSD2828_PUCR2 0xE1
+#define SSD2828_PUCR3 0xE2
+#define SSD2828_CBCR1 0xE9
+#define SSD2828_CBCR2 0xEA
+#define SSD2828_CBSR 0xEB
+#define SSD2828_ECR 0xEC
+#define SSD2828_VSDR 0xED
+#define SSD2828_TMR 0xEE
+#define SSD2828_GPIO1 0xEF
+#define SSD2828_GPIO2 0xF0
+#define SSD2828_DLYA01 0xF1
+#define SSD2828_DLYA23 0xF2
+#define SSD2828_DLYB01 0xF3
+#define SSD2828_DLYB23 0xF4
+#define SSD2828_DLYC01 0xF5
+#define SSD2828_DLYC23 0xF6
+#define SSD2828_ACR5 0xF7
+#define SSD2828_RR 0xFF
+
+#define SSD2828_CFGR_HS (1 << 0)
+#define SSD2828_CFGR_CKE (1 << 1)
+#define SSD2828_CFGR_SLP (1 << 2)
+#define SSD2828_CFGR_VEN (1 << 3)
+#define SSD2828_CFGR_HCLK (1 << 4)
+#define SSD2828_CFGR_CSS (1 << 5)
+#define SSD2828_CFGR_DCS (1 << 6)
+#define SSD2828_CFGR_REN (1 << 7)
+#define SSD2828_CFGR_ECD (1 << 8)
+#define SSD2828_CFGR_EOT (1 << 9)
+#define SSD2828_CFGR_LPE (1 << 10)
+#define SSD2828_CFGR_TXD (1 << 11)
+
+#define SSD2828_VIDEO_MODE_NON_BURST_WITH_SYNC_PULSES (0 << 2)
+#define SSD2828_VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS (1 << 2)
+#define SSD2828_VIDEO_MODE_BURST (2 << 2)
+
+#define SSD2828_VIDEO_PIXEL_FORMAT_16BPP 0
+#define SSD2828_VIDEO_PIXEL_FORMAT_18BPP_PACKED 1
+#define SSD2828_VIDEO_PIXEL_FORMAT_18BPP_LOOSELY_PACKED 2
+#define SSD2828_VIDEO_PIXEL_FORMAT_24BPP 3
+
+#define SSD2828_LP_CLOCK_DIVIDER(n) (((n) - 1) & 0x3F)
+
+/*
+ * SPI transfer, using the "24-bit 3 wire" mode (that's how it is called in
+ * the SSD2828 documentation). The 'dout' input parameter specifies 24-bits
+ * of data to be written to SSD2828. Returns the lowest 16-bits of data,
+ * that is received back.
+ */
+static u32 soft_spi_xfer_24bit_3wire(const struct ssd2828_config *drv, u32 dout)
+{
+ int j, bitlen = 24;
+ u32 tmpdin = 0;
+ /*
+ * According to the "24 Bit 3 Wire SPI Interface Timing Characteristics"
+ * and "TX_CLK Timing Characteristics" tables in the SSD2828 datasheet,
+ * the lowest possible 'tx_clk' clock frequency is 8MHz, and SPI runs
+ * at 1/8 of that after reset. So using 1 microsecond delays is safe in
+ * the main loop. But the delays around chip select pin manipulations
+ * need to be longer (up to 16 'tx_clk' cycles, or 2 microseconds in
+ * the worst case).
+ */
+ const int spi_delay_us = 1;
+ const int spi_cs_delay_us = 2;
+
+ gpio_set_value(drv->csx_pin, 0);
+ udelay(spi_cs_delay_us);
+ for (j = bitlen - 1; j >= 0; j--) {
+ gpio_set_value(drv->sck_pin, 0);
+ gpio_set_value(drv->sdi_pin, (dout & (1 << j)) != 0);
+ udelay(spi_delay_us);
+ if (drv->sdo_pin != -1)
+ tmpdin = (tmpdin << 1) | gpio_get_value(drv->sdo_pin);
+ gpio_set_value(drv->sck_pin, 1);
+ udelay(spi_delay_us);
+ }
+ udelay(spi_cs_delay_us);
+ gpio_set_value(drv->csx_pin, 1);
+ udelay(spi_cs_delay_us);
+ return tmpdin & 0xFFFF;
+}
+
+/*
+ * Read from a SSD2828 hardware register (regnum >= 0xB0)
+ */
+static u32 read_hw_register(const struct ssd2828_config *cfg, u8 regnum)
+{
+ soft_spi_xfer_24bit_3wire(cfg, 0x700000 | regnum);
+ return soft_spi_xfer_24bit_3wire(cfg, 0x730000);
+}
+
+/*
+ * Write to a SSD2828 hardware register (regnum >= 0xB0)
+ */
+static void write_hw_register(const struct ssd2828_config *cfg, u8 regnum,
+ u16 val)
+{
+ soft_spi_xfer_24bit_3wire(cfg, 0x700000 | regnum);
+ soft_spi_xfer_24bit_3wire(cfg, 0x720000 | val);
+}
+
+/*
+ * Send MIPI command to the LCD panel (cmdnum < 0xB0)
+ */
+static void send_mipi_dcs_command(const struct ssd2828_config *cfg, u8 cmdnum)
+{
+ /* Set packet size to 1 (a single command with no parameters) */
+ write_hw_register(cfg, SSD2828_PSCR1, 1);
+ /* Send the command */
+ write_hw_register(cfg, SSD2828_PDR, cmdnum);
+}
+
+/*
+ * Reset SSD2828
+ */
+static void ssd2828_reset(const struct ssd2828_config *cfg)
+{
+ /* RESET needs 10 milliseconds according to the datasheet */
+ gpio_set_value(cfg->reset_pin, 0);
+ mdelay(10);
+ gpio_set_value(cfg->reset_pin, 1);
+ mdelay(10);
+}
+
+static int ssd2828_enable_gpio(const struct ssd2828_config *cfg)
+{
+ if (gpio_request(cfg->csx_pin, "ssd2828_csx")) {
+ printf("SSD2828: request for 'ssd2828_csx' pin failed\n");
+ return 1;
+ }
+ if (gpio_request(cfg->sck_pin, "ssd2828_sck")) {
+ gpio_free(cfg->csx_pin);
+ printf("SSD2828: request for 'ssd2828_sck' pin failed\n");
+ return 1;
+ }
+ if (gpio_request(cfg->sdi_pin, "ssd2828_sdi")) {
+ gpio_free(cfg->csx_pin);
+ gpio_free(cfg->sck_pin);
+ printf("SSD2828: request for 'ssd2828_sdi' pin failed\n");
+ return 1;
+ }
+ if (gpio_request(cfg->reset_pin, "ssd2828_reset")) {
+ gpio_free(cfg->csx_pin);
+ gpio_free(cfg->sck_pin);
+ gpio_free(cfg->sdi_pin);
+ printf("SSD2828: request for 'ssd2828_reset' pin failed\n");
+ return 1;
+ }
+ if (cfg->sdo_pin != -1 && gpio_request(cfg->sdo_pin, "ssd2828_sdo")) {
+ gpio_free(cfg->csx_pin);
+ gpio_free(cfg->sck_pin);
+ gpio_free(cfg->sdi_pin);
+ gpio_free(cfg->reset_pin);
+ printf("SSD2828: request for 'ssd2828_sdo' pin failed\n");
+ return 1;
+ }
+ gpio_direction_output(cfg->reset_pin, 0);
+ gpio_direction_output(cfg->csx_pin, 1);
+ gpio_direction_output(cfg->sck_pin, 1);
+ gpio_direction_output(cfg->sdi_pin, 1);
+ if (cfg->sdo_pin != -1)
+ gpio_direction_input(cfg->sdo_pin);
+
+ return 0;
+}
+
+static int ssd2828_free_gpio(const struct ssd2828_config *cfg)
+{
+ gpio_free(cfg->csx_pin);
+ gpio_free(cfg->sck_pin);
+ gpio_free(cfg->sdi_pin);
+ gpio_free(cfg->reset_pin);
+ if (cfg->sdo_pin != -1)
+ gpio_free(cfg->sdo_pin);
+ return 1;
+}
+
+/*
+ * PLL configuration register settings.
+ *
+ * See the "PLL Configuration Register Description" in the SSD2828 datasheet.
+ */
+static u32 construct_pll_config(u32 desired_pll_freq_kbps,
+ u32 reference_freq_khz)
+{
+ u32 div_factor = 1, mul_factor, fr = 0;
+ u32 output_freq_kbps;
+
+ /* The intermediate clock after division can't be less than 5MHz */
+ while (reference_freq_khz / (div_factor + 1) >= 5000)
+ div_factor++;
+ if (div_factor > 31)
+ div_factor = 31;
+
+ mul_factor = DIV_ROUND_UP(desired_pll_freq_kbps * div_factor,
+ reference_freq_khz);
+
+ output_freq_kbps = reference_freq_khz * mul_factor / div_factor;
+
+ if (output_freq_kbps >= 501000)
+ fr = 3;
+ else if (output_freq_kbps >= 251000)
+ fr = 2;
+ else if (output_freq_kbps >= 126000)
+ fr = 1;
+
+ return (fr << 14) | (div_factor << 8) | mul_factor;
+}
+
+static u32 decode_pll_config(u32 pll_config, u32 reference_freq_khz)
+{
+ u32 mul_factor = pll_config & 0xFF;
+ u32 div_factor = (pll_config >> 8) & 0x1F;
+ if (mul_factor == 0)
+ mul_factor = 1;
+ if (div_factor == 0)
+ div_factor = 1;
+ return reference_freq_khz * mul_factor / div_factor;
+}
+
+static int ssd2828_configure_video_interface(const struct ssd2828_config *cfg,
+ const struct ctfb_res_modes *mode)
+{
+ u32 val;
+
+ /* RGB Interface Control Register 1 */
+ write_hw_register(cfg, SSD2828_VICR1, (mode->vsync_len << 8) |
+ (mode->hsync_len));
+
+ /* RGB Interface Control Register 2 */
+ u32 vbp = mode->vsync_len + mode->upper_margin;
+ u32 hbp = mode->hsync_len + mode->left_margin;
+ write_hw_register(cfg, SSD2828_VICR2, (vbp << 8) | hbp);
+
+ /* RGB Interface Control Register 3 */
+ write_hw_register(cfg, SSD2828_VICR3, (mode->lower_margin << 8) |
+ (mode->right_margin));
+
+ /* RGB Interface Control Register 4 */
+ write_hw_register(cfg, SSD2828_VICR4, mode->xres);
+
+ /* RGB Interface Control Register 5 */
+ write_hw_register(cfg, SSD2828_VICR5, mode->yres);
+
+ /* RGB Interface Control Register 6 */
+ val = SSD2828_VIDEO_MODE_BURST;
+ switch (cfg->ssd2828_color_depth) {
+ case 16:
+ val |= SSD2828_VIDEO_PIXEL_FORMAT_16BPP;
+ break;
+ case 18:
+ val |= cfg->mipi_dsi_loosely_packed_pixel_format ?
+ SSD2828_VIDEO_PIXEL_FORMAT_18BPP_LOOSELY_PACKED :
+ SSD2828_VIDEO_PIXEL_FORMAT_18BPP_PACKED;
+ break;
+ case 24:
+ val |= SSD2828_VIDEO_PIXEL_FORMAT_24BPP;
+ break;
+ default:
+ printf("SSD2828: unsupported color depth\n");
+ return 1;
+ }
+ write_hw_register(cfg, SSD2828_VICR6, val);
+
+ /* Lane Configuration Register */
+ write_hw_register(cfg, SSD2828_LCFR,
+ cfg->mipi_dsi_number_of_data_lanes - 1);
+
+ return 0;
+}
+
+int ssd2828_init(const struct ssd2828_config *cfg,
+ const struct ctfb_res_modes *mode)
+{
+ u32 lp_div, pll_freq_kbps, reference_freq_khz, pll_config;
+ /* The LP clock speed is limited by 10MHz */
+ const u32 mipi_dsi_low_power_clk_khz = 10000;
+ /*
+ * This is just the reset default value of CFGR register (0x301).
+ * Because we are not always able to read back from SPI, have
+ * it initialized here.
+ */
+ u32 cfgr_reg = SSD2828_CFGR_EOT | /* EOT Packet Enable */
+ SSD2828_CFGR_ECD | /* Disable ECC and CRC */
+ SSD2828_CFGR_HS; /* Data lanes are in HS mode */
+
+ /* Initialize the pins */
+ if (ssd2828_enable_gpio(cfg) != 0)
+ return 1;
+
+ /* Reset the chip */
+ ssd2828_reset(cfg);
+
+ /*
+ * If there is a pin to read data back from SPI, then we are lucky. Try
+ * to check if SPI is configured correctly and SSD2828 is actually able
+ * to talk back.
+ */
+ if (cfg->sdo_pin != -1) {
+ if (read_hw_register(cfg, SSD2828_DIR) != 0x2828 ||
+ read_hw_register(cfg, SSD2828_CFGR) != cfgr_reg) {
+ printf("SSD2828: SPI communication failed.\n");
+ ssd2828_free_gpio(cfg);
+ return 1;
+ }
+ }
+
+ /*
+ * Pick the reference clock for PLL. If we know the exact 'tx_clk'
+ * clock speed, then everything is good. If not, then we can fallback
+ * to 'pclk' (pixel clock from the parallel LCD interface). In the
+ * case of using this fallback, it is necessary to have parallel LCD
+ * already initialized and running at this point.
+ */
+ reference_freq_khz = cfg->ssd2828_tx_clk_khz;
+ if (reference_freq_khz == 0) {
+ reference_freq_khz = mode->pixclock_khz;
+ /* Use 'pclk' as the reference clock for PLL */
+ cfgr_reg |= SSD2828_CFGR_CSS;
+ }
+
+ /*
+ * Setup the parallel LCD timings in the appropriate registers.
+ */
+ if (ssd2828_configure_video_interface(cfg, mode) != 0) {
+ ssd2828_free_gpio(cfg);
+ return 1;
+ }
+
+ /* Configuration Register */
+ cfgr_reg &= ~SSD2828_CFGR_HS; /* Data lanes are in LP mode */
+ cfgr_reg |= SSD2828_CFGR_CKE; /* Clock lane is in HS mode */
+ cfgr_reg |= SSD2828_CFGR_DCS; /* Only use DCS packets */
+ write_hw_register(cfg, SSD2828_CFGR, cfgr_reg);
+
+ /* PLL Configuration Register */
+ pll_config = construct_pll_config(
+ cfg->mipi_dsi_bitrate_per_data_lane_mbps * 1000,
+ reference_freq_khz);
+ write_hw_register(cfg, SSD2828_PLCR, pll_config);
+
+ pll_freq_kbps = decode_pll_config(pll_config, reference_freq_khz);
+ lp_div = DIV_ROUND_UP(pll_freq_kbps, mipi_dsi_low_power_clk_khz * 8);
+
+ /* VC Control Register */
+ write_hw_register(cfg, SSD2828_VCR, 0);
+
+ /* Clock Control Register */
+ write_hw_register(cfg, SSD2828_CCR, SSD2828_LP_CLOCK_DIVIDER(lp_div));
+
+ /* PLL Control Register */
+ write_hw_register(cfg, SSD2828_PCR, 1); /* Enable PLL */
+
+ /* Wait for PLL lock */
+ udelay(500);
+
+ send_mipi_dcs_command(cfg, MIPI_DCS_EXIT_SLEEP_MODE);
+ mdelay(cfg->mipi_dsi_delay_after_exit_sleep_mode_ms);
+
+ send_mipi_dcs_command(cfg, MIPI_DCS_SET_DISPLAY_ON);
+ mdelay(cfg->mipi_dsi_delay_after_set_display_on_ms);
+
+ cfgr_reg |= SSD2828_CFGR_HS; /* Enable HS mode for data lanes */
+ cfgr_reg |= SSD2828_CFGR_VEN; /* Enable video pipeline */
+ write_hw_register(cfg, SSD2828_CFGR, cfgr_reg);
+
+ return 0;
+}
diff --git a/drivers/video/ssd2828.h b/drivers/video/ssd2828.h
new file mode 100644
index 0000000..1af6fa4
--- /dev/null
+++ b/drivers/video/ssd2828.h
@@ -0,0 +1,128 @@
+/*
+ * (C) 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Support for the SSD2828 bridge chip, which can take pixel data coming
+ * from a parallel LCD interface and translate it on the flight into MIPI DSI
+ * interface for driving a MIPI compatible TFT display.
+ *
+ * Implemented as a utility function. To be used from display drivers, which are
+ * responsible for driving parallel LCD hardware in front of the video pipeline.
+ */
+
+#ifndef _SSD2828_H
+#define _SSD2828_H
+
+struct ctfb_res_modes;
+
+struct ssd2828_config {
+ /*********************************************************************/
+ /* SSD2828 configuration */
+ /*********************************************************************/
+
+ /*
+ * The pins, which are used for SPI communication. This is only used
+ * for configuring SSD2828, so the performance is irrelevant (only
+ * around a hundred of bytes is moved). Also these can be any arbitrary
+ * GPIO pins (not necessarily the pins having hardware SPI function).
+ * Moreover, the 'sdo' pin may be even not wired up in some devices.
+ *
+ * These configuration variables need to be set as pin numbers for
+ * the standard u-boot GPIO interface (gpio_get_value/gpio_set_value
+ * functions). Note that -1 value can be used for the pins, which are
+ * not really wired up.
+ */
+ int csx_pin;
+ int sck_pin;
+ int sdi_pin;
+ int sdo_pin;
+ /* SSD2828 reset pin (shared with LCD panel reset) */
+ int reset_pin;
+
+ /*
+ * The SSD2828 has its own dedicated clock source 'tx_clk' (connected
+ * to TX_CLK_XIO/TX_CLK_XIN pins), which is necessary at least for
+ * clocking SPI after reset. The exact clock speed is not strictly,
+ * defined, but the datasheet says that it must be somewhere in the
+ * 8MHz - 30MHz range (see "TX_CLK Timing" section). It can be also
+ * used as a reference clock for PLL. If the exact clock frequency
+ * is known, then it can be specified here. If it is unknown, or the
+ * information is not trustworthy, then it can be set to 0.
+ *
+ * If unsure, set to 0.
+ */
+ int ssd2828_tx_clk_khz;
+
+ /*
+ * This is not a property of the used LCD panel, but more like a
+ * property of the SSD2828 wiring. See the "SSD2828QN4 RGB data
+ * arrangement" table in the datasheet. The SSD2828 pins are arranged
+ * in such a way that 18bpp and 24bpp configurations are completely
+ * incompatible with each other.
+ *
+ * Depending on the color depth, this must be set to 16, 18 or 24.
+ */
+ int ssd2828_color_depth;
+
+ /*********************************************************************/
+ /* LCD panel configuration */
+ /*********************************************************************/
+
+ /*
+ * The number of lanes in the MIPI DSI interface. May vary from 1 to 4.
+ *
+ * This information can be found in the LCD panel datasheet.
+ */
+ int mipi_dsi_number_of_data_lanes;
+
+ /*
+ * Data transfer bit rate per lane. Please note that it is expected
+ * to be higher than the pixel clock rate of the used video mode when
+ * multiplied by the number of lanes. This is perfectly normal because
+ * MIPI DSI handles data transfers in periodic bursts, and uses the
+ * idle time between bursts for sending configuration information and
+ * commands. Or just for saving power.
+ *
+ * The necessary Mbps/lane information can be found in the LCD panel
+ * datasheet. Note that the transfer rate can't be always set precisely
+ * and it may be rounded *up* (introducing no more than 10Mbps error).
+ */
+ int mipi_dsi_bitrate_per_data_lane_mbps;
+
+ /*
+ * Setting this to 1 enforces packing of 18bpp pixel data in 24bpp
+ * envelope when sending it over the MIPI DSI link.
+ *
+ * If unsure, set to 0.
+ */
+ int mipi_dsi_loosely_packed_pixel_format;
+
+ /*
+ * According to the "Example for system sleep in and out" section in
+ * the SSD2828 datasheet, some LCD panel specific delays are necessary
+ * after MIPI DCS commands EXIT_SLEEP_MODE and SET_DISPLAY_ON.
+ *
+ * For example, Allwinner uses 100 milliseconds delay after
+ * EXIT_SLEEP_MODE and 200 milliseconds delay after SET_DISPLAY_ON.
+ */
+ int mipi_dsi_delay_after_exit_sleep_mode_ms;
+ int mipi_dsi_delay_after_set_display_on_ms;
+};
+
+/*
+ * Initialize the SSD2828 chip. It needs the 'ssd2828_config' structure
+ * and also the video mode timings.
+ *
+ * The right place to insert this function call is after the parallel LCD
+ * interface is initialized and before turning on the backlight. This is
+ * advised in the "Example for system sleep in and out" section of the
+ * SSD2828 datasheet. And also SS2828 may use 'pclk' as the clock source
+ * for PLL, which means that the input signal must be already there.
+ */
+int ssd2828_init(const struct ssd2828_config *cfg,
+ const struct ctfb_res_modes *mode);
+
+#endif
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
index d92dfa8..f5f24fc 100644
--- a/drivers/video/sunxi_display.c
+++ b/drivers/video/sunxi_display.c
@@ -20,6 +20,16 @@
#include <fdt_support.h>
#include <video_fb.h>
#include "videomodes.h"
+#include "hitachi_tx18d42vm_lcd.h"
+#include "ssd2828.h"
+
+#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
+#define PWM_ON 0
+#define PWM_OFF 1
+#else
+#define PWM_ON 1
+#define PWM_OFF 0
+#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -270,6 +280,114 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
#endif /* CONFIG_VIDEO_HDMI */
+#ifdef CONFIG_MACH_SUN4I
+/*
+ * Testing has shown that on sun4i the display backend engine does not have
+ * deep enough fifo-s causing flickering / tearing in full-hd mode due to
+ * fifo underruns. So on sun4i we use the display frontend engine to do the
+ * dma from memory, as the frontend does have deep enough fifo-s.
+ */
+
+static const u32 sun4i_vert_coef[32] = {
+ 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+ 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+ 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+ 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+ 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+ 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+ 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+ 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+};
+
+static const u32 sun4i_horz_coef[64] = {
+ 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
+ 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
+ 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
+ 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
+ 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
+ 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
+ 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
+ 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
+ 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
+ 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
+ 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
+ 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
+ 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
+ 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
+ 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
+ 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
+};
+
+static void sunxi_frontend_init(void)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_de_fe_reg * const de_fe =
+ (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
+ int i;
+
+ /* Clocks on */
+ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
+ setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
+ clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
+
+ setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
+
+ for (i = 0; i < 32; i++) {
+ writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
+ writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
+ writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
+ writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
+ writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
+ writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
+ }
+
+ setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
+}
+
+static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
+ unsigned int address)
+{
+ struct sunxi_de_fe_reg * const de_fe =
+ (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
+
+ setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
+ writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
+ writel(mode->xres * 4, &de_fe->ch0_stride);
+ writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
+ writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
+
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch0_insize);
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch0_outsize);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
+
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch1_insize);
+ writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
+ &de_fe->ch1_outsize);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
+ writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
+
+ setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
+}
+
+static void sunxi_frontend_enable(void)
+{
+ struct sunxi_de_fe_reg * const de_fe =
+ (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
+
+ setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
+}
+#else
+static void sunxi_frontend_init(void) {}
+static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
+ unsigned int address) {}
+static void sunxi_frontend_enable(void) {}
+#endif
+
/*
* This is the entity that mixes and matches the different layers and inputs.
* Allwinner calls it the back-end, but i like composer better.
@@ -282,6 +400,8 @@ static void sunxi_composer_init(void)
(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
int i;
+ sunxi_frontend_init();
+
#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
/* Reset off */
setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
@@ -289,7 +409,9 @@ static void sunxi_composer_init(void)
/* Clocks on */
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
+#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
+#endif
clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
/* Engine bug, clear registers after reset */
@@ -305,13 +427,19 @@ static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
struct sunxi_de_be_reg * const de_be =
(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+ sunxi_frontend_mode_set(mode, address);
+
writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
&de_be->disp_size);
writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
&de_be->layer0_size);
+#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
writel(address << 3, &de_be->layer0_addr_low32b);
writel(address >> 29, &de_be->layer0_addr_high4b);
+#else
+ writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
+#endif
writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
@@ -322,6 +450,8 @@ static void sunxi_composer_enable(void)
struct sunxi_de_be_reg * const de_be =
(struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+ sunxi_frontend_enable();
+
setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
}
@@ -476,8 +606,7 @@ static void sunxi_lcdc_panel_enable(void)
pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
if (pin != -1) {
gpio_request(pin, "lcd_backlight_pwm");
- /* backlight pwm is inverted, set to 1 to disable backlight */
- gpio_direction_output(pin, 1);
+ gpio_direction_output(pin, PWM_OFF);
}
/* Give the backlight some time to turn off and power up the panel. */
@@ -504,10 +633,8 @@ static void sunxi_lcdc_backlight_enable(void)
gpio_direction_output(pin, 1);
pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
- if (pin != -1) {
- /* backlight pwm is inverted, set to 0 to enable backlight */
- gpio_direction_output(pin, 0);
- }
+ if (pin != -1)
+ gpio_direction_output(pin, PWM_ON);
}
static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
@@ -518,7 +645,8 @@ static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
return (delay > 30) ? 30 : delay;
}
-static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode)
+static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
+ bool for_ext_vga_dac)
{
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
@@ -587,16 +715,16 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode)
&lcdc->tcon0_frm_ctrl);
}
-#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
- val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE0;
-#endif
-#ifdef CONFIG_VIDEO_LCD_IF_LVDS
- val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE60;
-#endif
+ val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
val |= SUNXI_LCDC_TCON_HSYNC_MASK;
if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
val |= SUNXI_LCDC_TCON_VSYNC_MASK;
+
+#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
+ if (for_ext_vga_dac)
+ val = 0;
+#endif
writel(val, &lcdc->tcon0_io_polarity);
writel(0, &lcdc->tcon0_io_tristate);
@@ -826,6 +954,40 @@ static void sunxi_vga_external_dac_enable(void)
}
#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
+#ifdef CONFIG_VIDEO_LCD_SSD2828
+static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
+{
+ struct ssd2828_config cfg = {
+ .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
+ .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
+ .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
+ .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
+ .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
+ .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
+ .ssd2828_color_depth = 24,
+#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
+ .mipi_dsi_number_of_data_lanes = 4,
+ .mipi_dsi_bitrate_per_data_lane_mbps = 513,
+ .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
+ .mipi_dsi_delay_after_set_display_on_ms = 200
+#else
+#error MIPI LCD panel needs configuration parameters
+#endif
+ };
+
+ if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
+ printf("SSD2828: SPI pins are not properly configured\n");
+ return 1;
+ }
+ if (cfg.reset_pin == -1) {
+ printf("SSD2828: Reset pin is not properly configured\n");
+ return 1;
+ }
+
+ return ssd2828_init(&cfg, mode);
+}
+#endif /* CONFIG_VIDEO_LCD_SSD2828 */
+
static void sunxi_engines_init(void)
{
sunxi_composer_init();
@@ -854,10 +1016,17 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
break;
case sunxi_monitor_lcd:
sunxi_lcdc_panel_enable();
+ if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
+ mdelay(50); /* Wait for lcd controller power on */
+ hitachi_tx18d42vm_init();
+ }
sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon0_mode_set(mode);
+ sunxi_lcdc_tcon0_mode_set(mode, false);
sunxi_composer_enable();
sunxi_lcdc_enable();
+#ifdef CONFIG_VIDEO_LCD_SSD2828
+ sunxi_ssd2828_init(mode);
+#endif
sunxi_lcdc_backlight_enable();
break;
case sunxi_monitor_vga:
@@ -870,7 +1039,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
sunxi_vga_enable();
#elif defined CONFIG_VIDEO_VGA_VIA_LCD
sunxi_composer_mode_set(mode, address);
- sunxi_lcdc_tcon0_mode_set(mode);
+ sunxi_lcdc_tcon0_mode_set(mode, true);
sunxi_composer_enable();
sunxi_lcdc_enable();
sunxi_vga_external_dac_enable();
@@ -1027,21 +1196,27 @@ int sunxi_simplefb_setup(void *blob)
int offset, ret;
const char *pipeline = NULL;
+#ifdef CONFIG_MACH_SUN4I
+#define PIPELINE_PREFIX "de_fe0-"
+#else
+#define PIPELINE_PREFIX
+#endif
+
switch (sunxi_display.monitor) {
case sunxi_monitor_none:
return 0;
case sunxi_monitor_dvi:
case sunxi_monitor_hdmi:
- pipeline = "de_be0-lcd0-hdmi";
+ pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
break;
case sunxi_monitor_lcd:
- pipeline = "de_be0-lcd0";
+ pipeline = PIPELINE_PREFIX "de_be0-lcd0";
break;
case sunxi_monitor_vga:
#ifdef CONFIG_VIDEO_VGA
- pipeline = "de_be0-lcd0-tve0";
+ pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
#elif defined CONFIG_VIDEO_VGA_VIA_LCD
- pipeline = "de_be0-lcd0";
+ pipeline = PIPELINE_PREFIX "de_be0-lcd0";
#endif
break;
}
diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c
index 57cb007..b8f3431 100644
--- a/drivers/video/tegra.c
+++ b/drivers/video/tegra.c
@@ -149,14 +149,18 @@ static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config)
FDT_LCD_CACHE_WRITE_BACK_FLUSH);
/* These GPIOs are all optional */
- fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios",
- &config->backlight_en);
- fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios",
- &config->lvds_shutdown);
- fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios",
- &config->backlight_vdd);
- fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios",
- &config->panel_vdd);
+ gpio_request_by_name_nodev(blob, display_node,
+ "nvidia,backlight-enable-gpios", 0,
+ &config->backlight_en, GPIOD_IS_OUT);
+ gpio_request_by_name_nodev(blob, display_node,
+ "nvidia,lvds-shutdown-gpios", 0,
+ &config->lvds_shutdown, GPIOD_IS_OUT);
+ gpio_request_by_name_nodev(blob, display_node,
+ "nvidia,backlight-vdd-gpios", 0,
+ &config->backlight_vdd, GPIOD_IS_OUT);
+ gpio_request_by_name_nodev(blob, display_node,
+ "nvidia,panel-vdd-gpios", 0,
+ &config->panel_vdd, GPIOD_IS_OUT);
return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
config->panel_timings, FDT_LCD_TIMINGS);
@@ -196,36 +200,18 @@ static int handle_stage(const void *blob)
*/
funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
-
- fdtdec_setup_gpio(&config.panel_vdd);
- fdtdec_setup_gpio(&config.lvds_shutdown);
- fdtdec_setup_gpio(&config.backlight_vdd);
- fdtdec_setup_gpio(&config.backlight_en);
-
- /*
- * TODO: If fdt includes output flag we can omit this code
- * since fdtdec_setup_gpio will do it for us.
- */
- if (fdt_gpio_isvalid(&config.panel_vdd))
- gpio_direction_output(config.panel_vdd.gpio, 0);
- if (fdt_gpio_isvalid(&config.lvds_shutdown))
- gpio_direction_output(config.lvds_shutdown.gpio, 0);
- if (fdt_gpio_isvalid(&config.backlight_vdd))
- gpio_direction_output(config.backlight_vdd.gpio, 0);
- if (fdt_gpio_isvalid(&config.backlight_en))
- gpio_direction_output(config.backlight_en.gpio, 0);
break;
case STAGE_PANEL_VDD:
- if (fdt_gpio_isvalid(&config.panel_vdd))
- gpio_direction_output(config.panel_vdd.gpio, 1);
+ if (dm_gpio_is_valid(&config.panel_vdd))
+ dm_gpio_set_value(&config.panel_vdd, 1);
break;
case STAGE_LVDS:
- if (fdt_gpio_isvalid(&config.lvds_shutdown))
- gpio_set_value(config.lvds_shutdown.gpio, 1);
+ if (dm_gpio_is_valid(&config.lvds_shutdown))
+ dm_gpio_set_value(&config.lvds_shutdown, 1);
break;
case STAGE_BACKLIGHT_VDD:
- if (fdt_gpio_isvalid(&config.backlight_vdd))
- gpio_set_value(config.backlight_vdd.gpio, 1);
+ if (dm_gpio_is_valid(&config.backlight_vdd))
+ dm_gpio_set_value(&config.backlight_vdd, 1);
break;
case STAGE_PWM:
/* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
@@ -235,8 +221,8 @@ static int handle_stage(const void *blob)
pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
break;
case STAGE_BACKLIGHT_EN:
- if (fdt_gpio_isvalid(&config.backlight_en))
- gpio_set_value(config.backlight_en.gpio, 1);
+ if (dm_gpio_is_valid(&config.backlight_en))
+ dm_gpio_set_value(&config.backlight_en, 1);
break;
case STAGE_DONE:
break;
diff --git a/drivers/video/vesa_fb.c b/drivers/video/vesa_fb.c
new file mode 100644
index 0000000..47f824a
--- /dev/null
+++ b/drivers/video/vesa_fb.c
@@ -0,0 +1,67 @@
+/*
+ *
+ * Vesa frame buffer driver for x86
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <pci_rom.h>
+#include <video_fb.h>
+#include <vbe.h>
+
+/*
+ * The Graphic Device
+ */
+GraphicDevice ctfb;
+
+/* Devices to allow - only the last one works fully */
+struct pci_device_id vesa_video_ids[] = {
+ { .vendor = 0x102b, .device = 0x0525 },
+ { .vendor = 0x1002, .device = 0x5159 },
+ { .vendor = 0x1002, .device = 0x4752 },
+ { .vendor = 0x1002, .device = 0x5452 },
+ { .vendor = 0x8086, .device = 0x0f31 },
+ {},
+};
+
+void *video_hw_init(void)
+{
+ GraphicDevice *gdev = &ctfb;
+ int bits_per_pixel;
+ pci_dev_t dev;
+ int ret;
+
+ printf("Video: ");
+ if (vbe_get_video_info(gdev)) {
+ /* TODO: Should we look these up by class? */
+ dev = pci_find_devices(vesa_video_ids, 0);
+ if (dev == -1) {
+ printf("no card detected\n");
+ return NULL;
+ }
+ bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "vesa display");
+ ret = pci_run_vga_bios(dev, NULL, PCI_ROM_USE_NATIVE |
+ PCI_ROM_ALLOW_FALLBACK);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD);
+ if (ret) {
+ printf("failed to run video BIOS: %d\n", ret);
+ return NULL;
+ }
+ }
+
+ if (vbe_get_video_info(gdev)) {
+ printf("No video mode configured\n");
+ return NULL;
+ }
+
+ bits_per_pixel = gdev->gdfBytesPP * 8;
+ sprintf(gdev->modeIdent, "%dx%dx%d", gdev->winSizeX, gdev->winSizeY,
+ bits_per_pixel);
+ printf("%s\n", gdev->modeIdent);
+ debug("Frame buffer at %x\n", gdev->pciBase);
+
+ return (void *)gdev;
+}
diff --git a/drivers/video/x86_fb.c b/drivers/video/x86_fb.c
deleted file mode 100644
index 6641033..0000000
--- a/drivers/video/x86_fb.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- * Vesa frame buffer driver for x86
- *
- * Copyright (C) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <video_fb.h>
-#include <vbe.h>
-#include "videomodes.h"
-
-/*
- * The Graphic Device
- */
-GraphicDevice ctfb;
-
-void *video_hw_init(void)
-{
- GraphicDevice *gdev = &ctfb;
- int bits_per_pixel;
-
- printf("Video: ");
- if (vbe_get_video_info(gdev)) {
- printf("No video mode configured\n");
- return NULL;
- }
-
- bits_per_pixel = gdev->gdfBytesPP * 8;
- sprintf(gdev->modeIdent, "%dx%dx%d", gdev->winSizeX, gdev->winSizeY,
- bits_per_pixel);
- printf("%s\n", gdev->modeIdent);
- debug("Frame buffer at %x\n", gdev->frameAdrs);
-
- return (void *)gdev;
-}
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index ffd49a2..03c786c 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -30,7 +30,11 @@
#define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
/* Hardware timeout in seconds */
+#if !defined(CONFIG_AT91_HW_WDT_TIMEOUT)
#define WDT_HW_TIMEOUT 2
+#else
+#define WDT_HW_TIMEOUT CONFIG_AT91_HW_WDT_TIMEOUT
+#endif
/*
* Set the watchdog time interval in 1/256Hz (write-once)