summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/bios_emulator/Makefile2
-rw-r--r--drivers/bios_emulator/atibios.c198
-rw-r--r--drivers/bios_emulator/besys.c102
-rw-r--r--drivers/bios_emulator/bios.c6
-rw-r--r--drivers/bios_emulator/biosemui.h2
-rw-r--r--drivers/bios_emulator/include/biosemu.h53
-rw-r--r--drivers/bios_emulator/include/x86emu.h7
-rw-r--r--drivers/bios_emulator/include/x86emu/debug.h20
-rw-r--r--drivers/bios_emulator/include/x86emu/regs.h2
-rw-r--r--drivers/bios_emulator/x86emu/debug.c10
-rw-r--r--drivers/bios_emulator/x86emu/decode.c24
-rw-r--r--drivers/bios_emulator/x86emu/ops.c58
-rw-r--r--drivers/bios_emulator/x86emu/ops2.c4
-rw-r--r--drivers/bios_emulator/x86emu/sys.c5
-rw-r--r--drivers/block/ahci.c52
-rw-r--r--drivers/block/ata_piix.c5
-rw-r--r--drivers/block/dwc_ahsata.c23
-rw-r--r--drivers/block/fsl_sata.c5
-rw-r--r--drivers/block/pata_bfin.c5
-rw-r--r--drivers/block/pata_bfin.h1
-rw-r--r--drivers/block/sata_dwc.c5
-rw-r--r--drivers/block/sata_sil.c7
-rw-r--r--drivers/block/sata_sil3114.c5
-rw-r--r--drivers/core/Makefile3
-rw-r--r--drivers/core/device-remove.c187
-rw-r--r--drivers/core/device.c184
-rw-r--r--drivers/core/lists.c50
-rw-r--r--drivers/core/root.c4
-rw-r--r--drivers/crypto/fsl/jr.c2
-rw-r--r--drivers/ddr/fsl/arm_ddr_gen3.c45
-rw-r--r--drivers/ddr/fsl/ctrl_regs.c74
-rw-r--r--drivers/ddr/fsl/ddr4_dimm_params.c22
-rw-r--r--drivers/ddr/fsl/fsl_ddr_gen4.c44
-rw-r--r--drivers/ddr/fsl/lc_common_dimm_params.c62
-rw-r--r--drivers/ddr/fsl/main.c3
-rw-r--r--drivers/ddr/fsl/mpc85xx_ddr_gen3.c67
-rw-r--r--drivers/dfu/dfu.c55
-rw-r--r--drivers/dfu/dfu_mmc.c8
-rw-r--r--drivers/dma/keystone_nav.c12
-rw-r--r--drivers/fpga/zynqpl.c10
-rw-r--r--drivers/gpio/at91_gpio.c241
-rw-r--r--drivers/gpio/gpio-uclass.c19
-rw-r--r--drivers/gpio/intel_ich6_gpio.c58
-rw-r--r--drivers/gpio/sunxi_gpio.c202
-rw-r--r--drivers/i2c/Makefile4
-rw-r--r--drivers/i2c/adi_i2c.c305
-rw-r--r--drivers/i2c/bfin-twi_i2c.c379
-rw-r--r--drivers/i2c/fsl_i2c.c4
-rw-r--r--drivers/i2c/i2c-emul-uclass.c14
-rw-r--r--drivers/i2c/i2c-uclass.c466
-rw-r--r--drivers/i2c/i2c_core.c16
-rw-r--r--drivers/i2c/mxc_i2c.c22
-rw-r--r--drivers/i2c/ppc4xx_i2c.c30
-rw-r--r--drivers/i2c/rcar_i2c.c4
-rw-r--r--drivers/i2c/sandbox_i2c.c111
-rw-r--r--drivers/i2c/tegra_i2c.c366
-rw-r--r--drivers/input/cros_ec_keyb.c16
-rw-r--r--drivers/misc/Makefile5
-rw-r--r--drivers/misc/cros_ec.c1
-rw-r--r--drivers/misc/cros_ec_spi.c2
-rw-r--r--drivers/misc/i2c_eeprom.c52
-rw-r--r--drivers/misc/i2c_eeprom_emul.c168
-rw-r--r--drivers/misc/mxc_ocotp.c6
-rw-r--r--drivers/misc/mxs_ocotp.c14
-rw-r--r--drivers/misc/smsc_lpc47m.c33
-rw-r--r--drivers/mmc/Makefile22
-rw-r--r--drivers/mmc/dw_mmc.c2
-rw-r--r--drivers/mmc/exynos_dw_mmc.c22
-rw-r--r--drivers/mmc/fsl_esdhc.c10
-rw-r--r--drivers/mmc/mmc.c92
-rw-r--r--drivers/mmc/mvebu_mmc.c103
-rw-r--r--drivers/mmc/omap_hsmmc.c16
-rw-r--r--drivers/mmc/pxa_mmc_gen.c6
-rw-r--r--drivers/mmc/sh_mmcif.c19
-rw-r--r--drivers/mmc/sh_mmcif.h8
-rw-r--r--drivers/mmc/sunxi_mmc.c134
-rw-r--r--drivers/mtd/cfi_mtd.c1
-rw-r--r--drivers/mtd/jedec_flash.c51
-rw-r--r--drivers/mtd/nand/Kconfig7
-rw-r--r--drivers/mtd/nand/atmel_nand.c115
-rw-r--r--drivers/mtd/nand/atmel_nand_ecc.h4
-rw-r--r--drivers/mtd/nand/denali.c132
-rw-r--r--drivers/mtd/nand/denali.h5
-rw-r--r--drivers/mtd/nand/denali_spl.c2
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c2
-rw-r--r--drivers/mtd/nand/fsl_ifc_spl.c10
-rw-r--r--drivers/mtd/nand/mxs_nand.c9
-rw-r--r--drivers/mtd/nand/nand_base.c15
-rw-r--r--drivers/mtd/nand/nand_util.c4
-rw-r--r--drivers/mtd/nand/omap_gpmc.c12
-rw-r--r--drivers/mtd/nand/s3c2410_nand.c38
-rw-r--r--drivers/mtd/nand/vf610_nfc.c3
-rw-r--r--drivers/mtd/spi/Makefile1
-rw-r--r--drivers/mtd/spi/ramtron.c404
-rw-r--r--drivers/mtd/spi/sandbox.c6
-rw-r--r--drivers/mtd/spi/sf_internal.h22
-rw-r--r--drivers/mtd/spi/sf_ops.c36
-rw-r--r--drivers/mtd/spi/sf_params.c105
-rw-r--r--drivers/mtd/spi/sf_probe.c9
-rw-r--r--drivers/net/fm/Makefile2
-rw-r--r--drivers/net/fm/b4860.c64
-rw-r--r--drivers/net/fm/eth.c23
-rw-r--r--drivers/net/fm/init.c19
-rw-r--r--drivers/net/fm/memac.c12
-rw-r--r--drivers/net/fm/memac_phy.c7
-rw-r--r--drivers/net/fm/t1024.c88
-rw-r--r--drivers/net/fm/t1040.c4
-rw-r--r--drivers/net/keystone_net.c7
-rw-r--r--drivers/net/macb.c17
-rw-r--r--drivers/net/mpc5xxx_fec.c5
-rw-r--r--drivers/net/netconsole.c2
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/cortina.c333
-rw-r--r--drivers/net/phy/marvell.c53
-rw-r--r--drivers/net/phy/phy.c3
-rw-r--r--drivers/net/phy/vitesse.c13
-rw-r--r--drivers/net/rtl8169.c127
-rw-r--r--drivers/net/sh_eth.c102
-rw-r--r--drivers/net/sh_eth.h14
-rw-r--r--drivers/net/smc911x.c1
-rw-r--r--drivers/net/uli526x.c2
-rw-r--r--drivers/pci/Makefile4
-rw-r--r--drivers/pci/pci.c58
-rw-r--r--drivers/pci/pci_auto.c2
-rw-r--r--drivers/pci/pci_rom.c281
-rw-r--r--drivers/pci/pci_tegra.c1144
-rw-r--r--drivers/pci/pcie_layerscape.c51
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/i82365.c989
-rw-r--r--drivers/pcmcia/mpc8xx_pcmcia.c6
-rw-r--r--drivers/pcmcia/tqm8xx_pcmcia.c51
-rw-r--r--drivers/power/Kconfig65
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/as3722.c264
-rw-r--r--drivers/power/axp209.c72
-rw-r--r--drivers/power/axp221.c391
-rw-r--r--drivers/power/palmas.c2
-rw-r--r--drivers/power/pmic/pmic_max77686.c52
-rw-r--r--drivers/power/power_i2c.c2
-rw-r--r--drivers/power/power_spi.c33
-rw-r--r--drivers/power/tps6586x.c27
-rw-r--r--drivers/power/twl4030.c24
-rw-r--r--drivers/qe/Makefile3
-rw-r--r--drivers/qe/fdt.c2
-rw-r--r--drivers/qe/qe.c151
-rw-r--r--drivers/qe/qe.h5
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/bfin_rtc.c2
-rw-r--r--drivers/rtc/ds12887.c217
-rw-r--r--drivers/rtc/mc146818.c43
-rw-r--r--drivers/rtc/mvrtc.h2
-rw-r--r--drivers/serial/Makefile3
-rw-r--r--drivers/serial/atmel_usart.c116
-rw-r--r--drivers/serial/ns16550.c40
-rw-r--r--drivers/serial/serial-uclass.c112
-rw-r--r--drivers/serial/serial.c140
-rw-r--r--drivers/serial/serial_dw.c (renamed from drivers/serial/serial_coreboot.c)15
-rw-r--r--drivers/serial/serial_pl01x.c49
-rw-r--r--drivers/serial/serial_sh.h12
-rw-r--r--drivers/serial/serial_tegra.c16
-rw-r--r--drivers/serial/serial_uniphier.c51
-rw-r--r--drivers/serial/serial_x86.c44
-rw-r--r--drivers/serial/usbtty.c2
-rw-r--r--drivers/spi/Makefile2
-rw-r--r--drivers/spi/altera_spi.c132
-rw-r--r--drivers/spi/atmel_spi.h4
-rw-r--r--drivers/spi/cadence_qspi.c345
-rw-r--r--drivers/spi/cadence_qspi.h76
-rw-r--r--drivers/spi/cadence_qspi_apb.c898
-rw-r--r--drivers/spi/designware_spi.c426
-rw-r--r--drivers/spi/fsl_espi.c4
-rw-r--r--drivers/spi/fsl_qspi.c428
-rw-r--r--drivers/spi/fsl_qspi.h15
-rw-r--r--drivers/spi/ftssp010_spi.c36
-rw-r--r--drivers/spi/ich.c29
-rw-r--r--drivers/spi/mxc_spi.c42
-rw-r--r--drivers/spi/spi-uclass.c36
-rw-r--r--drivers/spi/ti_qspi.c8
-rw-r--r--drivers/thermal/Makefile9
-rw-r--r--drivers/thermal/imx_thermal.c175
-rw-r--r--drivers/thermal/thermal-uclass.c30
-rw-r--r--drivers/tpm/tpm.c2
-rw-r--r--drivers/tpm/tpm_tis_i2c.c2
-rw-r--r--drivers/tpm/tpm_tis_lpc.c2
-rw-r--r--drivers/usb/Kconfig46
-rw-r--r--drivers/usb/eth/Makefile5
-rw-r--r--drivers/usb/eth/asix88179.c700
-rw-r--r--drivers/usb/eth/usb_ether.c7
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c1
-rw-r--r--drivers/usb/gadget/composite.c4
-rw-r--r--drivers/usb/gadget/designware_udc.c4
-rw-r--r--drivers/usb/gadget/ether.c24
-rw-r--r--drivers/usb/gadget/f_dfu.c2
-rw-r--r--drivers/usb/gadget/f_fastboot.c14
-rw-r--r--drivers/usb/gadget/f_thor.c16
-rw-r--r--drivers/usb/gadget/g_dnl.c17
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c3
-rw-r--r--drivers/usb/gadget/s3c_udc_otg.c79
-rw-r--r--drivers/usb/gadget/s3c_udc_otg_phy.c101
-rw-r--r--drivers/usb/gadget/s3c_udc_otg_xfer_dma.c6
-rw-r--r--drivers/usb/host/Kconfig56
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/dwc2.c14
-rw-r--r--drivers/usb/host/ehci-exynos.c55
-rw-r--r--drivers/usb/host/ehci-fsl.c191
-rw-r--r--drivers/usb/host/ehci-hcd.c59
-rw-r--r--drivers/usb/host/ehci-mx6.c27
-rw-r--r--drivers/usb/host/ehci-rmobile.c16
-rw-r--r--drivers/usb/host/ehci-sunxi.c177
-rw-r--r--drivers/usb/host/ehci-uniphier.c75
-rw-r--r--drivers/usb/host/ehci.h4
-rw-r--r--drivers/usb/host/isp116x-hcd.c6
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-s3c24xx.c3
-rw-r--r--drivers/usb/host/r8a66597-hcd.c3
-rw-r--r--drivers/usb/host/xhci-ring.c2
-rw-r--r--drivers/usb/host/xhci.c2
-rw-r--r--drivers/usb/musb/musb_hcd.h3
-rw-r--r--drivers/usb/phy/omap_usb_phy.c2
-rw-r--r--drivers/video/Kconfig8
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/ati_radeon_fb.c7
-rw-r--r--drivers/video/cfb_console.c27
-rw-r--r--drivers/video/mpc8xx_lcd.c53
-rw-r--r--drivers/video/smiLynxEM.c3
-rw-r--r--drivers/video/sunxi_display.c1074
-rw-r--r--drivers/video/videomodes.c201
-rw-r--r--drivers/video/videomodes.h22
-rw-r--r--drivers/video/x86_fb.c38
231 files changed, 12425 insertions, 4288 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 33227c8bd6..5ef58c051e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -16,8 +16,10 @@ obj-y += twserial/
obj-y += video/
obj-y += watchdog/
obj-$(CONFIG_QE) += qe/
+obj-$(CONFIG_U_QE) += qe/
obj-y += memory/
obj-y += pwm/
obj-y += input/
# SOC specific infrastructure drivers.
obj-y += soc/
+obj-y += thermal/
diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile
index e56356ee86..2ba43ac731 100644
--- a/drivers/bios_emulator/Makefile
+++ b/drivers/bios_emulator/Makefile
@@ -9,4 +9,4 @@ obj-y = atibios.o biosemu.o besys.o bios.o \
$(X86DIR)/debug.o
ccflags-y := -I$(srctree)/$(src) -I$(srctree)/$(src)/include \
- -D__PPC__ -D__BIG_ENDIAN__
+ $(if $(CONFIG_PPC),-D__PPC__ -D__BIG_ENDIAN__)
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
index 3b2ed6e109..93b815ccb4 100644
--- a/drivers/bios_emulator/atibios.c
+++ b/drivers/bios_emulator/atibios.c
@@ -46,8 +46,11 @@
* BIOS in u-boot.
****************************************************************************/
#include <common.h>
-#include "biosemui.h"
+#include <bios_emul.h>
+#include <errno.h>
#include <malloc.h>
+#include <vbe.h>
+#include "biosemui.h"
/* Length of the BIOS image */
#define MAX_BIOSLEN (128 * 1024L)
@@ -59,17 +62,54 @@ 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)
+{
+ 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;
+ BE_int86(0x10, regs, regs);
+
+ 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;
+ 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);
+ memcpy(mode_info->mode_info_block, buffer,
+ sizeof(struct vbe_mode_info));
+ mode_info->valid = true;
+
+ 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);
+}
+
/****************************************************************************
PARAMETERS:
pcidev - PCI device info for the video card on the bus to boot
-VGAInfo - BIOS emulator VGA info structure
+vga_info - BIOS emulator VGA info structure
REMARKS:
This function executes the BIOS POST code on the controller. We assume that
at this stage the controller has its I/O and memory space enabled and
that all other controllers are in a disabled state.
****************************************************************************/
-static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
+static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo *vga_info,
+ int vesa_mode, struct vbe_mode_info *mode_info)
{
RMREGS regs;
RMSREGS sregs;
@@ -84,13 +124,16 @@ static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev);
/*Setup the X86 emulator for the VGA BIOS*/
- BE_setVGA(VGAInfo);
+ BE_setVGA(vga_info);
/*Execute the BIOS POST code*/
BE_callRealMode(0xC000, 0x0003, &regs, &sregs);
/*Cleanup and exit*/
- BE_getVGA(VGAInfo);
+ BE_getVGA(vga_info);
+
+ if (vesa_mode != -1)
+ atibios_set_vesa_mode(&regs, vesa_mode, mode_info);
}
/****************************************************************************
@@ -244,60 +287,61 @@ REMARKS:
Loads and POST's the display controllers BIOS, directly from the BIOS
image we can extract over the PCI bus.
****************************************************************************/
-static int PCI_postController(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
+static int PCI_postController(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
+ BE_VGAInfo *vga_info, int vesa_mode,
+ struct vbe_mode_info *mode_info)
{
- u32 BIOSImageLen;
- uchar *mappedBIOS;
- uchar *copyOfBIOS;
-
- /*Allocate memory to store copy of BIOS from display controller*/
- if ((mappedBIOS = PCI_mapBIOSImage(pcidev)) == NULL) {
- printf("videoboot: Video ROM failed to map!\n");
- return false;
- }
+ u32 bios_image_len;
+ uchar *mapped_bios;
+ uchar *copy_of_bios;
+
+ if (bios_rom) {
+ copy_of_bios = bios_rom;
+ bios_image_len = bios_len;
+ } else {
+ /*
+ * Allocate memory to store copy of BIOS from display
+ * controller
+ */
+ mapped_bios = PCI_mapBIOSImage(pcidev);
+ if (mapped_bios == NULL) {
+ printf("videoboot: Video ROM failed to map!\n");
+ return false;
+ }
- BIOSImageLen = mappedBIOS[2] * 512;
+ bios_image_len = mapped_bios[2] * 512;
- if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL) {
- printf("videoboot: Out of memory!\n");
- return false;
+ copy_of_bios = malloc(bios_image_len);
+ if (copy_of_bios == NULL) {
+ printf("videoboot: Out of memory!\n");
+ return false;
+ }
+ memcpy(copy_of_bios, mapped_bios, bios_image_len);
+ PCI_unmapBIOSImage(pcidev, mapped_bios);
}
- memcpy(copyOfBIOS, mappedBIOS, BIOSImageLen);
- PCI_unmapBIOSImage(pcidev, mappedBIOS);
-
- /*Save information in VGAInfo structure*/
- VGAInfo->function = PCI_FUNC(pcidev);
- VGAInfo->device = PCI_DEV(pcidev);
- VGAInfo->bus = PCI_BUS(pcidev);
- VGAInfo->pcidev = pcidev;
- VGAInfo->BIOSImage = copyOfBIOS;
- VGAInfo->BIOSImageLen = BIOSImageLen;
+ /*Save information in vga_info structure*/
+ vga_info->function = PCI_FUNC(pcidev);
+ vga_info->device = PCI_DEV(pcidev);
+ vga_info->bus = PCI_BUS(pcidev);
+ vga_info->pcidev = pcidev;
+ vga_info->BIOSImage = copy_of_bios;
+ vga_info->BIOSImageLen = bios_image_len;
/*Now execute the BIOS POST for the device*/
- if (copyOfBIOS[0] != 0x55 || copyOfBIOS[1] != 0xAA) {
+ if (copy_of_bios[0] != 0x55 || copy_of_bios[1] != 0xAA) {
printf("videoboot: Video ROM image is invalid!\n");
return false;
}
- PCI_doBIOSPOST(pcidev, VGAInfo);
+ PCI_doBIOSPOST(pcidev, vga_info, vesa_mode, mode_info);
/*Reset the size of the BIOS image to the final size*/
- VGAInfo->BIOSImageLen = copyOfBIOS[2] * 512;
+ vga_info->BIOSImageLen = copy_of_bios[2] * 512;
return true;
}
-/****************************************************************************
-PARAMETERS:
-pcidev - PCI device info for the video card on the bus to boot
-pVGAInfo - Place to return VGA info structure is requested
-cleanUp - true to clean up on exit, false to leave emulator active
-
-REMARKS:
-Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
-and the X86 BIOS emulator module.
-****************************************************************************/
-int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp)
+int biosemu_setup(pci_dev_t pcidev, BE_VGAInfo **vga_infop)
{
BE_VGAInfo *VGAInfo;
@@ -307,28 +351,70 @@ int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp)
/*Initialise the x86 BIOS emulator*/
if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) {
printf("videoboot: Out of memory!\n");
- return false;
+ return -ENOMEM;
}
memset(VGAInfo, 0, sizeof(*VGAInfo));
BE_init(0, 65536, VGAInfo, 0);
+ *vga_infop = VGAInfo;
- /*Post all the display controller BIOS'es*/
- if (!PCI_postController(pcidev, VGAInfo))
- return false;
+ return 0;
+}
- /*Cleanup and exit the emulator if requested. If the BIOS emulator
- is needed after booting the card, we will not call BE_exit and
- leave it enabled for further use (ie: VESA driver etc).
+void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void))
+{
+ X86EMU_setupIntrFunc(intnum, (X86EMU_intrFuncs)int_func);
+}
+
+int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
+ BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
+ struct vbe_mode_info *mode_info)
+{
+ /*Post all the display controller BIOS'es*/
+ if (!PCI_postController(pcidev, bios_rom, bios_len, vga_info,
+ vesa_mode, mode_info))
+ return -EINVAL;
+
+ /*
+ * Cleanup and exit the emulator if requested. If the BIOS emulator
+ * is needed after booting the card, we will not call BE_exit and
+ * leave it enabled for further use (ie: VESA driver etc).
*/
- if (cleanUp) {
+ if (clean_up) {
BE_exit();
- if (VGAInfo->BIOSImage)
- free(VGAInfo->BIOSImage);
- free(VGAInfo);
- VGAInfo = NULL;
+ if (vga_info->BIOSImage)
+ free(vga_info->BIOSImage);
+ free(vga_info);
+ vga_info = NULL;
}
- /*Return VGA info pointer if the caller requested it*/
+
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+pcidev - PCI device info for the video card on the bus to boot
+pVGAInfo - Place to return VGA info structure is requested
+cleanUp - true to clean up on exit, false to leave emulator active
+
+REMARKS:
+Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
+and the X86 BIOS emulator module.
+****************************************************************************/
+int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int clean_up)
+{
+ BE_VGAInfo *VGAInfo;
+ int ret;
+
+ ret = biosemu_setup(pcidev, &VGAInfo);
+ if (ret)
+ return false;
+ ret = biosemu_run(pcidev, NULL, 0, VGAInfo, clean_up, -1, NULL);
+ if (ret)
+ return false;
+
+ /* Return VGA info pointer if the caller requested it*/
if (pVGAInfo)
*pVGAInfo = VGAInfo;
+
return true;
}
diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c
index ad88a53f0c..02c4286a85 100644
--- a/drivers/bios_emulator/besys.c
+++ b/drivers/bios_emulator/besys.c
@@ -48,18 +48,26 @@
****************************************************************************/
#define __io
-#include <asm/io.h>
#include <common.h>
+#include <asm/io.h>
#include "biosemui.h"
/*------------------------- Global Variables ------------------------------*/
-#ifndef __i386__
+#ifndef CONFIG_X86EMU_RAW_IO
static char *BE_biosDate = "08/14/99";
static u8 BE_model = 0xFC;
static u8 BE_submodel = 0x00;
#endif
+#undef DEBUG_IO_ACCESS
+
+#ifdef DEBUG_IO_ACCESS
+#define debug_io(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define debug_io(x, b...)
+#endif
+
/*----------------------------- Implementation ----------------------------*/
/****************************************************************************
@@ -80,38 +88,40 @@ static u8 *BE_memaddr(u32 addr)
if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
return (u8*)(_BE_env.biosmem_base + addr - 0xC0000);
} else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) {
- DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);)
- return M.mem_base;
+ DB(printf("BE_memaddr: address %#lx may be invalid!\n",
+ (ulong)addr);)
+ return (u8 *)M.mem_base;
} else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
}
-#ifdef __i386__
+#ifdef CONFIG_X86EMU_RAW_IO
else if (addr >= 0xD0000 && addr <= 0xFFFFF) {
/* We map the real System BIOS directly on real PC's */
- DB(printf("BE_memaddr: System BIOS address %#lx\n", addr);)
- return _BE_env.busmem_base + addr - 0xA0000;
+ DB(printf("BE_memaddr: System BIOS address %#lx\n",
+ (ulong)addr);)
+ return (u8 *)_BE_env.busmem_base + addr - 0xA0000;
}
#else
else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
/* Return a faked BIOS date string for non-x86 machines */
- DB(printf("BE_memaddr - Returning BIOS date\n");)
+ debug_io("BE_memaddr - Returning BIOS date\n");
return (u8 *)(BE_biosDate + addr - 0xFFFF5);
} else if (addr == 0xFFFFE) {
/* Return system model identifier for non-x86 machines */
- DB(printf("BE_memaddr - Returning model\n");)
+ debug_io("BE_memaddr - Returning model\n");
return &BE_model;
} else if (addr == 0xFFFFF) {
/* Return system submodel identifier for non-x86 machines */
- DB(printf("BE_memaddr - Returning submodel\n");)
+ debug_io("BE_memaddr - Returning submodel\n");
return &BE_submodel;
}
#endif
else if (addr > M.mem_size - 1) {
HALT_SYS();
- return M.mem_base;
+ return (u8 *)M.mem_base;
}
- return M.mem_base + addr;
+ return (u8 *)(M.mem_base + addr);
}
/****************************************************************************
@@ -230,7 +240,7 @@ void X86API BE_wrl(u32 addr, u32 val)
}
}
-#if defined(DEBUG) || !defined(__i386__)
+#if !defined(CONFIG_X86EMU_RAW_IO)
/* For Non-Intel machines we may need to emulate some I/O port accesses that
* the BIOS may try to access, such as the PCI config registers.
@@ -258,6 +268,7 @@ static u8 VGA_inpb (const int port)
{
u8 val = 0xff;
+ debug_io("vga_inb.%04X -> ", (u16) port);
switch (port) {
case 0x3C0:
/* 3C0 has funky characteristics because it can act as either
@@ -560,7 +571,7 @@ u8 X86API BE_inb(X86EMU_pioAddr port)
{
u8 val = 0;
-#if defined(DEBUG) || !defined(__i386__)
+#if !defined(CONFIG_X86EMU_RAW_IO)
if (IS_VGA_PORT(port)){
/*seems reading port 0x3c3 return the high 16 bit of io port*/
if(port == 0x3c3)
@@ -581,7 +592,12 @@ u8 X86API BE_inb(X86EMU_pioAddr port)
val = LOG_inpb(port);
} else
#endif
+ {
+ debug_io("inb.%04X -> ", (u16) port);
val = LOG_inpb(port);
+ debug_io("%02X\n", val);
+ }
+
return val;
}
@@ -601,7 +617,7 @@ u16 X86API BE_inw(X86EMU_pioAddr port)
{
u16 val = 0;
-#if defined(DEBUG) || !defined(__i386__)
+#if !defined(CONFIG_X86EMU_RAW_IO)
if (IS_PCI_PORT(port))
val = PCI_inp(port, REG_READ_WORD);
else if (port < 0x100) {
@@ -609,7 +625,12 @@ u16 X86API BE_inw(X86EMU_pioAddr port)
val = LOG_inpw(port);
} else
#endif
+ {
+ debug_io("inw.%04X -> ", (u16) port);
val = LOG_inpw(port);
+ debug_io("%04X\n", val);
+ }
+
return val;
}
@@ -629,14 +650,19 @@ u32 X86API BE_inl(X86EMU_pioAddr port)
{
u32 val = 0;
-#if defined(DEBUG) || !defined(__i386__)
+#if !defined(CONFIG_X86EMU_RAW_IO)
if (IS_PCI_PORT(port))
val = PCI_inp(port, REG_READ_DWORD);
else if (port < 0x100) {
val = LOG_inpd(port);
} else
#endif
+ {
+ debug_io("inl.%04X -> ", (u16) port);
val = LOG_inpd(port);
+ debug_io("%08X\n", val);
+ }
+
return val;
}
@@ -652,7 +678,7 @@ through to the real hardware if we don't need to special case it.
****************************************************************************/
void X86API BE_outb(X86EMU_pioAddr port, u8 val)
{
-#if defined(DEBUG) || !defined(__i386__)
+#if !defined(CONFIG_X86EMU_RAW_IO)
if (IS_VGA_PORT(port))
VGA_outpb(port, val);
else if (IS_TIMER_PORT(port))
@@ -668,7 +694,11 @@ void X86API BE_outb(X86EMU_pioAddr port, u8 val)
LOG_outpb(port, val);
} else
#endif
+ {
+ debug_io("outb.%04X <- %02X", (u16) port, val);
LOG_outpb(port, val);
+ debug_io("\n");
+ }
}
/****************************************************************************
@@ -683,19 +713,23 @@ through to the real hardware if we don't need to special case it.
****************************************************************************/
void X86API BE_outw(X86EMU_pioAddr port, u16 val)
{
-#if defined(DEBUG) || !defined(__i386__)
- if (IS_VGA_PORT(port)) {
- VGA_outpb(port, val);
- VGA_outpb(port + 1, val >> 8);
- } else if (IS_PCI_PORT(port))
- PCI_outp(port, val, REG_WRITE_WORD);
- else if (port < 0x100) {
- DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port,
- val);)
- LOG_outpw(port, val);
- } else
+#if !defined(CONFIG_X86EMU_RAW_IO)
+ if (IS_VGA_PORT(port)) {
+ VGA_outpb(port, val);
+ VGA_outpb(port + 1, val >> 8);
+ } else if (IS_PCI_PORT(port)) {
+ PCI_outp(port, val, REG_WRITE_WORD);
+ } else if (port < 0x100) {
+ DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16)port,
+ val);)
+ LOG_outpw(port, val);
+ } else
#endif
- LOG_outpw(port, val);
+ {
+ debug_io("outw.%04X <- %04X", (u16) port, val);
+ LOG_outpw(port, val);
+ debug_io("\n");
+ }
}
/****************************************************************************
@@ -710,13 +744,17 @@ through to the real hardware if we don't need to special case it.
****************************************************************************/
void X86API BE_outl(X86EMU_pioAddr port, u32 val)
{
-#if defined(DEBUG) || !defined(__i386__)
- if (IS_PCI_PORT(port))
+#if !defined(CONFIG_X86EMU_RAW_IO)
+ if (IS_PCI_PORT(port)) {
PCI_outp(port, val, REG_WRITE_DWORD);
- else if (port < 0x100) {
+ } else if (port < 0x100) {
DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
LOG_outpd(port, val);
} else
#endif
+ {
+ debug_io("outl.%04X <- %08X", (u16) port, val);
LOG_outpd(port, val);
+ debug_io("\n");
+ }
}
diff --git a/drivers/bios_emulator/bios.c b/drivers/bios_emulator/bios.c
index bcc192fb2e..dd4c0a4f32 100644
--- a/drivers/bios_emulator/bios.c
+++ b/drivers/bios_emulator/bios.c
@@ -42,8 +42,8 @@
****************************************************************************/
#define __io
-#include <asm/io.h>
#include <common.h>
+#include <asm/io.h>
#include "biosemui.h"
/*----------------------------- Implementation ----------------------------*/
@@ -84,14 +84,14 @@ static void X86API int42(int intno)
PM_outpb(0x3c2, PM_inpb(0x3cc) & (u8) ~ 0x02);
return;
}
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
else {
printf("int42: unknown function AH=0x12, BL=0x32, AL=%#02x\n",
M.x86.R_AL);
}
#endif
}
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
else {
printf("int42: unknown function AH=%#02x, AL=%#02x, BL=%#02x\n",
M.x86.R_AH, M.x86.R_AL, M.x86.R_BL);
diff --git a/drivers/bios_emulator/biosemui.h b/drivers/bios_emulator/biosemui.h
index 8c1f111fc8..7853015c1e 100644
--- a/drivers/bios_emulator/biosemui.h
+++ b/drivers/bios_emulator/biosemui.h
@@ -48,7 +48,7 @@
#include <asm/io.h>
/*---------------------- Macros and type definitions ----------------------*/
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
#define DB(x) x
#else
#define DB(x) do{}while(0);
diff --git a/drivers/bios_emulator/include/biosemu.h b/drivers/bios_emulator/include/biosemu.h
index e92e96e82b..124d79d80e 100644
--- a/drivers/bios_emulator/include/biosemu.h
+++ b/drivers/bios_emulator/include/biosemu.h
@@ -43,6 +43,8 @@
#ifndef __BIOSEMU_H
#define __BIOSEMU_H
+#include <bios_emul.h>
+
#ifdef __KERNEL__
#include "x86emu.h"
#else
@@ -55,57 +57,6 @@
#pragma pack(1)
-#ifndef __KERNEL__
-/****************************************************************************
-REMARKS:
-Data structure used to describe the details specific to a particular VGA
-controller. This information is used to allow the VGA controller to be
-swapped on the fly within the BIOS emulator.
-
-HEADER:
-biosemu.h
-
-MEMBERS:
-pciInfo - PCI device information block for the controller
-BIOSImage - Pointer to a read/write copy of the BIOS image
-BIOSImageLen - Length of the BIOS image
-LowMem - Copy of key low memory areas
-****************************************************************************/
-typedef struct {
- PCIDeviceInfo *pciInfo;
- void *BIOSImage;
- ulong BIOSImageLen;
- uchar LowMem[1536];
-} BE_VGAInfo;
-#else
-/****************************************************************************
-REMARKS:
-Data structure used to describe the details for the BIOS emulator system
-environment as used by the X86 emulator library.
-
-HEADER:
-biosemu.h
-
-MEMBERS:
-vgaInfo - VGA BIOS information structure
-biosmem_base - Base of the BIOS image
-biosmem_limit - Limit of the BIOS image
-busmem_base - Base of the VGA bus memory
-****************************************************************************/
-typedef struct {
- int function;
- int device;
- int bus;
- u32 VendorID;
- u32 DeviceID;
- pci_dev_t pcidev;
- void *BIOSImage;
- u32 BIOSImageLen;
- u8 LowMem[1536];
-} BE_VGAInfo;
-
-#endif /* __KERNEL__ */
-
#define CRT_C 24 /* 24 CRT Controller Registers */
#define ATT_C 21 /* 21 Attribute Controller Registers */
#define GRA_C 9 /* 9 Graphics Controller Registers */
diff --git a/drivers/bios_emulator/include/x86emu.h b/drivers/bios_emulator/include/x86emu.h
index a70a76874b..b28cdc6b8c 100644
--- a/drivers/bios_emulator/include/x86emu.h
+++ b/drivers/bios_emulator/include/x86emu.h
@@ -53,9 +53,9 @@ typedef u16 X86EMU_pioAddr;
/*---------------------- Macros and type definitions ----------------------*/
-#if defined (CONFIG_ARM)
+#if defined(CONFIG_ARM)
#define GAS_LINE_COMMENT "@"
-#elif defined(CONFIG_MIPS) || defined(CONFIG_PPC)
+#elif defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_X86)
#define GAS_LINE_COMMENT "#"
#elif defined (CONFIG_SH)
#define GAS_LINE_COMMENT "!"
@@ -153,6 +153,7 @@ extern "C" { /* Use "C" linkage when in C++ mode */
void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs);
void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs);
void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]);
+ void X86EMU_setupIntrFunc(int intnum, X86EMU_intrFuncs func);
void X86EMU_prepareForInt(int num);
/* decode.c */
@@ -160,7 +161,7 @@ extern "C" { /* Use "C" linkage when in C++ mode */
void X86EMU_exec(void);
void X86EMU_halt_sys(void);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
#define HALT_SYS() \
printf("halt_sys: file %s, line %d\n", __FILE__, __LINE__), \
X86EMU_halt_sys()
diff --git a/drivers/bios_emulator/include/x86emu/debug.h b/drivers/bios_emulator/include/x86emu/debug.h
index 268c9d391e..304b2bf007 100644
--- a/drivers/bios_emulator/include/x86emu/debug.h
+++ b/drivers/bios_emulator/include/x86emu/debug.h
@@ -48,7 +48,7 @@
#define CHECK_MEM_ACCESS_F 0x4 /*using regular linear pointer */
#define CHECK_DATA_ACCESS_F 0x8 /*using segment:offset */
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
# define CHECK_IP_FETCH() (M.x86.check & CHECK_IP_FETCH_F)
# define CHECK_SP_ACCESS() (M.x86.check & CHECK_SP_ACCESS_F)
# define CHECK_MEM_ACCESS() (M.x86.check & CHECK_MEM_ACCESS_F)
@@ -60,7 +60,7 @@
# define CHECK_DATA_ACCESS()
#endif
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
# define DEBUG_INSTRUMENT() (M.x86.debug & DEBUG_INSTRUMENT_F)
# define DEBUG_DECODE() (M.x86.debug & DEBUG_DECODE_F)
# define DEBUG_TRACE() (M.x86.debug & DEBUG_TRACE_F)
@@ -99,7 +99,11 @@
# define DEBUG_DECODE_NOPRINT() 0
#endif
-#ifdef DEBUG
+# define ERR_PRINTF(x) printf(x)
+# define ERR_PRINTF2(x, y) printf(x, y)
+
+#ifdef CONFIG_X86EMU_DEBUG103
+
# define DECODE_PRINTF(x) if (DEBUG_DECODE()) \
x86emu_decode_printf(x)
@@ -129,7 +133,7 @@
# define SAVE_IP_CS(x,y)
#endif
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
#define TRACE_REGS() \
if (DEBUG_DISASSEMBLE()) { \
x86emu_just_disassemble(); \
@@ -140,7 +144,7 @@
# define TRACE_REGS()
#endif
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
# define SINGLE_STEP() if (DEBUG_STEP()) x86emu_single_step()
#else
# define SINGLE_STEP()
@@ -150,7 +154,7 @@
TRACE_REGS(); \
SINGLE_STEP()
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
# define START_OF_INSTR()
# define END_OF_INSTR() EndOfTheInstructionProcedure: x86emu_end_instr();
# define END_OF_INSTR_NO_TRACE() x86emu_end_instr();
@@ -160,7 +164,7 @@
# define END_OF_INSTR_NO_TRACE()
#endif
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
# define CALL_TRACE(u,v,w,x,s) \
if (DEBUG_TRACECALLREGS()) \
x86emu_dump_regs(); \
@@ -176,7 +180,7 @@
# define RETURN_TRACE(n,u,v)
#endif
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
#define DB(x) x
#else
#define DB(x)
diff --git a/drivers/bios_emulator/include/x86emu/regs.h b/drivers/bios_emulator/include/x86emu/regs.h
index a7fedd2f6c..29341297d9 100644
--- a/drivers/bios_emulator/include/x86emu/regs.h
+++ b/drivers/bios_emulator/include/x86emu/regs.h
@@ -282,7 +282,7 @@ typedef struct {
u8 intno;
volatile int intr; /* mask of pending interrupts */
int debug;
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
int check;
u16 saved_ip;
u16 saved_cs;
diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c
index 2fa8050f6a..27e90e441a 100644
--- a/drivers/bios_emulator/x86emu/debug.c
+++ b/drivers/bios_emulator/x86emu/debug.c
@@ -44,7 +44,7 @@
/*----------------------------- Implementation ----------------------------*/
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
static void print_encoded_bytes(u16 s, u16 o);
static void print_decoded_instruction(void);
@@ -211,9 +211,7 @@ void X86EMU_dump_memory(u16 seg, u16 off, u32 amt)
u32 start = off & 0xfffffff0;
u32 end = (off + 16) & 0xfffffff0;
u32 i;
- u32 current;
- current = start;
while (end <= off + amt) {
printk("%04x:%04x ", seg, start);
for (i = start; i < off; i++)
@@ -229,7 +227,7 @@ void X86EMU_dump_memory(u16 seg, u16 off, u32 amt)
void x86emu_single_step(void)
{
char s[1024];
- int ps[10];
+ int ps[10];
int ntok;
int cmd;
int done;
@@ -238,8 +236,6 @@ void x86emu_single_step(void)
static int breakpoint;
static int noDecode = 1;
- char *p;
-
if (DEBUG_BREAK()) {
if (M.x86.saved_ip != breakpoint) {
return;
@@ -255,6 +251,8 @@ void x86emu_single_step(void)
offset = M.x86.saved_ip;
while (!done) {
printk("-");
+ ps[1] = 0; /* Avoid dodgy compiler warnings */
+ ps[2] = 0;
cmd = x86emu_parse_line(s, ps, &ntok);
switch (cmd) {
case 'u':
diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c
index a782b817b7..da44c3d8d9 100644
--- a/drivers/bios_emulator/x86emu/decode.c
+++ b/drivers/bios_emulator/x86emu/decode.c
@@ -303,7 +303,7 @@ NOTE: Do not inline this function as (*sys_rdX) is already inline!
u8 fetch_data_byte(
uint offset)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access((u16)get_data_segment(), offset);
#endif
@@ -322,7 +322,7 @@ NOTE: Do not inline this function as (*sys_rdX) is already inline!
u16 fetch_data_word(
uint offset)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access((u16)get_data_segment(), offset);
#endif
@@ -341,7 +341,7 @@ NOTE: Do not inline this function as (*sys_rdX) is already inline!
u32 fetch_data_long(
uint offset)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access((u16)get_data_segment(), offset);
#endif
@@ -362,7 +362,7 @@ u8 fetch_data_byte_abs(
uint segment,
uint offset)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access(segment, offset);
#endif
@@ -383,7 +383,7 @@ u16 fetch_data_word_abs(
uint segment,
uint offset)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access(segment, offset);
#endif
@@ -404,7 +404,7 @@ u32 fetch_data_long_abs(
uint segment,
uint offset)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access(segment, offset);
#endif
@@ -426,7 +426,7 @@ void store_data_byte(
uint offset,
u8 val)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access((u16)get_data_segment(), offset);
#endif
@@ -448,7 +448,7 @@ void store_data_word(
uint offset,
u16 val)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access((u16)get_data_segment(), offset);
#endif
@@ -470,7 +470,7 @@ void store_data_long(
uint offset,
u32 val)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access((u16)get_data_segment(), offset);
#endif
@@ -493,7 +493,7 @@ void store_data_byte_abs(
uint offset,
u8 val)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access(segment, offset);
#endif
@@ -516,7 +516,7 @@ void store_data_word_abs(
uint offset,
u16 val)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access(segment, offset);
#endif
@@ -539,7 +539,7 @@ void store_data_long_abs(
uint offset,
u32 val)
{
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (CHECK_DATA_ACCESS())
x86emu_check_data_access(segment, offset);
#endif
diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c
index f8e093d751..2bb5e2d9d5 100644
--- a/drivers/bios_emulator/x86emu/ops.c
+++ b/drivers/bios_emulator/x86emu/ops.c
@@ -79,7 +79,7 @@
/* constant arrays to do several instructions in just one function */
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
static char *x86emu_GenOpName[8] = {
"ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP"};
#endif
@@ -160,7 +160,7 @@ static u32 (*opcD1_long_operation[])(u32 s, u8 d) =
sar_long,
};
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
static char *opF6_names[8] =
{ "TEST\t", "", "NOT\t", "NEG\t", "MUL\t", "IMUL\t", "DIV\t", "IDIV\t" };
@@ -179,7 +179,7 @@ void x86emuOp_illegal_op(
{
START_OF_INSTR();
if (M.x86.R_SP != 0) {
- DECODE_PRINTF("ILLEGAL X86 OPCODE\n");
+ ERR_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));
@@ -1281,7 +1281,7 @@ void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -1359,7 +1359,7 @@ void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -1475,7 +1475,7 @@ void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -1551,7 +1551,7 @@ void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -2148,7 +2148,7 @@ void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1))
DECODE_PRINTF("POP\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (rh != 0) {
- DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
+ ERR_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
HALT_SYS();
}
if (mod < 3) {
@@ -3083,7 +3083,7 @@ void x86emuOp_opcC0_byte_RM_MEM(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -3158,7 +3158,7 @@ void x86emuOp_opcC1_word_RM_MEM(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -3347,7 +3347,7 @@ void x86emuOp_mov_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (rh != 0) {
- DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\n");
+ ERR_PRINTF("ILLEGAL DECODE OF OPCODE c6\n");
HALT_SYS();
}
if (mod < 3) {
@@ -3381,7 +3381,7 @@ void x86emuOp_mov_word_RM_IMM(u8 X86EMU_UNUSED(op1))
DECODE_PRINTF("MOV\t");
FETCH_DECODE_MODRM(mod, rh, rl);
if (rh != 0) {
- DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
+ ERR_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
HALT_SYS();
}
if (mod < 3) {
@@ -3630,7 +3630,7 @@ void x86emuOp_opcD0_byte_RM_1(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -3701,7 +3701,7 @@ void x86emuOp_opcD1_word_RM_1(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -3803,7 +3803,7 @@ void x86emuOp_opcD2_byte_RM_CL(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -3876,7 +3876,7 @@ void x86emuOp_opcD3_word_RM_CL(u8 X86EMU_UNUSED(op1))
*/
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -3968,7 +3968,7 @@ void x86emuOp_aam(u8 X86EMU_UNUSED(op1))
DECODE_PRINTF("AAM\n");
a = fetch_byte_imm(); /* this is a stupid encoding. */
if (a != 10) {
- DECODE_PRINTF("ERROR DECODING AAM\n");
+ ERR_PRINTF("ERROR DECODING AAM\n");
TRACE_REGS();
HALT_SYS();
}
@@ -4443,7 +4443,7 @@ void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1))
test_byte(destval, srcval);
break;
case 1:
- DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+ ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
HALT_SYS();
break;
case 2:
@@ -4490,7 +4490,7 @@ void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1))
test_byte(*destreg, srcval);
break;
case 1:
- DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+ ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
HALT_SYS();
break;
case 2:
@@ -4559,7 +4559,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1))
test_long(destval, srcval);
break;
case 1:
- DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n");
+ ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n");
HALT_SYS();
break;
case 2:
@@ -4611,7 +4611,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1))
test_word(destval, srcval);
break;
case 1:
- DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n");
+ ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n");
HALT_SYS();
break;
case 2:
@@ -4666,7 +4666,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1))
test_long(*destreg, srcval);
break;
case 1:
- DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+ ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
HALT_SYS();
break;
case 2:
@@ -4715,7 +4715,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1))
test_word(*destreg, srcval);
break;
case 1:
- DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+ ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
HALT_SYS();
break;
case 2:
@@ -4859,7 +4859,7 @@ void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1))
/* Yet another special case instruction. */
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -4879,7 +4879,7 @@ void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1))
case 5:
case 6:
case 7:
- DECODE_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x \n", mod);
+ ERR_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x\n", mod);
HALT_SYS();
break;
}
@@ -4923,7 +4923,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1))
/* Yet another special case instruction. */
START_OF_INSTR();
FETCH_DECODE_MODRM(mod, rh, rl);
-#ifdef DEBUG
+#ifdef CONFIG_X86EMU_DEBUG
if (DEBUG_DECODE()) {
/* XXX DECODE_PRINTF may be changed to something more
general, so that it is important to leave the strings
@@ -4961,7 +4961,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1))
DECODE_PRINTF("PUSH\t");
break;
case 7:
- DECODE_PRINTF("ILLEGAL DECODING OF OPCODE FF\t");
+ ERR_PRINTF("ILLEGAL DECODING OF OPCODE FF\t");
HALT_SYS();
break;
}
@@ -5092,7 +5092,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1))
M.x86.R_IP = *destreg;
break;
case 3: /* jmp far ptr ... */
- DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n");
+ ERR_PRINTF("OPERATION UNDEFINED 0XFF\n");
TRACE_AND_STEP();
HALT_SYS();
break;
@@ -5104,7 +5104,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1))
M.x86.R_IP = (u16) (*destreg);
break;
case 5: /* jmp far ptr ... */
- DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n");
+ ERR_PRINTF("OPERATION UNDEFINED 0XFF\n");
TRACE_AND_STEP();
HALT_SYS();
break;
diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c
index 59dbb422dd..be4ef36443 100644
--- a/drivers/bios_emulator/x86emu/ops2.c
+++ b/drivers/bios_emulator/x86emu/ops2.c
@@ -58,7 +58,7 @@ void x86emuOp2_illegal_op(
u8 op2)
{
START_OF_INSTR();
- DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
+ ERR_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
TRACE_REGS();
printk("%04x:%04x: %02X ILLEGAL EXTENDED X86 OPCODE!\n",
M.x86.R_CS, M.x86.R_IP-2,op2);
@@ -1089,7 +1089,7 @@ void x86emuOp2_btX_I(u8 X86EMU_UNUSED(op2))
DECODE_PRINTF("BTC\t");
break;
default:
- DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
+ ERR_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
TRACE_REGS();
printk("%04x:%04x: %02X%02X ILLEGAL EXTENDED X86 OPCODE EXTENSION!\n",
M.x86.R_CS, M.x86.R_IP-3,op2, (mod<<6)|(rh<<3)|rl);
diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c
index 21f9730bec..0ba9c0c105 100644
--- a/drivers/bios_emulator/x86emu/sys.c
+++ b/drivers/bios_emulator/x86emu/sys.c
@@ -273,6 +273,11 @@ void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs)
sys_outl = funcs->outl;
}
+void X86EMU_setupIntrFunc(int intnum, X86EMU_intrFuncs func)
+{
+ _X86EMU_intrTab[intnum] = func;
+}
+
/****************************************************************************
PARAMETERS:
funcs - New interrupt vector table to make active
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index a93a8e1c04..37d2d2a28e 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -137,6 +137,33 @@ static void sunxi_dma_init(volatile u8 *port_mmio)
}
#endif
+int ahci_reset(u32 base)
+{
+ int i = 1000;
+ u32 host_ctl_reg = base + HOST_CTL;
+ u32 tmp = readl(host_ctl_reg); /* global controller reset */
+
+ if ((tmp & HOST_RESET) == 0)
+ writel_with_flush(tmp | HOST_RESET, host_ctl_reg);
+
+ /*
+ * reset must complete within 1 second, or
+ * the hardware should be considered fried.
+ */
+ do {
+ udelay(1000);
+ tmp = readl(host_ctl_reg);
+ i--;
+ } while ((i > 0) && (tmp & HOST_RESET));
+
+ if (i == 0) {
+ printf("controller reset failed (0x%x)\n", tmp);
+ return -1;
+ }
+
+ return 0;
+}
+
static int ahci_host_init(struct ahci_probe_ent *probe_ent)
{
#ifndef CONFIG_SCSI_AHCI_PLAT
@@ -156,23 +183,9 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
cap_save &= ((1 << 28) | (1 << 17));
cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */
- /* global controller reset */
- tmp = readl(mmio + HOST_CTL);
- if ((tmp & HOST_RESET) == 0)
- writel_with_flush(tmp | HOST_RESET, mmio + HOST_CTL);
-
- /* reset must complete within 1 second, or
- * the hardware should be considered fried.
- */
- i = 1000;
- do {
- udelay(1000);
- tmp = readl(mmio + HOST_CTL);
- if (!i--) {
- debug("controller reset failed (0x%x)\n", tmp);
- return -1;
- }
- } while (tmp & HOST_RESET);
+ ret = ahci_reset(probe_ent->mmio_base);
+ if (ret)
+ return ret;
writel_with_flush(HOST_AHCI_EN, mmio + HOST_CTL);
writel(cap_save, mmio + HOST_CAP);
@@ -730,7 +743,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
u16 now_blocks; /* number of blocks per iteration */
u32 transfer_size; /* number of bytes per iteration */
- now_blocks = min(MAX_SATA_BLOCKS_READ_WRITE, blocks);
+ now_blocks = min((u16)MAX_SATA_BLOCKS_READ_WRITE, blocks);
transfer_size = ATA_SECT_SIZE * now_blocks;
if (transfer_size > user_buffer_size) {
@@ -997,12 +1010,11 @@ static int ata_io_flush(u8 port)
}
-void scsi_bus_reset(void)
+__weak void scsi_bus_reset(void)
{
/*Not implement*/
}
-
void scsi_print_error(ccb * pccb)
{
/*The ahci error info can be read in the ahci driver*/
diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c
index 5cf91ade8d..30426842cc 100644
--- a/drivers/block/ata_piix.c
+++ b/drivers/block/ata_piix.c
@@ -192,6 +192,11 @@ int init_sata(int dev)
return 0;
}
+int reset_sata(int dev)
+{
+ return 0;
+}
+
static inline u8 sata_inb(unsigned long ioaddr)
{
return inb(ioaddr);
diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c
index c68fd2f256..01a4148a52 100644
--- a/drivers/block/dwc_ahsata.c
+++ b/drivers/block/dwc_ahsata.c
@@ -592,6 +592,29 @@ int init_sata(int dev)
return 0;
}
+int reset_sata(int dev)
+{
+ struct ahci_probe_ent *probe_ent;
+ struct sata_host_regs *host_mmio;
+
+ if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
+ printf("The sata index %d is out of ranges\n\r", dev);
+ return -1;
+ }
+
+ probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv;
+ if (NULL == probe_ent)
+ /* not initialized, so nothing to reset */
+ return 0;
+
+ host_mmio = (struct sata_host_regs *)probe_ent->mmio_base;
+ setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR);
+ while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR)
+ udelay(100);
+
+ return 0;
+}
+
static void dwc_ahsata_print_info(int dev)
{
block_dev_desc_t *pdev = &(sata_dev_desc[dev]);
diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c
index ebd626178d..71d7cec7bd 100644
--- a/drivers/block/fsl_sata.c
+++ b/drivers/block/fsl_sata.c
@@ -255,6 +255,11 @@ int init_sata(int dev)
return 0;
}
+int reset_sata(int dev)
+{
+ return 0;
+}
+
static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg)
{
printf("\n\rSATA: %08x\n\r", (u32)reg);
diff --git a/drivers/block/pata_bfin.c b/drivers/block/pata_bfin.c
index b7fd1cd634..c2673bd05d 100644
--- a/drivers/block/pata_bfin.c
+++ b/drivers/block/pata_bfin.c
@@ -1009,6 +1009,11 @@ int init_sata(int dev)
return res;
}
+int reset_sata(int dev)
+{
+ return 0;
+}
+
/* Read up to 255 sectors
*
* Returns sectors read
diff --git a/drivers/block/pata_bfin.h b/drivers/block/pata_bfin.h
index 2093cf06b4..b678f60b2d 100644
--- a/drivers/block/pata_bfin.h
+++ b/drivers/block/pata_bfin.h
@@ -43,7 +43,6 @@ struct ata_port {
#define DRV_NAME "pata-bfin"
#define DRV_VERSION "0.9"
-#define __iomem
#define ATA_REG_CTRL 0x0E
#define ATA_REG_ALTSTATUS ATA_REG_CTRL
diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c
index efca5eaba4..9e8b067cdc 100644
--- a/drivers/block/sata_dwc.c
+++ b/drivers/block/sata_dwc.c
@@ -423,6 +423,11 @@ int init_sata(int dev)
return rc;
}
+int reset_sata(int dev)
+{
+ return 0;
+}
+
static u8 ata_check_altstatus(struct ata_port *ap)
{
u8 val = 0;
diff --git a/drivers/block/sata_sil.c b/drivers/block/sata_sil.c
index 1f510cd265..daff7d4ab5 100644
--- a/drivers/block/sata_sil.c
+++ b/drivers/block/sata_sil.c
@@ -519,7 +519,7 @@ int init_sata(int dev)
u16 word;
if (init_done == 1 && dev < sata_info.maxport)
- return 1;
+ return 0;
init_done = 1;
@@ -571,6 +571,11 @@ int init_sata(int dev)
return 0;
}
+int reset_sata(int dev)
+{
+ return 0;
+}
+
/*
* SATA interface between low level driver and command layer
*/
diff --git a/drivers/block/sata_sil3114.c b/drivers/block/sata_sil3114.c
index 3aa6fc9839..61ffb66a77 100644
--- a/drivers/block/sata_sil3114.c
+++ b/drivers/block/sata_sil3114.c
@@ -702,6 +702,11 @@ int init_sata (int dev)
return res;
}
+int reset_sata(int dev)
+{
+ return 0;
+}
+
/* Check if device is connected to port */
int sata_bus_probe (int portno)
{
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 151c2398a4..f14695b2d6 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -4,5 +4,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y := device.o lists.o root.o uclass.o util.o
+obj-$(CONFIG_DM) += device.o lists.o root.o uclass.o util.o
obj-$(CONFIG_OF_CONTROL) += simple-bus.o
+obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
new file mode 100644
index 0000000000..8fc6b71084
--- /dev/null
+++ b/drivers/core/device-remove.c
@@ -0,0 +1,187 @@
+/*
+ * Device manager
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+#include <dm/util.h>
+
+/**
+ * device_chld_unbind() - Unbind all device's children from the device
+ *
+ * On error, the function continues to unbind all children, and reports the
+ * first error.
+ *
+ * @dev: The device that is to be stripped of its children
+ * @return 0 on success, -ve on error
+ */
+static int device_chld_unbind(struct udevice *dev)
+{
+ struct udevice *pos, *n;
+ int ret, saved_ret = 0;
+
+ assert(dev);
+
+ list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+ ret = device_unbind(pos);
+ if (ret && !saved_ret)
+ saved_ret = ret;
+ }
+
+ return saved_ret;
+}
+
+/**
+ * device_chld_remove() - Stop all device's children
+ * @dev: The device whose children are to be removed
+ * @return 0 on success, -ve on error
+ */
+static int device_chld_remove(struct udevice *dev)
+{
+ struct udevice *pos, *n;
+ int ret;
+
+ assert(dev);
+
+ list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+ ret = device_remove(pos);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int device_unbind(struct udevice *dev)
+{
+ struct driver *drv;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (dev->flags & DM_FLAG_ACTIVATED)
+ return -EINVAL;
+
+ drv = dev->driver;
+ assert(drv);
+
+ if (drv->unbind) {
+ ret = drv->unbind(dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = device_chld_unbind(dev);
+ if (ret)
+ return ret;
+
+ ret = uclass_unbind_device(dev);
+ if (ret)
+ return ret;
+
+ if (dev->parent)
+ list_del(&dev->sibling_node);
+ free(dev);
+
+ return 0;
+}
+
+/**
+ * device_free() - Free memory buffers allocated by a device
+ * @dev: Device that is to be started
+ */
+void device_free(struct udevice *dev)
+{
+ int size;
+
+ if (dev->driver->priv_auto_alloc_size) {
+ 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);
+ dev->uclass_priv = NULL;
+ }
+ if (dev->parent) {
+ size = dev->parent->driver->per_child_auto_alloc_size;
+ if (size) {
+ free(dev->parent_priv);
+ dev->parent_priv = NULL;
+ }
+ }
+}
+
+int device_remove(struct udevice *dev)
+{
+ struct driver *drv;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!(dev->flags & DM_FLAG_ACTIVATED))
+ return 0;
+
+ drv = dev->driver;
+ assert(drv);
+
+ ret = uclass_pre_remove_device(dev);
+ if (ret)
+ return ret;
+
+ ret = device_chld_remove(dev);
+ if (ret)
+ goto err;
+
+ if (drv->remove) {
+ ret = drv->remove(dev);
+ if (ret)
+ goto err_remove;
+ }
+
+ if (dev->parent && dev->parent->driver->child_post_remove) {
+ ret = dev->parent->driver->child_post_remove(dev);
+ if (ret) {
+ dm_warn("%s: Device '%s' failed child_post_remove()",
+ __func__, dev->name);
+ }
+ }
+
+ device_free(dev);
+
+ dev->seq = -1;
+ dev->flags &= ~DM_FLAG_ACTIVATED;
+
+ return ret;
+
+err_remove:
+ /* We can't put the children back */
+ dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
+ __func__, dev->name);
+err:
+ ret = uclass_post_probe_device(dev);
+ if (ret) {
+ dm_warn("%s: Device '%s' failed to post_probe on error path\n",
+ __func__, dev->name);
+ }
+
+ return ret;
+}
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 49faa29dc1..963b16f26f 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -24,52 +24,6 @@
DECLARE_GLOBAL_DATA_PTR;
-/**
- * device_chld_unbind() - Unbind all device's children from the device
- *
- * On error, the function continues to unbind all children, and reports the
- * first error.
- *
- * @dev: The device that is to be stripped of its children
- * @return 0 on success, -ve on error
- */
-static int device_chld_unbind(struct udevice *dev)
-{
- struct udevice *pos, *n;
- int ret, saved_ret = 0;
-
- assert(dev);
-
- list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
- ret = device_unbind(pos);
- if (ret && !saved_ret)
- saved_ret = ret;
- }
-
- return saved_ret;
-}
-
-/**
- * device_chld_remove() - Stop all device's children
- * @dev: The device whose children are to be removed
- * @return 0 on success, -ve on error
- */
-static int device_chld_remove(struct udevice *dev)
-{
- struct udevice *pos, *n;
- int ret;
-
- assert(dev);
-
- list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
- ret = device_remove(pos);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
int device_bind(struct udevice *parent, struct driver *drv, const char *name,
void *platdata, int of_offset, struct udevice **devp)
{
@@ -167,71 +121,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
-1, devp);
}
-int device_unbind(struct udevice *dev)
-{
- struct driver *drv;
- int ret;
-
- if (!dev)
- return -EINVAL;
-
- if (dev->flags & DM_FLAG_ACTIVATED)
- return -EINVAL;
-
- drv = dev->driver;
- assert(drv);
-
- if (drv->unbind) {
- ret = drv->unbind(dev);
- if (ret)
- return ret;
- }
-
- ret = device_chld_unbind(dev);
- if (ret)
- return ret;
-
- ret = uclass_unbind_device(dev);
- if (ret)
- return ret;
-
- if (dev->parent)
- list_del(&dev->sibling_node);
- free(dev);
-
- return 0;
-}
-
-/**
- * device_free() - Free memory buffers allocated by a device
- * @dev: Device that is to be started
- */
-static void device_free(struct udevice *dev)
-{
- int size;
-
- if (dev->driver->priv_auto_alloc_size) {
- 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);
- dev->uclass_priv = NULL;
- }
- if (dev->parent) {
- size = dev->parent->driver->per_child_auto_alloc_size;
- if (size) {
- free(dev->parent_priv);
- dev->parent_priv = NULL;
- }
- }
-}
-
int device_probe_child(struct udevice *dev, void *parent_priv)
{
struct driver *drv;
@@ -342,67 +231,10 @@ int device_probe(struct udevice *dev)
return device_probe_child(dev, NULL);
}
-int device_remove(struct udevice *dev)
-{
- struct driver *drv;
- int ret;
-
- if (!dev)
- return -EINVAL;
-
- if (!(dev->flags & DM_FLAG_ACTIVATED))
- return 0;
-
- drv = dev->driver;
- assert(drv);
-
- ret = uclass_pre_remove_device(dev);
- if (ret)
- return ret;
-
- ret = device_chld_remove(dev);
- if (ret)
- goto err;
-
- if (drv->remove) {
- ret = drv->remove(dev);
- if (ret)
- goto err_remove;
- }
-
- if (dev->parent && dev->parent->driver->child_post_remove) {
- ret = dev->parent->driver->child_post_remove(dev);
- if (ret) {
- dm_warn("%s: Device '%s' failed child_post_remove()",
- __func__, dev->name);
- }
- }
-
- device_free(dev);
-
- dev->seq = -1;
- dev->flags &= ~DM_FLAG_ACTIVATED;
-
- return ret;
-
-err_remove:
- /* We can't put the children back */
- dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
- __func__, dev->name);
-err:
- ret = uclass_post_probe_device(dev);
- if (ret) {
- dm_warn("%s: Device '%s' failed to post_probe on error path\n",
- __func__, dev->name);
- }
-
- return ret;
-}
-
void *dev_get_platdata(struct udevice *dev)
{
if (!dev) {
- dm_warn("%s: null device", __func__);
+ dm_warn("%s: null device\n", __func__);
return NULL;
}
@@ -412,7 +244,7 @@ void *dev_get_platdata(struct udevice *dev)
void *dev_get_priv(struct udevice *dev)
{
if (!dev) {
- dm_warn("%s: null device", __func__);
+ dm_warn("%s: null device\n", __func__);
return NULL;
}
@@ -422,7 +254,7 @@ void *dev_get_priv(struct udevice *dev)
void *dev_get_parentdata(struct udevice *dev)
{
if (!dev) {
- dm_warn("%s: null device", __func__);
+ dm_warn("%s: null device\n", __func__);
return NULL;
}
@@ -548,3 +380,13 @@ int device_find_next_child(struct udevice **devp)
return 0;
}
+
+struct udevice *dev_get_parent(struct udevice *child)
+{
+ return child->parent;
+}
+
+ulong dev_get_of_data(struct udevice *dev)
+{
+ return dev->of_id->data;
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 3a1ea85654..ff115c4723 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -25,9 +25,6 @@ struct driver *lists_driver_lookup_name(const char *name)
const int n_ents = ll_entry_count(struct driver, driver);
struct driver *entry;
- if (!drv || !n_ents)
- return NULL;
-
for (entry = drv; entry != drv + n_ents; entry++) {
if (!strcmp(name, entry->name))
return entry;
@@ -44,9 +41,6 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
const int n_ents = ll_entry_count(struct uclass_driver, uclass);
struct uclass_driver *entry;
- if ((id == UCLASS_INVALID) || !uclass)
- return NULL;
-
for (entry = uclass; entry != uclass + n_ents; entry++) {
if (entry->id == id)
return entry;
@@ -77,34 +71,60 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
return result;
}
+int device_bind_driver(struct udevice *parent, const char *drv_name,
+ const char *dev_name, struct udevice **devp)
+{
+ struct driver *drv;
+ int ret;
+
+ drv = lists_driver_lookup_name(drv_name);
+ if (!drv) {
+ printf("Cannot find driver '%s'\n", drv_name);
+ return -ENOENT;
+ }
+ ret = device_bind(parent, drv, dev_name, NULL, -1, devp);
+ if (ret) {
+ printf("Cannot create device named '%s' (err=%d)\n",
+ dev_name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_OF_CONTROL
/**
* driver_check_compatible() - Check if a driver is compatible with this node
*
* @param blob: Device tree pointer
* @param offset: Offset of node in device tree
- * @param of_matchL List of compatible strings to match
+ * @param of_match: List of compatible strings to match
+ * @param of_idp: Returns the match that was found
* @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node
* does not have a compatible string, other error <0 if there is a device
* tree error
*/
static int driver_check_compatible(const void *blob, int offset,
- const struct udevice_id *of_match)
+ const struct udevice_id *of_match,
+ const struct udevice_id **of_idp)
{
int ret;
+ *of_idp = NULL;
if (!of_match)
return -ENOENT;
while (of_match->compatible) {
ret = fdt_node_check_compatible(blob, offset,
of_match->compatible);
- if (!ret)
+ if (!ret) {
+ *of_idp = of_match;
return 0;
- else if (ret == -FDT_ERR_NOTFOUND)
+ } else if (ret == -FDT_ERR_NOTFOUND) {
return -ENODEV;
- else if (ret < 0)
+ } else if (ret < 0) {
return -EINVAL;
+ }
of_match++;
}
@@ -116,6 +136,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
{
struct driver *driver = ll_entry_start(struct driver, driver);
const int n_ents = ll_entry_count(struct driver, driver);
+ const struct udevice_id *id;
struct driver *entry;
struct udevice *dev;
bool found = false;
@@ -127,7 +148,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
if (devp)
*devp = NULL;
for (entry = driver; entry != driver + n_ents; entry++) {
- ret = driver_check_compatible(blob, offset, entry->of_match);
+ ret = driver_check_compatible(blob, offset, entry->of_match,
+ &id);
name = fdt_get_name(blob, offset, NULL);
if (ret == -ENOENT) {
continue;
@@ -136,8 +158,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
break;
} else if (ret) {
dm_warn("Device tree error at offset %d\n", offset);
- if (!result || ret != -ENOENT)
- result = ret;
+ result = ret;
break;
}
@@ -147,6 +168,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
dm_warn("Error binding driver '%s'\n", entry->name);
return ret;
} else {
+ dev->of_id = id;
found = true;
if (devp)
*devp = dev;
diff --git a/drivers/core/root.c b/drivers/core/root.c
index a328a4876f..47b3acfbe9 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -73,10 +73,8 @@ int dm_scan_platdata(bool pre_reloc_only)
dm_warn("Some drivers were not found\n");
ret = 0;
}
- if (ret)
- return ret;
- return 0;
+ return ret;
}
#ifdef CONFIG_OF_CONTROL
diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c
index 29681e18a6..f9d4938834 100644
--- a/drivers/crypto/fsl/jr.c
+++ b/drivers/crypto/fsl/jr.c
@@ -246,7 +246,7 @@ int run_descriptor_jr(uint32_t *desc)
struct result op;
int ret = 0;
- memset(&op, sizeof(op), 0);
+ memset(&op, 0, sizeof(op));
ret = jr_enqueue(desc, desc_done, &op);
if (ret) {
diff --git a/drivers/ddr/fsl/arm_ddr_gen3.c b/drivers/ddr/fsl/arm_ddr_gen3.c
index 59f2fd6610..c139da6da9 100644
--- a/drivers/ddr/fsl/arm_ddr_gen3.c
+++ b/drivers/ddr/fsl/arm_ddr_gen3.c
@@ -92,7 +92,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->timing_cfg_0, regs->timing_cfg_0);
ddr_out32(&ddr->timing_cfg_1, regs->timing_cfg_1);
ddr_out32(&ddr->timing_cfg_2, regs->timing_cfg_2);
- ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
ddr_out32(&ddr->sdram_mode, regs->ddr_sdram_mode);
ddr_out32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
ddr_out32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
@@ -105,9 +104,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->sdram_interval, regs->ddr_sdram_interval);
ddr_out32(&ddr->sdram_data_init, regs->ddr_data_init);
ddr_out32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
- ddr_out32(&ddr->init_addr, regs->ddr_init_addr);
- ddr_out32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
-
ddr_out32(&ddr->timing_cfg_4, regs->timing_cfg_4);
ddr_out32(&ddr->timing_cfg_5, regs->timing_cfg_5);
ddr_out32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
@@ -128,7 +124,24 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
ddr_out32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
ddr_out32(&ddr->ddr_cdr1, regs->ddr_cdr1);
- ddr_out32(&ddr->ddr_cdr2, regs->ddr_cdr2);
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ ddr_out32(&ddr->sdram_cfg_2,
+ regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
+ ddr_out32(&ddr->init_addr, CONFIG_SYS_SDRAM_BASE);
+ ddr_out32(&ddr->init_ext_addr, DDR_INIT_ADDR_EXT_UIA);
+
+ /* DRAM VRef will not be trained */
+ ddr_out32(&ddr->ddr_cdr2,
+ regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
+ } else
+#endif
+ {
+ ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ ddr_out32(&ddr->init_addr, regs->ddr_init_addr);
+ ddr_out32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+ ddr_out32(&ddr->ddr_cdr2, regs->ddr_cdr2);
+ }
ddr_out32(&ddr->err_disable, regs->err_disable);
ddr_out32(&ddr->err_int_en, regs->err_int_en);
for (i = 0; i < 32; i++) {
@@ -167,8 +180,20 @@ step2:
udelay(500);
asm volatile("dsb sy;isb");
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ /* enter self-refresh */
+ temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
+ temp_sdram_cfg |= SDRAM_CFG2_FRC_SR;
+ ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
+ /* do board specific memory setup */
+ board_mem_sleep_setup();
+
+ temp_sdram_cfg = (ddr_in32(&ddr->sdram_cfg) | SDRAM_CFG_BI);
+ } else
+#endif
+ temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
/* Let the controller go */
- temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
asm volatile("dsb sy;isb");
@@ -211,4 +236,12 @@ step2:
if (timeout <= 0)
printf("Waiting for D_INIT timeout. Memory may not work.\n");
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ /* exit self-refresh */
+ temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
+ temp_sdram_cfg &= ~SDRAM_CFG2_FRC_SR;
+ ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
+ }
+#endif
}
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index 9a156bfd5e..03d7ff17dd 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -253,22 +253,30 @@ static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr)
/* -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 */
#if !defined(CONFIG_SYS_FSL_DDR1)
+/*
+ * Check DIMM configuration, return 2 if quad-rank or two dual-rank
+ * Return 1 if other two slots configuration. Return 0 if single slot.
+ */
static inline int avoid_odt_overlap(const dimm_params_t *dimm_params)
{
#if CONFIG_DIMM_SLOTS_PER_CTLR == 1
if (dimm_params[0].n_ranks == 4)
- return 1;
+ return 2;
#endif
#if CONFIG_DIMM_SLOTS_PER_CTLR == 2
if ((dimm_params[0].n_ranks == 2) &&
(dimm_params[1].n_ranks == 2))
- return 1;
+ return 2;
#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
if (dimm_params[0].n_ranks == 4)
- return 1;
+ return 2;
#endif
+
+ if ((dimm_params[0].n_ranks != 0) &&
+ (dimm_params[2].n_ranks != 0))
+ return 1;
#endif
return 0;
}
@@ -303,7 +311,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
#ifdef CONFIG_SYS_FSL_DDR4
/* tXP=max(4nCK, 6ns) */
- int txp = max(mclk_ps * 4, 6000); /* unit=ps */
+ int txp = max((int)mclk_ps * 4, 6000); /* unit=ps */
trwt_mclk = 2;
twrt_mclk = 1;
act_pd_exit_mclk = picos_to_mclk(txp);
@@ -312,10 +320,12 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
* MRS_CYC = max(tMRD, tMOD)
* tMRD = 8nCK, tMOD = max(24nCK, 15ns)
*/
- tmrd_mclk = max(24, picos_to_mclk(15000));
+ tmrd_mclk = max(24U, picos_to_mclk(15000));
#elif defined(CONFIG_SYS_FSL_DDR3)
unsigned int data_rate = get_ddr_freq(0);
int txp;
+ unsigned int ip_rev;
+ int odt_overlap;
/*
* (tXARD and tXARDS). Empirical?
* The DDR3 spec has not tXARD,
@@ -325,19 +335,47 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
* spec has not the tAXPD, we use
* tAXPD=1, need design to confirm.
*/
- txp = max(mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000));
+ txp = max((int)mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000));
+
+ ip_rev = fsl_ddr_get_version();
+ if (ip_rev >= 0x40700) {
+ /*
+ * MRS_CYC = max(tMRD, tMOD)
+ * tMRD = 4nCK (8nCK for RDIMM)
+ * tMOD = max(12nCK, 15ns)
+ */
+ tmrd_mclk = max((unsigned int)12, picos_to_mclk(15000));
+ } else {
+ /*
+ * MRS_CYC = tMRD
+ * tMRD = 4nCK (8nCK for RDIMM)
+ */
+ if (popts->registered_dimm_en)
+ tmrd_mclk = 8;
+ else
+ tmrd_mclk = 4;
+ }
- tmrd_mclk = 4;
/* set the turnaround time */
/*
- * for single quad-rank DIMM and two dual-rank DIMMs
+ * for single quad-rank DIMM and two-slot DIMMs
* to avoid ODT overlap
*/
- if (avoid_odt_overlap(dimm_params)) {
+ odt_overlap = avoid_odt_overlap(dimm_params);
+ switch (odt_overlap) {
+ case 2:
twwt_mclk = 2;
trrt_mclk = 1;
+ break;
+ case 1:
+ twwt_mclk = 1;
+ trrt_mclk = 0;
+ break;
+ default:
+ break;
}
+
/* for faster clock, need more time for data setup */
trwt_mclk = (data_rate/1000000 > 1800) ? 2 : 1;
@@ -383,7 +421,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
);
debug("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0);
}
-#endif /* defined(CONFIG_SYS_FSL_DDR2) */
+#endif /* !defined(CONFIG_SYS_FSL_DDR1) */
/* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */
static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr,
@@ -511,8 +549,8 @@ static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
#ifdef CONFIG_SYS_FSL_DDR4
refrec_ctrl = picos_to_mclk(common_dimm->trfc1_ps) - 8;
wrrec_mclk = picos_to_mclk(common_dimm->twr_ps);
- acttoact_mclk = max(picos_to_mclk(common_dimm->trrds_ps), 4);
- wrtord_mclk = max(2, picos_to_mclk(2500));
+ acttoact_mclk = max(picos_to_mclk(common_dimm->trrds_ps), 4U);
+ wrtord_mclk = max(2U, picos_to_mclk(2500));
if ((wrrec_mclk < 1) || (wrrec_mclk > 24))
printf("Error: WRREC doesn't support %d clocks\n", wrrec_mclk);
else
@@ -627,14 +665,14 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
wr_data_delay = popts->write_data_delay;
#ifdef CONFIG_SYS_FSL_DDR4
cpo = 0;
- cke_pls = max(3, picos_to_mclk(5000));
+ cke_pls = max(3U, picos_to_mclk(5000));
#elif defined(CONFIG_SYS_FSL_DDR3)
/*
* cke pulse = max(3nCK, 7.5ns) for DDR3-800
* max(3nCK, 5.625ns) for DDR3-1066, 1333
* max(3nCK, 5ns) for DDR3-1600, 1866, 2133
*/
- cke_pls = max(3, picos_to_mclk(mclk_ps > 1870 ? 7500 :
+ cke_pls = max(3U, picos_to_mclk(mclk_ps > 1870 ? 7500 :
(mclk_ps > 1245 ? 5625 : 5000)));
#else
cke_pls = FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR;
@@ -1810,9 +1848,9 @@ static void set_timing_cfg_7(fsl_ddr_cfg_regs_t *ddr,
unsigned int txpr, tcksre, tcksrx;
unsigned int cke_rst, cksre, cksrx, par_lat, cs_to_cmd;
- txpr = max(5, picos_to_mclk(common_dimm->trfc1_ps + 10000));
- tcksre = max(5, picos_to_mclk(10000));
- tcksrx = max(5, picos_to_mclk(10000));
+ txpr = max(5U, picos_to_mclk(common_dimm->trfc1_ps + 10000));
+ tcksre = max(5U, picos_to_mclk(10000));
+ tcksrx = max(5U, picos_to_mclk(10000));
par_lat = 0;
cs_to_cmd = 0;
@@ -1877,7 +1915,7 @@ static void set_timing_cfg_8(fsl_ddr_cfg_regs_t *ddr,
}
acttoact_bg = picos_to_mclk(common_dimm->trrdl_ps);
- wrtord_bg = max(4, picos_to_mclk(7500));
+ wrtord_bg = max(4U, picos_to_mclk(7500));
if (popts->otf_burst_chop_en)
wrtord_bg += 2;
diff --git a/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c
index 2418dca6ab..aaddc8fa08 100644
--- a/drivers/ddr/fsl/ddr4_dimm_params.c
+++ b/drivers/ddr/fsl/ddr4_dimm_params.c
@@ -126,6 +126,12 @@ ddr_compute_dimm_parameters(const generic_spd_eeprom_t *spd,
{
unsigned int retval;
int i;
+ const u8 udimm_rc_e_dq[18] = {
+ 0x0c, 0x2c, 0x15, 0x35, 0x15, 0x35, 0x0b, 0x2c, 0x15,
+ 0x35, 0x0b, 0x35, 0x0b, 0x2c, 0x0b, 0x35, 0x15, 0x36
+ };
+ int spd_error = 0;
+ u8 *ptr;
if (spd->mem_type) {
if (spd->mem_type != SPD_MEMTYPE_DDR4) {
@@ -179,6 +185,22 @@ ddr_compute_dimm_parameters(const generic_spd_eeprom_t *spd,
/* Unbuffered DIMMs */
if (spd->mod_section.unbuffered.addr_mapping & 0x1)
pdimm->mirrored_dimm = 1;
+ if ((spd->mod_section.unbuffered.mod_height & 0xe0) == 0 &&
+ (spd->mod_section.unbuffered.ref_raw_card == 0x04)) {
+ /* Fix SPD error found on DIMMs with raw card E0 */
+ for (i = 0; i < 18; i++) {
+ if (spd->mapping[i] == udimm_rc_e_dq[i])
+ continue;
+ spd_error = 1;
+ debug("SPD byte %d: 0x%x, should be 0x%x\n",
+ 60 + i, spd->mapping[i],
+ udimm_rc_e_dq[i]);
+ ptr = (u8 *)&spd->mapping[i];
+ *ptr = udimm_rc_e_dq[i];
+ }
+ if (spd_error)
+ puts("SPD DQ mapping error fixed\n");
+ }
break;
default:
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index e024db9ee2..a3c01e7f1e 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -103,7 +103,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->dq_map_1, regs->dq_map_1);
ddr_out32(&ddr->dq_map_2, regs->dq_map_2);
ddr_out32(&ddr->dq_map_3, regs->dq_map_3);
- ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
ddr_out32(&ddr->sdram_cfg_3, regs->ddr_sdram_cfg_3);
ddr_out32(&ddr->sdram_mode, regs->ddr_sdram_mode);
ddr_out32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
@@ -124,8 +123,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
ddr_out32(&ddr->sdram_interval, regs->ddr_sdram_interval);
ddr_out32(&ddr->sdram_data_init, regs->ddr_data_init);
- ddr_out32(&ddr->init_addr, regs->ddr_init_addr);
- ddr_out32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
ddr_out32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
#ifndef CONFIG_SYS_FSL_DDR_EMU
/*
@@ -147,7 +144,24 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
ddr_out32(&ddr->ddr_sdram_rcw_5, regs->ddr_sdram_rcw_5);
ddr_out32(&ddr->ddr_sdram_rcw_6, regs->ddr_sdram_rcw_6);
ddr_out32(&ddr->ddr_cdr1, regs->ddr_cdr1);
- ddr_out32(&ddr->ddr_cdr2, regs->ddr_cdr2);
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ ddr_out32(&ddr->sdram_cfg_2,
+ regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
+ ddr_out32(&ddr->init_addr, CONFIG_SYS_SDRAM_BASE);
+ ddr_out32(&ddr->init_ext_addr, DDR_INIT_ADDR_EXT_UIA);
+
+ /* DRAM VRef will not be trained */
+ ddr_out32(&ddr->ddr_cdr2,
+ regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
+ } else
+#endif
+ {
+ ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ ddr_out32(&ddr->init_addr, regs->ddr_init_addr);
+ ddr_out32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+ ddr_out32(&ddr->ddr_cdr2, regs->ddr_cdr2);
+ }
ddr_out32(&ddr->err_disable, regs->err_disable);
ddr_out32(&ddr->err_int_en, regs->err_int_en);
for (i = 0; i < 32; i++) {
@@ -187,8 +201,20 @@ step2:
mb();
isb();
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ /* enter self-refresh */
+ temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
+ temp_sdram_cfg |= SDRAM_CFG2_FRC_SR;
+ ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
+ /* do board specific memory setup */
+ board_mem_sleep_setup();
+
+ temp_sdram_cfg = (ddr_in32(&ddr->sdram_cfg) | SDRAM_CFG_BI);
+ } else
+#endif
+ temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
/* Let the controller go */
- temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
mb();
isb();
@@ -233,4 +259,12 @@ step2:
if (timeout <= 0)
printf("Waiting for D_INIT timeout. Memory may not work.\n");
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ /* exit self-refresh */
+ temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg_2);
+ temp_sdram_cfg &= ~SDRAM_CFG2_FRC_SR;
+ ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg);
+ }
+#endif
}
diff --git a/drivers/ddr/fsl/lc_common_dimm_params.c b/drivers/ddr/fsl/lc_common_dimm_params.c
index 05a24dd6ef..73db444615 100644
--- a/drivers/ddr/fsl/lc_common_dimm_params.c
+++ b/drivers/ddr/fsl/lc_common_dimm_params.c
@@ -289,48 +289,58 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
* Find minimum tckmax_ps to find fastest slow speed,
* i.e., this is the slowest the whole system can go.
*/
- tckmax_ps = min(tckmax_ps, dimm_params[i].tckmax_ps);
+ tckmax_ps = min(tckmax_ps,
+ (unsigned int)dimm_params[i].tckmax_ps);
#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4)
- taamin_ps = max(taamin_ps, dimm_params[i].taa_ps);
+ taamin_ps = max(taamin_ps,
+ (unsigned int)dimm_params[i].taa_ps);
#endif
- tckmin_x_ps = max(tckmin_x_ps, dimm_params[i].tckmin_x_ps);
- trcd_ps = max(trcd_ps, dimm_params[i].trcd_ps);
- trp_ps = max(trp_ps, dimm_params[i].trp_ps);
- tras_ps = max(tras_ps, dimm_params[i].tras_ps);
+ tckmin_x_ps = max(tckmin_x_ps,
+ (unsigned int)dimm_params[i].tckmin_x_ps);
+ trcd_ps = max(trcd_ps, (unsigned int)dimm_params[i].trcd_ps);
+ trp_ps = max(trp_ps, (unsigned int)dimm_params[i].trp_ps);
+ tras_ps = max(tras_ps, (unsigned int)dimm_params[i].tras_ps);
#ifdef CONFIG_SYS_FSL_DDR4
- trfc1_ps = max(trfc1_ps, dimm_params[i].trfc1_ps);
- trfc2_ps = max(trfc2_ps, dimm_params[i].trfc2_ps);
- trfc4_ps = max(trfc4_ps, dimm_params[i].trfc4_ps);
- trrds_ps = max(trrds_ps, dimm_params[i].trrds_ps);
- trrdl_ps = max(trrdl_ps, dimm_params[i].trrdl_ps);
- tccdl_ps = max(tccdl_ps, dimm_params[i].tccdl_ps);
+ trfc1_ps = max(trfc1_ps,
+ (unsigned int)dimm_params[i].trfc1_ps);
+ trfc2_ps = max(trfc2_ps,
+ (unsigned int)dimm_params[i].trfc2_ps);
+ trfc4_ps = max(trfc4_ps,
+ (unsigned int)dimm_params[i].trfc4_ps);
+ trrds_ps = max(trrds_ps,
+ (unsigned int)dimm_params[i].trrds_ps);
+ trrdl_ps = max(trrdl_ps,
+ (unsigned int)dimm_params[i].trrdl_ps);
+ tccdl_ps = max(tccdl_ps,
+ (unsigned int)dimm_params[i].tccdl_ps);
#else
- twr_ps = max(twr_ps, dimm_params[i].twr_ps);
- twtr_ps = max(twtr_ps, dimm_params[i].twtr_ps);
- trfc_ps = max(trfc_ps, dimm_params[i].trfc_ps);
- trrd_ps = max(trrd_ps, dimm_params[i].trrd_ps);
- trtp_ps = max(trtp_ps, dimm_params[i].trtp_ps);
+ twr_ps = max(twr_ps, (unsigned int)dimm_params[i].twr_ps);
+ twtr_ps = max(twtr_ps, (unsigned int)dimm_params[i].twtr_ps);
+ trfc_ps = max(trfc_ps, (unsigned int)dimm_params[i].trfc_ps);
+ trrd_ps = max(trrd_ps, (unsigned int)dimm_params[i].trrd_ps);
+ trtp_ps = max(trtp_ps, (unsigned int)dimm_params[i].trtp_ps);
#endif
- trc_ps = max(trc_ps, dimm_params[i].trc_ps);
+ trc_ps = max(trc_ps, (unsigned int)dimm_params[i].trc_ps);
#if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2)
- tis_ps = max(tis_ps, dimm_params[i].tis_ps);
- tih_ps = max(tih_ps, dimm_params[i].tih_ps);
- tds_ps = max(tds_ps, dimm_params[i].tds_ps);
- tdh_ps = max(tdh_ps, dimm_params[i].tdh_ps);
- tqhs_ps = max(tqhs_ps, dimm_params[i].tqhs_ps);
+ tis_ps = max(tis_ps, (unsigned int)dimm_params[i].tis_ps);
+ tih_ps = max(tih_ps, (unsigned int)dimm_params[i].tih_ps);
+ tds_ps = max(tds_ps, (unsigned int)dimm_params[i].tds_ps);
+ tdh_ps = max(tdh_ps, (unsigned int)dimm_params[i].tdh_ps);
+ tqhs_ps = max(tqhs_ps, (unsigned int)dimm_params[i].tqhs_ps);
/*
* Find maximum tdqsq_max_ps to find slowest.
*
* FIXME: is finding the slowest value the correct
* strategy for this parameter?
*/
- tdqsq_max_ps = max(tdqsq_max_ps, dimm_params[i].tdqsq_max_ps);
+ tdqsq_max_ps = max(tdqsq_max_ps,
+ (unsigned int)dimm_params[i].tdqsq_max_ps);
#endif
refresh_rate_ps = max(refresh_rate_ps,
- dimm_params[i].refresh_rate_ps);
+ (unsigned int)dimm_params[i].refresh_rate_ps);
/* extended_op_srt is either 0 or 1, 0 having priority */
extended_op_srt = min(extended_op_srt,
- dimm_params[i].extended_op_srt);
+ (unsigned int)dimm_params[i].extended_op_srt);
}
outpdimm->ndimms_present = number_of_dimms - temp1;
diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c
index b43b669e41..6f291ebc03 100644
--- a/drivers/ddr/fsl/main.c
+++ b/drivers/ddr/fsl/main.c
@@ -106,7 +106,8 @@ static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address)
i2c_write(SPD_SPA1_ADDRESS, 0, 1, &dummy, 1);
ret = i2c_read(i2c_address, 0, 1,
(uchar *)((ulong)spd + 256),
- min(256, sizeof(generic_spd_eeprom_t) - 256));
+ min(256,
+ (int)sizeof(generic_spd_eeprom_t) - 256));
}
#else
ret = i2c_read(i2c_address, 0, 1, (uchar *)spd,
diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
index 4d5572ef21..8f4d01ad85 100644
--- a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
+++ b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
@@ -15,8 +15,6 @@
#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
#endif
-DECLARE_GLOBAL_DATA_PTR;
-
/*
* regs has the to-be-set values for DDR controller registers
* ctrl_num is the DDR controller number
@@ -44,16 +42,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
u32 save1, save2;
#endif
-#ifdef CONFIG_DEEP_SLEEP
- const ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
- bool sleep_flag = 0;
-#endif
-
-#ifdef CONFIG_DEEP_SLEEP
- if (in_be32(&gur->scrtsr[0]) & (1 << 3))
- sleep_flag = 1;
-#endif
-
switch (ctrl_num) {
case 0:
ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
@@ -130,13 +118,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
-#ifdef CONFIG_DEEP_SLEEP
- if (sleep_flag)
- out_be32(&ddr->sdram_cfg_2,
- regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
- else
-#endif
- out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
@@ -149,17 +130,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
-#ifdef CONFIG_DEEP_SLEEP
- if (sleep_flag) {
- out_be32(&ddr->init_addr, 0);
- out_be32(&ddr->init_ext_addr, (1 << 31));
- } else
-#endif
- {
- out_be32(&ddr->init_addr, regs->ddr_init_addr);
- out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
- }
-
out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4);
out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5);
out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
@@ -180,7 +150,24 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
out_be32(&ddr->ddr_cdr1, regs->ddr_cdr1);
- out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2);
+#ifdef CONFIG_DEEP_SLEEP
+ if (is_warm_boot()) {
+ out_be32(&ddr->sdram_cfg_2,
+ regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
+ out_be32(&ddr->init_addr, CONFIG_SYS_SDRAM_BASE);
+ out_be32(&ddr->init_ext_addr, DDR_INIT_ADDR_EXT_UIA);
+
+ /* DRAM VRef will not be trained */
+ out_be32(&ddr->ddr_cdr2,
+ regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN);
+ } else
+#endif
+ {
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ out_be32(&ddr->init_addr, regs->ddr_init_addr);
+ out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+ out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2);
+ }
out_be32(&ddr->err_disable, regs->err_disable);
out_be32(&ddr->err_int_en, regs->err_int_en);
for (i = 0; i < 32; i++) {
@@ -400,21 +387,17 @@ step2:
asm volatile("sync;isync");
#ifdef CONFIG_DEEP_SLEEP
- if (sleep_flag) {
+ if (is_warm_boot()) {
/* enter self-refresh */
- setbits_be32(&ddr->sdram_cfg_2, (1 << 31));
+ setbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_FRC_SR);
/* do board specific memory setup */
board_mem_sleep_setup();
- }
-#endif
-
- /* Let the controller go */
-#ifdef CONFIG_DEEP_SLEEP
- if (sleep_flag)
temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) | SDRAM_CFG_BI);
- else
+ } else
#endif
temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI);
+
+ /* Let the controller go */
out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
asm volatile("sync;isync");
@@ -566,8 +549,8 @@ step2:
}
#endif /* CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 */
#ifdef CONFIG_DEEP_SLEEP
- if (sleep_flag)
+ if (is_warm_boot())
/* exit self-refresh */
- clrbits_be32(&ddr->sdram_cfg_2, (1 << 31));
+ clrbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_FRC_SR);
#endif
}
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index 55e6a83b9a..ad0a7e7c25 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -17,7 +17,6 @@
#include <linux/list.h>
#include <linux/compiler.h>
-static bool dfu_detach_request;
static LIST_HEAD(dfu_list);
static int dfu_alt_num;
static int alt_num_cnt;
@@ -39,21 +38,6 @@ __weak bool dfu_usb_get_reset(void)
return true;
}
-bool dfu_detach(void)
-{
- return dfu_detach_request;
-}
-
-void dfu_trigger_detach(void)
-{
- dfu_detach_request = true;
-}
-
-void dfu_clear_detach(void)
-{
- dfu_detach_request = false;
-}
-
static int dfu_find_alt_num(const char *s)
{
int i = 0;
@@ -111,8 +95,12 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu)
return dfu_buf;
s = getenv("dfu_bufsiz");
- dfu_buf_size = s ? (unsigned long)simple_strtol(s, NULL, 16) :
- CONFIG_SYS_DFU_DATA_BUF_SIZE;
+ if (s)
+ dfu_buf_size = (unsigned long)simple_strtol(s, NULL, 0);
+
+ if (!s || !dfu_buf_size)
+ dfu_buf_size = CONFIG_SYS_DFU_DATA_BUF_SIZE;
+
if (dfu->max_buf_size && dfu_buf_size > dfu->max_buf_size)
dfu_buf_size = dfu->max_buf_size;
@@ -289,7 +277,7 @@ static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size)
readn = 0;
while (size > 0) {
/* get chunk that can be read */
- chunk = min(size, dfu->b_left);
+ chunk = min((long)size, dfu->b_left);
/* consume */
if (chunk > 0) {
memcpy(buf, dfu->i_buf, chunk);
@@ -544,10 +532,35 @@ struct dfu_entity *dfu_get_entity(int alt)
int dfu_get_alt(char *name)
{
struct dfu_entity *dfu;
+ char *str;
list_for_each_entry(dfu, &dfu_list, list) {
- if (!strncmp(dfu->name, name, strlen(dfu->name)))
- return dfu->alt;
+ if (dfu->name[0] != '/') {
+ if (!strncmp(dfu->name, name, strlen(dfu->name)))
+ return dfu->alt;
+ } else {
+ /*
+ * One must also consider absolute path
+ * (/boot/bin/uImage) available at dfu->name when
+ * compared "plain" file name (uImage)
+ *
+ * It is the case for e.g. thor gadget where lthor SW
+ * sends only the file name, so only the very last part
+ * of path must be checked for equality
+ */
+
+ str = strstr(dfu->name, name);
+ if (!str)
+ continue;
+
+ /*
+ * Check if matching substring is the last element of
+ * dfu->name (uImage)
+ */
+ if (strlen(dfu->name) ==
+ ((str - dfu->name) + strlen(name)))
+ return dfu->alt;
+ }
}
return -ENODEV;
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 72fa03eeda..62d72fe4c6 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -40,10 +40,16 @@ static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part)
static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
{
- struct mmc *mmc = find_mmc_device(dfu->data.mmc.dev_num);
+ struct mmc *mmc;
u32 blk_start, blk_count, n = 0;
int ret, part_num_bkp = 0;
+ mmc = find_mmc_device(dfu->data.mmc.dev_num);
+ if (!mmc) {
+ error("Device MMC %d - not found!", dfu->data.mmc.dev_num);
+ return -ENODEV;
+ }
+
/*
* We must ensure that we work in lba_blk_size chunks, so ALIGN
* this value.
diff --git a/drivers/dma/keystone_nav.c b/drivers/dma/keystone_nav.c
index 77707c2109..dfca75abdc 100644
--- a/drivers/dma/keystone_nav.c
+++ b/drivers/dma/keystone_nav.c
@@ -81,9 +81,6 @@ void qm_close(void)
{
u32 j;
- if (qm_cfg == NULL)
- return;
-
queue_close(qm_cfg->qpool_num);
qm_cfg->mngr_cfg->link_ram_base0 = 0;
@@ -105,9 +102,6 @@ void qm_push(struct qm_host_desc *hd, u32 qnum)
{
u32 regd;
- if (!qm_cfg)
- return;
-
cpu_to_bus((u32 *)hd, sizeof(struct qm_host_desc)/4);
regd = (u32)hd | ((sizeof(struct qm_host_desc) >> 4) - 1);
writel(regd, &qm_cfg->queue[qnum].ptr_size_thresh);
@@ -127,9 +121,6 @@ struct qm_host_desc *qm_pop(u32 qnum)
{
u32 uhd;
- if (!qm_cfg)
- return NULL;
-
uhd = readl(&qm_cfg->queue[qnum].ptr_size_thresh) & ~0xf;
if (uhd)
cpu_to_bus((u32 *)uhd, sizeof(struct qm_host_desc)/4);
@@ -139,9 +130,6 @@ struct qm_host_desc *qm_pop(u32 qnum)
struct qm_host_desc *qm_pop_from_free_pool(void)
{
- if (!qm_cfg)
- return NULL;
-
return qm_pop(qm_cfg->qpool_num);
}
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index 68fe0f3b03..6a74f89610 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -406,8 +406,8 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
unsigned long ts; /* Timestamp */
u32 isr_status, swap;
u32 partialbit = 0;
- u32 blocksize;
- u32 pos = 0;
+ loff_t blocksize, actread;
+ loff_t pos = 0;
int fstype;
char *interface, *dev_part, *filename;
@@ -420,7 +420,7 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
if (fs_set_blk_dev(interface, dev_part, fstype))
return FPGA_FAIL;
- if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+ if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0)
return FPGA_FAIL;
if (zynq_validate_bitstream(desc, buf, bsize, blocksize, &swap,
@@ -443,10 +443,10 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
return FPGA_FAIL;
if (bsize > blocksize) {
- if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+ if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0)
return FPGA_FAIL;
} else {
- if (fs_read(filename, (u32) buf, pos, bsize) < 0)
+ if (fs_read(filename, (u32) buf, pos, bsize, &actread) < 0)
return FPGA_FAIL;
}
} while (bsize > blocksize);
diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 6517af1628..6129c020ea 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -10,11 +10,14 @@
#include <config.h>
#include <common.h>
+#include <dm.h>
#include <asm/io.h>
#include <linux/sizes.h>
+#include <asm/gpio.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91_pio.h>
-#include <asm/arch/gpio.h>
+
+#define GPIO_PER_BANK 32
static struct at91_port *at91_pio_get_port(unsigned port)
{
@@ -39,19 +42,25 @@ static struct at91_port *at91_pio_get_port(unsigned port)
}
}
+static void at91_set_port_pullup(struct at91_port *at91_port, unsigned offset,
+ int use_pullup)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ if (use_pullup)
+ writel(mask, &at91_port->puer);
+ else
+ writel(mask, &at91_port->pudr);
+ writel(mask, &at91_port->per);
+}
+
int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup)
{
struct at91_port *at91_port = at91_pio_get_port(port);
- u32 mask;
- if (at91_port && (pin < 32)) {
- mask = 1 << pin;
- if (use_pullup)
- writel(1 << pin, &at91_port->puer);
- else
- writel(1 << pin, &at91_port->pudr);
- writel(mask, &at91_port->per);
- }
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_pullup(at91_port, pin, use_pullup);
return 0;
}
@@ -64,7 +73,7 @@ int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
writel(mask, &at91_port->idr);
at91_set_pio_pullup(port, pin, use_pullup);
@@ -82,7 +91,7 @@ int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
writel(mask, &at91_port->idr);
at91_set_pio_pullup(port, pin, use_pullup);
@@ -108,7 +117,7 @@ int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
writel(mask, &at91_port->idr);
at91_set_pio_pullup(port, pin, use_pullup);
@@ -135,7 +144,7 @@ int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
writel(mask, &at91_port->idr);
at91_set_pio_pullup(port, pin, use_pullup);
@@ -157,7 +166,7 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
writel(mask, &at91_port->idr);
at91_set_pio_pullup(port, pin, use_pullup);
@@ -172,6 +181,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup)
}
#endif
+#ifdef CONFIG_DM_GPIO
+static bool at91_get_port_output(struct at91_port *at91_port, int offset)
+{
+ u32 mask, val;
+
+ mask = 1 << offset;
+ val = readl(&at91_port->osr);
+ return val & mask;
+}
+#endif
+
+static void at91_set_port_input(struct at91_port *at91_port, int offset,
+ int use_pullup)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ writel(mask, &at91_port->idr);
+ at91_set_port_pullup(at91_port, offset, use_pullup);
+ writel(mask, &at91_port->odr);
+ writel(mask, &at91_port->per);
+}
+
/*
* mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
* configure it for an input.
@@ -179,19 +211,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup)
int at91_set_pio_input(unsigned port, u32 pin, int use_pullup)
{
struct at91_port *at91_port = at91_pio_get_port(port);
- u32 mask;
- if (at91_port && (pin < 32)) {
- mask = 1 << pin;
- writel(mask, &at91_port->idr);
- at91_set_pio_pullup(port, pin, use_pullup);
- writel(mask, &at91_port->odr);
- writel(mask, &at91_port->per);
- }
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_input(at91_port, pin, use_pullup);
return 0;
}
+static void at91_set_port_output(struct at91_port *at91_port, int offset,
+ int value)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ writel(mask, &at91_port->idr);
+ writel(mask, &at91_port->pudr);
+ if (value)
+ writel(mask, &at91_port->sodr);
+ else
+ writel(mask, &at91_port->codr);
+ writel(mask, &at91_port->oer);
+ writel(mask, &at91_port->per);
+}
+
/*
* mux the pin to the gpio controller (instead of "A" or "B" peripheral),
* and configure it for an output.
@@ -199,19 +241,9 @@ int at91_set_pio_input(unsigned port, u32 pin, int use_pullup)
int at91_set_pio_output(unsigned port, u32 pin, int value)
{
struct at91_port *at91_port = at91_pio_get_port(port);
- u32 mask;
- if (at91_port && (port < ATMEL_PIO_PORTS) && (pin < 32)) {
- mask = 1 << pin;
- writel(mask, &at91_port->idr);
- writel(mask, &at91_port->pudr);
- if (value)
- writel(mask, &at91_port->sodr);
- else
- writel(mask, &at91_port->codr);
- writel(mask, &at91_port->oer);
- writel(mask, &at91_port->per);
- }
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_output(at91_port, pin, value);
return 0;
}
@@ -224,7 +256,7 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
if (is_on) {
#if defined(CPU_HAS_PIO3)
@@ -248,7 +280,7 @@ int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
if (is_on) {
writel(mask, &at91_port->ifscer);
@@ -271,7 +303,7 @@ int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
writel(mask, &at91_port->pudr);
if (is_on)
@@ -291,7 +323,7 @@ int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
writel(readl(&at91_port->schmitt) | mask,
&at91_port->schmitt);
@@ -310,7 +342,7 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on)
struct at91_port *at91_port = at91_pio_get_port(port);
u32 mask;
- if (at91_port && (pin < 32)) {
+ if (at91_port && (pin < GPIO_PER_BANK)) {
mask = 1 << pin;
if (is_on)
writel(mask, &at91_port->mder);
@@ -321,41 +353,54 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on)
return 0;
}
+static void at91_set_port_value(struct at91_port *at91_port, int offset,
+ int value)
+{
+ u32 mask;
+
+ mask = 1 << offset;
+ if (value)
+ writel(mask, &at91_port->sodr);
+ else
+ writel(mask, &at91_port->codr);
+}
+
/*
* assuming the pin is muxed as a gpio output, set its value.
*/
int at91_set_pio_value(unsigned port, unsigned pin, int value)
{
struct at91_port *at91_port = at91_pio_get_port(port);
- u32 mask;
- if (at91_port && (pin < 32)) {
- mask = 1 << pin;
- if (value)
- writel(mask, &at91_port->sodr);
- else
- writel(mask, &at91_port->codr);
- }
+ if (at91_port && (pin < GPIO_PER_BANK))
+ at91_set_port_value(at91_port, pin, value);
return 0;
}
+static int at91_get_port_value(struct at91_port *at91_port, int offset)
+{
+ u32 pdsr = 0, mask;
+
+ mask = 1 << offset;
+ pdsr = readl(&at91_port->pdsr) & mask;
+
+ return pdsr != 0;
+}
/*
* read the pin's value (works even if it's not muxed as a gpio).
*/
int at91_get_pio_value(unsigned port, unsigned pin)
{
struct at91_port *at91_port = at91_pio_get_port(port);
- u32 pdsr = 0, mask;
- if (at91_port && (pin < 32)) {
- mask = 1 << pin;
- pdsr = readl(&at91_port->pdsr) & mask;
- }
+ if (at91_port && (pin < GPIO_PER_BANK))
+ return at91_get_port_value(at91_port, pin);
- return pdsr != 0;
+ return 0;
}
+#ifndef CONFIG_DM_GPIO
/* Common GPIO API */
int gpio_request(unsigned gpio, const char *label)
@@ -395,3 +440,91 @@ int gpio_set_value(unsigned gpio, int value)
return 0;
}
+#endif
+
+#ifdef CONFIG_DM_GPIO
+
+struct at91_port_priv {
+ struct at91_port *regs;
+};
+
+/* set GPIO pin 'gpio' as an input */
+static int at91_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_priv *port = dev_get_platdata(dev);
+
+ at91_set_port_input(port->regs, offset, 0);
+
+ return 0;
+}
+
+/* set GPIO pin 'gpio' as an output, with polarity 'value' */
+static int at91_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct at91_port_priv *port = dev_get_platdata(dev);
+
+ at91_set_port_output(port->regs, offset, value);
+
+ return 0;
+}
+
+/* read GPIO IN value of pin 'gpio' */
+static int at91_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_priv *port = dev_get_platdata(dev);
+
+ return at91_get_port_value(port->regs, offset);
+}
+
+/* write GPIO OUT value to pin 'gpio' */
+static int at91_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct at91_port_priv *port = dev_get_platdata(dev);
+
+ at91_set_port_value(port->regs, offset, value);
+
+ return 0;
+}
+
+static int at91_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_priv *port = dev_get_platdata(dev);
+
+ /* GPIOF_FUNC is not implemented yet */
+ if (at91_get_port_output(port->regs, offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_at91_ops = {
+ .direction_input = at91_gpio_direction_input,
+ .direction_output = at91_gpio_direction_output,
+ .get_value = at91_gpio_get_value,
+ .set_value = at91_gpio_set_value,
+ .get_function = at91_gpio_get_function,
+};
+
+static int at91_gpio_probe(struct udevice *dev)
+{
+ struct at91_port_priv *port = dev_get_priv(dev);
+ struct at91_port_platdata *plat = dev_get_platdata(dev);
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+ uc_priv->bank_name = plat->bank_name;
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ port->regs = (struct at91_port *)plat->base_addr;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_at91) = {
+ .name = "gpio_at91",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_at91_ops,
+ .probe = at91_gpio_probe,
+ .priv_auto_alloc_size = sizeof(struct at91_port_priv),
+};
+#endif
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 45e9a5ad22..255700ab18 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -390,6 +390,25 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
return 0;
}
+/*
+ * get a number comprised of multiple GPIO values. gpio_num_array points to
+ * the array of gpio pin numbers to scan, terminated by -1.
+ */
+unsigned gpio_get_values_as_int(const int *gpio_num_array)
+{
+ int gpio;
+ unsigned bitmask = 1;
+ unsigned vector = 0;
+
+ while (bitmask &&
+ ((gpio = *gpio_num_array++) != -1)) {
+ if (gpio_get_value(gpio))
+ vector |= bitmask;
+ bitmask <<= 1;
+ }
+ return vector;
+}
+
/* 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/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c
index d3381b0369..7720cc3dad 100644
--- a/drivers/gpio/intel_ich6_gpio.c
+++ b/drivers/gpio/intel_ich6_gpio.c
@@ -33,19 +33,23 @@
#include <pci.h>
#include <asm/gpio.h>
#include <asm/io.h>
+#include <asm/pci.h>
#define GPIO_PER_BANK 32
-/* Where in config space is the register that points to the GPIO registers? */
-#define PCI_CFG_GPIOBASE 0x48
-
struct ich6_bank_priv {
/* These are I/O addresses */
- uint32_t use_sel;
- uint32_t io_sel;
- uint32_t lvl;
+ uint16_t use_sel;
+ uint16_t io_sel;
+ uint16_t lvl;
};
+/* TODO: Move this to device tree, or platform data */
+void ich_gpio_set_gpio_map(const struct pch_gpio_map *map)
+{
+ gd->arch.gpio_map = map;
+}
+
static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
{
struct ich6_bank_platdata *plat = dev_get_platdata(dev);
@@ -53,20 +57,20 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
u8 tmpbyte;
u16 tmpword;
u32 tmplong;
- u32 gpiobase;
+ u16 gpiobase;
int offset;
/* Where should it be? */
pci_dev = PCI_BDF(0, 0x1f, 0);
/* Is the device present? */
- pci_read_config_word(pci_dev, PCI_VENDOR_ID, &tmpword);
+ tmpword = pci_read_config16(pci_dev, PCI_VENDOR_ID);
if (tmpword != PCI_VENDOR_ID_INTEL) {
debug("%s: wrong VendorID\n", __func__);
return -ENODEV;
}
- pci_read_config_word(pci_dev, PCI_DEVICE_ID, &tmpword);
+ tmpword = pci_read_config16(pci_dev, PCI_DEVICE_ID);
debug("Found %04x:%04x\n", PCI_VENDOR_ID_INTEL, tmpword);
/*
* We'd like to validate the Device ID too, but pretty much any
@@ -76,34 +80,34 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
*/
/* I/O should already be enabled (it's a RO bit). */
- pci_read_config_word(pci_dev, PCI_COMMAND, &tmpword);
+ tmpword = pci_read_config16(pci_dev, PCI_COMMAND);
if (!(tmpword & PCI_COMMAND_IO)) {
debug("%s: device IO not enabled\n", __func__);
return -ENODEV;
}
/* Header Type must be normal (bits 6-0 only; see spec.) */
- pci_read_config_byte(pci_dev, PCI_HEADER_TYPE, &tmpbyte);
+ tmpbyte = pci_read_config8(pci_dev, PCI_HEADER_TYPE);
if ((tmpbyte & 0x7f) != PCI_HEADER_TYPE_NORMAL) {
debug("%s: invalid Header type\n", __func__);
return -ENODEV;
}
/* Base Class must be a bridge device */
- pci_read_config_byte(pci_dev, PCI_CLASS_CODE, &tmpbyte);
+ tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_CODE);
if (tmpbyte != PCI_CLASS_CODE_BRIDGE) {
debug("%s: invalid class\n", __func__);
return -ENODEV;
}
/* Sub Class must be ISA */
- pci_read_config_byte(pci_dev, PCI_CLASS_SUB_CODE, &tmpbyte);
+ tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE);
if (tmpbyte != PCI_CLASS_SUB_CODE_BRIDGE_ISA) {
debug("%s: invalid subclass\n", __func__);
return -ENODEV;
}
/* Programming Interface must be 0x00 (no others exist) */
- pci_read_config_byte(pci_dev, PCI_CLASS_PROG, &tmpbyte);
+ tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_PROG);
if (tmpbyte != 0x00) {
debug("%s: invalid interface type\n", __func__);
return -ENODEV;
@@ -112,11 +116,15 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
/*
* GPIOBASE moved to its current offset with ICH6, but prior to
* that it was unused (or undocumented). Check that it looks
- * okay: not all ones or zeros, and mapped to I/O space (bit 0).
+ * okay: not all ones or zeros.
+ *
+ * Note we don't need check bit0 here, because the Tunnel Creek
+ * GPIO base address register bit0 is reserved (read returns 0),
+ * while on the Ivybridge the bit0 is used to indicate it is an
+ * I/O space.
*/
- pci_read_config_dword(pci_dev, PCI_CFG_GPIOBASE, &tmplong);
- if (tmplong == 0x00000000 || tmplong == 0xffffffff ||
- !(tmplong & 0x00000001)) {
+ tmplong = pci_read_config32(pci_dev, PCI_CFG_GPIOBASE);
+ if (tmplong == 0x00000000 || tmplong == 0xffffffff) {
debug("%s: unexpected GPIOBASE value\n", __func__);
return -ENODEV;
}
@@ -127,7 +135,7 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
* at the offset that we just read. Bit 0 indicates that it's
* an I/O address, not a memory address, so mask that off.
*/
- gpiobase = tmplong & 0xfffffffe;
+ gpiobase = tmplong & 0xfffe;
offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1);
if (offset == -1) {
debug("%s: Invalid register offset %d\n", __func__, offset);
@@ -140,12 +148,17 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
return 0;
}
-int ich6_gpio_probe(struct udevice *dev)
+static int ich6_gpio_probe(struct udevice *dev)
{
struct ich6_bank_platdata *plat = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
struct ich6_bank_priv *bank = dev_get_priv(dev);
+ if (gd->arch.gpio_map) {
+ setup_pch_gpios(plat->base_addr, gd->arch.gpio_map);
+ gd->arch.gpio_map = NULL;
+ }
+
uc_priv->gpio_count = GPIO_PER_BANK;
uc_priv->bank_name = plat->bank_name;
bank->use_sel = plat->base_addr;
@@ -155,7 +168,8 @@ int ich6_gpio_probe(struct udevice *dev)
return 0;
}
-int ich6_gpio_request(struct udevice *dev, unsigned offset, const char *label)
+static int ich6_gpio_request(struct udevice *dev, unsigned offset,
+ const char *label)
{
struct ich6_bank_priv *bank = dev_get_priv(dev);
u32 tmplong;
@@ -192,6 +206,8 @@ static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset,
struct ich6_bank_priv *bank = dev_get_priv(dev);
u32 tmplong;
+ gpio_set_value(offset, value);
+
tmplong = inl(bank->io_sel);
tmplong &= ~(1UL << offset);
outl(bank->io_sel, tmplong);
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 0c50a8f332..62960929ad 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -11,9 +11,28 @@
*/
#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
#include <asm/io.h>
#include <asm/gpio.h>
+#include <dm/device-internal.h>
+#ifdef CONFIG_AXP209_POWER
+#include <axp209.h>
+#endif
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR
+
+struct sunxi_gpio_platdata {
+ struct sunxi_gpio *regs;
+ const char *bank_name; /* Name of bank, e.g. "B" */
+ int gpio_count;
+};
+
+#ifndef CONFIG_DM_GPIO
static int sunxi_gpio_output(u32 pin, u32 val)
{
u32 dat;
@@ -57,13 +76,22 @@ int gpio_free(unsigned gpio)
int gpio_direction_input(unsigned gpio)
{
+#ifdef AXP_GPIO
+ if (gpio >= SUNXI_GPIO_AXP0_START)
+ return axp_gpio_direction_input(gpio - SUNXI_GPIO_AXP0_START);
+#endif
sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
- return sunxi_gpio_input(gpio);
+ return 0;
}
int gpio_direction_output(unsigned gpio, int value)
{
+#ifdef AXP_GPIO
+ if (gpio >= SUNXI_GPIO_AXP0_START)
+ return axp_gpio_direction_output(gpio - SUNXI_GPIO_AXP0_START,
+ value);
+#endif
sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
return sunxi_gpio_output(gpio, value);
@@ -71,11 +99,19 @@ int gpio_direction_output(unsigned gpio, int value)
int gpio_get_value(unsigned gpio)
{
+#ifdef AXP_GPIO
+ if (gpio >= SUNXI_GPIO_AXP0_START)
+ return axp_gpio_get_value(gpio - SUNXI_GPIO_AXP0_START);
+#endif
return sunxi_gpio_input(gpio);
}
int gpio_set_value(unsigned gpio, int value)
{
+#ifdef AXP_GPIO
+ if (gpio >= SUNXI_GPIO_AXP0_START)
+ return axp_gpio_set_value(gpio - SUNXI_GPIO_AXP0_START, value);
+#endif
return sunxi_gpio_output(gpio, value);
}
@@ -85,6 +121,16 @@ int sunxi_name_to_gpio(const char *name)
int groupsize = 9 * 32;
long pin;
char *eptr;
+
+#ifdef AXP_GPIO
+ if (strncasecmp(name, "AXP0-", 5) == 0) {
+ name += 5;
+ pin = simple_strtol(name, &eptr, 10);
+ if (!*name || *eptr)
+ return -1;
+ return SUNXI_GPIO_AXP0_START + pin;
+ }
+#endif
if (*name == 'P' || *name == 'p')
name++;
if (*name >= 'A') {
@@ -100,3 +146,157 @@ int sunxi_name_to_gpio(const char *name)
return -1;
return group * 32 + pin;
}
+#endif
+
+#ifdef CONFIG_DM_GPIO
+static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
+
+ sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
+
+ return 0;
+}
+
+static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
+ u32 num = GPIO_NUM(offset);
+
+ sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
+ clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
+
+ return 0;
+}
+
+static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
+ u32 num = GPIO_NUM(offset);
+ unsigned dat;
+
+ dat = readl(&plat->regs->dat);
+ dat >>= num;
+
+ return dat & 0x1;
+}
+
+static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
+ u32 num = GPIO_NUM(offset);
+
+ clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
+ return 0;
+}
+
+static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
+ int func;
+
+ func = sunxi_gpio_get_cfgbank(plat->regs, offset);
+ if (func == SUNXI_GPIO_OUTPUT)
+ return GPIOF_OUTPUT;
+ else if (func == SUNXI_GPIO_INPUT)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_FUNC;
+}
+
+static const struct dm_gpio_ops gpio_sunxi_ops = {
+ .direction_input = sunxi_gpio_direction_input,
+ .direction_output = sunxi_gpio_direction_output,
+ .get_value = sunxi_gpio_get_value,
+ .set_value = sunxi_gpio_set_value,
+ .get_function = sunxi_gpio_get_function,
+};
+
+/**
+ * Returns the name of a GPIO bank
+ *
+ * GPIO banks are named A, B, C, ...
+ *
+ * @bank: Bank number (0, 1..n-1)
+ * @return allocated string containing the name
+ */
+static char *gpio_bank_name(int bank)
+{
+ char *name;
+
+ name = malloc(2);
+ if (name) {
+ name[0] = 'A' + bank;
+ name[1] = '\0';
+ }
+
+ return name;
+}
+
+static int gpio_sunxi_probe(struct udevice *dev)
+{
+ struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+ /* Tell the uclass how many GPIOs we have */
+ if (plat) {
+ uc_priv->gpio_count = plat->gpio_count;
+ uc_priv->bank_name = plat->bank_name;
+ }
+
+ return 0;
+}
+/**
+ * We have a top-level GPIO device with no actual GPIOs. It has a child
+ * device for each Sunxi bank.
+ */
+static int gpio_sunxi_bind(struct udevice *parent)
+{
+ struct sunxi_gpio_platdata *plat = parent->platdata;
+ struct sunxi_gpio_reg *ctlr;
+ int bank;
+ int ret;
+
+ /* If this is a child device, there is nothing to do here */
+ if (plat)
+ return 0;
+
+ ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
+ parent->of_offset, "reg");
+ for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
+ struct sunxi_gpio_platdata *plat;
+ struct udevice *dev;
+
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+ plat->regs = &ctlr->gpio_bank[bank];
+ plat->bank_name = gpio_bank_name(bank);
+ plat->gpio_count = SUNXI_GPIOS_PER_BANK;
+
+ ret = device_bind(parent, parent->driver,
+ plat->bank_name, plat, -1, &dev);
+ if (ret)
+ return ret;
+ dev->of_offset = parent->of_offset;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id sunxi_gpio_ids[] = {
+ { .compatible = "allwinner,sun7i-a20-pinctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_sunxi) = {
+ .name = "gpio_sunxi",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_sunxi_ops,
+ .of_match = sunxi_gpio_ids,
+ .bind = gpio_sunxi_bind,
+ .probe = gpio_sunxi_probe,
+};
+#endif
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index d067897244..6f3c86c038 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -4,8 +4,9 @@
#
# SPDX-License-Identifier: GPL-2.0+
#
+obj-$(CONFIG_DM_I2C) += i2c-uclass.o
-obj-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
+obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o
obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o
obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o
+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
diff --git a/drivers/i2c/adi_i2c.c b/drivers/i2c/adi_i2c.c
new file mode 100644
index 0000000000..20495b1d7f
--- /dev/null
+++ b/drivers/i2c/adi_i2c.c
@@ -0,0 +1,305 @@
+/*
+ * i2c.c - driver for ADI TWI/I2C
+ *
+ * Copyright (c) 2006-2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <i2c.h>
+
+#include <asm/clock.h>
+#include <asm/twi.h>
+#include <asm/io.h>
+
+static struct twi_regs *i2c_get_base(struct i2c_adapter *adap);
+
+/* Every register is 32bit aligned, but only 16bits in size */
+#define ureg(name) u16 name; u16 __pad_##name;
+struct twi_regs {
+ ureg(clkdiv);
+ ureg(control);
+ ureg(slave_ctl);
+ ureg(slave_stat);
+ ureg(slave_addr);
+ ureg(master_ctl);
+ ureg(master_stat);
+ ureg(master_addr);
+ ureg(int_stat);
+ ureg(int_mask);
+ ureg(fifo_ctl);
+ ureg(fifo_stat);
+ char __pad[0x50];
+ ureg(xmt_data8);
+ ureg(xmt_data16);
+ ureg(rcv_data8);
+ ureg(rcv_data16);
+};
+#undef ureg
+
+#ifdef TWI_CLKDIV
+#define TWI0_CLKDIV TWI_CLKDIV
+# ifdef CONFIG_SYS_MAX_I2C_BUS
+# undef CONFIG_SYS_MAX_I2C_BUS
+# endif
+#define CONFIG_SYS_MAX_I2C_BUS 1
+#endif
+
+/*
+ * The way speed is changed into duty often results in integer truncation
+ * with 50% duty, so we'll force rounding up to the next duty by adding 1
+ * to the max. In practice this will get us a speed of something like
+ * 385 KHz. The other limit is easy to handle as it is only 8 bits.
+ */
+#define I2C_SPEED_MAX 400000
+#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed))
+#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
+#define I2C_DUTY_MIN 0xff /* 8 bit limited */
+#define SYS_I2C_DUTY I2C_SPEED_TO_DUTY(CONFIG_SYS_I2C_SPEED)
+/* Note: duty is inverse of speed, so the comparisons below are correct */
+#if SYS_I2C_DUTY < I2C_DUTY_MAX || SYS_I2C_DUTY > I2C_DUTY_MIN
+# error "The I2C hardware can only operate 20KHz - 400KHz"
+#endif
+
+/* All transfers are described by this data structure */
+struct i2c_msg {
+ u8 flags;
+#define I2C_M_COMBO 0x4
+#define I2C_M_STOP 0x2
+#define I2C_M_READ 0x1
+ int len; /* msg length */
+ u8 *buf; /* pointer to msg data */
+ int alen; /* addr length */
+ u8 *abuf; /* addr buffer */
+};
+
+/* Allow msec timeout per ~byte transfer */
+#define I2C_TIMEOUT 10
+
+/**
+ * wait_for_completion - manage the actual i2c transfer
+ * @msg: the i2c msg
+ */
+static int wait_for_completion(struct twi_regs *twi, struct i2c_msg *msg)
+{
+ u16 int_stat, ctl;
+ ulong timebase = get_timer(0);
+
+ do {
+ int_stat = readw(&twi->int_stat);
+
+ if (int_stat & XMTSERV) {
+ writew(XMTSERV, &twi->int_stat);
+ if (msg->alen) {
+ writew(*(msg->abuf++), &twi->xmt_data8);
+ --msg->alen;
+ } else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
+ writew(*(msg->buf++), &twi->xmt_data8);
+ --msg->len;
+ } else {
+ ctl = readw(&twi->master_ctl);
+ if (msg->flags & I2C_M_COMBO)
+ writew(ctl | RSTART | MDIR,
+ &twi->master_ctl);
+ else
+ writew(ctl | STOP, &twi->master_ctl);
+ }
+ }
+ if (int_stat & RCVSERV) {
+ writew(RCVSERV, &twi->int_stat);
+ if (msg->len) {
+ *(msg->buf++) = readw(&twi->rcv_data8);
+ --msg->len;
+ } else if (msg->flags & I2C_M_STOP) {
+ ctl = readw(&twi->master_ctl);
+ writew(ctl | STOP, &twi->master_ctl);
+ }
+ }
+ if (int_stat & MERR) {
+ writew(MERR, &twi->int_stat);
+ return msg->len;
+ }
+ if (int_stat & MCOMP) {
+ writew(MCOMP, &twi->int_stat);
+ if (msg->flags & I2C_M_COMBO && msg->len) {
+ ctl = readw(&twi->master_ctl);
+ ctl = (ctl & ~RSTART) |
+ (min(msg->len, 0xff) << 6) | MEN | MDIR;
+ writew(ctl, &twi->master_ctl);
+ } else
+ break;
+ }
+
+ /* If we were able to do something, reset timeout */
+ if (int_stat)
+ timebase = get_timer(0);
+
+ } while (get_timer(timebase) < I2C_TIMEOUT);
+
+ return msg->len;
+}
+
+static int i2c_transfer(struct i2c_adapter *adap, uint8_t chip, uint addr,
+ int alen, uint8_t *buffer, int len, uint8_t flags)
+{
+ struct twi_regs *twi = i2c_get_base(adap);
+ int ret;
+ u16 ctl;
+ uchar addr_buffer[] = {
+ (addr >> 0),
+ (addr >> 8),
+ (addr >> 16),
+ };
+ struct i2c_msg msg = {
+ .flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
+ .buf = buffer,
+ .len = len,
+ .abuf = addr_buffer,
+ .alen = alen,
+ };
+
+ /* wait for things to settle */
+ while (readw(&twi->master_stat) & BUSBUSY)
+ if (ctrlc())
+ return 1;
+
+ /* Set Transmit device address */
+ writew(chip, &twi->master_addr);
+
+ /* Clear the FIFO before starting things */
+ writew(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl);
+ writew(0, &twi->fifo_ctl);
+
+ /* prime the pump */
+ if (msg.alen) {
+ len = (msg.flags & I2C_M_COMBO) ? msg.alen : msg.alen + len;
+ writew(*(msg.abuf++), &twi->xmt_data8);
+ --msg.alen;
+ } else if (!(msg.flags & I2C_M_READ) && msg.len) {
+ writew(*(msg.buf++), &twi->xmt_data8);
+ --msg.len;
+ }
+
+ /* clear int stat */
+ writew(-1, &twi->master_stat);
+ writew(-1, &twi->int_stat);
+ writew(0, &twi->int_mask);
+
+ /* Master enable */
+ ctl = readw(&twi->master_ctl);
+ ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN |
+ ((msg.flags & I2C_M_READ) ? MDIR : 0);
+ writew(ctl, &twi->master_ctl);
+
+ /* process the rest */
+ ret = wait_for_completion(twi, &msg);
+
+ if (ret) {
+ ctl = readw(&twi->master_ctl) & ~MEN;
+ writew(ctl, &twi->master_ctl);
+ ctl = readw(&twi->control) & ~TWI_ENA;
+ writew(ctl, &twi->control);
+ ctl = readw(&twi->control) | TWI_ENA;
+ writew(ctl, &twi->control);
+ }
+
+ return ret;
+}
+
+static uint adi_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+{
+ struct twi_regs *twi = i2c_get_base(adap);
+ u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
+
+ /* Set TWI interface clock */
+ if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
+ return -1;
+ clkdiv = (clkdiv << 8) | (clkdiv & 0xff);
+ writew(clkdiv, &twi->clkdiv);
+
+ /* Don't turn it on */
+ writew(speed > 100000 ? FAST : 0, &twi->master_ctl);
+
+ return 0;
+}
+
+static void adi_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+ struct twi_regs *twi = i2c_get_base(adap);
+ u16 prescale = ((get_i2c_clk() / 1000 / 1000 + 5) / 10) & 0x7F;
+
+ /* Set TWI internal clock as 10MHz */
+ writew(prescale, &twi->control);
+
+ /* Set TWI interface clock as specified */
+ i2c_set_bus_speed(speed);
+
+ /* Enable it */
+ writew(TWI_ENA | prescale, &twi->control);
+}
+
+static int adi_i2c_read(struct i2c_adapter *adap, uint8_t chip,
+ uint addr, int alen, uint8_t *buffer, int len)
+{
+ return i2c_transfer(adap, chip, addr, alen, buffer,
+ len, alen ? I2C_M_COMBO : I2C_M_READ);
+}
+
+static int adi_i2c_write(struct i2c_adapter *adap, uint8_t chip,
+ uint addr, int alen, uint8_t *buffer, int len)
+{
+ return i2c_transfer(adap, chip, addr, alen, buffer, len, 0);
+}
+
+static int adi_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
+{
+ u8 byte;
+ return adi_i2c_read(adap, chip, 0, 0, &byte, 1);
+}
+
+static struct twi_regs *i2c_get_base(struct i2c_adapter *adap)
+{
+ switch (adap->hwadapnr) {
+#if CONFIG_SYS_MAX_I2C_BUS > 2
+ case 2:
+ return (struct twi_regs *)TWI2_CLKDIV;
+#endif
+#if CONFIG_SYS_MAX_I2C_BUS > 1
+ case 1:
+ return (struct twi_regs *)TWI1_CLKDIV;
+#endif
+ case 0:
+ return (struct twi_regs *)TWI0_CLKDIV;
+
+ default:
+ printf("wrong hwadapnr: %d\n", adap->hwadapnr);
+ }
+
+ return NULL;
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(adi_i2c0, adi_i2c_init, adi_i2c_probe,
+ adi_i2c_read, adi_i2c_write,
+ adi_i2c_setspeed,
+ CONFIG_SYS_I2C_SPEED,
+ 0,
+ 0)
+
+#if CONFIG_SYS_MAX_I2C_BUS > 1
+U_BOOT_I2C_ADAP_COMPLETE(adi_i2c1, adi_i2c_init, adi_i2c_probe,
+ adi_i2c_read, adi_i2c_write,
+ adi_i2c_setspeed,
+ CONFIG_SYS_I2C_SPEED,
+ 0,
+ 1)
+#endif
+
+#if CONFIG_SYS_MAX_I2C_BUS > 2
+U_BOOT_I2C_ADAP_COMPLETE(adi_i2c2, adi_i2c_init, adi_i2c_probe,
+ adi_i2c_read, adi_i2c_write,
+ adi_i2c_setspeed,
+ CONFIG_SYS_I2C_SPEED,
+ 0,
+ 2)
+#endif
diff --git a/drivers/i2c/bfin-twi_i2c.c b/drivers/i2c/bfin-twi_i2c.c
deleted file mode 100644
index cfab064dfa..0000000000
--- a/drivers/i2c/bfin-twi_i2c.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * i2c.c - driver for Blackfin on-chip TWI/I2C
- *
- * Copyright (c) 2006-2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <common.h>
-#include <i2c.h>
-
-#include <asm/blackfin.h>
-#include <asm/clock.h>
-#include <asm/mach-common/bits/twi.h>
-
-/* Every register is 32bit aligned, but only 16bits in size */
-#define ureg(name) u16 name; u16 __pad_##name;
-struct twi_regs {
- ureg(clkdiv);
- ureg(control);
- ureg(slave_ctl);
- ureg(slave_stat);
- ureg(slave_addr);
- ureg(master_ctl);
- ureg(master_stat);
- ureg(master_addr);
- ureg(int_stat);
- ureg(int_mask);
- ureg(fifo_ctl);
- ureg(fifo_stat);
- char __pad[0x50];
- ureg(xmt_data8);
- ureg(xmt_data16);
- ureg(rcv_data8);
- ureg(rcv_data16);
-};
-#undef ureg
-
-/* U-Boot I2C framework allows only one active device at a time. */
-#ifdef TWI_CLKDIV
-#define TWI0_CLKDIV TWI_CLKDIV
-#endif
-static volatile struct twi_regs *twi = (void *)TWI0_CLKDIV;
-
-#ifdef DEBUG
-# define dmemset(s, c, n) memset(s, c, n)
-#else
-# define dmemset(s, c, n)
-#endif
-#define debugi(fmt, args...) \
- debug( \
- "MSTAT:0x%03x FSTAT:0x%x ISTAT:0x%02x\t%-20s:%-3i: " fmt "\n", \
- twi->master_stat, twi->fifo_stat, twi->int_stat, \
- __func__, __LINE__, ## args)
-
-#ifdef CONFIG_TWICLK_KHZ
-# error do not define CONFIG_TWICLK_KHZ ... use CONFIG_SYS_I2C_SPEED
-#endif
-
-/*
- * The way speed is changed into duty often results in integer truncation
- * with 50% duty, so we'll force rounding up to the next duty by adding 1
- * to the max. In practice this will get us a speed of something like
- * 385 KHz. The other limit is easy to handle as it is only 8 bits.
- */
-#define I2C_SPEED_MAX 400000
-#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed))
-#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
-#define I2C_DUTY_MIN 0xff /* 8 bit limited */
-#define SYS_I2C_DUTY I2C_SPEED_TO_DUTY(CONFIG_SYS_I2C_SPEED)
-/* Note: duty is inverse of speed, so the comparisons below are correct */
-#if SYS_I2C_DUTY < I2C_DUTY_MAX || SYS_I2C_DUTY > I2C_DUTY_MIN
-# error "The Blackfin I2C hardware can only operate 20KHz - 400KHz"
-#endif
-
-/* All transfers are described by this data structure */
-struct i2c_msg {
- u8 flags;
-#define I2C_M_COMBO 0x4
-#define I2C_M_STOP 0x2
-#define I2C_M_READ 0x1
- int len; /* msg length */
- u8 *buf; /* pointer to msg data */
- int alen; /* addr length */
- u8 *abuf; /* addr buffer */
-};
-
-/* Allow msec timeout per ~byte transfer */
-#define I2C_TIMEOUT 10
-
-/**
- * wait_for_completion - manage the actual i2c transfer
- * @msg: the i2c msg
- */
-static int wait_for_completion(struct i2c_msg *msg)
-{
- uint16_t int_stat;
- ulong timebase = get_timer(0);
-
- do {
- int_stat = twi->int_stat;
-
- if (int_stat & XMTSERV) {
- debugi("processing XMTSERV");
- twi->int_stat = XMTSERV;
- SSYNC();
- if (msg->alen) {
- twi->xmt_data8 = *(msg->abuf++);
- --msg->alen;
- } else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
- twi->xmt_data8 = *(msg->buf++);
- --msg->len;
- } else {
- twi->master_ctl |= (msg->flags & I2C_M_COMBO) ? RSTART | MDIR : STOP;
- SSYNC();
- }
- }
- if (int_stat & RCVSERV) {
- debugi("processing RCVSERV");
- twi->int_stat = RCVSERV;
- SSYNC();
- if (msg->len) {
- *(msg->buf++) = twi->rcv_data8;
- --msg->len;
- } else if (msg->flags & I2C_M_STOP) {
- twi->master_ctl |= STOP;
- SSYNC();
- }
- }
- if (int_stat & MERR) {
- debugi("processing MERR");
- twi->int_stat = MERR;
- SSYNC();
- return msg->len;
- }
- if (int_stat & MCOMP) {
- debugi("processing MCOMP");
- twi->int_stat = MCOMP;
- SSYNC();
- if (msg->flags & I2C_M_COMBO && msg->len) {
- twi->master_ctl = (twi->master_ctl & ~RSTART) |
- (min(msg->len, 0xff) << 6) | MEN | MDIR;
- SSYNC();
- } else
- break;
- }
-
- /* If we were able to do something, reset timeout */
- if (int_stat)
- timebase = get_timer(0);
-
- } while (get_timer(timebase) < I2C_TIMEOUT);
-
- return msg->len;
-}
-
-/**
- * i2c_transfer - setup an i2c transfer
- * @return: 0 if things worked, non-0 if things failed
- *
- * Here we just get the i2c stuff all prepped and ready, and then tail off
- * into wait_for_completion() for all the bits to go.
- */
-static int i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer, int len, u8 flags)
-{
- uchar addr_buffer[] = {
- (addr >> 0),
- (addr >> 8),
- (addr >> 16),
- };
- struct i2c_msg msg = {
- .flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
- .buf = buffer,
- .len = len,
- .abuf = addr_buffer,
- .alen = alen,
- };
- int ret;
-
- dmemset(buffer, 0xff, len);
- debugi("chip=0x%x addr=0x%02x alen=%i buf[0]=0x%02x len=%i flags=0x%02x[%s] ",
- chip, addr, alen, buffer[0], len, flags, (flags & I2C_M_READ ? "rd" : "wr"));
-
- /* wait for things to settle */
- while (twi->master_stat & BUSBUSY)
- if (ctrlc())
- return 1;
-
- /* Set Transmit device address */
- twi->master_addr = chip;
-
- /* Clear the FIFO before starting things */
- twi->fifo_ctl = XMTFLUSH | RCVFLUSH;
- SSYNC();
- twi->fifo_ctl = 0;
- SSYNC();
-
- /* prime the pump */
- if (msg.alen) {
- len = (msg.flags & I2C_M_COMBO) ? msg.alen : msg.alen + len;
- debugi("first byte=0x%02x", *msg.abuf);
- twi->xmt_data8 = *(msg.abuf++);
- --msg.alen;
- } else if (!(msg.flags & I2C_M_READ) && msg.len) {
- debugi("first byte=0x%02x", *msg.buf);
- twi->xmt_data8 = *(msg.buf++);
- --msg.len;
- }
-
- /* clear int stat */
- twi->master_stat = -1;
- twi->int_stat = -1;
- twi->int_mask = 0;
- SSYNC();
-
- /* Master enable */
- twi->master_ctl =
- (twi->master_ctl & FAST) |
- (min(len, 0xff) << 6) | MEN |
- ((msg.flags & I2C_M_READ) ? MDIR : 0);
- SSYNC();
- debugi("CTL=0x%04x", twi->master_ctl);
-
- /* process the rest */
- ret = wait_for_completion(&msg);
- debugi("ret=%d", ret);
-
- if (ret) {
- twi->master_ctl &= ~MEN;
- twi->control &= ~TWI_ENA;
- SSYNC();
- twi->control |= TWI_ENA;
- SSYNC();
- }
-
- return ret;
-}
-
-/**
- * i2c_set_bus_speed - set i2c bus speed
- * @speed: bus speed (in HZ)
- */
-int i2c_set_bus_speed(unsigned int speed)
-{
- u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
-
- /* Set TWI interface clock */
- if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
- return -1;
- twi->clkdiv = (clkdiv << 8) | (clkdiv & 0xff);
-
- /* Don't turn it on */
- twi->master_ctl = (speed > 100000 ? FAST : 0);
-
- return 0;
-}
-
-/**
- * i2c_get_bus_speed - get i2c bus speed
- * @speed: bus speed (in HZ)
- */
-unsigned int i2c_get_bus_speed(void)
-{
- /* 10 MHz / (2 * CLKDIV) -> 5 MHz / CLKDIV */
- return 5000000 / (twi->clkdiv & 0xff);
-}
-
-/**
- * i2c_init - initialize the i2c bus
- * @speed: bus speed (in HZ)
- * @slaveaddr: address of device in slave mode (0 - not slave)
- *
- * Slave mode isn't actually implemented. It'll stay that way until
- * we get a real request for it.
- */
-void i2c_init(int speed, int slaveaddr)
-{
- uint8_t prescale = ((get_i2c_clk() / 1000 / 1000 + 5) / 10) & 0x7F;
-
- /* Set TWI internal clock as 10MHz */
- twi->control = prescale;
-
- /* Set TWI interface clock as specified */
- i2c_set_bus_speed(speed);
-
- /* Enable it */
- twi->control = TWI_ENA | prescale;
- SSYNC();
-
- debugi("CONTROL:0x%04x CLKDIV:0x%04x", twi->control, twi->clkdiv);
-
-#if CONFIG_SYS_I2C_SLAVE
-# error I2C slave support not tested/supported
- /* If they want us as a slave, do it */
- if (slaveaddr) {
- twi->slave_addr = slaveaddr;
- twi->slave_ctl = SEN;
- }
-#endif
-}
-
-/**
- * i2c_probe - test if a chip exists at a given i2c address
- * @chip: i2c chip addr to search for
- * @return: 0 if found, non-0 if not found
- */
-int i2c_probe(uchar chip)
-{
- u8 byte;
- return i2c_read(chip, 0, 0, &byte, 1);
-}
-
-/**
- * i2c_read - read data from an i2c device
- * @chip: i2c chip addr
- * @addr: memory (register) address in the chip
- * @alen: byte size of address
- * @buffer: buffer to store data read from chip
- * @len: how many bytes to read
- * @return: 0 on success, non-0 on failure
- */
-int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
-{
- return i2c_transfer(chip, addr, alen, buffer, len, (alen ? I2C_M_COMBO : I2C_M_READ));
-}
-
-/**
- * i2c_write - write data to an i2c device
- * @chip: i2c chip addr
- * @addr: memory (register) address in the chip
- * @alen: byte size of address
- * @buffer: buffer holding data to write to chip
- * @len: how many bytes to write
- * @return: 0 on success, non-0 on failure
- */
-int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
-{
- return i2c_transfer(chip, addr, alen, buffer, len, 0);
-}
-
-/**
- * i2c_set_bus_num - change active I2C bus
- * @bus: bus index, zero based
- * @returns: 0 on success, non-0 on failure
- */
-int i2c_set_bus_num(unsigned int bus)
-{
- switch (bus) {
-#if CONFIG_SYS_MAX_I2C_BUS > 0
- case 0: twi = (void *)TWI0_CLKDIV; return 0;
-#endif
-#if CONFIG_SYS_MAX_I2C_BUS > 1
- case 1: twi = (void *)TWI1_CLKDIV; return 0;
-#endif
-#if CONFIG_SYS_MAX_I2C_BUS > 2
- case 2: twi = (void *)TWI2_CLKDIV; return 0;
-#endif
- default: return -1;
- }
-}
-
-/**
- * i2c_get_bus_num - returns index of active I2C bus
- */
-unsigned int i2c_get_bus_num(void)
-{
- switch ((unsigned long)twi) {
-#if CONFIG_SYS_MAX_I2C_BUS > 0
- case TWI0_CLKDIV: return 0;
-#endif
-#if CONFIG_SYS_MAX_I2C_BUS > 1
- case TWI1_CLKDIV: return 1;
-#endif
-#if CONFIG_SYS_MAX_I2C_BUS > 2
- case TWI2_CLKDIV: return 2;
-#endif
- default: return -1;
- }
-}
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 811033b0b8..ff7f25a0ef 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -38,7 +38,7 @@
* generic value.
*/
#ifndef CONFIG_I2C_TIMEOUT
-#define CONFIG_I2C_TIMEOUT 10000
+#define CONFIG_I2C_TIMEOUT 100000
#endif
#define I2C_READ_BIT 1
@@ -127,7 +127,7 @@ static const struct {
static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev,
unsigned int i2c_clk, unsigned int speed)
{
- unsigned short divider = min(i2c_clk / speed, (unsigned short) -1);
+ unsigned short divider = min(i2c_clk / speed, (unsigned int)USHRT_MAX);
/*
* We want to choose an FDR/DFSR that generates an I2C bus speed that
diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c
new file mode 100644
index 0000000000..aa89f95953
--- /dev/null
+++ b/drivers/i2c/i2c-emul-uclass.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+
+UCLASS_DRIVER(i2c_emul) = {
+ .id = UCLASS_I2C_EMUL,
+ .name = "i2c_emul",
+};
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
new file mode 100644
index 0000000000..005bf8662f
--- /dev/null
+++ b/drivers/i2c/i2c-uclass.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define I2C_MAX_OFFSET_LEN 4
+
+/**
+ * i2c_setup_offset() - Set up a new message with a chip offset
+ *
+ * @chip: Chip to use
+ * @offset: Byte offset within chip
+ * @offset_buf: Place to put byte offset
+ * @msg: Message buffer
+ * @return 0 if OK, -EADDRNOTAVAIL if the offset length is 0. In that case the
+ * message is still set up but will not contain an offset.
+ */
+static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
+ uint8_t offset_buf[], struct i2c_msg *msg)
+{
+ int offset_len;
+
+ msg->addr = chip->chip_addr;
+ msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+ msg->len = chip->offset_len;
+ msg->buf = offset_buf;
+ if (!chip->offset_len)
+ return -EADDRNOTAVAIL;
+ assert(chip->offset_len <= I2C_MAX_OFFSET_LEN);
+ offset_len = chip->offset_len;
+ while (offset_len--)
+ *offset_buf++ = offset >> (8 * offset_len);
+
+ return 0;
+}
+
+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 udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[2], *ptr;
+ uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+ int ret;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
+ return -EINVAL;
+ ptr = msg + 1;
+ ptr->addr = chip->chip_addr;
+ ptr->flags = msg->flags | I2C_M_RD;
+ ptr->len = 1;
+ ptr->buf = &buffer[i];
+ ptr++;
+
+ ret = ops->xfer(bus, msg, ptr - msg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+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 udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[1];
+ uint8_t buf[I2C_MAX_OFFSET_LEN + 1];
+ int ret;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i2c_setup_offset(chip, offset + i, buf, msg))
+ return -EINVAL;
+ buf[msg->len++] = buffer[i];
+
+ ret = ops->xfer(bus, msg, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
+{
+ struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[2], *ptr;
+ uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+ int msg_count;
+
+ if (!ops->xfer)
+ return -ENOSYS;
+ if (chip->flags & DM_I2C_CHIP_RD_ADDRESS)
+ return i2c_read_bytewise(dev, offset, buffer, len);
+ ptr = msg;
+ if (!i2c_setup_offset(chip, offset, offset_buf, ptr))
+ ptr++;
+
+ if (len) {
+ ptr->addr = chip->chip_addr;
+ ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+ ptr->flags |= I2C_M_RD;
+ ptr->len = len;
+ ptr->buf = buffer;
+ ptr++;
+ }
+ msg_count = ptr - msg;
+
+ return ops->xfer(bus, msg, msg_count);
+}
+
+int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
+{
+ struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[1];
+
+ if (!ops->xfer)
+ return -ENOSYS;
+
+ if (chip->flags & DM_I2C_CHIP_WR_ADDRESS)
+ return i2c_write_bytewise(dev, offset, buffer, len);
+ /*
+ * The simple approach would be to send two messages here: one to
+ * set the offset and one to write the bytes. However some drivers
+ * will not be expecting this, and some chips won't like how the
+ * driver presents this on the I2C bus.
+ *
+ * The API does not support separate offset and data. We could extend
+ * it with a flag indicating that there is data in the next message
+ * that needs to be processed in the same transaction. We could
+ * instead add an additional buffer to each message. For now, handle
+ * this in the uclass since it isn't clear what the impact on drivers
+ * would be with this extra complication. Unfortunately this means
+ * copying the message.
+ *
+ * Use the stack for small messages, malloc() for larger ones. We
+ * need to allow space for the offset (up to 4 bytes) and the message
+ * itself.
+ */
+ if (len < 64) {
+ uint8_t buf[I2C_MAX_OFFSET_LEN + len];
+
+ i2c_setup_offset(chip, offset, buf, msg);
+ msg->len += len;
+ memcpy(buf + chip->offset_len, buffer, len);
+
+ return ops->xfer(bus, msg, 1);
+ } else {
+ uint8_t *buf;
+ int ret;
+
+ buf = malloc(I2C_MAX_OFFSET_LEN + len);
+ if (!buf)
+ return -ENOMEM;
+ i2c_setup_offset(chip, offset, buf, msg);
+ msg->len += len;
+ memcpy(buf + chip->offset_len, buffer, len);
+
+ ret = ops->xfer(bus, msg, 1);
+ free(buf);
+ return ret;
+ }
+}
+
+/**
+ * i2c_probe_chip() - probe for a chip on a bus
+ *
+ * @bus: Bus to probe
+ * @chip_addr: Chip address to probe
+ * @flags: Flags for the chip
+ * @return 0 if found, -ENOSYS if the driver is invalid, -EREMOTEIO if the chip
+ * does not respond to probe
+ */
+static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ enum dm_i2c_chip_flags chip_flags)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct i2c_msg msg[1];
+ int ret;
+
+ if (ops->probe_chip) {
+ ret = ops->probe_chip(bus, chip_addr, chip_flags);
+ if (!ret || ret != -ENOSYS)
+ return ret;
+ }
+
+ if (!ops->xfer)
+ return -ENOSYS;
+
+ /* Probe with a zero-length message */
+ msg->addr = chip_addr;
+ msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
+ msg->len = 0;
+ msg->buf = NULL;
+
+ return ops->xfer(bus, msg, 1);
+}
+
+static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
+ struct udevice **devp)
+{
+ struct dm_i2c_chip chip;
+ char name[30], *str;
+ struct udevice *dev;
+ int ret;
+
+ snprintf(name, sizeof(name), "generic_%x", chip_addr);
+ str = strdup(name);
+ ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev);
+ debug("%s: device_bind_driver: ret=%d\n", __func__, ret);
+ if (ret)
+ 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);
+ if (ret)
+ goto err_probe;
+
+ *devp = dev;
+ return 0;
+
+err_probe:
+ device_unbind(dev);
+err_bind:
+ free(str);
+ return ret;
+}
+
+int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ debug("%s: Searching bus '%s' for address %02x: ", __func__,
+ 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);
+ 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);
+ if (ret)
+ return ret;
+ *devp = dev;
+ return 0;
+ }
+ }
+ debug("not found\n");
+ return i2c_bind_driver(bus, chip_addr, devp);
+}
+
+int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
+ if (ret) {
+ debug("Cannot find I2C bus %d\n", busnum);
+ return ret;
+ }
+ ret = i2c_get_chip(bus, chip_addr, devp);
+ if (ret) {
+ debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
+ busnum);
+ return ret;
+ }
+
+ return 0;
+}
+
+int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
+ struct udevice **devp)
+{
+ int ret;
+
+ *devp = NULL;
+
+ /* First probe that chip */
+ ret = i2c_probe_chip(bus, chip_addr, chip_flags);
+ debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
+ chip_addr, ret);
+ if (ret)
+ return ret;
+
+ /* The chip was found, see if we have a driver, and probe it */
+ ret = i2c_get_chip(bus, chip_addr, devp);
+ debug("%s: i2c_get_chip: ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct dm_i2c_bus *i2c = bus->uclass_priv;
+ int ret;
+
+ /*
+ * If we have a method, call it. If not then the driver probably wants
+ * to deal with speed changes on the next transfer. It can easily read
+ * the current speed from this uclass
+ */
+ if (ops->set_bus_speed) {
+ ret = ops->set_bus_speed(bus, speed);
+ if (ret)
+ return ret;
+ }
+ i2c->speed_hz = speed;
+
+ return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ * Returns speed of selected I2C bus in Hz
+ */
+int i2c_get_bus_speed(struct udevice *bus)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+ struct dm_i2c_bus *i2c = bus->uclass_priv;
+
+ if (!ops->get_bus_speed)
+ return i2c->speed_hz;
+
+ return ops->get_bus_speed(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_ops *ops = i2c_get_ops(bus);
+ int ret;
+
+ if (ops->set_flags) {
+ ret = ops->set_flags(dev, flags);
+ if (ret)
+ return ret;
+ }
+ chip->flags = flags;
+
+ return 0;
+}
+
+int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
+{
+ struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+
+ *flagsp = chip->flags;
+
+ return 0;
+}
+
+int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
+{
+ struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+
+ if (offset_len > I2C_MAX_OFFSET_LEN)
+ return -EINVAL;
+ chip->offset_len = offset_len;
+
+ return 0;
+}
+
+int i2c_deblock(struct udevice *bus)
+{
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+
+ /*
+ * We could implement a software deblocking here if we could get
+ * access to the GPIOs used by I2C, and switch them to GPIO mode
+ * and then back to I2C. This is somewhat beyond our powers in
+ * driver model at present, so for now just fail.
+ *
+ * See https://patchwork.ozlabs.org/patch/399040/
+ */
+ if (!ops->deblock)
+ return -ENOSYS;
+
+ return ops->deblock(bus);
+}
+
+int i2c_chip_ofdata_to_platdata(const void *blob, int node,
+ struct dm_i2c_chip *chip)
+{
+ chip->offset_len = 1; /* default */
+ chip->flags = 0;
+ chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
+ if (chip->chip_addr == -1) {
+ debug("%s: I2C Node '%s' has no 'reg' property\n", __func__,
+ fdt_get_name(blob, node, NULL));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int i2c_post_probe(struct udevice *dev)
+{
+ struct dm_i2c_bus *i2c = dev->uclass_priv;
+
+ i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "clock-frequency", 100000);
+
+ return i2c_set_bus_speed(dev, i2c->speed_hz);
+}
+
+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);
+}
+
+UCLASS_DRIVER(i2c) = {
+ .id = UCLASS_I2C,
+ .name = "i2c",
+ .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+ .post_bind = i2c_post_bind,
+ .post_probe = i2c_post_probe,
+};
+
+UCLASS_DRIVER(i2c_generic) = {
+ .id = UCLASS_I2C_GENERIC,
+ .name = "i2c_generic",
+};
+
+U_BOOT_DRIVER(i2c_generic_chip_drv) = {
+ .name = "i2c_generic_chip_drv",
+ .id = UCLASS_I2C_GENERIC,
+};
diff --git a/drivers/i2c/i2c_core.c b/drivers/i2c/i2c_core.c
index 18d6736601..41cc3b8fa4 100644
--- a/drivers/i2c/i2c_core.c
+++ b/drivers/i2c/i2c_core.c
@@ -174,11 +174,11 @@ static int i2c_mux_set_all(void)
return 0;
}
-static int i2c_mux_disconnet_all(void)
+static int i2c_mux_disconnect_all(void)
{
struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
int i;
- uint8_t buf;
+ uint8_t buf = 0;
if (I2C_ADAP->init_done == 0)
return 0;
@@ -197,7 +197,7 @@ static int i2c_mux_disconnet_all(void)
ret = I2C_ADAP->write(I2C_ADAP, chip, 0, 0, &buf, 1);
if (ret != 0) {
- printf("i2c: mux diconnect error\n");
+ printf("i2c: mux disconnect error\n");
return ret;
}
} while (i > 0);
@@ -229,11 +229,9 @@ static void i2c_init_bus(unsigned int bus_no, int speed, int slaveaddr)
}
/* implement possible board specific board init */
-static void __def_i2c_init_board(void)
+__weak void i2c_init_board(void)
{
}
-void i2c_init_board(void)
- __attribute__((weak, alias("__def_i2c_init_board")));
/*
* i2c_init_all():
@@ -295,7 +293,7 @@ int i2c_set_bus_num(unsigned int bus)
}
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
- i2c_mux_disconnet_all();
+ i2c_mux_disconnect_all();
#endif
gd->cur_i2c_bus = bus;
@@ -395,9 +393,7 @@ void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val)
i2c_write(addr, reg, 1, &val, 1);
}
-void __i2c_init(int speed, int slaveaddr)
+__weak void i2c_init(int speed, int slaveaddr)
{
i2c_init_bus(i2c_get_bus_num(), speed, slaveaddr);
}
-void i2c_init(int speed, int slaveaddr)
- __attribute__((weak, alias("__i2c_init")));
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index 021b2fe511..fc5ee35a1a 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -402,17 +402,6 @@ int bus_i2c_write(void *base, uchar chip, uint addr, int alen,
return ret;
}
-struct i2c_parms {
- void *base;
- void *idle_bus_data;
- int (*idle_bus_fn)(void *p);
-};
-
-struct sram_data {
- unsigned curr_i2c_bus;
- struct i2c_parms i2c_data[3];
-};
-
static void * const i2c_bases[] = {
#if defined(CONFIG_MX25)
(void *)IMX_I2C_BASE,
@@ -439,6 +428,17 @@ static void * const i2c_bases[] = {
#endif
};
+struct i2c_parms {
+ void *base;
+ void *idle_bus_data;
+ int (*idle_bus_fn)(void *p);
+};
+
+struct sram_data {
+ unsigned curr_i2c_bus;
+ struct i2c_parms i2c_data[ARRAY_SIZE(i2c_bases)];
+};
+
void *i2c_get_base(struct i2c_adapter *adap)
{
return i2c_bases[adap->hwadapnr];
diff --git a/drivers/i2c/ppc4xx_i2c.c b/drivers/i2c/ppc4xx_i2c.c
index e7a15ba644..df8888550b 100644
--- a/drivers/i2c/ppc4xx_i2c.c
+++ b/drivers/i2c/ppc4xx_i2c.c
@@ -158,8 +158,7 @@ static void ppc4xx_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
*
* Typical case is a Write of an addr followd by a Read. The
* IBM FAQ does not cover this. On the last byte of the write
- * we don't set the creg CHT bit, and on the first bytes of the
- * read we set the RPST bit.
+ * we don't set the creg CHT bit but the RPST bit.
*
* It does not support address only transfers, there must be
* a data part. If you want to write the address yourself, put
@@ -247,6 +246,10 @@ static int _i2c_transfer(struct i2c_adapter *adap,
if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt))
creg |= IIC_CNTL_CHT;
+ /* last part of address, prepare for repeated start on read */
+ if (cmd_type && (ptr == addr) && ((tran + bc) == cnt))
+ creg |= IIC_CNTL_RPST;
+
if (reading) {
creg |= IIC_CNTL_READ;
} else {
@@ -286,6 +289,27 @@ static int _i2c_transfer(struct i2c_adapter *adap,
/* Transfer aborted? */
if (status & IIC_EXTSTS_XFRA)
result = IIC_NOK_XFRA;
+ /* Is bus free?
+ * If error happened during combined xfer
+ * IIC interface is usually stuck in some strange
+ * state without a valid stop condition.
+ * Brute, but working: generate stop, then soft reset.
+ */
+ if ((status & IIC_EXTSTS_BCS_MASK)
+ != IIC_EXTSTS_BCS_FREE){
+ u8 mdcntl = in_8(&i2c->mdcntl);
+
+ /* Generate valid stop condition */
+ out_8(&i2c->xtcntlss, IIC_XTCNTLSS_SRST);
+ out_8(&i2c->directcntl, IIC_DIRCNTL_SCC);
+ udelay(10);
+ out_8(&i2c->directcntl,
+ IIC_DIRCNTL_SCC | IIC_DIRCNTL_SDAC);
+ out_8(&i2c->xtcntlss, 0);
+
+ ppc4xx_i2c_init(adap, (mdcntl & IIC_MDCNTL_FSM)
+ ? 400000 : 100000, 0);
+ }
} else if ( status & IIC_STS_PT) {
result = IIC_NOK_TOUT;
}
@@ -314,8 +338,6 @@ static int _i2c_transfer(struct i2c_adapter *adap,
cnt = data_len;
tran = 0;
reading = cmd_type;
- if (reading)
- creg = IIC_CNTL_RPST;
}
}
return result;
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c
index 50cebd622b..90ad116a98 100644
--- a/drivers/i2c/rcar_i2c.c
+++ b/drivers/i2c/rcar_i2c.c
@@ -119,10 +119,10 @@ rcar_i2c_raw_read(struct rcar_i2c *dev, u8 chip, uint addr)
/* set slave address, receive */
writel((chip << 1) | 1, &dev->icmar);
- /* clear status */
- writel(0, &dev->icmsr);
/* start master receive */
writel(MCR_MDBS | MCR_MIE | MCR_ESG, &dev->icmcr);
+ /* clear status */
+ writel(0, &dev->icmsr);
while ((readl(&dev->icmsr) & (MSR_MAT | MSR_MDR))
!= (MSR_MAT | MSR_MDR))
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
new file mode 100644
index 0000000000..f0e9f51a1f
--- /dev/null
+++ b/drivers/i2c/sandbox_i2c.c
@@ -0,0 +1,111 @@
+/*
+ * Simulate an I2C port
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <asm/test.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct dm_sandbox_i2c_emul_priv {
+ struct udevice *emul;
+};
+
+static int get_emul(struct udevice *dev, struct udevice **devp,
+ struct dm_i2c_ops **opsp)
+{
+ struct dm_i2c_chip *priv;
+ int ret;
+
+ *devp = NULL;
+ *opsp = NULL;
+ priv = dev_get_parentdata(dev);
+ if (!priv->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);
+ if (ret)
+ return ret;
+ }
+ *devp = priv->emul;
+ *opsp = i2c_get_ops(priv->emul);
+
+ return 0;
+}
+
+static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct dm_i2c_bus *i2c = bus->uclass_priv;
+ struct dm_i2c_ops *ops;
+ struct udevice *emul, *dev;
+ bool is_read;
+ int ret;
+
+ /* Special test code to return success but with no emulation */
+ if (msg->addr == SANDBOX_I2C_TEST_ADDR)
+ return 0;
+
+ ret = i2c_get_chip(bus, msg->addr, &dev);
+ if (ret)
+ return ret;
+
+ ret = get_emul(dev, &emul, &ops);
+ if (ret)
+ return ret;
+
+ /*
+ * For testing, don't allow writing above 100KHz for writes and
+ * 400KHz for reads
+ */
+ is_read = nmsgs > 1;
+ if (i2c->speed_hz > (is_read ? 400000 : 100000))
+ return -EINVAL;
+ return ops->xfer(emul, msg, nmsgs);
+}
+
+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" },
+ { }
+};
+
+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 562211e7de..87290c3127 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -7,6 +7,8 @@
*/
#include <common.h>
+#include <dm.h>
+#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <asm/io.h>
@@ -19,6 +21,12 @@
DECLARE_GLOBAL_DATA_PTR;
+enum i2c_type {
+ TYPE_114,
+ TYPE_STD,
+ TYPE_DVC,
+};
+
/* Information about i2c controller */
struct i2c_bus {
int id;
@@ -27,20 +35,17 @@ struct i2c_bus {
int pinmux_config;
struct i2c_control *control;
struct i2c_ctlr *regs;
- int is_dvc; /* DVC type, rather than I2C */
- int is_scs; /* single clock source (T114+) */
+ enum i2c_type type;
int inited; /* bus is inited */
};
-static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS];
-
static void set_packet_mode(struct i2c_bus *i2c_bus)
{
u32 config;
config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
- if (i2c_bus->is_dvc) {
+ if (i2c_bus->type == TYPE_DVC) {
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
writel(config, &dvc->cnfg);
@@ -65,6 +70,9 @@ static void i2c_reset_controller(struct i2c_bus *i2c_bus)
static void i2c_init_controller(struct i2c_bus *i2c_bus)
{
+ if (!i2c_bus->speed)
+ return;
+ debug("%s: speed=%d\n", __func__, i2c_bus->speed);
/*
* Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
* here, in section 23.3.1, but in fact we seem to need a factor of
@@ -73,7 +81,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
i2c_bus->speed * 2 * 8);
- if (i2c_bus->is_scs) {
+ if (i2c_bus->type == TYPE_114) {
/*
* T114 I2C went to a single clock source for standard/fast and
* HS clock speeds. The new clock rate setting calculation is:
@@ -98,7 +106,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
i2c_reset_controller(i2c_bus);
/* Configure I2C controller. */
- if (i2c_bus->is_dvc) { /* only for DVC I2C */
+ if (i2c_bus->type == TYPE_DVC) { /* only for DVC I2C */
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
@@ -272,7 +280,7 @@ exit:
return error;
}
-static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
+static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
u32 len, bool end_with_repeated_start)
{
int error;
@@ -286,14 +294,14 @@ static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
- error = send_recv_packets(bus, &trans_info);
+ error = send_recv_packets(i2c_bus, &trans_info);
if (error)
debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
return error;
}
-static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
+static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
u32 len)
{
int error;
@@ -305,52 +313,32 @@ static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
- error = send_recv_packets(bus, &trans_info);
+ error = send_recv_packets(i2c_bus, &trans_info);
if (error)
debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
return error;
}
-#ifndef CONFIG_OF_CONTROL
-#error "Please enable device tree support to use this driver"
-#endif
-
-/**
- * Check that a bus number is valid and return a pointer to it
- *
- * @param bus_num Bus number to check / return
- * @return pointer to bus, if valid, else NULL
- */
-static struct i2c_bus *tegra_i2c_get_bus(struct i2c_adapter *adap)
+static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
- struct i2c_bus *bus;
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
- bus = &i2c_controllers[adap->hwadapnr];
- if (!bus->inited) {
- debug("%s: Bus %u not available\n", __func__, adap->hwadapnr);
- return NULL;
- }
-
- return bus;
-}
-
-static unsigned int tegra_i2c_set_bus_speed(struct i2c_adapter *adap,
- unsigned int speed)
-{
- struct i2c_bus *bus;
-
- bus = tegra_i2c_get_bus(adap);
- if (!bus)
- return 0;
- bus->speed = speed;
- i2c_init_controller(bus);
+ i2c_bus->speed = speed;
+ i2c_init_controller(i2c_bus);
return 0;
}
-static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
+static int tegra_i2c_probe(struct udevice *dev)
{
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
+ bool is_dvc;
+
+ i2c_bus->id = dev->seq;
+ i2c_bus->type = dev_get_of_data(dev);
i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
/*
@@ -358,7 +346,6 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
* far no one needs anything other than the default.
*/
i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
- i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0);
i2c_bus->periph_id = clock_decode_periph_id(blob, node);
/*
@@ -371,107 +358,25 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
* i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
*/
if (i2c_bus->periph_id == -1)
- return -FDT_ERR_NOTFOUND;
+ return -EINVAL;
- return 0;
-}
-
-/*
- * Process a list of nodes, adding them to our list of I2C ports.
- *
- * @param blob fdt blob
- * @param node_list list of nodes to process (any <=0 are ignored)
- * @param count number of nodes to process
- * @param is_dvc 1 if these are DVC ports, 0 if standard I2C
- * @param is_scs 1 if this HW uses a single clock source (T114+)
- * @return 0 if ok, -1 on error
- */
-static int process_nodes(const void *blob, int node_list[], int count,
- int is_dvc, int is_scs)
-{
- struct i2c_bus *i2c_bus;
- int i;
-
- /* build the i2c_controllers[] for each controller */
- for (i = 0; i < count; i++) {
- int node = node_list[i];
-
- if (node <= 0)
- continue;
-
- i2c_bus = &i2c_controllers[i];
- i2c_bus->id = i;
-
- if (i2c_get_config(blob, node, i2c_bus)) {
- printf("i2c_init_board: failed to decode bus %d\n", i);
- return -1;
- }
-
- i2c_bus->is_scs = is_scs;
-
- i2c_bus->is_dvc = is_dvc;
- if (is_dvc) {
- i2c_bus->control =
- &((struct dvc_ctlr *)i2c_bus->regs)->control;
- } else {
- i2c_bus->control = &i2c_bus->regs->control;
- }
- debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
- is_dvc ? "dvc" : "i2c", i, i2c_bus->regs,
- i2c_bus->periph_id, i2c_bus->speed);
- i2c_init_controller(i2c_bus);
- debug("ok\n");
- i2c_bus->inited = 1;
-
- /* Mark position as used */
- node_list[i] = -1;
+ is_dvc = dev_get_of_data(dev) == TYPE_DVC;
+ if (is_dvc) {
+ i2c_bus->control =
+ &((struct dvc_ctlr *)i2c_bus->regs)->control;
+ } else {
+ i2c_bus->control = &i2c_bus->regs->control;
}
+ i2c_init_controller(i2c_bus);
+ debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
+ is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
+ i2c_bus->periph_id, i2c_bus->speed);
return 0;
}
-/* Sadly there is no error return from this function */
-void i2c_init_board(void)
-{
- int node_list[TEGRA_I2C_NUM_CONTROLLERS];
- const void *blob = gd->fdt_blob;
- int count;
-
- /* First check for newer (T114+) I2C ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
- COMPAT_NVIDIA_TEGRA114_I2C, node_list,
- TEGRA_I2C_NUM_CONTROLLERS);
- if (process_nodes(blob, node_list, count, 0, 1))
- return;
-
- /* Now get the older (T20/T30) normal I2C ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
- COMPAT_NVIDIA_TEGRA20_I2C, node_list,
- TEGRA_I2C_NUM_CONTROLLERS);
- if (process_nodes(blob, node_list, count, 0, 0))
- return;
-
- /* Now look for dvc ports */
- count = fdtdec_add_aliases_for_id(blob, "i2c",
- COMPAT_NVIDIA_TEGRA20_DVC, node_list,
- TEGRA_I2C_NUM_CONTROLLERS);
- if (process_nodes(blob, node_list, count, 1, 0))
- return;
-}
-
-static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
-{
- /* No i2c support prior to relocation */
- if (!(gd->flags & GD_FLG_RELOC))
- return;
-
- /* This will override the speed selected in the fdt for that port */
- debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
- i2c_set_bus_speed(speed);
-}
-
/* i2c write version without the register address */
-static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer,
+static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
int len, bool end_with_repeated_start)
{
int rc;
@@ -484,7 +389,7 @@ static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer,
debug("\n");
/* Shift 7-bit address over for lower-level i2c functions */
- rc = tegra_i2c_write_data(bus, chip << 1, buffer, len,
+ rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len,
end_with_repeated_start);
if (rc)
debug("i2c_write_data(): rc=%d\n", rc);
@@ -493,14 +398,14 @@ static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer,
}
/* i2c read version without the register address */
-static int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer,
- int len)
+static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
+ int len)
{
int rc;
debug("inside i2c_read_data():\n");
/* Shift 7-bit address over for lower-level i2c functions */
- rc = tegra_i2c_read_data(bus, chip << 1, buffer, len);
+ rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len);
if (rc) {
debug("i2c_read_data(): rc=%d\n", rc);
return rc;
@@ -516,132 +421,99 @@ static int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer,
}
/* Probe to see if a chip is present. */
-static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip)
+static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
{
- struct i2c_bus *bus;
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
int rc;
- uchar reg;
-
- debug("i2c_probe: addr=0x%x\n", chip);
- bus = tegra_i2c_get_bus(adap);
- if (!bus)
- return 1;
- reg = 0;
- rc = i2c_write_data(bus, chip, &reg, 1, false);
- if (rc) {
- debug("Error probing 0x%x.\n", chip);
- return 1;
- }
- return 0;
-}
+ u8 reg;
-static int i2c_addr_ok(const uint addr, const int alen)
-{
- /* We support 7 or 10 bit addresses, so one or two bytes each */
- return alen == 1 || alen == 2;
+ /* Shift 7-bit address over for lower-level i2c functions */
+ rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, &reg, sizeof(reg),
+ false);
+
+ return rc;
}
-/* Read bytes */
-static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
- int alen, uchar *buffer, int len)
+static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
{
- struct i2c_bus *bus;
- uint offset;
- int i;
-
- debug("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n",
- chip, addr, alen, len);
- bus = tegra_i2c_get_bus(adap);
- if (!bus)
- return 1;
- if (!i2c_addr_ok(addr, alen)) {
- debug("i2c_read: Bad address %x.%d.\n", addr, alen);
- return 1;
- }
- for (offset = 0; offset < len; offset++) {
- if (alen) {
- uchar data[alen];
- for (i = 0; i < alen; i++) {
- data[alen - i - 1] =
- (addr + offset) >> (8 * i);
- }
- if (i2c_write_data(bus, chip, data, alen, true)) {
- debug("i2c_read: error sending (0x%x)\n",
- addr);
- return 1;
- }
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ 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 (i2c_read_data(bus, chip, buffer + offset, 1)) {
- debug("i2c_read: error reading (0x%x)\n", addr);
- return 1;
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
}
}
return 0;
}
-/* Write bytes */
-static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
- int alen, uchar *buffer, int len)
+int tegra_i2c_get_dvc_bus(struct udevice **busp)
{
- struct i2c_bus *bus;
- uint offset;
- int i;
-
- debug("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n",
- chip, addr, alen, len);
- bus = tegra_i2c_get_bus(adap);
- if (!bus)
- return 1;
- if (!i2c_addr_ok(addr, alen)) {
- debug("i2c_write: Bad address %x.%d.\n", addr, alen);
- return 1;
- }
- for (offset = 0; offset < len; offset++) {
- uchar data[alen + 1];
- for (i = 0; i < alen; i++)
- data[alen - i - 1] = (addr + offset) >> (8 * i);
- data[alen] = buffer[offset];
- if (i2c_write_data(bus, chip, data, alen + 1, false)) {
- debug("i2c_write: error sending (0x%x)\n", addr);
- return 1;
+ struct udevice *bus;
+
+ for (uclass_first_device(UCLASS_I2C, &bus);
+ bus;
+ uclass_next_device(&bus)) {
+ if (dev_get_of_data(bus) == TYPE_DVC) {
+ *busp = bus;
+ return 0;
}
}
- return 0;
+ return -ENODEV;
}
-int tegra_i2c_get_dvc_bus_num(void)
-{
- int i;
+static const struct dm_i2c_ops tegra_i2c_ops = {
+ .xfer = tegra_i2c_xfer,
+ .probe_chip = tegra_i2c_probe_chip,
+ .set_bus_speed = tegra_i2c_set_bus_speed,
+};
- for (i = 0; i < TEGRA_I2C_NUM_CONTROLLERS; i++) {
- struct i2c_bus *bus = &i2c_controllers[i];
+static int tegra_i2c_child_pre_probe(struct udevice *dev)
+{
+ struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
- if (bus->inited && bus->is_dvc)
- return i;
- }
+ if (dev->of_offset == -1)
+ return 0;
+ return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+ i2c_chip);
+}
- return -1;
+static int tegra_i2c_ofdata_to_platdata(struct udevice *dev)
+{
+ return 0;
}
-/*
- * Register soft i2c adapters
- */
-U_BOOT_I2C_ADAP_COMPLETE(tegra0, tegra_i2c_init, tegra_i2c_probe,
- tegra_i2c_read, tegra_i2c_write,
- tegra_i2c_set_bus_speed, 100000, 0, 0)
-U_BOOT_I2C_ADAP_COMPLETE(tegra1, tegra_i2c_init, tegra_i2c_probe,
- tegra_i2c_read, tegra_i2c_write,
- tegra_i2c_set_bus_speed, 100000, 0, 1)
-U_BOOT_I2C_ADAP_COMPLETE(tegra2, tegra_i2c_init, tegra_i2c_probe,
- tegra_i2c_read, tegra_i2c_write,
- tegra_i2c_set_bus_speed, 100000, 0, 2)
-U_BOOT_I2C_ADAP_COMPLETE(tegra3, tegra_i2c_init, tegra_i2c_probe,
- tegra_i2c_read, tegra_i2c_write,
- tegra_i2c_set_bus_speed, 100000, 0, 3)
-#if TEGRA_I2C_NUM_CONTROLLERS > 4
-U_BOOT_I2C_ADAP_COMPLETE(tegra4, tegra_i2c_init, tegra_i2c_probe,
- tegra_i2c_read, tegra_i2c_write,
- tegra_i2c_set_bus_speed, 100000, 0, 4)
-#endif
+static const struct udevice_id tegra_i2c_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
+ { .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
+ { }
+};
+
+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/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c
index 47502b1763..49ee7b2c9b 100644
--- a/drivers/input/cros_ec_keyb.c
+++ b/drivers/input/cros_ec_keyb.c
@@ -18,6 +18,8 @@ DECLARE_GLOBAL_DATA_PTR;
enum {
KBC_MAX_KEYS = 8, /* Maximum keys held down at once */
+ KBC_REPEAT_RATE_MS = 30,
+ KBC_REPEAT_DELAY_MS = 240,
};
static struct keyb {
@@ -26,8 +28,6 @@ static struct keyb {
struct key_matrix matrix; /* The key matrix layer */
int key_rows; /* Number of keyboard rows */
int key_cols; /* Number of keyboard columns */
- unsigned int repeat_delay_ms; /* Time before autorepeat starts */
- unsigned int repeat_rate_ms; /* Autorepeat rate in ms */
int ghost_filter; /* 1 to enable ghost filter, else 0 */
int inited; /* 1 if keyboard is ready */
} config;
@@ -188,8 +188,8 @@ static int cros_ec_keyb_decode_fdt(const void *blob, int node,
* Get keyboard rows and columns - at present we are limited to
* 8 columns by the protocol (one byte per row scan)
*/
- config->key_rows = fdtdec_get_int(blob, node, "google,key-rows", 0);
- config->key_cols = fdtdec_get_int(blob, node, "google,key-columns", 0);
+ config->key_rows = fdtdec_get_int(blob, node, "keypad,num-rows", 0);
+ config->key_cols = fdtdec_get_int(blob, node, "keypad,num-columns", 0);
if (!config->key_rows || !config->key_cols ||
config->key_rows * config->key_cols / 8
> CROS_EC_KEYSCAN_COLS) {
@@ -197,10 +197,6 @@ static int cros_ec_keyb_decode_fdt(const void *blob, int node,
config->key_rows, config->key_cols);
return -1;
}
- config->repeat_delay_ms = fdtdec_get_int(blob, node,
- "google,repeat-delay-ms", 0);
- config->repeat_rate_ms = fdtdec_get_int(blob, node,
- "google,repeat-rate-ms", 0);
config->ghost_filter = fdtdec_get_bool(blob, node,
"google,ghost-filter");
return 0;
@@ -232,8 +228,8 @@ static int cros_ec_init_keyboard(struct stdio_dev *dev)
}
if (cros_ec_keyb_decode_fdt(blob, node, &config))
return -1;
- input_set_delays(&config.input, config.repeat_delay_ms,
- config.repeat_rate_ms);
+ input_set_delays(&config.input, KBC_REPEAT_DELAY_MS,
+ KBC_REPEAT_RATE_MS);
if (key_matrix_init(&config.matrix, config.key_rows,
config.key_cols, config.ghost_filter)) {
debug("%s: cannot init key matrix\n", __func__);
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2f2e48f979..a34972df4e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -15,11 +15,16 @@ obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
obj-$(CONFIG_FSL_IIM) += fsl_iim.o
obj-$(CONFIG_GPIO_LED) += gpio_led.o
+obj-$(CONFIG_I2C_EEPROM) += i2c_eeprom.o
obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
obj-$(CONFIG_NS87308) += ns87308.o
obj-$(CONFIG_PDSP188x) += pdsp188x.o
+ifdef CONFIG_DM_I2C
+obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
+endif
+obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
obj-$(CONFIG_STATUS_LED) += status_led.o
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 521edfd5de..9b4effb2fb 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -701,6 +701,7 @@ static int cros_ec_check_version(struct cros_ec_dev *dev)
/* Try sending a version 3 packet */
dev->protocol_version = 3;
+ req.in_data = 0;
if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
(uint8_t **)&resp, sizeof(*resp)) > 0) {
return 0;
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index e403664bb5..e6dba298b1 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -143,7 +143,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
return -1;
}
- len = min(p[1], din_len);
+ len = min((int)p[1], din_len);
cros_ec_dump_data("in", -1, p, len + 3);
/* Response code is first byte of message */
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
new file mode 100644
index 0000000000..814134a2cb
--- /dev/null
+++ b/drivers/misc/i2c_eeprom.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <i2c.h>
+#include <i2c_eeprom.h>
+
+static int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf,
+ int size)
+{
+ return -ENODEV;
+}
+
+static int i2c_eeprom_write(struct udevice *dev, int offset,
+ const uint8_t *buf, int size)
+{
+ return -ENODEV;
+}
+
+struct i2c_eeprom_ops i2c_eeprom_std_ops = {
+ .read = i2c_eeprom_read,
+ .write = i2c_eeprom_write,
+};
+
+int i2c_eeprom_std_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct udevice_id i2c_eeprom_std_ids[] = {
+ { .compatible = "i2c-eeprom" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_eeprom_std) = {
+ .name = "i2c_eeprom",
+ .id = UCLASS_I2C_EEPROM,
+ .of_match = i2c_eeprom_std_ids,
+ .probe = i2c_eeprom_std_probe,
+ .priv_auto_alloc_size = sizeof(struct i2c_eeprom),
+ .ops = &i2c_eeprom_std_ops,
+};
+
+UCLASS_DRIVER(i2c_eeprom) = {
+ .id = UCLASS_I2C_EEPROM,
+ .name = "i2c_eeprom",
+};
diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c
new file mode 100644
index 0000000000..7343445d42
--- /dev/null
+++ b/drivers/misc/i2c_eeprom_emul.c
@@ -0,0 +1,168 @@
+/*
+ * Simulate an I2C eeprom
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/test.h>
+
+#ifdef DEBUG
+#define debug_buffer print_buffer
+#else
+#define debug_buffer(x, ...)
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sandbox_i2c_flash_plat_data {
+ enum sandbox_i2c_eeprom_test_mode test_mode;
+ const char *filename;
+ int offset_len; /* Length of an offset in bytes */
+ int size; /* Size of data buffer */
+};
+
+struct sandbox_i2c_flash {
+ uint8_t *data;
+};
+
+void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
+ enum sandbox_i2c_eeprom_test_mode mode)
+{
+ struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+
+ plat->test_mode = mode;
+}
+
+void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len)
+{
+ struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+
+ plat->offset_len = offset_len;
+}
+
+static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct sandbox_i2c_flash *priv = dev_get_priv(emul);
+ uint offset = 0;
+
+ debug("\n%s\n", __func__);
+ debug_buffer(0, priv->data, 1, 16, 0);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ struct sandbox_i2c_flash_plat_data *plat =
+ dev_get_platdata(emul);
+ int len;
+ u8 *ptr;
+
+ if (!plat->size)
+ return -ENODEV;
+ if (msg->addr + msg->len > plat->size) {
+ debug("%s: Address %x, len %x is outside range 0..%x\n",
+ __func__, msg->addr, msg->len, plat->size);
+ return -EINVAL;
+ }
+ len = msg->len;
+ debug(" %s: msg->len=%d",
+ msg->flags & I2C_M_RD ? "read" : "write",
+ msg->len);
+ if (msg->flags & I2C_M_RD) {
+ if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
+ len = 1;
+ debug(", offset %x, len %x: ", offset, len);
+ memcpy(msg->buf, priv->data + offset, len);
+ memset(msg->buf + len, '\xff', msg->len - len);
+ debug_buffer(0, msg->buf, 1, msg->len, 0);
+ } else if (len >= plat->offset_len) {
+ int i;
+
+ ptr = msg->buf;
+ for (i = 0; i < plat->offset_len; i++, len--)
+ offset = (offset << 8) | *ptr++;
+ debug(", set offset %x: ", offset);
+ debug_buffer(0, msg->buf, 1, msg->len, 0);
+ if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
+ len = min(len, 1);
+
+ /* For testing, map offsets into our limited buffer */
+ for (i = 24; i > 0; i -= 8) {
+ if (offset > (1 << i)) {
+ offset = (offset >> i) |
+ (offset & ((1 << i) - 1));
+ offset += i;
+ }
+ }
+ memcpy(priv->data + offset, ptr, len);
+ }
+ }
+ debug_buffer(0, priv->data, 1, 16, 0);
+
+ return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_emul_ops = {
+ .xfer = sandbox_i2c_eeprom_xfer,
+};
+
+static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev)
+{
+ struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+
+ plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "sandbox,size", 32);
+ plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset,
+ "sandbox,filename", NULL);
+ if (!plat->filename) {
+ debug("%s: No filename for device '%s'\n", __func__,
+ dev->name);
+ return -EINVAL;
+ }
+ plat->test_mode = SIE_TEST_MODE_NONE;
+ plat->offset_len = 1;
+
+ return 0;
+}
+
+static int sandbox_i2c_eeprom_probe(struct udevice *dev)
+{
+ struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+ struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+
+ priv->data = calloc(1, plat->size);
+ if (!priv->data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int sandbox_i2c_eeprom_remove(struct udevice *dev)
+{
+ struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+
+ free(priv->data);
+
+ return 0;
+}
+
+static const struct udevice_id sandbox_i2c_ids[] = {
+ { .compatible = "sandbox,i2c-eeprom" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_emul) = {
+ .name = "sandbox_i2c_eeprom_emul",
+ .id = UCLASS_I2C_EMUL,
+ .of_match = sandbox_i2c_ids,
+ .ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata,
+ .probe = sandbox_i2c_eeprom_probe,
+ .remove = sandbox_i2c_eeprom_remove,
+ .priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash),
+ .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data),
+ .ops = &sandbox_i2c_emul_ops,
+};
diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c
index 3de1245699..d92044eeda 100644
--- a/drivers/misc/mxc_ocotp.c
+++ b/drivers/misc/mxc_ocotp.c
@@ -81,8 +81,6 @@ static int finish_access(struct ocotp_regs *regs, const char *caller)
err = !!(readl(&regs->ctrl) & BM_CTRL_ERROR);
clear_error(regs);
- enable_ocotp_clk(0);
-
if (err) {
printf("mxc_ocotp %s(): Access protect error\n", caller);
return -EIO;
@@ -122,8 +120,8 @@ static void set_timing(struct ocotp_regs *regs)
relax = DIV_ROUND_UP(ipg_clk * BV_TIMING_RELAX_NS, 1000000000) - 1;
strobe_read = DIV_ROUND_UP(ipg_clk * BV_TIMING_STROBE_READ_NS,
1000000000) + 2 * (relax + 1) - 1;
- strobe_prog = DIV_ROUND(ipg_clk * BV_TIMING_STROBE_PROG_US, 1000000) +
- 2 * (relax + 1) - 1;
+ strobe_prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_STROBE_PROG_US,
+ 1000000) + 2 * (relax + 1) - 1;
timing = BF(strobe_read, TIMING_STROBE_READ) |
BF(relax, TIMING_RELAX) |
diff --git a/drivers/misc/mxs_ocotp.c b/drivers/misc/mxs_ocotp.c
index 545d3ebf52..6f0a1d3e6d 100644
--- a/drivers/misc/mxs_ocotp.c
+++ b/drivers/misc/mxs_ocotp.c
@@ -187,6 +187,8 @@ static int mxs_ocotp_write_fuse(uint32_t addr, uint32_t mask)
uint32_t hclk_val, vddio_val;
int ret;
+ mxs_ocotp_clear_error();
+
/* Make sure the banks are closed for reading. */
ret = mxs_ocotp_read_bank_open(0);
if (ret) {
@@ -221,13 +223,17 @@ static int mxs_ocotp_write_fuse(uint32_t addr, uint32_t mask)
goto fail;
}
+ /* Check for errors */
+ if (readl(&ocotp_regs->hw_ocotp_ctrl) & OCOTP_CTRL_ERROR) {
+ puts("Failed writing fuses!\n");
+ ret = -EPERM;
+ goto fail;
+ }
+
fail:
mxs_ocotp_scale_vddio(0, &vddio_val);
- ret = mxs_ocotp_scale_hclk(0, &hclk_val);
- if (ret) {
+ if (mxs_ocotp_scale_hclk(0, &hclk_val))
puts("Failed scaling up the HCLK!\n");
- return ret;
- }
return ret;
}
diff --git a/drivers/misc/smsc_lpc47m.c b/drivers/misc/smsc_lpc47m.c
new file mode 100644
index 0000000000..d51f8e3024
--- /dev/null
+++ b/drivers/misc/smsc_lpc47m.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/pnp_def.h>
+
+static void pnp_enter_conf_state(u16 dev)
+{
+ u16 port = dev >> 8;
+
+ outb(0x55, port);
+}
+
+static void pnp_exit_conf_state(u16 dev)
+{
+ u16 port = dev >> 8;
+
+ outb(0xaa, port);
+}
+
+void lpc47m_enable_serial(u16 dev, u16 iobase)
+{
+ pnp_enter_conf_state(dev);
+ pnp_set_logical_device(dev);
+ pnp_set_enable(dev, 0);
+ pnp_set_iobase(dev, PNP_IDX_IO0, iobase);
+ pnp_set_enable(dev, 1);
+ pnp_exit_conf_state(dev);
+}
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 464cee16d1..461d7d8ec1 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -5,37 +5,39 @@
# SPDX-License-Identifier: GPL-2.0+
#
+obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
+obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o
obj-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
+obj-$(CONFIG_DWMMC) += dw_mmc.o
+obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
obj-$(CONFIG_FTSDC010) += ftsdc010_mci.o
obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o
obj-$(CONFIG_GENERIC_MMC) += mmc.o
obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
+obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
-obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
+obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
obj-$(CONFIG_MV_SDHCI) += mv_sdhci.o
+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_PXA_MMC_GENERIC) += pxa_mmc_gen.o
-obj-$(CONFIG_SDHCI) += sdhci.o
-obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
-obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.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_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
-obj-$(CONFIG_DWMMC) += dw_mmc.o
-obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
-obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
-obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
-obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
+
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
else
obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
endif
-obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o
+
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 785eed567c..b18c75dee2 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -318,7 +318,7 @@ static void dwmci_set_ios(struct mmc *mmc)
dwmci_writel(host, DWMCI_CTYPE, ctype);
regs = dwmci_readl(host, DWMCI_UHS_REG);
- if (mmc->card_caps & MMC_MODE_DDR_52MHz)
+ if (mmc->ddr_mode)
regs |= DWMCI_DDR_MODE;
else
regs &= DWMCI_DDR_MODE;
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index d96dfe16a5..dfa209bded 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -101,7 +101,7 @@ static int exynos_dwmci_core_init(struct dwmci_host *host, int index)
host->get_mmc_clk = exynos_dwmci_get_clk;
/* Add the mmc channel to be registered with mmc core */
if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) {
- debug("dwmmc%d registration failed\n", index);
+ printf("DWMMC%d registration failed\n", index);
return -1;
}
return 0;
@@ -146,7 +146,7 @@ static int do_dwmci_init(struct dwmci_host *host)
flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
err = exynos_pinmux_config(host->dev_id, flag);
if (err) {
- debug("DWMMC not configure\n");
+ printf("DWMMC%d not configure\n", index);
return err;
}
@@ -162,21 +162,22 @@ static int exynos_dwmci_get_config(const void *blob, int node,
/* Extract device id for each mmc channel */
host->dev_id = pinmux_decode_periph_id(blob, node);
+ host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id);
+ if (host->dev_index == host->dev_id)
+ host->dev_index = host->dev_id - PERIPH_ID_SDMMC0;
+
+
/* Get the bus width from the device node */
host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
if (host->buswidth <= 0) {
- debug("DWMMC: Can't get bus-width\n");
+ printf("DWMMC%d: Can't get bus-width\n", host->dev_index);
return -EINVAL;
}
- host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id);
- if (host->dev_index == host->dev_id)
- host->dev_index = host->dev_id - PERIPH_ID_SDMMC0;
-
/* Set the base address from the device node */
base = fdtdec_get_addr(blob, node, "reg");
if (!base) {
- debug("DWMMC: Can't get base address\n");
+ printf("DWMMC%d: Can't get base address\n", host->dev_index);
return -EINVAL;
}
host->ioaddr = (void *)base;
@@ -184,7 +185,8 @@ static int exynos_dwmci_get_config(const void *blob, int node,
/* Extract the timing info from the node */
err = fdtdec_get_int_array(blob, node, "samsung,timing", timing, 3);
if (err) {
- debug("Can't get sdr-timings for devider\n");
+ printf("DWMMC%d: Can't get sdr-timings for devider\n",
+ host->dev_index);
return -EINVAL;
}
@@ -214,7 +216,7 @@ static int exynos_dwmci_process_node(const void *blob,
host = &dwmci_host[i];
err = exynos_dwmci_get_config(blob, node, host);
if (err) {
- debug("%s: failed to decode dev %d\n", __func__, i);
+ printf("%s: failed to decode dev %d\n", __func__, i);
return err;
}
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 2640607248..c55eb28217 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -23,6 +23,13 @@
DECLARE_GLOBAL_DATA_PTR;
+#define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \
+ IRQSTATEN_CINT | \
+ IRQSTATEN_CTOE | IRQSTATEN_CCE | IRQSTATEN_CEBE | \
+ IRQSTATEN_CIE | IRQSTATEN_DTOE | IRQSTATEN_DCE | \
+ IRQSTATEN_DEBE | IRQSTATEN_BRR | IRQSTATEN_BWR | \
+ IRQSTATEN_DINT)
+
struct fsl_esdhc {
uint dsaddr; /* SDMA system address register */
uint blkattr; /* Block attributes register */
@@ -558,6 +565,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
esdhc_setbits32(&regs->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN
| SYSCTL_IPGEN | SYSCTL_CKEN);
+ writel(SDHCI_IRQ_EN_BITS, &regs->irqstaten);
memset(&cfg->cfg, 0, sizeof(cfg->cfg));
voltage_caps = 0;
@@ -610,7 +618,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
#endif
cfg->cfg.f_min = 400000;
- cfg->cfg.f_max = min(gd->arch.sdhc_clk, 52000000);
+ cfg->cfg.f_max = min(cfg->sdhc_clk, (u32)52000000);
cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 44a4feb96e..1eb9c27339 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -159,7 +159,7 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
- if (mmc->card_caps & MMC_MODE_DDR_52MHz)
+ if (mmc->ddr_mode)
return 0;
cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
@@ -486,7 +486,7 @@ static int mmc_change_freq(struct mmc *mmc)
char cardtype;
int err;
- mmc->card_caps = 0;
+ mmc->card_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
if (mmc_host_is_spi(mmc))
return 0;
@@ -519,7 +519,7 @@ static int mmc_change_freq(struct mmc *mmc)
/* High Speed is set, there are two types: 52MHz and 26MHz */
if (cardtype & EXT_CSD_CARD_TYPE_52) {
- if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
+ if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
mmc->card_caps |= MMC_MODE_DDR_52MHz;
mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
} else {
@@ -1001,6 +1001,9 @@ static int mmc_startup(struct mmc *mmc)
case 6:
mmc->version = MMC_VERSION_4_5;
break;
+ case 7:
+ mmc->version = MMC_VERSION_5_0;
+ break;
}
/*
@@ -1022,6 +1025,21 @@ static int mmc_startup(struct mmc *mmc)
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
MMC_MAX_BLOCK_LEN * 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)) {
+ capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
+ (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
+ (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
+ (ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
+ capacity *= MMC_MAX_BLOCK_LEN;
+ mmc->capacity_user = capacity;
+ }
} else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
@@ -1103,8 +1121,10 @@ static int mmc_startup(struct mmc *mmc)
/* An array to map CSD bus widths to host cap bits */
static unsigned ext_to_hostcaps[] = {
- [EXT_CSD_DDR_BUS_WIDTH_4] = MMC_MODE_DDR_52MHz,
- [EXT_CSD_DDR_BUS_WIDTH_8] = MMC_MODE_DDR_52MHz,
+ [EXT_CSD_DDR_BUS_WIDTH_4] =
+ MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
+ [EXT_CSD_DDR_BUS_WIDTH_8] =
+ MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
};
@@ -1116,13 +1136,13 @@ static int mmc_startup(struct mmc *mmc)
for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
unsigned int extw = ext_csd_bits[idx];
+ unsigned int caps = ext_to_hostcaps[extw];
/*
- * Check to make sure the controller supports
- * this bus width, if it's more than 1
+ * Check to make sure the card and controller support
+ * these capabilities
*/
- if (extw != EXT_CSD_BUS_WIDTH_1 &&
- !(mmc->cfg->host_caps & ext_to_hostcaps[extw]))
+ if ((mmc->card_caps & caps) != caps)
continue;
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
@@ -1131,26 +1151,33 @@ static int mmc_startup(struct mmc *mmc)
if (err)
continue;
+ mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
mmc_set_bus_width(mmc, widths[idx]);
err = mmc_send_ext_csd(mmc, test_csd);
+
+ if (err)
+ continue;
+
/* Only compare read only fields */
- if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
- == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
- && ext_csd[EXT_CSD_HC_WP_GRP_SIZE] \
- == test_csd[EXT_CSD_HC_WP_GRP_SIZE] \
- && ext_csd[EXT_CSD_REV] \
- == test_csd[EXT_CSD_REV]
- && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
- == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
- && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
- &test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
-
- mmc->card_caps |= ext_to_hostcaps[extw];
+ if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
+ == test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
+ ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
+ == test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
+ ext_csd[EXT_CSD_REV]
+ == test_csd[EXT_CSD_REV] &&
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+ == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
+ memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+ &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
break;
- }
+ else
+ err = SWITCH_ERR;
}
+ if (err)
+ return err;
+
if (mmc->card_caps & MMC_MODE_HS) {
if (mmc->card_caps & MMC_MODE_HS_52MHz)
mmc->tran_speed = 52000000;
@@ -1161,6 +1188,12 @@ static int mmc_startup(struct mmc *mmc)
mmc_set_clock(mmc, mmc->tran_speed);
+ /* Fix the block length for DDR mode */
+ if (mmc->ddr_mode) {
+ mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
+ mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
+ }
+
/* fill in device description */
mmc->block_dev.lun = 0;
mmc->block_dev.type = 0;
@@ -1277,6 +1310,11 @@ block_dev_desc_t *mmc_get_dev(int dev)
}
#endif
+/* board-specific MMC power initializations. */
+__weak void board_mmc_power_init(void)
+{
+}
+
int mmc_start_init(struct mmc *mmc)
{
int err;
@@ -1293,12 +1331,15 @@ int mmc_start_init(struct mmc *mmc)
if (mmc->has_init)
return 0;
+ board_mmc_power_init();
+
/* made sure it's not NULL earlier */
err = mmc->cfg->ops->init(mmc);
if (err)
return err;
+ mmc->ddr_mode = 0;
mmc_set_bus_width(mmc, 1);
mmc_set_clock(mmc, 1);
@@ -1401,8 +1442,11 @@ void print_mmc_devices(char separator)
printf("%s: %d", m->cfg->name, m->block_dev.dev);
- if (entry->next != &mmc_devices)
- printf("%c ", separator);
+ if (entry->next != &mmc_devices) {
+ printf("%c", separator);
+ if (separator != '\n')
+ puts (" ");
+ }
}
printf("\n");
diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c
index 9f98c3f37c..8ca09042d8 100644
--- a/drivers/mmc/mvebu_mmc.c
+++ b/drivers/mmc/mvebu_mmc.c
@@ -1,7 +1,7 @@
/*
* Marvell MMC/SD/SDIO driver
*
- * (C) Copyright 2012
+ * (C) Copyright 2012-2014
* Marvell Semiconductor <www.marvell.com>
* Written-by: Maen Suleiman, Gerald Kerma
*
@@ -23,6 +23,8 @@ DECLARE_GLOBAL_DATA_PTR;
#define MVEBU_TARGET_DRAM 0
+#define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */
+
static void mvebu_mmc_write(u32 offs, u32 val)
{
writel(val, CONFIG_SYS_MMC_BASE + (offs));
@@ -63,37 +65,47 @@ static int mvebu_mmc_setup_data(struct mmc_data *data)
static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
- int timeout = 10;
+ ulong start;
ushort waittype = 0;
ushort resptype = 0;
ushort xfertype = 0;
ushort resp_indx = 0;
- debug("cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n",
- cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
-
- udelay(10*1000);
+ debug("%s: cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n",
+ DRIVER_NAME, cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME,
cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE));
- /* Checking if card is busy */
- while ((mvebu_mmc_read(SDIO_HW_STATE) & CARD_BUSY)) {
- if (timeout == 0) {
- printf("%s: card busy!\n", DRIVER_NAME);
- return -1;
- }
- timeout--;
- udelay(1000);
+ /*
+ * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE
+ * register is sometimes not set before a while when some
+ * "unusual" data block sizes are used (such as with the SWITCH
+ * command), even despite the fact that the XFER_DONE interrupt
+ * was raised. And if another data transfer starts before
+ * this bit comes to good sense (which eventually happens by
+ * itself) then the new transfer simply fails with a timeout.
+ */
+ if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) {
+ ushort hw_state, count = 0;
+
+ start = get_timer(0);
+ do {
+ hw_state = mvebu_mmc_read(SDIO_HW_STATE);
+ if ((get_timer(0) - start) > TIMEOUT_DELAY) {
+ printf("%s : FIFO_EMPTY bit missing\n",
+ DRIVER_NAME);
+ break;
+ }
+ count++;
+ } while (!(hw_state & CMD_FIFO_EMPTY));
+ debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n",
+ DRIVER_NAME, hw_state, count, (get_timer(0) - (start)));
}
- /* Set up for a data transfer if we have one */
- if (data) {
- int err = mvebu_mmc_setup_data(data);
-
- if (err)
- return err;
- }
+ /* Clear status */
+ mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
+ mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
resptype = SDIO_CMD_INDEX(cmd->cmdidx);
@@ -119,6 +131,14 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
if (data) {
+ int err = mvebu_mmc_setup_data(data);
+
+ if (err) {
+ debug("%s: command DATA error :%x\n",
+ DRIVER_NAME, err);
+ return err;
+ }
+
resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16;
xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN;
if (data->flags & MMC_DATA_READ) {
@@ -138,17 +158,10 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
/* Setting Xfer mode */
mvebu_mmc_write(SDIO_XFER_MODE, xfertype);
- mvebu_mmc_write(SDIO_NOR_INTR_STATUS, ~SDIO_NOR_CARD_INT);
- mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
-
/* Sending command */
mvebu_mmc_write(SDIO_CMD, resptype);
- mvebu_mmc_write(SDIO_NOR_INTR_EN, SDIO_POLL_MASK);
- mvebu_mmc_write(SDIO_ERR_INTR_EN, SDIO_POLL_MASK);
-
- /* Waiting for completion */
- timeout = 1000000;
+ start = get_timer(0);
while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) {
if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) {
@@ -156,21 +169,20 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
DRIVER_NAME, cmd->cmdidx,
mvebu_mmc_read(SDIO_ERR_INTR_STATUS));
if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
- (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT))
+ (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) {
+ debug("%s: command READ timed out\n",
+ DRIVER_NAME);
return TIMEOUT;
+ }
+ debug("%s: command READ error\n", DRIVER_NAME);
return COMM_ERR;
}
- timeout--;
- udelay(1);
- if (timeout <= 0) {
- printf("%s: command timed out\n", DRIVER_NAME);
+ if ((get_timer(0) - start) > TIMEOUT_DELAY) {
+ debug("%s: command timed out\n", DRIVER_NAME);
return TIMEOUT;
}
}
- if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
- (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT))
- return TIMEOUT;
/* Handling response */
if (cmd->resp_type & MMC_RSP_136) {
@@ -204,6 +216,11 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
cmd->response[1] = ((response[0] & 0xfc00) >> 10);
cmd->response[2] = 0;
cmd->response[3] = 0;
+ } else {
+ cmd->response[0] = 0;
+ cmd->response[1] = 0;
+ cmd->response[2] = 0;
+ cmd->response[3] = 0;
}
debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type);
@@ -213,6 +230,10 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
debug("[0x%x] ", cmd->response[3]);
debug("\n");
+ if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
+ (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT))
+ return TIMEOUT;
+
return 0;
}
@@ -251,9 +272,8 @@ static void mvebu_mmc_set_clk(unsigned int clock)
if (m > MVEBU_MMC_BASE_DIV_MAX)
m = MVEBU_MMC_BASE_DIV_MAX;
mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX);
+ debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m);
}
-
- udelay(10*1000);
}
static void mvebu_mmc_set_bus(unsigned int bus)
@@ -293,7 +313,6 @@ static void mvebu_mmc_set_bus(unsigned int bus)
"high-speed" : "");
mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg);
- udelay(10*1000);
}
static void mvebu_mmc_set_ios(struct mmc *mmc)
@@ -355,7 +374,7 @@ static void mvebu_window_setup(void)
static int mvebu_mmc_initialize(struct mmc *mmc)
{
- debug("%s: mvebu_mmc_initialize", DRIVER_NAME);
+ debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME);
/*
* Setting host parameters
@@ -384,8 +403,6 @@ static int mvebu_mmc_initialize(struct mmc *mmc)
/* SW reset */
mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
- udelay(10*1000);
-
return 0;
}
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index ef2cbf9e2f..c880cedb0a 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -135,12 +135,7 @@ static unsigned char mmc_board_init(struct mmc *mmc)
pbias_lite = readl(&t2_base->pbias_lite);
pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
writel(pbias_lite, &t2_base->pbias_lite);
-#endif
-#if defined(CONFIG_TWL4030_POWER)
- twl4030_power_mmc_init();
- mdelay(100); /* ramp-up delay from Linux code */
-#endif
-#if defined(CONFIG_OMAP34XX)
+
writel(pbias_lite | PBIASLITEPWRDNZ1 |
PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
&t2_base->pbias_lite);
@@ -611,7 +606,8 @@ static int omap_hsmmc_getcd(struct mmc *mmc)
if (cd_gpio < 0)
return 1;
- return gpio_get_value(cd_gpio);
+ /* NOTE: assumes card detect signal is active-low */
+ return !gpio_get_value(cd_gpio);
}
static int omap_hsmmc_getwp(struct mmc *mmc)
@@ -624,6 +620,7 @@ static int omap_hsmmc_getwp(struct mmc *mmc)
if (wp_gpio < 0)
return 0;
+ /* NOTE: assumes write protect signal is active-high */
return gpio_get_value(wp_gpio);
}
#endif
@@ -661,7 +658,8 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
case 1:
priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
- defined(CONFIG_DRA7XX)) && defined(CONFIG_HSMMC2_8BIT)
+ defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && \
+ defined(CONFIG_HSMMC2_8BIT)
/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
host_caps_val |= MMC_MODE_8BIT;
#endif
@@ -670,7 +668,7 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
#ifdef OMAP_HSMMC3_BASE
case 2:
priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
-#if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT)
+#if (defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && defined(CONFIG_HSMMC3_8BIT)
/* Enable 8-bit interface for eMMC on DRA7XX */
host_caps_val |= MMC_MODE_8BIT;
#endif
diff --git a/drivers/mmc/pxa_mmc_gen.c b/drivers/mmc/pxa_mmc_gen.c
index 1f297571e5..25ab0b1fc8 100644
--- a/drivers/mmc/pxa_mmc_gen.c
+++ b/drivers/mmc/pxa_mmc_gen.c
@@ -197,7 +197,7 @@ static int pxa_mmc_do_read_xfer(struct mmc *mmc, struct mmc_data *data)
while (len) {
/* The controller has data ready */
if (readl(&regs->i_reg) & MMC_I_REG_RXFIFO_RD_REQ) {
- size = min(len, PXAMMC_FIFO_SIZE);
+ size = min(len, (uint32_t)PXAMMC_FIFO_SIZE);
len -= size;
size /= 4;
@@ -233,14 +233,14 @@ static int pxa_mmc_do_write_xfer(struct mmc *mmc, struct mmc_data *data)
while (len) {
/* The controller is ready to receive data */
if (readl(&regs->i_reg) & MMC_I_REG_TXFIFO_WR_REQ) {
- size = min(len, PXAMMC_FIFO_SIZE);
+ size = min(len, (uint32_t)PXAMMC_FIFO_SIZE);
len -= size;
size /= 4;
while (size--)
writel(*buf++, &regs->txfifo);
- if (min(len, PXAMMC_FIFO_SIZE) < 32)
+ if (min(len, (uint32_t)PXAMMC_FIFO_SIZE) < 32)
writel(MMC_PRTBUF_BUF_PART_FULL, &regs->prtbuf);
}
diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c
index ed83a14c2d..76ba93b81d 100644
--- a/drivers/mmc/sh_mmcif.c
+++ b/drivers/mmc/sh_mmcif.c
@@ -103,20 +103,18 @@ static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host)
static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
{
- int i;
-
sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl);
sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl);
if (!clk)
return;
- if (clk == CLKDEV_EMMC_DATA) {
+
+ if (clk == CLKDEV_EMMC_DATA)
sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl);
- } else {
- for (i = 1; (unsigned int)host->clk / (1 << i) >= clk; i++)
- ;
- sh_mmcif_bitset((i - 1) << 16, &host->regs->ce_clk_ctrl);
- }
+ else
+ sh_mmcif_bitset((fls(DIV_ROUND_UP(host->clk,
+ clk) - 1) - 1) << 16,
+ &host->regs->ce_clk_ctrl);
sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl);
}
@@ -581,8 +579,6 @@ static struct mmc_config sh_mmcif_cfg = {
.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT |
MMC_MODE_8BIT | MMC_MODE_HC,
.voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
- .f_min = CLKDEV_MMC_INIT,
- .f_max = CLKDEV_EMMC_DATA,
.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
};
@@ -599,6 +595,9 @@ int mmcif_mmc_init(void)
host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;
host->clk = CONFIG_SH_MMCIF_CLK;
+ sh_mmcif_cfg.f_min = MMC_CLK_DIV_MIN(host->clk);
+ sh_mmcif_cfg.f_max = MMC_CLK_DIV_MAX(host->clk);
+
mmc = mmc_create(&sh_mmcif_cfg, host);
if (mmc == NULL) {
free(host);
diff --git a/drivers/mmc/sh_mmcif.h b/drivers/mmc/sh_mmcif.h
index bd6fbf7c62..4b6752f7f9 100644
--- a/drivers/mmc/sh_mmcif.h
+++ b/drivers/mmc/sh_mmcif.h
@@ -199,7 +199,13 @@ struct sh_mmcif_regs {
#define SOFT_RST_OFF (0 << 31)
#define CLKDEV_EMMC_DATA 52000000 /* 52MHz */
-#define CLKDEV_MMC_INIT 400000 /* 100 - 400 KHz */
+#ifdef CONFIG_RMOBILE
+#define MMC_CLK_DIV_MIN(clk) (clk / (1 << 9))
+#define MMC_CLK_DIV_MAX(clk) (clk / (1 << 1))
+#else
+#define MMC_CLK_DIV_MIN(clk) (clk / (1 << 8))
+#define MMC_CLK_DIV_MAX(clk) CLKDEV_EMMC_DATA
+#endif
#define MMC_BUS_WIDTH_1 0
#define MMC_BUS_WIDTH_4 2
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 16592e3d7c..623498187e 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -22,7 +22,6 @@ struct sunxi_mmc_host {
unsigned mmc_no;
uint32_t *mclkreg;
unsigned fatal_err;
- unsigned mod_clk;
struct sunxi_mmc *reg;
struct mmc_config cfg;
};
@@ -30,10 +29,22 @@ struct sunxi_mmc_host {
/* support 4 mmc hosts */
struct sunxi_mmc_host mmc_host[4];
+static int sunxi_mmc_getcd_gpio(int sdc_no)
+{
+ switch (sdc_no) {
+ case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
+ case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
+ case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
+ case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
+ }
+ return -1;
+}
+
static int mmc_resource_init(int sdc_no)
{
struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no];
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ int cd_pin, ret = 0;
debug("init mmc %d resource\n", sdc_no);
@@ -60,13 +71,73 @@ static int mmc_resource_init(int sdc_no)
}
mmchost->mmc_no = sdc_no;
+ cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
+ if (cd_pin != -1) {
+ ret = gpio_request(cd_pin, "mmc_cd");
+ if (!ret)
+ ret = gpio_direction_input(cd_pin);
+ }
+
+ return ret;
+}
+
+static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz)
+{
+ unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
+
+ if (hz <= 24000000) {
+ pll = CCM_MMC_CTRL_OSCM24;
+ pll_hz = 24000000;
+ } else {
+ pll = CCM_MMC_CTRL_PLL6;
+ pll_hz = clock_get_pll6();
+ }
+
+ div = pll_hz / hz;
+ if (pll_hz % hz)
+ div++;
+
+ n = 0;
+ while (div > 16) {
+ n++;
+ div = (div + 1) / 2;
+ }
+
+ if (n > 3) {
+ printf("mmc %u error cannot set clock to %u\n",
+ mmchost->mmc_no, hz);
+ return -1;
+ }
+
+ /* determine delays */
+ if (hz <= 400000) {
+ oclk_dly = 0;
+ sclk_dly = 7;
+ } else if (hz <= 25000000) {
+ oclk_dly = 0;
+ sclk_dly = 5;
+ } else if (hz <= 50000000) {
+ oclk_dly = 3;
+ sclk_dly = 5;
+ } else {
+ /* hz > 50000000 */
+ oclk_dly = 2;
+ sclk_dly = 4;
+ }
+
+ writel(CCM_MMC_CTRL_ENABLE | pll | CCM_MMC_CTRL_SCLK_DLY(sclk_dly) |
+ CCM_MMC_CTRL_N(n) | CCM_MMC_CTRL_OCLK_DLY(oclk_dly) |
+ CCM_MMC_CTRL_M(div), mmchost->mclkreg);
+
+ debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
+ mmchost->mmc_no, hz, pll_hz, 1u << n, div,
+ pll_hz / (1u << n) / div);
+
return 0;
}
static int mmc_clk_io_on(int sdc_no)
{
- unsigned int pll_clk;
- unsigned int divider;
struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no];
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@@ -75,20 +146,12 @@ 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_SUN6I) || defined(CONFIG_SUN8I)
+#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I)
/* unassert reset */
setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
#endif
- /* config mod clock */
- pll_clk = clock_get_pll6();
- /* should be close to 100 MHz but no more, so round up */
- divider = ((pll_clk + 99999999) / 100000000) - 1;
- writel(CCM_MMC_CTRL_ENABLE | CCM_MMC_CTRL_PLL6 | divider,
- mmchost->mclkreg);
- mmchost->mod_clk = pll_clk / (divider + 1);
-
- return 0;
+ return mmc_set_mod_clk(mmchost, 24000000);
}
static int mmc_update_clk(struct mmc *mmc)
@@ -113,7 +176,7 @@ static int mmc_update_clk(struct mmc *mmc)
return 0;
}
-static int mmc_config_clock(struct mmc *mmc, unsigned div)
+static int mmc_config_clock(struct mmc *mmc)
{
struct sunxi_mmc_host *mmchost = mmc->priv;
unsigned rval = readl(&mmchost->reg->clkcr);
@@ -124,16 +187,17 @@ static int mmc_config_clock(struct mmc *mmc, unsigned div)
if (mmc_update_clk(mmc))
return -1;
- /* Change Divider Factor */
+ /* Set mod_clk to new rate */
+ if (mmc_set_mod_clk(mmchost, mmc->clock))
+ return -1;
+
+ /* Clear internal divider */
rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
- rval |= div;
writel(rval, &mmchost->reg->clkcr);
- if (mmc_update_clk(mmc))
- return -1;
+
/* Re-enable Clock */
rval |= SUNXI_MMC_CLK_ENABLE;
writel(rval, &mmchost->reg->clkcr);
-
if (mmc_update_clk(mmc))
return -1;
@@ -143,18 +207,14 @@ static int mmc_config_clock(struct mmc *mmc, unsigned div)
static void mmc_set_ios(struct mmc *mmc)
{
struct sunxi_mmc_host *mmchost = mmc->priv;
- unsigned int clkdiv = 0;
- debug("set ios: bus_width: %x, clock: %d, mod_clk: %d\n",
- mmc->bus_width, mmc->clock, mmchost->mod_clk);
+ debug("set ios: bus_width: %x, clock: %d\n",
+ mmc->bus_width, mmc->clock);
/* Change clock first */
- clkdiv = (mmchost->mod_clk + (mmc->clock >> 1)) / mmc->clock / 2;
- if (mmc->clock) {
- if (mmc_config_clock(mmc, clkdiv)) {
- mmchost->fatal_err = 1;
- return;
- }
+ if (mmc->clock && mmc_config_clock(mmc) != 0) {
+ mmchost->fatal_err = 1;
+ return;
}
/* Change bus width */
@@ -351,19 +411,13 @@ out:
static int sunxi_mmc_getcd(struct mmc *mmc)
{
struct sunxi_mmc_host *mmchost = mmc->priv;
- int cd_pin = -1;
-
- switch (mmchost->mmc_no) {
- case 0: cd_pin = sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); break;
- case 1: cd_pin = sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); break;
- case 2: cd_pin = sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); break;
- case 3: cd_pin = sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); break;
- }
+ int cd_pin;
+ cd_pin = sunxi_mmc_getcd_gpio(mmchost->mmc_no);
if (cd_pin == -1)
return 1;
- return !gpio_direction_input(cd_pin);
+ return !gpio_get_value(cd_pin);
}
static const struct mmc_ops sunxi_mmc_ops = {
@@ -385,7 +439,7 @@ 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_SUN6I) || defined(CONFIG_SUN7I) || defined(CONFIG_SUN8I)
+#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || defined(CONFIG_MACH_SUN8I)
cfg->host_caps |= MMC_MODE_HC;
#endif
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
@@ -393,7 +447,9 @@ struct mmc *sunxi_mmc_init(int sdc_no)
cfg->f_min = 400000;
cfg->f_max = 52000000;
- mmc_resource_init(sdc_no);
+ if (mmc_resource_init(sdc_no) != 0)
+ return NULL;
+
mmc_clk_io_on(sdc_no);
return mmc_create(cfg, &mmc_host[sdc_no]);
diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c
index ac805ff1e9..709a48642d 100644
--- a/drivers/mtd/cfi_mtd.c
+++ b/drivers/mtd/cfi_mtd.c
@@ -226,6 +226,7 @@ int cfi_mtd_init(void)
mtd->flags = MTD_CAP_NORFLASH;
mtd->size = fi->size;
mtd->writesize = 1;
+ mtd->writebufsize = mtd->writesize;
mtd->_erase = cfi_mtd_erase;
mtd->_read = cfi_mtd_read;
diff --git a/drivers/mtd/jedec_flash.c b/drivers/mtd/jedec_flash.c
index 593b9b8433..ce9af8f254 100644
--- a/drivers/mtd/jedec_flash.c
+++ b/drivers/mtd/jedec_flash.c
@@ -333,6 +333,57 @@ static const struct amd_flash_info jedec_table[] = {
}
},
{
+ .mfr_id = (u16)AMD_MANUFACT,
+ .dev_id = AM29LV800BT,
+ .name = "AMD AM29LV800BT",
+ .uaddr = {
+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = CFI_CMDSET_AMD_LEGACY,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000, 15),
+ ERASEINFO(0x08000, 1),
+ ERASEINFO(0x02000, 2),
+ ERASEINFO(0x04000, 1),
+ }
+ },
+ {
+ .mfr_id = (u16)MX_MANUFACT,
+ .dev_id = AM29LV800BT,
+ .name = "MXIC MX29LV800BT",
+ .uaddr = {
+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = CFI_CMDSET_AMD_LEGACY,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000, 15),
+ ERASEINFO(0x08000, 1),
+ ERASEINFO(0x02000, 2),
+ ERASEINFO(0x04000, 1),
+ }
+ },
+ {
+ .mfr_id = (u16)EON_ALT_MANU,
+ .dev_id = AM29LV800BT,
+ .name = "EON EN29LV800BT",
+ .uaddr = {
+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = CFI_CMDSET_AMD_LEGACY,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000, 15),
+ ERASEINFO(0x08000, 1),
+ ERASEINFO(0x02000, 2),
+ ERASEINFO(0x04000, 1),
+ }
+ },
+ {
.mfr_id = (u16)STM_MANUFACT,
.dev_id = STM29F400BB,
.name = "ST Micro M29F400BB",
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 75c2c065c8..c24221499b 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,9 +1,16 @@
menu "NAND Device Support"
+config SYS_NAND_SELF_INIT
+ bool
+ help
+ This option, if enabled, provides more flexible and linux-like
+ NAND initialization process.
+
if !SPL_BUILD
config NAND_DENALI
bool "Support Denali NAND controller"
+ select SYS_NAND_SELF_INIT
help
Enable support for the Denali NAND controller.
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 9114a86da2..620b6e8ff9 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -18,6 +18,7 @@
#include <malloc.h>
#include <nand.h>
#include <watchdog.h>
+#include <linux/mtd/nand_ecc.h>
#ifdef CONFIG_ATMEL_NAND_HWECC
@@ -762,6 +763,62 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
}
#endif
+#if defined(NO_GALOIS_TABLE_IN_ROM)
+static uint16_t *pmecc_galois_table;
+static inline int deg(unsigned int poly)
+{
+ /* polynomial degree is the most-significant bit index */
+ return fls(poly) - 1;
+}
+
+static int build_gf_tables(int mm, unsigned int poly,
+ int16_t *index_of, int16_t *alpha_to)
+{
+ unsigned int i, x = 1;
+ const unsigned int k = 1 << deg(poly);
+ unsigned int nn = (1 << mm) - 1;
+
+ /* primitive polynomial must be of degree m */
+ if (k != (1u << mm))
+ return -EINVAL;
+
+ for (i = 0; i < nn; i++) {
+ alpha_to[i] = x;
+ index_of[x] = i;
+ if (i && (x == 1))
+ /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
+ return -EINVAL;
+ x <<= 1;
+ if (x & k)
+ x ^= poly;
+ }
+
+ alpha_to[nn] = 1;
+ index_of[0] = 0;
+
+ return 0;
+}
+
+static uint16_t *create_lookup_table(int sector_size)
+{
+ int degree = (sector_size == 512) ?
+ PMECC_GF_DIMENSION_13 :
+ PMECC_GF_DIMENSION_14;
+ unsigned int poly = (sector_size == 512) ?
+ PMECC_GF_13_PRIMITIVE_POLY :
+ PMECC_GF_14_PRIMITIVE_POLY;
+ int table_size = (sector_size == 512) ?
+ PMECC_INDEX_TABLE_SIZE_512 :
+ PMECC_INDEX_TABLE_SIZE_1024;
+
+ int16_t *addr = kzalloc(2 * table_size * sizeof(uint16_t), GFP_KERNEL);
+ if (addr && build_gf_tables(degree, poly, addr, addr + table_size))
+ return NULL;
+
+ return (uint16_t *)addr;
+}
+#endif
+
static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
struct mtd_info *mtd)
{
@@ -809,11 +866,18 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
sector_size = host->pmecc_sector_size;
/* TODO: need check whether cap & sector_size is validate */
-
+#if defined(NO_GALOIS_TABLE_IN_ROM)
+ /*
+ * As pmecc_rom_base is the begin of the gallois field table, So the
+ * index offset just set as 0.
+ */
+ host->pmecc_index_table_offset = 0;
+#else
if (host->pmecc_sector_size == 512)
host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_512;
else
host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_1024;
+#endif
MTDDEBUG(MTD_DEBUG_LEVEL1,
"Initialize PMECC params, cap: %d, sector: %d\n",
@@ -822,7 +886,17 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC;
host->pmerrloc = (struct pmecc_errloc_regs __iomem *)
ATMEL_BASE_PMERRLOC;
+#if defined(NO_GALOIS_TABLE_IN_ROM)
+ pmecc_galois_table = create_lookup_table(host->pmecc_sector_size);
+ if (!pmecc_galois_table) {
+ dev_err(host->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+
+ host->pmecc_rom_base = (void __iomem *)pmecc_galois_table;
+#else
host->pmecc_rom_base = (void __iomem *) ATMEL_BASE_ROM;
+#endif
/* ECC is calculated for the whole page (1 step) */
nand->ecc.size = mtd->writesize;
@@ -1187,7 +1261,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd)
void (*hwctrl)(struct mtd_info *mtd, int cmd,
unsigned int ctrl) = this->cmd_ctrl;
- while (this->dev_ready(&mtd))
+ while (!this->dev_ready(&mtd))
;
if (cmd == NAND_CMD_READOOB) {
@@ -1212,7 +1286,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd)
hwctrl(&mtd, NAND_CMD_READSTART, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
- while (this->dev_ready(&mtd))
+ while (!this->dev_ready(&mtd))
;
return 0;
@@ -1273,6 +1347,39 @@ static int nand_read_page(int block, int page, void *dst)
return 0;
}
+
+int spl_nand_erase_one(int block, int page)
+{
+ struct nand_chip *this = mtd.priv;
+ void (*hwctrl)(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl) = this->cmd_ctrl;
+ int page_addr;
+
+ if (nand_chip.select_chip)
+ nand_chip.select_chip(&mtd, 0);
+
+ page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+ hwctrl(&mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ /* Row address */
+ hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+ hwctrl(&mtd, ((page_addr >> 8) & 0xff),
+ NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
+ /* One more address cycle for devices > 128MiB */
+ hwctrl(&mtd, (page_addr >> 16) & 0x0f,
+ NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+#endif
+
+ hwctrl(&mtd, NAND_CMD_ERASE2, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ udelay(2000);
+
+ while (!this->dev_ready(&mtd))
+ ;
+
+ nand_deselect();
+
+ return 0;
+}
#else
static int nand_read_page(int block, int page, void *dst)
{
@@ -1319,7 +1426,7 @@ int at91_nand_wait_ready(struct mtd_info *mtd)
udelay(this->chip_delay);
- return 0;
+ return 1;
}
int board_nand_init(struct nand_chip *nand)
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
index 92d4ec59fd..eac860d13c 100644
--- a/drivers/mtd/nand/atmel_nand_ecc.h
+++ b/drivers/mtd/nand/atmel_nand_ecc.h
@@ -141,6 +141,10 @@ struct pmecc_errloc_regs {
#define PMECC_GF_DIMENSION_13 13
#define PMECC_GF_DIMENSION_14 14
+/* Primitive Polynomial used by PMECC */
+#define PMECC_GF_13_PRIMITIVE_POLY 0x201b
+#define PMECC_GF_14_PRIMITIVE_POLY 0x4443
+
#define PMECC_INDEX_TABLE_SIZE_512 0x2000
#define PMECC_INDEX_TABLE_SIZE_1024 0x4000
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 308b7845f1..9e0429aa19 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -44,7 +44,7 @@ static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
* this macro allows us to convert from an MTD structure to our own
* device context (denali) structure.
*/
-#define mtd_to_denali(m) (((struct nand_chip *)mtd->priv)->priv)
+#define mtd_to_denali(m) container_of(m->priv, struct denali_nand_info, nand)
/* These constants are defined by the driver to enable common driver
* configuration options. */
@@ -1144,70 +1144,128 @@ static void denali_hw_init(struct denali_nand_info *denali)
static struct nand_ecclayout nand_oob;
-static int denali_nand_init(struct nand_chip *nand)
+static int denali_init(struct denali_nand_info *denali)
{
- struct denali_nand_info *denali;
+ int ret;
- denali = malloc(sizeof(*denali));
- if (!denali)
- return -ENOMEM;
+ denali_hw_init(denali);
- nand->priv = denali;
+ denali->mtd->name = "denali-nand";
+ denali->mtd->owner = THIS_MODULE;
+ denali->mtd->priv = &denali->nand;
- denali->flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
- denali->flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
+ /* register the driver with the NAND core subsystem */
+ denali->nand.select_chip = denali_select_chip;
+ denali->nand.cmdfunc = denali_cmdfunc;
+ denali->nand.read_byte = denali_read_byte;
+ denali->nand.read_buf = denali_read_buf;
+ denali->nand.waitfunc = denali_waitfunc;
+
+ /*
+ * scan for NAND devices attached to the controller
+ * this is the first stage in a two step process to register
+ * with the nand subsystem
+ */
+ if (nand_scan_ident(denali->mtd, denali->max_banks, NULL)) {
+ ret = -ENXIO;
+ goto fail;
+ }
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
/* check whether flash got BBT table (located at end of flash). As we
* use NAND_BBT_NO_OOB, the BBT page will start with
* bbt_pattern. We will have mirror pattern too */
- nand->bbt_options |= NAND_BBT_USE_FLASH;
+ denali->nand.bbt_options |= NAND_BBT_USE_FLASH;
/*
* We are using main + spare with ECC support. As BBT need ECC support,
* we need to ensure BBT code don't write to OOB for the BBT pattern.
* All BBT info will be stored into data area with ECC support.
*/
- nand->bbt_options |= NAND_BBT_NO_OOB;
+ denali->nand.bbt_options |= NAND_BBT_NO_OOB;
#endif
- nand->ecc.mode = NAND_ECC_HW;
- nand->ecc.size = CONFIG_NAND_DENALI_ECC_SIZE;
- nand->ecc.read_oob = denali_read_oob;
- nand->ecc.write_oob = denali_write_oob;
- nand->ecc.read_page = denali_read_page;
- nand->ecc.read_page_raw = denali_read_page_raw;
- nand->ecc.write_page = denali_write_page;
- nand->ecc.write_page_raw = denali_write_page_raw;
+ denali->nand.ecc.mode = NAND_ECC_HW;
+ denali->nand.ecc.size = CONFIG_NAND_DENALI_ECC_SIZE;
+
/*
* Tell driver the ecc strength. This register may be already set
* correctly. So we read this value out.
*/
- nand->ecc.strength = readl(denali->flash_reg + ECC_CORRECTION);
- switch (nand->ecc.size) {
+ denali->nand.ecc.strength = readl(denali->flash_reg + ECC_CORRECTION);
+ switch (denali->nand.ecc.size) {
case 512:
- nand->ecc.bytes = (nand->ecc.strength * 13 + 15) / 16 * 2;
+ denali->nand.ecc.bytes =
+ (denali->nand.ecc.strength * 13 + 15) / 16 * 2;
break;
case 1024:
- nand->ecc.bytes = (nand->ecc.strength * 14 + 15) / 16 * 2;
+ denali->nand.ecc.bytes =
+ (denali->nand.ecc.strength * 14 + 15) / 16 * 2;
break;
default:
pr_err("Unsupported ECC size\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto fail;
}
- nand_oob.eccbytes = nand->ecc.bytes;
- nand->ecc.layout = &nand_oob;
-
- /* Set address of hardware control function */
- nand->cmdfunc = denali_cmdfunc;
- nand->read_byte = denali_read_byte;
- nand->read_buf = denali_read_buf;
- nand->select_chip = denali_select_chip;
- nand->waitfunc = denali_waitfunc;
- denali_hw_init(denali);
- return 0;
+ nand_oob.eccbytes = denali->nand.ecc.bytes;
+ denali->nand.ecc.layout = &nand_oob;
+
+ writel(denali->mtd->erasesize / denali->mtd->writesize,
+ denali->flash_reg + PAGES_PER_BLOCK);
+ writel(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
+ denali->flash_reg + DEVICE_WIDTH);
+ writel(denali->mtd->writesize,
+ denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
+ writel(denali->mtd->oobsize,
+ denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
+ if (readl(denali->flash_reg + DEVICES_CONNECTED) == 0)
+ writel(1, denali->flash_reg + DEVICES_CONNECTED);
+
+ /* override the default operations */
+ denali->nand.ecc.read_page = denali_read_page;
+ denali->nand.ecc.read_page_raw = denali_read_page_raw;
+ denali->nand.ecc.write_page = denali_write_page;
+ denali->nand.ecc.write_page_raw = denali_write_page_raw;
+ denali->nand.ecc.read_oob = denali_read_oob;
+ denali->nand.ecc.write_oob = denali_write_oob;
+
+ if (nand_scan_tail(denali->mtd)) {
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ ret = nand_register(0);
+
+fail:
+ return ret;
+}
+
+static int __board_nand_init(void)
+{
+ struct denali_nand_info *denali;
+
+ denali = kzalloc(sizeof(*denali), GFP_KERNEL);
+ if (!denali)
+ return -ENOMEM;
+
+ /*
+ * If CONFIG_SYS_NAND_SELF_INIT is defined, each driver is responsible
+ * for instantiating struct nand_chip, while drivers/mtd/nand/nand.c
+ * still provides a "struct mtd_info nand_info" instance.
+ */
+ denali->mtd = &nand_info[0];
+
+ /*
+ * In the future, these base addresses should be taken from
+ * Device Tree or platform data.
+ */
+ denali->flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
+ denali->flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
+
+ return denali_init(denali);
}
-int board_nand_init(struct nand_chip *chip)
+void board_nand_init(void)
{
- return denali_nand_init(chip);
+ if (__board_nand_init() < 0)
+ pr_warn("Failed to initialize Denali NAND controller.\n");
}
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 3277da71e1..a258df00fd 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -434,9 +434,8 @@ struct nand_buf {
#define DT 3
struct denali_nand_info {
- struct mtd_info mtd;
- struct nand_chip *nand;
-
+ struct mtd_info *mtd;
+ struct nand_chip nand;
int flash_bank; /* currently selected chip */
int status;
int platform;
diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c
index 65fdde8a65..e98f537c2c 100644
--- a/drivers/mtd/nand/denali_spl.c
+++ b/drivers/mtd/nand/denali_spl.c
@@ -203,7 +203,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
if (ret < 0)
return ret;
- readlen = min(page_size - column, size);
+ readlen = min(page_size - column, (int)size);
memcpy(dst, page_buffer, readlen);
column = 0;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 81b5070b54..b283eaea34 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -292,7 +292,7 @@ static int fsl_ifc_run_command(struct mtd_info *mtd)
struct fsl_ifc *ifc = ctrl->regs;
u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
u32 time_start;
- u32 eccstat[4];
+ u32 eccstat[4] = {0};
int i;
/* set the chip select for NAND Transaction */
diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c
index e336cb1c94..fb827c5e74 100644
--- a/drivers/mtd/nand/fsl_ifc_spl.c
+++ b/drivers/mtd/nand/fsl_ifc_spl.c
@@ -254,3 +254,13 @@ void nand_boot(void)
uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
uboot();
}
+
+#ifndef CONFIG_SPL_NAND_INIT
+void nand_init(void)
+{
+}
+
+void nand_deselect(void)
+{
+}
+#endif
diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c
index 036c113ad3..7a064ab1bf 100644
--- a/drivers/mtd/nand/mxs_nand.c
+++ b/drivers/mtd/nand/mxs_nand.c
@@ -146,8 +146,13 @@ static uint32_t mxs_nand_aux_status_offset(void)
static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
uint32_t page_oob_size)
{
- if (page_data_size == 2048)
- return 8;
+ if (page_data_size == 2048) {
+ if (page_oob_size == 64)
+ return 8;
+
+ if (page_oob_size == 112)
+ return 14;
+ }
if (page_data_size == 4096) {
if (page_oob_size == 128)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0b6e7ee385..63bdf65f82 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -634,6 +634,12 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
{
struct nand_chip *chip = mtd->priv;
+ if (!(chip->options & NAND_SKIP_BBTSCAN) &&
+ !(chip->options & NAND_BBT_SCANNED)) {
+ chip->options |= NAND_BBT_SCANNED;
+ chip->scan_bbt(mtd);
+ }
+
if (!chip->bbt)
return chip->block_bad(mtd, ofs, getchip);
@@ -2900,7 +2906,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
WATCHDOG_RESET();
/* Check if we have a bad block, we do not erase bad blocks! */
- if (nand_block_checkbad(mtd, ((loff_t) page) <<
+ if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<
chip->page_shift, 0, allowbbt)) {
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page);
@@ -4320,12 +4326,7 @@ int nand_scan_tail(struct mtd_info *mtd)
if (!mtd->bitflip_threshold)
mtd->bitflip_threshold = mtd->ecc_strength;
- /* Check, if we should skip the bad block table scan */
- if (chip->options & NAND_SKIP_BBTSCAN)
- return 0;
-
- /* Build bad block table */
- return chip->scan_bbt(mtd);
+ return 0;
}
EXPORT_SYMBOL(nand_scan_tail);
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 024f6fb440..afdd160d81 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -91,6 +91,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
kfree(chip->bbt);
}
chip->bbt = NULL;
+ chip->options &= ~NAND_BBT_SCANNED;
}
for (erased_length = 0;
@@ -179,9 +180,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
if (!opts->quiet)
printf("\n");
- if (opts->scrub)
- chip->scan_bbt(meminfo);
-
return 0;
}
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 40d670563c..459904d81c 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -73,14 +73,11 @@ static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
writeb(cmd, this->IO_ADDR_W);
}
-#ifdef CONFIG_SPL_BUILD
/* Check wait pin as dev ready indicator */
-static int omap_spl_dev_ready(struct mtd_info *mtd)
+static int omap_dev_ready(struct mtd_info *mtd)
{
return gpmc_cfg->status & (1 << 8);
}
-#endif
-
/*
* gen_true_ecc - This function will generate true ECC value, which
@@ -371,8 +368,9 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
uint32_t error_loc[ELM_MAX_ERROR_COUNT];
enum bch_level bch_type;
uint32_t i, ecc_flag = 0;
- uint8_t count, err = 0;
+ uint8_t count;
uint32_t byte_pos, bit_pos;
+ int err = 0;
/* check calculated ecc */
for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
@@ -887,7 +885,9 @@ int board_nand_init(struct nand_chip *nand)
nand->read_buf = nand_read_buf16;
else
nand->read_buf = nand_read_buf;
- nand->dev_ready = omap_spl_dev_ready;
#endif
+
+ nand->dev_ready = omap_dev_ready;
+
return 0;
}
diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c
index db87d07269..b3a2a60bb2 100644
--- a/drivers/mtd/nand/s3c2410_nand.c
+++ b/drivers/mtd/nand/s3c2410_nand.c
@@ -38,10 +38,10 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
#endif
-static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
- struct s3c2410_nand *nand = s3c2410_get_base_nand();
+ struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
@@ -67,35 +67,35 @@ static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
writeb(cmd, chip->IO_ADDR_W);
}
-static int s3c2410_dev_ready(struct mtd_info *mtd)
+static int s3c24x0_dev_ready(struct mtd_info *mtd)
{
- struct s3c2410_nand *nand = s3c2410_get_base_nand();
+ struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
debug("dev_ready\n");
return readl(&nand->nfstat) & 0x01;
}
#ifdef CONFIG_S3C2410_NAND_HWECC
-void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+void s3c24x0_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
- struct s3c2410_nand *nand = s3c2410_get_base_nand();
- debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
+ struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
+ debug("s3c24x0_nand_enable_hwecc(%p, %d)\n", mtd, mode);
writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf);
}
-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+static int s3c24x0_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
{
- struct s3c2410_nand *nand = s3c2410_get_base_nand();
+ struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
ecc_code[0] = readb(&nand->nfecc);
ecc_code[1] = readb(&nand->nfecc + 1);
ecc_code[2] = readb(&nand->nfecc + 2);
- debug("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
- mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
+ debug("s3c24x0_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
+ mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
return 0;
}
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+static int s3c24x0_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
if (read_ecc[0] == calc_ecc[0] &&
@@ -103,7 +103,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
read_ecc[2] == calc_ecc[2])
return 0;
- printf("s3c2410_nand_correct_data: not implemented\n");
+ printf("s3c24x0_nand_correct_data: not implemented\n");
return -1;
}
#endif
@@ -113,7 +113,7 @@ int board_nand_init(struct nand_chip *nand)
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
- struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
+ struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand();
debug("board_nand_init()\n");
@@ -149,14 +149,14 @@ int board_nand_init(struct nand_chip *nand)
#endif
/* hwcontrol always must be implemented */
- nand->cmd_ctrl = s3c2410_hwcontrol;
+ nand->cmd_ctrl = s3c24x0_hwcontrol;
- nand->dev_ready = s3c2410_dev_ready;
+ nand->dev_ready = s3c24x0_dev_ready;
#ifdef CONFIG_S3C2410_NAND_HWECC
- nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
- nand->ecc.calculate = s3c2410_nand_calculate_ecc;
- nand->ecc.correct = s3c2410_nand_correct_data;
+ nand->ecc.hwctl = s3c24x0_nand_enable_hwecc;
+ nand->ecc.calculate = s3c24x0_nand_calculate_ecc;
+ nand->ecc.correct = s3c24x0_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 7feb3a7b1e..928d58b3a7 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -611,6 +611,9 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
}
+ /* Disable subpage writes as we do not provide ecc->hwctl */
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
+
chip->dev_ready = vf610_nfc_dev_ready;
chip->cmdfunc = vf610_nfc_command;
chip->read_byte = vf610_nfc_read_byte;
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 15789a07d8..c61b784e17 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -17,6 +17,5 @@ obj-$(CONFIG_SPI_FLASH) += sf_probe.o
#endif
obj-$(CONFIG_CMD_SF) += sf.o
obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o
-obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
diff --git a/drivers/mtd/spi/ramtron.c b/drivers/mtd/spi/ramtron.c
deleted file mode 100644
index a23032cca5..0000000000
--- a/drivers/mtd/spi/ramtron.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * (C) Copyright 2010
- * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-/*
- * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs
- * with an interface identical to SPI flash devices.
- * However since they behave like RAM there are no delays or
- * busy polls required. They can sustain read or write at the
- * allowed SPI bus speed, which can be 40 MHz for some devices.
- *
- * Unfortunately some RAMTRON devices do not have a means of
- * identifying them. They will leave the SO line undriven when
- * the READ-ID command is issued. It is therefore mandatory
- * that the MISO line has a proper pull-up, so that READ-ID
- * will return a row of 0xff. This 0xff pseudo-id will cause
- * probes by all vendor specific functions that are designed
- * to handle it. If the MISO line is not pulled up, READ-ID
- * could return any random noise, even mimicking another
- * device.
- *
- * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
- * to define which device will be assumed after a simple status
- * register verify. This method is prone to false positive
- * detection and should therefore be the last to be tried.
- * Enter it in the last position in the table in spi_flash.c!
- *
- * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates
- * compilation of the special handler and defines the device
- * to assume.
- */
-
-#include <common.h>
-#include <malloc.h>
-#include <spi.h>
-#include <spi_flash.h>
-#include "sf_internal.h"
-
-/*
- * Properties of supported FRAMs
- * Note: speed is currently not used because we have no method to deliver that
- * value to the upper layers
- */
-struct ramtron_spi_fram_params {
- u32 size; /* size in bytes */
- u8 addr_len; /* number of address bytes */
- u8 merge_cmd; /* some address bits are in the command byte */
- u8 id1; /* device ID 1 (family, density) */
- u8 id2; /* device ID 2 (sub, rev, rsvd) */
- u32 speed; /* max. SPI clock in Hz */
- const char *name; /* name for display and/or matching */
-};
-
-struct ramtron_spi_fram {
- struct spi_flash flash;
- const struct ramtron_spi_fram_params *params;
-};
-
-static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash
- *flash)
-{
- return container_of(flash, struct ramtron_spi_fram, flash);
-}
-
-/*
- * table describing supported FRAM chips:
- * chips without RDID command must have the values 0xff for id1 and id2
- */
-static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = {
- {
- .size = 32*1024,
- .addr_len = 2,
- .merge_cmd = 0,
- .id1 = 0x22,
- .id2 = 0x00,
- .speed = 40000000,
- .name = "FM25V02",
- },
- {
- .size = 32*1024,
- .addr_len = 2,
- .merge_cmd = 0,
- .id1 = 0x22,
- .id2 = 0x01,
- .speed = 40000000,
- .name = "FM25VN02",
- },
- {
- .size = 64*1024,
- .addr_len = 2,
- .merge_cmd = 0,
- .id1 = 0x23,
- .id2 = 0x00,
- .speed = 40000000,
- .name = "FM25V05",
- },
- {
- .size = 64*1024,
- .addr_len = 2,
- .merge_cmd = 0,
- .id1 = 0x23,
- .id2 = 0x01,
- .speed = 40000000,
- .name = "FM25VN05",
- },
- {
- .size = 128*1024,
- .addr_len = 3,
- .merge_cmd = 0,
- .id1 = 0x24,
- .id2 = 0x00,
- .speed = 40000000,
- .name = "FM25V10",
- },
- {
- .size = 128*1024,
- .addr_len = 3,
- .merge_cmd = 0,
- .id1 = 0x24,
- .id2 = 0x01,
- .speed = 40000000,
- .name = "FM25VN10",
- },
-#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
- {
- .size = 256*1024,
- .addr_len = 3,
- .merge_cmd = 0,
- .id1 = 0xff,
- .id2 = 0xff,
- .speed = 40000000,
- .name = "FM25H20",
- },
-#endif
-};
-
-static int ramtron_common(struct spi_flash *flash,
- u32 offset, size_t len, void *buf, u8 command)
-{
- struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash);
- u8 cmd[4];
- int cmd_len;
- int ret;
-
- if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) {
- cmd[0] = command;
- cmd[1] = offset >> 16;
- cmd[2] = offset >> 8;
- cmd[3] = offset;
- cmd_len = 4;
- } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) {
- cmd[0] = command;
- cmd[1] = offset >> 8;
- cmd[2] = offset;
- cmd_len = 3;
- } else {
- printf("SF: unsupported addr_len or merge_cmd\n");
- return -1;
- }
-
- /* claim the bus */
- ret = spi_claim_bus(flash->spi);
- if (ret) {
- debug("SF: Unable to claim SPI bus\n");
- return ret;
- }
-
- if (command == CMD_PAGE_PROGRAM) {
- /* send WREN */
- ret = spi_flash_cmd_write_enable(flash);
- if (ret < 0) {
- debug("SF: Enabling Write failed\n");
- goto releasebus;
- }
- }
-
- /* do the transaction */
- if (command == CMD_PAGE_PROGRAM)
- ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len);
- else
- ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len);
- if (ret < 0)
- debug("SF: Transaction failed\n");
-
-releasebus:
- /* release the bus */
- spi_release_bus(flash->spi);
- return ret;
-}
-
-static int ramtron_read(struct spi_flash *flash,
- u32 offset, size_t len, void *buf)
-{
- return ramtron_common(flash, offset, len, buf,
- CMD_READ_ARRAY_SLOW);
-}
-
-static int ramtron_write(struct spi_flash *flash,
- u32 offset, size_t len, const void *buf)
-{
- return ramtron_common(flash, offset, len, (void *)buf,
- CMD_PAGE_PROGRAM);
-}
-
-static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len)
-{
- debug("SF: Erase of RAMTRON FRAMs is pointless\n");
- return -1;
-}
-
-/*
- * nore: we are called here with idcode pointing to the first non-0x7f byte
- * already!
- */
-static struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi,
- u8 *idcode)
-{
- const struct ramtron_spi_fram_params *params;
- struct ramtron_spi_fram *sn;
- unsigned int i;
-#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
- int ret;
- u8 sr;
-#endif
-
- /* NOTE: the bus has been claimed before this function is called! */
- switch (idcode[0]) {
- case 0xc2:
- /* JEDEC conformant RAMTRON id */
- for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) {
- params = &ramtron_spi_fram_table[i];
- if (idcode[1] == params->id1 &&
- idcode[2] == params->id2)
- goto found;
- }
- break;
-#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
- case 0xff:
- /*
- * probably open MISO line, pulled up.
- * We COULD have a non JEDEC conformant FRAM here,
- * read the status register to verify
- */
- ret = spi_flash_cmd(spi, CMD_READ_STATUS, &sr, 1);
- if (ret)
- return NULL;
-
- /* Bits 5,4,0 are fixed 0 for all devices */
- if ((sr & 0x31) != 0x00)
- return NULL;
- /* now find the device */
- for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) {
- params = &ramtron_spi_fram_table[i];
- if (!strcmp(params->name,
- CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC))
- goto found;
- }
- debug("SF: Unsupported non-JEDEC RAMTRON device "
- CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n");
- break;
-#endif
- default:
- break;
- }
-
- /* arriving here means no method has found a device we can handle */
- debug("SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n",
- idcode[0], idcode[1], idcode[2]);
- return NULL;
-
-found:
- sn = malloc(sizeof(*sn));
- if (!sn) {
- debug("SF: Failed to allocate memory\n");
- return NULL;
- }
-
- sn->params = params;
-
- sn->flash.write = ramtron_write;
- sn->flash.read = ramtron_read;
- sn->flash.erase = ramtron_erase;
- sn->flash.size = params->size;
-
- return &sn->flash;
-}
-
-/*
- * The following table holds all device probe functions
- * (All flashes are removed and implemented a common probe at
- * spi_flash_probe.c)
- *
- * shift: number of continuation bytes before the ID
- * idcode: the expected IDCODE or 0xff for non JEDEC devices
- * probe: the function to call
- *
- * Non JEDEC devices should be ordered in the table such that
- * the probe functions with best detection algorithms come first.
- *
- * Several matching entries are permitted, they will be tried
- * in sequence until a probe function returns non NULL.
- *
- * IDCODE_CONT_LEN may be redefined if a device needs to declare a
- * larger "shift" value. IDCODE_PART_LEN generally shouldn't be
- * changed. This is the max number of bytes probe functions may
- * examine when looking up part-specific identification info.
- *
- * Probe functions will be given the idcode buffer starting at their
- * manu id byte (the "idcode" in the table below). In other words,
- * all of the continuation bytes will be skipped (the "shift" below).
- */
-#define IDCODE_CONT_LEN 0
-#define IDCODE_PART_LEN 5
-static const struct {
- const u8 shift;
- const u8 idcode;
- struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode);
-} flashes[] = {
- /* Keep it sorted by define name */
-#ifdef CONFIG_SPI_FRAM_RAMTRON
- { 6, 0xc2, spi_fram_probe_ramtron, },
-# undef IDCODE_CONT_LEN
-# define IDCODE_CONT_LEN 6
-#endif
-#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
- { 0, 0xff, spi_fram_probe_ramtron, },
-#endif
-};
-#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN)
-
-struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int spi_mode)
-{
- struct spi_slave *spi;
- struct spi_flash *flash = NULL;
- int ret, i, shift;
- u8 idcode[IDCODE_LEN], *idp;
-
- spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
- if (!spi) {
- printf("SF: Failed to set up slave\n");
- return NULL;
- }
-
- ret = spi_claim_bus(spi);
- if (ret) {
- debug("SF: Failed to claim SPI bus: %d\n", ret);
- goto err_claim_bus;
- }
-
- /* Read the ID codes */
- ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
- if (ret)
- goto err_read_id;
-
-#ifdef DEBUG
- printf("SF: Got idcodes\n");
- print_buffer(0, idcode, 1, sizeof(idcode), 0);
-#endif
-
- /* count the number of continuation bytes */
- for (shift = 0, idp = idcode;
- shift < IDCODE_CONT_LEN && *idp == 0x7f;
- ++shift, ++idp)
- continue;
-
- /* search the table for matches in shift and id */
- for (i = 0; i < ARRAY_SIZE(flashes); ++i)
- if (flashes[i].shift == shift && flashes[i].idcode == *idp) {
- /* we have a match, call probe */
- flash = flashes[i].probe(spi, idp);
- if (flash)
- break;
- }
-
- if (!flash) {
- printf("SF: Unsupported manufacturer %02x\n", *idp);
- goto err_manufacturer_probe;
- }
-
- printf("SF: Detected %s with total size ", flash->name);
- print_size(flash->size, "");
- puts("\n");
-
- spi_release_bus(spi);
-
- return flash;
-
-err_manufacturer_probe:
-err_read_id:
- spi_release_bus(spi);
-err_claim_bus:
- spi_free_slave(spi);
- return NULL;
-}
-
-void spi_flash_free(struct spi_flash *flash)
-{
- spi_free_slave(flash->spi);
- free(flash);
-}
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index 1cf2f98310..3024b988fe 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -315,7 +315,7 @@ int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size)
int ret;
while (size > 0) {
- todo = min(size, sizeof(sandbox_sf_0xff));
+ todo = min(size, (int)sizeof(sandbox_sf_0xff));
ret = os_write(sbsf->fd, sandbox_sf_0xff, todo);
if (ret != todo)
return ret;
@@ -602,14 +602,14 @@ static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum,
spec, ret);
return ret;
}
- ret = device_find_child_by_seq(bus, cs, true, &slave);
+ ret = spi_find_chip_select(bus, cs, &slave);
if (!ret) {
printf("Chip select %d already exists for spec '%s'\n", cs,
spec);
return -EEXIST;
}
- ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave);
+ ret = device_bind_driver(bus, "spi_flash_std", spec, &slave);
if (ret)
return ret;
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 5b7670c9aa..785f7a96fe 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -23,13 +23,16 @@ enum spi_dual_flash {
/* Enum list - Full read commands */
enum spi_read_cmds {
ARRAY_SLOW = 1 << 0,
- DUAL_OUTPUT_FAST = 1 << 1,
- DUAL_IO_FAST = 1 << 2,
- QUAD_OUTPUT_FAST = 1 << 3,
- QUAD_IO_FAST = 1 << 4,
+ ARRAY_FAST = 1 << 1,
+ DUAL_OUTPUT_FAST = 1 << 2,
+ DUAL_IO_FAST = 1 << 3,
+ QUAD_OUTPUT_FAST = 1 << 4,
+ QUAD_IO_FAST = 1 << 5,
};
-#define RD_EXTN (ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+/* Normal - Extended - Full command set */
+#define RD_NORM (ARRAY_SLOW | ARRAY_FAST)
+#define RD_EXTN (RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
#define RD_FULL (RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
/* sf param flags */
@@ -37,9 +40,13 @@ enum {
SECT_4K = 1 << 0,
SECT_32K = 1 << 1,
E_FSR = 1 << 2,
- WR_QPP = 1 << 3,
+ SST_BP = 1 << 3,
+ SST_WP = 1 << 4,
+ WR_QPP = 1 << 5,
};
+#define SST_WR (SST_BP | SST_WP)
+
#define SPI_FLASH_3B_ADDR_LEN 3
#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN)
#define SPI_FLASH_16MB_BOUN 0x1000000
@@ -101,12 +108,13 @@ enum {
/* SST specific */
#ifdef CONFIG_SPI_FLASH_SST
-# define SST_WP 0x01 /* Supports AAI word program */
# define CMD_SST_BP 0x02 /* Byte Program */
# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
const void *buf);
+int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
+ const void *buf);
#endif
/**
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index 85cf22d42e..34bc54e73e 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -313,10 +313,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
return ret;
#endif
byte_addr = offset % page_size;
- chunk_len = min(len - actual, page_size - byte_addr);
+ chunk_len = min(len - actual, (size_t)(page_size - byte_addr));
if (flash->spi->max_write_size)
- chunk_len = min(chunk_len, flash->spi->max_write_size);
+ chunk_len = min(chunk_len,
+ (size_t)flash->spi->max_write_size);
spi_flash_addr(write_addr, cmd);
@@ -516,4 +517,35 @@ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
spi_release_bus(flash->spi);
return ret;
}
+
+int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
+ const void *buf)
+{
+ size_t actual;
+ int ret;
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: Unable to claim SPI bus\n");
+ return ret;
+ }
+
+ for (actual = 0; actual < len; actual++) {
+ ret = sst_byte_write(flash, offset, buf + actual);
+ if (ret) {
+ debug("SF: sst byte program failed\n");
+ break;
+ }
+ offset++;
+ }
+
+ if (!ret)
+ ret = spi_flash_cmd_write_disable(flash);
+
+ debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
+ ret ? "failure" : "success", len, offset - actual);
+
+ spi_release_bus(flash->spi);
+ return ret;
+}
#endif
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
index 61545cacaa..c12e8c6fe7 100644
--- a/drivers/mtd/spi/sf_params.c
+++ b/drivers/mtd/spi/sf_params.c
@@ -15,42 +15,44 @@
/* SPI/QSPI flash device params structure */
const struct spi_flash_params spi_flash_params_table[] = {
#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */
- {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0, SECT_4K},
- {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K},
- {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K},
- {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K},
- {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K},
- {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K},
- {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K},
- {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K},
+ {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K},
+ {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
+ {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
+ {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K},
+ {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K},
+ {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
+ {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+ {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
#endif
#ifdef CONFIG_SPI_FLASH_EON /* EON */
- {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0},
- {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K},
- {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0},
- {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0},
+ {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+ {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+ {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, RD_NORM, 0},
+ {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, RD_NORM, 0},
#endif
#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */
- {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K},
- {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K},
+ {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+ {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
#endif
#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
- {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0},
- {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0},
- {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0},
- {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0},
- {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0},
- {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0},
+ {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, RD_NORM, 0},
+ {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, RD_NORM, 0},
+ {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, RD_NORM, 0},
+ {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, RD_NORM, 0},
+ {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+ {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, RD_NORM, 0},
{"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
{"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP},
{"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP},
{"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
#endif
#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
- {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0},
- {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0},
- {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0},
- {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0},
+ {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, RD_NORM, 0},
+ {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, RD_NORM, 0},
+ {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, RD_NORM, 0},
+ {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, RD_NORM, 0},
+ {"S25FL116K", 0x014015, 0x0, 64 * 1024, 128, RD_NORM, 0},
+ {"S25FL164K", 0x014017, 0x0140, 64 * 1024, 128, RD_NORM, 0},
{"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, RD_FULL, WR_QPP},
{"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, RD_FULL, WR_QPP},
{"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, RD_FULL, WR_QPP},
@@ -64,17 +66,17 @@ const struct spi_flash_params spi_flash_params_table[] = {
{"S25FL512S_512K", 0x010220, 0x4f00, 256 * 1024, 256, RD_FULL, WR_QPP},
#endif
#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
- {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0},
- {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0},
- {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0},
- {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0},
- {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0},
- {"M25PE16", 0x208015, 0x1000, 64 * 1024, 32, 0, 0},
+ {"M25P10", 0x202011, 0x0, 32 * 1024, 4, RD_NORM, 0},
+ {"M25P20", 0x202012, 0x0, 64 * 1024, 4, RD_NORM, 0},
+ {"M25P40", 0x202013, 0x0, 64 * 1024, 8, RD_NORM, 0},
+ {"M25P80", 0x202014, 0x0, 64 * 1024, 16, RD_NORM, 0},
+ {"M25P16", 0x202015, 0x0, 64 * 1024, 32, RD_NORM, 0},
+ {"M25PE16", 0x208015, 0x1000, 64 * 1024, 32, RD_NORM, 0},
{"M25PX16", 0x207115, 0x1000, 64 * 1024, 32, RD_EXTN, 0},
- {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0},
- {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0},
- {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0},
- {"M25PX64", 0x207117, 0x0, 64 * 1024, 128, 0, SECT_4K},
+ {"M25P32", 0x202016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+ {"M25P64", 0x202017, 0x0, 64 * 1024, 128, RD_NORM, 0},
+ {"M25P128", 0x202018, 0x0, 256 * 1024, 64, RD_NORM, 0},
+ {"M25PX64", 0x207117, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
{"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
{"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K},
@@ -89,25 +91,26 @@ const struct spi_flash_params spi_flash_params_table[] = {
{"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
#endif
#ifdef CONFIG_SPI_FLASH_SST /* SST */
- {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP},
- {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP},
- {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP},
- {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP},
- {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K},
- {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP},
- {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP},
- {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP},
- {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP},
- {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP},
+ {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
+ {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR},
+ {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K | SST_WR},
+ {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K | SST_WR},
+ {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
+ {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, RD_NORM, SECT_4K | SST_WR},
+ {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, RD_NORM, SECT_4K | SST_WR},
+ {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, RD_NORM, SECT_4K | SST_WR},
+ {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
+ {"SST25WF040B", 0x621613, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K | SST_WR},
+ {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K | SST_WR},
#endif
#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */
- {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0},
- {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0},
- {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0},
- {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K},
- {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K},
- {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K},
- {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K},
+ {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, RD_NORM, 0},
+ {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, RD_NORM, 0},
+ {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, RD_NORM, 0},
+ {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, RD_NORM, SECT_4K},
+ {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, RD_NORM, SECT_4K},
+ {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K},
+ {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K},
{"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K},
{"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K},
{"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K},
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 26364269be..ce9987fd1a 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -24,6 +24,7 @@ DECLARE_GLOBAL_DATA_PTR;
/* Read commands array */
static u8 spi_read_cmds_array[] = {
CMD_READ_ARRAY_SLOW,
+ CMD_READ_ARRAY_FAST,
CMD_READ_DUAL_OUTPUT_FAST,
CMD_READ_DUAL_IO_FAST,
CMD_READ_QUAD_OUTPUT_FAST,
@@ -135,8 +136,12 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
#ifndef CONFIG_DM_SPI_FLASH
flash->write = spi_flash_cmd_write_ops;
#if defined(CONFIG_SPI_FLASH_SST)
- if (params->flags & SST_WP)
- flash->write = sst_write_wp;
+ if (params->flags & SST_WR) {
+ if (flash->spi->op_mode_tx & SPI_OPM_TX_BP)
+ flash->write = sst_write_bp;
+ else
+ flash->write = sst_write_wp;
+ }
#endif
flash->erase = spi_flash_cmd_erase_ops;
flash->read = spi_flash_cmd_read_ops;
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile
index 5ae3b167a9..d052fcb372 100644
--- a/drivers/net/fm/Makefile
+++ b/drivers/net/fm/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_PPC_T1040) += t1040.o
obj-$(CONFIG_PPC_T1042) += t1040.o
obj-$(CONFIG_PPC_T1020) += t1040.o
obj-$(CONFIG_PPC_T1022) += t1040.o
+obj-$(CONFIG_PPC_T1023) += t1024.o
+obj-$(CONFIG_PPC_T1024) += t1024.o
obj-$(CONFIG_PPC_T2080) += t2080.o
obj-$(CONFIG_PPC_T2081) += t2080.o
obj-$(CONFIG_PPC_T4240) += t4240.o
diff --git a/drivers/net/fm/b4860.c b/drivers/net/fm/b4860.c
index 373cc4f424..eb058c9c3d 100644
--- a/drivers/net/fm/b4860.c
+++ b/drivers/net/fm/b4860.c
@@ -10,6 +10,7 @@
#include <asm/io.h>
#include <asm/immap_85xx.h>
#include <asm/fsl_serdes.h>
+#include <hwconfig.h>
u32 port_to_devdisr[] = {
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
@@ -46,15 +47,76 @@ void fman_enable_port(enum fm_port port)
phy_interface_t fman_port_enet_if(enum fm_port port)
{
+#if defined(CONFIG_B4860QDS)
+ u32 serdes2_prtcl;
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif
+
if (is_device_disabled(port))
return PHY_INTERFACE_MODE_NONE;
/*B4860 has two 10Gig Mac*/
if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
((is_serdes_configured(XAUI_FM1_MAC9)) ||
- (is_serdes_configured(XAUI_FM1_MAC10))))
+ #if !defined(CONFIG_B4860QDS)
+ (is_serdes_configured(XFI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC10)) ||
+ #endif
+ (is_serdes_configured(XAUI_FM1_MAC10))
+ ))
return PHY_INTERFACE_MODE_XGMII;
+#if defined(CONFIG_B4860QDS)
+ serdes2_prtcl = in_be32(&gur->rcwsr[4]) &
+ FSL_CORENET2_RCWSR4_SRDS2_PRTCL;
+
+ if (serdes2_prtcl) {
+ serdes2_prtcl >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT;
+ switch (serdes2_prtcl) {
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0xb1:
+ case 0xb2:
+ /*
+ * Extract hwconfig from environment since environment
+ * is not setup yet
+ */
+ getenv_f("hwconfig", buffer, sizeof(buffer));
+ buf = buffer;
+
+ /* check if XFI interface enable in hwconfig for 10g */
+ if (hwconfig_subarg_cmp_f("fsl_b4860_serdes2",
+ "sfp_amc", "sfp", buf)) {
+ if ((port == FM1_10GEC1 ||
+ port == FM1_10GEC2) &&
+ ((is_serdes_configured(XFI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC10))))
+ return PHY_INTERFACE_MODE_XGMII;
+ else if ((port == FM1_DTSEC1) ||
+ (port == FM1_DTSEC2) ||
+ (port == FM1_DTSEC3) ||
+ (port == FM1_DTSEC4))
+ return PHY_INTERFACE_MODE_NONE;
+ }
+ }
+ }
+#endif
+
/* Fix me need to handle RGMII here first */
switch (port) {
diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c
index 218a5ed175..f1e39b982a 100644
--- a/drivers/net/fm/eth.c
+++ b/drivers/net/fm/eth.c
@@ -39,9 +39,14 @@ static void dtsec_configure_serdes(struct fm_eth *priv)
u32 value;
struct mii_dev bus;
bus.priv = priv->mac->phyregs;
+ bool sgmii_2500 = (priv->enet_if ==
+ PHY_INTERFACE_MODE_SGMII_2500) ? true : false;
+
+ /* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */
+ value = PHY_SGMII_IF_MODE_SGMII;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_IF_MODE_AN;
- /* SGMII IF mode + AN enable */
- value = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
/* Dev ability according to SGMII specification */
@@ -54,7 +59,9 @@ static void dtsec_configure_serdes(struct fm_eth *priv)
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xd40);
/* Restart AN */
- value = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ value = PHY_SGMII_CR_DEF_VAL;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_CR_RESET_AN;
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
#else
struct dtsec *regs = priv->mac->base;
@@ -83,7 +90,8 @@ static void dtsec_init_phy(struct eth_device *dev)
out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
#endif
- if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII)
+ if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII ||
+ fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII_2500)
dtsec_configure_serdes(fm_eth);
}
@@ -557,9 +565,11 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
num = fm_eth->num;
#ifdef CONFIG_SYS_FMAN_V3
+#ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
if (fm_eth->type == FM_ETH_10G_E) {
- /* 10GEC1/10GEC2 use mEMAC9/mEMAC10
- * 10GEC3/10GEC4 use mEMAC1/mEMAC2
+ /* 10GEC1/10GEC2 use mEMAC9/mEMAC10 on T2080/T4240.
+ * 10GEC3/10GEC4 use mEMAC1/mEMAC2 on T2080.
+ * 10GEC1 uses mEMAC1 on T1024.
* so it needs to change the num.
*/
if (fm_eth->num >= 2)
@@ -567,6 +577,7 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
else
num += 8;
}
+#endif
base = &reg->memac[num].fm_memac;
phyregs = &reg->memac[num].fm_memac_mdio;
#else
diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c
index 6cf21c6f65..9a8a007861 100644
--- a/drivers/net/fm/init.c
+++ b/drivers/net/fm/init.c
@@ -247,10 +247,12 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
}
#ifdef CONFIG_SYS_FMAN_V3
+#ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
/*
- * Physically FM1_DTSEC9 and FM1_10GEC1 use the same dual-role MAC, when
- * FM1_10GEC1 is enabled and FM1_DTSEC9 is disabled, ensure that the
- * dual-role MAC is not disabled, ditto for other dual-role MACs.
+ * On T2/T4 SoCs, physically FM1_DTSEC9 and FM1_10GEC1 use the same
+ * dual-role MAC, when FM1_10GEC1 is enabled and FM1_DTSEC9
+ * is disabled, ensure that the dual-role MAC is not disabled,
+ * ditto for other dual-role MACs.
*/
if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
@@ -267,6 +269,17 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) ||
((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10)))
#endif
+#else
+ /* FM1_DTSECx and FM1_10GECx use the same dual-role MAC */
+ if (((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
+ ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
+ ((info->port == FM1_DTSEC3) && (PORT_IS_ENABLED(FM1_10GEC3))) ||
+ ((info->port == FM1_DTSEC4) && (PORT_IS_ENABLED(FM1_10GEC4))) ||
+ ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC1))) ||
+ ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC2))) ||
+ ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC3))) ||
+ ((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC4)))
+#endif
)
return;
#endif
diff --git a/drivers/net/fm/memac.c b/drivers/net/fm/memac.c
index 9499290bba..60e898cd7c 100644
--- a/drivers/net/fm/memac.c
+++ b/drivers/net/fm/memac.c
@@ -37,7 +37,8 @@ static void memac_enable_mac(struct fsl_enet_mac *mac)
{
struct memac *regs = mac->base;
- setbits_be32(&regs->command_config, MEMAC_CMD_CFG_RXTX_EN);
+ setbits_be32(&regs->command_config,
+ MEMAC_CMD_CFG_RXTX_EN | MEMAC_CMD_CFG_NO_LEN_CHK);
}
static void memac_disable_mac(struct fsl_enet_mac *mac)
@@ -93,11 +94,16 @@ static void memac_set_interface_mode(struct fsl_enet_mac *mac,
if_mode &= ~IF_MODE_MASK;
if_mode |= (IF_MODE_GMII);
break;
+ case PHY_INTERFACE_MODE_XGMII:
+ if_mode &= ~IF_MODE_MASK;
+ if_mode |= IF_MODE_XGMII;
+ break;
default:
break;
}
- /* Enable automatic speed selection */
- if_mode |= IF_MODE_EN_AUTO;
+ /* Enable automatic speed selection for Non-XGMII */
+ if (type != PHY_INTERFACE_MODE_XGMII)
+ if_mode |= IF_MODE_EN_AUTO;
if (type == PHY_INTERFACE_MODE_RGMII) {
if_mode &= ~IF_MODE_EN_AUTO;
diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c
index 5f910c2cdd..a155d8930b 100644
--- a/drivers/net/fm/memac_phy.c
+++ b/drivers/net/fm/memac_phy.c
@@ -71,6 +71,8 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
u32 c45 = 1;
if (dev_addr == MDIO_DEVAD_NONE) {
+ if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME))
+ return 0xffff;
c45 = 0; /* clause 22 */
dev_addr = regnum & 0x1f;
clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
@@ -137,9 +139,12 @@ int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
* is zero, so MDIO clock is disabled.
* So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to
* be properly initialized.
+ * NEG bit default should be '1' as per FMAN-v3 RM, but on platform
+ * like T2080QDS, this bit default is '0', which leads to MDIO failure
+ * on XAUI PHY, so set this bit definitely.
*/
setbits_be32(&((struct memac_mdio_controller *)info->regs)->mdio_stat,
- MDIO_STAT_CLKDIV(258));
+ MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG);
return mdio_register(bus);
}
diff --git a/drivers/net/fm/t1024.c b/drivers/net/fm/t1024.c
new file mode 100644
index 0000000000..9b3117341e
--- /dev/null
+++ b/drivers/net/fm/t1024.c
@@ -0,0 +1,88 @@
+/* Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * Shengzhou Liu <Shengzhou.Liu@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1, /* MAC1 */
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ if ((port == FM1_10GEC1) && (is_serdes_configured(XFI_FM1_MAC1)))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ if ((port == FM1_DTSEC3) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_RGMII) &&
+ (!is_serdes_configured(QSGMII_FM1_A)))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC4) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_RGMII) &&
+ (!is_serdes_configured(QSGMII_FM1_A)))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ /* handle SGMII */
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ else if (is_serdes_configured(SGMII_2500_FM1_DTSEC1
+ + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII_2500;
+ break;
+ default:
+ break;
+ }
+
+ /* handle QSGMII */
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ /* check lane A on SerDes1 */
+ if (is_serdes_configured(QSGMII_FM1_A))
+ return PHY_INTERFACE_MODE_QSGMII;
+ break;
+ default:
+ break;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/drivers/net/fm/t1040.c b/drivers/net/fm/t1040.c
index 4cce46d7f8..d2a097e0e5 100644
--- a/drivers/net/fm/t1040.c
+++ b/drivers/net/fm/t1040.c
@@ -25,8 +25,6 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
return PHY_INTERFACE_MODE_MII;
- else
- return PHY_INTERFACE_MODE_NONE;
}
if ((port == FM1_DTSEC4) &&
@@ -38,8 +36,6 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
return PHY_INTERFACE_MODE_MII;
- else
- return PHY_INTERFACE_MODE_NONE;
}
if (port == FM1_DTSEC5) {
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c
index c8681d0223..bedab1d606 100644
--- a/drivers/net/keystone_net.c
+++ b/drivers/net/keystone_net.c
@@ -315,7 +315,7 @@ int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg)
writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN);
writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL);
-#ifdef CONFIG_K2E_EVM
+#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
/* Map RX packet flow priority to 0 */
writel(0, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RX_PRI_MAP);
#endif
@@ -400,6 +400,9 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
keystone2_net_serdes_setup();
+ if (sys_has_mdio)
+ keystone2_mdio_reset(mdio_bus);
+
keystone_sgmii_config(phy_dev, eth_priv->slave_port - 1,
eth_priv->sgmii_link_type);
@@ -582,7 +585,7 @@ static void keystone2_net_serdes_setup(void)
&ks2_serdes_sgmii_156p25mhz,
CONFIG_KSNET_SERDES_LANES_PER_SGMII);
-#ifdef CONFIG_SOC_K2E
+#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE,
&ks2_serdes_sgmii_156p25mhz,
CONFIG_KSNET_SERDES_LANES_PER_SGMII);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 375c8a4454..9c2ff487a7 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -525,6 +525,7 @@ static int macb_phy_init(struct macb_device *macb)
return 1;
}
+static int macb_write_hwaddr(struct eth_device *dev);
static int macb_init(struct eth_device *netdev, bd_t *bd)
{
struct macb_device *macb = to_macb(netdev);
@@ -565,7 +566,13 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
macb_writel(macb, TBQP, macb->tx_ring_dma);
if (macb_is_gem(macb)) {
-#ifdef CONFIG_RGMII
+ /*
+ * When the GMAC IP with GE feature, this bit is used to
+ * select interface between RGMII and GMII.
+ * When the GMAC IP without GE feature, this bit is used
+ * to select interface between RMII and MII.
+ */
+#if defined(CONFIG_RGMII) || defined(CONFIG_RMII)
gem_writel(macb, UR, GEM_BIT(RGMII));
#else
gem_writel(macb, UR, 0);
@@ -587,6 +594,14 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
#endif /* CONFIG_RMII */
}
+ /* update the ethaddr */
+ if (is_valid_ether_addr(netdev->enetaddr)) {
+ macb_write_hwaddr(netdev);
+ } else {
+ printf("%s: mac address is not valid\n", netdev->name);
+ return -1;
+ }
+
if (!macb_phy_init(macb))
return -1;
diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c
index 1093ba59da..d9d6f4f28b 100644
--- a/drivers/net/mpc5xxx_fec.c
+++ b/drivers/net/mpc5xxx_fec.c
@@ -476,11 +476,6 @@ static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis)
miiphy_write(dev->name, phyAddr, 0x0, 0x8000);
udelay(1000);
-#if defined(CONFIG_UC101) || defined(CONFIG_MUCMC52)
- /* Set the LED configuration Register for the UC101
- and MUCMC52 Board */
- miiphy_write(dev->name, phyAddr, 0x14, 0x4122);
-#endif
if (fec->xcv_type == MII10) {
/*
* Force 10Base-T, FDX operation
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 623f7492c7..677c89f048 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -256,7 +256,7 @@ static void nc_puts(struct stdio_dev *dev, const char *s)
len = strlen(s);
while (len) {
- int send_len = min(len, sizeof(input_buffer));
+ int send_len = min(len, (int)sizeof(input_buffer));
nc_send_packet(s, send_len);
len -= send_len;
s += send_len;
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 9556536b77..f46bf00abe 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHYLIB) += phy.o
obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
obj-$(CONFIG_PHY_ATHEROS) += atheros.o
obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
+obj-$(CONFIG_PHY_CORTINA) += cortina.o
obj-$(CONFIG_PHY_DAVICOM) += davicom.o
obj-$(CONFIG_PHY_ET1011C) += et1011c.o
obj-$(CONFIG_PHY_LXT) += lxt.o
diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
new file mode 100644
index 0000000000..254f056df4
--- /dev/null
+++ b/drivers/net/phy/cortina.c
@@ -0,0 +1,333 @@
+/*
+ * Cortina CS4315/CS4340 10G PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <phy.h>
+#include <cortina.h>
+#ifdef CONFIG_SYS_CORTINA_FW_IN_NAND
+#include <nand.h>
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH)
+#include <spi_flash.h>
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC)
+#include <mmc.h>
+#endif
+
+#ifndef CONFIG_PHYLIB_10G
+#error The Cortina PHY needs 10G support
+#endif
+
+struct cortina_reg_config cortina_reg_cfg[] = {
+ /* CS4315_enable_sr_mode */
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004},
+ {VILLA_MSEQ_OPTIONS, 0xf},
+ {VILLA_MSEQ_PC, 0x0},
+ {VILLA_MSEQ_BANKSELECT, 0x4},
+ {VILLA_LINE_SDS_COMMON_SRX0_RX_CPA, 0x55},
+ {VILLA_LINE_SDS_COMMON_SRX0_RX_LOOP_FILTER, 0x30},
+ {VILLA_DSP_SDS_SERDES_SRX_DFE0_SELECT, 0x1},
+ {VILLA_DSP_SDS_DSP_COEF_DFE0_SELECT, 0x2},
+ {VILLA_LINE_SDS_COMMON_SRX0_RX_CPB, 0x2003},
+ {VILLA_DSP_SDS_SERDES_SRX_FFE_DELAY_CTRL, 0xF047},
+ {VILLA_MSEQ_ENABLE_MSB, 0x0000},
+ {VILLA_MSEQ_SPARE21_LSB, 0x6},
+ {VILLA_MSEQ_RESET_COUNT_LSB, 0x0},
+ {VILLA_MSEQ_SPARE12_MSB, 0x0000},
+ /*
+ * to invert the receiver path, uncomment the next line
+ * write (VILLA_MSEQ_SPARE12_MSB, 0x4000)
+ *
+ * SPARE2_LSB is used to configure the device while in sr mode to
+ * enable power savings and to use the optical module LOS signal.
+ * in power savings mode, the internal prbs checker can not be used.
+ * if the optical module LOS signal is used as an input to the micro
+ * code, then the micro code will wait until the optical module
+ * LOS = 0 before turning on the adaptive equalizer.
+ * Setting SPARE2_LSB bit 0 to 1 places the devie in power savings mode
+ * while setting bit 0 to 0 disables power savings mode.
+ * Setting SPARE2_LSB bit 2 to 0 configures the device to use the
+ * optical module LOS signal while setting bit 2 to 1 configures the
+ * device so that it will ignore the optical module LOS SPARE2_LSB = 0
+ */
+
+ /* enable power savings, ignore optical module LOS */
+ {VILLA_MSEQ_SPARE2_LSB, 0x5},
+
+ {VILLA_MSEQ_SPARE7_LSB, 0x1e},
+ {VILLA_MSEQ_BANKSELECT, 0x4},
+ {VILLA_MSEQ_SPARE9_LSB, 0x2},
+ {VILLA_MSEQ_SPARE3_LSB, 0x0F53},
+ {VILLA_MSEQ_SPARE3_MSB, 0x2006},
+ {VILLA_MSEQ_SPARE8_LSB, 0x3FF7},
+ {VILLA_MSEQ_SPARE8_MSB, 0x0A46},
+ {VILLA_MSEQ_COEF8_FFE0_LSB, 0xD500},
+ {VILLA_MSEQ_COEF8_FFE1_LSB, 0x0200},
+ {VILLA_MSEQ_COEF8_FFE2_LSB, 0xBA00},
+ {VILLA_MSEQ_COEF8_FFE3_LSB, 0x0100},
+ {VILLA_MSEQ_COEF8_FFE4_LSB, 0x0300},
+ {VILLA_MSEQ_COEF8_FFE5_LSB, 0x0300},
+ {VILLA_MSEQ_COEF8_DFE0_LSB, 0x0700},
+ {VILLA_MSEQ_COEF8_DFE0N_LSB, 0x0E00},
+ {VILLA_MSEQ_COEF8_DFE1_LSB, 0x0B00},
+ {VILLA_DSP_SDS_DSP_COEF_LARGE_LEAK, 0x2},
+ {VILLA_DSP_SDS_SERDES_SRX_DAC_ENABLEB_LSB, 0xD000},
+ {VILLA_MSEQ_POWER_DOWN_LSB, 0xFFFF},
+ {VILLA_MSEQ_POWER_DOWN_MSB, 0x0},
+ {VILLA_MSEQ_CAL_RX_SLICER, 0x80},
+ {VILLA_DSP_SDS_SERDES_SRX_DAC_BIAS_SELECT1_MSB, 0x3f},
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x4},
+ {VILLA_MSEQ_OPTIONS, 0x7},
+
+ /* set up min value for ffe1 */
+ {VILLA_MSEQ_COEF_INIT_SEL, 0x2},
+ {VILLA_DSP_SDS_DSP_PRECODEDINITFFE21, 0x41},
+
+ /* CS4315_sr_rx_pre_eq_set_4in */
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004},
+ {VILLA_MSEQ_OPTIONS, 0xf},
+ {VILLA_MSEQ_BANKSELECT, 0x4},
+ {VILLA_MSEQ_PC, 0x0},
+
+ /* for lengths from 3.5 to 4.5inches */
+ {VILLA_MSEQ_SERDES_PARAM_LSB, 0x0306},
+ {VILLA_MSEQ_SPARE25_LSB, 0x0306},
+ {VILLA_MSEQ_SPARE21_LSB, 0x2},
+ {VILLA_MSEQ_SPARE23_LSB, 0x2},
+ {VILLA_MSEQ_CAL_RX_DFE_EQ, 0x0},
+
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x4},
+ {VILLA_MSEQ_OPTIONS, 0x7},
+
+ /* CS4315_rx_drive_4inch */
+ /* for length 4inches */
+ {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000},
+ {VILLA_HOST_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023},
+ {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E},
+
+ /* CS4315_tx_drive_4inch */
+ /* for length 4inches */
+ {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000},
+ {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023},
+ {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E},
+};
+
+void cs4340_upload_firmware(struct phy_device *phydev)
+{
+ char line_temp[0x50] = {0};
+ char reg_addr[0x50] = {0};
+ char reg_data[0x50] = {0};
+ int i, line_cnt = 0, column_cnt = 0;
+ struct cortina_reg_config fw_temp;
+ char *addr = NULL;
+
+#if defined(CONFIG_SYS_CORTINA_FW_IN_NOR) || \
+ defined(CONFIG_SYS_CORTINA_FW_IN_REMOTE)
+
+ addr = (char *)CONFIG_CORTINA_FW_ADDR;
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_NAND)
+ int ret;
+ size_t fw_length = CONFIG_CORTINA_FW_LENGTH;
+
+ addr = malloc(CONFIG_CORTINA_FW_LENGTH);
+ ret = nand_read(&nand_info[0], (loff_t)CONFIG_CORTINA_FW_ADDR,
+ &fw_length, (u_char *)addr);
+ if (ret == -EUCLEAN) {
+ printf("NAND read of Cortina firmware at 0x%x failed %d\n",
+ CONFIG_CORTINA_FW_ADDR, ret);
+ }
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH)
+ int ret;
+ struct spi_flash *ucode_flash;
+
+ addr = malloc(CONFIG_CORTINA_FW_LENGTH);
+ ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (!ucode_flash) {
+ puts("SF: probe for Cortina ucode failed\n");
+ } else {
+ ret = spi_flash_read(ucode_flash, CONFIG_CORTINA_FW_ADDR,
+ CONFIG_CORTINA_FW_LENGTH, addr);
+ if (ret)
+ puts("SF: read for Cortina ucode failed\n");
+ spi_flash_free(ucode_flash);
+ }
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC)
+ int dev = CONFIG_SYS_MMC_ENV_DEV;
+ u32 cnt = CONFIG_CORTINA_FW_LENGTH / 512;
+ u32 blk = CONFIG_CORTINA_FW_ADDR / 512;
+ struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
+
+ if (!mmc) {
+ puts("Failed to find MMC device for Cortina ucode\n");
+ } else {
+ addr = malloc(CONFIG_CORTINA_FW_LENGTH);
+ printf("MMC read: dev # %u, block # %u, count %u ...\n",
+ dev, blk, cnt);
+ mmc_init(mmc);
+ (void)mmc->block_dev.block_read(dev, blk, cnt, addr);
+ /* flush cache after read */
+ flush_cache((ulong)addr, cnt * 512);
+ }
+#endif
+
+ while (*addr != 'Q') {
+ i = 0;
+
+ while (*addr != 0x0a) {
+ line_temp[i++] = *addr++;
+ if (0x50 < i) {
+ printf("Not found Cortina PHY ucode at 0x%x\n",
+ CONFIG_CORTINA_FW_ADDR);
+ return;
+ }
+ }
+
+ addr++; /* skip '\n' */
+ line_cnt++;
+ column_cnt = i;
+ line_temp[column_cnt] = '\0';
+
+ if (CONFIG_CORTINA_FW_LENGTH < line_cnt)
+ return;
+
+ for (i = 0; i < column_cnt; i++) {
+ if (isspace(line_temp[i++]))
+ break;
+ }
+
+ memcpy(reg_addr, line_temp, i);
+ memcpy(reg_data, &line_temp[i], column_cnt - i);
+ strim(reg_addr);
+ strim(reg_data);
+ fw_temp.reg_addr = (simple_strtoul(reg_addr, NULL, 0)) & 0xffff;
+ fw_temp.reg_value = (simple_strtoul(reg_data, NULL, 0)) &
+ 0xffff;
+ phy_write(phydev, 0x00, fw_temp.reg_addr, fw_temp.reg_value);
+ }
+}
+
+int cs4340_phy_init(struct phy_device *phydev)
+{
+ int timeout = 100; /* 100ms */
+ int reg_value;
+
+ /* step1: BIST test */
+ phy_write(phydev, 0x00, VILLA_GLOBAL_MSEQCLKCTRL, 0x0004);
+ phy_write(phydev, 0x00, VILLA_GLOBAL_LINE_SOFT_RESET, 0x0000);
+ phy_write(phydev, 0x00, VILLA_GLOBAL_BIST_CONTROL, 0x0001);
+ while (--timeout) {
+ reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_BIST_STATUS);
+ if (reg_value & mseq_edc_bist_done) {
+ if (0 == (reg_value & mseq_edc_bist_fail))
+ break;
+ }
+ udelay(1000);
+ }
+
+ if (!timeout) {
+ printf("%s BIST mseq_edc_bist_done timeout!\n", __func__);
+ return -1;
+ }
+
+ /* setp2: upload ucode */
+ cs4340_upload_firmware(phydev);
+ reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_DWNLD_CHECKSUM_STATUS);
+ if (reg_value) {
+ debug("%s checksum status failed.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cs4340_config(struct phy_device *phydev)
+{
+ cs4340_phy_init(phydev);
+ return 0;
+}
+
+int cs4340_startup(struct phy_device *phydev)
+{
+ phydev->link = 1;
+
+ /* For now just lie and say it's 10G all the time */
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+ return 0;
+}
+
+struct phy_driver cs4340_driver = {
+ .name = "Cortina CS4315/CS4340",
+ .uid = PHY_UID_CS4340,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
+ MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
+ MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
+ .config = &cs4340_config,
+ .startup = &cs4340_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
+int phy_cortina_init(void)
+{
+ phy_register(&cs4340_driver);
+ return 0;
+}
+
+int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
+{
+ int phy_reg;
+ bool is_cortina_phy = false;
+
+ switch (addr) {
+#ifdef CORTINA_PHY_ADDR1
+ case CORTINA_PHY_ADDR1:
+#endif
+#ifdef CORTINA_PHY_ADDR2
+ case CORTINA_PHY_ADDR2:
+#endif
+#ifdef CORTINA_PHY_ADDR3
+ case CORTINA_PHY_ADDR3:
+#endif
+#ifdef CORTINA_PHY_ADDR4
+ case CORTINA_PHY_ADDR4:
+#endif
+ is_cortina_phy = true;
+ break;
+ default:
+ break;
+ }
+
+ /* Cortina PHY has non-standard offset of PHY ID registers */
+ if (is_cortina_phy)
+ phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_LSB);
+ else
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id = (phy_reg & 0xffff) << 16;
+ if (is_cortina_phy)
+ phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_MSB);
+ else
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id |= (phy_reg & 0xffff);
+
+ return 0;
+}
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index d2ecadc890..9437c3bbcc 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -276,6 +276,57 @@ static int m88e1111s_config(struct phy_device *phydev)
return 0;
}
+/**
+ * m88e1518_phy_writebits - write bits to a register
+ */
+void m88e1518_phy_writebits(struct phy_device *phydev,
+ u8 reg_num, u16 offset, u16 len, u16 data)
+{
+ u16 reg, mask;
+
+ if ((len + offset) >= 16)
+ mask = 0 - (1 << offset);
+ else
+ mask = (1 << (len + offset)) - (1 << offset);
+
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num);
+
+ reg &= ~mask;
+ reg |= data << offset;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg);
+}
+
+static int m88e1518_config(struct phy_device *phydev)
+{
+ /*
+ * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512
+ * /88E1514 Rev A0, Errata Section 3.1
+ */
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff); /* page 0xff */
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D);
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000); /* reg page 0 */
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 18); /* reg page 18 */
+ /* Write HWCFG_MODE = SGMII to Copper */
+ m88e1518_phy_writebits(phydev, 20, 0, 3, 1);
+
+ /* Phy reset */
+ m88e1518_phy_writebits(phydev, 20, 15, 1, 1);
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 0); /* reg page 18 */
+ udelay(100);
+ }
+
+ return m88e1111s_config(phydev);
+}
+
/* Marvell 88E1118 */
static int m88e1118_config(struct phy_device *phydev)
{
@@ -493,7 +544,7 @@ static struct phy_driver M88E1518_driver = {
.uid = 0x1410dd1,
.mask = 0xffffff0,
.features = PHY_GBIT_FEATURES,
- .config = &m88e1111s_config,
+ .config = &m88e1518_config,
.startup = &m88e1011s_startup,
.shutdown = &genphy_shutdown,
};
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 467c972243..5b04c85939 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -448,6 +448,9 @@ int phy_init(void)
#ifdef CONFIG_PHY_BROADCOM
phy_broadcom_init();
#endif
+#ifdef CONFIG_PHY_CORTINA
+ phy_cortina_init();
+#endif
#ifdef CONFIG_PHY_DAVICOM
phy_davicom_init();
#endif
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 2b29cd89f8..20a67466a7 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -1,8 +1,8 @@
/*
* Vitesse PHY drivers
*
- * Copyright 2010-2012 Freescale Semiconductor, Inc.
- * Author: Andy Fleming
+ * Copyright 2010-2014 Freescale Semiconductor, Inc.
+ * Original Author: Andy Fleming
* Add vsc8662 phy support - Priyanka Jain
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -50,6 +50,7 @@
#define MIIM_VSC8574_18G_CMDSTAT 0x8000
/* Vitesse VSC8514 control register */
+#define MIIM_VSC8514_MAC_SERDES_CON 0x10
#define MIIM_VSC8514_GENERAL18 0x12
#define MIIM_VSC8514_GENERAL19 0x13
#define MIIM_VSC8514_GENERAL23 0x17
@@ -246,6 +247,14 @@ static int vsc8514_config(struct phy_device *phydev)
val = (val & 0xf8ff);
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val);
+ /* Enable Serdes Auto-negotiation */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_EXTENDED3);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON);
+ val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val);
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+
genphy_config_aneg(phydev);
return 0;
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index c3ce17516c..cea6701203 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -41,6 +41,7 @@
* Modified to use le32_to_cpu and cpu_to_le32 properly
*/
#include <common.h>
+#include <errno.h>
#include <malloc.h>
#include <net.h>
#include <netdev.h>
@@ -79,7 +80,11 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */
-#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
+#ifdef CONFIG_SYS_RX_ETH_BUFFER
+ #define NUM_RX_DESC CONFIG_SYS_RX_ETH_BUFFER
+#else
+ #define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
+#endif
#define RX_BUF_SIZE 1536 /* Rx Buffer size */
#define RX_BUF_LEN 8192
@@ -248,6 +253,7 @@ static struct {
{"RTL-8168b/8111sb", 0x38, 0xff7e1880,},
{"RTL-8168d/8111d", 0x28, 0xff7e1880,},
{"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,},
+ {"RTL-8168/8111g", 0x4c, 0xff7e1880,},
{"RTL-8101e", 0x34, 0xff7e1880,},
{"RTL-8100e", 0x32, 0xff7e1880,},
};
@@ -273,23 +279,40 @@ struct RxDesc {
u32 buf_Haddr;
};
-/* Define the TX Descriptor */
-static u8 tx_ring[NUM_TX_DESC * sizeof(struct TxDesc) + 256];
-/* __attribute__ ((aligned(256))); */
+#define RTL8169_DESC_SIZE 16
-/* Create a static buffer of size RX_BUF_SZ for each
-TX Descriptor. All descriptors point to a
-part of this buffer */
-static unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
+#if ARCH_DMA_MINALIGN > 256
+# define RTL8169_ALIGN ARCH_DMA_MINALIGN
+#else
+# define RTL8169_ALIGN 256
+#endif
-/* Define the RX Descriptor */
-static u8 rx_ring[NUM_RX_DESC * sizeof(struct TxDesc) + 256];
- /* __attribute__ ((aligned(256))); */
+/*
+ * Warn if the cache-line size is larger than the descriptor size. In such
+ * cases the driver will likely fail because the CPU needs to flush the cache
+ * when requeuing RX buffers, therefore descriptors written by the hardware
+ * may be discarded.
+ *
+ * This can be fixed by defining CONFIG_SYS_NONCACHED_MEMORY which will cause
+ * the driver to allocate descriptors from a pool of non-cached memory.
+ */
+#if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN
+#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#warning cache-line size is larger than descriptor size
+#endif
+#endif
-/* Create a static buffer of size RX_BUF_SZ for each
-RX Descriptor All descriptors point to a
-part of this buffer */
-static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
+/*
+ * Create a static buffer of size RX_BUF_SZ for each TX Descriptor. All
+ * descriptors point to a part of this buffer.
+ */
+DEFINE_ALIGN_BUFFER(u8, txb, NUM_TX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
+
+/*
+ * Create a static buffer of size RX_BUF_SZ for each RX Descriptor. All
+ * descriptors point to a part of this buffer.
+ */
+DEFINE_ALIGN_BUFFER(u8, rxb, NUM_RX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
struct rtl8169_private {
void *mmio_addr; /* memory map physical address */
@@ -297,8 +320,6 @@ struct rtl8169_private {
unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
unsigned long dirty_tx;
- unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */
- unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */
struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
unsigned char *RxBufferRings; /* Index of Rx Buffer */
@@ -398,34 +419,71 @@ match:
}
/*
+ * TX and RX descriptors are 16 bytes. This causes problems with the cache
+ * maintenance on CPUs where the cache-line size exceeds the size of these
+ * descriptors. What will happen is that when the driver receives a packet
+ * it will be immediately requeued for the hardware to reuse. The CPU will
+ * therefore need to flush the cache-line containing the descriptor, which
+ * will cause all other descriptors in the same cache-line to be flushed
+ * along with it. If one of those descriptors had been written to by the
+ * device those changes (and the associated packet) will be lost.
+ *
+ * To work around this, we make use of non-cached memory if available. If
+ * descriptors are mapped uncached there's no need to manually flush them
+ * or invalidate them.
+ *
+ * Note that this only applies to descriptors. The packet data buffers do
+ * not have the same constraints since they are 1536 bytes large, so they
+ * are unlikely to share cache-lines.
+ */
+static void *rtl_alloc_descs(unsigned int num)
+{
+ size_t size = num * RTL8169_DESC_SIZE;
+
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+ return (void *)noncached_alloc(size, RTL8169_ALIGN);
+#else
+ return memalign(RTL8169_ALIGN, size);
+#endif
+}
+
+/*
* Cache maintenance functions. These are simple wrappers around the more
* general purpose flush_cache() and invalidate_dcache_range() functions.
*/
static void rtl_inval_rx_desc(struct RxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
invalidate_dcache_range(start, end);
+#endif
}
static void rtl_flush_rx_desc(struct RxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
flush_cache((unsigned long)desc, sizeof(*desc));
+#endif
}
static void rtl_inval_tx_desc(struct TxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
invalidate_dcache_range(start, end);
+#endif
}
static void rtl_flush_tx_desc(struct TxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
flush_cache((unsigned long)desc, sizeof(*desc));
+#endif
}
static void rtl_inval_buffer(void *buf, size_t size)
@@ -707,16 +765,6 @@ static int rtl_reset(struct eth_device *dev, bd_t *bis)
printf ("%s\n", __FUNCTION__);
#endif
- tpc->TxDescArrays = tx_ring;
- /* Tx Desscriptor needs 256 bytes alignment; */
- tpc->TxDescArray = (struct TxDesc *) ((unsigned long)(tpc->TxDescArrays +
- 255) & ~255);
-
- tpc->RxDescArrays = rx_ring;
- /* Rx Desscriptor needs 256 bytes alignment; */
- tpc->RxDescArray = (struct RxDesc *) ((unsigned long)(tpc->RxDescArrays +
- 255) & ~255);
-
rtl8169_init_ring(dev);
rtl8169_hw_start(dev);
/* Construct a perfect filter frame with the mac address as first match
@@ -758,10 +806,6 @@ static void rtl_halt(struct eth_device *dev)
RTL_W32(RxMissed, 0);
- tpc->TxDescArrays = NULL;
- tpc->RxDescArrays = NULL;
- tpc->TxDescArray = NULL;
- tpc->RxDescArray = NULL;
for (i = 0; i < NUM_RX_DESC; i++) {
tpc->RxBufferRing[i] = NULL;
}
@@ -906,7 +950,16 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)
#endif
}
- return 1;
+
+ tpc->RxDescArray = rtl_alloc_descs(NUM_RX_DESC);
+ if (!tpc->RxDescArray)
+ return -ENOMEM;
+
+ tpc->TxDescArray = rtl_alloc_descs(NUM_TX_DESC);
+ if (!tpc->TxDescArray)
+ return -ENOMEM;
+
+ return 0;
}
int rtl8169_initialize(bd_t *bis)
@@ -920,6 +973,7 @@ int rtl8169_initialize(bd_t *bis)
while(1){
unsigned int region;
u16 device;
+ int err;
/* Find RTL8169 */
if ((devno = pci_find_devices(supported, idx++)) < 0)
@@ -958,9 +1012,14 @@ int rtl8169_initialize(bd_t *bis)
dev->send = rtl_send;
dev->recv = rtl_recv;
- eth_register (dev);
+ err = rtl_init(dev, bis);
+ if (err < 0) {
+ printf(pr_fmt("failed to initialize card: %d\n"), err);
+ free(dev);
+ continue;
+ }
- rtl_init(dev, bis);
+ eth_register (dev);
card_number++;
}
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 451c33e1a1..4bf493ed45 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -2,9 +2,9 @@
* sh_eth.c - Driver for Renesas ethernet controler.
*
* Copyright (C) 2008, 2011 Renesas Solutions Corp.
- * Copyright (c) 2008, 2011 Nobuhiro Iwamatsu
+ * Copyright (c) 2008, 2011, 2014 2014 Nobuhiro Iwamatsu
* Copyright (c) 2007 Carlos Munoz <carlos@kenati.com>
- * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013, 2014 Renesas Electronics Corporation
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -83,6 +83,8 @@ int sh_eth_send(struct eth_device *dev, void *packet, int len)
else
port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP;
+ flush_cache_wback(port_info->tx_desc_cur, sizeof(struct tx_desc_s));
+
/* Restart the transmitter if disabled */
if (!(sh_eth_read(eth, EDTRR) & EDTRR_TRNS))
sh_eth_write(eth, EDTRR_TRNS, EDTRR);
@@ -133,6 +135,10 @@ int sh_eth_recv(struct eth_device *dev)
port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE;
else
port_info->rx_desc_cur->rd0 = RD_RACT;
+
+ flush_cache_wback(port_info->rx_desc_cur,
+ sizeof(struct rx_desc_s));
+
/* Point to the next descriptor */
port_info->rx_desc_cur++;
if (port_info->rx_desc_cur >=
@@ -181,27 +187,27 @@ static int sh_eth_reset(struct sh_eth_dev *eth)
static int sh_eth_tx_desc_init(struct sh_eth_dev *eth)
{
int port = eth->port, i, ret = 0;
- u32 tmp_addr;
+ u32 alloc_desc_size = NUM_TX_DESC * sizeof(struct tx_desc_s);
struct sh_eth_info *port_info = &eth->port_info[port];
struct tx_desc_s *cur_tx_desc;
/*
- * Allocate tx descriptors. They must be TX_DESC_SIZE bytes aligned
+ * Allocate rx descriptors. They must be aligned to size of struct
+ * tx_desc_s.
*/
- port_info->tx_desc_malloc = malloc(NUM_TX_DESC *
- sizeof(struct tx_desc_s) +
- TX_DESC_SIZE - 1);
- if (!port_info->tx_desc_malloc) {
- printf(SHETHER_NAME ": malloc failed\n");
+ port_info->tx_desc_alloc =
+ memalign(sizeof(struct tx_desc_s), alloc_desc_size);
+ if (!port_info->tx_desc_alloc) {
+ printf(SHETHER_NAME ": memalign failed\n");
ret = -ENOMEM;
goto err;
}
- tmp_addr = (u32) (((int)port_info->tx_desc_malloc + TX_DESC_SIZE - 1) &
- ~(TX_DESC_SIZE - 1));
- flush_cache_wback(tmp_addr, NUM_TX_DESC * sizeof(struct tx_desc_s));
+ flush_cache_wback((u32)port_info->tx_desc_alloc, alloc_desc_size);
+
/* Make sure we use a P2 address (non-cacheable) */
- port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2(tmp_addr);
+ port_info->tx_desc_base =
+ (struct tx_desc_s *)ADDR_TO_P2((u32)port_info->tx_desc_alloc);
port_info->tx_desc_cur = port_info->tx_desc_base;
/* Initialize all descriptors */
@@ -232,47 +238,44 @@ err:
static int sh_eth_rx_desc_init(struct sh_eth_dev *eth)
{
int port = eth->port, i , ret = 0;
+ u32 alloc_desc_size = NUM_RX_DESC * sizeof(struct rx_desc_s);
struct sh_eth_info *port_info = &eth->port_info[port];
struct rx_desc_s *cur_rx_desc;
- u32 tmp_addr;
u8 *rx_buf;
/*
- * Allocate rx descriptors. They must be RX_DESC_SIZE bytes aligned
+ * Allocate rx descriptors. They must be aligned to size of struct
+ * rx_desc_s.
*/
- port_info->rx_desc_malloc = malloc(NUM_RX_DESC *
- sizeof(struct rx_desc_s) +
- RX_DESC_SIZE - 1);
- if (!port_info->rx_desc_malloc) {
- printf(SHETHER_NAME ": malloc failed\n");
+ port_info->rx_desc_alloc =
+ memalign(sizeof(struct rx_desc_s), alloc_desc_size);
+ if (!port_info->rx_desc_alloc) {
+ printf(SHETHER_NAME ": memalign failed\n");
ret = -ENOMEM;
goto err;
}
- tmp_addr = (u32) (((int)port_info->rx_desc_malloc + RX_DESC_SIZE - 1) &
- ~(RX_DESC_SIZE - 1));
- flush_cache_wback(tmp_addr, NUM_RX_DESC * sizeof(struct rx_desc_s));
+ flush_cache_wback(port_info->rx_desc_alloc, alloc_desc_size);
+
/* Make sure we use a P2 address (non-cacheable) */
- port_info->rx_desc_base = (struct rx_desc_s *)ADDR_TO_P2(tmp_addr);
+ port_info->rx_desc_base =
+ (struct rx_desc_s *)ADDR_TO_P2((u32)port_info->rx_desc_alloc);
port_info->rx_desc_cur = port_info->rx_desc_base;
/*
- * Allocate rx data buffers. They must be 32 bytes aligned and in
- * P2 area
+ * Allocate rx data buffers. They must be RX_BUF_ALIGNE_SIZE bytes
+ * aligned and in P2 area.
*/
- port_info->rx_buf_malloc = malloc(
- NUM_RX_DESC * MAX_BUF_SIZE + RX_BUF_ALIGNE_SIZE - 1);
- if (!port_info->rx_buf_malloc) {
- printf(SHETHER_NAME ": malloc failed\n");
+ port_info->rx_buf_alloc =
+ memalign(RX_BUF_ALIGNE_SIZE, NUM_RX_DESC * MAX_BUF_SIZE);
+ if (!port_info->rx_buf_alloc) {
+ printf(SHETHER_NAME ": alloc failed\n");
ret = -ENOMEM;
- goto err_buf_malloc;
+ goto err_buf_alloc;
}
- tmp_addr = (u32)(((int)port_info->rx_buf_malloc
- + (RX_BUF_ALIGNE_SIZE - 1)) &
- ~(RX_BUF_ALIGNE_SIZE - 1));
- port_info->rx_buf_base = (u8 *)ADDR_TO_P2(tmp_addr);
+ port_info->rx_buf_base = (u8 *)ADDR_TO_P2((u32)port_info->rx_buf_alloc);
/* Initialize all descriptors */
for (cur_rx_desc = port_info->rx_desc_base,
@@ -297,9 +300,9 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth)
return ret;
-err_buf_malloc:
- free(port_info->rx_desc_malloc);
- port_info->rx_desc_malloc = NULL;
+err_buf_alloc:
+ free(port_info->rx_desc_alloc);
+ port_info->rx_desc_alloc = NULL;
err:
return ret;
@@ -310,9 +313,9 @@ static void sh_eth_tx_desc_free(struct sh_eth_dev *eth)
int port = eth->port;
struct sh_eth_info *port_info = &eth->port_info[port];
- if (port_info->tx_desc_malloc) {
- free(port_info->tx_desc_malloc);
- port_info->tx_desc_malloc = NULL;
+ if (port_info->tx_desc_alloc) {
+ free(port_info->tx_desc_alloc);
+ port_info->tx_desc_alloc = NULL;
}
}
@@ -321,14 +324,14 @@ static void sh_eth_rx_desc_free(struct sh_eth_dev *eth)
int port = eth->port;
struct sh_eth_info *port_info = &eth->port_info[port];
- if (port_info->rx_desc_malloc) {
- free(port_info->rx_desc_malloc);
- port_info->rx_desc_malloc = NULL;
+ if (port_info->rx_desc_alloc) {
+ free(port_info->rx_desc_alloc);
+ port_info->rx_desc_alloc = NULL;
}
- if (port_info->rx_buf_malloc) {
- free(port_info->rx_buf_malloc);
- port_info->rx_buf_malloc = NULL;
+ if (port_info->rx_buf_alloc) {
+ free(port_info->rx_buf_alloc);
+ port_info->rx_buf_alloc = NULL;
}
}
@@ -414,7 +417,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
#if defined(CONFIG_CPU_SH7734) || defined(CONFIG_R8A7740)
sh_eth_write(eth, CONFIG_SH_ETHER_SH7734_MII, RMII_MII);
#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
sh_eth_write(eth, sh_eth_read(eth, RMIIMR) | 0x1, RMIIMR);
#endif
/* Configure phy */
@@ -440,7 +443,8 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)
sh_eth_write(eth, 1, RTRATE);
#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) || \
- defined(CONFIG_R8A7791) || defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7791) || defined(CONFIG_R8A7793) || \
+ defined(CONFIG_R8A7794)
val = ECMR_RTM;
#endif
} else if (phy->speed == 10) {
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index e325a39aac..5cb520c63e 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -51,8 +51,6 @@
/* The size of the tx descriptor is determined by how much padding is used.
4, 20, or 52 bytes of padding can be used */
#define TX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12)
-/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */
-#define TX_DESC_SIZE (12 + TX_DESC_PADDING)
/* Tx descriptor. We always use 3 bytes of padding */
struct tx_desc_s {
@@ -68,8 +66,6 @@ struct tx_desc_s {
/* The size of the rx descriptor is determined by how much padding is used.
4, 20, or 52 bytes of padding can be used */
#define RX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12)
-/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */
-#define RX_DESC_SIZE (12 + RX_DESC_PADDING)
/* aligned cache line size */
#define RX_BUF_ALIGNE_SIZE (CONFIG_SH_ETHER_ALIGNE_SIZE > 32 ? 64 : 32)
@@ -82,13 +78,13 @@ struct rx_desc_s {
};
struct sh_eth_info {
- struct tx_desc_s *tx_desc_malloc;
+ struct tx_desc_s *tx_desc_alloc;
struct tx_desc_s *tx_desc_base;
struct tx_desc_s *tx_desc_cur;
- struct rx_desc_s *rx_desc_malloc;
+ struct rx_desc_s *rx_desc_alloc;
struct rx_desc_s *rx_desc_base;
struct rx_desc_s *rx_desc_cur;
- u8 *rx_buf_malloc;
+ u8 *rx_buf_alloc;
u8 *rx_buf_base;
u8 mac_addr[6];
u8 phy_addr;
@@ -359,7 +355,7 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
#define SH_ETH_TYPE_GETHER
#define BASE_IO_ADDR 0xE9A00000
#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
#define SH_ETH_TYPE_ETHER
#define BASE_IO_ADDR 0xEE700200
#elif defined(CONFIG_R7S72100)
@@ -571,7 +567,7 @@ enum FELIC_MODE_BIT {
#ifdef CONFIG_CPU_SH7724
ECMR_RTM = 0x00000010,
#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
ECMR_RTM = 0x00000004,
#endif
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index b097c1a56f..5959672370 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -187,6 +187,7 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length)
static void smc911x_halt(struct eth_device *dev)
{
smc911x_reset(dev);
+ smc911x_handle_mac_address(dev);
}
static int smc911x_rx(struct eth_device *dev)
diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c
index 538f11e3eb..9526faa4af 100644
--- a/drivers/net/uli526x.c
+++ b/drivers/net/uli526x.c
@@ -548,7 +548,7 @@ static int uli526x_rx_packet(struct eth_device *dev)
rdes0 = le32_to_cpu(rxptr->rdes0);
#ifdef RX_DEBUG
- printf("%s(): rxptr->rdes0=%x:%x\n", __FUNCTION__, rxptr->rdes0);
+ printf("%s(): rxptr->rdes0=%x\n", __FUNCTION__, rxptr->rdes0);
#endif
if (!(rdes0 & 0x80000000)) { /* packet owner check */
if ((rdes0 & 0x300) != 0x300) {
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e73a498619..50b7be53ca 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -6,7 +6,7 @@
#
obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
-obj-$(CONFIG_PCI) += pci.o pci_auto.o
+obj-$(CONFIG_PCI) += pci.o pci_auto.o pci_rom.o
obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
@@ -15,5 +15,7 @@ obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
obj-$(CONFIG_SH4_PCI) += pci_sh4.o
obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
obj-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
+obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o
obj-$(CONFIG_TSI108_PCI) += tsi108_pci.o
obj-$(CONFIG_WINBOND_83C553) += w83c553f.o
+obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 60c333e2c0..83fd9a068f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -19,6 +19,8 @@
#include <asm/io.h>
#include <pci.h>
+DECLARE_GLOBAL_DATA_PTR;
+
#define PCI_HOSE_OP(rw, size, type) \
int pci_hose_##rw##_config_##size(struct pci_controller *hose, \
pci_dev_t dev, \
@@ -123,6 +125,14 @@ void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
static struct pci_controller* hose_head;
+struct pci_controller *pci_get_hose_head(void)
+{
+ if (gd->hose)
+ return gd->hose;
+
+ return hose_head;
+}
+
void pci_register_hose(struct pci_controller* hose)
{
struct pci_controller **phose = &hose_head;
@@ -139,7 +149,7 @@ struct pci_controller *pci_bus_to_hose(int bus)
{
struct pci_controller *hose;
- for (hose = hose_head; hose; hose = hose->next) {
+ for (hose = pci_get_hose_head(); hose; hose = hose->next) {
if (bus >= hose->first_busno && bus <= hose->last_busno)
return hose;
}
@@ -152,7 +162,7 @@ struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
{
struct pci_controller *hose;
- for (hose = hose_head; hose; hose = hose->next) {
+ for (hose = pci_get_hose_head(); hose; hose = hose->next) {
if (hose->cfg_addr == cfg_addr)
return hose;
}
@@ -162,7 +172,7 @@ struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
int pci_last_busno(void)
{
- struct pci_controller *hose = hose_head;
+ struct pci_controller *hose = pci_get_hose_head();
if (!hose)
return -1;
@@ -181,7 +191,7 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
pci_dev_t bdf;
int i, bus, found_multi = 0;
- for (hose = hose_head; hose; hose = hose->next) {
+ for (hose = pci_get_hose_head(); hose; hose = hose->next) {
#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
#else
@@ -195,6 +205,9 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
bdf < PCI_BDF(bus + 1, 0, 0);
#endif
bdf += PCI_BDF(0, 0, 1)) {
+ if (pci_skip_dev(hose, bdf))
+ continue;
+
if (!PCI_FUNC(bdf)) {
pci_read_config_byte(bdf,
PCI_HEADER_TYPE,
@@ -230,7 +243,7 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
{
- static struct pci_device_id ids[2] = {{}, {0, 0}};
+ struct pci_device_id ids[2] = { {}, {0, 0} };
ids[0].vendor = vendor;
ids[0].device = device;
@@ -363,9 +376,27 @@ phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
return phys_addr;
}
-/*
- *
- */
+void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
+ u32 addr_and_ctrl)
+{
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
+}
+
+u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
+{
+ u32 addr;
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ pci_hose_read_config_dword(hose, dev, bar, &addr);
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+ return addr & PCI_BASE_ADDRESS_IO_MASK;
+ else
+ return addr & PCI_BASE_ADDRESS_MEM_MASK;
+}
int pci_hose_config_device(struct pci_controller *hose,
pci_dev_t dev,
@@ -662,13 +693,15 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus)
#endif
#ifdef CONFIG_PCI_PNP
- sub_bus = max(pciauto_config_device(hose, dev), sub_bus);
+ sub_bus = max((unsigned int)pciauto_config_device(hose, dev),
+ sub_bus);
#else
cfg = pci_find_config(hose, class, vendor, device,
PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
if (cfg) {
cfg->config_device(hose, dev, cfg);
- sub_bus = max(sub_bus, hose->current_busno);
+ sub_bus = max(sub_bus,
+ (unsigned int)hose->current_busno);
}
#endif
@@ -686,11 +719,10 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus)
int pci_hose_scan(struct pci_controller *hose)
{
#if defined(CONFIG_PCI_BOOTDELAY)
- static int pcidelay_done;
char *s;
int i;
- if (!pcidelay_done) {
+ if (!gd->pcidelay_done) {
/* wait "pcidelay" ms (if defined)... */
s = getenv("pcidelay");
if (s) {
@@ -698,7 +730,7 @@ int pci_hose_scan(struct pci_controller *hose)
for (i = 0; i < val; i++)
udelay(1000);
}
- pcidelay_done = 1;
+ gd->pcidelay_done = 1;
}
#endif /* CONFIG_PCI_BOOTDELAY */
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index 86ba6b523c..44470fa812 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -387,7 +387,7 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
n = pci_hose_scan_bus(hose, hose->current_busno);
/* figure out the deepest we've gone for this leg */
- sub_bus = max(n, sub_bus);
+ sub_bus = max((unsigned int)n, sub_bus);
pciauto_postscan_setup_bridge(hose, dev, sub_bus);
sub_bus = hose->current_busno;
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
new file mode 100644
index 0000000000..7d25cc9f2f
--- /dev/null
+++ b/drivers/pci/pci_rom.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * From coreboot, originally based on the Linux kernel (drivers/pci/pci.c).
+ *
+ * Modifications are:
+ * Copyright (C) 2003-2004 Linux Networx
+ * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
+ * Copyright (C) 2003-2006 Ronald G. Minnich <rminnich@gmail.com>
+ * Copyright (C) 2004-2005 Li-Ta Lo <ollie@lanl.gov>
+ * Copyright (C) 2005-2006 Tyan
+ * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
+ * Copyright (C) 2005-2009 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
+ *
+ * PCI Bus Services, see include/linux/pci.h for further explanation.
+ *
+ * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ * David Mosberger-Tang
+ *
+ * Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <bios_emul.h>
+#include <errno.h>
+#include <malloc.h>
+#include <pci.h>
+#include <pci_rom.h>
+#include <vbe.h>
+#include <video_fb.h>
+
+#ifdef CONFIG_HAVE_ACPI_RESUME
+#include <asm/acpi.h>
+#endif
+
+__weak bool board_should_run_oprom(pci_dev_t dev)
+{
+ return true;
+}
+
+static bool should_load_oprom(pci_dev_t dev)
+{
+#ifdef CONFIG_HAVE_ACPI_RESUME
+ if (acpi_get_slp_type() == 3)
+ return false;
+#endif
+ if (IS_ENABLED(CONFIG_ALWAYS_LOAD_OPROM))
+ return 1;
+ if (board_should_run_oprom(dev))
+ return 1;
+
+ return 0;
+}
+
+__weak uint32_t board_map_oprom_vendev(uint32_t vendev)
+{
+ return vendev;
+}
+
+static int pci_rom_probe(pci_dev_t dev, uint class,
+ struct pci_rom_header **hdrp)
+{
+ struct pci_rom_header *rom_header;
+ struct pci_rom_data *rom_data;
+ u16 vendor, device;
+ u32 vendev;
+ u32 mapped_vendev;
+ u32 rom_address;
+
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
+ pci_read_config_word(dev, PCI_DEVICE_ID, &device);
+ vendev = vendor << 16 | device;
+ mapped_vendev = board_map_oprom_vendev(vendev);
+ if (vendev != mapped_vendev)
+ debug("Device ID mapped to %#08x\n", mapped_vendev);
+
+#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);
+ 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);
+ return -ENOENT;
+ }
+
+ /* Enable expansion ROM address decoding. */
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+ rom_address | PCI_ROM_ADDRESS_ENABLE);
+#endif
+ debug("Option ROM address %x\n", rom_address);
+ rom_header = (struct pci_rom_header *)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));
+
+ if (le32_to_cpu(rom_header->signature) != PCI_ROM_HDR) {
+ printf("Incorrect expansion ROM header signature %04x\n",
+ le32_to_cpu(rom_header->signature));
+ return -EINVAL;
+ }
+
+ rom_data = (((void *)rom_header) + le32_to_cpu(rom_header->data));
+
+ debug("PCI ROM image, vendor ID %04x, device ID %04x,\n",
+ rom_data->vendor, rom_data->device);
+
+ /* If the device id is mapped, a mismatch is expected */
+ if ((vendor != rom_data->vendor || device != rom_data->device) &&
+ (vendev == mapped_vendev)) {
+ printf("ID mismatch: vendor ID %04x, device ID %04x\n",
+ rom_data->vendor, rom_data->device);
+ return -EPERM;
+ }
+
+ debug("PCI ROM image, Class Code %04x%02x, Code Type %02x\n",
+ rom_data->class_hi, rom_data->class_lo, rom_data->type);
+
+ if (class != ((rom_data->class_hi << 8) | rom_data->class_lo)) {
+ debug("Class Code mismatch ROM %08x, dev %08x\n",
+ (rom_data->class_hi << 8) | rom_data->class_lo,
+ class);
+ }
+ *hdrp = rom_header;
+
+ return 0;
+}
+
+int pci_rom_load(uint16_t class, struct pci_rom_header *rom_header,
+ struct pci_rom_header **ram_headerp)
+{
+ struct pci_rom_data *rom_data;
+ unsigned int rom_size;
+ unsigned int image_size = 0;
+ void *target;
+
+ do {
+ /* Get next image, until we see an x86 version */
+ rom_header = (struct pci_rom_header *)((void *)rom_header +
+ image_size);
+
+ rom_data = (struct pci_rom_data *)((void *)rom_header +
+ le32_to_cpu(rom_header->data));
+
+ image_size = le32_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;
+
+ target = (void *)PCI_VGA_RAM_IMAGE_START;
+ if (target != rom_header) {
+ ulong start = get_timer(0);
+
+ debug("Copying VGA ROM Image from %p to %p, 0x%x bytes\n",
+ rom_header, target, rom_size);
+ memcpy(target, rom_header, rom_size);
+ if (memcmp(target, rom_header, rom_size)) {
+ printf("VGA ROM copy failed\n");
+ return -EFAULT;
+ }
+ debug("Copy took %lums\n", get_timer(start));
+ }
+ *ram_headerp = target;
+
+ return 0;
+}
+
+static struct vbe_mode_info mode_info;
+
+int vbe_get_video_info(struct graphic_device *gdev)
+{
+#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE
+ struct vesa_mode_info *vesa = &mode_info.vesa;
+
+ gdev->winSizeX = vesa->x_resolution;
+ gdev->winSizeY = vesa->y_resolution;
+
+ gdev->plnSizeX = vesa->x_resolution;
+ gdev->plnSizeY = vesa->y_resolution;
+
+ gdev->gdfBytesPP = vesa->bits_per_pixel / 8;
+
+ switch (vesa->bits_per_pixel) {
+ case 24:
+ gdev->gdfIndex = GDF_32BIT_X888RGB;
+ break;
+ case 16:
+ gdev->gdfIndex = GDF_16BIT_565RGB;
+ break;
+ default:
+ gdev->gdfIndex = GDF__8BIT_INDEX;
+ break;
+ }
+
+ gdev->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS;
+ gdev->pciBase = vesa->phys_base_ptr;
+
+ gdev->frameAdrs = vesa->phys_base_ptr;
+ gdev->memSize = vesa->bytes_per_scanline * vesa->y_resolution;
+
+ gdev->vprBase = vesa->phys_base_ptr;
+ gdev->cprBase = vesa->phys_base_ptr;
+
+ return gdev->winSizeX ? 0 : -ENOSYS;
+#else
+ return -ENOSYS;
+#endif
+}
+
+int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate)
+{
+ struct pci_rom_header *rom, *ram;
+ int vesa_mode = -1;
+ uint16_t class;
+ int ret;
+
+ /* Only execute VGA ROMs */
+ pci_read_config_word(dev, PCI_CLASS_DEVICE, &class);
+ if ((class ^ PCI_CLASS_DISPLAY_VGA) & 0xff00) {
+ debug("%s: Class %#x, should be %#x\n", __func__, class,
+ PCI_CLASS_DISPLAY_VGA);
+ return -ENODEV;
+ }
+
+ if (!should_load_oprom(dev))
+ return -ENXIO;
+
+ ret = pci_rom_probe(dev, class, &rom);
+ if (ret)
+ return ret;
+
+ ret = pci_rom_load(class, rom, &ram);
+ if (ret)
+ return ret;
+
+ if (!board_should_run_oprom(dev))
+ return -ENXIO;
+
+#if defined(CONFIG_FRAMEBUFFER_SET_VESA_MODE) && \
+ defined(CONFIG_FRAMEBUFFER_VESA_MODE)
+ vesa_mode = CONFIG_FRAMEBUFFER_VESA_MODE;
+#endif
+ debug("Selected vesa mode %#x\n", vesa_mode);
+ if (emulate) {
+#ifdef CONFIG_BIOSEMU
+ BE_VGAInfo *info;
+
+ ret = biosemu_setup(dev, &info);
+ if (ret)
+ return ret;
+ biosemu_set_interrupt_handler(0x15, int15_handler);
+ ret = biosemu_run(dev, (uchar *)ram, 1 << 16, info, true,
+ 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
+ bios_set_interrupt_handler(0x15, int15_handler);
+
+ 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);
+
+ return 0;
+}
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
new file mode 100644
index 0000000000..f9e05add19
--- /dev/null
+++ b/drivers/pci/pci_tegra.c
@@ -0,0 +1,1144 @@
+/*
+ * Copyright (c) 2010, CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on NVIDIA PCIe driver
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * Copyright (c) 2013-2014, NVIDIA Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#define DEBUG
+#define pr_fmt(fmt) "tegra-pcie: " fmt
+
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <pci.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/powergate.h>
+#include <asm/arch-tegra/xusb-padctl.h>
+
+#include <linux/list.h>
+
+#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define AFI_AXI_BAR0_SZ 0x00
+#define AFI_AXI_BAR1_SZ 0x04
+#define AFI_AXI_BAR2_SZ 0x08
+#define AFI_AXI_BAR3_SZ 0x0c
+#define AFI_AXI_BAR4_SZ 0x10
+#define AFI_AXI_BAR5_SZ 0x14
+
+#define AFI_AXI_BAR0_START 0x18
+#define AFI_AXI_BAR1_START 0x1c
+#define AFI_AXI_BAR2_START 0x20
+#define AFI_AXI_BAR3_START 0x24
+#define AFI_AXI_BAR4_START 0x28
+#define AFI_AXI_BAR5_START 0x2c
+
+#define AFI_FPCI_BAR0 0x30
+#define AFI_FPCI_BAR1 0x34
+#define AFI_FPCI_BAR2 0x38
+#define AFI_FPCI_BAR3 0x3c
+#define AFI_FPCI_BAR4 0x40
+#define AFI_FPCI_BAR5 0x44
+
+#define AFI_CACHE_BAR0_SZ 0x48
+#define AFI_CACHE_BAR0_ST 0x4c
+#define AFI_CACHE_BAR1_SZ 0x50
+#define AFI_CACHE_BAR1_ST 0x54
+
+#define AFI_MSI_BAR_SZ 0x60
+#define AFI_MSI_FPCI_BAR_ST 0x64
+#define AFI_MSI_AXI_BAR_ST 0x68
+
+#define AFI_CONFIGURATION 0xac
+#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
+
+#define AFI_FPCI_ERROR_MASKS 0xb0
+
+#define AFI_INTR_MASK 0xb4
+#define AFI_INTR_MASK_INT_MASK (1 << 0)
+#define AFI_INTR_MASK_MSI_MASK (1 << 8)
+
+#define AFI_SM_INTR_ENABLE 0xc4
+#define AFI_SM_INTR_INTA_ASSERT (1 << 0)
+#define AFI_SM_INTR_INTB_ASSERT (1 << 1)
+#define AFI_SM_INTR_INTC_ASSERT (1 << 2)
+#define AFI_SM_INTR_INTD_ASSERT (1 << 3)
+#define AFI_SM_INTR_INTA_DEASSERT (1 << 4)
+#define AFI_SM_INTR_INTB_DEASSERT (1 << 5)
+#define AFI_SM_INTR_INTC_DEASSERT (1 << 6)
+#define AFI_SM_INTR_INTD_DEASSERT (1 << 7)
+
+#define AFI_AFI_INTR_ENABLE 0xc8
+#define AFI_INTR_EN_INI_SLVERR (1 << 0)
+#define AFI_INTR_EN_INI_DECERR (1 << 1)
+#define AFI_INTR_EN_TGT_SLVERR (1 << 2)
+#define AFI_INTR_EN_TGT_DECERR (1 << 3)
+#define AFI_INTR_EN_TGT_WRERR (1 << 4)
+#define AFI_INTR_EN_DFPCI_DECERR (1 << 5)
+#define AFI_INTR_EN_AXI_DECERR (1 << 6)
+#define AFI_INTR_EN_FPCI_TIMEOUT (1 << 7)
+#define AFI_INTR_EN_PRSNT_SENSE (1 << 8)
+
+#define AFI_PCIE_CONFIG 0x0f8
+#define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1))
+#define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0xe
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
+
+#define AFI_FUSE 0x104
+#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
+
+#define AFI_PEX0_CTRL 0x110
+#define AFI_PEX1_CTRL 0x118
+#define AFI_PEX2_CTRL 0x128
+#define AFI_PEX_CTRL_RST (1 << 0)
+#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
+#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
+#define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4)
+
+#define AFI_PLLE_CONTROL 0x160
+#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
+#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
+
+#define AFI_PEXBIAS_CTRL_0 0x168
+
+#define PADS_CTL_SEL 0x0000009C
+
+#define PADS_CTL 0x000000A0
+#define PADS_CTL_IDDQ_1L (1 << 0)
+#define PADS_CTL_TX_DATA_EN_1L (1 << 6)
+#define PADS_CTL_RX_DATA_EN_1L (1 << 10)
+
+#define PADS_PLL_CTL_TEGRA20 0x000000B8
+#define PADS_PLL_CTL_TEGRA30 0x000000B4
+#define PADS_PLL_CTL_RST_B4SM (0x1 << 1)
+#define PADS_PLL_CTL_LOCKDET (0x1 << 8)
+#define PADS_PLL_CTL_REFCLK_MASK (0x3 << 16)
+#define PADS_PLL_CTL_REFCLK_INTERNAL_CML (0x0 << 16)
+#define PADS_PLL_CTL_REFCLK_INTERNAL_CMOS (0x1 << 16)
+#define PADS_PLL_CTL_REFCLK_EXTERNAL (0x2 << 16)
+#define PADS_PLL_CTL_TXCLKREF_MASK (0x1 << 20)
+#define PADS_PLL_CTL_TXCLKREF_DIV10 (0x0 << 20)
+#define PADS_PLL_CTL_TXCLKREF_DIV5 (0x1 << 20)
+#define PADS_PLL_CTL_TXCLKREF_BUF_EN (0x1 << 22)
+
+#define PADS_REFCLK_CFG0 0x000000C8
+#define PADS_REFCLK_CFG1 0x000000CC
+
+/*
+ * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
+ * entries, one entry per PCIe port. These field definitions and desired
+ * values aren't in the TRM, but do come from NVIDIA.
+ */
+#define PADS_REFCLK_CFG_TERM_SHIFT 2 /* 6:2 */
+#define PADS_REFCLK_CFG_E_TERM_SHIFT 7
+#define PADS_REFCLK_CFG_PREDI_SHIFT 8 /* 11:8 */
+#define PADS_REFCLK_CFG_DRVI_SHIFT 12 /* 15:12 */
+
+/* Default value provided by HW engineering is 0xfa5c */
+#define PADS_REFCLK_CFG_VALUE \
+ ( \
+ (0x17 << PADS_REFCLK_CFG_TERM_SHIFT) | \
+ (0 << PADS_REFCLK_CFG_E_TERM_SHIFT) | \
+ (0xa << PADS_REFCLK_CFG_PREDI_SHIFT) | \
+ (0xf << PADS_REFCLK_CFG_DRVI_SHIFT) \
+ )
+
+#define RP_VEND_XP 0x00000F00
+#define RP_VEND_XP_DL_UP (1 << 30)
+
+#define RP_PRIV_MISC 0x00000FE0
+#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
+#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
+
+#define RP_LINK_CONTROL_STATUS 0x00000090
+#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
+#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
+
+struct tegra_pcie;
+
+struct tegra_pcie_port {
+ struct tegra_pcie *pcie;
+
+ struct fdt_resource regs;
+ unsigned int num_lanes;
+ unsigned int index;
+
+ struct list_head list;
+};
+
+struct tegra_pcie_soc {
+ unsigned int num_ports;
+ unsigned long pads_pll_ctl;
+ unsigned long tx_ref_sel;
+ bool has_pex_clkreq_en;
+ bool has_pex_bias_ctrl;
+ bool has_cml_clk;
+ bool has_gen2;
+};
+
+struct tegra_pcie {
+ struct pci_controller hose;
+
+ struct fdt_resource pads;
+ struct fdt_resource afi;
+ struct fdt_resource cs;
+
+ struct fdt_resource prefetch;
+ struct fdt_resource mem;
+ struct fdt_resource io;
+
+ struct list_head ports;
+ unsigned long xbar;
+
+ const struct tegra_pcie_soc *soc;
+ struct tegra_xusb_phy *phy;
+};
+
+static inline struct tegra_pcie *to_tegra_pcie(struct pci_controller *hose)
+{
+ return container_of(hose, struct tegra_pcie, hose);
+}
+
+static void afi_writel(struct tegra_pcie *pcie, unsigned long value,
+ unsigned long offset)
+{
+ writel(value, pcie->afi.start + offset);
+}
+
+static unsigned long afi_readl(struct tegra_pcie *pcie, unsigned long offset)
+{
+ return readl(pcie->afi.start + offset);
+}
+
+static void pads_writel(struct tegra_pcie *pcie, unsigned long value,
+ unsigned long offset)
+{
+ writel(value, pcie->pads.start + offset);
+}
+
+static unsigned long pads_readl(struct tegra_pcie *pcie, unsigned long offset)
+{
+ return readl(pcie->pads.start + offset);
+}
+
+static unsigned long rp_readl(struct tegra_pcie_port *port,
+ unsigned long offset)
+{
+ return readl(port->regs.start + offset);
+}
+
+static void rp_writel(struct tegra_pcie_port *port, unsigned long value,
+ unsigned long offset)
+{
+ writel(value, port->regs.start + offset);
+}
+
+static unsigned long tegra_pcie_conf_offset(pci_dev_t bdf, int where)
+{
+ return ((where & 0xf00) << 16) | (PCI_BUS(bdf) << 16) |
+ (PCI_DEV(bdf) << 11) | (PCI_FUNC(bdf) << 8) |
+ (where & 0xfc);
+}
+
+static int tegra_pcie_conf_address(struct tegra_pcie *pcie, pci_dev_t bdf,
+ int where, unsigned long *address)
+{
+ unsigned int bus = PCI_BUS(bdf);
+
+ if (bus == 0) {
+ unsigned int dev = PCI_DEV(bdf);
+ struct tegra_pcie_port *port;
+
+ list_for_each_entry(port, &pcie->ports, list) {
+ if (port->index + 1 == dev) {
+ *address = port->regs.start + (where & ~3);
+ return 0;
+ }
+ }
+ } else {
+ *address = pcie->cs.start + tegra_pcie_conf_offset(bdf, where);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int tegra_pcie_read_conf(struct pci_controller *hose, pci_dev_t bdf,
+ int where, u32 *value)
+{
+ struct tegra_pcie *pcie = to_tegra_pcie(hose);
+ unsigned long address;
+ int err;
+
+ err = tegra_pcie_conf_address(pcie, bdf, where, &address);
+ if (err < 0) {
+ *value = 0xffffffff;
+ return 1;
+ }
+
+ *value = readl(address);
+
+ /* fixup root port class */
+ if (PCI_BUS(bdf) == 0) {
+ if (where == PCI_CLASS_REVISION) {
+ *value &= ~0x00ff0000;
+ *value |= PCI_CLASS_BRIDGE_PCI << 16;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra_pcie_write_conf(struct pci_controller *hose, pci_dev_t bdf,
+ int where, u32 value)
+{
+ struct tegra_pcie *pcie = to_tegra_pcie(hose);
+ unsigned long address;
+ int err;
+
+ err = tegra_pcie_conf_address(pcie, bdf, where, &address);
+ if (err < 0)
+ return 1;
+
+ writel(value, address);
+
+ return 0;
+}
+
+static int tegra_pcie_port_parse_dt(const void *fdt, int node,
+ struct tegra_pcie_port *port)
+{
+ const u32 *addr;
+ int len;
+
+ addr = fdt_getprop(fdt, node, "assigned-addresses", &len);
+ if (!addr) {
+ error("property \"assigned-addresses\" not found");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ port->regs.start = fdt32_to_cpu(addr[2]);
+ port->regs.end = port->regs.start + fdt32_to_cpu(addr[4]);
+
+ return 0;
+}
+
+static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
+ unsigned long *xbar)
+{
+ enum fdt_compat_id id = fdtdec_lookup(fdt, node);
+
+ switch (id) {
+ case COMPAT_NVIDIA_TEGRA20_PCIE:
+ switch (lanes) {
+ case 0x00000004:
+ debug("single-mode configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE;
+ return 0;
+
+ case 0x00000202:
+ debug("dual-mode configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
+ return 0;
+ }
+ break;
+
+ case COMPAT_NVIDIA_TEGRA30_PCIE:
+ switch (lanes) {
+ case 0x00000204:
+ debug("4x1, 2x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420;
+ return 0;
+
+ case 0x00020202:
+ debug("2x3 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222;
+ return 0;
+
+ case 0x00010104:
+ debug("4x1, 1x2 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411;
+ return 0;
+ }
+ break;
+
+ case COMPAT_NVIDIA_TEGRA124_PCIE:
+ switch (lanes) {
+ case 0x0000104:
+ debug("4x1, 1x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
+ return 0;
+
+ case 0x0000102:
+ debug("2x1, 1x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+static int tegra_pcie_parse_dt_ranges(const void *fdt, int node,
+ struct tegra_pcie *pcie)
+{
+ const u32 *ptr, *end;
+ int len;
+
+ ptr = fdt_getprop(fdt, node, "ranges", &len);
+ if (!ptr) {
+ error("missing \"ranges\" property");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ end = ptr + len / 4;
+
+ while (ptr < end) {
+ struct fdt_resource *res = NULL;
+ u32 space = fdt32_to_cpu(*ptr);
+
+ switch ((space >> 24) & 0x3) {
+ case 0x01:
+ res = &pcie->io;
+ break;
+
+ case 0x02: /* 32 bit */
+ case 0x03: /* 64 bit */
+ if (space & (1 << 30))
+ res = &pcie->prefetch;
+ else
+ res = &pcie->mem;
+
+ break;
+ }
+
+ if (res) {
+ res->start = fdt32_to_cpu(ptr[3]);
+ res->end = res->start + fdt32_to_cpu(ptr[5]);
+ }
+
+ ptr += 3 + 1 + 2;
+ }
+
+ debug("PCI regions:\n");
+ debug(" I/O: %#x-%#x\n", pcie->io.start, pcie->io.end);
+ debug(" non-prefetchable memory: %#x-%#x\n", pcie->mem.start,
+ pcie->mem.end);
+ debug(" prefetchable memory: %#x-%#x\n", pcie->prefetch.start,
+ pcie->prefetch.end);
+
+ return 0;
+}
+
+static int tegra_pcie_parse_port_info(const void *fdt, int node,
+ unsigned int *index,
+ unsigned int *lanes)
+{
+ struct fdt_pci_addr addr;
+ pci_dev_t bdf;
+ int err;
+
+ err = fdtdec_get_int(fdt, node, "nvidia,num-lanes", 0);
+ if (err < 0) {
+ error("failed to parse \"nvidia,num-lanes\" property");
+ return err;
+ }
+
+ *lanes = err;
+
+ err = fdtdec_get_pci_bdf(fdt, node, &addr, &bdf);
+ if (err < 0) {
+ error("failed to parse \"reg\" property");
+ return err;
+ }
+
+ *index = PCI_DEV(bdf) - 1;
+
+ return 0;
+}
+
+static int tegra_pcie_parse_dt(const void *fdt, int node,
+ struct tegra_pcie *pcie)
+{
+ int err, subnode;
+ u32 lanes = 0;
+
+ err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "pads",
+ &pcie->pads);
+ if (err < 0) {
+ error("resource \"pads\" not found");
+ return err;
+ }
+
+ err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "afi",
+ &pcie->afi);
+ if (err < 0) {
+ error("resource \"afi\" not found");
+ return err;
+ }
+
+ err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "cs",
+ &pcie->cs);
+ if (err < 0) {
+ error("resource \"cs\" not found");
+ return err;
+ }
+
+ pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
+ if (pcie->phy) {
+ err = tegra_xusb_phy_prepare(pcie->phy);
+ if (err < 0) {
+ error("failed to prepare PHY: %d", err);
+ return err;
+ }
+ }
+
+ err = tegra_pcie_parse_dt_ranges(fdt, node, pcie);
+ if (err < 0) {
+ error("failed to parse \"ranges\" property");
+ return err;
+ }
+
+ fdt_for_each_subnode(fdt, subnode, node) {
+ unsigned int index = 0, num_lanes = 0;
+ struct tegra_pcie_port *port;
+
+ err = tegra_pcie_parse_port_info(fdt, subnode, &index,
+ &num_lanes);
+ if (err < 0) {
+ error("failed to obtain root port info");
+ continue;
+ }
+
+ lanes |= num_lanes << (index << 3);
+
+ if (!fdtdec_get_is_enabled(fdt, subnode))
+ continue;
+
+ port = malloc(sizeof(*port));
+ if (!port)
+ continue;
+
+ memset(port, 0, sizeof(*port));
+ port->num_lanes = num_lanes;
+ port->index = index;
+
+ err = tegra_pcie_port_parse_dt(fdt, subnode, port);
+ if (err < 0) {
+ free(port);
+ continue;
+ }
+
+ list_add_tail(&port->list, &pcie->ports);
+ port->pcie = pcie;
+ }
+
+ err = tegra_pcie_get_xbar_config(fdt, node, lanes, &pcie->xbar);
+ if (err < 0) {
+ error("invalid lane configuration");
+ return err;
+ }
+
+ return 0;
+}
+
+int __weak tegra_pcie_board_init(void)
+{
+ return 0;
+}
+
+static int tegra_pcie_power_on(struct tegra_pcie *pcie)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ unsigned long value;
+ int err;
+
+ /* reset PCIEXCLK logic, AFI controller and PCIe controller */
+ reset_set_enable(PERIPH_ID_PCIEXCLK, 1);
+ reset_set_enable(PERIPH_ID_AFI, 1);
+ reset_set_enable(PERIPH_ID_PCIE, 1);
+
+ err = tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+ if (err < 0) {
+ error("failed to power off PCIe partition: %d", err);
+ return err;
+ }
+
+ tegra_pcie_board_init();
+
+ err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
+ PERIPH_ID_PCIE);
+ if (err < 0) {
+ error("failed to power up PCIe partition: %d", err);
+ return err;
+ }
+
+ /* take AFI controller out of reset */
+ reset_set_enable(PERIPH_ID_AFI, 0);
+
+ /* enable AFI clock */
+ clock_enable(PERIPH_ID_AFI);
+
+ if (soc->has_cml_clk) {
+ /* enable CML clock */
+ value = readl(NV_PA_CLK_RST_BASE + 0x48c);
+ value |= (1 << 0);
+ value &= ~(1 << 1);
+ writel(value, NV_PA_CLK_RST_BASE + 0x48c);
+ }
+
+ err = tegra_plle_enable();
+ if (err < 0) {
+ error("failed to enable PLLE: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ unsigned long start = get_timer(0);
+ u32 value;
+
+ while (get_timer(start) < timeout) {
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ if (value & PADS_PLL_CTL_LOCKDET)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ u32 value;
+ int err;
+
+ /* initialize internal PHY, enable up to 16 PCIe lanes */
+ pads_writel(pcie, 0, PADS_CTL_SEL);
+
+ /* override IDDQ to 1 on all 4 lanes */
+ value = pads_readl(pcie, PADS_CTL);
+ value |= PADS_CTL_IDDQ_1L;
+ pads_writel(pcie, value, PADS_CTL);
+
+ /*
+ * Set up PHY PLL inputs select PLLE output as refclock, set TX
+ * ref sel to div10 (not div5).
+ */
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
+ value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
+ pads_writel(pcie, value, soc->pads_pll_ctl);
+
+ /* reset PLL */
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ value &= ~PADS_PLL_CTL_RST_B4SM;
+ pads_writel(pcie, value, soc->pads_pll_ctl);
+
+ udelay(20);
+
+ /* take PLL out of reset */
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ value |= PADS_PLL_CTL_RST_B4SM;
+ pads_writel(pcie, value, soc->pads_pll_ctl);
+
+ /* configure the reference clock driver */
+ value = PADS_REFCLK_CFG_VALUE | (PADS_REFCLK_CFG_VALUE << 16);
+ pads_writel(pcie, value, PADS_REFCLK_CFG0);
+
+ if (soc->num_ports > 2)
+ pads_writel(pcie, PADS_REFCLK_CFG_VALUE, PADS_REFCLK_CFG1);
+
+ /* wait for the PLL to lock */
+ err = tegra_pcie_pll_wait(pcie, 500);
+ if (err < 0) {
+ error("PLL failed to lock: %d", err);
+ return err;
+ }
+
+ /* turn off IDDQ override */
+ value = pads_readl(pcie, PADS_CTL);
+ value &= ~PADS_CTL_IDDQ_1L;
+ pads_writel(pcie, value, PADS_CTL);
+
+ /* enable TX/RX data */
+ value = pads_readl(pcie, PADS_CTL);
+ value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
+ pads_writel(pcie, value, PADS_CTL);
+
+ return 0;
+}
+
+static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ struct tegra_pcie_port *port;
+ u32 value;
+ int err;
+
+ if (pcie->phy) {
+ value = afi_readl(pcie, AFI_PLLE_CONTROL);
+ value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
+ value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
+ afi_writel(pcie, value, AFI_PLLE_CONTROL);
+ }
+
+ if (soc->has_pex_bias_ctrl)
+ afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
+
+ value = afi_readl(pcie, AFI_PCIE_CONFIG);
+ value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
+ value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar;
+
+ list_for_each_entry(port, &pcie->ports, list)
+ value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
+
+ afi_writel(pcie, value, AFI_PCIE_CONFIG);
+
+ value = afi_readl(pcie, AFI_FUSE);
+
+ if (soc->has_gen2)
+ value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+ else
+ value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
+
+ afi_writel(pcie, value, AFI_FUSE);
+
+ if (pcie->phy)
+ err = tegra_xusb_phy_enable(pcie->phy);
+ else
+ err = tegra_pcie_phy_enable(pcie);
+
+ if (err < 0) {
+ error("failed to power on PHY: %d\n", err);
+ return err;
+ }
+
+ /* take the PCIEXCLK logic out of reset */
+ reset_set_enable(PERIPH_ID_PCIEXCLK, 0);
+
+ /* finally enable PCIe */
+ value = afi_readl(pcie, AFI_CONFIGURATION);
+ value |= AFI_CONFIGURATION_EN_FPCI;
+ afi_writel(pcie, value, AFI_CONFIGURATION);
+
+ /* disable all interrupts */
+ afi_writel(pcie, 0, AFI_AFI_INTR_ENABLE);
+ afi_writel(pcie, 0, AFI_SM_INTR_ENABLE);
+ afi_writel(pcie, 0, AFI_INTR_MASK);
+ afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
+
+ return 0;
+}
+
+static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
+{
+ unsigned long fpci, axi, size;
+
+ /* BAR 0: type 1 extended configuration space */
+ fpci = 0xfe100000;
+ size = fdt_resource_size(&pcie->cs);
+ axi = pcie->cs.start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR0_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR0);
+
+ /* BAR 1: downstream I/O */
+ fpci = 0xfdfc0000;
+ size = fdt_resource_size(&pcie->io);
+ axi = pcie->io.start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR1_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR1);
+
+ /* BAR 2: prefetchable memory */
+ fpci = (((pcie->prefetch.start >> 12) & 0x0fffffff) << 4) | 0x1;
+ size = fdt_resource_size(&pcie->prefetch);
+ axi = pcie->prefetch.start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR2_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR2);
+
+ /* BAR 3: non-prefetchable memory */
+ fpci = (((pcie->mem.start >> 12) & 0x0fffffff) << 4) | 0x1;
+ size = fdt_resource_size(&pcie->mem);
+ axi = pcie->mem.start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR3_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR3);
+
+ /* NULL out the remaining BARs as they are not used */
+ afi_writel(pcie, 0, AFI_AXI_BAR4_START);
+ afi_writel(pcie, 0, AFI_AXI_BAR4_SZ);
+ afi_writel(pcie, 0, AFI_FPCI_BAR4);
+
+ afi_writel(pcie, 0, AFI_AXI_BAR5_START);
+ afi_writel(pcie, 0, AFI_AXI_BAR5_SZ);
+ afi_writel(pcie, 0, AFI_FPCI_BAR5);
+
+ /* map all upstream transactions as uncached */
+ afi_writel(pcie, NV_PA_SDRAM_BASE, AFI_CACHE_BAR0_ST);
+ afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
+ afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
+ afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
+
+ /* MSI translations are setup only when needed */
+ afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST);
+ afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
+ afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST);
+ afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
+}
+
+static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
+{
+ unsigned long ret = 0;
+
+ switch (port->index) {
+ case 0:
+ ret = AFI_PEX0_CTRL;
+ break;
+
+ case 1:
+ ret = AFI_PEX1_CTRL;
+ break;
+
+ case 2:
+ ret = AFI_PEX2_CTRL;
+ break;
+ }
+
+ return ret;
+}
+
+static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
+{
+ unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ unsigned long value;
+
+ /* pulse reset signel */
+ value = afi_readl(port->pcie, ctrl);
+ value &= ~AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+
+ udelay(2000);
+
+ value = afi_readl(port->pcie, ctrl);
+ value |= AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+}
+
+static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
+{
+ unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ unsigned long value;
+
+ /* enable reference clock */
+ value = afi_readl(port->pcie, ctrl);
+ value |= AFI_PEX_CTRL_REFCLK_EN;
+
+ if (port->pcie->soc->has_pex_clkreq_en)
+ value |= AFI_PEX_CTRL_CLKREQ_EN;
+
+ value |= AFI_PEX_CTRL_OVERRIDE_EN;
+
+ afi_writel(port->pcie, value, ctrl);
+
+ tegra_pcie_port_reset(port);
+}
+
+static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
+{
+ unsigned int retries = 3;
+ unsigned long value;
+
+ value = rp_readl(port, RP_PRIV_MISC);
+ value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
+ value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
+ rp_writel(port, value, RP_PRIV_MISC);
+
+ do {
+ unsigned int timeout = 200;
+
+ do {
+ value = rp_readl(port, RP_VEND_XP);
+ if (value & RP_VEND_XP_DL_UP)
+ break;
+
+ udelay(2000);
+ } while (--timeout);
+
+ if (!timeout) {
+ debug("link %u down, retrying\n", port->index);
+ goto retry;
+ }
+
+ timeout = 200;
+
+ do {
+ value = rp_readl(port, RP_LINK_CONTROL_STATUS);
+ if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
+ return true;
+
+ udelay(2000);
+ } while (--timeout);
+
+retry:
+ tegra_pcie_port_reset(port);
+ } while (--retries);
+
+ return false;
+}
+
+static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
+{
+ unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ unsigned long value;
+
+ /* assert port reset */
+ value = afi_readl(port->pcie, ctrl);
+ value &= ~AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+
+ /* disable reference clock */
+ value = afi_readl(port->pcie, ctrl);
+ value &= ~AFI_PEX_CTRL_REFCLK_EN;
+ afi_writel(port->pcie, value, ctrl);
+}
+
+static void tegra_pcie_port_free(struct tegra_pcie_port *port)
+{
+ list_del(&port->list);
+ free(port);
+}
+
+static int tegra_pcie_enable(struct tegra_pcie *pcie)
+{
+ struct tegra_pcie_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ debug("probing port %u, using %u lanes\n", port->index,
+ port->num_lanes);
+
+ tegra_pcie_port_enable(port);
+
+ if (tegra_pcie_port_check_link(port))
+ continue;
+
+ debug("link %u down, ignoring\n", port->index);
+
+ tegra_pcie_port_disable(port);
+ tegra_pcie_port_free(port);
+ }
+
+ return 0;
+}
+
+static const struct tegra_pcie_soc tegra20_pcie_soc = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
+ .has_pex_clkreq_en = false,
+ .has_pex_bias_ctrl = false,
+ .has_cml_clk = false,
+ .has_gen2 = false,
+};
+
+static const struct tegra_pcie_soc tegra30_pcie_soc = {
+ .num_ports = 3,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = false,
+};
+
+static const struct tegra_pcie_soc tegra124_pcie_soc = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = true,
+};
+
+static int process_nodes(const void *fdt, int nodes[], unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ const struct tegra_pcie_soc *soc;
+ struct tegra_pcie *pcie;
+ enum fdt_compat_id id;
+ int err;
+
+ if (!fdtdec_get_is_enabled(fdt, nodes[i]))
+ continue;
+
+ id = fdtdec_lookup(fdt, nodes[i]);
+ switch (id) {
+ case COMPAT_NVIDIA_TEGRA20_PCIE:
+ soc = &tegra20_pcie_soc;
+ break;
+
+ case COMPAT_NVIDIA_TEGRA30_PCIE:
+ soc = &tegra30_pcie_soc;
+ break;
+
+ case COMPAT_NVIDIA_TEGRA124_PCIE:
+ soc = &tegra124_pcie_soc;
+ break;
+
+ default:
+ error("unsupported compatible: %s",
+ fdtdec_get_compatible(id));
+ continue;
+ }
+
+ pcie = malloc(sizeof(*pcie));
+ if (!pcie) {
+ error("failed to allocate controller");
+ continue;
+ }
+
+ memset(pcie, 0, sizeof(*pcie));
+ pcie->soc = soc;
+
+ INIT_LIST_HEAD(&pcie->ports);
+
+ err = tegra_pcie_parse_dt(fdt, nodes[i], pcie);
+ if (err < 0) {
+ free(pcie);
+ continue;
+ }
+
+ err = tegra_pcie_power_on(pcie);
+ if (err < 0) {
+ error("failed to power on");
+ continue;
+ }
+
+ err = tegra_pcie_enable_controller(pcie);
+ if (err < 0) {
+ error("failed to enable controller");
+ continue;
+ }
+
+ tegra_pcie_setup_translations(pcie);
+
+ err = tegra_pcie_enable(pcie);
+ if (err < 0) {
+ error("failed to enable PCIe");
+ continue;
+ }
+
+ pcie->hose.first_busno = 0;
+ pcie->hose.current_busno = 0;
+ pcie->hose.last_busno = 0;
+
+ pci_set_region(&pcie->hose.regions[0], NV_PA_SDRAM_BASE,
+ NV_PA_SDRAM_BASE, gd->ram_size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ pci_set_region(&pcie->hose.regions[1], pcie->io.start,
+ pcie->io.start, fdt_resource_size(&pcie->io),
+ PCI_REGION_IO);
+
+ pci_set_region(&pcie->hose.regions[2], pcie->mem.start,
+ pcie->mem.start, fdt_resource_size(&pcie->mem),
+ PCI_REGION_MEM);
+
+ pci_set_region(&pcie->hose.regions[3], pcie->prefetch.start,
+ pcie->prefetch.start,
+ fdt_resource_size(&pcie->prefetch),
+ PCI_REGION_MEM | PCI_REGION_PREFETCH);
+
+ pcie->hose.region_count = 4;
+
+ pci_set_ops(&pcie->hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ tegra_pcie_read_conf,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ tegra_pcie_write_conf);
+
+ pci_register_hose(&pcie->hose);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Enumerating devices...\n");
+ printf("---------------------------------------\n");
+ printf(" Device ID Description\n");
+ printf(" ------ -- -----------\n");
+#endif
+
+ pcie->hose.last_busno = pci_hose_scan(&pcie->hose);
+ }
+
+ return 0;
+}
+
+void pci_init_board(void)
+{
+ const void *fdt = gd->fdt_blob;
+ int count, nodes[1];
+
+ count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
+ COMPAT_NVIDIA_TEGRA124_PCIE,
+ nodes, ARRAY_SIZE(nodes));
+ if (process_nodes(fdt, nodes, count))
+ return;
+
+ count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
+ COMPAT_NVIDIA_TEGRA30_PCIE,
+ nodes, ARRAY_SIZE(nodes));
+ if (process_nodes(fdt, nodes, count))
+ return;
+
+ count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
+ COMPAT_NVIDIA_TEGRA20_PCIE,
+ nodes, ARRAY_SIZE(nodes));
+ if (process_nodes(fdt, nodes, count))
+ return;
+}
+
+int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ if (PCI_BUS(dev) != 0 && PCI_DEV(dev) > 0)
+ return 1;
+
+ return 0;
+}
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c
new file mode 100644
index 0000000000..291c249c86
--- /dev/null
+++ b/drivers/pci/pcie_layerscape.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ * Layerscape PCIe driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/fsl_serdes.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/pcie_layerscape.h>
+
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <libfdt.h>
+#include <fdt_support.h>
+
+static void ft_pcie_ls_setup(void *blob, const char *pci_compat,
+ unsigned long ctrl_addr, enum srds_prtcl dev)
+{
+ int off;
+
+ off = fdt_node_offset_by_compat_reg(blob, pci_compat,
+ (phys_addr_t)ctrl_addr);
+ if (off < 0)
+ return;
+
+ if (!is_serdes_configured(dev))
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+void ft_pcie_setup(void *blob, bd_t *bd)
+{
+ #ifdef CONFIG_PCIE1
+ ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE1_ADDR, PCIE1);
+ #endif
+
+ #ifdef CONFIG_PCIE2
+ ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE2_ADDR, PCIE2);
+ #endif
+}
+
+#else
+void ft_pcie_setup(void *blob, bd_t *bd)
+{
+}
+#endif
+
+void pci_init_board(void)
+{
+}
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 91821f4c77..c506f796fa 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -5,7 +5,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-$(CONFIG_I82365) += i82365.o
obj-$(CONFIG_8xx) += mpc8xx_pcmcia.o
obj-$(CONFIG_IDE_TI_CARDBUS) += ti_pci1410a.o
obj-y += tqm8xx_pcmcia.o
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
deleted file mode 100644
index 84a3d2ecb3..0000000000
--- a/drivers/pcmcia/i82365.c
+++ /dev/null
@@ -1,989 +0,0 @@
-/*
- * (C) Copyright 2003-2005
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * SPDX-License-Identifier: GPL-2.0+
- ********************************************************************
- *
- * Lots of code copied from:
- *
- * i82365.c 1.352 - Linux driver for Intel 82365 and compatible
- * PC Card controllers, and Yenta-compatible PCI-to-CardBus controllers.
- * (C) 1999 David A. Hinds <dahinds@users.sourceforge.net>
- */
-
-#include <common.h>
-
-#include <command.h>
-#include <pci.h>
-#include <pcmcia.h>
-#include <asm/io.h>
-
-#include <pcmcia/ss.h>
-#include <pcmcia/i82365.h>
-#include <pcmcia/yenta.h>
-#ifdef CONFIG_CPC45
-#include <pcmcia/cirrus.h>
-#else
-#include <pcmcia/ti113x.h>
-#endif
-
-static struct pci_device_id supported[] = {
-#ifdef CONFIG_CPC45
- {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729},
-#else
- {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510},
-#endif
- {0, 0}
-};
-
-#define CYCLE_TIME 120
-
-#ifdef CONFIG_CPC45
-extern int SPD67290Init (void);
-#endif
-
-#ifdef DEBUG
-static void i82365_dump_regions (pci_dev_t dev);
-#endif
-
-typedef struct socket_info_t {
- pci_dev_t dev;
- u_short bcr;
- u_char pci_lat, cb_lat, sub_bus, cache;
- u_int cb_phys;
-
- socket_cap_t cap;
- u_short type;
- u_int flags;
-#ifdef CONFIG_CPC45
- cirrus_state_t c_state;
-#else
- ti113x_state_t state;
-#endif
-} socket_info_t;
-
-#ifdef CONFIG_CPC45
-/* These definitions must match the pcic table! */
-typedef enum pcic_id {
- IS_PD6710, IS_PD672X, IS_VT83C469
-} pcic_id;
-
-typedef struct pcic_t {
- char *name;
-} pcic_t;
-
-static pcic_t pcic[] = {
- {" Cirrus PD6710: "},
- {" Cirrus PD672x: "},
- {" VIA VT83C469: "},
-};
-#endif
-
-static socket_info_t socket;
-static socket_state_t state;
-static struct pccard_mem_map mem;
-static struct pccard_io_map io;
-
-/*====================================================================*/
-
-/* Some PCI shortcuts */
-
-static int pci_readb (socket_info_t * s, int r, u_char * v)
-{
- return pci_read_config_byte (s->dev, r, v);
-}
-static int pci_writeb (socket_info_t * s, int r, u_char v)
-{
- return pci_write_config_byte (s->dev, r, v);
-}
-static int pci_readw (socket_info_t * s, int r, u_short * v)
-{
- return pci_read_config_word (s->dev, r, v);
-}
-static int pci_writew (socket_info_t * s, int r, u_short v)
-{
- return pci_write_config_word (s->dev, r, v);
-}
-#ifndef CONFIG_CPC45
-static int pci_readl (socket_info_t * s, int r, u_int * v)
-{
- return pci_read_config_dword (s->dev, r, v);
-}
-static int pci_writel (socket_info_t * s, int r, u_int v)
-{
- return pci_write_config_dword (s->dev, r, v);
-}
-#endif /* !CONFIG_CPC45 */
-
-/*====================================================================*/
-
-#ifdef CONFIG_CPC45
-
-#define cb_readb(s) readb((s)->cb_phys + 1)
-#define cb_writeb(s, v) writeb(v, (s)->cb_phys)
-#define cb_writeb2(s, v) writeb(v, (s)->cb_phys + 1)
-#define cb_readl(s, r) readl((s)->cb_phys + (r))
-#define cb_writel(s, r, v) writel(v, (s)->cb_phys + (r))
-
-
-static u_char i365_get (socket_info_t * s, u_short reg)
-{
- u_char val;
-#ifdef CONFIG_PCMCIA_SLOT_A
- int slot = 0;
-#else
- int slot = 1;
-#endif
-
- val = I365_REG (slot, reg);
-
- cb_writeb (s, val);
- val = cb_readb (s);
-
- debug ("i365_get slot:%x reg: %x val: %x\n", slot, reg, val);
- return val;
-}
-
-static void i365_set (socket_info_t * s, u_short reg, u_char data)
-{
-#ifdef CONFIG_PCMCIA_SLOT_A
- int slot = 0;
-#else
- int slot = 1;
-#endif
- u_char val;
-
- val = I365_REG (slot, reg);
-
- cb_writeb (s, val);
- cb_writeb2 (s, data);
-
- debug ("i365_set slot:%x reg: %x data:%x\n", slot, reg, data);
-}
-
-#else /* ! CONFIG_CPC45 */
-
-#define cb_readb(s, r) readb((s)->cb_phys + (r))
-#define cb_readl(s, r) readl((s)->cb_phys + (r))
-#define cb_writeb(s, r, v) writeb(v, (s)->cb_phys + (r))
-#define cb_writel(s, r, v) writel(v, (s)->cb_phys + (r))
-
-static u_char i365_get (socket_info_t * s, u_short reg)
-{
- return cb_readb (s, 0x0800 + reg);
-}
-
-static void i365_set (socket_info_t * s, u_short reg, u_char data)
-{
- cb_writeb (s, 0x0800 + reg, data);
-}
-#endif /* CONFIG_CPC45 */
-
-static void i365_bset (socket_info_t * s, u_short reg, u_char mask)
-{
- i365_set (s, reg, i365_get (s, reg) | mask);
-}
-
-static void i365_bclr (socket_info_t * s, u_short reg, u_char mask)
-{
- i365_set (s, reg, i365_get (s, reg) & ~mask);
-}
-
-#if 0 /* not used */
-static void i365_bflip (socket_info_t * s, u_short reg, u_char mask, int b)
-{
- u_char d = i365_get (s, reg);
-
- i365_set (s, reg, (b) ? (d | mask) : (d & ~mask));
-}
-
-static u_short i365_get_pair (socket_info_t * s, u_short reg)
-{
- return (i365_get (s, reg) + (i365_get (s, reg + 1) << 8));
-}
-#endif /* not used */
-
-static void i365_set_pair (socket_info_t * s, u_short reg, u_short data)
-{
- i365_set (s, reg, data & 0xff);
- i365_set (s, reg + 1, data >> 8);
-}
-
-#ifdef CONFIG_CPC45
-/*======================================================================
-
- Code to save and restore global state information for Cirrus
- PD67xx controllers, and to set and report global configuration
- options.
-
-======================================================================*/
-
-#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
-
-static void cirrus_get_state (socket_info_t * s)
-{
- int i;
- cirrus_state_t *p = &s->c_state;
-
- p->misc1 = i365_get (s, PD67_MISC_CTL_1);
- p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
- p->misc2 = i365_get (s, PD67_MISC_CTL_2);
- for (i = 0; i < 6; i++)
- p->timer[i] = i365_get (s, PD67_TIME_SETUP (0) + i);
-
-}
-
-static void cirrus_set_state (socket_info_t * s)
-{
- int i;
- u_char misc;
- cirrus_state_t *p = &s->c_state;
-
- misc = i365_get (s, PD67_MISC_CTL_2);
- i365_set (s, PD67_MISC_CTL_2, p->misc2);
- if (misc & PD67_MC2_SUSPEND)
- udelay (50000);
- misc = i365_get (s, PD67_MISC_CTL_1);
- misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
- i365_set (s, PD67_MISC_CTL_1, misc | p->misc1);
- for (i = 0; i < 6; i++)
- i365_set (s, PD67_TIME_SETUP (0) + i, p->timer[i]);
-}
-
-static u_int cirrus_set_opts (socket_info_t * s)
-{
- cirrus_state_t *p = &s->c_state;
- u_int mask = 0xffff;
- char buf[200] = {0};
-
- if (has_ring == -1)
- has_ring = 1;
- flip (p->misc2, PD67_MC2_IRQ15_RI, has_ring);
- flip (p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
-#if DEBUG
- if (p->misc2 & PD67_MC2_IRQ15_RI)
- strcat (buf, " [ring]");
- if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
- strcat (buf, " [dyn mode]");
- if (p->misc1 & PD67_MC1_INPACK_ENA)
- strcat (buf, " [inpack]");
-#endif
-
- if (p->misc2 & PD67_MC2_IRQ15_RI)
- mask &= ~0x8000;
- if (has_led > 0) {
-#if DEBUG
- strcat (buf, " [led]");
-#endif
- mask &= ~0x1000;
- }
- if (has_dma > 0) {
-#if DEBUG
- strcat (buf, " [dma]");
-#endif
- mask &= ~0x0600;
- flip (p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
-#if DEBUG
- if (p->misc2 & PD67_MC2_FREQ_BYPASS)
- strcat (buf, " [freq bypass]");
-#endif
- }
-
- if (setup_time >= 0)
- p->timer[0] = p->timer[3] = setup_time;
- if (cmd_time > 0) {
- p->timer[1] = cmd_time;
- p->timer[4] = cmd_time * 2 + 4;
- }
- if (p->timer[1] == 0) {
- p->timer[1] = 6;
- p->timer[4] = 16;
- if (p->timer[0] == 0)
- p->timer[0] = p->timer[3] = 1;
- }
- if (recov_time >= 0)
- p->timer[2] = p->timer[5] = recov_time;
-
- debug ("i82365 Opt: %s [%d/%d/%d] [%d/%d/%d]\n",
- buf,
- p->timer[0], p->timer[1], p->timer[2],
- p->timer[3], p->timer[4], p->timer[5]);
-
- return mask;
-}
-
-#else /* !CONFIG_CPC45 */
-
-/*======================================================================
-
- Code to save and restore global state information for TI 1130 and
- TI 1131 controllers, and to set and report global configuration
- options.
-
-======================================================================*/
-
-static void ti113x_get_state (socket_info_t * s)
-{
- ti113x_state_t *p = &s->state;
-
- pci_readl (s, TI113X_SYSTEM_CONTROL, &p->sysctl);
- pci_readb (s, TI113X_CARD_CONTROL, &p->cardctl);
- pci_readb (s, TI113X_DEVICE_CONTROL, &p->devctl);
- pci_readb (s, TI1250_DIAGNOSTIC, &p->diag);
- pci_readl (s, TI12XX_IRQMUX, &p->irqmux);
-}
-
-static void ti113x_set_state (socket_info_t * s)
-{
- ti113x_state_t *p = &s->state;
-
- pci_writel (s, TI113X_SYSTEM_CONTROL, p->sysctl);
- pci_writeb (s, TI113X_CARD_CONTROL, p->cardctl);
- pci_writeb (s, TI113X_DEVICE_CONTROL, p->devctl);
- pci_writeb (s, TI1250_MULTIMEDIA_CTL, 0);
- pci_writeb (s, TI1250_DIAGNOSTIC, p->diag);
- pci_writel (s, TI12XX_IRQMUX, p->irqmux);
- i365_set_pair (s, TI113X_IO_OFFSET (0), 0);
- i365_set_pair (s, TI113X_IO_OFFSET (1), 0);
-}
-
-static u_int ti113x_set_opts (socket_info_t * s)
-{
- ti113x_state_t *p = &s->state;
- u_int mask = 0xffff;
-
- p->cardctl &= ~TI113X_CCR_ZVENABLE;
- p->cardctl |= TI113X_CCR_SPKROUTEN;
-
- return mask;
-}
-#endif /* CONFIG_CPC45 */
-
-/*======================================================================
-
- Routines to handle common CardBus options
-
-======================================================================*/
-
-/* Default settings for PCI command configuration register */
-#define CMD_DFLT (PCI_COMMAND_IO|PCI_COMMAND_MEMORY| \
- PCI_COMMAND_MASTER|PCI_COMMAND_WAIT)
-
-static void cb_get_state (socket_info_t * s)
-{
- pci_readb (s, PCI_CACHE_LINE_SIZE, &s->cache);
- pci_readb (s, PCI_LATENCY_TIMER, &s->pci_lat);
- pci_readb (s, CB_LATENCY_TIMER, &s->cb_lat);
- pci_readb (s, CB_CARDBUS_BUS, &s->cap.cardbus);
- pci_readb (s, CB_SUBORD_BUS, &s->sub_bus);
- pci_readw (s, CB_BRIDGE_CONTROL, &s->bcr);
-}
-
-static void cb_set_state (socket_info_t * s)
-{
-#ifndef CONFIG_CPC45
- pci_writel (s, CB_LEGACY_MODE_BASE, 0);
- pci_writel (s, PCI_BASE_ADDRESS_0, s->cb_phys);
-#endif
- pci_writew (s, PCI_COMMAND, CMD_DFLT);
- pci_writeb (s, PCI_CACHE_LINE_SIZE, s->cache);
- pci_writeb (s, PCI_LATENCY_TIMER, s->pci_lat);
- pci_writeb (s, CB_LATENCY_TIMER, s->cb_lat);
- pci_writeb (s, CB_CARDBUS_BUS, s->cap.cardbus);
- pci_writeb (s, CB_SUBORD_BUS, s->sub_bus);
- pci_writew (s, CB_BRIDGE_CONTROL, s->bcr);
-}
-
-static void cb_set_opts (socket_info_t * s)
-{
-#ifndef CONFIG_CPC45
- if (s->cache == 0)
- s->cache = 8;
- if (s->pci_lat == 0)
- s->pci_lat = 0xa8;
- if (s->cb_lat == 0)
- s->cb_lat = 0xb0;
-#endif
-}
-
-/*======================================================================
-
- Power control for Cardbus controllers: used both for 16-bit and
- Cardbus cards.
-
-======================================================================*/
-
-static int cb_set_power (socket_info_t * s, socket_state_t * state)
-{
- u_int reg = 0;
-
-#ifdef CONFIG_CPC45
-
- reg = I365_PWR_NORESET;
- if (state->flags & SS_PWR_AUTO)
- reg |= I365_PWR_AUTO;
- if (state->flags & SS_OUTPUT_ENA)
- reg |= I365_PWR_OUT;
- if (state->Vpp != 0) {
- if (state->Vpp == 120) {
- reg |= I365_VPP1_12V;
- puts (" 12V card found: ");
- } else if (state->Vpp == state->Vcc) {
- reg |= I365_VPP1_5V;
- } else {
- puts (" power not found: ");
- return -1;
- }
- }
- if (state->Vcc != 0) {
- reg |= I365_VCC_5V;
- if (state->Vcc == 33) {
- puts (" 3.3V card found: ");
- i365_bset (s, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
- } else if (state->Vcc == 50) {
- puts (" 5V card found: ");
- i365_bclr (s, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
- } else {
- puts (" power not found: ");
- return -1;
- }
- }
-
- if (reg != i365_get (s, I365_POWER)) {
- reg = (I365_PWR_OUT | I365_PWR_NORESET | I365_VCC_5V | I365_VPP1_5V);
- i365_set (s, I365_POWER, reg);
- }
-
-#else /* ! CONFIG_CPC45 */
-
- /* restart card voltage detection if it seems appropriate */
- if ((state->Vcc == 0) && (state->Vpp == 0) &&
- !(cb_readl (s, CB_SOCKET_STATE) & CB_SS_VSENSE))
- cb_writel (s, CB_SOCKET_FORCE, CB_SF_CVSTEST);
- switch (state->Vcc) {
- case 0:
- reg = 0;
- break;
- case 33:
- reg = CB_SC_VCC_3V;
- break;
- case 50:
- reg = CB_SC_VCC_5V;
- break;
- default:
- return -1;
- }
- switch (state->Vpp) {
- case 0:
- break;
- case 33:
- reg |= CB_SC_VPP_3V;
- break;
- case 50:
- reg |= CB_SC_VPP_5V;
- break;
- case 120:
- reg |= CB_SC_VPP_12V;
- break;
- default:
- return -1;
- }
- if (reg != cb_readl (s, CB_SOCKET_CONTROL))
- cb_writel (s, CB_SOCKET_CONTROL, reg);
-#endif /* CONFIG_CPC45 */
- return 0;
-}
-
-/*======================================================================
-
- Generic routines to get and set controller options
-
-======================================================================*/
-
-static void get_bridge_state (socket_info_t * s)
-{
-#ifdef CONFIG_CPC45
- cirrus_get_state (s);
-#else
- ti113x_get_state (s);
-#endif
- cb_get_state (s);
-}
-
-static void set_bridge_state (socket_info_t * s)
-{
- cb_set_state (s);
- i365_set (s, I365_GBLCTL, 0x00);
- i365_set (s, I365_GENCTL, 0x00);
-#ifdef CONFIG_CPC45
- cirrus_set_state (s);
-#else
- ti113x_set_state (s);
-#endif
-}
-
-static void set_bridge_opts (socket_info_t * s)
-{
-#ifdef CONFIG_CPC45
- cirrus_set_opts (s);
-#else
- ti113x_set_opts (s);
-#endif
- cb_set_opts (s);
-}
-
-/*====================================================================*/
-#define PD67_EXT_INDEX 0x2e /* Extension index */
-#define PD67_EXT_DATA 0x2f /* Extension data */
-#define PD67_EXD_VS1(s) (0x01 << ((s)<<1))
-
-#define pd67_ext_get(s, r) \
- (i365_set(s, PD67_EXT_INDEX, r), i365_get(s, PD67_EXT_DATA))
-
-static int i365_get_status (socket_info_t * s, u_int * value)
-{
- u_int status;
-#ifdef CONFIG_CPC45
- u_char val;
- u_char power, vcc, vpp;
- u_int powerstate;
-#endif
-
- status = i365_get (s, I365_IDENT);
- status = i365_get (s, I365_STATUS);
- *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0;
- if (i365_get (s, I365_INTCTL) & I365_PC_IOCARD) {
- *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
- } else {
- *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
- *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
- }
- *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
- *value |= (status & I365_CS_READY) ? SS_READY : 0;
- *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
-
-#ifdef CONFIG_CPC45
- /* Check for Cirrus CL-PD67xx chips */
- i365_set (s, PD67_CHIP_INFO, 0);
- val = i365_get (s, PD67_CHIP_INFO);
- s->type = -1;
- if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
- val = i365_get (s, PD67_CHIP_INFO);
- if ((val & PD67_INFO_CHIP_ID) == 0) {
- s->type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
- i365_set (s, PD67_EXT_INDEX, 0xe5);
- if (i365_get (s, PD67_EXT_INDEX) != 0xe5)
- s->type = IS_VT83C469;
- }
- } else {
- printf ("no Cirrus Chip found\n");
- *value = 0;
- return -1;
- }
-
- power = i365_get (s, I365_POWER);
- state.flags |= (power & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
- state.flags |= (power & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
- vcc = power & I365_VCC_MASK;
- vpp = power & I365_VPP1_MASK;
- state.Vcc = state.Vpp = 0;
- if((vcc== 0) || (vpp == 0)) {
- /*
- * On the Cirrus we get the info which card voltage
- * we have in EXTERN DATA and write it to MISC_CTL1
- */
- powerstate = pd67_ext_get(s, PD67_EXTERN_DATA);
- if (powerstate & PD67_EXD_VS1(0)) {
- /* 5V Card */
- i365_bclr (s, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
- } else {
- /* 3.3V Card */
- i365_bset (s, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
- }
- i365_set (s, I365_POWER, (I365_PWR_OUT | I365_PWR_NORESET | I365_VCC_5V | I365_VPP1_5V));
- power = i365_get (s, I365_POWER);
- }
- if (power & I365_VCC_5V) {
- state.Vcc = (i365_get(s, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) ? 33 : 50;
- }
-
- if (power == I365_VPP1_12V)
- state.Vpp = 120;
-
- /* IO card, RESET flags, IO interrupt */
- power = i365_get (s, I365_INTCTL);
- state.flags |= (power & I365_PC_RESET) ? 0 : SS_RESET;
- if (power & I365_PC_IOCARD)
- state.flags |= SS_IOCARD;
- state.io_irq = power & I365_IRQ_MASK;
-
- /* Card status change mask */
- power = i365_get (s, I365_CSCINT);
- state.csc_mask = (power & I365_CSC_DETECT) ? SS_DETECT : 0;
- if (state.flags & SS_IOCARD)
- state.csc_mask |= (power & I365_CSC_STSCHG) ? SS_STSCHG : 0;
- else {
- state.csc_mask |= (power & I365_CSC_BVD1) ? SS_BATDEAD : 0;
- state.csc_mask |= (power & I365_CSC_BVD2) ? SS_BATWARN : 0;
- state.csc_mask |= (power & I365_CSC_READY) ? SS_READY : 0;
- }
- debug ("i82365: GetStatus(0) = flags %#3.3x, Vcc %d, Vpp %d, "
- "io_irq %d, csc_mask %#2.2x\n", state.flags,
- state.Vcc, state.Vpp, state.io_irq, state.csc_mask);
-
-#else /* !CONFIG_CPC45 */
-
- status = cb_readl (s, CB_SOCKET_STATE);
- *value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0;
- *value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0;
- *value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0;
- *value |= (status & CB_SS_VSENSE) ? 0 : SS_PENDING;
- /* For now, ignore cards with unsupported voltage keys */
- if (*value & SS_XVCARD)
- *value &= ~(SS_DETECT | SS_3VCARD | SS_XVCARD);
-#endif /* CONFIG_CPC45 */
- return 0;
-} /* i365_get_status */
-
-static int i365_set_socket (socket_info_t * s, socket_state_t * state)
-{
- u_char reg;
-
- set_bridge_state (s);
-
- /* IO card, RESET flag */
- reg = 0;
- reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
- reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
- i365_set (s, I365_INTCTL, reg);
-
-#ifdef CONFIG_CPC45
- cb_set_power (s, state);
-
-#if 0
- /* Card status change interrupt mask */
- reg = s->cs_irq << 4;
- if (state->csc_mask & SS_DETECT)
- reg |= I365_CSC_DETECT;
- if (state->flags & SS_IOCARD) {
- if (state->csc_mask & SS_STSCHG)
- reg |= I365_CSC_STSCHG;
- } else {
- if (state->csc_mask & SS_BATDEAD)
- reg |= I365_CSC_BVD1;
- if (state->csc_mask & SS_BATWARN)
- reg |= I365_CSC_BVD2;
- if (state->csc_mask & SS_READY)
- reg |= I365_CSC_READY;
- }
- i365_set (s, I365_CSCINT, reg);
- i365_get (s, I365_CSC);
-#endif /* 0 */
-
-#else /* !CONFIG_CPC45 */
-
- reg = I365_PWR_NORESET;
- if (state->flags & SS_PWR_AUTO)
- reg |= I365_PWR_AUTO;
- if (state->flags & SS_OUTPUT_ENA)
- reg |= I365_PWR_OUT;
-
- cb_set_power (s, state);
- reg |= i365_get (s, I365_POWER) & (I365_VCC_MASK | I365_VPP1_MASK);
-
- if (reg != i365_get (s, I365_POWER))
- i365_set (s, I365_POWER, reg);
-#endif /* CONFIG_CPC45 */
-
- return 0;
-} /* i365_set_socket */
-
-/*====================================================================*/
-
-static int i365_set_mem_map (socket_info_t * s, struct pccard_mem_map *mem)
-{
- u_short base, i;
- u_char map;
-
- debug ("i82365: SetMemMap(%d, %#2.2x, %d ns, %#5.5lx-%#5.5lx, %#5.5x)\n",
- mem->map, mem->flags, mem->speed,
- mem->sys_start, mem->sys_stop, mem->card_start);
-
- map = mem->map;
- if ((map > 4) ||
- (mem->card_start > 0x3ffffff) ||
- (mem->sys_start > mem->sys_stop) ||
- (mem->speed > 1000)) {
- return -1;
- }
-
- /* Turn off the window before changing anything */
- if (i365_get (s, I365_ADDRWIN) & I365_ENA_MEM (map))
- i365_bclr (s, I365_ADDRWIN, I365_ENA_MEM (map));
-
- /* Take care of high byte, for PCI controllers */
- i365_set (s, CB_MEM_PAGE (map), mem->sys_start >> 24);
-
- base = I365_MEM (map);
- i = (mem->sys_start >> 12) & 0x0fff;
- if (mem->flags & MAP_16BIT)
- i |= I365_MEM_16BIT;
- if (mem->flags & MAP_0WS)
- i |= I365_MEM_0WS;
- i365_set_pair (s, base + I365_W_START, i);
-
- i = (mem->sys_stop >> 12) & 0x0fff;
- switch (mem->speed / CYCLE_TIME) {
- case 0:
- break;
- case 1:
- i |= I365_MEM_WS0;
- break;
- case 2:
- i |= I365_MEM_WS1;
- break;
- default:
- i |= I365_MEM_WS1 | I365_MEM_WS0;
- break;
- }
- i365_set_pair (s, base + I365_W_STOP, i);
-
-#ifdef CONFIG_CPC45
- i = 0;
-#else
- i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
-#endif
- if (mem->flags & MAP_WRPROT)
- i |= I365_MEM_WRPROT;
- if (mem->flags & MAP_ATTRIB)
- i |= I365_MEM_REG;
- i365_set_pair (s, base + I365_W_OFF, i);
-
-#ifdef CONFIG_CPC45
- /* set System Memory map Upper Adress */
- i365_set(s, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
- i365_set(s, PD67_EXT_DATA, ((mem->sys_start >> 24) & 0xff));
-#endif
-
- /* Turn on the window if necessary */
- if (mem->flags & MAP_ACTIVE)
- i365_bset (s, I365_ADDRWIN, I365_ENA_MEM (map));
- return 0;
-} /* i365_set_mem_map */
-
-static int i365_set_io_map (socket_info_t * s, struct pccard_io_map *io)
-{
- u_char map, ioctl;
-
- map = io->map;
- /* comment out: comparison is always false due to limited range of data type */
- if ((map > 1) || /* (io->start > 0xffff) || (io->stop > 0xffff) || */
- (io->stop < io->start))
- return -1;
- /* Turn off the window before changing anything */
- if (i365_get (s, I365_ADDRWIN) & I365_ENA_IO (map))
- i365_bclr (s, I365_ADDRWIN, I365_ENA_IO (map));
- i365_set_pair (s, I365_IO (map) + I365_W_START, io->start);
- i365_set_pair (s, I365_IO (map) + I365_W_STOP, io->stop);
- ioctl = i365_get (s, I365_IOCTL) & ~I365_IOCTL_MASK (map);
- if (io->speed)
- ioctl |= I365_IOCTL_WAIT (map);
- if (io->flags & MAP_0WS)
- ioctl |= I365_IOCTL_0WS (map);
- if (io->flags & MAP_16BIT)
- ioctl |= I365_IOCTL_16BIT (map);
- if (io->flags & MAP_AUTOSZ)
- ioctl |= I365_IOCTL_IOCS16 (map);
- i365_set (s, I365_IOCTL, ioctl);
- /* Turn on the window if necessary */
- if (io->flags & MAP_ACTIVE)
- i365_bset (s, I365_ADDRWIN, I365_ENA_IO (map));
- return 0;
-} /* i365_set_io_map */
-
-/*====================================================================*/
-
-int i82365_init (void)
-{
- u_int val;
- int i;
-
-#ifdef CONFIG_CPC45
- if (SPD67290Init () != 0)
- return 1;
-#endif
- if ((socket.dev = pci_find_devices (supported, 0)) < 0) {
- /* Controller not found */
- return 1;
- }
- debug ("i82365 Device Found!\n");
-
- pci_read_config_dword (socket.dev, PCI_BASE_ADDRESS_0, &socket.cb_phys);
- socket.cb_phys &= ~0xf;
-
-#ifdef CONFIG_CPC45
- /* + 0xfe000000 see MPC 8245 Users Manual Adress Map B */
- socket.cb_phys += 0xfe000000;
-#endif
-
- get_bridge_state (&socket);
- set_bridge_opts (&socket);
-
- i = i365_get_status (&socket, &val);
-
-#ifdef CONFIG_CPC45
- if (i > -1) {
- puts (pcic[socket.type].name);
- } else {
- printf ("i82365: Controller not found.\n");
- return 1;
- }
- if((val & SS_DETECT) != SS_DETECT){
- puts ("No card\n");
- return 1;
- }
-#else /* !CONFIG_CPC45 */
- if (val & SS_DETECT) {
- if (val & SS_3VCARD) {
- state.Vcc = state.Vpp = 33;
- puts (" 3.3V card found: ");
- } else if (!(val & SS_XVCARD)) {
- state.Vcc = state.Vpp = 50;
- puts (" 5.0V card found: ");
- } else {
- puts ("i82365: unsupported voltage key\n");
- state.Vcc = state.Vpp = 0;
- }
- } else {
- /* No card inserted */
- puts ("No card\n");
- return 1;
- }
-#endif /* CONFIG_CPC45 */
-
-#ifdef CONFIG_CPC45
- state.flags |= SS_OUTPUT_ENA;
-#else
- state.flags = SS_IOCARD | SS_OUTPUT_ENA;
- state.csc_mask = 0;
- state.io_irq = 0;
-#endif
-
- i365_set_socket (&socket, &state);
-
- for (i = 500; i; i--) {
- if ((i365_get (&socket, I365_STATUS) & I365_CS_READY))
- break;
- udelay (1000);
- }
-
- if (i == 0) {
- /* PC Card not ready for data transfer */
- puts ("i82365 PC Card not ready for data transfer\n");
- return 1;
- }
- debug (" PC Card ready for data transfer: ");
-
- mem.map = 0;
- mem.flags = MAP_ATTRIB | MAP_ACTIVE;
- mem.speed = 300;
- mem.sys_start = CONFIG_SYS_PCMCIA_MEM_ADDR;
- mem.sys_stop = CONFIG_SYS_PCMCIA_MEM_ADDR + CONFIG_SYS_PCMCIA_MEM_SIZE - 1;
- mem.card_start = 0;
- i365_set_mem_map (&socket, &mem);
-
-#ifdef CONFIG_CPC45
- mem.map = 1;
- mem.flags = MAP_ACTIVE;
- mem.speed = 300;
- mem.sys_start = CONFIG_SYS_PCMCIA_MEM_ADDR + CONFIG_SYS_PCMCIA_MEM_SIZE;
- mem.sys_stop = CONFIG_SYS_PCMCIA_MEM_ADDR + (2 * CONFIG_SYS_PCMCIA_MEM_SIZE) - 1;
- mem.card_start = 0;
- i365_set_mem_map (&socket, &mem);
-
-#else /* !CONFIG_CPC45 */
-
- io.map = 0;
- io.flags = MAP_AUTOSZ | MAP_ACTIVE;
- io.speed = 0;
- io.start = 0x0100;
- io.stop = 0x010F;
- i365_set_io_map (&socket, &io);
-
-#endif /* CONFIG_CPC45 */
-
-#ifdef DEBUG
- i82365_dump_regions (socket.dev);
-#endif
-
- return 0;
-}
-
-void i82365_exit (void)
-{
- io.map = 0;
- io.flags = 0;
- io.speed = 0;
- io.start = 0;
- io.stop = 0x1;
-
- i365_set_io_map (&socket, &io);
-
- mem.map = 0;
- mem.flags = 0;
- mem.speed = 0;
- mem.sys_start = 0;
- mem.sys_stop = 0x1000;
- mem.card_start = 0;
-
- i365_set_mem_map (&socket, &mem);
-
-#ifdef CONFIG_CPC45
- mem.map = 1;
- mem.flags = 0;
- mem.speed = 0;
- mem.sys_start = 0;
- mem.sys_stop = 0x1000;
- mem.card_start = 0;
-
- i365_set_mem_map (&socket, &mem);
-#else /* !CONFIG_CPC45 */
- socket.state.sysctl &= 0xFFFF00FF;
-#endif
- state.Vcc = state.Vpp = 0;
-
- i365_set_socket (&socket, &state);
-}
-
-/*======================================================================
-
- Debug stuff
-
-======================================================================*/
-
-#ifdef DEBUG
-static void i82365_dump_regions (pci_dev_t dev)
-{
- u_int tmp[2];
- u_int *mem = (void *) socket.cb_phys;
- u_char *cis = (void *) CONFIG_SYS_PCMCIA_MEM_ADDR;
- u_char *ide = (void *) (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_REG_OFFSET);
-
- pci_read_config_dword (dev, 0x00, tmp + 0);
- pci_read_config_dword (dev, 0x80, tmp + 1);
-
- printf ("PCI CONF: %08X ... %08X\n",
- tmp[0], tmp[1]);
- printf ("PCI MEM: ... %08X ... %08X\n",
- mem[0x8 / 4], mem[0x800 / 4]);
- printf ("CIS: ...%c%c%c%c%c%c%c%c...\n",
- cis[0x38], cis[0x3a], cis[0x3c], cis[0x3e],
- cis[0x40], cis[0x42], cis[0x44], cis[0x48]);
- printf ("CIS CONF: %02X %02X %02X ...\n",
- cis[0x200], cis[0x202], cis[0x204]);
- printf ("IDE: %02X %02X %02X %02X %02X %02X %02X %02X\n",
- ide[0], ide[1], ide[2], ide[3],
- ide[4], ide[5], ide[6], ide[7]);
-}
-#endif /* DEBUG */
diff --git a/drivers/pcmcia/mpc8xx_pcmcia.c b/drivers/pcmcia/mpc8xx_pcmcia.c
index af774260ee..1b41e39158 100644
--- a/drivers/pcmcia/mpc8xx_pcmcia.c
+++ b/drivers/pcmcia/mpc8xx_pcmcia.c
@@ -58,15 +58,9 @@ static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] =
/* -------------------------------------------------------------------- */
-#if defined(CONFIG_LWMON) || defined(CONFIG_NSCU)
-#define CONFIG_SYS_PCMCIA_TIMING ( PCMCIA_SHT(9) \
- | PCMCIA_SST(3) \
- | PCMCIA_SL(12))
-#else
#define CONFIG_SYS_PCMCIA_TIMING ( PCMCIA_SHT(2) \
| PCMCIA_SST(4) \
| PCMCIA_SL(9))
-#endif
/* -------------------------------------------------------------------- */
diff --git a/drivers/pcmcia/tqm8xx_pcmcia.c b/drivers/pcmcia/tqm8xx_pcmcia.c
index 8b7447853b..45dcb54d71 100644
--- a/drivers/pcmcia/tqm8xx_pcmcia.c
+++ b/drivers/pcmcia/tqm8xx_pcmcia.c
@@ -22,51 +22,10 @@
#if defined(CONFIG_PCMCIA) \
&& defined(CONFIG_TQM8xxL)
-#if defined(CONFIG_VIRTLAB2)
-#define PCMCIA_BOARD_MSG "Virtlab2"
-#elif defined(CONFIG_TQM8xxL)
+#if defined(CONFIG_TQM8xxL)
#define PCMCIA_BOARD_MSG "TQM8xxL"
#endif
-#if defined(CONFIG_NSCU)
-
-static inline void power_config(int slot) {}
-static inline void power_off(int slot) {}
-static inline void power_on_5_0(int slot) {}
-static inline void power_on_3_3(int slot) {}
-
-#elif defined(CONFIG_VIRTLAB2)
-
-static inline void power_config(int slot) {}
-
-static inline void power_off(int slot)
-{
- volatile unsigned __iomem *addr;
- addr = (volatile unsigned __iomem *)PCMCIA_CTRL;
-
- out_be32(addr, 0);
-}
-
-static inline void power_on_5_0(int slot)
-{
- volatile unsigned __iomem *addr;
- addr = (volatile unsigned __iomem *)PCMCIA_CTRL;
-
- /* Enable 5V Vccout */
- out_be32(addr, 2);
-}
-
-static inline void power_on_3_3(int slot)
-{
- volatile unsigned __iomem *addr;
- addr = (volatile unsigned __iomem *)PCMCIA_CTRL;
-
- /* Enable 3.3V Vccout */
- out_be32(addr, 1);
-}
-
-#else
-
static inline void power_config(int slot)
{
immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
@@ -98,8 +57,6 @@ static inline void power_on_3_3(int slot)
setbits_be16(&immap->im_ioport.iop_pcdir, 0x0002 | 0x0004);
}
-#endif
-
/*
* Function to retrieve the PIPR register, used for debuging purposes.
*/
@@ -121,11 +78,7 @@ static inline int check_card_is_absent(int slot)
return pipr & (0x18000000 >> (slot << 4));
}
-#ifdef NSCU_OE_INV
-#define NSCU_GCRX_CXOE 0
-#else
#define NSCU_GCRX_CXOE __MY_PCMCIA_GCRX_CXOE
-#endif
int pcmcia_hardware_enable(int slot)
{
@@ -243,7 +196,6 @@ int pcmcia_hardware_disable(int slot)
int pcmcia_voltage_set(int slot, int vcc, int vpp)
{
-#ifndef CONFIG_NSCU
u_long reg;
uint32_t pipr = 0;
@@ -296,7 +248,6 @@ done:
udelay(500);
debug("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n", slot+'A');
-#endif /* CONFIG_NSCU */
return 0;
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index e69de29bb2..e68e16b321 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -0,0 +1,65 @@
+config AXP221_POWER
+ boolean "axp221 / axp223 pmic support"
+ depends on MACH_SUN6I || MACH_SUN8I
+ default y
+ ---help---
+ Say y here to enable support for the axp221 / axp223 pmic found on most
+ sun6i (A31) / sun8i (A23) boards.
+
+config AXP221_DCDC1_VOLT
+ int "axp221 dcdc1 voltage"
+ depends on AXP221_POWER
+ default 3000
+ ---help---
+ Set the voltage (mV) to program the axp221 dcdc1 at, set to 0 to
+ disable dcdc1. This is typically used as generic 3.3V IO voltage for
+ things like GPIO-s, sdcard interfaces, etc. On most boards this is
+ undervolted to 3.0V to safe battery.
+
+config AXP221_DLDO1_VOLT
+ int "axp221 dldo1 voltage"
+ depends on AXP221_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp221 dldo1 at, set to 0 to
+ disable dldo1. On sun6i (A31) boards with ethernet this is often used
+ to power the ethernet phy. On sun8i (A23) boards this is often used to
+ power the wifi.
+
+config AXP221_DLDO4_VOLT
+ int "axp221 dldo4 voltage"
+ depends on AXP221_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp221 dldo4 at, set to 0 to
+ disable dldo4.
+
+config AXP221_ALDO1_VOLT
+ int "axp221 aldo1 voltage"
+ depends on AXP221_POWER
+ default 0
+ ---help---
+ Set the voltage (mV) to program the axp221 aldo1 at, set to 0 to
+ disable aldo1. On sun6i (A31) boards which have a wifi module this is
+ often used to power the wifi module.
+
+config AXP221_ALDO2_VOLT
+ int "axp221 aldo2 voltage"
+ depends on AXP221_POWER
+ default 0 if MACH_SUN6I
+ default 2500 if MACH_SUN8I
+ ---help---
+ Set the voltage (mV) to program the axp221 aldo2 at, set to 0 to
+ disable aldo2. On sun6i (A31) boards this is typically unused and
+ should be disabled, if it is used for LPDDR2 it should be set to 1.8V.
+ On sun8i (A23) this is typically connected to VDD-DLL and must be set
+ to 2.5V.
+
+config AXP221_ALDO3_VOLT
+ int "axp221 aldo3 voltage"
+ depends on AXP221_POWER
+ default 3000
+ ---help---
+ 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.
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index dc64e4d32b..214565241e 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -5,8 +5,10 @@
# SPDX-License-Identifier: GPL-2.0+
#
+obj-$(CONFIG_AS3722_POWER) += as3722.o
obj-$(CONFIG_AXP152_POWER) += axp152.o
obj-$(CONFIG_AXP209_POWER) += axp209.o
+obj-$(CONFIG_AXP221_POWER) += axp221.o
obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
obj-$(CONFIG_FTPMU010_POWER) += ftpmu010.o
obj-$(CONFIG_TPS6586X_POWER) += tps6586x.o
diff --git a/drivers/power/as3722.c b/drivers/power/as3722.c
new file mode 100644
index 0000000000..4c6de79cd6
--- /dev/null
+++ b/drivers/power/as3722.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2014 NVIDIA Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#define pr_fmt(fmt) "as3722: " fmt
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+
+#include <power/as3722.h>
+
+#define AS3722_SD_VOLTAGE(n) (0x00 + (n))
+#define AS3722_GPIO_CONTROL(n) (0x08 + (n))
+#define AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH (1 << 0)
+#define AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDL (7 << 0)
+#define AS3722_GPIO_CONTROL_INVERT (1 << 7)
+#define AS3722_LDO_VOLTAGE(n) (0x10 + (n))
+#define AS3722_GPIO_SIGNAL_OUT 0x20
+#define AS3722_SD_CONTROL 0x4d
+#define AS3722_LDO_CONTROL 0x4e
+#define AS3722_ASIC_ID1 0x90
+#define AS3722_DEVICE_ID 0x0c
+#define AS3722_ASIC_ID2 0x91
+
+static int as3722_read(struct udevice *pmic, u8 reg, u8 *value)
+{
+ int err;
+
+ err = i2c_read(pmic, reg, value, 1);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int as3722_write(struct udevice *pmic, u8 reg, u8 value)
+{
+ int err;
+
+ err = i2c_write(pmic, reg, &value, 1);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int as3722_read_id(struct udevice *pmic, u8 *id, u8 *revision)
+{
+ int err;
+
+ err = as3722_read(pmic, AS3722_ASIC_ID1, id);
+ if (err) {
+ error("failed to read ID1 register: %d", err);
+ return err;
+ }
+
+ err = as3722_read(pmic, AS3722_ASIC_ID2, revision);
+ if (err) {
+ error("failed to read ID2 register: %d", err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_sd_enable(struct udevice *pmic, unsigned int sd)
+{
+ u8 value;
+ int err;
+
+ if (sd > 6)
+ return -EINVAL;
+
+ err = as3722_read(pmic, AS3722_SD_CONTROL, &value);
+ if (err) {
+ error("failed to read SD control register: %d", err);
+ return err;
+ }
+
+ value |= 1 << sd;
+
+ err = as3722_write(pmic, AS3722_SD_CONTROL, value);
+ if (err < 0) {
+ error("failed to write SD control register: %d", err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_sd_set_voltage(struct udevice *pmic, unsigned int sd, u8 value)
+{
+ int err;
+
+ if (sd > 6)
+ return -EINVAL;
+
+ err = as3722_write(pmic, AS3722_SD_VOLTAGE(sd), value);
+ if (err < 0) {
+ error("failed to write SD%u voltage register: %d", sd, err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_ldo_enable(struct udevice *pmic, unsigned int ldo)
+{
+ u8 value;
+ int err;
+
+ if (ldo > 11)
+ return -EINVAL;
+
+ err = as3722_read(pmic, AS3722_LDO_CONTROL, &value);
+ if (err) {
+ error("failed to read LDO control register: %d", err);
+ return err;
+ }
+
+ value |= 1 << ldo;
+
+ err = as3722_write(pmic, AS3722_LDO_CONTROL, value);
+ if (err < 0) {
+ error("failed to write LDO control register: %d", err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_ldo_set_voltage(struct udevice *pmic, unsigned int ldo, u8 value)
+{
+ int err;
+
+ if (ldo > 11)
+ return -EINVAL;
+
+ err = as3722_write(pmic, AS3722_LDO_VOLTAGE(ldo), value);
+ if (err < 0) {
+ error("failed to write LDO%u voltage register: %d", ldo,
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_gpio_configure(struct udevice *pmic, unsigned int gpio,
+ unsigned long flags)
+{
+ u8 value = 0;
+ int err;
+
+ if (flags & AS3722_GPIO_OUTPUT_VDDH)
+ value |= AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH;
+
+ if (flags & AS3722_GPIO_INVERT)
+ value |= AS3722_GPIO_CONTROL_INVERT;
+
+ err = as3722_write(pmic, AS3722_GPIO_CONTROL(gpio), value);
+ if (err) {
+ error("failed to configure GPIO#%u: %d", gpio, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int as3722_gpio_set(struct udevice *pmic, unsigned int gpio,
+ unsigned int level)
+{
+ const char *l;
+ u8 value;
+ int err;
+
+ if (gpio > 7)
+ return -EINVAL;
+
+ err = as3722_read(pmic, AS3722_GPIO_SIGNAL_OUT, &value);
+ if (err < 0) {
+ error("failed to read GPIO signal out register: %d", err);
+ return err;
+ }
+
+ if (level == 0) {
+ value &= ~(1 << gpio);
+ l = "low";
+ } else {
+ value |= 1 << gpio;
+ l = "high";
+ }
+
+ err = as3722_write(pmic, AS3722_GPIO_SIGNAL_OUT, value);
+ if (err) {
+ error("failed to set GPIO#%u %s: %d", gpio, l, err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_gpio_direction_output(struct udevice *pmic, unsigned int gpio,
+ unsigned int level)
+{
+ u8 value;
+ int err;
+
+ if (gpio > 7)
+ return -EINVAL;
+
+ if (level == 0)
+ value = AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDL;
+ else
+ value = AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH;
+
+ err = as3722_write(pmic, AS3722_GPIO_CONTROL(gpio), value);
+ if (err) {
+ error("failed to configure GPIO#%u as output: %d", gpio, err);
+ return err;
+ }
+
+ err = as3722_gpio_set(pmic, gpio, level);
+ if (err < 0) {
+ error("failed to set GPIO#%u high: %d", gpio, err);
+ return err;
+ }
+
+ return 0;
+}
+
+int as3722_init(struct udevice **devp)
+{
+ struct udevice *pmic;
+ u8 id, revision;
+ const unsigned int bus = 0;
+ const unsigned int address = 0x40;
+ int err;
+
+ err = i2c_get_chip_for_busnum(bus, address, &pmic);
+ if (err)
+ return err;
+ err = as3722_read_id(pmic, &id, &revision);
+ if (err < 0) {
+ error("failed to read ID: %d", err);
+ return err;
+ }
+
+ if (id != AS3722_DEVICE_ID) {
+ error("unknown device");
+ return -ENOENT;
+ }
+
+ debug("AS3722 revision %#x found on I2C bus %u, address %#x\n",
+ revision, bus, address);
+ *devp = pmic;
+
+ return 0;
+}
diff --git a/drivers/power/axp209.c b/drivers/power/axp209.c
index 9798e5bf7c..3b1a6a73ae 100644
--- a/drivers/power/axp209.c
+++ b/drivers/power/axp209.c
@@ -18,6 +18,11 @@ enum axp209_reg {
AXP209_LDO3_VOLTAGE = 0x29,
AXP209_IRQ_STATUS5 = 0x4c,
AXP209_SHUTDOWN = 0x32,
+ AXP209_GPIO0_CTRL = 0x90,
+ AXP209_GPIO1_CTRL = 0x92,
+ AXP209_GPIO2_CTRL = 0x93,
+ AXP209_GPIO_STATE = 0x94,
+ AXP209_GPIO3_CTRL = 0x95,
};
#define AXP209_POWER_STATUS_ON_BY_DC (1 << 0)
@@ -27,6 +32,15 @@ enum axp209_reg {
#define AXP209_POWEROFF (1 << 7)
+#define AXP209_GPIO_OUTPUT_LOW 0x00 /* Drive pin low */
+#define AXP209_GPIO_OUTPUT_HIGH 0x01 /* Drive pin high */
+#define AXP209_GPIO_INPUT 0x02 /* Float pin */
+
+/* GPIO3 is different from the others */
+#define AXP209_GPIO3_OUTPUT_LOW 0x00 /* Drive pin low, Output mode */
+#define AXP209_GPIO3_OUTPUT_HIGH 0x02 /* Float pin, Output mode */
+#define AXP209_GPIO3_INPUT 0x06 /* Float pin, Input mode */
+
static int axp209_write(enum axp209_reg reg, u8 val)
{
return i2c_write(0x34, reg, 1, &val, 1);
@@ -165,3 +179,61 @@ int axp209_power_button(void)
return v & AXP209_IRQ5_PEK_DOWN;
}
+
+static u8 axp209_get_gpio_ctrl_reg(unsigned int pin)
+{
+ switch (pin) {
+ case 0: return AXP209_GPIO0_CTRL;
+ case 1: return AXP209_GPIO1_CTRL;
+ case 2: return AXP209_GPIO2_CTRL;
+ case 3: return AXP209_GPIO3_CTRL;
+ }
+ return 0;
+}
+
+int axp_gpio_direction_input(unsigned int pin)
+{
+ u8 reg = axp209_get_gpio_ctrl_reg(pin);
+ /* GPIO3 is "special" */
+ u8 val = (pin == 3) ? AXP209_GPIO3_INPUT : AXP209_GPIO_INPUT;
+
+ return axp209_write(reg, val);
+}
+
+int axp_gpio_direction_output(unsigned int pin, unsigned int val)
+{
+ u8 reg = axp209_get_gpio_ctrl_reg(pin);
+
+ if (val) {
+ val = (pin == 3) ? AXP209_GPIO3_OUTPUT_HIGH :
+ AXP209_GPIO_OUTPUT_HIGH;
+ } else {
+ val = (pin == 3) ? AXP209_GPIO3_OUTPUT_LOW :
+ AXP209_GPIO_OUTPUT_LOW;
+ }
+
+ return axp209_write(reg, val);
+}
+
+int axp_gpio_get_value(unsigned int pin)
+{
+ u8 val, mask;
+ int rc;
+
+ if (pin == 3) {
+ rc = axp209_read(AXP209_GPIO3_CTRL, &val);
+ mask = 1;
+ } else {
+ rc = axp209_read(AXP209_GPIO_STATE, &val);
+ mask = 1 << (pin + 4);
+ }
+ if (rc)
+ return rc;
+
+ return (val & mask) ? 1 : 0;
+}
+
+int axp_gpio_set_value(unsigned int pin, unsigned int val)
+{
+ return axp_gpio_direction_output(pin, val);
+}
diff --git a/drivers/power/axp221.c b/drivers/power/axp221.c
new file mode 100644
index 0000000000..4c86f099a2
--- /dev/null
+++ b/drivers/power/axp221.c
@@ -0,0 +1,391 @@
+/*
+ * AXP221 and AXP223 driver
+ *
+ * IMPORTANT when making changes to this file check that the registers
+ * used are the same for the axp221 and axp223.
+ *
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/p2wi.h>
+#include <asm/arch/rsb.h>
+#include <axp221.h>
+
+/*
+ * The axp221 uses the p2wi bus, the axp223 is identical (for all registers
+ * used sofar) but uses the rsb bus. These functions abstract this.
+ */
+static int pmic_bus_init(void)
+{
+#ifdef CONFIG_MACH_SUN6I
+ p2wi_init();
+ return p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
+ AXP221_INIT_DATA);
+#else
+ int ret;
+
+ rsb_init();
+
+ ret = rsb_set_device_mode(AXP223_DEVICE_MODE_DATA);
+ if (ret)
+ return ret;
+
+ return rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
+#endif
+}
+
+static int pmic_bus_read(const u8 addr, u8 *data)
+{
+#ifdef CONFIG_MACH_SUN6I
+ return p2wi_read(addr, data);
+#else
+ return rsb_read(AXP223_RUNTIME_ADDR, addr, data);
+#endif
+}
+
+static int pmic_bus_write(const u8 addr, u8 data)
+{
+#ifdef CONFIG_MACH_SUN6I
+ return p2wi_write(addr, data);
+#else
+ return rsb_write(AXP223_RUNTIME_ADDR, addr, data);
+#endif
+}
+
+static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+static int axp221_setbits(u8 reg, u8 bits)
+{
+ int ret;
+ u8 val;
+
+ ret = pmic_bus_read(reg, &val);
+ if (ret)
+ return ret;
+
+ val |= bits;
+ return pmic_bus_write(reg, val);
+}
+
+static int axp221_clrbits(u8 reg, u8 bits)
+{
+ int ret;
+ u8 val;
+
+ ret = pmic_bus_read(reg, &val);
+ if (ret)
+ return ret;
+
+ val &= ~bits;
+ return pmic_bus_write(reg, val);
+}
+
+int axp221_set_dcdc1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC1_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ ret = axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DCDC1SW_EN);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC1_EN);
+}
+
+int axp221_set_dcdc2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC2_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC2_EN);
+}
+
+int axp221_set_dcdc3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC3_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC3_EN);
+}
+
+int axp221_set_dcdc4(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC4_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC4_EN);
+}
+
+int axp221_set_dcdc5(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC5_EN);
+
+ ret = pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_DCDC5_EN);
+}
+
+int axp221_set_dldo1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO1_EN);
+
+ ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO1_EN);
+}
+
+int axp221_set_dldo2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO2_EN);
+
+ ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO2_EN);
+}
+
+int axp221_set_dldo3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO3_EN);
+
+ ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO3_EN);
+}
+
+int axp221_set_dldo4(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO4_EN);
+
+ ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO4_EN);
+}
+
+int axp221_set_aldo1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO1_EN);
+
+ ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO1_EN);
+}
+
+int axp221_set_aldo2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO2_EN);
+
+ ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO2_EN);
+}
+
+int axp221_set_aldo3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ if (mvolt == 0)
+ return axp221_clrbits(AXP221_OUTPUT_CTRL3,
+ AXP221_OUTPUT_CTRL3_ALDO3_EN);
+
+ ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL3,
+ AXP221_OUTPUT_CTRL3_ALDO3_EN);
+}
+
+int axp221_init(void)
+{
+ /* This cannot be 0 because it is used in SPL before BSS is ready */
+ static int needs_init = 1;
+ u8 axp_chip_id;
+ int ret;
+
+ if (!needs_init)
+ return 0;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
+ return -ENODEV;
+
+ needs_init = 0;
+ return 0;
+}
+
+int axp221_get_sid(unsigned int *sid)
+{
+ u8 *dest = (u8 *)sid;
+ int i, ret;
+
+ ret = axp221_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_write(AXP221_PAGE, 1);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 16; i++) {
+ ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
+ if (ret)
+ return ret;
+ }
+
+ pmic_bus_write(AXP221_PAGE, 0);
+
+ for (i = 0; i < 4; i++)
+ sid[i] = be32_to_cpu(sid[i]);
+
+ return 0;
+}
+
+static int axp_drivebus_setup(void)
+{
+ int ret;
+
+ ret = axp221_init();
+ if (ret)
+ return ret;
+
+ /* Set N_VBUSEN pin to output / DRIVEBUS function */
+ return axp221_clrbits(AXP221_MISC_CTRL, AXP221_MISC_CTRL_N_VBUSEN_FUNC);
+}
+
+int axp_drivebus_enable(void)
+{
+ int ret;
+
+ ret = axp_drivebus_setup();
+ if (ret)
+ return ret;
+
+ /* Set DRIVEBUS high */
+ return axp221_setbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
+}
+
+int axp_drivebus_disable(void)
+{
+ int ret;
+
+ ret = axp_drivebus_setup();
+ if (ret)
+ return ret;
+
+ /* Set DRIVEBUS low */
+ return axp221_clrbits(AXP221_VBUS_IPSOUT, AXP221_VBUS_IPSOUT_DRIVEBUS);
+}
diff --git a/drivers/power/palmas.c b/drivers/power/palmas.c
index cfbc9dc522..6430fe004d 100644
--- a/drivers/power/palmas.c
+++ b/drivers/power/palmas.c
@@ -27,7 +27,7 @@ int palmas_mmc1_poweron_ldo(void)
{
u8 val = 0;
-#if defined(CONFIG_DRA7XX)
+#if defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)
/*
* Currently valid for the dra7xx_evm board:
* Set TPS659038 LDO1 to 3.0 V
diff --git a/drivers/power/pmic/pmic_max77686.c b/drivers/power/pmic/pmic_max77686.c
index df1fd91de3..95b1a57ca2 100644
--- a/drivers/power/pmic/pmic_max77686.c
+++ b/drivers/power/pmic/pmic_max77686.c
@@ -42,11 +42,30 @@ static unsigned int max77686_ldo_volt2hex(int ldo, ulong uV)
return 0;
}
+static int max77686_buck_volt2hex(int buck, ulong uV)
+{
+ int hex = 0;
+
+ if (buck < 5 || buck > 9) {
+ debug("%s: buck %d is not supported\n", __func__, buck);
+ return -EINVAL;
+ }
+
+ hex = (uV - 750000) / 50000;
+
+ if (hex >= 0 && hex <= MAX77686_BUCK_VOLT_MAX_HEX)
+ return hex;
+
+ debug("%s: %ld is wrong voltage value for BUCK%d\n",
+ __func__, uV, buck);
+ return -EINVAL;
+}
+
int max77686_set_ldo_voltage(struct pmic *p, int ldo, ulong uV)
{
unsigned int val, ret, hex, adr;
- if (ldo < 1 && ldo > 26) {
+ if (ldo < 1 || ldo > 26) {
printf("%s: %d is wrong ldo number\n", __func__, ldo);
return -1;
}
@@ -68,11 +87,38 @@ int max77686_set_ldo_voltage(struct pmic *p, int ldo, ulong uV)
return ret;
}
+int max77686_set_buck_voltage(struct pmic *p, int buck, ulong uV)
+{
+ unsigned int val, adr;
+ int hex, ret;
+
+ if (buck < 5 || buck > 9) {
+ printf("%s: %d is an unsupported bucket number\n",
+ __func__, buck);
+ return -EINVAL;
+ }
+
+ adr = max77686_buck_addr[buck] + 1;
+ hex = max77686_buck_volt2hex(buck, uV);
+
+ if (hex < 0)
+ return hex;
+
+ ret = pmic_reg_read(p, adr, &val);
+ if (ret)
+ return ret;
+
+ val &= ~MAX77686_BUCK_VOLT_MASK;
+ ret |= pmic_reg_write(p, adr, val | hex);
+
+ return ret;
+}
+
int max77686_set_ldo_mode(struct pmic *p, int ldo, char opmode)
{
unsigned int val, ret, adr, mode;
- if (ldo < 1 && 26 < ldo) {
+ if (ldo < 1 || 26 < ldo) {
printf("%s: %d is wrong ldo number\n", __func__, ldo);
return -1;
}
@@ -157,7 +203,7 @@ int max77686_set_buck_mode(struct pmic *p, int buck, char opmode)
/* mode */
switch (opmode) {
case OPMODE_OFF:
- mode = MAX77686_BUCK_MODE_OFF;
+ mode = MAX77686_BUCK_MODE_OFF << mode_shift;
break;
case OPMODE_STANDBY:
switch (buck) {
diff --git a/drivers/power/power_i2c.c b/drivers/power/power_i2c.c
index 594cd11725..0dcf9fe918 100644
--- a/drivers/power/power_i2c.c
+++ b/drivers/power/power_i2c.c
@@ -14,7 +14,7 @@
#include <linux/types.h>
#include <power/pmic.h>
#include <i2c.h>
-#include <compiler.h>
+#include <linux/compiler.h>
int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
{
diff --git a/drivers/power/power_spi.c b/drivers/power/power_spi.c
index fb455a0061..1e554461f3 100644
--- a/drivers/power/power_spi.c
+++ b/drivers/power/power_spi.c
@@ -17,27 +17,14 @@
static struct spi_slave *slave;
-void pmic_spi_free(struct spi_slave *slave)
-{
- if (slave)
- spi_free_slave(slave);
-}
-
-struct spi_slave *pmic_spi_probe(struct pmic *p)
-{
- return spi_setup_slave(p->bus,
- p->hw.spi.cs,
- p->hw.spi.clk,
- p->hw.spi.mode);
-}
-
static u32 pmic_reg(struct pmic *p, u32 reg, u32 *val, u32 write)
{
u32 pmic_tx, pmic_rx;
u32 tmp;
if (!slave) {
- slave = pmic_spi_probe(p);
+ slave = spi_setup_slave(p->bus, p->hw.spi.cs, p->hw.spi.clk,
+ p->hw.spi.mode);
if (!slave)
return -1;
@@ -54,25 +41,25 @@ static u32 pmic_reg(struct pmic *p, u32 reg, u32 *val, u32 write)
tmp = cpu_to_be32(pmic_tx);
if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx,
- pmic_spi_flags)) {
- spi_release_bus(slave);
- return -1;
- }
+ pmic_spi_flags))
+ goto err;
if (write) {
pmic_tx = p->hw.spi.prepare_tx(reg, val, 0);
tmp = cpu_to_be32(pmic_tx);
if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx,
- pmic_spi_flags)) {
- spi_release_bus(slave);
- return -1;
- }
+ pmic_spi_flags))
+ goto err;
}
spi_release_bus(slave);
*val = cpu_to_be32(pmic_rx);
return 0;
+
+err:
+ spi_release_bus(slave);
+ return -1;
}
int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c
index d29d969533..29bab4cc00 100644
--- a/drivers/power/tps6586x.c
+++ b/drivers/power/tps6586x.c
@@ -10,9 +10,7 @@
#include <asm/io.h>
#include <i2c.h>
-static int bus_num; /* I2C bus we are on */
-#define I2C_ADDRESS 0x34 /* chip requires this address */
-static char inited; /* 1 if we have been inited */
+static struct udevice *tps6586x_dev;
enum {
/* Registers that we access */
@@ -37,13 +35,9 @@ static int tps6586x_read(int reg)
int i;
uchar data;
int retval = -1;
- int old_bus_num;
-
- old_bus_num = i2c_get_bus_num();
- i2c_set_bus_num(bus_num);
for (i = 0; i < MAX_I2C_RETRY; ++i) {
- if (!i2c_read(I2C_ADDRESS, reg, 1, &data, 1)) {
+ if (!i2c_read(tps6586x_dev, reg, &data, 1)) {
retval = (int)data;
goto exit;
}
@@ -53,7 +47,6 @@ static int tps6586x_read(int reg)
}
exit:
- i2c_set_bus_num(old_bus_num);
debug("pmu_read %x=%x\n", reg, retval);
if (retval < 0)
debug("%s: failed to read register %#x: %d\n", __func__, reg,
@@ -65,13 +58,9 @@ static int tps6586x_write(int reg, uchar *data, uint len)
{
int i;
int retval = -1;
- int old_bus_num;
-
- old_bus_num = i2c_get_bus_num();
- i2c_set_bus_num(bus_num);
for (i = 0; i < MAX_I2C_RETRY; ++i) {
- if (!i2c_write(I2C_ADDRESS, reg, 1, data, len)) {
+ if (!i2c_write(tps6586x_dev, reg, data, len)) {
retval = 0;
goto exit;
}
@@ -81,7 +70,6 @@ static int tps6586x_write(int reg, uchar *data, uint len)
}
exit:
- i2c_set_bus_num(old_bus_num);
debug("pmu_write %x=%x: ", reg, retval);
for (i = 0; i < len; i++)
debug("%x ", data[i]);
@@ -163,7 +151,7 @@ int tps6586x_set_pwm_mode(int mask)
uchar val;
int ret;
- assert(inited);
+ assert(tps6586x_dev);
ret = tps6586x_read(PFM_MODE);
if (ret != -1) {
val = (uchar)ret;
@@ -184,7 +172,7 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,
int sm0, sm1;
int bad;
- assert(inited);
+ assert(tps6586x_dev);
/* get current voltage settings */
if (read_voltages(&sm0, &sm1)) {
@@ -255,10 +243,9 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,
return bad ? -1 : 0;
}
-int tps6586x_init(int bus)
+int tps6586x_init(struct udevice *dev)
{
- bus_num = bus;
- inited = 1;
+ tps6586x_dev = dev;
return 0;
}
diff --git a/drivers/power/twl4030.c b/drivers/power/twl4030.c
index 3e50310464..7f1fdd1534 100644
--- a/drivers/power/twl4030.c
+++ b/drivers/power/twl4030.c
@@ -91,11 +91,23 @@ void twl4030_power_init(void)
TWL4030_PM_RECEIVER_DEV_GRP_P1);
}
-void twl4030_power_mmc_init(void)
+void twl4030_power_mmc_init(int dev_index)
{
- /* Set VMMC1 to 3.15 Volts */
- twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC1_DEDICATED,
- TWL4030_PM_RECEIVER_VMMC1_VSEL_32,
- TWL4030_PM_RECEIVER_VMMC1_DEV_GRP,
- TWL4030_PM_RECEIVER_DEV_GRP_P1);
+ if (dev_index == 0) {
+ /* Set VMMC1 to 3.15 Volts */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC1_DEDICATED,
+ TWL4030_PM_RECEIVER_VMMC1_VSEL_32,
+ TWL4030_PM_RECEIVER_VMMC1_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+
+ mdelay(100); /* ramp-up delay from Linux code */
+ } else if (dev_index == 1) {
+ /* Set VMMC2 to 3.15 Volts */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC2_DEDICATED,
+ TWL4030_PM_RECEIVER_VMMC2_VSEL_32,
+ TWL4030_PM_RECEIVER_VMMC2_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+
+ mdelay(100); /* ramp-up delay from Linux code */
+ }
}
diff --git a/drivers/qe/Makefile b/drivers/qe/Makefile
index 7f1bd06922..8fa48667ec 100644
--- a/drivers/qe/Makefile
+++ b/drivers/qe/Makefile
@@ -4,5 +4,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y := qe.o uccf.o uec.o uec_phy.o
+obj-$(CONFIG_QE) += qe.o uccf.o uec.o uec_phy.o
+obj-$(CONFIG_U_QE) += qe.o
obj-$(CONFIG_OF_LIBFDT) += fdt.o
diff --git a/drivers/qe/fdt.c b/drivers/qe/fdt.c
index d9a7d8206f..dfae4bf64d 100644
--- a/drivers/qe/fdt.c
+++ b/drivers/qe/fdt.c
@@ -12,6 +12,7 @@
#include <fdt_support.h>
#include "qe.h"
+#ifdef CONFIG_QE
DECLARE_GLOBAL_DATA_PTR;
/*
@@ -72,3 +73,4 @@ void ft_qe_setup(void *blob)
"clock-frequency", gd->arch.qe_clk / 2, 1);
fdt_fixup_qe_firmware(blob);
}
+#endif
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 4358a91adb..d24651b5ba 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -13,6 +13,9 @@
#include "asm/io.h"
#include "linux/immap_qe.h"
#include "qe.h"
+#ifdef CONFIG_LS102XA
+#include <asm/arch/immap_ls102xa.h>
+#endif
#define MPC85xx_DEVDISR_QE_DISABLE 0x1
@@ -40,6 +43,7 @@ void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
return;
}
+#ifdef CONFIG_QE
uint qe_muram_alloc(uint size, uint align)
{
uint retloc;
@@ -70,6 +74,7 @@ uint qe_muram_alloc(uint size, uint align)
return retloc;
}
+#endif
void *qe_muram_addr(uint offset)
{
@@ -180,6 +185,17 @@ void qe_init(uint qe_base)
qe_snums_init();
}
+#ifdef CONFIG_U_QE
+void u_qe_init(void)
+{
+ uint qe_base = CONFIG_SYS_IMMR + 0x01400000; /* QE immr base */
+ qe_immr = (qe_map_t *)qe_base;
+
+ u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
+ out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
+}
+#endif
+
void qe_reset(void)
{
qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
@@ -212,6 +228,7 @@ void qe_assign_page(uint snum, uint para_ram_base)
#define BRG_CLK (gd->arch.brg_clk)
+#ifdef CONFIG_QE
int qe_set_brg(uint brg, uint rate)
{
volatile uint *bp;
@@ -239,6 +256,7 @@ int qe_set_brg(uint brg, uint rate)
return 0;
}
+#endif
/* Set ethernet MII clock master
*/
@@ -320,8 +338,12 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
size_t length;
const struct qe_header *hdr;
#ifdef CONFIG_DEEP_SLEEP
+#ifdef CONFIG_LS102XA
+ struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
+#else
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
#endif
+#endif
if (!firmware) {
printf("Invalid address\n");
return -EINVAL;
@@ -429,6 +451,135 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
return 0;
}
+#ifdef CONFIG_U_QE
+/*
+ * Upload a microcode to the I-RAM at a specific address.
+ *
+ * See docs/README.qe_firmware for information on QE microcode uploading.
+ *
+ * Currently, only version 1 is supported, so the 'version' field must be
+ * set to 1.
+ *
+ * The SOC model and revision are not validated, they are only displayed for
+ * informational purposes.
+ *
+ * 'calc_size' is the calculated size, in bytes, of the firmware structure and
+ * all of the microcode structures, minus the CRC.
+ *
+ * 'length' is the size that the structure says it is, including the CRC.
+ */
+int u_qe_upload_firmware(const struct qe_firmware *firmware)
+{
+ unsigned int i;
+ unsigned int j;
+ u32 crc;
+ size_t calc_size = sizeof(struct qe_firmware);
+ size_t length;
+ const struct qe_header *hdr;
+#ifdef CONFIG_DEEP_SLEEP
+#ifdef CONFIG_LS102XA
+ struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
+#else
+ ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif
+#endif
+ if (!firmware) {
+ printf("Invalid address\n");
+ return -EINVAL;
+ }
+
+ hdr = &firmware->header;
+ length = be32_to_cpu(hdr->length);
+
+ /* Check the magic */
+ if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
+ (hdr->magic[2] != 'F')) {
+ printf("Not a microcode\n");
+#ifdef CONFIG_DEEP_SLEEP
+ setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
+#endif
+ return -EPERM;
+ }
+
+ /* Check the version */
+ if (hdr->version != 1) {
+ printf("Unsupported version\n");
+ return -EPERM;
+ }
+
+ /* Validate some of the fields */
+ if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
+ printf("Invalid data\n");
+ return -EINVAL;
+ }
+
+ /* Validate the length and check if there's a CRC */
+ calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
+
+ for (i = 0; i < firmware->count; i++)
+ /*
+ * For situations where the second RISC uses the same microcode
+ * as the first, the 'code_offset' and 'count' fields will be
+ * zero, so it's okay to add those.
+ */
+ calc_size += sizeof(u32) *
+ be32_to_cpu(firmware->microcode[i].count);
+
+ /* Validate the length */
+ if (length != calc_size + sizeof(u32)) {
+ printf("Invalid length\n");
+ return -EPERM;
+ }
+
+ /*
+ * Validate the CRC. We would normally call crc32_no_comp(), but that
+ * function isn't available unless you turn on JFFS support.
+ */
+ crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
+ if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
+ printf("Firmware CRC is invalid\n");
+ return -EIO;
+ }
+
+ /*
+ * If the microcode calls for it, split the I-RAM.
+ */
+ if (!firmware->split) {
+ out_be16(&qe_immr->cp.cercr,
+ in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
+ }
+
+ if (firmware->soc.model)
+ printf("Firmware '%s' for %u V%u.%u\n",
+ firmware->id, be16_to_cpu(firmware->soc.model),
+ firmware->soc.major, firmware->soc.minor);
+ else
+ printf("Firmware '%s'\n", firmware->id);
+
+ /* Loop through each microcode. */
+ for (i = 0; i < firmware->count; i++) {
+ const struct qe_microcode *ucode = &firmware->microcode[i];
+
+ /* Upload a microcode if it's present */
+ if (ucode->code_offset)
+ qe_upload_microcode(firmware, ucode);
+
+ /* Program the traps for this processor */
+ for (j = 0; j < 16; j++) {
+ u32 trap = be32_to_cpu(ucode->traps[j]);
+
+ if (trap)
+ out_be32(&qe_immr->rsp[i].tibcr[j], trap);
+ }
+
+ /* Enable traps */
+ out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
+ }
+
+ return 0;
+}
+#endif
+
struct qe_firmware_info *qe_get_firmware_info(void)
{
return qe_firmware_uploaded ? &qe_firmware_info : NULL;
diff --git a/drivers/qe/qe.h b/drivers/qe/qe.h
index ebb7c5f124..33878f897b 100644
--- a/drivers/qe/qe.h
+++ b/drivers/qe/qe.h
@@ -285,4 +285,9 @@ void ft_qe_setup(void *blob);
void qe_init(uint qe_base);
void qe_reset(void);
+#ifdef CONFIG_U_QE
+void u_qe_init(void);
+int u_qe_upload_firmware(const struct qe_firmware *firmware);
+#endif
+
#endif /* __QE_H__ */
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 43f85460a3..fdcbc00295 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
obj-$(CONFIG_RTC_BFIN) += bfin_rtc.o
obj-y += date.o
obj-$(CONFIG_RTC_DAVINCI) += davinci.o
-obj-$(CONFIG_RTC_DS12887) += ds12887.o
obj-$(CONFIG_RTC_DS1302) += ds1302.o
obj-$(CONFIG_RTC_DS1306) += ds1306.o
obj-$(CONFIG_RTC_DS1307) += ds1307.o
diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c
index 21a2189e27..4cf2d834b2 100644
--- a/drivers/rtc/bfin_rtc.c
+++ b/drivers/rtc/bfin_rtc.c
@@ -27,7 +27,7 @@
#define NUM_SECS_IN_DAY DAYS_TO_SECS(1)
/* Enable the RTC prescaler enable register */
-static void rtc_init(void)
+void rtc_init(void)
{
if (!(bfin_read_RTC_PREN() & 0x1))
bfin_write_RTC_PREN(0x1);
diff --git a/drivers/rtc/ds12887.c b/drivers/rtc/ds12887.c
deleted file mode 100644
index d8a519b8fe..0000000000
--- a/drivers/rtc/ds12887.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * (C) Copyright 2003
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-/*
- * Date & Time support for the DS12887 RTC
- */
-
-#undef RTC_DEBUG
-
-#include <common.h>
-#include <command.h>
-#include <config.h>
-#include <rtc.h>
-
-#if defined(CONFIG_CMD_DATE)
-
-#define RTC_SECONDS 0x00
-#define RTC_SECONDS_ALARM 0x01
-#define RTC_MINUTES 0x02
-#define RTC_MINUTES_ALARM 0x03
-#define RTC_HOURS 0x04
-#define RTC_HOURS_ALARM 0x05
-#define RTC_DAY_OF_WEEK 0x06
-#define RTC_DATE_OF_MONTH 0x07
-#define RTC_MONTH 0x08
-#define RTC_YEAR 0x09
-#define RTC_CONTROL_A 0x0A
-#define RTC_CONTROL_B 0x0B
-#define RTC_CONTROL_C 0x0C
-#define RTC_CONTROL_D 0x0D
-
-#define RTC_CA_UIP 0x80
-#define RTC_CB_DM 0x04
-#define RTC_CB_24_12 0x02
-#define RTC_CB_SET 0x80
-
-#if defined(CONFIG_ATC)
-
-static uchar rtc_read (uchar reg)
-{
- uchar val;
-
- *(volatile unsigned char*)(RTC_PORT_ADDR) = reg;
- __asm__ __volatile__ ("sync");
-
- val = *(volatile unsigned char*)(RTC_PORT_DATA);
- return (val);
-}
-
-static void rtc_write (uchar reg, uchar val)
-{
- *(volatile unsigned char*)(RTC_PORT_ADDR) = reg;
- __asm__ __volatile__ ("sync");
-
- *(volatile unsigned char*)(RTC_PORT_DATA) = val;
- __asm__ __volatile__ ("sync");
-}
-
-#else
-# error Board specific rtc access functions should be supplied
-#endif
-
-int rtc_get (struct rtc_time *tmp)
-{
- uchar sec, min, hour, mday, wday, mon, year;
-
- /* check if rtc is available for access */
- while( rtc_read(RTC_CONTROL_A) & RTC_CA_UIP)
- ;
-
- 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);
-
-#ifdef RTC_DEBUG
- printf( "Get RTC year: %d; mon: %d; mday: %d; wday: %d; "
- "hr: %d; min: %d; sec: %d\n",
- year, mon, mday, wday, hour, min, sec );
-
- printf ( "Alarms: hour: %02x min: %02x sec: %02x\n",
- rtc_read (RTC_HOURS_ALARM),
- rtc_read (RTC_MINUTES_ALARM),
- rtc_read (RTC_SECONDS_ALARM) );
-#endif
-
- if( !(rtc_read(RTC_CONTROL_B) & RTC_CB_DM))
- { /* Information is in BCD format */
-printf(" Get: Convert BSD to BIN\n");
- tmp->tm_sec = bcd2bin (sec & 0x7F);
- tmp->tm_min = bcd2bin (min & 0x7F);
- tmp->tm_hour = bcd2bin (hour & 0x3F);
- tmp->tm_mday = bcd2bin (mday & 0x3F);
- tmp->tm_mon = bcd2bin (mon & 0x1F);
- tmp->tm_year = bcd2bin (year);
- tmp->tm_wday = bcd2bin (wday & 0x07);
- }
-else
- {
- tmp->tm_sec = sec & 0x7F;
- tmp->tm_min = min & 0x7F;
- tmp->tm_hour = hour & 0x3F;
- tmp->tm_mday = mday & 0x3F;
- tmp->tm_mon = mon & 0x1F;
- tmp->tm_year = year;
- tmp->tm_wday = wday & 0x07;
- }
-
-
- if(tmp->tm_year<70)
- tmp->tm_year+=2000;
- else
- tmp->tm_year+=1900;
-
- tmp->tm_yday = 0;
- tmp->tm_isdst= 0;
-#ifdef RTC_DEBUG
- printf ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
- tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-#endif
-
- return 0;
-}
-
-int rtc_set (struct rtc_time *tmp)
-{
- uchar save_ctrl_b;
- uchar sec, min, hour, mday, wday, mon, year;
-
-#ifdef RTC_DEBUG
- printf ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
- tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-#endif
-
- if( !(rtc_read(RTC_CONTROL_B) & RTC_CB_DM))
- { /* Information is in BCD format */
- year = bin2bcd(tmp->tm_year % 100);
- mon = bin2bcd(tmp->tm_mon);
- wday = bin2bcd(tmp->tm_wday);
- mday = bin2bcd(tmp->tm_mday);
- hour = bin2bcd(tmp->tm_hour);
- min = bin2bcd(tmp->tm_min);
- sec = bin2bcd(tmp->tm_sec);
- }
- else
- {
- year = tmp->tm_year % 100;
- mon = tmp->tm_mon;
- wday = tmp->tm_wday;
- mday = tmp->tm_mday;
- hour = tmp->tm_hour;
- min = tmp->tm_min;
- sec = tmp->tm_sec;
- }
-
- /* disables the RTC to update the regs */
- save_ctrl_b = rtc_read(RTC_CONTROL_B);
- save_ctrl_b |= RTC_CB_SET;
- rtc_write(RTC_CONTROL_B, save_ctrl_b);
-
- rtc_write (RTC_YEAR, year);
- rtc_write (RTC_MONTH, mon);
- rtc_write (RTC_DAY_OF_WEEK, wday);
- rtc_write (RTC_DATE_OF_MONTH, mday);
- rtc_write (RTC_HOURS, hour);
- rtc_write (RTC_MINUTES, min);
- rtc_write (RTC_SECONDS, sec);
-
- /* enables the RTC to update the regs */
- save_ctrl_b &= ~RTC_CB_SET;
- rtc_write(RTC_CONTROL_B, save_ctrl_b);
-
- return 0;
-}
-
-void rtc_reset (void)
-{
- struct rtc_time tmp;
- uchar ctrl_rg;
-
- ctrl_rg = RTC_CB_SET;
- rtc_write(RTC_CONTROL_B,ctrl_rg);
-
- tmp.tm_year = 1970 % 100;
- tmp.tm_mon = 1;
- tmp.tm_mday= 1;
- tmp.tm_hour = 0;
- tmp.tm_min = 0;
- tmp.tm_sec = 0;
-
-#ifdef RTC_DEBUG
- printf ( "RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n",
- tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
- tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
-#endif
-
- ctrl_rg = RTC_CB_SET | RTC_CB_24_12 | RTC_CB_DM;
- rtc_write(RTC_CONTROL_B,ctrl_rg);
- rtc_set(&tmp);
-
- rtc_write(RTC_HOURS_ALARM, 0),
- rtc_write(RTC_MINUTES_ALARM, 0),
- rtc_write(RTC_SECONDS_ALARM, 0);
-
- ctrl_rg = RTC_CB_24_12 | RTC_CB_DM;
- rtc_write(RTC_CONTROL_B,ctrl_rg);
-}
-
-#endif
diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c
index f7cf1064f9..39e6041be3 100644
--- a/drivers/rtc/mc146818.c
+++ b/drivers/rtc/mc146818.c
@@ -14,6 +14,7 @@
#include <common.h>
#include <command.h>
#include <rtc.h>
+#include <version.h>
#if defined(__I386__) || defined(CONFIG_MALTA)
#include <asm/io.h>
@@ -23,6 +24,9 @@
#if defined(CONFIG_CMD_DATE)
+/* 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);
@@ -41,7 +45,14 @@ static void rtc_write (uchar reg, uchar val);
#define RTC_CONFIG_B 0x0B
#define RTC_CONFIG_C 0x0C
#define RTC_CONFIG_D 0x0D
+#define RTC_REG_SIZE 0x80
+
+#define RTC_CONFIG_A_REF_CLCK_32KHZ (1 << 5)
+#define RTC_CONFIG_A_RATE_1024HZ 6
+#define RTC_CONFIG_B_24H (1 << 1)
+
+#define RTC_CONFIG_D_VALID_RAM_AND_TIME 0x80
/* ------------------------------------------------------------------------- */
@@ -128,25 +139,49 @@ void rtc_reset (void)
*/
static uchar rtc_read (uchar reg)
{
- return(in8(CONFIG_SYS_RTC_REG_BASE_ADDR+reg));
+ return in8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg);
}
static void rtc_write (uchar reg, uchar val)
{
- out8(CONFIG_SYS_RTC_REG_BASE_ADDR+reg, val);
+ out8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg, val);
}
#else
static uchar rtc_read (uchar reg)
{
out8(RTC_PORT_MC146818,reg);
- return(in8(RTC_PORT_MC146818+1));
+ return in8(RTC_PORT_MC146818 + 1);
}
static void rtc_write (uchar reg, uchar val)
{
out8(RTC_PORT_MC146818,reg);
- out8(RTC_PORT_MC146818+1,val);
+ out8(RTC_PORT_MC146818+1, val);
}
#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);
+ for (i = RTC_CONFIG_A; i < RTC_REG_SIZE; i++)
+ rtc_write(i, 0);
+ printf("RTC: zeroing CMOS RAM\n");
+#endif
+
+ /* Setup the real time clock */
+ rtc_write(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_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);
+
+ /* Clear any pending interrupts */
+ rtc_read(RTC_CONFIG_C);
+}
#endif
diff --git a/drivers/rtc/mvrtc.h b/drivers/rtc/mvrtc.h
index ebddc124c3..424743c990 100644
--- a/drivers/rtc/mvrtc.h
+++ b/drivers/rtc/mvrtc.h
@@ -13,7 +13,7 @@
#define _MVRTC_H_
#include <asm/arch/soc.h>
-#include <compiler.h>
+#include <linux/compiler.h>
/* RTC registers */
struct mvrtc_registers {
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 2c19ebc288..4cc00cd2f8 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
obj-$(CONFIG_ARM_DCC) += arm_dcc.o
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
+obj-$(CONFIG_DW_SERIAL) += serial_dw.o
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
obj-$(CONFIG_MCFUART) += mcfuart.o
obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o
@@ -42,7 +43,7 @@ obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o
obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
-obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o
+obj-$(CONFIG_X86_SERIAL) += serial_x86.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c
index 8f0e3489a0..4fe992bf2b 100644
--- a/drivers/serial/atmel_usart.c
+++ b/drivers/serial/atmel_usart.c
@@ -7,11 +7,16 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <dm.h>
+#include <errno.h>
#include <watchdog.h>
#include <serial.h>
#include <linux/compiler.h>
#include <asm/io.h>
+#ifdef CONFIG_DM_SERIAL
+#include <asm/arch/atmel_serial.h>
+#endif
#include <asm/arch/clk.h>
#include <asm/arch/hardware.h>
@@ -19,9 +24,9 @@
DECLARE_GLOBAL_DATA_PTR;
-static void atmel_serial_setbrg(void)
+static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id,
+ int baudrate)
{
- atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
unsigned long divisor;
unsigned long usart_hz;
@@ -30,15 +35,13 @@ static void atmel_serial_setbrg(void)
* Baud Rate = --------------
* 16 * CD
*/
- usart_hz = get_usart_clk_rate(CONFIG_USART_ID);
- divisor = (usart_hz / 16 + gd->baudrate / 2) / gd->baudrate;
+ usart_hz = get_usart_clk_rate(id);
+ divisor = (usart_hz / 16 + baudrate / 2) / baudrate;
writel(USART3_BF(CD, divisor), &usart->brgr);
}
-static int atmel_serial_init(void)
+static void atmel_serial_init_internal(atmel_usart3_t *usart)
{
- atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
-
/*
* Just in case: drain transmitter register
* 1000us is enough for baudrate >= 9600
@@ -47,9 +50,10 @@ static int atmel_serial_init(void)
__udelay(1000);
writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
+}
- serial_setbrg();
-
+static void atmel_serial_activate(atmel_usart3_t *usart)
+{
writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL)
| USART3_BF(USCLKS, USART3_USCLKS_MCK)
| USART3_BF(CHRL, USART3_CHRL_8)
@@ -59,6 +63,22 @@ static int atmel_serial_init(void)
writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
/* 100us is enough for the new settings to be settled */
__udelay(100);
+}
+
+#ifndef CONFIG_DM_SERIAL
+static void atmel_serial_setbrg(void)
+{
+ atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE,
+ CONFIG_USART_ID, gd->baudrate);
+}
+
+static int atmel_serial_init(void)
+{
+ atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
+
+ atmel_serial_init_internal(usart);
+ serial_setbrg();
+ atmel_serial_activate(usart);
return 0;
}
@@ -109,3 +129,81 @@ __weak struct serial_device *default_serial_console(void)
{
return &atmel_serial_drv;
}
+#endif
+
+#ifdef CONFIG_DM_SERIAL
+
+struct atmel_serial_priv {
+ atmel_usart3_t *usart;
+};
+
+int atmel_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct atmel_serial_priv *priv = dev_get_priv(dev);
+
+ atmel_serial_setbrg_internal(priv->usart, 0 /* ignored */, baudrate);
+ atmel_serial_activate(priv->usart);
+
+ return 0;
+}
+
+static int atmel_serial_getc(struct udevice *dev)
+{
+ struct atmel_serial_priv *priv = dev_get_priv(dev);
+
+ if (!(readl(&priv->usart->csr) & USART3_BIT(RXRDY)))
+ return -EAGAIN;
+
+ return readl(&priv->usart->rhr);
+}
+
+static int atmel_serial_putc(struct udevice *dev, const char ch)
+{
+ struct atmel_serial_priv *priv = dev_get_priv(dev);
+
+ if (!(readl(&priv->usart->csr) & USART3_BIT(TXRDY)))
+ return -EAGAIN;
+
+ writel(ch, &priv->usart->thr);
+
+ return 0;
+}
+
+static int atmel_serial_pending(struct udevice *dev, bool input)
+{
+ struct atmel_serial_priv *priv = dev_get_priv(dev);
+ uint32_t csr = readl(&priv->usart->csr);
+
+ if (input)
+ return csr & USART3_BIT(RXRDY) ? 1 : 0;
+ else
+ return csr & USART3_BIT(TXEMPTY) ? 0 : 1;
+}
+
+static const struct dm_serial_ops atmel_serial_ops = {
+ .putc = atmel_serial_putc,
+ .pending = atmel_serial_pending,
+ .getc = atmel_serial_getc,
+ .setbrg = atmel_serial_setbrg,
+};
+
+static int atmel_serial_probe(struct udevice *dev)
+{
+ struct atmel_serial_platdata *plat = dev->platdata;
+ struct atmel_serial_priv *priv = dev_get_priv(dev);
+
+ priv->usart = (atmel_usart3_t *)plat->base_addr;
+ atmel_serial_init_internal(priv->usart);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(serial_atmel) = {
+ .name = "serial_atmel",
+ .id = UCLASS_SERIAL,
+ .probe = atmel_serial_probe,
+ .ops = &atmel_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+ .priv_auto_alloc_size = sizeof(struct atmel_serial_priv),
+};
+#endif
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 8f051914f5..70c946249f 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -132,11 +132,12 @@ static void NS16550_setbrg(NS16550_t com_port, int baud_divisor)
void NS16550_init(NS16550_t com_port, int baud_divisor)
{
-#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_OMAP34XX))
+#if (defined(CONFIG_SPL_BUILD) && \
+ (defined(CONFIG_OMAP34XX) || defined(CONFIG_OMAP44XX)))
/*
- * On some OMAP3 devices when UART3 is configured for boot mode before
- * SPL starts only THRE bit is set. We have to empty the transmitter
- * before initialization starts.
+ * On some OMAP3/OMAP4 devices when UART3 is configured for boot mode
+ * before SPL starts only THRE bit is set. We have to empty the
+ * transmitter before initialization starts.
*/
if ((serial_in(&com_port->lsr) & (UART_LSR_TEMT | UART_LSR_THRE))
== UART_LSR_THRE) {
@@ -288,7 +289,38 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
struct ns16550_platdata *plat = dev->platdata;
fdt_addr_t addr;
+ /* try Processor Local Bus device first */
addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+#ifdef CONFIG_PCI
+ if (addr == FDT_ADDR_T_NONE) {
+ /* then try pci device */
+ struct fdt_pci_addr pci_addr;
+ u32 bar;
+ int ret;
+
+ /* we prefer to use a memory-mapped register */
+ ret = fdtdec_get_pci_addr(gd->fdt_blob, dev->of_offset,
+ FDT_PCI_SPACE_MEM32, "reg",
+ &pci_addr);
+ if (ret) {
+ /* try if there is any i/o-mapped register */
+ ret = fdtdec_get_pci_addr(gd->fdt_blob,
+ dev->of_offset,
+ FDT_PCI_SPACE_IO,
+ "reg", &pci_addr);
+ if (ret)
+ return ret;
+ }
+
+ ret = fdtdec_get_pci_bar32(gd->fdt_blob, dev->of_offset,
+ &pci_addr, &bar);
+ if (ret)
+ return ret;
+
+ addr = bar;
+ }
+#endif
+
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 71f1a5cb91..d1b5777cec 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <dm.h>
+#include <environment.h>
#include <errno.h>
#include <fdtdec.h>
#include <os.h>
@@ -19,8 +20,10 @@
DECLARE_GLOBAL_DATA_PTR;
-/* The currently-selected console serial device */
-struct udevice *cur_dev __attribute__ ((section(".data")));
+/*
+ * Table with supported baudrates (defined in config_xyz.h)
+ */
+static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
#ifndef CONFIG_SYS_MALLOC_F_LEN
#error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work"
@@ -28,25 +31,30 @@ struct udevice *cur_dev __attribute__ ((section(".data")));
static void serial_find_console_or_panic(void)
{
+ struct udevice *dev;
+
#ifdef CONFIG_OF_CONTROL
int node;
/* Check for a chosen console */
node = fdtdec_get_chosen_node(gd->fdt_blob, "stdout-path");
if (node < 0)
- node = fdtdec_get_alias_node(gd->fdt_blob, "console");
- if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &cur_dev))
+ node = fdt_path_offset(gd->fdt_blob, "console");
+ if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &dev)) {
+ gd->cur_serial_dev = dev;
return;
+ }
/*
* If the console is not marked to be bound before relocation, bind
* it anyway.
*/
if (node > 0 &&
- !lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &cur_dev)) {
- if (!device_probe(cur_dev))
+ !lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &dev)) {
+ if (!device_probe(dev)) {
+ gd->cur_serial_dev = dev;
return;
- cur_dev = NULL;
+ }
}
#endif
/*
@@ -61,11 +69,12 @@ static void serial_find_console_or_panic(void)
#else
#define INDEX 0
#endif
- if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &cur_dev) &&
- uclass_get_device(UCLASS_SERIAL, INDEX, &cur_dev) &&
- (uclass_first_device(UCLASS_SERIAL, &cur_dev) || !cur_dev))
+ if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) &&
+ uclass_get_device(UCLASS_SERIAL, INDEX, &dev) &&
+ (uclass_first_device(UCLASS_SERIAL, &dev) || !dev))
panic("No serial driver found");
#undef INDEX
+ gd->cur_serial_dev = dev;
}
/* Called prior to relocation */
@@ -127,40 +136,42 @@ static int _serial_tstc(struct udevice *dev)
void serial_putc(char ch)
{
- _serial_putc(cur_dev, ch);
+ _serial_putc(gd->cur_serial_dev, ch);
}
void serial_puts(const char *str)
{
- _serial_puts(cur_dev, str);
+ _serial_puts(gd->cur_serial_dev, str);
}
int serial_getc(void)
{
- return _serial_getc(cur_dev);
+ return _serial_getc(gd->cur_serial_dev);
}
int serial_tstc(void)
{
- return _serial_tstc(cur_dev);
+ return _serial_tstc(gd->cur_serial_dev);
}
void serial_setbrg(void)
{
- struct dm_serial_ops *ops = serial_get_ops(cur_dev);
+ struct dm_serial_ops *ops = serial_get_ops(gd->cur_serial_dev);
if (ops->setbrg)
- ops->setbrg(cur_dev, gd->baudrate);
+ ops->setbrg(gd->cur_serial_dev, gd->baudrate);
}
void serial_stdio_init(void)
{
}
+#ifdef CONFIG_DM_STDIO
static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
{
_serial_putc(sdev->priv, ch);
}
+#endif
void serial_stub_puts(struct stdio_dev *sdev, const char *str)
{
@@ -177,11 +188,74 @@ int serial_stub_tstc(struct stdio_dev *sdev)
return _serial_tstc(sdev->priv);
}
+/**
+ * on_baudrate() - Update the actual baudrate when the env var changes
+ *
+ * This will check for a valid baudrate and only apply it if valid.
+ */
+static int on_baudrate(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ int i;
+ int baudrate;
+
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ /*
+ * Switch to new baudrate if new baudrate is supported
+ */
+ baudrate = simple_strtoul(value, NULL, 10);
+
+ /* Not actually changing */
+ if (gd->baudrate == baudrate)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
+ if (baudrate == baudrate_table[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(baudrate_table)) {
+ if ((flags & H_FORCE) == 0)
+ printf("## Baudrate %d bps not supported\n",
+ baudrate);
+ return 1;
+ }
+ if ((flags & H_INTERACTIVE) != 0) {
+ printf("## Switch baudrate to %d bps and press ENTER ...\n",
+ baudrate);
+ udelay(50000);
+ }
+
+ gd->baudrate = baudrate;
+
+ serial_setbrg();
+
+ udelay(50000);
+
+ if ((flags & H_INTERACTIVE) != 0)
+ while (1) {
+ if (getc() == '\r')
+ break;
+ }
+
+ return 0;
+ case env_op_delete:
+ printf("## Baudrate may not be deleted\n");
+ return 1;
+ default:
+ return 0;
+ }
+}
+U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
+
static int serial_post_probe(struct udevice *dev)
{
- struct stdio_dev sdev;
struct dm_serial_ops *ops = serial_get_ops(dev);
+#ifdef CONFIG_DM_STDIO
struct serial_dev_priv *upriv = dev->uclass_priv;
+ struct stdio_dev sdev;
+#endif
int ret;
/* Set the baud rate */
@@ -191,9 +265,9 @@ static int serial_post_probe(struct udevice *dev)
return ret;
}
+#ifdef CONFIG_DM_STDIO
if (!(gd->flags & GD_FLG_RELOC))
return 0;
-
memset(&sdev, '\0', sizeof(sdev));
strncpy(sdev.name, dev->name, sizeof(sdev.name));
@@ -204,7 +278,7 @@ static int serial_post_probe(struct udevice *dev)
sdev.getc = serial_stub_getc;
sdev.tstc = serial_stub_tstc;
stdio_register_dev(&sdev, &upriv->sdev);
-
+#endif
return 0;
}
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index 18e41b2302..95c992a5a3 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -109,54 +109,54 @@ U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
void name(void) \
__attribute__((weak, alias("serial_null")));
-serial_initfunc(mpc8xx_serial_initialize);
-serial_initfunc(ns16550_serial_initialize);
-serial_initfunc(pxa_serial_initialize);
-serial_initfunc(s3c24xx_serial_initialize);
-serial_initfunc(s5p_serial_initialize);
-serial_initfunc(zynq_serial_initialize);
-serial_initfunc(bfin_serial_initialize);
-serial_initfunc(bfin_jtag_initialize);
-serial_initfunc(mpc512x_serial_initialize);
-serial_initfunc(uartlite_serial_initialize);
-serial_initfunc(au1x00_serial_initialize);
-serial_initfunc(asc_serial_initialize);
-serial_initfunc(jz_serial_initialize);
-serial_initfunc(mpc5xx_serial_initialize);
-serial_initfunc(mpc8260_scc_serial_initialize);
-serial_initfunc(mpc8260_smc_serial_initialize);
-serial_initfunc(mpc85xx_serial_initialize);
-serial_initfunc(iop480_serial_initialize);
-serial_initfunc(leon2_serial_initialize);
-serial_initfunc(leon3_serial_initialize);
-serial_initfunc(marvell_serial_initialize);
+serial_initfunc(altera_jtag_serial_initialize);
+serial_initfunc(altera_serial_initialize);
serial_initfunc(amirix_serial_initialize);
+serial_initfunc(arc_serial_initialize);
+serial_initfunc(arm_dcc_initialize);
+serial_initfunc(asc_serial_initialize);
+serial_initfunc(atmel_serial_initialize);
+serial_initfunc(au1x00_serial_initialize);
+serial_initfunc(bfin_jtag_initialize);
+serial_initfunc(bfin_serial_initialize);
serial_initfunc(bmw_serial_initialize);
+serial_initfunc(clps7111_serial_initialize);
serial_initfunc(cogent_serial_initialize);
serial_initfunc(cpci750_serial_initialize);
serial_initfunc(evb64260_serial_initialize);
-serial_initfunc(ml2_serial_initialize);
-serial_initfunc(sconsole_serial_initialize);
-serial_initfunc(p3mx_serial_initialize);
-serial_initfunc(altera_jtag_serial_initialize);
-serial_initfunc(altera_serial_initialize);
-serial_initfunc(atmel_serial_initialize);
-serial_initfunc(lpc32xx_serial_initialize);
-serial_initfunc(mcf_serial_initialize);
-serial_initfunc(oc_serial_initialize);
-serial_initfunc(sandbox_serial_initialize);
-serial_initfunc(clps7111_serial_initialize);
serial_initfunc(imx_serial_initialize);
+serial_initfunc(iop480_serial_initialize);
+serial_initfunc(jz_serial_initialize);
serial_initfunc(ks8695_serial_initialize);
+serial_initfunc(leon2_serial_initialize);
+serial_initfunc(leon3_serial_initialize);
serial_initfunc(lh7a40x_serial_initialize);
+serial_initfunc(lpc32xx_serial_initialize);
+serial_initfunc(marvell_serial_initialize);
serial_initfunc(max3100_serial_initialize);
+serial_initfunc(mcf_serial_initialize);
+serial_initfunc(ml2_serial_initialize);
+serial_initfunc(mpc512x_serial_initialize);
+serial_initfunc(mpc5xx_serial_initialize);
+serial_initfunc(mpc8260_scc_serial_initialize);
+serial_initfunc(mpc8260_smc_serial_initialize);
+serial_initfunc(mpc85xx_serial_initialize);
+serial_initfunc(mpc8xx_serial_initialize);
serial_initfunc(mxc_serial_initialize);
+serial_initfunc(mxs_auart_initialize);
+serial_initfunc(ns16550_serial_initialize);
+serial_initfunc(oc_serial_initialize);
+serial_initfunc(p3mx_serial_initialize);
serial_initfunc(pl01x_serial_initialize);
+serial_initfunc(pxa_serial_initialize);
+serial_initfunc(s3c24xx_serial_initialize);
+serial_initfunc(s5p_serial_initialize);
serial_initfunc(sa1100_serial_initialize);
+serial_initfunc(sandbox_serial_initialize);
+serial_initfunc(sconsole_serial_initialize);
serial_initfunc(sh_serial_initialize);
-serial_initfunc(arm_dcc_initialize);
-serial_initfunc(mxs_auart_initialize);
-serial_initfunc(arc_serial_initialize);
+serial_initfunc(uartlite_serial_initialize);
+serial_initfunc(zynq_serial_initialize);
/**
* serial_register() - Register serial driver with serial driver core
@@ -202,54 +202,54 @@ void serial_register(struct serial_device *dev)
*/
void serial_initialize(void)
{
- mpc8xx_serial_initialize();
- ns16550_serial_initialize();
- pxa_serial_initialize();
- s3c24xx_serial_initialize();
- s5p_serial_initialize();
- mpc512x_serial_initialize();
- bfin_serial_initialize();
- bfin_jtag_initialize();
- uartlite_serial_initialize();
- zynq_serial_initialize();
- au1x00_serial_initialize();
- asc_serial_initialize();
- jz_serial_initialize();
- mpc5xx_serial_initialize();
- mpc8260_scc_serial_initialize();
- mpc8260_smc_serial_initialize();
- mpc85xx_serial_initialize();
- iop480_serial_initialize();
- leon2_serial_initialize();
- leon3_serial_initialize();
- marvell_serial_initialize();
+ altera_jtag_serial_initialize();
+ altera_serial_initialize();
amirix_serial_initialize();
+ arc_serial_initialize();
+ arm_dcc_initialize();
+ asc_serial_initialize();
+ atmel_serial_initialize();
+ au1x00_serial_initialize();
+ bfin_jtag_initialize();
+ bfin_serial_initialize();
bmw_serial_initialize();
+ clps7111_serial_initialize();
cogent_serial_initialize();
cpci750_serial_initialize();
evb64260_serial_initialize();
- ml2_serial_initialize();
- sconsole_serial_initialize();
- p3mx_serial_initialize();
- altera_jtag_serial_initialize();
- altera_serial_initialize();
- atmel_serial_initialize();
- lpc32xx_serial_initialize();
- mcf_serial_initialize();
- oc_serial_initialize();
- sandbox_serial_initialize();
- clps7111_serial_initialize();
imx_serial_initialize();
+ iop480_serial_initialize();
+ jz_serial_initialize();
ks8695_serial_initialize();
+ leon2_serial_initialize();
+ leon3_serial_initialize();
lh7a40x_serial_initialize();
+ lpc32xx_serial_initialize();
+ marvell_serial_initialize();
max3100_serial_initialize();
+ mcf_serial_initialize();
+ ml2_serial_initialize();
+ mpc512x_serial_initialize();
+ mpc5xx_serial_initialize();
+ mpc8260_scc_serial_initialize();
+ mpc8260_smc_serial_initialize();
+ mpc85xx_serial_initialize();
+ mpc8xx_serial_initialize();
mxc_serial_initialize();
+ mxs_auart_initialize();
+ ns16550_serial_initialize();
+ oc_serial_initialize();
+ p3mx_serial_initialize();
pl01x_serial_initialize();
+ pxa_serial_initialize();
+ s3c24xx_serial_initialize();
+ s5p_serial_initialize();
sa1100_serial_initialize();
+ sandbox_serial_initialize();
+ sconsole_serial_initialize();
sh_serial_initialize();
- arm_dcc_initialize();
- mxs_auart_initialize();
- arc_serial_initialize();
+ uartlite_serial_initialize();
+ zynq_serial_initialize();
serial_assign(default_serial_console()->name);
}
diff --git a/drivers/serial/serial_coreboot.c b/drivers/serial/serial_dw.c
index 5c6a76c59c..a348f2956a 100644
--- a/drivers/serial/serial_coreboot.c
+++ b/drivers/serial/serial_dw.c
@@ -9,12 +9,12 @@
#include <ns16550.h>
#include <serial.h>
-static const struct udevice_id coreboot_serial_ids[] = {
- { .compatible = "coreboot-uart" },
+static const struct udevice_id dw_serial_ids[] = {
+ { .compatible = "snps,dw-apb-uart" },
{ }
};
-static int coreboot_serial_ofdata_to_platdata(struct udevice *dev)
+static int dw_serial_ofdata_to_platdata(struct udevice *dev)
{
struct ns16550_platdata *plat = dev_get_platdata(dev);
int ret;
@@ -22,15 +22,16 @@ static int coreboot_serial_ofdata_to_platdata(struct udevice *dev)
ret = ns16550_serial_ofdata_to_platdata(dev);
if (ret)
return ret;
- plat->clock = 1843200;
+ plat->clock = CONFIG_SYS_NS16550_CLK;
return 0;
}
+
U_BOOT_DRIVER(serial_ns16550) = {
- .name = "serial_coreboot",
+ .name = "serial_dw",
.id = UCLASS_SERIAL,
- .of_match = coreboot_serial_ids,
- .ofdata_to_platdata = coreboot_serial_ofdata_to_platdata,
+ .of_match = dw_serial_ids,
+ .ofdata_to_platdata = dw_serial_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
.priv_auto_alloc_size = sizeof(struct NS16550),
.probe = ns16550_serial_probe,
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index 38dda91021..75eb6bd729 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -72,30 +72,39 @@ static int pl01x_tstc(struct pl01x_regs *regs)
static int pl01x_generic_serial_init(struct pl01x_regs *regs,
enum pl01x_type type)
{
- unsigned int lcr;
-
+ switch (type) {
+ case TYPE_PL010:
+ /* disable everything */
+ writel(0, &regs->pl010_cr);
+ break;
+ case TYPE_PL011:
#ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT
- if (type == TYPE_PL011) {
/* Empty RX fifo if necessary */
if (readl(&regs->pl011_cr) & UART_PL011_CR_UARTEN) {
while (!(readl(&regs->fr) & UART_PL01x_FR_RXFE))
readl(&regs->dr);
}
- }
#endif
+ /* disable everything */
+ writel(0, &regs->pl011_cr);
+ break;
+ default:
+ return -EINVAL;
+ }
- /* First, disable everything */
- writel(0, &regs->pl010_cr);
+ return 0;
+}
- /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */
+static int set_line_control(struct pl01x_regs *regs)
+{
+ unsigned int lcr;
+ /*
+ * Internal update of baud rate register require line
+ * control register write
+ */
lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN;
- writel(lcr, &regs->pl011_lcrh);
-
- switch (type) {
- case TYPE_PL010:
- break;
- case TYPE_PL011: {
#ifdef CONFIG_PL011_SERIAL_RLCR
+ {
int i;
/*
@@ -107,15 +116,9 @@ static int pl01x_generic_serial_init(struct pl01x_regs *regs,
writel(lcr, &regs->fr);
writel(lcr, &regs->pl011_rlcr);
- /* lcrh needs to be set again for change to be effective */
- writel(lcr, &regs->pl011_lcrh);
-#endif
- break;
- }
- default:
- return -EINVAL;
}
-
+#endif
+ writel(lcr, &regs->pl011_lcrh);
return 0;
}
@@ -175,6 +178,7 @@ static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type,
writel(divider, &regs->pl011_ibrd);
writel(fraction, &regs->pl011_fbrd);
+ set_line_control(regs);
/* Finally, enable the UART */
writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE |
UART_PL011_CR_RXE | UART_PL011_CR_RTS, &regs->pl011_cr);
@@ -201,7 +205,7 @@ static void pl01x_serial_init_baud(int baudrate)
base_regs = (struct pl01x_regs *)port[CONFIG_CONS_INDEX];
pl01x_generic_serial_init(base_regs, pl01x_type);
- pl01x_generic_setbrg(base_regs, TYPE_PL010, clock, baudrate);
+ pl01x_generic_setbrg(base_regs, pl01x_type, clock, baudrate);
}
/*
@@ -344,6 +348,7 @@ U_BOOT_DRIVER(serial_pl01x) = {
.probe = pl01x_serial_probe,
.ops = &pl01x_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
+ .priv_auto_alloc_size = sizeof(struct pl01x_priv),
};
#endif
diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h
index fe8cde4ded..ef88c8f273 100644
--- a/drivers/serial/serial_sh.h
+++ b/drivers/serial/serial_sh.h
@@ -227,7 +227,7 @@ struct uart_port {
# define SCIF_ORER 0x0001 /* Overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
# define SCIF_ORER 0x0001
# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0, */
#else
@@ -304,7 +304,8 @@ struct uart_port {
/* SH7763 SCIF2 support */
# define SCIF2_RFDC_MASK 0x001f
# define SCIF2_TXROOM_MAX 16
-#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791)
+#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
# define SCIF_ERRORS (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
# define SCIF_RFDC_MASK 0x003f
#else
@@ -432,7 +433,7 @@ static inline void sci_##name##_out(struct uart_port *port,\
SCI_OUT(sci_size, sci_offset, value);\
}
-#if defined(CONFIG_SH3) || \
+#if defined(CONFIG_CPU_SH3) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377) || \
defined(CONFIG_ARCH_SH7372) || \
@@ -589,7 +590,7 @@ SCIF_FNS(SCSPTR, 0, 0, 0, 0)
SCIF_FNS(SCSPTR, 0, 0, 0x20, 16)
#endif
#if defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
SCIF_FNS(DL, 0, 0, 0x30, 16)
SCIF_FNS(CKS, 0, 0, 0x34, 16)
#endif
@@ -734,7 +735,8 @@ static inline int scbrr_calc(struct uart_port port, int bps, int clk)
#define SCBRR_VALUE(bps, clk) scbrr_calc(sh_sci, bps, clk)
#elif defined(__H8300H__) || defined(__H8300S__)
#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1)
-#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791)
+#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
#define DL_VALUE(bps, clk) (clk / bps / 16) /* External Clock */
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) /* Internal Clock */
#else /* Generic SH */
diff --git a/drivers/serial/serial_tegra.c b/drivers/serial/serial_tegra.c
index 7eb70e1de1..b9227f0563 100644
--- a/drivers/serial/serial_tegra.c
+++ b/drivers/serial/serial_tegra.c
@@ -9,6 +9,7 @@
#include <ns16550.h>
#include <serial.h>
+#ifdef CONFIG_OF_CONTROL
static const struct udevice_id tegra_serial_ids[] = {
{ .compatible = "nvidia,tegra20-uart" },
{ }
@@ -26,13 +27,28 @@ static int tegra_serial_ofdata_to_platdata(struct udevice *dev)
return 0;
}
+#else
+struct ns16550_platdata tegra_serial = {
+ .base = CONFIG_SYS_NS16550_COM1,
+ .reg_shift = 2,
+ .clock = V_NS16550_CLK,
+};
+
+U_BOOT_DEVICE(ns16550_serial) = {
+ "serial_tegra20", &tegra_serial
+};
+#endif
+
U_BOOT_DRIVER(serial_ns16550) = {
.name = "serial_tegra20",
.id = UCLASS_SERIAL,
+#ifdef CONFIG_OF_CONTROL
.of_match = tegra_serial_ids,
.ofdata_to_platdata = tegra_serial_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+#endif
.priv_auto_alloc_size = sizeof(struct NS16550),
.probe = ns16550_serial_probe,
.ops = &ns16550_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c
index 9114b3ed60..e8a1608b99 100644
--- a/drivers/serial/serial_uniphier.c
+++ b/drivers/serial/serial_uniphier.c
@@ -5,12 +5,13 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-#include <common.h>
+#include <linux/serial_reg.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <dm/device.h>
#include <dm/platform_data/serial-uniphier.h>
#include <serial.h>
+#include <fdtdec.h>
#define UART_REG(x) \
u8 x; \
@@ -37,17 +38,6 @@ struct uniphier_serial {
#define thr rbr
-/*
- * These are the definitions for the Line Control Register
- */
-#define UART_LCR_WLS_8 0x03 /* 8 bit character length */
-
-/*
- * These are the definitions for the Line Status Register
- */
-#define UART_LSR_DR 0x01 /* Data ready */
-#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
-
struct uniphier_serial_private_data {
struct uniphier_serial __iomem *membase;
};
@@ -55,14 +45,14 @@ struct uniphier_serial_private_data {
#define uniphier_serial_port(dev) \
((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase
-int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
+static int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
{
struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
const unsigned int mode_x_div = 16;
unsigned int divisor;
- writeb(UART_LCR_WLS_8, &port->lcr);
+ writeb(UART_LCR_WLEN8, &port->lcr);
divisor = DIV_ROUND_CLOSEST(plat->uartclk, mode_x_div * baudrate);
@@ -93,7 +83,17 @@ static int uniphier_serial_putc(struct udevice *dev, const char c)
return 0;
}
-int uniphier_serial_probe(struct udevice *dev)
+static int uniphier_serial_pending(struct udevice *dev, bool input)
+{
+ struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
+
+ if (input)
+ return readb(&port->lsr) & UART_LSR_DR;
+ else
+ return !(readb(&port->lsr) & UART_LSR_THRE);
+}
+
+static int uniphier_serial_probe(struct udevice *dev)
{
struct uniphier_serial_private_data *priv = dev_get_priv(dev);
struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
@@ -106,7 +106,7 @@ int uniphier_serial_probe(struct udevice *dev)
return 0;
}
-int uniphier_serial_remove(struct udevice *dev)
+static int uniphier_serial_remove(struct udevice *dev)
{
unmap_sysmem(uniphier_serial_port(dev));
@@ -114,19 +114,21 @@ int uniphier_serial_remove(struct udevice *dev)
}
#ifdef CONFIG_OF_CONTROL
-static const struct udevice_id uniphier_uart_of_match = {
- { .compatible = "panasonic,uniphier-uart"},
+static const struct udevice_id uniphier_uart_of_match[] = {
+ { .compatible = "panasonic,uniphier-uart" },
{},
};
static int uniphier_serial_ofdata_to_platdata(struct udevice *dev)
{
- /*
- * TODO: Masahiro Yamada (yamada.m@jp.panasonic.com)
- *
- * Implement conversion code from DTB to platform data
- * when supporting CONFIG_OF_CONTROL on UniPhir platform.
- */
+ struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
+ DECLARE_GLOBAL_DATA_PTR;
+
+ plat->base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+ plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "clock-frequency", 0);
+
+ return 0;
}
#endif
@@ -134,6 +136,7 @@ static const struct dm_serial_ops uniphier_serial_ops = {
.setbrg = uniphier_serial_setbrg,
.getc = uniphier_serial_getc,
.putc = uniphier_serial_putc,
+ .pending = uniphier_serial_pending,
};
U_BOOT_DRIVER(uniphier_serial) = {
diff --git a/drivers/serial/serial_x86.c b/drivers/serial/serial_x86.c
new file mode 100644
index 0000000000..4bf6062c64
--- /dev/null
+++ b/drivers/serial/serial_x86.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <ns16550.h>
+#include <serial.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id x86_serial_ids[] = {
+ { .compatible = "x86-uart" },
+ { }
+};
+
+static int x86_serial_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ns16550_platdata *plat = dev_get_platdata(dev);
+ int ret;
+
+ ret = ns16550_serial_ofdata_to_platdata(dev);
+ if (ret)
+ return ret;
+
+ plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "clock-frequency", 1843200);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(serial_ns16550) = {
+ .name = "serial_x86",
+ .id = UCLASS_SERIAL,
+ .of_match = x86_serial_ids,
+ .ofdata_to_platdata = x86_serial_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+ .priv_auto_alloc_size = sizeof(struct NS16550),
+ .probe = ns16550_serial_probe,
+ .ops = &ns16550_serial_ops,
+};
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
index 7fb0b92078..75f0ec31bb 100644
--- a/drivers/serial/usbtty.c
+++ b/drivers/serial/usbtty.c
@@ -882,7 +882,7 @@ static int write_buffer (circbuf_t * buf)
space_avail =
current_urb->buffer_length -
current_urb->actual_length;
- popnum = min(space_avail, buf->size);
+ popnum = min(space_avail, (int)buf->size);
if (popnum == 0)
break;
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index eabbf27d4d..edbd520141 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -23,9 +23,11 @@ obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
obj-$(CONFIG_BFIN_SPI) += bfin_spi.o
obj-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
+obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o
obj-$(CONFIG_CF_SPI) += cf_spi.o
obj-$(CONFIG_CF_QSPI) += cf_qspi.o
obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
+obj-$(CONFIG_DESIGNWARE_SPI) += designware_spi.o
obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
obj-$(CONFIG_ICH_SPI) += ich.o
diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c
index 5accbb5c22..a4d03d97cf 100644
--- a/drivers/spi/altera_spi.c
+++ b/drivers/spi/altera_spi.c
@@ -12,58 +12,62 @@
#include <malloc.h>
#include <spi.h>
-#define ALTERA_SPI_RXDATA 0
-#define ALTERA_SPI_TXDATA 4
-#define ALTERA_SPI_STATUS 8
-#define ALTERA_SPI_CONTROL 12
-#define ALTERA_SPI_SLAVE_SEL 20
-
-#define ALTERA_SPI_STATUS_ROE_MSK (0x8)
-#define ALTERA_SPI_STATUS_TOE_MSK (0x10)
-#define ALTERA_SPI_STATUS_TMT_MSK (0x20)
-#define ALTERA_SPI_STATUS_TRDY_MSK (0x40)
-#define ALTERA_SPI_STATUS_RRDY_MSK (0x80)
-#define ALTERA_SPI_STATUS_E_MSK (0x100)
-
-#define ALTERA_SPI_CONTROL_IROE_MSK (0x8)
-#define ALTERA_SPI_CONTROL_ITOE_MSK (0x10)
-#define ALTERA_SPI_CONTROL_ITRDY_MSK (0x40)
-#define ALTERA_SPI_CONTROL_IRRDY_MSK (0x80)
-#define ALTERA_SPI_CONTROL_IE_MSK (0x100)
-#define ALTERA_SPI_CONTROL_SSO_MSK (0x400)
+#ifndef CONFIG_ALTERA_SPI_IDLE_VAL
+#define CONFIG_ALTERA_SPI_IDLE_VAL 0xff
+#endif
#ifndef CONFIG_SYS_ALTERA_SPI_LIST
#define CONFIG_SYS_ALTERA_SPI_LIST { CONFIG_SYS_SPI_BASE }
#endif
+struct altera_spi_regs {
+ u32 rxdata;
+ u32 txdata;
+ u32 status;
+ u32 control;
+ u32 _reserved;
+ u32 slave_sel;
+};
+
+#define ALTERA_SPI_STATUS_ROE_MSK (1 << 3)
+#define ALTERA_SPI_STATUS_TOE_MSK (1 << 4)
+#define ALTERA_SPI_STATUS_TMT_MSK (1 << 5)
+#define ALTERA_SPI_STATUS_TRDY_MSK (1 << 6)
+#define ALTERA_SPI_STATUS_RRDY_MSK (1 << 7)
+#define ALTERA_SPI_STATUS_E_MSK (1 << 8)
+
+#define ALTERA_SPI_CONTROL_IROE_MSK (1 << 3)
+#define ALTERA_SPI_CONTROL_ITOE_MSK (1 << 4)
+#define ALTERA_SPI_CONTROL_ITRDY_MSK (1 << 6)
+#define ALTERA_SPI_CONTROL_IRRDY_MSK (1 << 7)
+#define ALTERA_SPI_CONTROL_IE_MSK (1 << 8)
+#define ALTERA_SPI_CONTROL_SSO_MSK (1 << 10)
+
static ulong altera_spi_base_list[] = CONFIG_SYS_ALTERA_SPI_LIST;
struct altera_spi_slave {
- struct spi_slave slave;
- ulong base;
+ struct spi_slave slave;
+ struct altera_spi_regs *regs;
};
#define to_altera_spi_slave(s) container_of(s, struct altera_spi_slave, slave)
-__attribute__((weak))
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+__weak int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
return bus < ARRAY_SIZE(altera_spi_base_list) && cs < 32;
}
-__attribute__((weak))
-void spi_cs_activate(struct spi_slave *slave)
+__weak void spi_cs_activate(struct spi_slave *slave)
{
struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
- writel(1 << slave->cs, altspi->base + ALTERA_SPI_SLAVE_SEL);
- writel(ALTERA_SPI_CONTROL_SSO_MSK, altspi->base + ALTERA_SPI_CONTROL);
+ writel(1 << slave->cs, &altspi->regs->slave_sel);
+ writel(ALTERA_SPI_CONTROL_SSO_MSK, &altspi->regs->control);
}
-__attribute__((weak))
-void spi_cs_deactivate(struct spi_slave *slave)
+__weak void spi_cs_deactivate(struct spi_slave *slave)
{
struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
- writel(0, altspi->base + ALTERA_SPI_CONTROL);
- writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
+ writel(0, &altspi->regs->control);
+ writel(0, &altspi->regs->slave_sel);
}
void spi_init(void)
@@ -87,9 +91,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (!altspi)
return NULL;
- altspi->base = altera_spi_base_list[bus];
- debug("%s: bus:%i cs:%i base:%lx\n", __func__,
- bus, cs, altspi->base);
+ altspi->regs = (struct altera_spi_regs *)altera_spi_base_list[bus];
+ debug("%s: bus:%i cs:%i base:%p\n", __func__, bus, cs, altspi->regs);
return &altspi->slave;
}
@@ -105,8 +108,8 @@ int spi_claim_bus(struct spi_slave *slave)
struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
- writel(0, altspi->base + ALTERA_SPI_CONTROL);
- writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
+ writel(0, &altspi->regs->control);
+ writel(0, &altspi->regs->slave_sel);
return 0;
}
@@ -115,24 +118,22 @@ void spi_release_bus(struct spi_slave *slave)
struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
- writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
+ writel(0, &altspi->regs->slave_sel);
}
-#ifndef CONFIG_ALTERA_SPI_IDLE_VAL
-# define CONFIG_ALTERA_SPI_IDLE_VAL 0xff
-#endif
-
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
/* assume spi core configured to do 8 bit transfers */
- uint bytes = bitlen / 8;
- const uchar *txp = dout;
- uchar *rxp = din;
+ unsigned int bytes = bitlen / 8;
+ const unsigned char *txp = dout;
+ unsigned char *rxp = din;
+ uint32_t reg, data, start;
debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
- slave->bus, slave->cs, bitlen, bytes, flags);
+ slave->bus, slave->cs, bitlen, bytes, flags);
+
if (bitlen == 0)
goto done;
@@ -142,25 +143,40 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
/* empty read buffer */
- if (readl(altspi->base + ALTERA_SPI_STATUS) &
- ALTERA_SPI_STATUS_RRDY_MSK)
- readl(altspi->base + ALTERA_SPI_RXDATA);
+ if (readl(&altspi->regs->status) & ALTERA_SPI_STATUS_RRDY_MSK)
+ readl(&altspi->regs->rxdata);
+
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(slave);
while (bytes--) {
- uchar d = txp ? *txp++ : CONFIG_ALTERA_SPI_IDLE_VAL;
- debug("%s: tx:%x ", __func__, d);
- writel(d, altspi->base + ALTERA_SPI_TXDATA);
- while (!(readl(altspi->base + ALTERA_SPI_STATUS) &
- ALTERA_SPI_STATUS_RRDY_MSK))
- ;
- d = readl(altspi->base + ALTERA_SPI_RXDATA);
+ if (txp)
+ data = *txp++;
+ else
+ data = CONFIG_ALTERA_SPI_IDLE_VAL;
+
+ debug("%s: tx:%x ", __func__, data);
+ writel(data, &altspi->regs->txdata);
+
+ start = get_timer(0);
+ while (1) {
+ reg = readl(&altspi->regs->status);
+ if (reg & ALTERA_SPI_STATUS_RRDY_MSK)
+ break;
+ if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+ printf("%s: Transmission timed out!\n", __func__);
+ goto done;
+ }
+ }
+
+ data = readl(&altspi->regs->rxdata);
if (rxp)
- *rxp++ = d;
- debug("rx:%x\n", d);
+ *rxp++ = data & 0xff;
+
+ debug("rx:%x\n", data);
}
- done:
+
+done:
if (flags & SPI_XFER_END)
spi_cs_deactivate(slave);
diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h
index d2409454f9..1538a235a5 100644
--- a/drivers/spi/atmel_spi.h
+++ b/drivers/spi/atmel_spi.h
@@ -94,3 +94,7 @@ static inline struct atmel_spi_slave *to_atmel_spi(struct spi_slave *slave)
readl(as->regs + ATMEL_SPI_##reg)
#define spi_writel(as, reg, value) \
writel(value, as->regs + ATMEL_SPI_##reg)
+
+#if !defined(CONFIG_SYS_SPI_WRITE_TOUT)
+#define CONFIG_SYS_SPI_WRITE_TOUT (5 * CONFIG_SYS_HZ)
+#endif
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
new file mode 100644
index 0000000000..98ae3b808f
--- /dev/null
+++ b/drivers/spi/cadence_qspi.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2012
+ * Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/errno.h>
+#include "cadence_qspi.h"
+
+#define CQSPI_STIG_READ 0
+#define CQSPI_STIG_WRITE 1
+#define CQSPI_INDIRECT_READ 2
+#define CQSPI_INDIRECT_WRITE 3
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int cadence_spi_write_speed(struct udevice *bus, uint hz)
+{
+ struct cadence_spi_platdata *plat = bus->platdata;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+
+ cadence_qspi_apb_config_baudrate_div(priv->regbase,
+ CONFIG_CQSPI_REF_CLK, hz);
+
+ /* Reconfigure delay timing if speed is changed. */
+ cadence_qspi_apb_delay(priv->regbase, CONFIG_CQSPI_REF_CLK, hz,
+ plat->tshsl_ns, plat->tsd2d_ns,
+ plat->tchsh_ns, plat->tslch_ns);
+
+ return 0;
+}
+
+/* Calibration sequence to determine the read data capture delay register */
+static int spi_calibration(struct udevice *bus)
+{
+ struct cadence_spi_platdata *plat = bus->platdata;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ void *base = priv->regbase;
+ u8 opcode_rdid = 0x9F;
+ unsigned int idcode = 0, temp = 0;
+ int err = 0, i, range_lo = -1, range_hi = -1;
+
+ /* start with slowest clock (1 MHz) */
+ cadence_spi_write_speed(bus, 1000000);
+
+ /* configure the read data capture delay register to 0 */
+ cadence_qspi_apb_readdata_capture(base, 1, 0);
+
+ /* Enable QSPI */
+ cadence_qspi_apb_controller_enable(base);
+
+ /* read the ID which will be our golden value */
+ err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
+ 3, (u8 *)&idcode);
+ if (err) {
+ puts("SF: Calibration failed (read)\n");
+ return err;
+ }
+
+ /* use back the intended clock and find low range */
+ cadence_spi_write_speed(bus, plat->max_hz);
+ for (i = 0; i < CQSPI_READ_CAPTURE_MAX_DELAY; i++) {
+ /* Disable QSPI */
+ cadence_qspi_apb_controller_disable(base);
+
+ /* reconfigure the read data capture delay register */
+ cadence_qspi_apb_readdata_capture(base, 1, i);
+
+ /* Enable back QSPI */
+ cadence_qspi_apb_controller_enable(base);
+
+ /* issue a RDID to get the ID value */
+ err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
+ 3, (u8 *)&temp);
+ if (err) {
+ puts("SF: Calibration failed (read)\n");
+ return err;
+ }
+
+ /* search for range lo */
+ if (range_lo == -1 && temp == idcode) {
+ range_lo = i;
+ continue;
+ }
+
+ /* search for range hi */
+ if (range_lo != -1 && temp != idcode) {
+ range_hi = i - 1;
+ break;
+ }
+ range_hi = i;
+ }
+
+ if (range_lo == -1) {
+ puts("SF: Calibration failed (low range)\n");
+ return err;
+ }
+
+ /* Disable QSPI for subsequent initialization */
+ cadence_qspi_apb_controller_disable(base);
+
+ /* configure the final value for read data capture delay register */
+ cadence_qspi_apb_readdata_capture(base, 1, (range_hi + range_lo) / 2);
+ debug("SF: Read data capture delay calibrated to %i (%i - %i)\n",
+ (range_hi + range_lo) / 2, range_lo, range_hi);
+
+ /* just to ensure we do once only when speed or chip select change */
+ priv->qspi_calibrated_hz = plat->max_hz;
+ priv->qspi_calibrated_cs = spi_chip_select(bus);
+
+ return 0;
+}
+
+static int cadence_spi_set_speed(struct udevice *bus, uint hz)
+{
+ struct cadence_spi_platdata *plat = bus->platdata;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ int err;
+
+ /* Disable QSPI */
+ cadence_qspi_apb_controller_disable(priv->regbase);
+
+ cadence_spi_write_speed(bus, hz);
+
+ /* Calibration required for different SCLK speed or chip select */
+ if (priv->qspi_calibrated_hz != plat->max_hz ||
+ priv->qspi_calibrated_cs != spi_chip_select(bus)) {
+ err = spi_calibration(bus);
+ if (err)
+ return err;
+ }
+
+ /* Enable QSPI */
+ cadence_qspi_apb_controller_enable(priv->regbase);
+
+ debug("%s: speed=%d\n", __func__, hz);
+
+ return 0;
+}
+
+static int cadence_spi_probe(struct udevice *bus)
+{
+ struct cadence_spi_platdata *plat = bus->platdata;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+
+ priv->regbase = plat->regbase;
+ priv->ahbbase = plat->ahbbase;
+
+ if (!priv->qspi_is_init) {
+ cadence_qspi_apb_controller_init(plat);
+ priv->qspi_is_init = 1;
+ }
+
+ return 0;
+}
+
+static int cadence_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ unsigned int clk_pol = (mode & SPI_CPOL) ? 1 : 0;
+ unsigned int clk_pha = (mode & SPI_CPHA) ? 1 : 0;
+
+ /* Disable QSPI */
+ cadence_qspi_apb_controller_disable(priv->regbase);
+
+ /* Set SPI mode */
+ cadence_qspi_apb_set_clk_mode(priv->regbase, clk_pol, clk_pha);
+
+ /* Enable QSPI */
+ cadence_qspi_apb_controller_enable(priv->regbase);
+
+ return 0;
+}
+
+static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev->parent;
+ struct cadence_spi_platdata *plat = bus->platdata;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ void *base = priv->regbase;
+ u8 *cmd_buf = priv->cmd_buf;
+ size_t data_bytes;
+ int err = 0;
+ u32 mode = CQSPI_STIG_WRITE;
+
+ if (flags & SPI_XFER_BEGIN) {
+ /* copy command to local buffer */
+ priv->cmd_len = bitlen / 8;
+ memcpy(cmd_buf, dout, priv->cmd_len);
+ }
+
+ if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
+ /* if start and end bit are set, the data bytes is 0. */
+ data_bytes = 0;
+ } else {
+ data_bytes = bitlen / 8;
+ }
+ debug("%s: len=%d [bytes]\n", __func__, data_bytes);
+
+ /* Set Chip select */
+ cadence_qspi_apb_chipselect(base, spi_chip_select(dev),
+ CONFIG_CQSPI_DECODER);
+
+ if ((flags & SPI_XFER_END) || (flags == 0)) {
+ if (priv->cmd_len == 0) {
+ printf("QSPI: Error, command is empty.\n");
+ return -1;
+ }
+
+ if (din && data_bytes) {
+ /* read */
+ /* Use STIG if no address. */
+ if (!CQSPI_IS_ADDR(priv->cmd_len))
+ mode = CQSPI_STIG_READ;
+ else
+ mode = CQSPI_INDIRECT_READ;
+ } else if (dout && !(flags & SPI_XFER_BEGIN)) {
+ /* write */
+ if (!CQSPI_IS_ADDR(priv->cmd_len))
+ mode = CQSPI_STIG_WRITE;
+ else
+ mode = CQSPI_INDIRECT_WRITE;
+ }
+
+ switch (mode) {
+ case CQSPI_STIG_READ:
+ err = cadence_qspi_apb_command_read(
+ base, priv->cmd_len, cmd_buf,
+ data_bytes, din);
+
+ break;
+ case CQSPI_STIG_WRITE:
+ err = cadence_qspi_apb_command_write(base,
+ priv->cmd_len, cmd_buf,
+ data_bytes, dout);
+ break;
+ case CQSPI_INDIRECT_READ:
+ err = cadence_qspi_apb_indirect_read_setup(plat,
+ priv->cmd_len, cmd_buf);
+ if (!err) {
+ err = cadence_qspi_apb_indirect_read_execute
+ (plat, data_bytes, din);
+ }
+ break;
+ case CQSPI_INDIRECT_WRITE:
+ err = cadence_qspi_apb_indirect_write_setup
+ (plat, priv->cmd_len, cmd_buf);
+ if (!err) {
+ err = cadence_qspi_apb_indirect_write_execute
+ (plat, data_bytes, dout);
+ }
+ break;
+ default:
+ err = -1;
+ break;
+ }
+
+ if (flags & SPI_XFER_END) {
+ /* clear command buffer */
+ memset(cmd_buf, 0, sizeof(priv->cmd_buf));
+ priv->cmd_len = 0;
+ }
+ }
+
+ return err;
+}
+
+static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct cadence_spi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
+ int subnode;
+ u32 data[4];
+ int ret;
+
+ /* 2 base addresses are needed, lets get them from the DT */
+ ret = fdtdec_get_int_array(blob, node, "reg", data, ARRAY_SIZE(data));
+ if (ret) {
+ printf("Error: Can't get base addresses (ret=%d)!\n", ret);
+ return -ENODEV;
+ }
+
+ plat->regbase = (void *)data[0];
+ plat->ahbbase = (void *)data[2];
+
+ /* Use 500KHz as a suitable default */
+ plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
+ 500000);
+
+ /* All other paramters are embedded in the child node */
+ subnode = fdt_first_subnode(blob, node);
+ if (subnode < 0) {
+ printf("Error: subnode with SPI flash config missing!\n");
+ return -ENODEV;
+ }
+
+ /* Read other parameters from DT */
+ plat->page_size = fdtdec_get_int(blob, subnode, "page-size", 256);
+ plat->block_size = fdtdec_get_int(blob, subnode, "block-size", 16);
+ plat->tshsl_ns = fdtdec_get_int(blob, subnode, "tshsl-ns", 200);
+ plat->tsd2d_ns = fdtdec_get_int(blob, subnode, "tsd2d-ns", 255);
+ plat->tchsh_ns = fdtdec_get_int(blob, subnode, "tchsh-ns", 20);
+ plat->tslch_ns = fdtdec_get_int(blob, subnode, "tslch-ns", 20);
+
+ debug("%s: regbase=%p ahbbase=%p max-frequency=%d page-size=%d\n",
+ __func__, plat->regbase, plat->ahbbase, plat->max_hz,
+ plat->page_size);
+
+ return 0;
+}
+
+static const struct dm_spi_ops cadence_spi_ops = {
+ .xfer = cadence_spi_xfer,
+ .set_speed = cadence_spi_set_speed,
+ .set_mode = cadence_spi_set_mode,
+ /*
+ * cs_info is not needed, since we require all chip selects to be
+ * in the device tree explicitly
+ */
+};
+
+static const struct udevice_id cadence_spi_ids[] = {
+ { .compatible = "cadence,qspi" },
+ { }
+};
+
+U_BOOT_DRIVER(cadence_spi) = {
+ .name = "cadence_spi",
+ .id = UCLASS_SPI,
+ .of_match = cadence_spi_ids,
+ .ops = &cadence_spi_ops,
+ .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/cadence_qspi.h b/drivers/spi/cadence_qspi.h
new file mode 100644
index 0000000000..c9a6142e82
--- /dev/null
+++ b/drivers/spi/cadence_qspi.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012
+ * Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CADENCE_QSPI_H__
+#define __CADENCE_QSPI_H__
+
+#define CQSPI_IS_ADDR(cmd_len) (cmd_len > 1 ? 1 : 0)
+
+#define CQSPI_NO_DECODER_MAX_CS 4
+#define CQSPI_DECODER_MAX_CS 16
+#define CQSPI_READ_CAPTURE_MAX_DELAY 16
+
+struct cadence_spi_platdata {
+ unsigned int max_hz;
+ void *regbase;
+ void *ahbbase;
+
+ u32 page_size;
+ u32 block_size;
+ u32 tshsl_ns;
+ u32 tsd2d_ns;
+ u32 tchsh_ns;
+ u32 tslch_ns;
+};
+
+struct cadence_spi_priv {
+ void *regbase;
+ void *ahbbase;
+ size_t cmd_len;
+ u8 cmd_buf[32];
+ size_t data_len;
+
+ int qspi_is_init;
+ unsigned int qspi_calibrated_hz;
+ unsigned int qspi_calibrated_cs;
+};
+
+/* Functions call declaration */
+void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat);
+void cadence_qspi_apb_controller_enable(void *reg_base_addr);
+void cadence_qspi_apb_controller_disable(void *reg_base_addr);
+
+int cadence_qspi_apb_command_read(void *reg_base_addr,
+ unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen, u8 *rxbuf);
+int cadence_qspi_apb_command_write(void *reg_base_addr,
+ unsigned int cmdlen, const u8 *cmdbuf,
+ unsigned int txlen, const u8 *txbuf);
+
+int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
+ unsigned int cmdlen, const u8 *cmdbuf);
+int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
+ unsigned int rxlen, u8 *rxbuf);
+int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
+ unsigned int cmdlen, const u8 *cmdbuf);
+int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
+ unsigned int txlen, const u8 *txbuf);
+
+void cadence_qspi_apb_chipselect(void *reg_base,
+ unsigned int chip_select, unsigned int decoder_enable);
+void cadence_qspi_apb_set_clk_mode(void *reg_base_addr,
+ unsigned int clk_pol, unsigned int clk_pha);
+void cadence_qspi_apb_config_baudrate_div(void *reg_base,
+ unsigned int ref_clk_hz, unsigned int sclk_hz);
+void cadence_qspi_apb_delay(void *reg_base,
+ unsigned int ref_clk, unsigned int sclk_hz,
+ unsigned int tshsl_ns, unsigned int tsd2d_ns,
+ unsigned int tchsh_ns, unsigned int tslch_ns);
+void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy);
+void cadence_qspi_apb_readdata_capture(void *reg_base,
+ unsigned int bypass, unsigned int delay);
+
+#endif /* __CADENCE_QSPI_H__ */
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
new file mode 100644
index 0000000000..00a115f3fb
--- /dev/null
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -0,0 +1,898 @@
+/*
+ * Copyright (C) 2012 Altera Corporation <www.altera.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of the Altera Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL ALTERA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include "cadence_qspi.h"
+
+#define CQSPI_REG_POLL_US (1) /* 1us */
+#define CQSPI_REG_RETRY (10000)
+#define CQSPI_POLL_IDLE_RETRY (3)
+
+#define CQSPI_FIFO_WIDTH (4)
+
+/* Controller sram size in word */
+#define CQSPI_REG_SRAM_SIZE_WORD (128)
+#define CQSPI_REG_SRAM_RESV_WORDS (2)
+#define CQSPI_REG_SRAM_PARTITION_WR (1)
+#define CQSPI_REG_SRAM_PARTITION_RD \
+ (CQSPI_REG_SRAM_SIZE_WORD - CQSPI_REG_SRAM_RESV_WORDS)
+#define CQSPI_REG_SRAM_THRESHOLD_WORDS (50)
+
+/* Transfer mode */
+#define CQSPI_INST_TYPE_SINGLE (0)
+#define CQSPI_INST_TYPE_DUAL (1)
+#define CQSPI_INST_TYPE_QUAD (2)
+
+#define CQSPI_STIG_DATA_LEN_MAX (8)
+#define CQSPI_INDIRECTTRIGGER_ADDR_MASK (0xFFFFF)
+
+#define CQSPI_DUMMY_CLKS_PER_BYTE (8)
+#define CQSPI_DUMMY_BYTES_MAX (4)
+
+
+#define CQSPI_REG_SRAM_FILL_THRESHOLD \
+ ((CQSPI_REG_SRAM_SIZE_WORD / 2) * CQSPI_FIFO_WIDTH)
+/****************************************************************************
+ * Controller's configuration and status register (offset from QSPI_BASE)
+ ****************************************************************************/
+#define CQSPI_REG_CONFIG 0x00
+#define CQSPI_REG_CONFIG_CLK_POL_LSB 1
+#define CQSPI_REG_CONFIG_CLK_PHA_LSB 2
+#define CQSPI_REG_CONFIG_ENABLE_MASK (1 << 0)
+#define CQSPI_REG_CONFIG_DIRECT_MASK (1 << 7)
+#define CQSPI_REG_CONFIG_DECODE_MASK (1 << 9)
+#define CQSPI_REG_CONFIG_XIP_IMM_MASK (1 << 18)
+#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
+#define CQSPI_REG_CONFIG_BAUD_LSB 19
+#define CQSPI_REG_CONFIG_IDLE_LSB 31
+#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
+#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
+
+#define CQSPI_REG_RD_INSTR 0x04
+#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16
+#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20
+#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
+#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
+
+#define CQSPI_REG_WR_INSTR 0x08
+#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
+
+#define CQSPI_REG_DELAY 0x0C
+#define CQSPI_REG_DELAY_TSLCH_LSB 0
+#define CQSPI_REG_DELAY_TCHSH_LSB 8
+#define CQSPI_REG_DELAY_TSD2D_LSB 16
+#define CQSPI_REG_DELAY_TSHSL_LSB 24
+#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF
+#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF
+#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF
+#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF
+
+#define CQSPI_READLCAPTURE 0x10
+#define CQSPI_READLCAPTURE_BYPASS_LSB 0
+#define CQSPI_READLCAPTURE_DELAY_LSB 1
+#define CQSPI_READLCAPTURE_DELAY_MASK 0xF
+
+#define CQSPI_REG_SIZE 0x14
+#define CQSPI_REG_SIZE_ADDRESS_LSB 0
+#define CQSPI_REG_SIZE_PAGE_LSB 4
+#define CQSPI_REG_SIZE_BLOCK_LSB 16
+#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF
+#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF
+#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F
+
+#define CQSPI_REG_SRAMPARTITION 0x18
+#define CQSPI_REG_INDIRECTTRIGGER 0x1C
+
+#define CQSPI_REG_REMAP 0x24
+#define CQSPI_REG_MODE_BIT 0x28
+
+#define CQSPI_REG_SDRAMLEVEL 0x2C
+#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0
+#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16
+#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF
+#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF
+
+#define CQSPI_REG_IRQSTATUS 0x40
+#define CQSPI_REG_IRQMASK 0x44
+
+#define CQSPI_REG_INDIRECTRD 0x60
+#define CQSPI_REG_INDIRECTRD_START_MASK (1 << 0)
+#define CQSPI_REG_INDIRECTRD_CANCEL_MASK (1 << 1)
+#define CQSPI_REG_INDIRECTRD_INPROGRESS_MASK (1 << 2)
+#define CQSPI_REG_INDIRECTRD_DONE_MASK (1 << 5)
+
+#define CQSPI_REG_INDIRECTRDWATERMARK 0x64
+#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68
+#define CQSPI_REG_INDIRECTRDBYTES 0x6C
+
+#define CQSPI_REG_CMDCTRL 0x90
+#define CQSPI_REG_CMDCTRL_EXECUTE_MASK (1 << 0)
+#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK (1 << 1)
+#define CQSPI_REG_CMDCTRL_DUMMY_LSB 7
+#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
+#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
+#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19
+#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20
+#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23
+#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24
+#define CQSPI_REG_CMDCTRL_DUMMY_MASK 0x1F
+#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
+#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
+#define CQSPI_REG_CMDCTRL_OPCODE_MASK 0xFF
+
+#define CQSPI_REG_INDIRECTWR 0x70
+#define CQSPI_REG_INDIRECTWR_START_MASK (1 << 0)
+#define CQSPI_REG_INDIRECTWR_CANCEL_MASK (1 << 1)
+#define CQSPI_REG_INDIRECTWR_INPROGRESS_MASK (1 << 2)
+#define CQSPI_REG_INDIRECTWR_DONE_MASK (1 << 5)
+
+#define CQSPI_REG_INDIRECTWRWATERMARK 0x74
+#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
+#define CQSPI_REG_INDIRECTWRBYTES 0x7C
+
+#define CQSPI_REG_CMDADDRESS 0x94
+#define CQSPI_REG_CMDREADDATALOWER 0xA0
+#define CQSPI_REG_CMDREADDATAUPPER 0xA4
+#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
+#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
+
+#define CQSPI_REG_IS_IDLE(base) \
+ ((readl(base + CQSPI_REG_CONFIG) >> \
+ CQSPI_REG_CONFIG_IDLE_LSB) & 0x1)
+
+#define CQSPI_CAL_DELAY(tdelay_ns, tref_ns, tsclk_ns) \
+ ((((tdelay_ns) - (tsclk_ns)) / (tref_ns)))
+
+#define CQSPI_GET_RD_SRAM_LEVEL(reg_base) \
+ (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >> \
+ CQSPI_REG_SDRAMLEVEL_RD_LSB) & CQSPI_REG_SDRAMLEVEL_RD_MASK)
+
+#define CQSPI_GET_WR_SRAM_LEVEL(reg_base) \
+ (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >> \
+ CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK)
+
+static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf,
+ unsigned int addr_width)
+{
+ unsigned int addr;
+
+ addr = (addr_buf[0] << 16) | (addr_buf[1] << 8) | addr_buf[2];
+
+ if (addr_width == 4)
+ addr = (addr << 8) | addr_buf[3];
+
+ return addr;
+}
+
+static void cadence_qspi_apb_read_fifo_data(void *dest,
+ const void *src_ahb_addr, unsigned int bytes)
+{
+ unsigned int temp;
+ int remaining = bytes;
+ unsigned int *dest_ptr = (unsigned int *)dest;
+ unsigned int *src_ptr = (unsigned int *)src_ahb_addr;
+
+ while (remaining > 0) {
+ if (remaining >= CQSPI_FIFO_WIDTH) {
+ *dest_ptr = readl(src_ptr);
+ remaining -= CQSPI_FIFO_WIDTH;
+ } else {
+ /* dangling bytes */
+ temp = readl(src_ptr);
+ memcpy(dest_ptr, &temp, remaining);
+ break;
+ }
+ dest_ptr++;
+ }
+
+ return;
+}
+
+static void cadence_qspi_apb_write_fifo_data(const void *dest_ahb_addr,
+ const void *src, unsigned int bytes)
+{
+ unsigned int temp;
+ int remaining = bytes;
+ unsigned int *dest_ptr = (unsigned int *)dest_ahb_addr;
+ unsigned int *src_ptr = (unsigned int *)src;
+
+ while (remaining > 0) {
+ if (remaining >= CQSPI_FIFO_WIDTH) {
+ writel(*src_ptr, dest_ptr);
+ remaining -= sizeof(unsigned int);
+ } else {
+ /* dangling bytes */
+ memcpy(&temp, src_ptr, remaining);
+ writel(temp, dest_ptr);
+ break;
+ }
+ src_ptr++;
+ }
+
+ return;
+}
+
+/* Read from SRAM FIFO with polling SRAM fill level. */
+static int qspi_read_sram_fifo_poll(const void *reg_base, void *dest_addr,
+ const void *src_addr, unsigned int num_bytes)
+{
+ unsigned int remaining = num_bytes;
+ unsigned int retry;
+ unsigned int sram_level = 0;
+ unsigned char *dest = (unsigned char *)dest_addr;
+
+ while (remaining > 0) {
+ retry = CQSPI_REG_RETRY;
+ while (retry--) {
+ sram_level = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
+ if (sram_level)
+ break;
+ udelay(1);
+ }
+
+ if (!retry) {
+ printf("QSPI: No receive data after polling for %d times\n",
+ CQSPI_REG_RETRY);
+ return -1;
+ }
+
+ sram_level *= CQSPI_FIFO_WIDTH;
+ sram_level = sram_level > remaining ? remaining : sram_level;
+
+ /* Read data from FIFO. */
+ cadence_qspi_apb_read_fifo_data(dest, src_addr, sram_level);
+ dest += sram_level;
+ remaining -= sram_level;
+ udelay(1);
+ }
+ return 0;
+}
+
+/* Write to SRAM FIFO with polling SRAM fill level. */
+static int qpsi_write_sram_fifo_push(struct cadence_spi_platdata *plat,
+ const void *src_addr, unsigned int num_bytes)
+{
+ const void *reg_base = plat->regbase;
+ void *dest_addr = plat->ahbbase;
+ unsigned int retry = CQSPI_REG_RETRY;
+ unsigned int sram_level;
+ unsigned int wr_bytes;
+ unsigned char *src = (unsigned char *)src_addr;
+ int remaining = num_bytes;
+ unsigned int page_size = plat->page_size;
+ unsigned int sram_threshold_words = CQSPI_REG_SRAM_THRESHOLD_WORDS;
+
+ while (remaining > 0) {
+ retry = CQSPI_REG_RETRY;
+ while (retry--) {
+ sram_level = CQSPI_GET_WR_SRAM_LEVEL(reg_base);
+ if (sram_level <= sram_threshold_words)
+ break;
+ }
+ if (!retry) {
+ printf("QSPI: SRAM fill level (0x%08x) not hit lower expected level (0x%08x)",
+ sram_level, sram_threshold_words);
+ return -1;
+ }
+ /* Write a page or remaining bytes. */
+ wr_bytes = (remaining > page_size) ?
+ page_size : remaining;
+
+ cadence_qspi_apb_write_fifo_data(dest_addr, src, wr_bytes);
+ src += wr_bytes;
+ remaining -= wr_bytes;
+ }
+
+ return 0;
+}
+
+void cadence_qspi_apb_controller_enable(void *reg_base)
+{
+ unsigned int reg;
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+ return;
+}
+
+void cadence_qspi_apb_controller_disable(void *reg_base)
+{
+ unsigned int reg;
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+ return;
+}
+
+/* Return 1 if idle, otherwise return 0 (busy). */
+static unsigned int cadence_qspi_wait_idle(void *reg_base)
+{
+ unsigned int start, count = 0;
+ /* timeout in unit of ms */
+ unsigned int timeout = 5000;
+
+ start = get_timer(0);
+ for ( ; get_timer(start) < timeout ; ) {
+ if (CQSPI_REG_IS_IDLE(reg_base))
+ count++;
+ else
+ count = 0;
+ /*
+ * Ensure the QSPI controller is in true idle state after
+ * reading back the same idle status consecutively
+ */
+ if (count >= CQSPI_POLL_IDLE_RETRY)
+ return 1;
+ }
+
+ /* Timeout, still in busy mode. */
+ printf("QSPI: QSPI is still busy after poll for %d times.\n",
+ CQSPI_REG_RETRY);
+ return 0;
+}
+
+void cadence_qspi_apb_readdata_capture(void *reg_base,
+ unsigned int bypass, unsigned int delay)
+{
+ unsigned int reg;
+ cadence_qspi_apb_controller_disable(reg_base);
+
+ reg = readl(reg_base + CQSPI_READLCAPTURE);
+
+ if (bypass)
+ reg |= (1 << CQSPI_READLCAPTURE_BYPASS_LSB);
+ else
+ reg &= ~(1 << CQSPI_READLCAPTURE_BYPASS_LSB);
+
+ reg &= ~(CQSPI_READLCAPTURE_DELAY_MASK
+ << CQSPI_READLCAPTURE_DELAY_LSB);
+
+ reg |= ((delay & CQSPI_READLCAPTURE_DELAY_MASK)
+ << CQSPI_READLCAPTURE_DELAY_LSB);
+
+ writel(reg, reg_base + CQSPI_READLCAPTURE);
+
+ cadence_qspi_apb_controller_enable(reg_base);
+ return;
+}
+
+void cadence_qspi_apb_config_baudrate_div(void *reg_base,
+ unsigned int ref_clk_hz, unsigned int sclk_hz)
+{
+ unsigned int reg;
+ unsigned int div;
+
+ cadence_qspi_apb_controller_disable(reg_base);
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
+
+ div = ref_clk_hz / sclk_hz;
+
+ if (div > 32)
+ div = 32;
+
+ /* Check if even number. */
+ if ((div & 1)) {
+ div = (div / 2);
+ } else {
+ if (ref_clk_hz % sclk_hz)
+ /* ensure generated SCLK doesn't exceed user
+ specified sclk_hz */
+ div = (div / 2);
+ else
+ div = (div / 2) - 1;
+ }
+
+ debug("%s: ref_clk %dHz sclk %dHz Div 0x%x\n", __func__,
+ ref_clk_hz, sclk_hz, div);
+
+ div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
+ reg |= div;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+
+ cadence_qspi_apb_controller_enable(reg_base);
+ return;
+}
+
+void cadence_qspi_apb_set_clk_mode(void *reg_base,
+ unsigned int clk_pol, unsigned int clk_pha)
+{
+ unsigned int reg;
+
+ cadence_qspi_apb_controller_disable(reg_base);
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg &= ~(1 <<
+ (CQSPI_REG_CONFIG_CLK_POL_LSB | CQSPI_REG_CONFIG_CLK_PHA_LSB));
+
+ reg |= ((clk_pol & 0x1) << CQSPI_REG_CONFIG_CLK_POL_LSB);
+ reg |= ((clk_pha & 0x1) << CQSPI_REG_CONFIG_CLK_PHA_LSB);
+
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+
+ cadence_qspi_apb_controller_enable(reg_base);
+ return;
+}
+
+void cadence_qspi_apb_chipselect(void *reg_base,
+ unsigned int chip_select, unsigned int decoder_enable)
+{
+ unsigned int reg;
+
+ cadence_qspi_apb_controller_disable(reg_base);
+
+ debug("%s : chipselect %d decode %d\n", __func__, chip_select,
+ decoder_enable);
+
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ /* docoder */
+ if (decoder_enable) {
+ reg |= CQSPI_REG_CONFIG_DECODE_MASK;
+ } else {
+ reg &= ~CQSPI_REG_CONFIG_DECODE_MASK;
+ /* Convert CS if without decoder.
+ * CS0 to 4b'1110
+ * CS1 to 4b'1101
+ * CS2 to 4b'1011
+ * CS3 to 4b'0111
+ */
+ chip_select = 0xF & ~(1 << chip_select);
+ }
+
+ reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
+ << CQSPI_REG_CONFIG_CHIPSELECT_LSB);
+ reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK)
+ << CQSPI_REG_CONFIG_CHIPSELECT_LSB;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+
+ cadence_qspi_apb_controller_enable(reg_base);
+ return;
+}
+
+void cadence_qspi_apb_delay(void *reg_base,
+ unsigned int ref_clk, unsigned int sclk_hz,
+ unsigned int tshsl_ns, unsigned int tsd2d_ns,
+ unsigned int tchsh_ns, unsigned int tslch_ns)
+{
+ unsigned int ref_clk_ns;
+ unsigned int sclk_ns;
+ unsigned int tshsl, tchsh, tslch, tsd2d;
+ unsigned int reg;
+
+ cadence_qspi_apb_controller_disable(reg_base);
+
+ /* Convert to ns. */
+ ref_clk_ns = (1000000000) / ref_clk;
+
+ /* Convert to ns. */
+ sclk_ns = (1000000000) / sclk_hz;
+
+ /* Plus 1 to round up 1 clock cycle. */
+ tshsl = CQSPI_CAL_DELAY(tshsl_ns, ref_clk_ns, sclk_ns) + 1;
+ tchsh = CQSPI_CAL_DELAY(tchsh_ns, ref_clk_ns, sclk_ns) + 1;
+ tslch = CQSPI_CAL_DELAY(tslch_ns, ref_clk_ns, sclk_ns) + 1;
+ tsd2d = CQSPI_CAL_DELAY(tsd2d_ns, ref_clk_ns, sclk_ns) + 1;
+
+ reg = ((tshsl & CQSPI_REG_DELAY_TSHSL_MASK)
+ << CQSPI_REG_DELAY_TSHSL_LSB);
+ reg |= ((tchsh & CQSPI_REG_DELAY_TCHSH_MASK)
+ << CQSPI_REG_DELAY_TCHSH_LSB);
+ reg |= ((tslch & CQSPI_REG_DELAY_TSLCH_MASK)
+ << CQSPI_REG_DELAY_TSLCH_LSB);
+ reg |= ((tsd2d & CQSPI_REG_DELAY_TSD2D_MASK)
+ << CQSPI_REG_DELAY_TSD2D_LSB);
+ writel(reg, reg_base + CQSPI_REG_DELAY);
+
+ cadence_qspi_apb_controller_enable(reg_base);
+ return;
+}
+
+void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat)
+{
+ unsigned reg;
+
+ cadence_qspi_apb_controller_disable(plat->regbase);
+
+ /* Configure the device size and address bytes */
+ reg = readl(plat->regbase + CQSPI_REG_SIZE);
+ /* Clear the previous value */
+ reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
+ reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
+ reg |= (plat->page_size << CQSPI_REG_SIZE_PAGE_LSB);
+ reg |= (plat->block_size << CQSPI_REG_SIZE_BLOCK_LSB);
+ writel(reg, plat->regbase + CQSPI_REG_SIZE);
+
+ /* Configure the remap address register, no remap */
+ writel(0, plat->regbase + CQSPI_REG_REMAP);
+
+ /* Disable all interrupts */
+ writel(0, plat->regbase + CQSPI_REG_IRQMASK);
+
+ cadence_qspi_apb_controller_enable(plat->regbase);
+ return;
+}
+
+static int cadence_qspi_apb_exec_flash_cmd(void *reg_base,
+ unsigned int reg)
+{
+ unsigned int retry = CQSPI_REG_RETRY;
+
+ /* Write the CMDCTRL without start execution. */
+ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
+ /* Start execute */
+ reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK;
+ writel(reg, reg_base + CQSPI_REG_CMDCTRL);
+
+ while (retry--) {
+ reg = readl(reg_base + CQSPI_REG_CMDCTRL);
+ if ((reg & CQSPI_REG_CMDCTRL_INPROGRESS_MASK) == 0)
+ break;
+ udelay(1);
+ }
+
+ if (!retry) {
+ printf("QSPI: flash command execution timeout\n");
+ return -EIO;
+ }
+
+ /* Polling QSPI idle status. */
+ if (!cadence_qspi_wait_idle(reg_base))
+ return -EIO;
+
+ return 0;
+}
+
+/* For command RDID, RDSR. */
+int cadence_qspi_apb_command_read(void *reg_base,
+ unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen,
+ u8 *rxbuf)
+{
+ unsigned int reg;
+ unsigned int read_len;
+ int status;
+
+ if (!cmdlen || rxlen > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) {
+ printf("QSPI: Invalid input arguments cmdlen %d rxlen %d\n",
+ cmdlen, rxlen);
+ return -EINVAL;
+ }
+
+ reg = cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
+
+ /* 0 means 1 byte. */
+ reg |= (((rxlen - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
+ << CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
+ status = cadence_qspi_apb_exec_flash_cmd(reg_base, reg);
+ if (status != 0)
+ return status;
+
+ reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER);
+
+ /* Put the read value into rx_buf */
+ read_len = (rxlen > 4) ? 4 : rxlen;
+ memcpy(rxbuf, &reg, read_len);
+ rxbuf += read_len;
+
+ if (rxlen > 4) {
+ reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
+
+ read_len = rxlen - read_len;
+ memcpy(rxbuf, &reg, read_len);
+ }
+ return 0;
+}
+
+/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
+int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
+ const u8 *cmdbuf, unsigned int txlen, const u8 *txbuf)
+{
+ unsigned int reg = 0;
+ unsigned int addr_value;
+ unsigned int wr_data;
+ unsigned int wr_len;
+
+ if (!cmdlen || cmdlen > 5 || txlen > 8 || cmdbuf == NULL) {
+ printf("QSPI: Invalid input arguments cmdlen %d txlen %d\n",
+ cmdlen, txlen);
+ return -EINVAL;
+ }
+
+ reg |= cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+
+ if (cmdlen == 4 || cmdlen == 5) {
+ /* Command with address */
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+ /* Number of bytes to write. */
+ reg |= ((cmdlen - 2) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
+ << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
+ /* Get address */
+ addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1],
+ cmdlen >= 5 ? 4 : 3);
+
+ writel(addr_value, reg_base + CQSPI_REG_CMDADDRESS);
+ }
+
+ if (txlen) {
+ /* writing data = yes */
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
+ reg |= ((txlen - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
+ << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
+
+ wr_len = txlen > 4 ? 4 : txlen;
+ memcpy(&wr_data, txbuf, wr_len);
+ writel(wr_data, reg_base +
+ CQSPI_REG_CMDWRITEDATALOWER);
+
+ if (txlen > 4) {
+ txbuf += wr_len;
+ wr_len = txlen - wr_len;
+ memcpy(&wr_data, txbuf, wr_len);
+ writel(wr_data, reg_base +
+ CQSPI_REG_CMDWRITEDATAUPPER);
+ }
+ }
+
+ /* Execute the command */
+ return cadence_qspi_apb_exec_flash_cmd(reg_base, reg);
+}
+
+/* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
+int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
+ unsigned int cmdlen, const u8 *cmdbuf)
+{
+ unsigned int reg;
+ unsigned int rd_reg;
+ unsigned int addr_value;
+ unsigned int dummy_clk;
+ unsigned int dummy_bytes;
+ unsigned int addr_bytes;
+
+ /*
+ * Identify addr_byte. All NOR flash device drivers are using fast read
+ * which always expecting 1 dummy byte, 1 cmd byte and 3/4 addr byte.
+ * With that, the length is in value of 5 or 6. Only FRAM chip from
+ * ramtron using normal read (which won't need dummy byte).
+ * Unlikely NOR flash using normal read due to performance issue.
+ */
+ if (cmdlen >= 5)
+ /* to cater fast read where cmd + addr + dummy */
+ addr_bytes = cmdlen - 2;
+ else
+ /* for normal read (only ramtron as of now) */
+ addr_bytes = cmdlen - 1;
+
+ /* Setup the indirect trigger address */
+ writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
+ plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
+
+ /* Configure SRAM partition for read. */
+ writel(CQSPI_REG_SRAM_PARTITION_RD, plat->regbase +
+ CQSPI_REG_SRAMPARTITION);
+
+ /* Configure the opcode */
+ rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB;
+
+#if (CONFIG_SPI_FLASH_QUAD == 1)
+ /* Instruction and address at DQ0, data at DQ0-3. */
+ rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
+#endif
+
+ /* Get address */
+ addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
+ writel(addr_value, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
+
+ /* The remaining lenght is dummy bytes. */
+ dummy_bytes = cmdlen - addr_bytes - 1;
+ if (dummy_bytes) {
+ if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
+ dummy_bytes = CQSPI_DUMMY_BYTES_MAX;
+
+ rd_reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
+#if defined(CONFIG_SPL_SPI_XIP) && defined(CONFIG_SPL_BUILD)
+ writel(0x0, plat->regbase + CQSPI_REG_MODE_BIT);
+#else
+ writel(0xFF, plat->regbase + CQSPI_REG_MODE_BIT);
+#endif
+
+ /* Convert to clock cycles. */
+ dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
+ /* Need to minus the mode byte (8 clocks). */
+ dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE;
+
+ if (dummy_clk)
+ rd_reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
+ << CQSPI_REG_RD_INSTR_DUMMY_LSB;
+ }
+
+ writel(rd_reg, plat->regbase + CQSPI_REG_RD_INSTR);
+
+ /* set device size */
+ reg = readl(plat->regbase + CQSPI_REG_SIZE);
+ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
+ reg |= (addr_bytes - 1);
+ writel(reg, plat->regbase + CQSPI_REG_SIZE);
+ return 0;
+}
+
+int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
+ unsigned int rxlen, u8 *rxbuf)
+{
+ unsigned int reg;
+
+ writel(rxlen, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
+
+ /* Start the indirect read transfer */
+ writel(CQSPI_REG_INDIRECTRD_START_MASK,
+ plat->regbase + CQSPI_REG_INDIRECTRD);
+
+ if (qspi_read_sram_fifo_poll(plat->regbase, (void *)rxbuf,
+ (const void *)plat->ahbbase, rxlen))
+ goto failrd;
+
+ /* Check flash indirect controller */
+ reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD);
+ if (!(reg & CQSPI_REG_INDIRECTRD_DONE_MASK)) {
+ reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD);
+ printf("QSPI: indirect completion status error with reg 0x%08x\n",
+ reg);
+ goto failrd;
+ }
+
+ /* Clear indirect completion status */
+ writel(CQSPI_REG_INDIRECTRD_DONE_MASK,
+ plat->regbase + CQSPI_REG_INDIRECTRD);
+ return 0;
+
+failrd:
+ /* Cancel the indirect read */
+ writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK,
+ plat->regbase + CQSPI_REG_INDIRECTRD);
+ return -1;
+}
+
+/* Opcode + Address (3/4 bytes) */
+int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
+ unsigned int cmdlen, const u8 *cmdbuf)
+{
+ unsigned int reg;
+ unsigned int addr_bytes = cmdlen > 4 ? 4 : 3;
+
+ if (cmdlen < 4 || cmdbuf == NULL) {
+ printf("QSPI: iInvalid input argument, len %d cmdbuf 0x%08x\n",
+ cmdlen, (unsigned int)cmdbuf);
+ return -EINVAL;
+ }
+ /* Setup the indirect trigger address */
+ writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
+ plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
+
+ writel(CQSPI_REG_SRAM_PARTITION_WR,
+ plat->regbase + CQSPI_REG_SRAMPARTITION);
+
+ /* Configure the opcode */
+ reg = cmdbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB;
+ writel(reg, plat->regbase + CQSPI_REG_WR_INSTR);
+
+ /* Setup write address. */
+ reg = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
+ writel(reg, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
+
+ reg = readl(plat->regbase + CQSPI_REG_SIZE);
+ reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
+ reg |= (addr_bytes - 1);
+ writel(reg, plat->regbase + CQSPI_REG_SIZE);
+ return 0;
+}
+
+int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
+ unsigned int txlen, const u8 *txbuf)
+{
+ unsigned int reg = 0;
+ unsigned int retry;
+
+ /* Configure the indirect read transfer bytes */
+ writel(txlen, plat->regbase + CQSPI_REG_INDIRECTWRBYTES);
+
+ /* Start the indirect write transfer */
+ writel(CQSPI_REG_INDIRECTWR_START_MASK,
+ plat->regbase + CQSPI_REG_INDIRECTWR);
+
+ if (qpsi_write_sram_fifo_push(plat, (const void *)txbuf, txlen))
+ goto failwr;
+
+ /* Wait until last write is completed (FIFO empty) */
+ retry = CQSPI_REG_RETRY;
+ while (retry--) {
+ reg = CQSPI_GET_WR_SRAM_LEVEL(plat->regbase);
+ if (reg == 0)
+ break;
+
+ udelay(1);
+ }
+
+ if (reg != 0) {
+ printf("QSPI: timeout for indirect write\n");
+ goto failwr;
+ }
+
+ /* Check flash indirect controller status */
+ retry = CQSPI_REG_RETRY;
+ while (retry--) {
+ reg = readl(plat->regbase + CQSPI_REG_INDIRECTWR);
+ if (reg & CQSPI_REG_INDIRECTWR_DONE_MASK)
+ break;
+ udelay(1);
+ }
+
+ if (!(reg & CQSPI_REG_INDIRECTWR_DONE_MASK)) {
+ printf("QSPI: indirect completion status error with reg 0x%08x\n",
+ reg);
+ goto failwr;
+ }
+
+ /* Clear indirect completion status */
+ writel(CQSPI_REG_INDIRECTWR_DONE_MASK,
+ plat->regbase + CQSPI_REG_INDIRECTWR);
+ return 0;
+
+failwr:
+ /* Cancel the indirect write */
+ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
+ plat->regbase + CQSPI_REG_INDIRECTWR);
+ return -1;
+}
+
+void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
+{
+ unsigned int reg;
+
+ /* enter XiP mode immediately and enable direct mode */
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+ reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
+ reg |= CQSPI_REG_CONFIG_DIRECT_MASK;
+ reg |= CQSPI_REG_CONFIG_XIP_IMM_MASK;
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+
+ /* keep the XiP mode */
+ writel(xip_dummy, reg_base + CQSPI_REG_MODE_BIT);
+
+ /* Enable mode bit at devrd */
+ reg = readl(reg_base + CQSPI_REG_RD_INSTR);
+ reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
+ writel(reg, reg_base + CQSPI_REG_RD_INSTR);
+}
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
new file mode 100644
index 0000000000..700f616ad7
--- /dev/null
+++ b/drivers/spi/designware_spi.c
@@ -0,0 +1,426 @@
+/*
+ * Designware master SPI core controller driver
+ *
+ * Copyright (C) 2014 Stefan Roese <sr@denx.de>
+ *
+ * Very loosely based on the Linux driver:
+ * drivers/spi/spi-dw.c, which is:
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <spi.h>
+#include <fdtdec.h>
+#include <linux/compat.h>
+#include <asm/io.h>
+#include <asm/arch/clock_manager.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Register offsets */
+#define DW_SPI_CTRL0 0x00
+#define DW_SPI_CTRL1 0x04
+#define DW_SPI_SSIENR 0x08
+#define DW_SPI_MWCR 0x0c
+#define DW_SPI_SER 0x10
+#define DW_SPI_BAUDR 0x14
+#define DW_SPI_TXFLTR 0x18
+#define DW_SPI_RXFLTR 0x1c
+#define DW_SPI_TXFLR 0x20
+#define DW_SPI_RXFLR 0x24
+#define DW_SPI_SR 0x28
+#define DW_SPI_IMR 0x2c
+#define DW_SPI_ISR 0x30
+#define DW_SPI_RISR 0x34
+#define DW_SPI_TXOICR 0x38
+#define DW_SPI_RXOICR 0x3c
+#define DW_SPI_RXUICR 0x40
+#define DW_SPI_MSTICR 0x44
+#define DW_SPI_ICR 0x48
+#define DW_SPI_DMACR 0x4c
+#define DW_SPI_DMATDLR 0x50
+#define DW_SPI_DMARDLR 0x54
+#define DW_SPI_IDR 0x58
+#define DW_SPI_VERSION 0x5c
+#define DW_SPI_DR 0x60
+
+/* Bit fields in CTRLR0 */
+#define SPI_DFS_OFFSET 0
+
+#define SPI_FRF_OFFSET 4
+#define SPI_FRF_SPI 0x0
+#define SPI_FRF_SSP 0x1
+#define SPI_FRF_MICROWIRE 0x2
+#define SPI_FRF_RESV 0x3
+
+#define SPI_MODE_OFFSET 6
+#define SPI_SCPH_OFFSET 6
+#define SPI_SCOL_OFFSET 7
+
+#define SPI_TMOD_OFFSET 8
+#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET)
+#define SPI_TMOD_TR 0x0 /* xmit & recv */
+#define SPI_TMOD_TO 0x1 /* xmit only */
+#define SPI_TMOD_RO 0x2 /* recv only */
+#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
+
+#define SPI_SLVOE_OFFSET 10
+#define SPI_SRL_OFFSET 11
+#define SPI_CFS_OFFSET 12
+
+/* Bit fields in SR, 7 bits */
+#define SR_MASK 0x7f /* cover 7 bits */
+#define SR_BUSY (1 << 0)
+#define SR_TF_NOT_FULL (1 << 1)
+#define SR_TF_EMPT (1 << 2)
+#define SR_RF_NOT_EMPT (1 << 3)
+#define SR_RF_FULL (1 << 4)
+#define SR_TX_ERR (1 << 5)
+#define SR_DCOL (1 << 6)
+
+#define RX_TIMEOUT 1000 /* timeout in ms */
+
+struct dw_spi_platdata {
+ s32 frequency; /* Default clock frequency, -1 for none */
+ void __iomem *regs;
+};
+
+struct dw_spi_priv {
+ void __iomem *regs;
+ unsigned int freq; /* Default frequency */
+ unsigned int mode;
+
+ int bits_per_word;
+ u8 cs; /* chip select pin */
+ u8 tmode; /* TR/TO/RO/EEPROM */
+ u8 type; /* SPI/SSP/MicroWire */
+ int len;
+
+ u32 fifo_len; /* depth of the FIFO buffer */
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+};
+
+static inline u32 dw_readl(struct dw_spi_priv *priv, u32 offset)
+{
+ return __raw_readl(priv->regs + offset);
+}
+
+static inline void dw_writel(struct dw_spi_priv *priv, u32 offset, u32 val)
+{
+ __raw_writel(val, priv->regs + offset);
+}
+
+static inline u16 dw_readw(struct dw_spi_priv *priv, u32 offset)
+{
+ return __raw_readw(priv->regs + offset);
+}
+
+static inline void dw_writew(struct dw_spi_priv *priv, u32 offset, u16 val)
+{
+ __raw_writew(val, priv->regs + offset);
+}
+
+static int dw_spi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct dw_spi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
+
+ plat->regs = (struct dw_spi *)fdtdec_get_addr(blob, node, "reg");
+
+ /* Use 500KHz as a suitable default */
+ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+ 500000);
+ debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs,
+ plat->frequency);
+
+ return 0;
+}
+
+static inline void spi_enable_chip(struct dw_spi_priv *priv, int enable)
+{
+ dw_writel(priv, DW_SPI_SSIENR, (enable ? 1 : 0));
+}
+
+/* Restart the controller, disable all interrupts, clean rx fifo */
+static void spi_hw_init(struct dw_spi_priv *priv)
+{
+ spi_enable_chip(priv, 0);
+ dw_writel(priv, DW_SPI_IMR, 0xff);
+ spi_enable_chip(priv, 1);
+
+ /*
+ * Try to detect the FIFO depth if not set by interface driver,
+ * the depth could be from 2 to 256 from HW spec
+ */
+ if (!priv->fifo_len) {
+ u32 fifo;
+
+ for (fifo = 2; fifo <= 256; fifo++) {
+ dw_writew(priv, DW_SPI_TXFLTR, fifo);
+ if (fifo != dw_readw(priv, DW_SPI_TXFLTR))
+ break;
+ }
+
+ priv->fifo_len = (fifo == 2) ? 0 : fifo - 1;
+ dw_writew(priv, DW_SPI_TXFLTR, 0);
+ }
+ debug("%s: fifo_len=%d\n", __func__, priv->fifo_len);
+}
+
+static int dw_spi_probe(struct udevice *bus)
+{
+ struct dw_spi_platdata *plat = dev_get_platdata(bus);
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+
+ priv->regs = plat->regs;
+ priv->freq = plat->frequency;
+
+ /* Currently only bits_per_word == 8 supported */
+ priv->bits_per_word = 8;
+
+ priv->tmode = 0; /* Tx & Rx */
+
+ /* Basic HW init */
+ spi_hw_init(priv);
+
+ return 0;
+}
+
+/* Return the max entries we can fill into tx fifo */
+static inline u32 tx_max(struct dw_spi_priv *priv)
+{
+ u32 tx_left, tx_room, rxtx_gap;
+
+ tx_left = (priv->tx_end - priv->tx) / (priv->bits_per_word >> 3);
+ tx_room = priv->fifo_len - dw_readw(priv, DW_SPI_TXFLR);
+
+ /*
+ * Another concern is about the tx/rx mismatch, we
+ * thought about using (priv->fifo_len - rxflr - txflr) as
+ * one maximum value for tx, but it doesn't cover the
+ * data which is out of tx/rx fifo and inside the
+ * shift registers. So a control from sw point of
+ * view is taken.
+ */
+ rxtx_gap = ((priv->rx_end - priv->rx) - (priv->tx_end - priv->tx)) /
+ (priv->bits_per_word >> 3);
+
+ return min3(tx_left, tx_room, (u32)(priv->fifo_len - rxtx_gap));
+}
+
+/* Return the max entries we should read out of rx fifo */
+static inline u32 rx_max(struct dw_spi_priv *priv)
+{
+ u32 rx_left = (priv->rx_end - priv->rx) / (priv->bits_per_word >> 3);
+
+ return min_t(u32, rx_left, dw_readw(priv, DW_SPI_RXFLR));
+}
+
+static void dw_writer(struct dw_spi_priv *priv)
+{
+ u32 max = tx_max(priv);
+ u16 txw = 0;
+
+ while (max--) {
+ /* Set the tx word if the transfer's original "tx" is not null */
+ if (priv->tx_end - priv->len) {
+ if (priv->bits_per_word == 8)
+ txw = *(u8 *)(priv->tx);
+ else
+ txw = *(u16 *)(priv->tx);
+ }
+ dw_writew(priv, DW_SPI_DR, txw);
+ debug("%s: tx=0x%02x\n", __func__, txw);
+ priv->tx += priv->bits_per_word >> 3;
+ }
+}
+
+static int dw_reader(struct dw_spi_priv *priv)
+{
+ unsigned start = get_timer(0);
+ u32 max;
+ u16 rxw;
+
+ /* Wait for rx data to be ready */
+ while (rx_max(priv) == 0) {
+ if (get_timer(start) > RX_TIMEOUT)
+ return -ETIMEDOUT;
+ }
+
+ max = rx_max(priv);
+
+ while (max--) {
+ rxw = dw_readw(priv, DW_SPI_DR);
+ debug("%s: rx=0x%02x\n", __func__, rxw);
+
+ /*
+ * Care about rx only if the transfer's original "rx" is
+ * not null
+ */
+ if (priv->rx_end - priv->len) {
+ if (priv->bits_per_word == 8)
+ *(u8 *)(priv->rx) = rxw;
+ else
+ *(u16 *)(priv->rx) = rxw;
+ }
+ priv->rx += priv->bits_per_word >> 3;
+ }
+
+ return 0;
+}
+
+static int poll_transfer(struct dw_spi_priv *priv)
+{
+ int ret;
+
+ do {
+ dw_writer(priv);
+ ret = dw_reader(priv);
+ if (ret < 0)
+ return ret;
+ } while (priv->rx_end > priv->rx);
+
+ return 0;
+}
+
+static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev->parent;
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+ const u8 *tx = dout;
+ u8 *rx = din;
+ int ret = 0;
+ u32 cr0 = 0;
+ u32 cs;
+
+ /* spi core configured to do 8 bit transfers */
+ if (bitlen % 8) {
+ debug("Non byte aligned SPI transfer.\n");
+ return -1;
+ }
+
+ cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) |
+ (priv->mode << SPI_MODE_OFFSET) |
+ (priv->tmode << SPI_TMOD_OFFSET);
+
+ if (rx && tx)
+ priv->tmode = SPI_TMOD_TR;
+ else if (rx)
+ priv->tmode = SPI_TMOD_RO;
+ else
+ priv->tmode = SPI_TMOD_TO;
+
+ cr0 &= ~SPI_TMOD_MASK;
+ cr0 |= (priv->tmode << SPI_TMOD_OFFSET);
+
+ priv->len = bitlen >> 3;
+ debug("%s: rx=%p tx=%p len=%d [bytes]\n", __func__, rx, tx, priv->len);
+
+ priv->tx = (void *)tx;
+ priv->tx_end = priv->tx + priv->len;
+ priv->rx = rx;
+ priv->rx_end = priv->rx + priv->len;
+
+ /* Disable controller before writing control registers */
+ spi_enable_chip(priv, 0);
+
+ debug("%s: cr0=%08x\n", __func__, cr0);
+ /* Reprogram cr0 only if changed */
+ if (dw_readw(priv, DW_SPI_CTRL0) != cr0)
+ dw_writew(priv, DW_SPI_CTRL0, cr0);
+
+ /*
+ * Configure the desired SS (slave select 0...3) in the controller
+ * The DW SPI controller will activate and deactivate this CS
+ * automatically. So no cs_activate() etc is needed in this driver.
+ */
+ cs = spi_chip_select(dev);
+ dw_writel(priv, DW_SPI_SER, 1 << cs);
+
+ /* Enable controller after writing control registers */
+ spi_enable_chip(priv, 1);
+
+ /* Start transfer in a polling loop */
+ ret = poll_transfer(priv);
+
+ return ret;
+}
+
+static int dw_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct dw_spi_platdata *plat = bus->platdata;
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+ u16 clk_div;
+
+ if (speed > plat->frequency)
+ speed = plat->frequency;
+
+ /* Disable controller before writing control registers */
+ spi_enable_chip(priv, 0);
+
+ /* clk_div doesn't support odd number */
+ clk_div = cm_get_spi_controller_clk_hz() / speed;
+ clk_div = (clk_div + 1) & 0xfffe;
+ dw_writel(priv, DW_SPI_BAUDR, clk_div);
+
+ /* Enable controller after writing control registers */
+ spi_enable_chip(priv, 1);
+
+ priv->freq = speed;
+ debug("%s: regs=%p speed=%d clk_div=%d\n", __func__, priv->regs,
+ priv->freq, clk_div);
+
+ return 0;
+}
+
+static int dw_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+
+ /*
+ * Can't set mode yet. Since this depends on if rx, tx, or
+ * rx & tx is requested. So we have to defer this to the
+ * real transfer function.
+ */
+ priv->mode = mode;
+ debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+ return 0;
+}
+
+static const struct dm_spi_ops dw_spi_ops = {
+ .xfer = dw_spi_xfer,
+ .set_speed = dw_spi_set_speed,
+ .set_mode = dw_spi_set_mode,
+ /*
+ * cs_info is not needed, since we require all chip selects to be
+ * in the device tree explicitly
+ */
+};
+
+static const struct udevice_id dw_spi_ids[] = {
+ { .compatible = "snps,dw-apb-ssi" },
+ { }
+};
+
+U_BOOT_DRIVER(dw_spi) = {
+ .name = "dw_spi",
+ .id = UCLASS_SPI,
+ .of_match = dw_spi_ids,
+ .ops = &dw_spi_ops,
+ .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/fsl_espi.c b/drivers/spi/fsl_espi.c
index ae0fe58f2c..375dc07f5f 100644
--- a/drivers/spi/fsl_espi.c
+++ b/drivers/spi/fsl_espi.c
@@ -273,7 +273,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
spi_cs_deactivate(slave);
return 0;
}
- buf_len = 2 * cmd_len + min(data_len, max_tran_len);
+ buf_len = 2 * cmd_len + min(data_len, (size_t)max_tran_len);
len = cmd_len + data_len;
rx_offset = cmd_len;
buffer = (unsigned char *)malloc(buf_len);
@@ -306,7 +306,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
if (data_in)
din = buffer + rx_offset;
dout = buffer;
- tran_len = min(data_len , max_tran_len);
+ tran_len = min(data_len, (size_t)max_tran_len);
num_blks = DIV_ROUND_UP(tran_len + cmd_len, 4);
num_bytes = (tran_len + cmd_len) % 4;
fsl->data_len = tran_len + cmd_len;
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index ba20beff4f..5e0b069274 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -14,7 +14,11 @@
#include "fsl_qspi.h"
#define RX_BUFFER_SIZE 0x80
+#ifdef CONFIG_MX6SX
+#define TX_BUFFER_SIZE 0x200
+#else
#define TX_BUFFER_SIZE 0x40
+#endif
#define OFFSET_BITS_MASK 0x00ffffff
@@ -28,20 +32,36 @@
#define SEQID_CHIP_ERASE 5
#define SEQID_PP 6
#define SEQID_RDID 7
+#define SEQID_BE_4K 8
+#ifdef CONFIG_SPI_FLASH_BAR
+#define SEQID_BRRD 9
+#define SEQID_BRWR 10
+#define SEQID_RDEAR 11
+#define SEQID_WREAR 12
+#endif
-/* Flash opcodes */
-#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
-#define OPCODE_RDSR 0x05 /* Read status register */
-#define OPCODE_WREN 0x06 /* Write enable */
-#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
-#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
-#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
-#define OPCODE_RDID 0x9f /* Read JEDEC ID */
-
-/* 4-byte address opcodes - used on Spansion and some Macronix flashes */
-#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
-#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
-#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
+/* QSPI CMD */
+#define QSPI_CMD_PP 0x02 /* Page program (up to 256 bytes) */
+#define QSPI_CMD_RDSR 0x05 /* Read status register */
+#define QSPI_CMD_WREN 0x06 /* Write enable */
+#define QSPI_CMD_FAST_READ 0x0b /* Read data bytes (high frequency) */
+#define QSPI_CMD_BE_4K 0x20 /* 4K erase */
+#define QSPI_CMD_CHIP_ERASE 0xc7 /* Erase whole flash chip */
+#define QSPI_CMD_SE 0xd8 /* Sector erase (usually 64KiB) */
+#define QSPI_CMD_RDID 0x9f /* Read JEDEC ID */
+
+/* Used for Micron, winbond and Macronix flashes */
+#define QSPI_CMD_WREAR 0xc5 /* EAR register write */
+#define QSPI_CMD_RDEAR 0xc8 /* EAR reigster read */
+
+/* Used for Spansion flashes only. */
+#define QSPI_CMD_BRRD 0x16 /* Bank register read */
+#define QSPI_CMD_BRWR 0x17 /* Bank register write */
+
+/* 4-byte address QSPI CMD - used on Spansion and some Macronix flashes */
+#define QSPI_CMD_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
+#define QSPI_CMD_PP_4B 0x12 /* Page program (up to 256 bytes) */
+#define QSPI_CMD_SE_4B 0xdc /* Sector erase (usually 64KiB) */
#ifdef CONFIG_SYS_FSL_QSPI_LE
#define qspi_read32 in_le32
@@ -53,10 +73,16 @@
static unsigned long spi_bases[] = {
QSPI0_BASE_ADDR,
+#ifdef CONFIG_MX6SX
+ QSPI1_BASE_ADDR,
+#endif
};
static unsigned long amba_bases[] = {
QSPI0_AMBA_BASE,
+#ifdef CONFIG_MX6SX
+ QSPI1_AMBA_BASE,
+#endif
};
struct fsl_qspi {
@@ -94,7 +120,7 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
/* Write Enable */
lut_base = SEQID_WREN * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_WREN) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
qspi_write32(&regs->lut[lut_base + 1], 0);
qspi_write32(&regs->lut[lut_base + 2], 0);
@@ -102,14 +128,22 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
/* Fast Read */
lut_base = SEQID_FAST_READ * 4;
+#ifdef CONFIG_SPI_FLASH_BAR
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_FAST_READ) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_FAST_READ_4B) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(&regs->lut[lut_base],
+ OPRND0(QSPI_CMD_FAST_READ_4B) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) |
+ OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) |
+ INSTR1(LUT_ADDR));
+#endif
qspi_write32(&regs->lut[lut_base + 1], OPRND0(8) | PAD0(LUT_PAD1) |
INSTR0(LUT_DUMMY) | OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
INSTR1(LUT_READ));
@@ -118,7 +152,7 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
/* Read Status */
lut_base = SEQID_RDSR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_RDSR) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
qspi_write32(&regs->lut[lut_base + 1], 0);
@@ -127,21 +161,27 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
/* Erase a sector */
lut_base = SEQID_SE * 4;
+#ifdef CONFIG_SPI_FLASH_BAR
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_SE) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_SE_4B) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE_4B) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+#endif
qspi_write32(&regs->lut[lut_base + 1], 0);
qspi_write32(&regs->lut[lut_base + 2], 0);
qspi_write32(&regs->lut[lut_base + 3], 0);
/* Erase the whole chip */
lut_base = SEQID_CHIP_ERASE * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_CHIP_ERASE) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_CHIP_ERASE) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
qspi_write32(&regs->lut[lut_base + 1], 0);
qspi_write32(&regs->lut[lut_base + 2], 0);
@@ -149,33 +189,184 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
/* Page Program */
lut_base = SEQID_PP * 4;
+#ifdef CONFIG_SPI_FLASH_BAR
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_PP) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_PP_4B) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP_4B) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+#endif
+#ifdef CONFIG_MX6SX
+ /*
+ * To MX6SX, OPRND0(TX_BUFFER_SIZE) can not work correctly.
+ * So, Use IDATSZ in IPCR to determine the size and here set 0.
+ */
+ qspi_write32(&regs->lut[lut_base + 1], OPRND0(0) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
+#else
qspi_write32(&regs->lut[lut_base + 1], OPRND0(TX_BUFFER_SIZE) |
PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
+#endif
qspi_write32(&regs->lut[lut_base + 2], 0);
qspi_write32(&regs->lut[lut_base + 3], 0);
/* READ ID */
lut_base = SEQID_RDID * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(OPCODE_RDID) |
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
qspi_write32(&regs->lut[lut_base + 1], 0);
qspi_write32(&regs->lut[lut_base + 2], 0);
qspi_write32(&regs->lut[lut_base + 3], 0);
+ /* SUB SECTOR 4K ERASE */
+ lut_base = SEQID_BE_4K * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+
+#ifdef CONFIG_SPI_FLASH_BAR
+ /*
+ * BRRD BRWR RDEAR WREAR are all supported, because it is hard to
+ * dynamically check whether to set BRRD BRWR or RDEAR WREAR during
+ * initialization.
+ */
+ lut_base = SEQID_BRRD * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BRRD) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_READ));
+
+ lut_base = SEQID_BRWR * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BRWR) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
+
+ lut_base = SEQID_RDEAR * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_READ));
+
+ lut_base = SEQID_WREAR * 4;
+ qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
+#endif
/* Lock the LUT */
qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
qspi_write32(&regs->lckcr, QSPI_LCKCR_LOCK);
}
+#if defined(CONFIG_SYS_FSL_QSPI_AHB)
+/*
+ * If we have changed the content of the flash by writing or erasing,
+ * we need to invalidate the AHB buffer. If we do not do so, we may read out
+ * the wrong data. The spec tells us reset the AHB domain and Serial Flash
+ * domain at the same time.
+ */
+static inline void qspi_ahb_invalid(struct fsl_qspi *q)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
+ u32 reg;
+
+ reg = qspi_read32(&regs->mcr);
+ reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
+ qspi_write32(&regs->mcr, reg);
+
+ /*
+ * The minimum delay : 1 AHB + 2 SFCK clocks.
+ * Delay 1 us is enough.
+ */
+ udelay(1);
+
+ reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
+ qspi_write32(&regs->mcr, reg);
+}
+
+/* Read out the data from the AHB buffer. */
+static inline void qspi_ahb_read(struct fsl_qspi *q, u8 *rxbuf, int len)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
+ u32 mcr_reg;
+
+ mcr_reg = qspi_read32(&regs->mcr);
+
+ qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+
+ /* Read out the data directly from the AHB buffer. */
+ memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len);
+
+ qspi_write32(&regs->mcr, mcr_reg);
+}
+
+static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs)
+{
+ u32 reg, reg2;
+
+ reg = qspi_read32(&regs->mcr);
+ /* Disable the module */
+ qspi_write32(&regs->mcr, reg | QSPI_MCR_MDIS_MASK);
+
+ /* Set the Sampling Register for DDR */
+ reg2 = qspi_read32(&regs->smpr);
+ reg2 &= ~QSPI_SMPR_DDRSMP_MASK;
+ reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT);
+ qspi_write32(&regs->smpr, reg2);
+
+ /* Enable the module again (enable the DDR too) */
+ reg |= QSPI_MCR_DDR_EN_MASK;
+ /* Enable bit 29 for imx6sx */
+ reg |= (1 << 29);
+
+ qspi_write32(&regs->mcr, reg);
+}
+
+/*
+ * There are two different ways to read out the data from the flash:
+ * the "IP Command Read" and the "AHB Command Read".
+ *
+ * The IC guy suggests we use the "AHB Command Read" which is faster
+ * then the "IP Command Read". (What's more is that there is a bug in
+ * the "IP Command Read" in the Vybrid.)
+ *
+ * After we set up the registers for the "AHB Command Read", we can use
+ * the memcpy to read the data directly. A "missed" access to the buffer
+ * causes the controller to clear the buffer, and use the sequence pointed
+ * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
+ */
+static void qspi_init_ahb_read(struct fsl_qspi_regs *regs)
+{
+ /* AHB configuration for access buffer 0/1/2 .*/
+ qspi_write32(&regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(&regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(&regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(&regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
+ (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
+
+ /* We only use the buffer3 */
+ qspi_write32(&regs->buf0ind, 0);
+ qspi_write32(&regs->buf1ind, 0);
+ qspi_write32(&regs->buf2ind, 0);
+
+ /*
+ * Set the default lut sequence for AHB Read.
+ * Parallel mode is disabled.
+ */
+ qspi_write32(&regs->bfgencr,
+ SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT);
+
+ /*Enable DDR Mode*/
+ qspi_enable_ddr_mode(regs);
+}
+#endif
+
void spi_init()
{
/* do nothing */
@@ -186,18 +377,28 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
{
struct fsl_qspi *qspi;
struct fsl_qspi_regs *regs;
- u32 reg_val, smpr_val;
- u32 total_size, seq_id;
+ u32 smpr_val;
+ u32 total_size;
if (bus >= ARRAY_SIZE(spi_bases))
return NULL;
+ if (cs >= FSL_QSPI_FLASH_NUM)
+ return NULL;
+
qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
if (!qspi)
return NULL;
qspi->reg_base = spi_bases[bus];
- qspi->amba_base = amba_bases[bus];
+ /*
+ * According cs, use different amba_base to choose the
+ * corresponding flash devices.
+ *
+ * If not, only one flash device is used even if passing
+ * different cs using `sf probe`
+ */
+ qspi->amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE;
qspi->slave.max_write_size = TX_BUFFER_SIZE;
@@ -210,10 +411,20 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
- qspi_write32(&regs->sfa1ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base);
- qspi_write32(&regs->sfa2ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base);
- qspi_write32(&regs->sfb1ad, total_size | qspi->amba_base);
- qspi_write32(&regs->sfb2ad, total_size | qspi->amba_base);
+ /*
+ * Any read access to non-implemented addresses will provide
+ * undefined results.
+ *
+ * In case single die flash devices, TOP_ADDR_MEMA2 and
+ * TOP_ADDR_MEMB2 should be initialized/programmed to
+ * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
+ * setting the size of these devices to 0. This would ensure
+ * that the complete memory map is assigned to only one flash device.
+ */
+ qspi_write32(&regs->sfa1ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
+ qspi_write32(&regs->sfa2ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
+ qspi_write32(&regs->sfb1ad, total_size | amba_bases[bus]);
+ qspi_write32(&regs->sfb2ad, total_size | amba_bases[bus]);
qspi_set_lut(qspi);
@@ -222,13 +433,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
qspi_write32(&regs->smpr, smpr_val);
qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
- seq_id = 0;
- reg_val = qspi_read32(&regs->bfgencr);
- reg_val &= ~QSPI_BFGENCR_SEQID_MASK;
- reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT);
- reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK;
- qspi_write32(&regs->bfgencr, reg_val);
-
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+ qspi_init_ahb_read(regs);
+#endif
return &qspi->slave;
}
@@ -244,6 +451,47 @@ int spi_claim_bus(struct spi_slave *slave)
return 0;
}
+#ifdef CONFIG_SPI_FLASH_BAR
+/* Bank register read/write, EAR register read/write */
+static void qspi_op_rdbank(struct fsl_qspi *qspi, u8 *rxbuf, u32 len)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 reg, mcr_reg, data, seqid;
+
+ mcr_reg = qspi_read32(&regs->mcr);
+ qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+
+ qspi_write32(&regs->sfar, qspi->amba_base);
+
+ if (qspi->cur_seqid == QSPI_CMD_BRRD)
+ seqid = SEQID_BRRD;
+ else
+ seqid = SEQID_RDEAR;
+
+ qspi_write32(&regs->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
+
+ /* Wait previous command complete */
+ while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ while (1) {
+ reg = qspi_read32(&regs->rbsr);
+ if (reg & QSPI_RBSR_RDBFL_MASK) {
+ data = qspi_read32(&regs->rbdr[0]);
+ data = qspi_endian_xchg(data);
+ memcpy(rxbuf, &data, len);
+ qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
+ break;
+ }
+ }
+
+ qspi_write32(&regs->mcr, mcr_reg);
+}
+#endif
+
static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
{
struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
@@ -278,6 +526,8 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
qspi_write32(&regs->mcr, mcr_reg);
}
+#ifndef CONFIG_SYS_FSL_QSPI_AHB
+/* If not use AHB read, read data from ip interface */
static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
{
struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
@@ -321,11 +571,12 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
qspi_write32(&regs->mcr, mcr_reg);
}
+#endif
-static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len)
+static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
{
struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
- u32 mcr_reg, data, reg, status_reg;
+ u32 mcr_reg, data, reg, status_reg, seqid;
int i, size, tx_size;
u32 to_or_from = 0;
@@ -355,22 +606,39 @@ static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len)
qspi_read32(&regs->mcr) | QSPI_MCR_CLR_RXF_MASK);
}
+ /* Default is page programming */
+ seqid = SEQID_PP;
+#ifdef CONFIG_SPI_FLASH_BAR
+ if (qspi->cur_seqid == QSPI_CMD_BRWR)
+ seqid = SEQID_BRWR;
+ else if (qspi->cur_seqid == QSPI_CMD_WREAR)
+ seqid = SEQID_WREAR;
+#endif
+
to_or_from = qspi->sf_addr + qspi->amba_base;
+
qspi_write32(&regs->sfar, to_or_from);
tx_size = (len > TX_BUFFER_SIZE) ?
TX_BUFFER_SIZE : len;
- size = (tx_size + 3) / 4;
-
+ size = tx_size / 4;
for (i = 0; i < size; i++) {
- data = qspi_endian_xchg(*txbuf);
+ memcpy(&data, txbuf, 4);
+ data = qspi_endian_xchg(data);
qspi_write32(&regs->tbdr, data);
- txbuf++;
+ txbuf += 4;
}
- qspi_write32(&regs->ipcr,
- (SEQID_PP << QSPI_IPCR_SEQID_SHIFT) | tx_size);
+ size = tx_size % 4;
+ if (size) {
+ data = 0;
+ memcpy(&data, txbuf, size);
+ data = qspi_endian_xchg(data);
+ qspi_write32(&regs->tbdr, data);
+ }
+
+ qspi_write32(&regs->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
;
@@ -409,7 +677,7 @@ static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf)
qspi_write32(&regs->mcr, mcr_reg);
}
-static void qspi_op_se(struct fsl_qspi *qspi)
+static void qspi_op_erase(struct fsl_qspi *qspi)
{
struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
u32 mcr_reg;
@@ -428,8 +696,13 @@ static void qspi_op_se(struct fsl_qspi *qspi)
while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
;
- qspi_write32(&regs->ipcr,
- (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
+ if (qspi->cur_seqid == QSPI_CMD_SE) {
+ qspi_write32(&regs->ipcr,
+ (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
+ } else if (qspi->cur_seqid == QSPI_CMD_BE_4K) {
+ qspi_write32(&regs->ipcr,
+ (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0);
+ }
while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
;
@@ -441,38 +714,67 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
{
struct fsl_qspi *qspi = to_qspi_spi(slave);
u32 bytes = DIV_ROUND_UP(bitlen, 8);
- static u32 pp_sfaddr;
+ static u32 wr_sfaddr;
u32 txbuf;
if (dout) {
- memcpy(&txbuf, dout, 4);
- qspi->cur_seqid = *(u8 *)dout;
+ if (flags & SPI_XFER_BEGIN) {
+ qspi->cur_seqid = *(u8 *)dout;
+ memcpy(&txbuf, dout, 4);
+ }
if (flags == SPI_XFER_END) {
- qspi->sf_addr = pp_sfaddr;
- qspi_op_pp(qspi, (u32 *)dout, bytes);
+ qspi->sf_addr = wr_sfaddr;
+ qspi_op_write(qspi, (u8 *)dout, bytes);
return 0;
}
- if (qspi->cur_seqid == OPCODE_FAST_READ) {
+ if (qspi->cur_seqid == QSPI_CMD_FAST_READ) {
qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- } else if (qspi->cur_seqid == OPCODE_SE) {
+ } else if ((qspi->cur_seqid == QSPI_CMD_SE) ||
+ (qspi->cur_seqid == QSPI_CMD_BE_4K)) {
qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- qspi_op_se(qspi);
- } else if (qspi->cur_seqid == OPCODE_PP) {
- pp_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
+ qspi_op_erase(qspi);
+ } else if (qspi->cur_seqid == QSPI_CMD_PP)
+ wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
+#ifdef CONFIG_SPI_FLASH_BAR
+ else if ((qspi->cur_seqid == QSPI_CMD_BRWR) ||
+ (qspi->cur_seqid == QSPI_CMD_WREAR)) {
+ wr_sfaddr = 0;
}
+#endif
}
if (din) {
- if (qspi->cur_seqid == OPCODE_FAST_READ)
+ if (qspi->cur_seqid == QSPI_CMD_FAST_READ) {
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+ qspi_ahb_read(qspi, din, bytes);
+#else
qspi_op_read(qspi, din, bytes);
- else if (qspi->cur_seqid == OPCODE_RDID)
+#endif
+ }
+ else if (qspi->cur_seqid == QSPI_CMD_RDID)
qspi_op_rdid(qspi, din, bytes);
- else if (qspi->cur_seqid == OPCODE_RDSR)
+ else if (qspi->cur_seqid == QSPI_CMD_RDSR)
qspi_op_rdsr(qspi, din);
+#ifdef CONFIG_SPI_FLASH_BAR
+ else if ((qspi->cur_seqid == QSPI_CMD_BRRD) ||
+ (qspi->cur_seqid == QSPI_CMD_RDEAR)) {
+ qspi->sf_addr = 0;
+ qspi_op_rdbank(qspi, din, bytes);
+ }
+#endif
}
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+ if ((qspi->cur_seqid == QSPI_CMD_SE) ||
+ (qspi->cur_seqid == QSPI_CMD_PP) ||
+ (qspi->cur_seqid == QSPI_CMD_BE_4K) ||
+ (qspi->cur_seqid == QSPI_CMD_WREAR) ||
+ (qspi->cur_seqid == QSPI_CMD_BRWR))
+ qspi_ahb_invalid(qspi);
+#endif
+
return 0;
}
diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h
index db400e66b5..6cb361018b 100644
--- a/drivers/spi/fsl_qspi.h
+++ b/drivers/spi/fsl_qspi.h
@@ -58,7 +58,12 @@ struct fsl_qspi_regs {
#define QSPI_MCR_END_CFD_SHIFT 2
#define QSPI_MCR_END_CFD_MASK (3 << QSPI_MCR_END_CFD_SHIFT)
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+/* AHB needs 64bit operation */
+#define QSPI_MCR_END_CFD_LE (3 << QSPI_MCR_END_CFD_SHIFT)
+#else
#define QSPI_MCR_END_CFD_LE (1 << QSPI_MCR_END_CFD_SHIFT)
+#endif
#define QSPI_MCR_DDR_EN_SHIFT 7
#define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT)
#define QSPI_MCR_CLR_RXF_SHIFT 10
@@ -69,6 +74,10 @@ struct fsl_qspi_regs {
#define QSPI_MCR_MDIS_MASK (1 << QSPI_MCR_MDIS_SHIFT)
#define QSPI_MCR_RESERVED_SHIFT 16
#define QSPI_MCR_RESERVED_MASK (0xf << QSPI_MCR_RESERVED_SHIFT)
+#define QSPI_MCR_SWRSTHD_SHIFT 1
+#define QSPI_MCR_SWRSTHD_MASK (1 << QSPI_MCR_SWRSTHD_SHIFT)
+#define QSPI_MCR_SWRSTSD_SHIFT 0
+#define QSPI_MCR_SWRSTSD_MASK (1 << QSPI_MCR_SWRSTSD_SHIFT)
#define QSPI_SMPR_HSENA_SHIFT 0
#define QSPI_SMPR_HSENA_MASK (1 << QSPI_SMPR_HSENA_SHIFT)
@@ -79,6 +88,12 @@ struct fsl_qspi_regs {
#define QSPI_SMPR_DDRSMP_SHIFT 16
#define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT)
+#define QSPI_BUFXCR_INVALID_MSTRID 0xe
+#define QSPI_BUF3CR_ALLMST_SHIFT 31
+#define QSPI_BUF3CR_ALLMST_MASK (1 << QSPI_BUF3CR_ALLMST_SHIFT)
+#define QSPI_BUF3CR_ADATSZ_SHIFT 8
+#define QSPI_BUF3CR_ADATSZ_MASK (0xFF << QSPI_BUF3CR_ADATSZ_SHIFT)
+
#define QSPI_BFGENCR_SEQID_SHIFT 12
#define QSPI_BFGENCR_SEQID_MASK (0xf << QSPI_BFGENCR_SEQID_SHIFT)
#define QSPI_BFGENCR_PAR_EN_SHIFT 16
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
index aa3b5a01cd..267e4d83bd 100644
--- a/drivers/spi/ftssp010_spi.c
+++ b/drivers/spi/ftssp010_spi.c
@@ -169,61 +169,49 @@ static int get_spi_gpio(int bus, struct ftssp010_gpio *chip)
static int ftssp010_wait(struct ftssp010_spi *chip)
{
struct ftssp010_regs *regs = chip->regs;
- int ret = -1;
ulong t;
/* wait until device idle */
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
- if (readl(&regs->sr) & SR_BUSY)
- continue;
- ret = 0;
- break;
+ if (!(readl(&regs->sr) & SR_BUSY))
+ return 0;
}
- if (ret)
- puts("ftspi010: busy timeout\n");
+ puts("ftspi010: busy timeout\n");
- return ret;
+ return -1;
}
static int ftssp010_wait_tx(struct ftssp010_spi *chip)
{
struct ftssp010_regs *regs = chip->regs;
- int ret = -1;
ulong t;
/* wait until tx fifo not full */
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
- if (!(readl(&regs->sr) & SR_TFNF))
- continue;
- ret = 0;
- break;
+ if (readl(&regs->sr) & SR_TFNF)
+ return 0;
}
- if (ret)
- puts("ftssp010: tx timeout\n");
+ puts("ftssp010: tx timeout\n");
- return ret;
+ return -1;
}
static int ftssp010_wait_rx(struct ftssp010_spi *chip)
{
struct ftssp010_regs *regs = chip->regs;
- int ret = -1;
ulong t;
/* wait until rx fifo not empty */
for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
- if (!SR_RFVE(readl(&regs->sr)))
- continue;
- ret = 0;
- break;
+ if (SR_RFVE(readl(&regs->sr)))
+ return 0;
}
- if (ret)
- puts("ftssp010: rx timeout\n");
+ puts("ftssp010: rx timeout\n");
- return ret;
+ return -1;
}
static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip,
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index f5c6f3e7d2..0379444872 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -141,6 +141,15 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
ich->slave.max_write_size = ctlr.databytes;
ich->speed = max_hz;
+ /*
+ * ICH 7 SPI controller only supports array read command
+ * and byte program command for SST flash
+ */
+ if (ctlr.ich_version == 7) {
+ ich->slave.op_mode_rx = SPI_OPM_RX_AS;
+ ich->slave.op_mode_tx = SPI_OPM_TX_BP;
+ }
+
return &ich->slave;
}
@@ -158,7 +167,8 @@ 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)
+ if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC ||
+ device_id == PCI_DEVICE_ID_INTEL_ITC_LPC)
return 7;
if ((device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
@@ -483,8 +493,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
struct spi_trans *trans = &ich->trans;
unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END);
int using_cmd = 0;
- /* Align read transactions to 64-byte boundaries */
- char buff[ctlr.databytes];
/* Ee don't support writing partial bytes. */
if (bitlen % 8) {
@@ -632,14 +640,9 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
*/
while (trans->bytesout || trans->bytesin) {
uint32_t data_length;
- uint32_t aligned_offset;
- uint32_t diff;
-
- aligned_offset = trans->offset & ~(ctlr.databytes - 1);
- diff = trans->offset - aligned_offset;
/* SPI addresses are 24 bit only */
- ich_writel(aligned_offset & 0x00FFFFFF, ctlr.addr);
+ ich_writel(trans->offset & 0x00FFFFFF, ctlr.addr);
if (trans->bytesout)
data_length = min(trans->bytesout, ctlr.databytes);
@@ -673,13 +676,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
if (trans->bytesin) {
- if (diff) {
- data_length -= diff;
- read_reg(ctlr.data, buff, ctlr.databytes);
- memcpy(trans->in, buff + diff, data_length);
- } else {
- read_reg(ctlr.data, trans->in, data_length);
- }
+ read_reg(ctlr.data, trans->in, data_length);
spi_use_in(trans, data_length);
if (with_address)
trans->offset += data_length;
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index be102692d4..08815994fe 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -49,6 +49,8 @@ struct mxc_spi_slave {
#endif
int gpio;
int ss_pol;
+ unsigned int max_hz;
+ unsigned int mode;
};
static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave)
@@ -83,12 +85,13 @@ u32 get_cspi_div(u32 div)
}
#ifdef MXC_CSPI
-static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
+static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs)
{
unsigned int ctrl_reg;
u32 clk_src;
u32 div;
+ unsigned int max_hz = mxcs->max_hz;
+ unsigned int mode = mxcs->mode;
clk_src = mxc_get_clock(MXC_CSPI_CLK);
@@ -120,19 +123,15 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs,
#endif
#ifdef MXC_ECSPI
-static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
+static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs)
{
u32 clk_src = mxc_get_clock(MXC_CSPI_CLK);
s32 reg_ctrl, reg_config;
u32 ss_pol = 0, sclkpol = 0, sclkpha = 0, sclkctl = 0;
u32 pre_div = 0, post_div = 0;
struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
-
- if (max_hz == 0) {
- printf("Error: desired clock is 0\n");
- return -1;
- }
+ unsigned int max_hz = mxcs->max_hz;
+ unsigned int mode = mxcs->mode;
/*
* Reset SPI and set all CSs to master mode, if toggling
@@ -169,9 +168,6 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs,
reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_POSTDIV(0x0F)) |
MXC_CSPICTRL_POSTDIV(post_div);
- /* We need to disable SPI before changing registers */
- reg_ctrl &= ~MXC_CSPICTRL_EN;
-
if (mode & SPI_CS_HIGH)
ss_pol = 1;
@@ -319,7 +315,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,
tmp = reg_read(&regs->rxdata);
data = cpu_to_be32(tmp);
debug("SPI Rx: 0x%x 0x%x\n", tmp, data);
- cnt = min(nbytes, sizeof(data));
+ cnt = min_t(u32, nbytes, sizeof(data));
if (din) {
memcpy(din, &data, cnt);
din += cnt;
@@ -412,6 +408,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (bus >= ARRAY_SIZE(spi_bases))
return NULL;
+ if (max_hz == 0) {
+ printf("Error: desired clock is 0\n");
+ return NULL;
+ }
+
mxcs = spi_alloc_slave(struct mxc_spi_slave, bus, cs);
if (!mxcs) {
puts("mxc_spi: SPI Slave not allocated !\n");
@@ -427,13 +428,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
}
mxcs->base = spi_bases[bus];
+ mxcs->max_hz = max_hz;
+ mxcs->mode = mode;
- ret = spi_cfg_mxc(mxcs, cs, max_hz, mode);
- if (ret) {
- printf("mxc_spi: cannot setup SPI controller\n");
- free(mxcs);
- return NULL;
- }
return &mxcs->slave;
}
@@ -446,12 +443,17 @@ void spi_free_slave(struct spi_slave *slave)
int spi_claim_bus(struct spi_slave *slave)
{
+ int ret;
struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
reg_write(&regs->rxdata, 1);
udelay(1);
- reg_write(&regs->ctrl, mxcs->ctrl_reg);
+ ret = spi_cfg_mxc(mxcs, slave->cs);
+ if (ret) {
+ printf("mxc_spi: cannot setup SPI controller\n");
+ return ret;
+ }
reg_write(&regs->period, MXC_CSPIPERIOD_32KHZ);
reg_write(&regs->intr, 0);
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 13c6b77d73..7a57bceb26 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -57,7 +57,7 @@ int spi_claim_bus(struct spi_slave *slave)
speed = slave->max_hz;
if (spi->max_hz) {
if (speed)
- speed = min(speed, spi->max_hz);
+ speed = min(speed, (int)spi->max_hz);
else
speed = spi->max_hz;
}
@@ -115,16 +115,7 @@ int spi_chip_select(struct udevice *dev)
return slave ? slave->cs : -ENOENT;
}
-/**
- * spi_find_chip_select() - Find the slave attached to chip select
- *
- * @bus: SPI bus to search
- * @cs: Chip select to look for
- * @devp: Returns the slave device if found
- * @return 0 if found, -ENODEV on error
- */
-static int spi_find_chip_select(struct udevice *bus, int cs,
- struct udevice **devp)
+int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
{
struct udevice *dev;
@@ -197,27 +188,6 @@ int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info)
return -ENODEV;
}
-int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
- const char *dev_name, struct udevice **devp)
-{
- struct driver *drv;
- int ret;
-
- drv = lists_driver_lookup_name(drv_name);
- if (!drv) {
- printf("Cannot find driver '%s'\n", drv_name);
- return -ENOENT;
- }
- ret = device_bind(bus, drv, dev_name, NULL, -1, devp);
- if (ret) {
- printf("Cannot create device named '%s' (err=%d)\n",
- dev_name, ret);
- return ret;
- }
-
- return 0;
-}
-
int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
struct udevice **devp)
{
@@ -264,7 +234,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
if (ret == -ENODEV && drv_name) {
debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
__func__, dev_name, busnum, cs, drv_name);
- ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev);
+ ret = device_bind_driver(bus, drv_name, dev_name, &dev);
if (ret)
return ret;
created = true;
diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c
index fd7fea8df5..857b60455a 100644
--- a/drivers/spi/ti_qspi.c
+++ b/drivers/spi/ti_qspi.c
@@ -102,7 +102,7 @@ static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave)
struct spi_slave *slave = &qslave->slave;
u32 memval = 0;
-#ifdef CONFIG_DRA7XX
+#if defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)
slave->memory_map = (void *)MMAP_START_ADDR_DRA;
#else
slave->memory_map = (void *)MMAP_START_ADDR_AM43x;
@@ -244,7 +244,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
uint status;
int timeout;
-#ifdef CONFIG_DRA7XX
+#if defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)
int val;
#endif
@@ -254,7 +254,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
/* Setup mmap flags */
if (flags & SPI_XFER_MMAP) {
writel(MM_SWITCH, &qslave->base->memswitch);
-#ifdef CONFIG_DRA7XX
+#if defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)
val = readl(CORE_CTRL_IO);
val |= MEM_CS;
writel(val, CORE_CTRL_IO);
@@ -262,7 +262,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
return 0;
} else if (flags & SPI_XFER_MMAP_END) {
writel(~MM_SWITCH, &qslave->base->memswitch);
-#ifdef CONFIG_DRA7XX
+#if defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)
val = readl(CORE_CTRL_IO);
val &= MEM_CS_UNSELECT;
writel(val, CORE_CTRL_IO);
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
new file mode 100644
index 0000000000..6d4cacdcf7
--- /dev/null
+++ b/drivers/thermal/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2014 Freescale Semiconductor, Inc.
+# Author: Nitin Garg <nitin.garg@freescale.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o
+obj-$(CONFIG_IMX6_THERMAL) += imx_thermal.o
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
new file mode 100644
index 0000000000..0bd9cfd030
--- /dev/null
+++ b/drivers/thermal/imx_thermal.c
@@ -0,0 +1,175 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc.
+ * Author: Nitin Garg <nitin.garg@freescale.com>
+ * Ye Li <Ye.Li@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <div64.h>
+#include <fuse.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <thermal.h>
+#include <imx_thermal.h>
+
+#define TEMPERATURE_MIN -40
+#define TEMPERATURE_HOT 80
+#define TEMPERATURE_MAX 125
+#define FACTOR0 10000000
+#define FACTOR1 15976
+#define FACTOR2 4297157
+#define MEASURE_FREQ 327
+
+#define TEMPSENSE0_TEMP_CNT_SHIFT 8
+#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
+#define TEMPSENSE0_FINISHED (1 << 2)
+#define TEMPSENSE0_MEASURE_TEMP (1 << 1)
+#define TEMPSENSE0_POWER_DOWN (1 << 0)
+#define MISC0_REFTOP_SELBIASOFF (1 << 3)
+#define TEMPSENSE1_MEASURE_FREQ 0xffff
+
+static int read_cpu_temperature(struct udevice *dev)
+{
+ int temperature;
+ unsigned int reg, n_meas;
+ const struct imx_thermal_plat *pdata = dev_get_platdata(dev);
+ struct anatop_regs *anatop = (struct anatop_regs *)pdata->regs;
+ unsigned int *priv = dev_get_priv(dev);
+ u32 fuse = *priv;
+ int t1, n1;
+ u32 c1, c2;
+ u64 temp64;
+
+ /*
+ * Sensor data layout:
+ * [31:20] - sensor value @ 25C
+ * We use universal formula now and only need sensor value @ 25C
+ * slope = 0.4297157 - (0.0015976 * 25C fuse)
+ */
+ n1 = fuse >> 20;
+ t1 = 25; /* t1 always 25C */
+
+ /*
+ * Derived from linear interpolation:
+ * slope = 0.4297157 - (0.0015976 * 25C fuse)
+ * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0
+ * (Nmeas - n1) / (Tmeas - t1) = slope
+ * We want to reduce this down to the minimum computation necessary
+ * for each temperature read. Also, we want Tmeas in millicelsius
+ * and we don't want to lose precision from integer division. So...
+ * Tmeas = (Nmeas - n1) / slope + t1
+ * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1
+ * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1
+ * Let constant c1 = (-1000 / slope)
+ * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1
+ * Let constant c2 = n1 *c1 + 1000 * t1
+ * milli_Tmeas = c2 - Nmeas * c1
+ */
+ temp64 = FACTOR0;
+ temp64 *= 1000;
+ do_div(temp64, FACTOR1 * n1 - FACTOR2);
+ c1 = temp64;
+ c2 = n1 * c1 + 1000 * t1;
+
+ /*
+ * now we only use single measure, every time we read
+ * the temperature, we will power on/down anadig thermal
+ * module
+ */
+ writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr);
+ writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
+
+ /* setup measure freq */
+ reg = readl(&anatop->tempsense1);
+ reg &= ~TEMPSENSE1_MEASURE_FREQ;
+ reg |= MEASURE_FREQ;
+ writel(reg, &anatop->tempsense1);
+
+ /* start the measurement process */
+ writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr);
+ writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
+ writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set);
+
+ /* make sure that the latest temp is valid */
+ while ((readl(&anatop->tempsense0) &
+ TEMPSENSE0_FINISHED) == 0)
+ udelay(10000);
+
+ /* read temperature count */
+ reg = readl(&anatop->tempsense0);
+ n_meas = (reg & TEMPSENSE0_TEMP_CNT_MASK)
+ >> TEMPSENSE0_TEMP_CNT_SHIFT;
+ writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
+
+ /* milli_Tmeas = c2 - Nmeas * c1 */
+ temperature = (c2 - n_meas * c1)/1000;
+
+ /* power down anatop thermal sensor */
+ writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set);
+ writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr);
+
+ return temperature;
+}
+
+int imx_thermal_get_temp(struct udevice *dev, int *temp)
+{
+ int cpu_tmp = 0;
+
+ cpu_tmp = read_cpu_temperature(dev);
+ while (cpu_tmp > TEMPERATURE_MIN && cpu_tmp < TEMPERATURE_MAX) {
+ if (cpu_tmp >= TEMPERATURE_HOT) {
+ printf("CPU Temperature is %d C, too hot to boot, waiting...\n",
+ cpu_tmp);
+ udelay(5000000);
+ cpu_tmp = read_cpu_temperature(dev);
+ } else {
+ break;
+ }
+ }
+
+ *temp = cpu_tmp;
+
+ return 0;
+}
+
+static const struct dm_thermal_ops imx_thermal_ops = {
+ .get_temp = imx_thermal_get_temp,
+};
+
+static int imx_thermal_probe(struct udevice *dev)
+{
+ unsigned int fuse = ~0;
+
+ const struct imx_thermal_plat *pdata = dev_get_platdata(dev);
+ unsigned int *priv = dev_get_priv(dev);
+
+ /* Read Temperature calibration data fuse */
+ fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse);
+
+ /* Check for valid fuse */
+ if (fuse == 0 || fuse == ~0) {
+ printf("CPU: Thermal invalid data, fuse: 0x%x\n", fuse);
+ return -EPERM;
+ }
+
+ *priv = fuse;
+
+ enable_thermal_clk();
+
+ return 0;
+}
+
+U_BOOT_DRIVER(imx_thermal) = {
+ .name = "imx_thermal",
+ .id = UCLASS_THERMAL,
+ .ops = &imx_thermal_ops,
+ .probe = imx_thermal_probe,
+ .priv_auto_alloc_size = sizeof(unsigned int),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/thermal/thermal-uclass.c b/drivers/thermal/thermal-uclass.c
new file mode 100644
index 0000000000..3bee1a7dc7
--- /dev/null
+++ b/drivers/thermal/thermal-uclass.c
@@ -0,0 +1,30 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <thermal.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/list.h>
+
+
+int thermal_get_temp(struct udevice *dev, int *temp)
+{
+ const struct dm_thermal_ops *ops = device_get_ops(dev);
+
+ if (!ops->get_temp)
+ return -ENOSYS;
+
+ return ops->get_temp(dev, temp);
+}
+
+UCLASS_DRIVER(thermal) = {
+ .id = UCLASS_THERMAL,
+ .name = "thermal",
+};
diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c
index bc0f9645b5..31761ec338 100644
--- a/drivers/tpm/tpm.c
+++ b/drivers/tpm/tpm.c
@@ -34,7 +34,7 @@
#include <config.h>
#include <common.h>
-#include <compiler.h>
+#include <linux/compiler.h>
#include <fdtdec.h>
#include <i2c.h>
#include <tpm.h>
diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c
index 2dd8501f92..c1bbed4eb5 100644
--- a/drivers/tpm/tpm_tis_i2c.c
+++ b/drivers/tpm/tpm_tis_i2c.c
@@ -38,7 +38,7 @@
#include <common.h>
#include <fdtdec.h>
-#include <compiler.h>
+#include <linux/compiler.h>
#include <i2c.h>
#include <tpm.h>
#include <asm-generic/errno.h>
diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c
index eecf18cbf9..d09f8cee05 100644
--- a/drivers/tpm/tpm_tis_lpc.c
+++ b/drivers/tpm/tpm_tis_lpc.c
@@ -274,7 +274,7 @@ static u32 tis_senddata(const u8 * const data, u32 len)
* changes to zero exactly after the last byte is fed into the
* FIFO.
*/
- count = min(burst, len - offset - 1);
+ count = min((u32)burst, len - offset - 1);
while (count--)
tpm_write_byte(data[offset++],
&lpc_tpm_dev[locality].data);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index e69de29bb2..b4a9442703 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -0,0 +1,46 @@
+config USB_ARCH_HAS_HCD
+ def_bool y
+
+config USB
+ bool "Support for Host-side USB"
+ depends on USB_ARCH_HAS_HCD
+ ---help---
+ Universal Serial Bus (USB) is a specification for a serial bus
+ subsystem which offers higher speeds and more features than the
+ traditional PC serial port. The bus supplies power to peripherals
+ and allows for hot swapping. Up to 127 USB peripherals can be
+ connected to a single USB host in a tree structure.
+
+ The USB host is the root of the tree, the peripherals are the
+ leaves and the inner nodes are special USB devices called hubs.
+ Most PCs now have USB host ports, used to connect peripherals
+ such as scanners, keyboards, mice, modems, cameras, disks,
+ flash memory, network links, and printers to the PC.
+
+ Say Y here if your computer has a host-side USB port and you want
+ to use USB devices. You then need to say Y to at least one of the
+ Host Controller Driver (HCD) options below. Choose a USB 1.1
+ controller, such as "UHCI HCD support" or "OHCI HCD support",
+ and "EHCI HCD (USB 2.0) support" except for older systems that
+ do not have USB 2.0 support. It doesn't normally hurt to select
+ them all if you are not certain.
+
+ If your system has a device-side USB port, used in the peripheral
+ side of the USB protocol, see the "USB Gadget" framework instead.
+
+ After choosing your HCD, then select drivers for the USB peripherals
+ you'll be using. You may want to check out the information provided
+ in <file:Documentation/usb/> and especially the links given in
+ <file:Documentation/usb/usb-help.txt>.
+
+if USB
+
+source "drivers/usb/host/Kconfig"
+
+config USB_STORAGE
+ bool "USB Mass Storage support"
+ ---help---
+ Say Y here if you want to connect USB mass storage devices to your
+ board's USB port.
+
+endif
diff --git a/drivers/usb/eth/Makefile b/drivers/usb/eth/Makefile
index 94551c4c0c..c92d2b02d2 100644
--- a/drivers/usb/eth/Makefile
+++ b/drivers/usb/eth/Makefile
@@ -5,8 +5,7 @@
# new USB host ethernet layer dependencies
obj-$(CONFIG_USB_HOST_ETHER) += usb_ether.o
-ifdef CONFIG_USB_ETHER_ASIX
-obj-y += asix.o
-endif
+obj-$(CONFIG_USB_ETHER_ASIX) += asix.o
+obj-$(CONFIG_USB_ETHER_ASIX88179) += asix88179.o
obj-$(CONFIG_USB_ETHER_MCS7830) += mcs7830.o
obj-$(CONFIG_USB_ETHER_SMSC95XX) += smsc95xx.o
diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c
new file mode 100644
index 0000000000..b8ca720e25
--- /dev/null
+++ b/drivers/usb/eth/asix88179.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2014 Rene Griessl <rgriessl@cit-ec.uni-bielefeld.de>
+ * based on the U-Boot Asix driver as well as information
+ * from the Linux AX88179_178a driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <net.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+#include <malloc.h>
+#include <errno.h>
+
+/* ASIX AX88179 based USB 3.0 Ethernet Devices */
+#define AX88179_PHY_ID 0x03
+#define AX_EEPROM_LEN 0x100
+#define AX88179_EEPROM_MAGIC 0x17900b95
+#define AX_MCAST_FLTSIZE 8
+#define AX_MAX_MCAST 64
+#define AX_INT_PPLS_LINK (1 << 16)
+#define AX_RXHDR_L4_TYPE_MASK 0x1c
+#define AX_RXHDR_L4_TYPE_UDP 4
+#define AX_RXHDR_L4_TYPE_TCP 16
+#define AX_RXHDR_L3CSUM_ERR 2
+#define AX_RXHDR_L4CSUM_ERR 1
+#define AX_RXHDR_CRC_ERR (1 << 29)
+#define AX_RXHDR_DROP_ERR (1 << 31)
+#define AX_ENDPOINT_INT 0x01
+#define AX_ENDPOINT_IN 0x02
+#define AX_ENDPOINT_OUT 0x03
+#define AX_ACCESS_MAC 0x01
+#define AX_ACCESS_PHY 0x02
+#define AX_ACCESS_EEPROM 0x04
+#define AX_ACCESS_EFUS 0x05
+#define AX_PAUSE_WATERLVL_HIGH 0x54
+#define AX_PAUSE_WATERLVL_LOW 0x55
+
+#define PHYSICAL_LINK_STATUS 0x02
+ #define AX_USB_SS (1 << 2)
+ #define AX_USB_HS (1 << 1)
+
+#define GENERAL_STATUS 0x03
+ #define AX_SECLD (1 << 2)
+
+#define AX_SROM_ADDR 0x07
+#define AX_SROM_CMD 0x0a
+ #define EEP_RD (1 << 2)
+ #define EEP_BUSY (1 << 4)
+
+#define AX_SROM_DATA_LOW 0x08
+#define AX_SROM_DATA_HIGH 0x09
+
+#define AX_RX_CTL 0x0b
+ #define AX_RX_CTL_DROPCRCERR (1 << 8)
+ #define AX_RX_CTL_IPE (1 << 9)
+ #define AX_RX_CTL_START (1 << 7)
+ #define AX_RX_CTL_AP (1 << 5)
+ #define AX_RX_CTL_AM (1 << 4)
+ #define AX_RX_CTL_AB (1 << 3)
+ #define AX_RX_CTL_AMALL (1 << 1)
+ #define AX_RX_CTL_PRO (1 << 0)
+ #define AX_RX_CTL_STOP 0
+
+#define AX_NODE_ID 0x10
+#define AX_MULFLTARY 0x16
+
+#define AX_MEDIUM_STATUS_MODE 0x22
+ #define AX_MEDIUM_GIGAMODE (1 << 0)
+ #define AX_MEDIUM_FULL_DUPLEX (1 << 1)
+ #define AX_MEDIUM_EN_125MHZ (1 << 3)
+ #define AX_MEDIUM_RXFLOW_CTRLEN (1 << 4)
+ #define AX_MEDIUM_TXFLOW_CTRLEN (1 << 5)
+ #define AX_MEDIUM_RECEIVE_EN (1 << 8)
+ #define AX_MEDIUM_PS (1 << 9)
+ #define AX_MEDIUM_JUMBO_EN 0x8040
+
+#define AX_MONITOR_MOD 0x24
+ #define AX_MONITOR_MODE_RWLC (1 << 1)
+ #define AX_MONITOR_MODE_RWMP (1 << 2)
+ #define AX_MONITOR_MODE_PMEPOL (1 << 5)
+ #define AX_MONITOR_MODE_PMETYPE (1 << 6)
+
+#define AX_GPIO_CTRL 0x25
+ #define AX_GPIO_CTRL_GPIO3EN (1 << 7)
+ #define AX_GPIO_CTRL_GPIO2EN (1 << 6)
+ #define AX_GPIO_CTRL_GPIO1EN (1 << 5)
+
+#define AX_PHYPWR_RSTCTL 0x26
+ #define AX_PHYPWR_RSTCTL_BZ (1 << 4)
+ #define AX_PHYPWR_RSTCTL_IPRL (1 << 5)
+ #define AX_PHYPWR_RSTCTL_AT (1 << 12)
+
+#define AX_RX_BULKIN_QCTRL 0x2e
+#define AX_CLK_SELECT 0x33
+ #define AX_CLK_SELECT_BCS (1 << 0)
+ #define AX_CLK_SELECT_ACS (1 << 1)
+ #define AX_CLK_SELECT_ULR (1 << 3)
+
+#define AX_RXCOE_CTL 0x34
+ #define AX_RXCOE_IP (1 << 0)
+ #define AX_RXCOE_TCP (1 << 1)
+ #define AX_RXCOE_UDP (1 << 2)
+ #define AX_RXCOE_TCPV6 (1 << 5)
+ #define AX_RXCOE_UDPV6 (1 << 6)
+
+#define AX_TXCOE_CTL 0x35
+ #define AX_TXCOE_IP (1 << 0)
+ #define AX_TXCOE_TCP (1 << 1)
+ #define AX_TXCOE_UDP (1 << 2)
+ #define AX_TXCOE_TCPV6 (1 << 5)
+ #define AX_TXCOE_UDPV6 (1 << 6)
+
+#define AX_LEDCTRL 0x73
+
+#define GMII_PHY_PHYSR 0x11
+ #define GMII_PHY_PHYSR_SMASK 0xc000
+ #define GMII_PHY_PHYSR_GIGA (1 << 15)
+ #define GMII_PHY_PHYSR_100 (1 << 14)
+ #define GMII_PHY_PHYSR_FULL (1 << 13)
+ #define GMII_PHY_PHYSR_LINK (1 << 10)
+
+#define GMII_LED_ACT 0x1a
+ #define GMII_LED_ACTIVE_MASK 0xff8f
+ #define GMII_LED0_ACTIVE (1 << 4)
+ #define GMII_LED1_ACTIVE (1 << 5)
+ #define GMII_LED2_ACTIVE (1 << 6)
+
+#define GMII_LED_LINK 0x1c
+ #define GMII_LED_LINK_MASK 0xf888
+ #define GMII_LED0_LINK_10 (1 << 0)
+ #define GMII_LED0_LINK_100 (1 << 1)
+ #define GMII_LED0_LINK_1000 (1 << 2)
+ #define GMII_LED1_LINK_10 (1 << 4)
+ #define GMII_LED1_LINK_100 (1 << 5)
+ #define GMII_LED1_LINK_1000 (1 << 6)
+ #define GMII_LED2_LINK_10 (1 << 8)
+ #define GMII_LED2_LINK_100 (1 << 9)
+ #define GMII_LED2_LINK_1000 (1 << 10)
+ #define LED0_ACTIVE (1 << 0)
+ #define LED0_LINK_10 (1 << 1)
+ #define LED0_LINK_100 (1 << 2)
+ #define LED0_LINK_1000 (1 << 3)
+ #define LED0_FD (1 << 4)
+ #define LED0_USB3_MASK 0x001f
+ #define LED1_ACTIVE (1 << 5)
+ #define LED1_LINK_10 (1 << 6)
+ #define LED1_LINK_100 (1 << 7)
+ #define LED1_LINK_1000 (1 << 8)
+ #define LED1_FD (1 << 9)
+ #define LED1_USB3_MASK 0x03e0
+ #define LED2_ACTIVE (1 << 10)
+ #define LED2_LINK_1000 (1 << 13)
+ #define LED2_LINK_100 (1 << 12)
+ #define LED2_LINK_10 (1 << 11)
+ #define LED2_FD (1 << 14)
+ #define LED_VALID (1 << 15)
+ #define LED2_USB3_MASK 0x7c00
+
+#define GMII_PHYPAGE 0x1e
+#define GMII_PHY_PAGE_SELECT 0x1f
+ #define GMII_PHY_PGSEL_EXT 0x0007
+ #define GMII_PHY_PGSEL_PAGE0 0x0000
+
+/* local defines */
+#define ASIX_BASE_NAME "axg"
+#define USB_CTRL_SET_TIMEOUT 5000
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_BULK_SEND_TIMEOUT 5000
+#define USB_BULK_RECV_TIMEOUT 5000
+
+#define AX_RX_URB_SIZE 1024 * 0x12
+#define BLK_FRAME_SIZE 0x200
+#define PHY_CONNECT_TIMEOUT 5000
+
+#define TIMEOUT_RESOLUTION 50 /* ms */
+
+#define FLAG_NONE 0
+#define FLAG_TYPE_AX88179 (1U << 0)
+#define FLAG_TYPE_AX88178a (1U << 1)
+#define FLAG_TYPE_DLINK_DUB1312 (1U << 2)
+#define FLAG_TYPE_SITECOM (1U << 3)
+#define FLAG_TYPE_SAMSUNG (1U << 4)
+#define FLAG_TYPE_LENOVO (1U << 5)
+
+/* local vars */
+static const struct {
+ unsigned char ctrl, timer_l, timer_h, size, ifg;
+} AX88179_BULKIN_SIZE[] = {
+ {7, 0x4f, 0, 0x02, 0xff},
+ {7, 0x20, 3, 0x03, 0xff},
+ {7, 0xae, 7, 0x04, 0xff},
+ {7, 0xcc, 0x4c, 0x04, 8},
+};
+
+static int curr_eth_dev; /* index for name of next device detected */
+
+/* driver private */
+struct asix_private {
+ int flags;
+ int rx_urb_size;
+ int maxpacketsize;
+};
+
+/*
+ * Asix infrastructure commands
+ */
+static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int len;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, size);
+
+ debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+ cmd, value, index, size);
+
+ memcpy(buf, data, size);
+
+ len = usb_control_msg(
+ dev->pusb_dev,
+ usb_sndctrlpipe(dev->pusb_dev, 0),
+ cmd,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ buf,
+ size,
+ USB_CTRL_SET_TIMEOUT);
+
+ return len == size ? 0 : ECOMM;
+}
+
+static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int len;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, size);
+
+ debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+ cmd, value, index, size);
+
+ len = usb_control_msg(
+ dev->pusb_dev,
+ usb_rcvctrlpipe(dev->pusb_dev, 0),
+ cmd,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ buf,
+ size,
+ USB_CTRL_GET_TIMEOUT);
+
+ memcpy(data, buf, size);
+
+ return len == size ? 0 : ECOMM;
+}
+
+static int asix_read_mac(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ u8 buf[ETH_ALEN];
+
+ asix_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, 6, 6, buf);
+ debug("asix_read_mac() returning %02x:%02x:%02x:%02x:%02x:%02x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+ memcpy(eth->enetaddr, buf, ETH_ALEN);
+
+ return 0;
+}
+
+static int asix_basic_reset(struct ueth_data *dev)
+{
+ struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
+ u8 buf[5];
+ u16 *tmp16;
+ u8 *tmp;
+
+ tmp16 = (u16 *)buf;
+ tmp = (u8 *)buf;
+
+ /* Power up ethernet PHY */
+ *tmp16 = 0;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+
+ *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+ mdelay(200);
+
+ *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
+ mdelay(200);
+
+ /* RX bulk configuration */
+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
+
+ dev_priv->rx_urb_size = 128 * 20;
+
+ /* Water Level configuration */
+ *tmp = 0x34;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
+
+ *tmp = 0x52;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, 1, 1, tmp);
+
+ /* Enable checksum offload */
+ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
+
+ *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
+ AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
+
+ /* Configure RX control register => start operation */
+ *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
+ AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
+
+ *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
+ AX_MONITOR_MODE_RWMP;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp);
+
+ /* Configure default medium type => giga */
+ *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
+ AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX |
+ AX_MEDIUM_GIGAMODE | AX_MEDIUM_JUMBO_EN;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, 2, 2, tmp16);
+
+ u16 adv = 0;
+ adv = ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_LPACK |
+ ADVERTISE_NPAGE | ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP;
+ asix_write_cmd(dev, AX_ACCESS_PHY, 0x03, MII_ADVERTISE, 2, &adv);
+
+ adv = ADVERTISE_1000FULL;
+ asix_write_cmd(dev, AX_ACCESS_PHY, 0x03, MII_CTRL1000, 2, &adv);
+
+ return 0;
+}
+
+static int asix_wait_link(struct ueth_data *dev)
+{
+ int timeout = 0;
+ int link_detected;
+ u8 buf[2];
+ u16 *tmp16;
+
+ tmp16 = (u16 *)buf;
+
+ do {
+ asix_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ MII_BMSR, 2, buf);
+ link_detected = *tmp16 & BMSR_LSTATUS;
+ if (!link_detected) {
+ if (timeout == 0)
+ printf("Waiting for Ethernet connection... ");
+ mdelay(TIMEOUT_RESOLUTION);
+ timeout += TIMEOUT_RESOLUTION;
+ }
+ } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+
+ if (link_detected) {
+ if (timeout > 0)
+ printf("done.\n");
+ return 0;
+ } else {
+ printf("unable to connect.\n");
+ return -ENETUNREACH;
+ }
+}
+
+/*
+ * Asix callbacks
+ */
+static int asix_init(struct eth_device *eth, bd_t *bd)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
+ u8 buf[2], tmp[5], link_sts;
+ u16 *tmp16, mode;
+
+
+ tmp16 = (u16 *)buf;
+
+ debug("** %s()\n", __func__);
+
+ /* Configure RX control register => start operation */
+ *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
+ AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
+ if (asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16) != 0)
+ goto out_err;
+
+ if (asix_wait_link(dev) != 0) {
+ /*reset device and try again*/
+ printf("Reset Ethernet Device\n");
+ asix_basic_reset(dev);
+ if (asix_wait_link(dev) != 0)
+ goto out_err;
+ }
+
+ /* Configure link */
+ mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
+ AX_MEDIUM_RXFLOW_CTRLEN;
+
+ asix_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS,
+ 1, 1, &link_sts);
+
+ asix_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+ GMII_PHY_PHYSR, 2, tmp16);
+
+ if (!(*tmp16 & GMII_PHY_PHYSR_LINK)) {
+ return 0;
+ } else if (GMII_PHY_PHYSR_GIGA == (*tmp16 & GMII_PHY_PHYSR_SMASK)) {
+ mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ |
+ AX_MEDIUM_JUMBO_EN;
+
+ if (link_sts & AX_USB_SS)
+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
+ else if (link_sts & AX_USB_HS)
+ memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5);
+ else
+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+ } else if (GMII_PHY_PHYSR_100 == (*tmp16 & GMII_PHY_PHYSR_SMASK)) {
+ mode |= AX_MEDIUM_PS;
+
+ if (link_sts & (AX_USB_SS | AX_USB_HS))
+ memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5);
+ else
+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+ } else {
+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+ }
+
+ /* RX bulk configuration */
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
+
+ dev_priv->rx_urb_size = (1024 * (tmp[3] + 2));
+ if (*tmp16 & GMII_PHY_PHYSR_FULL)
+ mode |= AX_MEDIUM_FULL_DUPLEX;
+ asix_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+ 2, 2, &mode);
+
+ return 0;
+out_err:
+ return -1;
+}
+
+static int asix_send(struct eth_device *eth, void *packet, int length)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
+
+ int err;
+ u32 packet_len, tx_hdr2;
+ int actual_len, framesize;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
+ PKTSIZE + (2 * sizeof(packet_len)));
+
+ debug("** %s(), len %d\n", __func__, length);
+
+ packet_len = length;
+ cpu_to_le32s(&packet_len);
+
+ memcpy(msg, &packet_len, sizeof(packet_len));
+ framesize = dev_priv->maxpacketsize;
+ tx_hdr2 = 0;
+ if (((length + 8) % framesize) == 0)
+ tx_hdr2 |= 0x80008000; /* Enable padding */
+
+ cpu_to_le32s(&tx_hdr2);
+
+ memcpy(msg + sizeof(packet_len), &tx_hdr2, sizeof(tx_hdr2));
+
+ memcpy(msg + sizeof(packet_len) + sizeof(tx_hdr2),
+ (void *)packet, length);
+
+ err = usb_bulk_msg(dev->pusb_dev,
+ usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
+ (void *)msg,
+ length + sizeof(packet_len) + sizeof(tx_hdr2),
+ &actual_len,
+ USB_BULK_SEND_TIMEOUT);
+ debug("Tx: len = %u, actual = %u, err = %d\n",
+ length + sizeof(packet_len), actual_len, err);
+
+ return err;
+}
+
+static int asix_recv(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
+
+ u16 frame_pos;
+ int err;
+ int actual_len;
+
+ int pkt_cnt;
+ u32 rx_hdr;
+ u16 hdr_off;
+ u32 *pkt_hdr;
+ ALLOC_CACHE_ALIGN_BUFFER(u8, recv_buf, dev_priv->rx_urb_size);
+
+ actual_len = -1;
+
+ debug("** %s()\n", __func__);
+
+ err = usb_bulk_msg(dev->pusb_dev,
+ usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+ (void *)recv_buf,
+ dev_priv->rx_urb_size,
+ &actual_len,
+ USB_BULK_RECV_TIMEOUT);
+ debug("Rx: len = %u, actual = %u, err = %d\n", dev_priv->rx_urb_size,
+ actual_len, err);
+
+ if (err != 0) {
+ debug("Rx: failed to receive\n");
+ return -ECOMM;
+ }
+ if (actual_len > dev_priv->rx_urb_size) {
+ debug("Rx: received too many bytes %d\n", actual_len);
+ return -EMSGSIZE;
+ }
+
+
+ rx_hdr = *(u32 *)(recv_buf + actual_len - 4);
+ le32_to_cpus(&pkt_hdr);
+
+ pkt_cnt = (u16)rx_hdr;
+ hdr_off = (u16)(rx_hdr >> 16);
+ pkt_hdr = (u32 *)(recv_buf + hdr_off);
+
+
+ frame_pos = 0;
+
+ while (pkt_cnt--) {
+ u16 pkt_len;
+
+ le32_to_cpus(pkt_hdr);
+ pkt_len = (*pkt_hdr >> 16) & 0x1fff;
+
+ frame_pos += 2;
+
+ NetReceive(recv_buf + frame_pos, pkt_len);
+
+ pkt_hdr++;
+ frame_pos += ((pkt_len + 7) & 0xFFF8)-2;
+
+ if (pkt_cnt == 0)
+ return 0;
+ }
+ return err;
+}
+
+static void asix_halt(struct eth_device *eth)
+{
+ debug("** %s()\n", __func__);
+}
+
+/*
+ * Asix probing functions
+ */
+void ax88179_eth_before_probe(void)
+{
+ curr_eth_dev = 0;
+}
+
+struct asix_dongle {
+ unsigned short vendor;
+ unsigned short product;
+ int flags;
+};
+
+static const struct asix_dongle asix_dongles[] = {
+ { 0x0b95, 0x1790, FLAG_TYPE_AX88179 },
+ { 0x0b95, 0x178a, FLAG_TYPE_AX88178a },
+ { 0x2001, 0x4a00, FLAG_TYPE_DLINK_DUB1312 },
+ { 0x0df6, 0x0072, FLAG_TYPE_SITECOM },
+ { 0x04e8, 0xa100, FLAG_TYPE_SAMSUNG },
+ { 0x17ef, 0x304b, FLAG_TYPE_LENOVO },
+ { 0x0000, 0x0000, FLAG_NONE } /* END - Do not remove */
+};
+
+/* Probe to see if a new device is actually an asix device */
+int ax88179_eth_probe(struct usb_device *dev, unsigned int ifnum,
+ struct ueth_data *ss)
+{
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *iface_desc;
+ struct asix_private *dev_priv;
+ int ep_in_found = 0, ep_out_found = 0;
+ int i;
+
+ /* let's examine the device now */
+ iface = &dev->config.if_desc[ifnum];
+ iface_desc = &dev->config.if_desc[ifnum].desc;
+
+ for (i = 0; asix_dongles[i].vendor != 0; i++) {
+ if (dev->descriptor.idVendor == asix_dongles[i].vendor &&
+ dev->descriptor.idProduct == asix_dongles[i].product)
+ /* Found a supported dongle */
+ break;
+ }
+
+ if (asix_dongles[i].vendor == 0)
+ return 0;
+
+ memset(ss, 0, sizeof(struct ueth_data));
+
+ /* At this point, we know we've got a live one */
+ debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+ /* Initialize the ueth_data structure with some useful info */
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+ ss->subclass = iface_desc->bInterfaceSubClass;
+ ss->protocol = iface_desc->bInterfaceProtocol;
+
+ /* alloc driver private */
+ ss->dev_priv = calloc(1, sizeof(struct asix_private));
+ if (!ss->dev_priv)
+ return 0;
+ dev_priv = ss->dev_priv;
+ dev_priv->flags = asix_dongles[i].flags;
+
+ /*
+ * We are expecting a minimum of 3 endpoints - in, out (bulk), and
+ * int. We will ignore any others.
+ */
+ for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+ /* is it an interrupt endpoint? */
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+ ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->irqinterval = iface->ep_desc[i].bInterval;
+ continue;
+ }
+
+ /* is it an BULK endpoint? */
+ if (!((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
+ continue;
+
+ u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
+ if ((ep_addr & USB_DIR_IN) && !ep_in_found) {
+ ss->ep_in = ep_addr &
+ USB_ENDPOINT_NUMBER_MASK;
+ ep_in_found = 1;
+ }
+ if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
+ ss->ep_out = ep_addr &
+ USB_ENDPOINT_NUMBER_MASK;
+ dev_priv->maxpacketsize =
+ dev->epmaxpacketout[AX_ENDPOINT_OUT];
+ ep_out_found = 1;
+ }
+ }
+ debug("Endpoints In %d Out %d Int %d\n",
+ ss->ep_in, ss->ep_out, ss->ep_int);
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+ !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+ debug("Problems with device\n");
+ return 0;
+ }
+ dev->privptr = (void *)ss;
+ return 1;
+}
+
+int ax88179_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+ struct eth_device *eth)
+{
+ if (!eth) {
+ debug("%s: missing parameter.\n", __func__);
+ return 0;
+ }
+ sprintf(eth->name, "%s%d", ASIX_BASE_NAME, curr_eth_dev++);
+ eth->init = asix_init;
+ eth->send = asix_send;
+ eth->recv = asix_recv;
+ eth->halt = asix_halt;
+ eth->priv = ss;
+
+ if (asix_basic_reset(ss))
+ return 0;
+
+ /* Get the MAC address */
+ if (asix_read_mac(eth))
+ return 0;
+ debug("MAC %pM\n", eth->enetaddr);
+
+ return 1;
+}
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c
index 1dda54c2f1..7cb96e3bf6 100644
--- a/drivers/usb/eth/usb_ether.c
+++ b/drivers/usb/eth/usb_ether.c
@@ -30,6 +30,13 @@ static const struct usb_eth_prob_dev prob_dev[] = {
.get_info = asix_eth_get_info,
},
#endif
+#ifdef CONFIG_USB_ETHER_ASIX88179
+ {
+ .before_probe = ax88179_eth_before_probe,
+ .probe = ax88179_eth_probe,
+ .get_info = ax88179_eth_get_info,
+ },
+#endif
#ifdef CONFIG_USB_ETHER_MCS7830
{
.before_probe = mcs7830_eth_before_probe,
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 2efd5a4d5b..70bb550fa4 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o
ifdef CONFIG_USB_GADGET
obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+obj-$(CONFIG_USB_GADGET_S3C_UDC_OTG_PHY) += s3c_udc_otg_phy.o
obj-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
obj-$(CONFIG_CI_UDC) += ci_udc.o
obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 12628effe8..fbc74f3bed 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1062,7 +1062,6 @@ static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
receive_data(ep);
- usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
}
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7bd25629c8..a4c5606527 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -743,8 +743,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (!gadget_is_dualspeed(gadget))
break;
device_qual(cdev);
- value = min(w_length,
- sizeof(struct usb_qualifier_descriptor));
+ value = min_t(int, w_length,
+ sizeof(struct usb_qualifier_descriptor));
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget_is_dualspeed(gadget))
diff --git a/drivers/usb/gadget/designware_udc.c b/drivers/usb/gadget/designware_udc.c
index 3559400b28..0db7a3b6c1 100644
--- a/drivers/usb/gadget/designware_udc.c
+++ b/drivers/usb/gadget/designware_udc.c
@@ -269,8 +269,8 @@ static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance
UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d",
urb->buffer, urb->buffer_length, urb->actual_length);
- last = min(urb->actual_length - endpoint->sent,
- endpoint->tx_packetSize);
+ last = min_t(u32, urb->actual_length - endpoint->sent,
+ endpoint->tx_packetSize);
if (last) {
u8 *cp = urb->buffer + endpoint->sent;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index d0dd29ffb2..ba442d5ed5 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -852,30 +852,6 @@ DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ);
DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT);
#endif
-
-/**
- * strlcpy - Copy a %NUL terminated string into a sized buffer
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
- * @size: size of destination buffer
- *
- * Compatible with *BSD: the result is always a valid
- * NUL-terminated string that fits in the buffer (unless,
- * of course, the buffer size is zero). It does not pad
- * out the result like strncpy() does.
- */
-size_t strlcpy(char *dest, const char *src, size_t size)
-{
- size_t ret = strlen(src);
-
- if (size) {
- size_t len = (ret >= size) ? size - 1 : ret;
- memcpy(dest, src, len);
- dest[len] = '\0';
- }
- return ret;
-}
-
/*============================================================================*/
/*
diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c
index 16fc9ddf82..ead71eba6b 100644
--- a/drivers/usb/gadget/f_dfu.c
+++ b/drivers/usb/gadget/f_dfu.c
@@ -366,7 +366,7 @@ static int state_dfu_idle(struct f_dfu *f_dfu,
to_runtime_mode(f_dfu);
f_dfu->dfu_state = DFU_STATE_appIDLE;
- dfu_trigger_detach();
+ g_dnl_trigger_detach();
break;
default:
f_dfu->dfu_state = DFU_STATE_dfuERROR;
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 71b62e5005..310175acfe 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -480,6 +480,17 @@ static void cb_boot(struct usb_ep *ep, struct usb_request *req)
fastboot_tx_write_str("OKAY");
}
+static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ g_dnl_trigger_detach();
+}
+
+static void cb_continue(struct usb_ep *ep, struct usb_request *req)
+{
+ fastboot_func->in_req->complete = do_exit_on_complete;
+ fastboot_tx_write_str("OKAY");
+}
+
#ifdef CONFIG_FASTBOOT_FLASH
static void cb_flash(struct usb_ep *ep, struct usb_request *req)
{
@@ -520,6 +531,9 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = {
}, {
.cmd = "boot",
.cb = cb_boot,
+ }, {
+ .cmd = "continue",
+ .cb = cb_continue,
},
#ifdef CONFIG_FASTBOOT_FLASH
{
diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c
index 78519fa41f..2d0410d795 100644
--- a/drivers/usb/gadget/f_thor.c
+++ b/drivers/usb/gadget/f_thor.c
@@ -205,12 +205,24 @@ static long long int download_head(unsigned long long total,
static int download_tail(long long int left, int cnt)
{
- struct dfu_entity *dfu_entity = dfu_get_entity(alt_setting_num);
- void *transfer_buffer = dfu_get_buf(dfu_entity);
+ struct dfu_entity *dfu_entity;
+ void *transfer_buffer;
int ret;
debug("%s: left: %llu cnt: %d\n", __func__, left, cnt);
+ dfu_entity = dfu_get_entity(alt_setting_num);
+ if (!dfu_entity) {
+ error("Alt setting: %d entity not found!\n", alt_setting_num);
+ return -ENOENT;
+ }
+
+ transfer_buffer = dfu_get_buf(dfu_entity);
+ if (!transfer_buffer) {
+ error("Transfer buffer not allocated!");
+ return -ENXIO;
+ }
+
if (left) {
ret = dfu_write(dfu_entity, transfer_buffer, left, cnt++);
if (ret) {
diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
index 25611acd60..ee52a29467 100644
--- a/drivers/usb/gadget/g_dnl.c
+++ b/drivers/usb/gadget/g_dnl.c
@@ -163,6 +163,23 @@ __weak int g_dnl_board_usb_cable_connected(void)
return -EOPNOTSUPP;
}
+static bool g_dnl_detach_request;
+
+bool g_dnl_detach(void)
+{
+ return g_dnl_detach_request;
+}
+
+void g_dnl_trigger_detach(void)
+{
+ g_dnl_detach_request = true;
+}
+
+void g_dnl_clear_detach(void)
+{
+ g_dnl_detach_request = false;
+}
+
static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index efd5c7fda1..9423555280 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -65,7 +65,8 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
if (!urb || !urb->actual_length)
return -1;
- n = min(urb->actual_length - endpoint->sent, endpoint->tx_packetSize);
+ n = min_t(unsigned int, urb->actual_length - endpoint->sent,
+ endpoint->tx_packetSize);
if (n <= 0)
return -1;
diff --git a/drivers/usb/gadget/s3c_udc_otg.c b/drivers/usb/gadget/s3c_udc_otg.c
index b9816dfe30..7653f03949 100644
--- a/drivers/usb/gadget/s3c_udc_otg.c
+++ b/drivers/usb/gadget/s3c_udc_otg.c
@@ -31,7 +31,6 @@
#include <asm/io.h>
#include <asm/mach-types.h>
-#include <asm/arch/gpio.h>
#include "regs-otg.h"
#include <usb/lin_gadget_compat.h>
@@ -105,7 +104,7 @@ static void stop_activity(struct s3c_udc *dev,
struct usb_gadget_driver *driver);
static int udc_enable(struct s3c_udc *dev);
static void udc_set_address(struct s3c_udc *dev, unsigned char address);
-static void reconfig_usbd(void);
+static void reconfig_usbd(struct s3c_udc *dev);
static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed);
static void nuke(struct s3c_ep *ep, int status);
static int s3c_udc_set_halt(struct usb_ep *_ep, int value);
@@ -146,68 +145,14 @@ static struct usb_ep_ops s3c_ep_ops = {
void __iomem *regs_otg;
struct s3c_usbotg_reg *reg;
-struct s3c_usbotg_phy *phy;
-static unsigned int usb_phy_ctrl;
bool dfu_usb_get_reset(void)
{
return !!(readl(&reg->gintsts) & INT_RESET);
}
-void otg_phy_init(struct s3c_udc *dev)
-{
- dev->pdata->phy_control(1);
-
- /*USB PHY0 Enable */
- printf("USB PHY0 Enable\n");
-
- /* Enable PHY */
- writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl);
-
- if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */
- writel((readl(&phy->phypwr)
- &~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN)
- &~FORCE_SUSPEND_0), &phy->phypwr);
- else /* C110 GONI */
- writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN)
- &~FORCE_SUSPEND_0), &phy->phypwr);
-
- if (s5p_cpu_id == 0x4412)
- writel((readl(&phy->phyclk) & ~(EXYNOS4X12_ID_PULLUP0 |
- EXYNOS4X12_COMMON_ON_N0)) | EXYNOS4X12_CLK_SEL_24MHZ,
- &phy->phyclk); /* PLL 24Mhz */
- else
- writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)) |
- CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */
-
- writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST))
- | PHY_SW_RST0, &phy->rstcon);
- udelay(10);
- writel(readl(&phy->rstcon)
- &~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon);
- udelay(10);
-}
-
-void otg_phy_off(struct s3c_udc *dev)
-{
- /* reset controller just in case */
- writel(PHY_SW_RST0, &phy->rstcon);
- udelay(20);
- writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon);
- udelay(20);
-
- writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN
- | FORCE_SUSPEND_0, &phy->phypwr);
-
- writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl);
-
- writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)),
- &phy->phyclk);
-
- udelay(10000);
-
- dev->pdata->phy_control(0);
-}
+__weak void otg_phy_init(struct s3c_udc *dev) {}
+__weak void otg_phy_off(struct s3c_udc *dev) {}
/***********************************************************/
@@ -270,7 +215,7 @@ static int udc_enable(struct s3c_udc *dev)
debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev);
otg_phy_init(dev);
- reconfig_usbd();
+ reconfig_usbd(dev);
debug_cond(DEBUG_SETUP != 0,
"S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n",
@@ -451,15 +396,17 @@ static void stop_activity(struct s3c_udc *dev,
udc_reinit(dev);
}
-static void reconfig_usbd(void)
+static void reconfig_usbd(struct s3c_udc *dev)
{
/* 2. Soft-reset OTG Core and then unreset again. */
int i;
unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
+ uint32_t dflt_gusbcfg;
debug("Reseting OTG controller\n");
- writel(0<<15 /* PHY Low Power Clock sel*/
+ dflt_gusbcfg =
+ 0<<15 /* PHY Low Power Clock sel*/
|1<<14 /* Non-Periodic TxFIFO Rewind Enable*/
|0x5<<10 /* Turnaround time*/
|0<<9 | 0<<8 /* [0:HNP disable,1:HNP enable][ 0:SRP disable*/
@@ -468,8 +415,12 @@ static void reconfig_usbd(void)
|0<<6 /* 0: high speed utmi+, 1: full speed serial*/
|0<<4 /* 0: utmi+, 1:ulpi*/
|1<<3 /* phy i/f 0:8bit, 1:16bit*/
- |0x7<<0, /* HS/FS Timeout**/
- &reg->gusbcfg);
+ |0x7<<0; /* HS/FS Timeout**/
+
+ if (dev->pdata->usb_gusbcfg)
+ dflt_gusbcfg = dev->pdata->usb_gusbcfg;
+
+ writel(dflt_gusbcfg, &reg->gusbcfg);
/* 3. Put the OTG device core in the disconnected state.*/
uTemp = readl(&reg->dctl);
@@ -854,9 +805,7 @@ int s3c_udc_probe(struct s3c_plat_otg_data *pdata)
dev->pdata = pdata;
- phy = (struct s3c_usbotg_phy *)pdata->regs_phy;
reg = (struct s3c_usbotg_reg *)pdata->regs_otg;
- usb_phy_ctrl = pdata->usb_phy_ctrl;
/* regs_otg = (void *)pdata->regs_otg; */
diff --git a/drivers/usb/gadget/s3c_udc_otg_phy.c b/drivers/usb/gadget/s3c_udc_otg_phy.c
new file mode 100644
index 0000000000..f13cb8910a
--- /dev/null
+++ b/drivers/usb/gadget/s3c_udc_otg_phy.c
@@ -0,0 +1,101 @@
+/*
+ * drivers/usb/gadget/s3c_udc_otg.c
+ * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2008 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <linux/list.h>
+#include <malloc.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <asm/io.h>
+
+#include <asm/mach-types.h>
+
+#include "regs-otg.h"
+#include <usb/lin_gadget_compat.h>
+
+#include <usb/s3c_udc.h>
+
+void otg_phy_init(struct s3c_udc *dev)
+{
+ unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl;
+ struct s3c_usbotg_phy *phy =
+ (struct s3c_usbotg_phy *)dev->pdata->regs_phy;
+
+ dev->pdata->phy_control(1);
+
+ /* USB PHY0 Enable */
+ printf("USB PHY0 Enable\n");
+
+ /* Enable PHY */
+ writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+ if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */
+ writel((readl(&phy->phypwr)
+ &~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN)
+ &~FORCE_SUSPEND_0), &phy->phypwr);
+ else /* C110 GONI */
+ writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN)
+ &~FORCE_SUSPEND_0), &phy->phypwr);
+
+ if (s5p_cpu_id == 0x4412)
+ writel((readl(&phy->phyclk) & ~(EXYNOS4X12_ID_PULLUP0 |
+ EXYNOS4X12_COMMON_ON_N0)) | EXYNOS4X12_CLK_SEL_24MHZ,
+ &phy->phyclk); /* PLL 24Mhz */
+ else
+ writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)) |
+ CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */
+
+ writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST))
+ | PHY_SW_RST0, &phy->rstcon);
+ udelay(10);
+ writel(readl(&phy->rstcon)
+ &~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon);
+ udelay(10);
+}
+
+void otg_phy_off(struct s3c_udc *dev)
+{
+ unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl;
+ struct s3c_usbotg_phy *phy =
+ (struct s3c_usbotg_phy *)dev->pdata->regs_phy;
+
+ /* reset controller just in case */
+ writel(PHY_SW_RST0, &phy->rstcon);
+ udelay(20);
+ writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon);
+ udelay(20);
+
+ writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN
+ | FORCE_SUSPEND_0, &phy->phypwr);
+
+ writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+ writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)),
+ &phy->phyclk);
+
+ udelay(10000);
+
+ dev->pdata->phy_control(0);
+}
diff --git a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
index 4f69b22a25..7e7a2c2d90 100644
--- a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
+++ b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
@@ -97,8 +97,8 @@ static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req)
u32 ep_num = ep_index(ep);
buf = req->req.buf + req->req.actual;
- length = min(req->req.length - req->req.actual,
- ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket);
+ length = min_t(u32, req->req.length - req->req.actual,
+ ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket);
ep->len = length;
ep->dma_buf = buf;
@@ -551,7 +551,7 @@ static int s3c_udc_irq(int irq, void *_dev)
debug_cond(DEBUG_ISR,
"\t\tOTG core got reset (%d)!!\n",
reset_available);
- reconfig_usbd();
+ reconfig_usbd(dev);
dev->ep0state = WAIT_FOR_SETUP;
reset_available = 0;
s3c_udc_pre_setup();
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
new file mode 100644
index 0000000000..30d1457638
--- /dev/null
+++ b/drivers/usb/host/Kconfig
@@ -0,0 +1,56 @@
+#
+# USB Host Controller Drivers
+#
+comment "USB Host Controller Drivers"
+
+config USB_XHCI_HCD
+ bool "xHCI HCD (USB 3.0) support"
+ ---help---
+ The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
+ "SuperSpeed" host controller hardware.
+
+config USB_XHCI
+ bool
+ default USB_XHCI_HCD
+ ---help---
+ TODO: rename after most boards switch to Kconfig
+
+if USB_XHCI_HCD
+
+endif
+
+config USB_EHCI_HCD
+ bool "EHCI HCD (USB 2.0) support"
+ ---help---
+ The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
+ "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
+ If your USB host controller supports USB 2.0, you will likely want to
+ configure this Host Controller Driver.
+
+ EHCI controllers are packaged with "companion" host controllers (OHCI
+ or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports
+ will connect to EHCI if the device is high speed, otherwise they
+ connect to a companion controller. If you configure EHCI, you should
+ probably configure the OHCI (for NEC and some other vendors) USB Host
+ Controller Driver or UHCI (for Via motherboards) Host Controller
+ Driver too.
+
+ You may want to read <file:Documentation/usb/ehci.txt>.
+
+config USB_EHCI
+ bool
+ default USB_EHCI_HCD
+ ---help---
+ TODO: rename after most boards switch to Kconfig
+
+if USB_EHCI_HCD
+
+config USB_EHCI_UNIPHIER
+ bool "Support for Panasonic UniPhier on-chip EHCI USB controller"
+ depends on ARCH_UNIPHIER
+ default y
+ ---help---
+ Enables support for the on-chip EHCI controller on Panasonic
+ UniPhier SoCs.
+
+endif
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 1c3592914d..c11b551620 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o
obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
+obj-$(CONFIG_USB_EHCI_UNIPHIER) += ehci-uniphier.o
obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index 2a5bbf5ac0..e8142ac092 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -503,23 +503,23 @@ static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
case 0:
switch (wValue & 0xff00) {
case 0x0100: /* device descriptor */
- len = min3(txlen, sizeof(root_hub_dev_des), wLength);
+ len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
memcpy(buffer, root_hub_dev_des, len);
break;
case 0x0200: /* configuration descriptor */
- len = min3(txlen, sizeof(root_hub_config_des), wLength);
+ len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
memcpy(buffer, root_hub_config_des, len);
break;
case 0x0300: /* string descriptors */
switch (wValue & 0xff) {
case 0x00:
- len = min3(txlen, sizeof(root_hub_str_index0),
- wLength);
+ len = min3(txlen, (int)sizeof(root_hub_str_index0),
+ (int)wLength);
memcpy(buffer, root_hub_str_index0, len);
break;
case 0x01:
- len = min3(txlen, sizeof(root_hub_str_index1),
- wLength);
+ len = min3(txlen, (int)sizeof(root_hub_str_index1),
+ (int)wLength);
memcpy(buffer, root_hub_str_index1, len);
break;
}
@@ -556,7 +556,7 @@ static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
data[10] = data[9];
}
- len = min3(txlen, data[0], wLength);
+ len = min3(txlen, (int)data[0], (int)wLength);
memcpy(buffer, data, len);
break;
default:
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index edd91a84a7..6fdbf5724f 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -85,15 +85,10 @@ static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
}
#endif
-/* Setup the EHCI host controller. */
-static void setup_usb_phy(struct exynos_usb_phy *usb)
+static void exynos5_setup_usb_phy(struct exynos_usb_phy *usb)
{
u32 hsic_ctrl;
- set_usbhost_mode(USB20_PHY_CFG_HOST_LINK_EN);
-
- set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_EN);
-
clrbits_le32(&usb->usbphyctrl0,
HOST_CTRL0_FSEL_MASK |
HOST_CTRL0_COMMONON_N |
@@ -150,8 +145,34 @@ static void setup_usb_phy(struct exynos_usb_phy *usb)
EHCICTRL_ENAINCR16);
}
-/* Reset the EHCI host controller. */
-static void reset_usb_phy(struct exynos_usb_phy *usb)
+static void exynos4412_setup_usb_phy(struct exynos4412_usb_phy *usb)
+{
+ writel(CLK_24MHZ, &usb->usbphyclk);
+
+ clrbits_le32(&usb->usbphyctrl, (PHYPWR_NORMAL_MASK_HSIC0 |
+ PHYPWR_NORMAL_MASK_HSIC1 | PHYPWR_NORMAL_MASK_PHY1 |
+ PHYPWR_NORMAL_MASK_PHY0));
+
+ setbits_le32(&usb->usbphyrstcon, (RSTCON_HOSTPHY_SWRST | RSTCON_SWRST));
+ udelay(10);
+ clrbits_le32(&usb->usbphyrstcon, (RSTCON_HOSTPHY_SWRST | RSTCON_SWRST));
+}
+
+static void setup_usb_phy(struct exynos_usb_phy *usb)
+{
+ set_usbhost_mode(USB20_PHY_CFG_HOST_LINK_EN);
+
+ set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_EN);
+
+ if (cpu_is_exynos5())
+ exynos5_setup_usb_phy(usb);
+ else if (cpu_is_exynos4())
+ if (proid_is_exynos4412())
+ exynos4412_setup_usb_phy((struct exynos4412_usb_phy *)
+ usb);
+}
+
+static void exynos5_reset_usb_phy(struct exynos_usb_phy *usb)
{
u32 hsic_ctrl;
@@ -171,6 +192,24 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
setbits_le32(&usb->hsicphyctrl1, hsic_ctrl);
setbits_le32(&usb->hsicphyctrl2, hsic_ctrl);
+}
+
+static void exynos4412_reset_usb_phy(struct exynos4412_usb_phy *usb)
+{
+ setbits_le32(&usb->usbphyctrl, (PHYPWR_NORMAL_MASK_HSIC0 |
+ PHYPWR_NORMAL_MASK_HSIC1 | PHYPWR_NORMAL_MASK_PHY1 |
+ PHYPWR_NORMAL_MASK_PHY0));
+}
+
+/* Reset the EHCI host controller. */
+static void reset_usb_phy(struct exynos_usb_phy *usb)
+{
+ if (cpu_is_exynos5())
+ exynos5_reset_usb_phy(usb);
+ else if (cpu_is_exynos4())
+ if (proid_is_exynos4412())
+ exynos4412_reset_usb_phy((struct exynos4412_usb_phy *)
+ usb);
set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);
}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 45062e699b..5d4288d38f 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -14,10 +14,15 @@
#include <asm/io.h>
#include <usb/ehci-fsl.h>
#include <hwconfig.h>
-#include <asm/fsl_errata.h>
+#include <fsl_usb.h>
+#include <fdt_support.h>
#include "ehci.h"
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
static void set_txfifothresh(struct usb_ehci *, u32);
/* Check USB PHY clock valid */
@@ -130,8 +135,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
in_le32(&ehci->usbmode);
- if (SVR_SOC_VER(get_svr()) == SVR_T4240 &&
- IS_SVR_REV(get_svr(), 2, 0))
+ if (has_erratum_a007798())
set_txfifothresh(ehci, TXFIFOTHRESH);
return 0;
@@ -159,3 +163,184 @@ static void set_txfifothresh(struct usb_ehci *ehci, u32 txfifo_thresh)
cmd |= TXFIFO_THRESH(txfifo_thresh);
ehci_writel(&ehci->txfilltuning, cmd);
}
+
+#if defined(CONFIG_HAS_FSL_DR_USB) || defined(CONFIG_HAS_FSL_MPH_USB)
+static int fdt_fixup_usb_mode_phy_type(void *blob, const char *mode,
+ const char *phy_type, int start_offset)
+{
+ const char *compat_dr = "fsl-usb2-dr";
+ const char *compat_mph = "fsl-usb2-mph";
+ const char *prop_mode = "dr_mode";
+ const char *prop_type = "phy_type";
+ const char *node_type = NULL;
+ int node_offset;
+ int err;
+
+ node_offset = fdt_node_offset_by_compatible(blob,
+ start_offset, compat_mph);
+ if (node_offset < 0) {
+ node_offset = fdt_node_offset_by_compatible(blob,
+ start_offset,
+ compat_dr);
+ if (node_offset < 0) {
+ printf("WARNING: could not find compatible node: %s",
+ fdt_strerror(node_offset));
+ return -1;
+ }
+ node_type = compat_dr;
+ } else {
+ node_type = compat_mph;
+ }
+
+ if (mode) {
+ err = fdt_setprop(blob, node_offset, prop_mode, mode,
+ strlen(mode) + 1);
+ if (err < 0)
+ printf("WARNING: could not set %s for %s: %s.\n",
+ prop_mode, node_type, fdt_strerror(err));
+ }
+
+ if (phy_type) {
+ err = fdt_setprop(blob, node_offset, prop_type, phy_type,
+ strlen(phy_type) + 1);
+ if (err < 0)
+ printf("WARNING: could not set %s for %s: %s.\n",
+ prop_type, node_type, fdt_strerror(err));
+ }
+
+ return node_offset;
+}
+
+static const char *fdt_usb_get_node_type(void *blob, int start_offset,
+ int *node_offset)
+{
+ const char *compat_dr = "fsl-usb2-dr";
+ const char *compat_mph = "fsl-usb2-mph";
+ const char *node_type = NULL;
+
+ *node_offset = fdt_node_offset_by_compatible(blob, start_offset,
+ compat_mph);
+ if (*node_offset < 0) {
+ *node_offset = fdt_node_offset_by_compatible(blob,
+ start_offset,
+ compat_dr);
+ if (*node_offset < 0) {
+ printf("ERROR: could not find compatible node: %s\n",
+ fdt_strerror(*node_offset));
+ } else {
+ node_type = compat_dr;
+ }
+ } else {
+ node_type = compat_mph;
+ }
+
+ return node_type;
+}
+
+static int fdt_fixup_usb_erratum(void *blob, const char *prop_erratum,
+ int start_offset)
+{
+ int node_offset, err;
+ const char *node_type = NULL;
+
+ node_type = fdt_usb_get_node_type(blob, start_offset, &node_offset);
+ if (!node_type)
+ return -1;
+
+ err = fdt_setprop(blob, node_offset, prop_erratum, NULL, 0);
+ if (err < 0) {
+ printf("ERROR: could not set %s for %s: %s.\n",
+ prop_erratum, node_type, fdt_strerror(err));
+ }
+
+ return node_offset;
+}
+
+void fdt_fixup_dr_usb(void *blob, bd_t *bd)
+{
+ static const char * const modes[] = { "host", "peripheral", "otg" };
+ static const char * const phys[] = { "ulpi", "utmi" };
+ int usb_erratum_a006261_off = -1;
+ int usb_erratum_a007075_off = -1;
+ int usb_erratum_a007792_off = -1;
+ int usb_mode_off = -1;
+ int usb_phy_off = -1;
+ char str[5];
+ int i, j;
+
+ for (i = 1; i <= CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
+ const char *dr_mode_type = NULL;
+ const char *dr_phy_type = NULL;
+ int mode_idx = -1, phy_idx = -1;
+
+ snprintf(str, 5, "%s%d", "usb", i);
+ if (hwconfig(str)) {
+ for (j = 0; j < ARRAY_SIZE(modes); j++) {
+ if (hwconfig_subarg_cmp(str, "dr_mode",
+ modes[j])) {
+ mode_idx = j;
+ break;
+ }
+ }
+
+ for (j = 0; j < ARRAY_SIZE(phys); j++) {
+ if (hwconfig_subarg_cmp(str, "phy_type",
+ phys[j])) {
+ phy_idx = j;
+ break;
+ }
+ }
+
+ if (mode_idx < 0 && phy_idx < 0) {
+ printf("WARNING: invalid phy or mode\n");
+ return;
+ }
+
+ if (mode_idx > -1)
+ dr_mode_type = modes[mode_idx];
+
+ if (phy_idx > -1)
+ dr_phy_type = phys[phy_idx];
+ }
+
+ usb_mode_off = fdt_fixup_usb_mode_phy_type(blob,
+ dr_mode_type, NULL,
+ usb_mode_off);
+
+ if (usb_mode_off < 0)
+ return;
+
+ usb_phy_off = fdt_fixup_usb_mode_phy_type(blob,
+ NULL, dr_phy_type,
+ usb_phy_off);
+
+ if (usb_phy_off < 0)
+ return;
+
+ if (has_erratum_a006261()) {
+ usb_erratum_a006261_off = fdt_fixup_usb_erratum
+ (blob,
+ "fsl,usb-erratum-a006261",
+ usb_erratum_a006261_off);
+ if (usb_erratum_a006261_off < 0)
+ return;
+ }
+ if (has_erratum_a007075()) {
+ usb_erratum_a007075_off = fdt_fixup_usb_erratum
+ (blob,
+ "fsl,usb-erratum-a007075",
+ usb_erratum_a007075_off);
+ if (usb_erratum_a007075_off < 0)
+ return;
+ }
+ if (has_erratum_a007792()) {
+ usb_erratum_a007792_off = fdt_fixup_usb_erratum
+ (blob,
+ "fsl,usb-erratum-a007792",
+ usb_erratum_a007792_off);
+ if (usb_erratum_a007792_off < 0)
+ return;
+ }
+ }
+}
+#endif
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 936d006ba4..bc7606646b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -910,7 +910,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
}
mdelay(1);
- len = min3(srclen, le16_to_cpu(req->length), length);
+ len = min3(srclen, (int)le16_to_cpu(req->length), length);
if (srcptr != NULL && len > 0)
memcpy(buffer, srcptr, len);
else
@@ -971,7 +971,6 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
qh_list->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);
qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) |
QH_ENDPT1_EPS(USB_SPEED_HIGH));
- qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
qh_list->qh_overlay.qt_token =
@@ -1097,6 +1096,7 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
}
struct int_queue {
+ int elementsize;
struct QH *first;
struct QH *current;
struct QH *last;
@@ -1154,6 +1154,23 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
struct int_queue *result = NULL;
int i;
+ /*
+ * Interrupt transfers requiring several transactions are not supported
+ * because bInterval is ignored.
+ *
+ * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2
+ * <= PKT_ALIGN if several qTDs are required, while the USB
+ * specification does not constrain this for interrupt transfers. That
+ * means that ehci_submit_async() would support interrupt transfers
+ * requiring several transactions only as long as the transfer size does
+ * not require more than a single qTD.
+ */
+ if (elementsize > usb_maxpacket(dev, pipe)) {
+ printf("%s: xfers requiring several transactions are not supported.\n",
+ __func__);
+ return NULL;
+ }
+
debug("Enter create_int_queue\n");
if (usb_pipetype(pipe) != PIPE_INTERRUPT) {
debug("non-interrupt pipe (type=%lu)", usb_pipetype(pipe));
@@ -1174,6 +1191,7 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
debug("ehci intr queue: out of memory\n");
goto fail1;
}
+ result->elementsize = elementsize;
result->first = memalign(USB_DMA_MINALIGN,
sizeof(struct QH) * queuesize);
if (!result->first) {
@@ -1249,9 +1267,11 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
ALIGN_END_ADDR(struct qTD, result->tds,
queuesize));
- if (disable_periodic(ctrl) < 0) {
- debug("FATAL: periodic should never fail, but did");
- goto fail3;
+ if (ctrl->periodic_schedules > 0) {
+ if (disable_periodic(ctrl) < 0) {
+ debug("FATAL: periodic should never fail, but did");
+ goto fail3;
+ }
}
/* hook up to periodic list */
@@ -1308,13 +1328,18 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
queue->current++;
else
queue->current = NULL;
+
+ invalidate_dcache_range((uint32_t)cur->buffer,
+ ALIGN_END_ADDR(char, cur->buffer,
+ queue->elementsize));
+
debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
hc32_to_cpu(cur_td->qt_token), cur, queue->first);
return cur->buffer;
}
/* Do not free buffers associated with QHs, they're owned by someone else */
-static int
+int
destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
{
struct ehci_ctrl *ctrl = dev->controller;
@@ -1373,24 +1398,9 @@ 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);
- /*
- * Interrupt transfers requiring several transactions are not supported
- * because bInterval is ignored.
- *
- * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2
- * <= PKT_ALIGN if several qTDs are required, while the USB
- * specification does not constrain this for interrupt transfers. That
- * means that ehci_submit_async() would support interrupt transfers
- * requiring several transactions only as long as the transfer size does
- * not require more than a single qTD.
- */
- if (length > usb_maxpacket(dev, pipe)) {
- printf("%s: Interrupt transfers requiring several "
- "transactions are not supported.\n", __func__);
- return -1;
- }
-
queue = create_int_queue(dev, pipe, 1, length, buffer);
+ if (!queue)
+ return -1;
timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
while ((backbuffer = poll_int_queue(dev, queue)) == NULL)
@@ -1406,9 +1416,6 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return -EINVAL;
}
- invalidate_dcache_range((uint32_t)buffer,
- ALIGN_END_ADDR(char, buffer, length));
-
ret = destroy_int_queue(dev, queue);
if (ret < 0)
return ret;
diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c
index 9ec5a0a539..951dd3b25f 100644
--- a/drivers/usb/host/ehci-mx6.c
+++ b/drivers/usb/host/ehci-mx6.c
@@ -160,7 +160,7 @@ static int usb_phy_enable(int index, struct usb_ehci *ehci)
val |= (USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3);
__raw_writel(val, phy_ctrl);
- return val & USBPHY_CTRL_OTG_ID;
+ return 0;
}
/* Base address for this IP block is 0x02184800 */
@@ -193,6 +193,28 @@ static void usb_oc_config(int index)
__raw_writel(val, ctrl);
}
+int usb_phy_mode(int port)
+{
+ void __iomem *phy_reg;
+ void __iomem *phy_ctrl;
+ u32 val;
+
+ phy_reg = (void __iomem *)phy_bases[port];
+ phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
+
+ val = __raw_readl(phy_ctrl);
+
+ if (val & USBPHY_CTRL_OTG_ID)
+ return USB_INIT_DEVICE;
+ else
+ return USB_INIT_HOST;
+}
+
+int __weak board_usb_phy_mode(int port)
+{
+ return usb_phy_mode(port);
+}
+
int __weak board_ehci_hcd_init(int port)
{
return 0;
@@ -221,7 +243,8 @@ int ehci_hcd_init(int index, enum usb_init_type init,
usb_power_config(index);
usb_oc_config(index);
usb_internal_phy_clock_gate(index, 1);
- type = usb_phy_enable(index, ehci) ? USB_INIT_DEVICE : USB_INIT_HOST;
+ usb_phy_enable(index, ehci);
+ type = board_usb_phy_mode(index);
*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
diff --git a/drivers/usb/host/ehci-rmobile.c b/drivers/usb/host/ehci-rmobile.c
index 0d1a726d35..7fe79efc17 100644
--- a/drivers/usb/host/ehci-rmobile.c
+++ b/drivers/usb/host/ehci-rmobile.c
@@ -13,22 +13,18 @@
#include "ehci.h"
#if defined(CONFIG_R8A7740)
-static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
+static u32 usb_base_address[] = {
0xC6700000
};
#elif defined(CONFIG_R8A7790)
-static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
+static u32 usb_base_address[] = {
0xEE080000, /* USB0 (EHCI) */
0xEE0A0000, /* USB1 */
0xEE0C0000, /* USB2 */
};
-#elif defined(CONFIG_R8A7791)
-static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
- 0xEE080000, /* USB0 (EHCI) */
- 0xEE0C0000, /* USB1 */
-};
-#elif defined(CONFIG_R8A7794)
-static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = {
+#elif defined(CONFIG_R8A7791) || defined(CONFIG_R8A7793) || \
+ defined(CONFIG_R8A7794)
+static u32 usb_base_address[] = {
0xEE080000, /* USB0 (EHCI) */
0xEE0C0000, /* USB1 */
};
@@ -57,7 +53,7 @@ int ehci_hcd_stop(int index)
if (!i)
printf("error : ehci(%d) reset failed.\n", index);
- if (index == (CONFIG_USB_MAX_CONTROLLER_COUNT - 1))
+ if (index == (ARRAY_SIZE(usb_base_address) - 1))
setbits_le32(SMSTPCR7, SMSTPCR703);
return 0;
diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c
index 23617b7adc..eda9f698d9 100644
--- a/drivers/usb/host/ehci-sunxi.c
+++ b/drivers/usb/host/ehci-sunxi.c
@@ -9,168 +9,23 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-#include <asm/arch/clock.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
+#include <asm/arch/usbc.h>
#include <common.h>
#include "ehci.h"
-#define SUNXI_USB1_IO_BASE 0x01c14000
-#define SUNXI_USB2_IO_BASE 0x01c1c000
-
-#define SUNXI_USB_PMU_IRQ_ENABLE 0x800
-#define SUNXI_USB_CSR 0x01c13404
-#define SUNXI_USB_PASSBY_EN 1
-
-#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
-#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
-#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
-#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
-
-static struct sunxi_ehci_hcd {
- struct usb_hcd *hcd;
- int usb_rst_mask;
- int ahb_clk_mask;
- int gpio_vbus;
- void *csr;
- int irq;
- int id;
-} sunxi_echi_hcd[] = {
- {
- .usb_rst_mask = CCM_USB_CTRL_PHY1_RST,
- .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
- .gpio_vbus = CONFIG_SUNXI_USB_VBUS0_GPIO,
- .csr = (void *)SUNXI_USB_CSR,
- .irq = 39,
- .id = 1,
- },
-#if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1)
- {
- .usb_rst_mask = CCM_USB_CTRL_PHY2_RST,
- .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1,
- .gpio_vbus = CONFIG_SUNXI_USB_VBUS1_GPIO,
- .csr = (void *)SUNXI_USB_CSR,
- .irq = 40,
- .id = 2,
- }
-#endif
-};
-
-static int enabled_hcd_count;
-
-static void *get_io_base(int hcd_id)
-{
- if (hcd_id == 1)
- return (void *)SUNXI_USB1_IO_BASE;
- else if (hcd_id == 2)
- return (void *)SUNXI_USB2_IO_BASE;
- else
- return NULL;
-}
-
-static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci, int addr,
- int data, int len)
-{
- int j = 0, usbc_bit = 0;
- void *dest = sunxi_ehci->csr;
-
- usbc_bit = 1 << (sunxi_ehci->id * 2);
- for (j = 0; j < len; j++) {
- /* set the bit address to be written */
- clrbits_le32(dest, 0xff << 8);
- setbits_le32(dest, (addr + j) << 8);
-
- clrbits_le32(dest, usbc_bit);
- /* set data bit */
- if (data & 0x1)
- setbits_le32(dest, 1 << 7);
- else
- clrbits_le32(dest, 1 << 7);
-
- setbits_le32(dest, usbc_bit);
-
- clrbits_le32(dest, usbc_bit);
-
- data >>= 1;
- }
-}
-
-static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci)
-{
- /* The following comments are machine
- * translated from Chinese, you have been warned!
- */
-
- /* adjust PHY's magnitude and rate */
- usb_phy_write(sunxi_ehci, 0x20, 0x14, 5);
-
- /* threshold adjustment disconnect */
-#ifdef CONFIG_SUN4I
- usb_phy_write(sunxi_ehci, 0x2a, 3, 2);
-#else
- usb_phy_write(sunxi_ehci, 0x2a, 2, 2);
-#endif
-
- return;
-}
-
-static void sunxi_usb_passby(struct sunxi_ehci_hcd *sunxi_ehci, int enable)
-{
- unsigned long bits = 0;
- void *addr = get_io_base(sunxi_ehci->id) + SUNXI_USB_PMU_IRQ_ENABLE;
-
- bits = SUNXI_EHCI_AHB_ICHR8_EN |
- SUNXI_EHCI_AHB_INCR4_BURST_EN |
- SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
- SUNXI_EHCI_ULPI_BYPASS_EN;
-
- if (enable)
- setbits_le32(addr, bits);
- else
- clrbits_le32(addr, bits);
-
- return;
-}
-
-static void sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci)
-{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-
- setbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
- setbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
-
- sunxi_usb_phy_init(sunxi_ehci);
-
- sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN);
-
- gpio_direction_output(sunxi_ehci->gpio_vbus, 1);
-}
-
-static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci)
-{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-
- gpio_direction_output(sunxi_ehci->gpio_vbus, 0);
-
- sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN);
-
- clrbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
- clrbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
-}
-
int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
struct ehci_hcor **hcor)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
+ int err;
- /* enable common PHY only once */
- if (index == 0)
- setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
+ err = sunxi_usbc_request_resources(index + 1);
+ if (err)
+ return err;
- sunxi_ehci_enable(sunxi_ehci);
+ sunxi_usbc_enable(index + 1);
+ sunxi_usbc_vbus_enable(index + 1);
- *hccr = get_io_base(sunxi_ehci->id);
+ *hccr = sunxi_usbc_get_io_base(index + 1);
*hcor = (struct ehci_hcor *)((uint32_t) *hccr
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
@@ -179,23 +34,13 @@ int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
- enabled_hcd_count++;
-
return 0;
}
int ehci_hcd_stop(int index)
{
- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
-
- sunxi_ehci_disable(sunxi_ehci);
-
- /* disable common PHY only once, for the last enabled hcd */
- if (enabled_hcd_count == 1)
- clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
+ sunxi_usbc_vbus_disable(index + 1);
+ sunxi_usbc_disable(index + 1);
- enabled_hcd_count--;
-
- return 0;
+ return sunxi_usbc_free_resources(index + 1);
}
diff --git a/drivers/usb/host/ehci-uniphier.c b/drivers/usb/host/ehci-uniphier.c
new file mode 100644
index 0000000000..32a4375279
--- /dev/null
+++ b/drivers/usb/host/ehci-uniphier.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ * Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <usb.h>
+#include <asm/arch/ehci-uniphier.h>
+#include "ehci.h"
+
+#ifdef CONFIG_OF_CONTROL
+#include <fdtdec.h>
+DECLARE_GLOBAL_DATA_PTR;
+
+#define FDT gd->fdt_blob
+#define COMPAT "panasonic,uniphier-ehci"
+
+static int get_uniphier_ehci_base(int index, struct ehci_hccr **base)
+{
+ int offset;
+
+ for (offset = fdt_node_offset_by_compatible(FDT, 0, COMPAT);
+ offset >= 0;
+ offset = fdt_node_offset_by_compatible(FDT, offset, COMPAT)) {
+ if (index == 0) {
+ *base = (struct ehci_hccr *)
+ fdtdec_get_addr(FDT, offset, "reg");
+ return 0;
+ }
+ index--;
+ }
+
+ return -ENODEV; /* not found */
+}
+#else
+static int get_uniphier_ehci_base(int index, struct ehci_hccr **base)
+{
+ *base = (struct ehci_hccr *)uniphier_ehci_platdata[index].base;
+ return 0;
+}
+#endif
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
+ struct ehci_hcor **hcor)
+{
+ int ret;
+ struct ehci_hccr *cr;
+ struct ehci_hcor *or;
+
+ uniphier_ehci_reset(index, 0);
+
+ ret = get_uniphier_ehci_base(index, &cr);
+ if (ret < 0)
+ return ret;
+ or = (void *)cr + HC_LENGTH(ehci_readl(&cr->cr_capbase));
+
+ *hccr = cr;
+ *hcor = or;
+
+ return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+ uniphier_ehci_reset(index, 1);
+
+ return 0;
+}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 433e703da8..79aecd414e 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -47,9 +47,9 @@ struct ehci_hcor {
uint32_t or_usbcmd;
#define CMD_PARK (1 << 11) /* enable "park" */
#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */
-#define CMD_ASE (1 << 5) /* async schedule enable */
#define CMD_LRESET (1 << 7) /* partial reset */
-#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */
+#define CMD_IAAD (1 << 6) /* "doorbell" interrupt */
+#define CMD_ASE (1 << 5) /* async schedule enable */
#define CMD_PSE (1 << 4) /* periodic schedule enable */
#define CMD_RESET (1 << 1) /* reset HC not bus */
#define CMD_RUN (1 << 0) /* start/stop HC */
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 46e4cee1d0..0556f328e4 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -103,12 +103,6 @@ static int rh_devnum; /* address of Root Hub endpoint */
/* ------------------------------------------------------------------------- */
-#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
-#define min_t(type,x,y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
-
-/* ------------------------------------------------------------------------- */
-
static int isp116x_reset(struct isp116x *isp116x);
/* --- Debugging functions ------------------------------------------------- */
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index dc0a4e3179..97a7edeb53 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -47,7 +47,7 @@
#include <asm/arch/hardware.h> /* needed for AT91_USB_HOST_BASE */
#endif
-#if defined(CONFIG_ARM920T) || \
+#if defined(CONFIG_CPU_ARM920T) || \
defined(CONFIG_S3C24X0) || \
defined(CONFIG_440EP) || \
defined(CONFIG_PCI_OHCI) || \
@@ -65,9 +65,6 @@
#define OHCI_CONTROL_INIT \
(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-
#ifdef CONFIG_PCI_OHCI
static struct pci_device_id ohci_pci_ids[] = {
{0x10b9, 0x5237}, /* ULI1575 PCI OHCI module ids */
diff --git a/drivers/usb/host/ohci-s3c24xx.c b/drivers/usb/host/ohci-s3c24xx.c
index 3c659c60c9..8bb2275c09 100644
--- a/drivers/usb/host/ohci-s3c24xx.c
+++ b/drivers/usb/host/ohci-s3c24xx.c
@@ -35,9 +35,6 @@
#define OHCI_CONTROL_INIT \
(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
-
#undef DEBUG
#ifdef DEBUG
#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 511454479b..6f33456c90 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -550,9 +550,6 @@ static int check_usb_device_connecting(struct r8a66597 *r8a66597)
return -1; /* fail */
}
-/* based on usb_ohci.c */
-#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
/*-------------------------------------------------------------------------*
* Virtual Root Hub
*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 19c3ec6211..b5aade988d 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -511,7 +511,7 @@ static void record_transfer_result(struct usb_device *udev,
union xhci_trb *event, int length)
{
udev->act_len = min(length, length -
- EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len)));
+ (int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len)));
switch (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))) {
case COMP_SUCCESS:
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 59dc096b0c..87f2972cb2 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -829,7 +829,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
debug("scrlen = %d\n req->length = %d\n",
srclen, le16_to_cpu(req->length));
- len = min(srclen, le16_to_cpu(req->length));
+ len = min(srclen, (int)le16_to_cpu(req->length));
if (srcptr != NULL && len > 0)
memcpy(buffer, srcptr, len);
diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h
index 02b9adcbe4..0c8e75d46c 100644
--- a/drivers/usb/musb/musb_hcd.h
+++ b/drivers/usb/musb/musb_hcd.h
@@ -37,9 +37,6 @@ extern unsigned char new[];
((readb(&musbr->power) & MUSB_POWER_HSMODE) \
>> MUSB_POWER_HSMODE_SHIFT)
-#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
-
/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
/* destination of request */
diff --git a/drivers/usb/phy/omap_usb_phy.c b/drivers/usb/phy/omap_usb_phy.c
index f78d532966..52a3664b99 100644
--- a/drivers/usb/phy/omap_usb_phy.c
+++ b/drivers/usb/phy/omap_usb_phy.c
@@ -118,7 +118,6 @@ void usb_phy_power(int on)
void omap_usb3_phy_init(struct omap_usb3_phy *phy_regs)
{
omap_usb_dpll_lock(phy_regs);
-
usb3_phy_partial_powerup(phy_regs);
/*
* Give enough time for the PHY to partially power-up before
@@ -126,7 +125,6 @@ void omap_usb3_phy_init(struct omap_usb3_phy *phy_regs)
* team.
*/
mdelay(100);
- usb3_phy_power(1);
}
static void omap_enable_usb3_phy(struct omap_xhci *omap)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e69de29bb2..fdbf3f64f2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -0,0 +1,8 @@
+config VIDEO_X86
+ bool "Enable x86 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.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 14a6781edc..42b1eaaf76 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -39,8 +39,10 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o
obj-$(CONFIG_VIDEO_SED13806) += sed13806.o
obj-$(CONFIG_VIDEO_SM501) += sm501.o
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_FORMIKE) += formike.o
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
obj-$(CONFIG_VIDEO_PARADE) += parade.o
diff --git a/drivers/video/ati_radeon_fb.c b/drivers/video/ati_radeon_fb.c
index 38d2eb107e..574895155d 100644
--- a/drivers/video/ati_radeon_fb.c
+++ b/drivers/video/ati_radeon_fb.c
@@ -19,6 +19,7 @@
#include <common.h>
#include <command.h>
+#include <bios_emul.h>
#include <pci.h>
#include <asm/processor.h>
#include <asm/errno.h>
@@ -39,11 +40,6 @@
#define DPRINT(x...) do{}while(0)
#endif
-#ifndef min_t
-#define min_t(type,x,y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-#endif
-
#define MAX_MAPPED_VRAM (2048*2048*4)
#define MIN_MAPPED_VRAM (1024*768*1)
@@ -549,7 +545,6 @@ void radeon_setmode_9200(int vesa_idx, int bpp)
}
#include "../bios_emulator/include/biosemu.h"
-extern int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp);
int radeon_probe(struct radeonfb_info *rinfo)
{
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 6aa50cb4f9..a653bb4168 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -1160,10 +1160,19 @@ static void video_putc(struct stdio_dev *dev, const char c)
static void video_puts(struct stdio_dev *dev, const char *s)
{
+ int flush = cfb_do_flush_cache;
int count = strlen(s);
+ /* temporarily disable cache flush */
+ cfb_do_flush_cache = 0;
+
while (count--)
video_putc(dev, *s++);
+
+ if (flush) {
+ cfb_do_flush_cache = flush;
+ flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
+ }
}
/*
@@ -1532,14 +1541,14 @@ int video_display_bitmap(ulong bmp_image, int x, int y)
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
if (x == BMP_ALIGN_CENTER)
- x = max(0, (VIDEO_VISIBLE_COLS - width) / 2);
+ x = max(0, (int)(VIDEO_VISIBLE_COLS - width) / 2);
else if (x < 0)
- x = max(0, VIDEO_VISIBLE_COLS - width + x + 1);
+ x = max(0, (int)(VIDEO_VISIBLE_COLS - width + x + 1));
if (y == BMP_ALIGN_CENTER)
- y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2);
+ y = max(0, (int)(VIDEO_VISIBLE_ROWS - height) / 2);
else if (y < 0)
- y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1);
+ y = max(0, (int)(VIDEO_VISIBLE_ROWS - height + y + 1));
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
/*
@@ -1865,14 +1874,14 @@ static void plot_logo_or_black(void *screen, int width, int x, int y, int black)
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
if (x == BMP_ALIGN_CENTER)
- x = max(0, (VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2);
+ x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2);
else if (x < 0)
- x = max(0, VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1);
+ x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1));
if (y == BMP_ALIGN_CENTER)
- y = max(0, (VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2);
+ y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2);
else if (y < 0)
- y = max(0, VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1);
+ y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1));
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
dest = (unsigned char *)screen + (y * width + x) * VIDEO_PIXEL_SIZE;
@@ -2019,7 +2028,7 @@ static void *video_logo(void)
* we need to adjust the logo height
*/
if (video_logo_ypos == BMP_ALIGN_CENTER)
- video_logo_height += max(0, (VIDEO_VISIBLE_ROWS - \
+ video_logo_height += max(0, (int)(VIDEO_VISIBLE_ROWS -
VIDEO_LOGO_HEIGHT) / 2);
else if (video_logo_ypos > 0)
video_logo_height += video_logo_ypos;
diff --git a/drivers/video/mpc8xx_lcd.c b/drivers/video/mpc8xx_lcd.c
index 2bc3ceb418..50eed89d09 100644
--- a/drivers/video/mpc8xx_lcd.c
+++ b/drivers/video/mpc8xx_lcd.c
@@ -412,59 +412,6 @@ void lcd_enable (void)
/* Enable the LCD panel */
immr->im_siu_conf.sc_sdcr |= (1 << (31 - 25)); /* LAM = 1 */
lcdp->lcd_lccr |= LCCR_PON;
-
-#if defined(CONFIG_LWMON)
- { uchar c = pic_read (0x60);
-#if defined(CONFIG_LCD) && defined(CONFIG_LWMON) && (CONFIG_POST & CONFIG_SYS_POST_SYSMON)
- /* Enable LCD later in sysmon test, only if temperature is OK */
-#else
- c |= 0x07; /* Power on CCFL, Enable CCFL, Chip Enable LCD */
-#endif
- pic_write (0x60, c);
- }
-#endif /* CONFIG_LWMON */
-
-#if defined(CONFIG_R360MPI)
- {
- extern void r360_i2c_lcd_write (uchar data0, uchar data1);
- unsigned long bgi, ctr;
- char *p;
-
- if ((p = getenv("lcdbgi")) != NULL) {
- bgi = simple_strtoul (p, 0, 10) & 0xFFF;
- } else {
- bgi = 0xFFF;
- }
-
- if ((p = getenv("lcdctr")) != NULL) {
- ctr = simple_strtoul (p, 0, 10) & 0xFFF;
- } else {
- ctr=0x7FF;
- }
-
- r360_i2c_lcd_write(0x10, 0x01);
- r360_i2c_lcd_write(0x20, 0x01);
- r360_i2c_lcd_write(0x30 | ((bgi>>8) & 0xF), bgi & 0xFF);
- r360_i2c_lcd_write(0x40 | ((ctr>>8) & 0xF), ctr & 0xFF);
- }
-#endif /* CONFIG_R360MPI */
-#ifdef CONFIG_RRVISION
- debug ("PC4->Output(1): enable LVDS\n");
- debug ("PC5->Output(0): disable PAL clock\n");
- immr->im_ioport.iop_pddir |= 0x1000;
- immr->im_ioport.iop_pcpar &= ~(0x0C00);
- immr->im_ioport.iop_pcdir |= 0x0C00 ;
- immr->im_ioport.iop_pcdat |= 0x0800 ;
- immr->im_ioport.iop_pcdat &= ~(0x0400);
- debug ("PDPAR=0x%04X PDDIR=0x%04X PDDAT=0x%04X\n",
- immr->im_ioport.iop_pdpar,
- immr->im_ioport.iop_pddir,
- immr->im_ioport.iop_pddat);
- debug ("PCPAR=0x%04X PCDIR=0x%04X PCDAT=0x%04X\n",
- immr->im_ioport.iop_pcpar,
- immr->im_ioport.iop_pcdir,
- immr->im_ioport.iop_pcdat);
-#endif
}
/************************************************************************/
diff --git a/drivers/video/smiLynxEM.c b/drivers/video/smiLynxEM.c
index 614bcb3c92..1880cccac2 100644
--- a/drivers/video/smiLynxEM.c
+++ b/drivers/video/smiLynxEM.c
@@ -131,9 +131,6 @@ static char SMI_PCR [] = {
};
static char SMI_MCR[] = {
0x60, 0x01, 0x61, 0x00,
-#ifdef CONFIG_HMI1001
- 0x62, 0x74, /* Memory type is not configured by pins on HMI1001 */
-#endif
};
static char SMI_HCR[] = {
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
new file mode 100644
index 0000000000..d92dfa8863
--- /dev/null
+++ b/drivers/video/sunxi_display.c
@@ -0,0 +1,1074 @@
+/*
+ * Display driver for Allwinner SoCs.
+ *
+ * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/display.h>
+#include <asm/arch/gpio.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <video_fb.h>
+#include "videomodes.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum sunxi_monitor {
+ sunxi_monitor_none,
+ sunxi_monitor_dvi,
+ sunxi_monitor_hdmi,
+ sunxi_monitor_lcd,
+ sunxi_monitor_vga,
+};
+#define SUNXI_MONITOR_LAST sunxi_monitor_vga
+
+struct sunxi_display {
+ GraphicDevice graphic_device;
+ enum sunxi_monitor monitor;
+ unsigned int depth;
+} sunxi_display;
+
+#ifdef CONFIG_VIDEO_HDMI
+
+/*
+ * Wait up to 200ms for value to be set in given part of reg.
+ */
+static int await_completion(u32 *reg, u32 mask, u32 val)
+{
+ unsigned long tmo = timer_get_us() + 200000;
+
+ while ((readl(reg) & mask) != val) {
+ if (timer_get_us() > tmo) {
+ printf("DDC: timeout reading EDID\n");
+ return -ETIME;
+ }
+ }
+ return 0;
+}
+
+static int sunxi_hdmi_hpd_detect(int hpd_delay)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+ unsigned long tmo = timer_get_us() + hpd_delay * 1000;
+
+ /* Set pll3 to 300MHz */
+ clock_set_pll3(300000000);
+
+ /* Set hdmi parent to pll3 */
+ clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
+ CCM_HDMI_CTRL_PLL3);
+
+ /* Set ahb gating to pass */
+#ifdef CONFIG_MACH_SUN6I
+ setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
+#endif
+ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
+
+ /* Clock on */
+ setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
+
+ writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
+ writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
+
+ while (timer_get_us() < tmo) {
+ if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void sunxi_hdmi_shutdown(void)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+
+ clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
+ clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
+ clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
+#ifdef CONFIG_MACH_SUN6I
+ clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
+#endif
+ clock_set_pll3(0);
+}
+
+static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
+{
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+
+ setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
+ writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
+ SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
+ SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
+ SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
+#ifndef CONFIG_MACH_SUN6I
+ writel(n, &hdmi->ddc_byte_count);
+ writel(cmnd, &hdmi->ddc_cmnd);
+#else
+ writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
+#endif
+ setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
+
+ return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
+}
+
+static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
+{
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+ int i, n;
+
+ while (count > 0) {
+ if (count > 16)
+ n = 16;
+ else
+ n = count;
+
+ if (sunxi_hdmi_ddc_do_command(
+ SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
+ offset, n))
+ return -ETIME;
+
+ for (i = 0; i < n; i++)
+ *buf++ = readb(&hdmi->ddc_fifo_data);
+
+ offset += n;
+ count -= n;
+ }
+
+ return 0;
+}
+
+static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
+{
+ int r, retries = 2;
+
+ do {
+ r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
+ if (r)
+ continue;
+ r = edid_check_checksum(buf);
+ if (r) {
+ printf("EDID block %d: checksum error%s\n",
+ block, retries ? ", retrying" : "");
+ }
+ } while (r && retries--);
+
+ return r;
+}
+
+static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
+{
+ struct edid1_info edid1;
+ struct edid_cea861_info cea681[4];
+ struct edid_detailed_timing *t =
+ (struct edid_detailed_timing *)edid1.monitor_details.timing;
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ int i, r, ext_blocks = 0;
+
+ /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
+ writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
+ &hdmi->pad_ctrl1);
+ writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
+ &hdmi->pll_ctrl);
+ writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
+
+ /* Reset i2c controller */
+ setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
+ writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
+ SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
+ SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
+ SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
+ if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
+ return -EIO;
+
+ writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
+#ifndef CONFIG_MACH_SUN6I
+ writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
+ SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
+#endif
+
+ r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
+ if (r == 0) {
+ r = edid_check_info(&edid1);
+ if (r) {
+ printf("EDID: invalid EDID data\n");
+ r = -EINVAL;
+ }
+ }
+ if (r == 0) {
+ ext_blocks = edid1.extension_flag;
+ if (ext_blocks > 4)
+ ext_blocks = 4;
+ for (i = 0; i < ext_blocks; i++) {
+ if (sunxi_hdmi_edid_get_block(1 + i,
+ (u8 *)&cea681[i]) != 0) {
+ ext_blocks = i;
+ break;
+ }
+ }
+ }
+
+ /* Disable DDC engine, no longer needed */
+ clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
+ clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
+
+ if (r)
+ return r;
+
+ /* We want version 1.3 or 1.2 with detailed timing info */
+ if (edid1.version != 1 || (edid1.revision < 3 &&
+ !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
+ printf("EDID: unsupported version %d.%d\n",
+ edid1.version, edid1.revision);
+ return -EINVAL;
+ }
+
+ /* Take the first usable detailed timing */
+ for (i = 0; i < 4; i++, t++) {
+ r = video_edid_dtd_to_ctfb_res_modes(t, mode);
+ if (r == 0)
+ break;
+ }
+ if (i == 4) {
+ printf("EDID: no usable detailed timing found\n");
+ return -ENOENT;
+ }
+
+ /* Check for basic audio support, if found enable hdmi output */
+ sunxi_display.monitor = sunxi_monitor_dvi;
+ for (i = 0; i < ext_blocks; i++) {
+ if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
+ cea681[i].revision < 2)
+ continue;
+
+ if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
+ sunxi_display.monitor = sunxi_monitor_hdmi;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_VIDEO_HDMI */
+
+/*
+ * This is the entity that mixes and matches the different layers and inputs.
+ * Allwinner calls it the back-end, but i like composer better.
+ */
+static void sunxi_composer_init(void)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_de_be_reg * const de_be =
+ (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+ int i;
+
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
+ /* Reset off */
+ setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
+#endif
+
+ /* Clocks on */
+ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
+ setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
+ clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
+
+ /* Engine bug, clear registers after reset */
+ for (i = 0x0800; i < 0x1000; i += 4)
+ writel(0, SUNXI_DE_BE0_BASE + i);
+
+ setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
+}
+
+static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
+ unsigned int address)
+{
+ struct sunxi_de_be_reg * const de_be =
+ (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+
+ 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);
+ 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);
+ writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
+
+ setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
+}
+
+static void sunxi_composer_enable(void)
+{
+ struct sunxi_de_be_reg * const de_be =
+ (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
+
+ setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
+ setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
+}
+
+/*
+ * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
+ */
+static void sunxi_lcdc_pll_set(int tcon, int dotclock,
+ int *clk_div, int *clk_double)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ int value, n, m, min_m, max_m, diff;
+ int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
+ int best_double = 0;
+
+ if (tcon == 0) {
+#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
+ min_m = 6;
+ max_m = 127;
+#endif
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ min_m = max_m = 7;
+#endif
+ } else {
+ min_m = 1;
+ max_m = 15;
+ }
+
+ /*
+ * Find the lowest divider resulting in a matching clock, if there
+ * is no match, pick the closest lower clock, as monitors tend to
+ * not sync to higher frequencies.
+ */
+ for (m = min_m; m <= max_m; m++) {
+ n = (m * dotclock) / 3000;
+
+ if ((n >= 9) && (n <= 127)) {
+ value = (3000 * n) / m;
+ diff = dotclock - value;
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_m = m;
+ best_n = n;
+ best_double = 0;
+ }
+ }
+
+ /* These are just duplicates */
+ if (!(m & 1))
+ continue;
+
+ n = (m * dotclock) / 6000;
+ if ((n >= 9) && (n <= 127)) {
+ value = (6000 * n) / m;
+ diff = dotclock - value;
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_m = m;
+ best_n = n;
+ best_double = 1;
+ }
+ }
+ }
+
+ debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
+ dotclock, (best_double + 1) * 3000 * best_n / best_m,
+ best_double + 1, best_n, best_m);
+
+ clock_set_pll3(best_n * 3000000);
+
+ if (tcon == 0) {
+ writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
+ (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
+ CCM_LCD_CH0_CTRL_PLL3),
+ &ccm->lcd0_ch0_clk_cfg);
+ } else {
+ writel(CCM_LCD_CH1_CTRL_GATE |
+ (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
+ CCM_LCD_CH1_CTRL_PLL3) |
+ CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
+ }
+
+ *clk_div = best_m;
+ *clk_double = best_double;
+}
+
+static void sunxi_lcdc_init(void)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_lcdc_reg * const lcdc =
+ (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+
+ /* Reset off */
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
+ setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
+#else
+ setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
+#endif
+
+ /* Clock on */
+ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
+#endif
+
+ /* Init lcdc */
+ writel(0, &lcdc->ctrl); /* Disable tcon */
+ writel(0, &lcdc->int0); /* Disable all interrupts */
+
+ /* Disable tcon0 dot clock */
+ clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
+
+ /* Set all io lines to tristate */
+ writel(0xffffffff, &lcdc->tcon0_io_tristate);
+ writel(0xffffffff, &lcdc->tcon1_io_tristate);
+}
+
+static void sunxi_lcdc_enable(void)
+{
+ struct sunxi_lcdc_reg * const lcdc =
+ (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+
+ setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
+ udelay(2); /* delay at least 1200 ns */
+ setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
+ udelay(1); /* delay at least 120 ns */
+ setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
+ setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
+#endif
+}
+
+static void sunxi_lcdc_panel_enable(void)
+{
+ int pin;
+
+ /*
+ * Start with backlight disabled to avoid the screen flashing to
+ * white while the lcd inits.
+ */
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
+ if (pin != -1) {
+ gpio_request(pin, "lcd_backlight_enable");
+ gpio_direction_output(pin, 0);
+ }
+
+ 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);
+ }
+
+ /* Give the backlight some time to turn off and power up the panel. */
+ mdelay(40);
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
+ if (pin != -1) {
+ gpio_request(pin, "lcd_power");
+ gpio_direction_output(pin, 1);
+ }
+}
+
+static void sunxi_lcdc_backlight_enable(void)
+{
+ int pin;
+
+ /*
+ * We want to have scanned out at least one frame before enabling the
+ * backlight to avoid the screen flashing to white when we enable it.
+ */
+ mdelay(40);
+
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
+ if (pin != -1)
+ 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);
+ }
+}
+
+static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
+{
+ int delay;
+
+ delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
+ return (delay > 30) ? 30 : delay;
+}
+
+static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode)
+{
+ struct sunxi_lcdc_reg * const lcdc =
+ (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+ int bp, clk_delay, clk_div, clk_double, pin, total, val;
+
+ for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
+#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
+ sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0);
+#endif
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0);
+#endif
+
+ sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
+
+ /* Use tcon0 */
+ clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
+ SUNXI_LCDC_CTRL_IO_MAP_TCON0);
+
+ clk_delay = sunxi_lcdc_get_clk_delay(mode);
+ writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
+ SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
+
+ writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
+ SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
+
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ &lcdc->tcon0_timing_active);
+
+ bp = mode->hsync_len + mode->left_margin;
+ total = mode->xres + mode->right_margin + bp;
+ writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
+ SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
+
+ bp = mode->vsync_len + mode->upper_margin;
+ total = mode->yres + mode->lower_margin + bp;
+ writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
+ SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
+
+#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
+ writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
+ &lcdc->tcon0_timing_sync);
+
+ writel(0, &lcdc->tcon0_hv_intf);
+ writel(0, &lcdc->tcon0_cpu_intf);
+#endif
+#ifdef CONFIG_VIDEO_LCD_IF_LVDS
+ val = (sunxi_display.depth == 18) ? 1 : 0;
+ writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf);
+#endif
+
+ if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
+ writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
+ writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
+ writel(((sunxi_display.depth == 18) ?
+ SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
+ SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
+ &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
+ 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;
+ writel(val, &lcdc->tcon0_io_polarity);
+
+ writel(0, &lcdc->tcon0_io_tristate);
+}
+
+#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
+static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
+ int *clk_div, int *clk_double,
+ bool use_portd_hvsync)
+{
+ struct sunxi_lcdc_reg * const lcdc =
+ (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+ int bp, clk_delay, total, val;
+
+ /* Use tcon1 */
+ clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
+ SUNXI_LCDC_CTRL_IO_MAP_TCON1);
+
+ clk_delay = sunxi_lcdc_get_clk_delay(mode);
+ writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
+ SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
+
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ &lcdc->tcon1_timing_source);
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ &lcdc->tcon1_timing_scale);
+ writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
+ &lcdc->tcon1_timing_out);
+
+ bp = mode->hsync_len + mode->left_margin;
+ total = mode->xres + mode->right_margin + bp;
+ writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
+ SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
+
+ bp = mode->vsync_len + mode->upper_margin;
+ total = mode->yres + mode->lower_margin + bp;
+ writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
+ SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
+
+ writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
+ &lcdc->tcon1_timing_sync);
+
+ if (use_portd_hvsync) {
+ sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD0_LCD0);
+ sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD0_LCD0);
+
+ val = 0;
+ 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;
+ writel(val, &lcdc->tcon1_io_polarity);
+
+ clrbits_le32(&lcdc->tcon1_io_tristate,
+ SUNXI_LCDC_TCON_VSYNC_MASK |
+ SUNXI_LCDC_TCON_HSYNC_MASK);
+ }
+ sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
+}
+#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
+
+#ifdef CONFIG_VIDEO_HDMI
+
+static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
+{
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+ u8 checksum = 0;
+ u8 avi_info_frame[17] = {
+ 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ };
+ u8 vendor_info_frame[19] = {
+ 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+ };
+ int i;
+
+ if (mode->pixclock_khz <= 27000)
+ avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
+ else
+ avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
+
+ if (mode->xres * 100 / mode->yres < 156)
+ avi_info_frame[5] |= 0x18; /* 4 : 3 */
+ else
+ avi_info_frame[5] |= 0x28; /* 16 : 9 */
+
+ for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
+ checksum += avi_info_frame[i];
+
+ avi_info_frame[3] = 0x100 - checksum;
+
+ for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
+ writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
+
+ writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
+ writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
+
+ for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
+ writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
+
+ writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
+ writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
+
+ setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
+}
+
+static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
+ int clk_div, int clk_double)
+{
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+ int x, y;
+
+ /* Write clear interrupt status bits */
+ writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
+
+ if (sunxi_display.monitor == sunxi_monitor_hdmi)
+ sunxi_hdmi_setup_info_frames(mode);
+
+ /* Set input sync enable */
+ writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
+
+ /* Init various registers, select pll3 as clock source */
+ writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
+ writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
+ writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
+ writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
+ writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
+
+ /* Setup clk div and doubler */
+ clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
+ SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
+ if (!clk_double)
+ setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
+
+ /* Setup timing registers */
+ writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
+ &hdmi->video_size);
+
+ x = mode->hsync_len + mode->left_margin;
+ y = mode->vsync_len + mode->upper_margin;
+ writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
+
+ x = mode->right_margin;
+ y = mode->lower_margin;
+ writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
+
+ x = mode->hsync_len;
+ y = mode->vsync_len;
+ writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
+
+ if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+ setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
+
+ if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+ setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
+}
+
+static void sunxi_hdmi_enable(void)
+{
+ struct sunxi_hdmi_reg * const hdmi =
+ (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
+
+ udelay(100);
+ setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
+}
+
+#endif /* CONFIG_VIDEO_HDMI */
+
+#ifdef CONFIG_VIDEO_VGA
+
+static void sunxi_vga_mode_set(void)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_tve_reg * const tve =
+ (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
+
+ /* Clock on */
+ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
+
+ /* Set TVE in VGA mode */
+ writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
+ writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
+ writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
+ writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
+}
+
+static void sunxi_vga_enable(void)
+{
+ struct sunxi_tve_reg * const tve =
+ (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
+
+ setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
+}
+
+#endif /* CONFIG_VIDEO_VGA */
+
+static void sunxi_drc_init(void)
+{
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+ /* On sun6i the drc must be clocked even when in pass-through mode */
+ setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
+ clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
+#endif
+}
+
+#ifdef CONFIG_VIDEO_VGA_VIA_LCD
+static void sunxi_vga_external_dac_enable(void)
+{
+ int pin;
+
+ pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
+ if (pin != -1) {
+ gpio_request(pin, "vga_enable");
+ gpio_direction_output(pin, 1);
+ }
+}
+#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
+
+static void sunxi_engines_init(void)
+{
+ sunxi_composer_init();
+ sunxi_lcdc_init();
+ sunxi_drc_init();
+}
+
+static void sunxi_mode_set(const struct ctfb_res_modes *mode,
+ unsigned int address)
+{
+ int __maybe_unused clk_div, clk_double;
+
+ switch (sunxi_display.monitor) {
+ case sunxi_monitor_none:
+ break;
+ case sunxi_monitor_dvi:
+ case sunxi_monitor_hdmi:
+#ifdef CONFIG_VIDEO_HDMI
+ sunxi_composer_mode_set(mode, address);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
+ sunxi_hdmi_mode_set(mode, clk_div, clk_double);
+ sunxi_composer_enable();
+ sunxi_lcdc_enable();
+ sunxi_hdmi_enable();
+#endif
+ break;
+ case sunxi_monitor_lcd:
+ sunxi_lcdc_panel_enable();
+ sunxi_composer_mode_set(mode, address);
+ sunxi_lcdc_tcon0_mode_set(mode);
+ sunxi_composer_enable();
+ sunxi_lcdc_enable();
+ sunxi_lcdc_backlight_enable();
+ break;
+ case sunxi_monitor_vga:
+#ifdef CONFIG_VIDEO_VGA
+ sunxi_composer_mode_set(mode, address);
+ sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
+ sunxi_vga_mode_set();
+ sunxi_composer_enable();
+ sunxi_lcdc_enable();
+ sunxi_vga_enable();
+#elif defined CONFIG_VIDEO_VGA_VIA_LCD
+ sunxi_composer_mode_set(mode, address);
+ sunxi_lcdc_tcon0_mode_set(mode);
+ sunxi_composer_enable();
+ sunxi_lcdc_enable();
+ sunxi_vga_external_dac_enable();
+#endif
+ break;
+ }
+}
+
+static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
+{
+ switch (monitor) {
+ case sunxi_monitor_none: return "none";
+ case sunxi_monitor_dvi: return "dvi";
+ case sunxi_monitor_hdmi: return "hdmi";
+ case sunxi_monitor_lcd: return "lcd";
+ case sunxi_monitor_vga: return "vga";
+ }
+ return NULL; /* never reached */
+}
+
+void *video_hw_init(void)
+{
+ static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+ const struct ctfb_res_modes *mode;
+ struct ctfb_res_modes custom;
+ const char *options;
+#ifdef CONFIG_VIDEO_HDMI
+ int ret, hpd, hpd_delay, edid;
+#endif
+ char mon[16];
+ char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
+ int i;
+
+ memset(&sunxi_display, 0, sizeof(struct sunxi_display));
+
+ printf("Reserved %dkB of RAM for Framebuffer.\n",
+ CONFIG_SUNXI_FB_SIZE >> 10);
+ gd->fb_base = gd->ram_top;
+
+ video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
+ &sunxi_display.depth, &options);
+#ifdef CONFIG_VIDEO_HDMI
+ hpd = video_get_option_int(options, "hpd", 1);
+ hpd_delay = video_get_option_int(options, "hpd_delay", 500);
+ edid = video_get_option_int(options, "edid", 1);
+ sunxi_display.monitor = sunxi_monitor_dvi;
+#elif defined CONFIG_VIDEO_VGA_VIA_LCD
+ sunxi_display.monitor = sunxi_monitor_vga;
+#else
+ sunxi_display.monitor = sunxi_monitor_lcd;
+#endif
+ video_get_option_string(options, "monitor", mon, sizeof(mon),
+ sunxi_get_mon_desc(sunxi_display.monitor));
+ for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
+ if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
+ sunxi_display.monitor = i;
+ break;
+ }
+ }
+ if (i > SUNXI_MONITOR_LAST)
+ printf("Unknown monitor: '%s', falling back to '%s'\n",
+ mon, sunxi_get_mon_desc(sunxi_display.monitor));
+
+#ifdef CONFIG_VIDEO_HDMI
+ /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
+ if (sunxi_display.monitor == sunxi_monitor_dvi ||
+ sunxi_display.monitor == sunxi_monitor_hdmi) {
+ /* Always call hdp_detect, as it also enables clocks, etc. */
+ ret = sunxi_hdmi_hpd_detect(hpd_delay);
+ if (ret) {
+ printf("HDMI connected: ");
+ if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
+ mode = &custom;
+ } else if (hpd) {
+ sunxi_hdmi_shutdown();
+ /* Fallback to lcd / vga / none */
+ if (lcd_mode[0]) {
+ sunxi_display.monitor = sunxi_monitor_lcd;
+ } else {
+#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
+ sunxi_display.monitor = sunxi_monitor_vga;
+#else
+ sunxi_display.monitor = sunxi_monitor_none;
+#endif
+ }
+ } /* else continue with hdmi/dvi without a cable connected */
+ }
+#endif
+
+ switch (sunxi_display.monitor) {
+ case sunxi_monitor_none:
+ return NULL;
+ case sunxi_monitor_dvi:
+ case sunxi_monitor_hdmi:
+#ifdef CONFIG_VIDEO_HDMI
+ break;
+#else
+ printf("HDMI/DVI not supported on this board\n");
+ sunxi_display.monitor = sunxi_monitor_none;
+ return NULL;
+#endif
+ case sunxi_monitor_lcd:
+ if (lcd_mode[0]) {
+ sunxi_display.depth = video_get_params(&custom, lcd_mode);
+ mode = &custom;
+ break;
+ }
+ printf("LCD not supported on this board\n");
+ sunxi_display.monitor = sunxi_monitor_none;
+ return NULL;
+ case sunxi_monitor_vga:
+#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
+ sunxi_display.depth = 18;
+ break;
+#else
+ printf("VGA not supported on this board\n");
+ sunxi_display.monitor = sunxi_monitor_none;
+ return NULL;
+#endif
+ }
+
+ if (mode->vmode != FB_VMODE_NONINTERLACED) {
+ printf("Only non-interlaced modes supported, falling back to 1024x768\n");
+ mode = &res_mode_init[RES_MODE_1024x768];
+ } else {
+ printf("Setting up a %dx%d %s console\n", mode->xres,
+ mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
+ }
+
+ sunxi_engines_init();
+ sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
+
+ /*
+ * These are the only members of this structure that are used. All the
+ * others are driver specific. There is nothing to decribe pitch or
+ * stride, but we are lucky with our hw.
+ */
+ graphic_device->frameAdrs = gd->fb_base;
+ graphic_device->gdfIndex = GDF_32BIT_X888RGB;
+ graphic_device->gdfBytesPP = 4;
+ graphic_device->winSizeX = mode->xres;
+ graphic_device->winSizeY = mode->yres;
+
+ return graphic_device;
+}
+
+/*
+ * Simplefb support.
+ */
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
+int sunxi_simplefb_setup(void *blob)
+{
+ static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
+ int offset, ret;
+ const char *pipeline = NULL;
+
+ switch (sunxi_display.monitor) {
+ case sunxi_monitor_none:
+ return 0;
+ case sunxi_monitor_dvi:
+ case sunxi_monitor_hdmi:
+ pipeline = "de_be0-lcd0-hdmi";
+ break;
+ case sunxi_monitor_lcd:
+ pipeline = "de_be0-lcd0";
+ break;
+ case sunxi_monitor_vga:
+#ifdef CONFIG_VIDEO_VGA
+ pipeline = "de_be0-lcd0-tve0";
+#elif defined CONFIG_VIDEO_VGA_VIA_LCD
+ pipeline = "de_be0-lcd0";
+#endif
+ break;
+ }
+
+ /* Find a prefilled simpefb node, matching out pipeline config */
+ offset = fdt_node_offset_by_compatible(blob, -1,
+ "allwinner,simple-framebuffer");
+ while (offset >= 0) {
+ ret = fdt_find_string(blob, offset, "allwinner,pipeline",
+ pipeline);
+ if (ret == 0)
+ break;
+ offset = fdt_node_offset_by_compatible(blob, offset,
+ "allwinner,simple-framebuffer");
+ }
+ if (offset < 0) {
+ eprintf("Cannot setup simplefb: node not found\n");
+ return 0; /* Keep older kernels working */
+ }
+
+ ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
+ graphic_device->winSizeX, graphic_device->winSizeY,
+ graphic_device->winSizeX * graphic_device->gdfBytesPP,
+ "x8r8g8b8");
+ if (ret)
+ eprintf("Cannot setup simplefb: Error setting properties\n");
+
+ return ret;
+}
+#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
diff --git a/drivers/video/videomodes.c b/drivers/video/videomodes.c
index 18c1f3d8ac..cf71ad120e 100644
--- a/drivers/video/videomodes.c
+++ b/drivers/video/videomodes.c
@@ -58,6 +58,8 @@
****************************************************************************/
#include <common.h>
+#include <edid.h>
+#include <errno.h>
#include <linux/ctype.h>
#include "videomodes.h"
@@ -84,13 +86,26 @@ const struct ctfb_vesa_modes vesa_modes[VESA_MODES_COUNT] = {
{0x31B, RES_MODE_1280x1024, 24},
};
const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
- /* x y pixclk le ri up lo hs vs s vmode */
- {640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED},
- {800, 600, 27778, 64, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED},
- {1024, 768, 15384, 168, 8, 29, 3, 144, 4, 0, FB_VMODE_NONINTERLACED},
- {960, 720, 13100, 160, 40, 32, 8, 80, 4, 0, FB_VMODE_NONINTERLACED},
- {1152, 864, 12004, 200, 64, 32, 16, 80, 4, 0, FB_VMODE_NONINTERLACED},
- {1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, FB_VMODE_NONINTERLACED},
+ /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
+#ifndef CONFIG_VIDEO_STD_TIMINGS
+ { 640, 480, 60, 39721, 25180, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED},
+ { 800, 600, 60, 27778, 36000, 64, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED},
+ {1024, 768, 60, 15384, 65000, 168, 8, 29, 3, 144, 4, 0, FB_VMODE_NONINTERLACED},
+ { 960, 720, 80, 13100, 76335, 160, 40, 32, 8, 80, 4, 0, FB_VMODE_NONINTERLACED},
+ {1152, 864, 60, 12004, 83300, 200, 64, 32, 16, 80, 4, 0, FB_VMODE_NONINTERLACED},
+ {1280, 1024, 60, 9090, 110000, 200, 48, 26, 1, 184, 3, 0, FB_VMODE_NONINTERLACED},
+#else
+ { 640, 480, 60, 39683, 25200, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED},
+ { 800, 600, 60, 25000, 40000, 88, 40, 23, 1, 128, 4, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+ {1024, 768, 60, 15384, 65000, 160, 24, 29, 3, 136, 6, 0, FB_VMODE_NONINTERLACED},
+ { 960, 720, 75, 13468, 74250, 176, 72, 27, 1, 112, 2, 0, FB_VMODE_NONINTERLACED},
+ {1152, 864, 75, 9259, 108000, 256, 64, 32, 1, 128, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+ {1280, 1024, 60, 9259, 108000, 248, 48, 38, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+#endif
+ {1280, 720, 60, 13468, 74250, 220, 110, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+ {1360, 768, 60, 11696, 85500, 256, 64, 17, 3, 112, 7, 0, FB_VMODE_NONINTERLACED},
+ {1920, 1080, 60, 6734, 148500, 148, 88, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
+ {1920, 1200, 60, 6494, 154000, 80, 48, 26, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED},
};
/************************************************************************
@@ -100,7 +115,7 @@ const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
* returns the length to the next seperator
*/
static int
-video_get_param_len (char *start, char sep)
+video_get_param_len(const char *start, char sep)
{
int i = 0;
while ((*start != 0) && (*start != sep)) {
@@ -183,6 +198,7 @@ int video_get_params (struct ctfb_res_modes *pPar, char *penv)
while ((i = video_get_param_len (p, ',')) != 0) {
GET_OPTION ("x:", pPar->xres)
GET_OPTION ("y:", pPar->yres)
+ GET_OPTION ("refresh:", pPar->refresh)
GET_OPTION ("le:", pPar->left_margin)
GET_OPTION ("ri:", pPar->right_margin)
GET_OPTION ("up:", pPar->upper_margin)
@@ -192,6 +208,7 @@ int video_get_params (struct ctfb_res_modes *pPar, char *penv)
GET_OPTION ("sync:", pPar->sync)
GET_OPTION ("vmode:", pPar->vmode)
GET_OPTION ("pclk:", pPar->pixclock)
+ GET_OPTION ("pclk_khz:", pPar->pixclock_khz)
GET_OPTION ("depth:", bpp)
p += i;
if (*p != 0)
@@ -260,3 +277,171 @@ int video_get_video_mode(unsigned int *xres, unsigned int *yres,
return 1;
}
+
+/*
+ * Parse the 'video-mode' environment variable using video_get_video_mode()
+ * and lookup the matching ctfb_res_modes in res_mode_init.
+ *
+ * @default_mode: RES_MODE_##x## define for the mode to store in mode_ret
+ * when 'video-mode' is not set or does not contain a valid mode
+ * @default_depth: depth to set when 'video-mode' is not set
+ * @mode_ret: pointer where the mode will be stored
+ * @depth_ret: pointer where the depth will be stored
+ * @options: pointer to any remaining options, or NULL
+ */
+void video_get_ctfb_res_modes(int default_mode, unsigned int default_depth,
+ const struct ctfb_res_modes **mode_ret,
+ unsigned int *depth_ret,
+ const char **options)
+{
+ unsigned int i, xres, yres, depth, refresh;
+
+ *mode_ret = &res_mode_init[default_mode];
+ *depth_ret = default_depth;
+ *options = NULL;
+
+ if (!video_get_video_mode(&xres, &yres, &depth, &refresh, options))
+ return;
+
+ for (i = 0; i < RES_MODES_COUNT; i++) {
+ if (res_mode_init[i].xres == xres &&
+ res_mode_init[i].yres == yres &&
+ res_mode_init[i].refresh == refresh) {
+ *mode_ret = &res_mode_init[i];
+ *depth_ret = depth;
+ return;
+ }
+ }
+
+ printf("video-mode %dx%d-%d@%d not available, falling back to %dx%d-%d@%d\n",
+ xres, yres, depth, refresh, (*mode_ret)->xres,
+ (*mode_ret)->yres, *depth_ret, (*mode_ret)->refresh);
+}
+
+/*
+ * Find the named string option within the ',' separated options string, and
+ * store its value in dest.
+ *
+ * @options: ',' separated options string
+ * @name: name of the option to look for
+ * @dest: destination buffer to store the value of the option in
+ * @dest_len: length of dest
+ * @def: value to store in dest if the option is not present in options
+ */
+void video_get_option_string(const char *options, const char *name,
+ char *dest, int dest_len, const char *def)
+{
+ const char *p = options;
+ const int name_len = strlen(name);
+ int i, len;
+
+ while (p && (i = video_get_param_len(p, ',')) != 0) {
+ if (strncmp(p, name, name_len) == 0 && p[name_len] == '=') {
+ len = i - (name_len + 1);
+ if (len >= dest_len)
+ len = dest_len - 1;
+ memcpy(dest, &p[name_len + 1], len);
+ dest[len] = 0;
+ return;
+ }
+ p += i;
+ if (*p != 0)
+ p++; /* skip ',' */
+ }
+ strcpy(dest, def);
+}
+
+/*
+ * Find the named integer option within the ',' separated options string, and
+ * return its value.
+ *
+ * @options: ',' separated options string
+ * @name: name of the option to look for
+ * @def: value to return if the option is not present in options
+ */
+int video_get_option_int(const char *options, const char *name, int def)
+{
+ const char *p = options;
+ const int name_len = strlen(name);
+ int i;
+
+ while (p && (i = video_get_param_len(p, ',')) != 0) {
+ if (strncmp(p, name, name_len) == 0 && p[name_len] == '=')
+ return simple_strtoul(&p[name_len + 1], NULL, 10);
+
+ p += i;
+ if (*p != 0)
+ p++; /* skip ',' */
+ }
+ return def;
+}
+
+/**
+ * Convert an EDID detailed timing to a struct ctfb_res_modes
+ *
+ * @param t The EDID detailed timing to be converted
+ * @param mode Returns the converted timing
+ *
+ * @return 0 on success, or a negative errno on error
+ */
+int video_edid_dtd_to_ctfb_res_modes(struct edid_detailed_timing *t,
+ struct ctfb_res_modes *mode)
+{
+ int margin, h_total, v_total;
+
+ /* Check all timings are non 0 */
+ if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) == 0 ||
+ EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*t) == 0 ||
+ EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*t) == 0 ||
+ EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*t) == 0 ||
+ EDID_DETAILED_TIMING_VERTICAL_BLANKING(*t) == 0 ||
+ EDID_DETAILED_TIMING_HSYNC_OFFSET(*t) == 0 ||
+ EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(*t) == 0 ||
+ EDID_DETAILED_TIMING_VSYNC_OFFSET(*t) == 0 ||
+ EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(*t) == 0 ||
+ /* 3d formats are not supported*/
+ EDID_DETAILED_TIMING_FLAG_STEREO(*t) != 0)
+ return -EINVAL;
+
+ mode->xres = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*t);
+ mode->yres = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*t);
+
+ h_total = mode->xres + EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*t);
+ v_total = mode->yres + EDID_DETAILED_TIMING_VERTICAL_BLANKING(*t);
+ mode->refresh = EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) /
+ (h_total * v_total);
+
+ mode->pixclock_khz = EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) / 1000;
+ mode->pixclock = 1000000000L / mode->pixclock_khz;
+
+ mode->right_margin = EDID_DETAILED_TIMING_HSYNC_OFFSET(*t);
+ mode->hsync_len = EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(*t);
+ margin = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*t) -
+ (mode->right_margin + mode->hsync_len);
+ if (margin <= 0)
+ return -EINVAL;
+
+ mode->left_margin = margin;
+
+ mode->lower_margin = EDID_DETAILED_TIMING_VSYNC_OFFSET(*t);
+ mode->vsync_len = EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(*t);
+ margin = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*t) -
+ (mode->lower_margin + mode->vsync_len);
+ if (margin <= 0)
+ return -EINVAL;
+
+ mode->upper_margin = margin;
+
+ mode->sync = 0;
+ if (EDID_DETAILED_TIMING_FLAG_HSYNC_POLARITY(*t))
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (EDID_DETAILED_TIMING_FLAG_VSYNC_POLARITY(*t))
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ if (EDID_DETAILED_TIMING_FLAG_INTERLACED(*t))
+ mode->vmode = FB_VMODE_INTERLACED;
+ else
+ mode->vmode = FB_VMODE_NONINTERLACED;
+
+ return 0;
+}
diff --git a/drivers/video/videomodes.h b/drivers/video/videomodes.h
index d83993a563..82190a2aec 100644
--- a/drivers/video/videomodes.h
+++ b/drivers/video/videomodes.h
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: GPL-2.0+
*/
+#include <edid.h>
#ifndef CONFIG_SYS_DEFAULT_VIDEO_MODE
#define CONFIG_SYS_DEFAULT_VIDEO_MODE 0x301
@@ -35,8 +36,10 @@
struct ctfb_res_modes {
int xres; /* visible resolution */
int yres;
+ int refresh; /* vertical refresh rate in hz */
/* Timing: All values in pixclocks, except pixclock (of course) */
int pixclock; /* pixel clock in ps (pico seconds) */
+ int pixclock_khz; /* pixel clock in kHz */
int left_margin; /* time from sync to picture */
int right_margin; /* time from picture to sync */
int upper_margin; /* time from sync to picture */
@@ -62,7 +65,11 @@ struct ctfb_vesa_modes {
#define RES_MODE_960_720 3
#define RES_MODE_1152x864 4
#define RES_MODE_1280x1024 5
-#define RES_MODES_COUNT 6
+#define RES_MODE_1280x720 6
+#define RES_MODE_1360x768 7
+#define RES_MODE_1920x1080 8
+#define RES_MODE_1920x1200 9
+#define RES_MODES_COUNT 10
#define VESA_MODES_COUNT 19
@@ -73,3 +80,16 @@ int video_get_params (struct ctfb_res_modes *pPar, char *penv);
int video_get_video_mode(unsigned int *xres, unsigned int *yres,
unsigned int *depth, unsigned int *freq, const char **options);
+
+void video_get_ctfb_res_modes(int default_mode, unsigned int default_depth,
+ const struct ctfb_res_modes **mode_ret,
+ unsigned int *depth_ret,
+ const char **options);
+
+void video_get_option_string(const char *options, const char *name,
+ char *dest, int dest_len, const char *def);
+
+int video_get_option_int(const char *options, const char *name, int def);
+
+int video_edid_dtd_to_ctfb_res_modes(struct edid_detailed_timing *t,
+ struct ctfb_res_modes *mode);
diff --git a/drivers/video/x86_fb.c b/drivers/video/x86_fb.c
new file mode 100644
index 0000000000..6641033a5d
--- /dev/null
+++ b/drivers/video/x86_fb.c
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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;
+}