summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/rockchip/clk_rk3399.c1
-rw-r--r--drivers/mtd/nand/spi/Makefile2
-rw-r--r--drivers/mtd/nand/spi/core.c1
-rw-r--r--drivers/mtd/nand/spi/toshiba.c201
-rw-r--r--drivers/mtd/spi/spi-nor-core.c6
-rw-r--r--drivers/mtd/spi/spi-nor-ids.c12
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/dc2114x.c965
-rw-r--r--drivers/net/dwc_eth_qos.c18
-rw-r--r--drivers/net/pcnet.c52
-rw-r--r--drivers/net/rtl8139.c742
-rw-r--r--drivers/net/smc911x.c560
-rw-r--r--drivers/net/smc911x.h157
-rw-r--r--drivers/rng/Kconfig8
-rw-r--r--drivers/rng/Makefile1
-rw-r--r--drivers/rng/rockchip_rng.c224
-rw-r--r--drivers/rtc/pcf2127.c4
-rw-r--r--drivers/spi/cadence_qspi.c33
-rw-r--r--drivers/spi/fsl_qspi.c1577
-rw-r--r--drivers/spi/fsl_qspi.h145
-rw-r--r--drivers/spi/spi-mem.c2
-rw-r--r--drivers/spi/spi-sifive.c178
-rw-r--r--drivers/timer/mtk_timer.c1
-rw-r--r--drivers/video/rockchip/rk3288_mipi.c1
-rw-r--r--drivers/video/rockchip/rk3399_mipi.c1
-rw-r--r--drivers/video/rockchip/rk_edp.c2
-rw-r--r--drivers/video/rockchip/rk_lvds.c13
-rw-r--r--drivers/video/rockchip/rk_mipi.c14
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/mtk_wdt.c1
30 files changed, 2547 insertions, 2378 deletions
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index 1f62376595..d822acace1 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -996,6 +996,7 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
break;
case ACLK_VOP1:
case HCLK_VOP1:
+ case HCLK_SD:
/**
* assigned-clocks handling won't require for vopl, so
* return 0 to satisfy clk_set_defaults during device probe.
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index dd6bacae34..6c65b187e8 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index cd624ec6ae..397dfa4178 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -835,6 +835,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,
+ &toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
};
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
new file mode 100644
index 0000000000..77c25398fc
--- /dev/null
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 exceet electronics GmbH
+ * Copyright (c) 2018 Kontron Electronics GmbH
+ *
+ * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
+ */
+
+#ifndef __UBOOT__
+#include <malloc.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_TOSHIBA 0x98
+#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int tc58cxgxsx_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 0)
+ return -ERANGE;
+
+ region->offset = mtd->oobsize / 2;
+ region->length = mtd->oobsize / 2;
+
+ return 0;
+}
+
+static int tc58cxgxsx_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 0)
+ return -ERANGE;
+
+ /* 2 bytes reserved for BBM */
+ region->offset = 2;
+ region->length = (mtd->oobsize / 2) - 2;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = {
+ .ecc = tc58cxgxsx_ooblayout_ecc,
+ .rfree = tc58cxgxsx_ooblayout_free,
+};
+
+static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ u8 mbf = 0;
+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
+
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ case STATUS_ECC_HAS_BITFLIPS:
+ case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
+ /*
+ * Let's try to retrieve the real maximum number of bitflips
+ * in order to avoid forcing the wear-leveling layer to move
+ * data around if it's not necessary.
+ */
+ if (spi_mem_exec_op(spinand->slave, &op))
+ return nand->eccreq.strength;
+
+ mbf >>= 4;
+
+ if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
+ return nand->eccreq.strength;
+
+ return mbf;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct spinand_info toshiba_spinand_table[] = {
+ /* 3.3V 1Gb */
+ SPINAND_INFO("TC58CVG0S3", 0xC2,
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
+ tc58cxgxsx_ecc_get_status)),
+ /* 3.3V 2Gb */
+ SPINAND_INFO("TC58CVG1S3", 0xCB,
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
+ tc58cxgxsx_ecc_get_status)),
+ /* 3.3V 4Gb */
+ SPINAND_INFO("TC58CVG2S0", 0xCD,
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
+ tc58cxgxsx_ecc_get_status)),
+ /* 3.3V 4Gb */
+ SPINAND_INFO("TC58CVG2S0", 0xED,
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
+ tc58cxgxsx_ecc_get_status)),
+ /* 1.8V 1Gb */
+ SPINAND_INFO("TC58CYG0S3", 0xB2,
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
+ tc58cxgxsx_ecc_get_status)),
+ /* 1.8V 2Gb */
+ SPINAND_INFO("TC58CYG1S3", 0xBB,
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
+ tc58cxgxsx_ecc_get_status)),
+ /* 1.8V 4Gb */
+ SPINAND_INFO("TC58CYG2S0", 0xBD,
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
+ tc58cxgxsx_ecc_get_status)),
+};
+
+static int toshiba_spinand_detect(struct spinand_device *spinand)
+{
+ u8 *id = spinand->id.data;
+ int ret;
+
+ /*
+ * Toshiba SPI NAND read ID needs a dummy byte,
+ * so the first byte in id is garbage.
+ */
+ if (id[1] != SPINAND_MFR_TOSHIBA)
+ return 0;
+
+ ret = spinand_match_and_init(spinand, toshiba_spinand_table,
+ ARRAY_SIZE(toshiba_spinand_table),
+ id[2]);
+ if (ret)
+ return ret;
+
+ return 1;
+}
+
+static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
+ .detect = toshiba_spinand_detect,
+};
+
+const struct spinand_manufacturer toshiba_spinand_manufacturer = {
+ .id = SPINAND_MFR_TOSHIBA,
+ .name = "Toshiba",
+ .ops = &toshiba_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 7b6ad495ac..e840c60f27 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -325,6 +325,7 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
case SNOR_MFR_MICRON:
/* Some Micron need WREN command; all will accept it */
need_wren = true;
+ case SNOR_MFR_ISSI:
case SNOR_MFR_MACRONIX:
case SNOR_MFR_WINBOND:
if (need_wren)
@@ -1246,11 +1247,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
* If page_size is a power of two, the offset can be quickly
* calculated with an AND operation. On the other cases we
* need to do a modulus operation (more expensive).
- * Power of two numbers have only one bit set and we can use
- * the instruction hweight32 to detect if we need to do a
- * modulus (do_div()) or not.
*/
- if (hweight32(nor->page_size) == 1) {
+ if (is_power_of_2(nor->page_size)) {
page_offset = addr & (nor->page_size - 1);
} else {
u64 aux = addr;
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index abdf560e02..e5e7102923 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -135,7 +135,8 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("is25wp128", 0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512,
- SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+ SPI_NOR_4B_OPCODES) },
#endif
#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */
/* Macronix */
@@ -183,8 +184,8 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
- { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_4B_OPCODES) },
- { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, USE_FSR | SPI_NOR_4B_OPCODES) },
+ { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) },
+ { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) },
#endif
#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
/* Spansion/Cypress -- single (large) sector size only, at least
@@ -192,9 +193,10 @@ const struct flash_info spi_nor_ids[] = {
*/
{ INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
- { INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) },
+ { INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ INFO("s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
- { INFO6("s25fl512s", 0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
+ { INFO6("s25fl512s", 0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
+ { INFO6("s25fs512s", 0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ INFO("s25fl512s_256k", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ INFO("s25fl512s_64k", 0x010220, 0x4d01, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ INFO("s25fl512s_512k", 0x010220, 0x4f00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bc518f218d..a2587a29e1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -388,11 +388,13 @@ config SMC911X
if SMC911X
+if !DM_ETH
config SMC911X_BASE
hex "SMC911X Base Address"
help
Define this to hold the physical address
of the device (I/O space)
+endif #DM_ETH
choice
prompt "SMC911X bus width"
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index 43c2253f10..d008696b0f 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -7,24 +7,21 @@
#include <netdev.h>
#include <pci.h>
-#undef DEBUG_SROM
-#undef DEBUG_SROM2
+#define SROM_DLEVEL 0
#undef UPDATE_SROM
-/* PCI Registers.
- */
-#define PCI_CFDA_PSM 0x43
+/* PCI Registers. */
+#define PCI_CFDA_PSM 0x43
#define CFRV_RN 0x000000f0 /* Revision Number */
#define WAKEUP 0x00 /* Power Saving Wakeup */
#define SLEEP 0x80 /* Power Saving Sleep Mode */
-#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */
+#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */
-/* Ethernet chip registers.
- */
+/* Ethernet chip registers. */
#define DE4X5_BMR 0x000 /* Bus Mode Register */
#define DE4X5_TPD 0x008 /* Transmit Poll Demand Reg */
#define DE4X5_RRBA 0x018 /* RX Ring Base Address Reg */
@@ -34,8 +31,7 @@
#define DE4X5_SICR 0x068 /* SIA Connectivity Register */
#define DE4X5_APROM 0x048 /* Ethernet Address PROM */
-/* Register bits.
- */
+/* Register bits. */
#define BMR_SWR 0x00000001 /* Software Reset */
#define STS_TS 0x00700000 /* Transmit Process State */
#define STS_RS 0x000e0000 /* Receive Process State */
@@ -45,8 +41,7 @@
#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */
#define OMR_PM 0x00000080 /* Pass All Multicast */
-/* Descriptor bits.
- */
+/* Descriptor bits. */
#define R_OWN 0x80000000 /* Own Bit */
#define RD_RER 0x02000000 /* Receive End Of Ring */
#define RD_LS 0x00000100 /* Last Descriptor */
@@ -63,12 +58,12 @@
#define SROM_READ_CMD 6
#define SROM_ERASE_CMD 7
-#define SROM_HWADD 0x0014 /* Hardware Address offset in SROM */
+#define SROM_HWADD 0x0014 /* Hardware Address offset in SROM */
#define SROM_RD 0x00004000 /* Read from Boot ROM */
-#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
-#define EE_WRITE_0 0x4801
-#define EE_WRITE_1 0x4805
-#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x4801
+#define EE_WRITE_1 0x4805
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
#define SROM_SR 0x00000800 /* Select Serial ROM when set */
#define DT_IN 0x00000004 /* Serial Data In */
@@ -77,48 +72,14 @@
#define POLL_DEMAND 1
-#ifdef CONFIG_TULIP_FIX_DAVICOM
-#define RESET_DM9102(dev) {\
- unsigned long i;\
- i=INL(dev, 0x0);\
- udelay(1000);\
- OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
- udelay(1000);\
-}
+#if defined(CONFIG_E500)
+#define phys_to_bus(a) (a)
#else
-#define RESET_DE4X5(dev) {\
- int i;\
- i=INL(dev, DE4X5_BMR);\
- udelay(1000);\
- OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
- udelay(1000);\
- OUTL(dev, i, DE4X5_BMR);\
- udelay(1000);\
- for (i=0;i<5;i++) {INL(dev, DE4X5_BMR); udelay(10000);}\
- udelay(1000);\
-}
+#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
#endif
-#define START_DE4X5(dev) {\
- s32 omr; \
- omr = INL(dev, DE4X5_OMR);\
- omr |= OMR_ST | OMR_SR;\
- OUTL(dev, omr, DE4X5_OMR); /* Enable the TX and/or RX */\
-}
-
-#define STOP_DE4X5(dev) {\
- s32 omr; \
- omr = INL(dev, DE4X5_OMR);\
- omr &= ~(OMR_ST|OMR_SR);\
- OUTL(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ \
-}
-
#define NUM_RX_DESC PKTBUFSRX
-#ifndef CONFIG_TULIP_FIX_DAVICOM
- #define NUM_TX_DESC 1 /* Number of TX descriptors */
-#else
- #define NUM_TX_DESC 4
-#endif
+#define NUM_TX_DESC 1 /* Number of TX descriptors */
#define RX_BUFF_SZ PKTSIZE_ALIGN
#define TOUT_LOOP 1000000
@@ -132,455 +93,117 @@ struct de4x5_desc {
u32 next;
};
-static struct de4x5_desc rx_ring[NUM_RX_DESC] __attribute__ ((aligned(32))); /* RX descriptor ring */
-static struct de4x5_desc tx_ring[NUM_TX_DESC] __attribute__ ((aligned(32))); /* TX descriptor ring */
-static int rx_new; /* RX descriptor ring pointer */
-static int tx_new; /* TX descriptor ring pointer */
+/* RX and TX descriptor ring */
+static struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32);
+static struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32);
+static int rx_new; /* RX descriptor ring pointer */
+static int tx_new; /* TX descriptor ring pointer */
-static char rxRingSize;
-static char txRingSize;
+static char rx_ring_size;
+static char tx_ring_size;
-#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
-static void sendto_srom(struct eth_device* dev, u_int command, u_long addr);
-static int getfrom_srom(struct eth_device* dev, u_long addr);
-static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr,int cmd,int cmd_len);
-static int do_read_eeprom(struct eth_device *dev,u_long ioaddr,int location,int addr_len);
-#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
-#ifdef UPDATE_SROM
-static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value);
-static void update_srom(struct eth_device *dev, bd_t *bis);
-#endif
-#ifndef CONFIG_TULIP_FIX_DAVICOM
-static int read_srom(struct eth_device *dev, u_long ioaddr, int index);
-static void read_hw_addr(struct eth_device* dev, bd_t * bis);
-#endif /* CONFIG_TULIP_FIX_DAVICOM */
-static void send_setup_frame(struct eth_device* dev, bd_t * bis);
-
-static int dc21x4x_init(struct eth_device* dev, bd_t* bis);
-static int dc21x4x_send(struct eth_device *dev, void *packet, int length);
-static int dc21x4x_recv(struct eth_device* dev);
-static void dc21x4x_halt(struct eth_device* dev);
-#ifdef CONFIG_TULIP_SELECT_MEDIA
-extern void dc21x4x_select_media(struct eth_device* dev);
-#endif
-
-#if defined(CONFIG_E500)
-#define phys_to_bus(a) (a)
-#else
-#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
-#endif
-
-static int INL(struct eth_device* dev, u_long addr)
+static u32 dc2114x_inl(struct eth_device *dev, u32 addr)
{
- return le32_to_cpu(*(volatile u_long *)(addr + dev->iobase));
+ return le32_to_cpu(*(volatile u32 *)(addr + dev->iobase));
}
-static void OUTL(struct eth_device* dev, int command, u_long addr)
+static void dc2114x_outl(struct eth_device *dev, u32 command, u32 addr)
{
- *(volatile u_long *)(addr + dev->iobase) = cpu_to_le32(command);
+ *(volatile u32 *)(addr + dev->iobase) = cpu_to_le32(command);
}
-static struct pci_device_id supported[] = {
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST },
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 },
-#ifdef CONFIG_TULIP_FIX_DAVICOM
- { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DAVICOM_DM9102A },
-#endif
- { }
-};
-
-int dc21x4x_initialize(bd_t *bis)
+static void reset_de4x5(struct eth_device *dev)
{
- int idx=0;
- int card_number = 0;
- unsigned int cfrv;
- unsigned char timer;
- pci_dev_t devbusfn;
- unsigned int iobase;
- unsigned short status;
- struct eth_device* dev;
-
- while(1) {
- devbusfn = pci_find_devices(supported, idx++);
- if (devbusfn == -1) {
- break;
- }
-
- /* Get the chip configuration revision register. */
- pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv);
-
-#ifndef CONFIG_TULIP_FIX_DAVICOM
- if ((cfrv & CFRV_RN) < DC2114x_BRK ) {
- printf("Error: The chip is not DC21143.\n");
- continue;
- }
-#endif
-
- pci_read_config_word(devbusfn, PCI_COMMAND, &status);
- status |=
-#ifdef CONFIG_TULIP_USE_IO
- PCI_COMMAND_IO |
-#else
- PCI_COMMAND_MEMORY |
-#endif
- PCI_COMMAND_MASTER;
- pci_write_config_word(devbusfn, PCI_COMMAND, status);
-
- pci_read_config_word(devbusfn, PCI_COMMAND, &status);
-#ifdef CONFIG_TULIP_USE_IO
- if (!(status & PCI_COMMAND_IO)) {
- printf("Error: Can not enable I/O access.\n");
- continue;
- }
-#else
- if (!(status & PCI_COMMAND_MEMORY)) {
- printf("Error: Can not enable MEMORY access.\n");
- continue;
- }
-#endif
-
- if (!(status & PCI_COMMAND_MASTER)) {
- printf("Error: Can not enable Bus Mastering.\n");
- continue;
- }
-
- /* Check the latency timer for values >= 0x60. */
- pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer);
-
- if (timer < 0x60) {
- pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x60);
- }
-
-#ifdef CONFIG_TULIP_USE_IO
- /* read BAR for memory space access */
- pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &iobase);
- iobase &= PCI_BASE_ADDRESS_IO_MASK;
-#else
- /* read BAR for memory space access */
- pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &iobase);
- iobase &= PCI_BASE_ADDRESS_MEM_MASK;
-#endif
- debug ("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase);
-
- dev = (struct eth_device*) malloc(sizeof *dev);
-
- if (!dev) {
- printf("Can not allocalte memory of dc21x4x\n");
- break;
- }
- memset(dev, 0, sizeof(*dev));
-
-#ifdef CONFIG_TULIP_FIX_DAVICOM
- sprintf(dev->name, "Davicom#%d", card_number);
-#else
- sprintf(dev->name, "dc21x4x#%d", card_number);
-#endif
-
-#ifdef CONFIG_TULIP_USE_IO
- dev->iobase = pci_io_to_phys(devbusfn, iobase);
-#else
- dev->iobase = pci_mem_to_phys(devbusfn, iobase);
-#endif
- dev->priv = (void*) devbusfn;
- dev->init = dc21x4x_init;
- dev->halt = dc21x4x_halt;
- dev->send = dc21x4x_send;
- dev->recv = dc21x4x_recv;
-
- /* Ensure we're not sleeping. */
- pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
-
- udelay(10 * 1000);
-
-#ifndef CONFIG_TULIP_FIX_DAVICOM
- read_hw_addr(dev, bis);
-#endif
- eth_register(dev);
-
- card_number++;
+ u32 i;
+
+ i = dc2114x_inl(dev, DE4X5_BMR);
+ mdelay(1);
+ dc2114x_outl(dev, i | BMR_SWR, DE4X5_BMR);
+ mdelay(1);
+ dc2114x_outl(dev, i, DE4X5_BMR);
+ mdelay(1);
+
+ for (i = 0; i < 5; i++) {
+ dc2114x_inl(dev, DE4X5_BMR);
+ mdelay(10);
}
- return card_number;
+ mdelay(1);
}
-static int dc21x4x_init(struct eth_device* dev, bd_t* bis)
+static void start_de4x5(struct eth_device *dev)
{
- int i;
- int devbusfn = (int) dev->priv;
+ u32 omr;
- /* Ensure we're not sleeping. */
- pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
-
-#ifdef CONFIG_TULIP_FIX_DAVICOM
- RESET_DM9102(dev);
-#else
- RESET_DE4X5(dev);
-#endif
-
- if ((INL(dev, DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
- printf("Error: Cannot reset ethernet controller.\n");
- return -1;
- }
-
-#ifdef CONFIG_TULIP_SELECT_MEDIA
- dc21x4x_select_media(dev);
-#else
- OUTL(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
-#endif
-
- for (i = 0; i < NUM_RX_DESC; i++) {
- rx_ring[i].status = cpu_to_le32(R_OWN);
- rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
- rx_ring[i].buf = cpu_to_le32(
- phys_to_bus((u32)net_rx_packets[i]));
-#ifdef CONFIG_TULIP_FIX_DAVICOM
- rx_ring[i].next = cpu_to_le32(
- phys_to_bus((u32)&rx_ring[(i + 1) % NUM_RX_DESC]));
-#else
- rx_ring[i].next = 0;
-#endif
- }
-
- for (i=0; i < NUM_TX_DESC; i++) {
- tx_ring[i].status = 0;
- tx_ring[i].des1 = 0;
- tx_ring[i].buf = 0;
-
-#ifdef CONFIG_TULIP_FIX_DAVICOM
- tx_ring[i].next = cpu_to_le32(phys_to_bus((u32) &tx_ring[(i+1) % NUM_TX_DESC]));
-#else
- tx_ring[i].next = 0;
-#endif
- }
-
- rxRingSize = NUM_RX_DESC;
- txRingSize = NUM_TX_DESC;
-
- /* Write the end of list marker to the descriptor lists. */
- rx_ring[rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
- tx_ring[txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
-
- /* Tell the adapter where the TX/RX rings are located. */
- OUTL(dev, phys_to_bus((u32) &rx_ring), DE4X5_RRBA);
- OUTL(dev, phys_to_bus((u32) &tx_ring), DE4X5_TRBA);
-
- START_DE4X5(dev);
-
- tx_new = 0;
- rx_new = 0;
-
- send_setup_frame(dev, bis);
-
- return 0;
+ omr = dc2114x_inl(dev, DE4X5_OMR);
+ omr |= OMR_ST | OMR_SR;
+ dc2114x_outl(dev, omr, DE4X5_OMR); /* Enable the TX and/or RX */
}
-static int dc21x4x_send(struct eth_device *dev, void *packet, int length)
+static void stop_de4x5(struct eth_device *dev)
{
- int status = -1;
- int i;
+ u32 omr;
- if (length <= 0) {
- printf("%s: bad packet size: %d\n", dev->name, length);
- goto Done;
- }
-
- for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
- if (i >= TOUT_LOOP) {
- printf("%s: tx error buffer not ready\n", dev->name);
- goto Done;
- }
- }
-
- tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32) packet));
- tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length);
- tx_ring[tx_new].status = cpu_to_le32(T_OWN);
-
- OUTL(dev, POLL_DEMAND, DE4X5_TPD);
-
- for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
- if (i >= TOUT_LOOP) {
- printf(".%s: tx buffer not ready\n", dev->name);
- goto Done;
- }
- }
-
- if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) {
-#if 0 /* test-only */
- printf("TX error status = 0x%08X\n",
- le32_to_cpu(tx_ring[tx_new].status));
-#endif
- tx_ring[tx_new].status = 0x0;
- goto Done;
- }
-
- status = length;
-
- Done:
- tx_new = (tx_new+1) % NUM_TX_DESC;
- return status;
+ omr = dc2114x_inl(dev, DE4X5_OMR);
+ omr &= ~(OMR_ST | OMR_SR);
+ dc2114x_outl(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */
}
-static int dc21x4x_recv(struct eth_device* dev)
+/* SROM Read and write routines. */
+static void sendto_srom(struct eth_device *dev, u_int command, u_long addr)
{
- s32 status;
- int length = 0;
-
- for ( ; ; ) {
- status = (s32)le32_to_cpu(rx_ring[rx_new].status);
-
- if (status & R_OWN) {
- break;
- }
-
- if (status & RD_LS) {
- /* Valid frame status.
- */
- if (status & RD_ES) {
-
- /* There was an error.
- */
- printf("RX error status = 0x%08X\n", status);
- } else {
- /* A valid frame received.
- */
- length = (le32_to_cpu(rx_ring[rx_new].status) >> 16);
-
- /* Pass the packet up to the protocol
- * layers.
- */
- net_process_received_packet(
- net_rx_packets[rx_new], length - 4);
- }
-
- /* Change buffer ownership for this frame, back
- * to the adapter.
- */
- rx_ring[rx_new].status = cpu_to_le32(R_OWN);
- }
-
- /* Update entry information.
- */
- rx_new = (rx_new + 1) % rxRingSize;
- }
-
- return length;
-}
-
-static void dc21x4x_halt(struct eth_device* dev)
-{
- int devbusfn = (int) dev->priv;
-
- STOP_DE4X5(dev);
- OUTL(dev, 0, DE4X5_SICR);
-
- pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP);
-}
-
-static void send_setup_frame(struct eth_device* dev, bd_t *bis)
-{
- int i;
- char setup_frame[SETUP_FRAME_LEN];
- char *pa = &setup_frame[0];
-
- memset(pa, 0xff, SETUP_FRAME_LEN);
-
- for (i = 0; i < ETH_ALEN; i++) {
- *(pa + (i & 1)) = dev->enetaddr[i];
- if (i & 0x01) {
- pa += 4;
- }
- }
-
- for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
- if (i >= TOUT_LOOP) {
- printf("%s: tx error buffer not ready\n", dev->name);
- goto Done;
- }
- }
-
- tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32) &setup_frame[0]));
- tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET| SETUP_FRAME_LEN);
- tx_ring[tx_new].status = cpu_to_le32(T_OWN);
-
- OUTL(dev, POLL_DEMAND, DE4X5_TPD);
-
- for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
- if (i >= TOUT_LOOP) {
- printf("%s: tx buffer not ready\n", dev->name);
- goto Done;
- }
- }
-
- if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) {
- printf("TX error status2 = 0x%08X\n", le32_to_cpu(tx_ring[tx_new].status));
- }
- tx_new = (tx_new+1) % NUM_TX_DESC;
-
-Done:
- return;
-}
-
-#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
-/* SROM Read and write routines.
- */
-static void
-sendto_srom(struct eth_device* dev, u_int command, u_long addr)
-{
- OUTL(dev, command, addr);
+ dc2114x_outl(dev, command, addr);
udelay(1);
}
-static int
-getfrom_srom(struct eth_device* dev, u_long addr)
+static int getfrom_srom(struct eth_device *dev, u_long addr)
{
- s32 tmp;
+ u32 tmp = dc2114x_inl(dev, addr);
- tmp = INL(dev, addr);
udelay(1);
-
return tmp;
}
/* Note: this routine returns extra data bits for size detection. */
-static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, int addr_len)
+static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location,
+ int addr_len)
{
- int i;
- unsigned retval = 0;
int read_cmd = location | (SROM_READ_CMD << addr_len);
+ unsigned int retval = 0;
+ int i;
sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
-#ifdef DEBUG_SROM
- printf(" EEPROM read at %d ", location);
-#endif
+ debug_cond(SROM_DLEVEL >= 1, " EEPROM read at %d ", location);
/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval, ioaddr);
+
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval,
+ ioaddr);
udelay(10);
- sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK, ioaddr);
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK,
+ ioaddr);
udelay(10);
-#ifdef DEBUG_SROM2
- printf("%X", getfrom_srom(dev, ioaddr) & 15);
-#endif
- retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
+ debug_cond(SROM_DLEVEL >= 2, "%X",
+ getfrom_srom(dev, ioaddr) & 15);
+ retval = (retval << 1) |
+ !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
}
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
-#ifdef DEBUG_SROM2
- printf(" :%X:", getfrom_srom(dev, ioaddr) & 15);
-#endif
+ debug_cond(SROM_DLEVEL >= 2, " :%X:", getfrom_srom(dev, ioaddr) & 15);
for (i = 16; i > 0; i--) {
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
udelay(10);
-#ifdef DEBUG_SROM2
- printf("%X", getfrom_srom(dev, ioaddr) & 15);
-#endif
- retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
+ debug_cond(SROM_DLEVEL >= 2, "%X",
+ getfrom_srom(dev, ioaddr) & 15);
+ retval = (retval << 1) |
+ !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
udelay(10);
}
@@ -588,145 +211,115 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, i
/* Terminate the EEPROM access. */
sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
-#ifdef DEBUG_SROM2
- printf(" EEPROM value at %d is %5.5x.\n", location, retval);
-#endif
+ debug_cond(SROM_DLEVEL >= 2, " EEPROM value at %d is %5.5x.\n",
+ location, retval);
return retval;
}
-#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
-/* This executes a generic EEPROM command, typically a write or write
+/*
+ * This executes a generic EEPROM command, typically a write or write
* enable. It returns the data output from the EEPROM, and thus may
* also be used for reads.
*/
-#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
-static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, int cmd_len)
+static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd,
+ int cmd_len)
{
- unsigned retval = 0;
+ unsigned int retval = 0;
-#ifdef DEBUG_SROM
- printf(" EEPROM op 0x%x: ", cmd);
-#endif
+ debug_cond(SROM_DLEVEL >= 1, " EEPROM op 0x%x: ", cmd);
- sendto_srom(dev,SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
/* Shift the command bits out. */
do {
- short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
- sendto_srom(dev,dataval, ioaddr);
+ short dataval = (cmd & BIT(cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
+
+ sendto_srom(dev, dataval, ioaddr);
udelay(10);
-#ifdef DEBUG_SROM2
- printf("%X", getfrom_srom(dev,ioaddr) & 15);
-#endif
+ debug_cond(SROM_DLEVEL >= 2, "%X",
+ getfrom_srom(dev, ioaddr) & 15);
- sendto_srom(dev,dataval | DT_CLK, ioaddr);
+ sendto_srom(dev, dataval | DT_CLK, ioaddr);
udelay(10);
- retval = (retval << 1) | ((getfrom_srom(dev,ioaddr) & EE_DATA_READ) ? 1 : 0);
+ retval = (retval << 1) |
+ !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
} while (--cmd_len >= 0);
- sendto_srom(dev,SROM_RD | SROM_SR | DT_CS, ioaddr);
+
+ sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
/* Terminate the EEPROM access. */
- sendto_srom(dev,SROM_RD | SROM_SR, ioaddr);
+ sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
-#ifdef DEBUG_SROM
- printf(" EEPROM result is 0x%5.5x.\n", retval);
-#endif
+ debug_cond(SROM_DLEVEL >= 1, " EEPROM result is 0x%5.5x.\n", retval);
return retval;
}
-#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
-#ifndef CONFIG_TULIP_FIX_DAVICOM
static int read_srom(struct eth_device *dev, u_long ioaddr, int index)
{
- int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+ int ee_addr_size;
- return do_eeprom_cmd(dev, ioaddr,
- (((SROM_READ_CMD << ee_addr_size) | index) << 16)
- | 0xffff, 3 + ee_addr_size + 16);
+ ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6;
+
+ return do_eeprom_cmd(dev, ioaddr, 0xffff |
+ (((SROM_READ_CMD << ee_addr_size) | index) << 16),
+ 3 + ee_addr_size + 16);
}
-#endif /* CONFIG_TULIP_FIX_DAVICOM */
#ifdef UPDATE_SROM
-static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value)
+static int write_srom(struct eth_device *dev, u_long ioaddr, int index,
+ int new_value)
{
- int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
- int i;
unsigned short newval;
+ int ee_addr_size;
+ int i;
- udelay(10*1000); /* test-only */
+ ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6;
-#ifdef DEBUG_SROM
- printf("ee_addr_size=%d.\n", ee_addr_size);
- printf("Writing new entry 0x%4.4x to offset %d.\n", new_value, index);
-#endif
+ udelay(10 * 1000); /* test-only */
+
+ debug_cond(SROM_DLEVEL >= 1, "ee_addr_size=%d.\n", ee_addr_size);
+ debug_cond(SROM_DLEVEL >= 1,
+ "Writing new entry 0x%4.4x to offset %d.\n",
+ new_value, index);
/* Enable programming modes. */
- do_eeprom_cmd(dev, ioaddr, (0x4f << (ee_addr_size-4)), 3+ee_addr_size);
+ do_eeprom_cmd(dev, ioaddr, 0x4f << (ee_addr_size - 4),
+ 3 + ee_addr_size);
/* Do the actual write. */
- do_eeprom_cmd(dev, ioaddr,
- (((SROM_WRITE_CMD<<ee_addr_size)|index) << 16) | new_value,
+ do_eeprom_cmd(dev, ioaddr, new_value |
+ (((SROM_WRITE_CMD << ee_addr_size) | index) << 16),
3 + ee_addr_size + 16);
/* Poll for write finished. */
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
- for (i = 0; i < 10000; i++) /* Typical 2000 ticks */
+ for (i = 0; i < 10000; i++) { /* Typical 2000 ticks */
if (getfrom_srom(dev, ioaddr) & EE_DATA_READ)
break;
+ }
-#ifdef DEBUG_SROM
- printf(" Write finished after %d ticks.\n", i);
-#endif
+ debug_cond(SROM_DLEVEL >= 1, " Write finished after %d ticks.\n", i);
/* Disable programming. */
- do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size-4)), 3 + ee_addr_size);
+ do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size - 4)),
+ 3 + ee_addr_size);
/* And read the result. */
newval = do_eeprom_cmd(dev, ioaddr,
- (((SROM_READ_CMD<<ee_addr_size)|index) << 16)
+ (((SROM_READ_CMD << ee_addr_size) | index) << 16)
| 0xffff, 3 + ee_addr_size + 16);
-#ifdef DEBUG_SROM
- printf(" New value at offset %d is %4.4x.\n", index, newval);
-#endif
- return 1;
-}
-#endif
-
-#ifndef CONFIG_TULIP_FIX_DAVICOM
-static void read_hw_addr(struct eth_device *dev, bd_t *bis)
-{
- u_short tmp, *p = (u_short *)(&dev->enetaddr[0]);
- int i, j = 0;
- for (i = 0; i < (ETH_ALEN >> 1); i++) {
- tmp = read_srom(dev, DE4X5_APROM, ((SROM_HWADD >> 1) + i));
- *p = le16_to_cpu(tmp);
- j += *p++;
- }
+ debug_cond(SROM_DLEVEL >= 1, " New value at offset %d is %4.4x.\n",
+ index, newval);
- if ((j == 0) || (j == 0x2fffd)) {
- memset (dev->enetaddr, 0, ETH_ALEN);
- debug ("Warning: can't read HW address from SROM.\n");
- goto Done;
- }
-
- return;
-
-Done:
-#ifdef UPDATE_SROM
- update_srom(dev, bis);
-#endif
- return;
+ return 1;
}
-#endif /* CONFIG_TULIP_FIX_DAVICOM */
-#ifdef UPDATE_SROM
static void update_srom(struct eth_device *dev, bd_t *bis)
{
- int i;
static unsigned short eeprom[0x40] = {
0x140b, 0x6610, 0x0000, 0x0000, /* 00 */
0x0000, 0x0000, 0x0000, 0x0000, /* 04 */
@@ -746,16 +339,318 @@ static void update_srom(struct eth_device *dev, bd_t *bis)
0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */
};
uchar enetaddr[6];
+ int i;
/* Ethernet Addr... */
if (!eth_env_get_enetaddr("ethaddr", enetaddr))
return;
+
eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0];
eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2];
eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4];
- for (i=0; i<0x40; i++) {
+ for (i = 0; i < 0x40; i++)
write_srom(dev, DE4X5_APROM, i, eeprom[i]);
+}
+#endif /* UPDATE_SROM */
+
+static void send_setup_frame(struct eth_device *dev, bd_t *bis)
+{
+ char setup_frame[SETUP_FRAME_LEN];
+ char *pa = &setup_frame[0];
+ int i;
+
+ memset(pa, 0xff, SETUP_FRAME_LEN);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ *(pa + (i & 1)) = dev->enetaddr[i];
+ if (i & 0x01)
+ pa += 4;
+ }
+
+ for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i < TOUT_LOOP)
+ continue;
+
+ printf("%s: tx error buffer not ready\n", dev->name);
+ return;
+ }
+
+ tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32)&setup_frame[0]));
+ tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN);
+ tx_ring[tx_new].status = cpu_to_le32(T_OWN);
+
+ dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD);
+
+ for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i < TOUT_LOOP)
+ continue;
+
+ printf("%s: tx buffer not ready\n", dev->name);
+ return;
+ }
+
+ if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) {
+ printf("TX error status2 = 0x%08X\n",
+ le32_to_cpu(tx_ring[tx_new].status));
+ }
+
+ tx_new = (tx_new + 1) % NUM_TX_DESC;
+}
+
+static int dc21x4x_send(struct eth_device *dev, void *packet, int length)
+{
+ int status = -1;
+ int i;
+
+ if (length <= 0) {
+ printf("%s: bad packet size: %d\n", dev->name, length);
+ goto done;
+ }
+
+ for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i < TOUT_LOOP)
+ continue;
+
+ printf("%s: tx error buffer not ready\n", dev->name);
+ goto done;
+ }
+
+ tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32)packet));
+ tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length);
+ tx_ring[tx_new].status = cpu_to_le32(T_OWN);
+
+ dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD);
+
+ for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+ if (i < TOUT_LOOP)
+ continue;
+
+ printf(".%s: tx buffer not ready\n", dev->name);
+ goto done;
+ }
+
+ if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) {
+ tx_ring[tx_new].status = 0x0;
+ goto done;
+ }
+
+ status = length;
+
+done:
+ tx_new = (tx_new + 1) % NUM_TX_DESC;
+ return status;
+}
+
+static int dc21x4x_recv(struct eth_device *dev)
+{
+ int length = 0;
+ u32 status;
+
+ while (true) {
+ status = le32_to_cpu(rx_ring[rx_new].status);
+
+ if (status & R_OWN)
+ break;
+
+ if (status & RD_LS) {
+ /* Valid frame status. */
+ if (status & RD_ES) {
+ /* There was an error. */
+ printf("RX error status = 0x%08X\n", status);
+ } else {
+ /* A valid frame received. */
+ length = (le32_to_cpu(rx_ring[rx_new].status)
+ >> 16);
+
+ /* Pass the packet up to the protocol layers */
+ net_process_received_packet
+ (net_rx_packets[rx_new], length - 4);
+ }
+
+ /*
+ * Change buffer ownership for this frame,
+ * back to the adapter.
+ */
+ rx_ring[rx_new].status = cpu_to_le32(R_OWN);
+ }
+
+ /* Update entry information. */
+ rx_new = (rx_new + 1) % rx_ring_size;
+ }
+
+ return length;
+}
+
+static int dc21x4x_init(struct eth_device *dev, bd_t *bis)
+{
+ int i;
+ int devbusfn = (int)dev->priv;
+
+ /* Ensure we're not sleeping. */
+ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+
+ reset_de4x5(dev);
+
+ if (dc2114x_inl(dev, DE4X5_STS) & (STS_TS | STS_RS)) {
+ printf("Error: Cannot reset ethernet controller.\n");
+ return -1;
+ }
+
+ dc2114x_outl(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
+
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ rx_ring[i].status = cpu_to_le32(R_OWN);
+ rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
+ rx_ring[i].buf =
+ cpu_to_le32(phys_to_bus((u32)net_rx_packets[i]));
+ rx_ring[i].next = 0;
+ }
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ tx_ring[i].status = 0;
+ tx_ring[i].des1 = 0;
+ tx_ring[i].buf = 0;
+ tx_ring[i].next = 0;
}
+
+ rx_ring_size = NUM_RX_DESC;
+ tx_ring_size = NUM_TX_DESC;
+
+ /* Write the end of list marker to the descriptor lists. */
+ rx_ring[rx_ring_size - 1].des1 |= cpu_to_le32(RD_RER);
+ tx_ring[tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
+
+ /* Tell the adapter where the TX/RX rings are located. */
+ dc2114x_outl(dev, phys_to_bus((u32)&rx_ring), DE4X5_RRBA);
+ dc2114x_outl(dev, phys_to_bus((u32)&tx_ring), DE4X5_TRBA);
+
+ start_de4x5(dev);
+
+ tx_new = 0;
+ rx_new = 0;
+
+ send_setup_frame(dev, bis);
+
+ return 0;
+}
+
+static void dc21x4x_halt(struct eth_device *dev)
+{
+ int devbusfn = (int)dev->priv;
+
+ stop_de4x5(dev);
+ dc2114x_outl(dev, 0, DE4X5_SICR);
+
+ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP);
+}
+
+static void read_hw_addr(struct eth_device *dev, bd_t *bis)
+{
+ u_short tmp, *p = (u_short *)(&dev->enetaddr[0]);
+ int i, j = 0;
+
+ for (i = 0; i < (ETH_ALEN >> 1); i++) {
+ tmp = read_srom(dev, DE4X5_APROM, (SROM_HWADD >> 1) + i);
+ *p = le16_to_cpu(tmp);
+ j += *p++;
+ }
+
+ if (!j || j == 0x2fffd) {
+ memset(dev->enetaddr, 0, ETH_ALEN);
+ debug("Warning: can't read HW address from SROM.\n");
+#ifdef UPDATE_SROM
+ update_srom(dev, bis);
+#endif
+ }
+}
+
+static struct pci_device_id supported[] = {
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST },
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 },
+ { }
+};
+
+int dc21x4x_initialize(bd_t *bis)
+{
+ struct eth_device *dev;
+ unsigned short status;
+ unsigned char timer;
+ unsigned int iobase;
+ int card_number = 0;
+ pci_dev_t devbusfn;
+ unsigned int cfrv;
+ int idx = 0;
+
+ while (1) {
+ devbusfn = pci_find_devices(supported, idx++);
+ if (devbusfn == -1)
+ break;
+
+ /* Get the chip configuration revision register. */
+ pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv);
+
+ if ((cfrv & CFRV_RN) < DC2114x_BRK) {
+ printf("Error: The chip is not DC21143.\n");
+ continue;
+ }
+
+ pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+ status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(devbusfn, PCI_COMMAND, status);
+
+ pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+ if (!(status & PCI_COMMAND_MEMORY)) {
+ printf("Error: Can not enable MEMORY access.\n");
+ continue;
+ }
+
+ if (!(status & PCI_COMMAND_MASTER)) {
+ printf("Error: Can not enable Bus Mastering.\n");
+ continue;
+ }
+
+ /* Check the latency timer for values >= 0x60. */
+ pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer);
+
+ if (timer < 0x60) {
+ pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER,
+ 0x60);
+ }
+
+ /* read BAR for memory space access */
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &iobase);
+ iobase &= PCI_BASE_ADDRESS_MEM_MASK;
+ debug("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase);
+
+ dev = (struct eth_device *)malloc(sizeof(*dev));
+ if (!dev) {
+ printf("Can not allocalte memory of dc21x4x\n");
+ break;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf(dev->name, "dc21x4x#%d", card_number);
+
+ dev->iobase = pci_mem_to_phys(devbusfn, iobase);
+ dev->priv = (void *)devbusfn;
+ dev->init = dc21x4x_init;
+ dev->halt = dc21x4x_halt;
+ dev->send = dc21x4x_send;
+ dev->recv = dc21x4x_recv;
+
+ /* Ensure we're not sleeping. */
+ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+
+ udelay(10 * 1000);
+
+ read_hw_addr(dev, bis);
+
+ eth_register(dev);
+
+ card_number++;
+ }
+
+ return card_number;
}
-#endif /* UPDATE_SROM */
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 63f2086dec..60dfd17a74 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -1288,9 +1288,9 @@ static int eqos_start(struct udevice *dev)
struct eqos_desc *rx_desc = &(eqos->rx_descs[i]);
rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf +
(i * EQOS_MAX_PACKET_SIZE));
- rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+ rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+ eqos->config->ops->eqos_flush_desc(rx_desc);
}
- eqos->config->ops->eqos_flush_desc(eqos->descs);
writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address);
@@ -1419,7 +1419,8 @@ static int eqos_send(struct udevice *dev, void *packet, int length)
tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length;
eqos->config->ops->eqos_flush_desc(tx_desc);
- writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer);
+ writel((ulong)(&(eqos->tx_descs[eqos->tx_desc_idx])),
+ &eqos->dma_regs->ch0_txdesc_tail_pointer);
for (i = 0; i < 1000000; i++) {
eqos->config->ops->eqos_inval_desc(tx_desc);
@@ -1442,6 +1443,7 @@ static int eqos_recv(struct udevice *dev, int flags, uchar **packetp)
debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags);
rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]);
+ eqos->config->ops->eqos_inval_desc(rx_desc);
if (rx_desc->des3 & EQOS_DESC3_OWN) {
debug("%s: RX packet not available\n", __func__);
return -EAGAIN;
@@ -1474,6 +1476,11 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
}
rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]);
+
+ rx_desc->des0 = 0;
+ mb();
+ eqos->config->ops->eqos_flush_desc(rx_desc);
+ eqos->config->ops->eqos_inval_buffer(packet, length);
rx_desc->des0 = (u32)(ulong)packet;
rx_desc->des1 = 0;
rx_desc->des2 = 0;
@@ -1482,7 +1489,7 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
* writes to the rest of the descriptor too.
*/
mb();
- rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+ rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
eqos->config->ops->eqos_flush_desc(rx_desc);
writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
@@ -1536,6 +1543,9 @@ static int eqos_probe_resources_core(struct udevice *dev)
}
debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt);
+ eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf,
+ EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX);
+
debug("%s: OK\n", __func__);
return 0;
diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c
index b4ad11d3fa..f97e7f8c6a 100644
--- a/drivers/net/pcnet.c
+++ b/drivers/net/pcnet.c
@@ -21,10 +21,6 @@
#define PCNET_DEBUG2(fmt,args...) \
debug_cond(PCNET_DEBUG_LEVEL > 1, fmt ,##args)
-#if !defined(CONF_PCNET_79C973) && defined(CONF_PCNET_79C975)
-#error "Macro for PCnet chip version is not defined!"
-#endif
-
/*
* Set the number of Tx and Rx buffers, using Log_2(# buffers).
* Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
@@ -95,37 +91,49 @@ static pcnet_priv_t *lp;
static u16 pcnet_read_csr(struct eth_device *dev, int index)
{
- outw(index, dev->iobase + PCNET_RAP);
- return inw(dev->iobase + PCNET_RDP);
+ void __iomem *base = (void __iomem *)dev->iobase;
+
+ writew(index, base + PCNET_RAP);
+ return readw(base + PCNET_RDP);
}
static void pcnet_write_csr(struct eth_device *dev, int index, u16 val)
{
- outw(index, dev->iobase + PCNET_RAP);
- outw(val, dev->iobase + PCNET_RDP);
+ void __iomem *base = (void __iomem *)dev->iobase;
+
+ writew(index, base + PCNET_RAP);
+ writew(val, base + PCNET_RDP);
}
static u16 pcnet_read_bcr(struct eth_device *dev, int index)
{
- outw(index, dev->iobase + PCNET_RAP);
- return inw(dev->iobase + PCNET_BDP);
+ void __iomem *base = (void __iomem *)dev->iobase;
+
+ writew(index, base + PCNET_RAP);
+ return readw(base + PCNET_BDP);
}
static void pcnet_write_bcr(struct eth_device *dev, int index, u16 val)
{
- outw(index, dev->iobase + PCNET_RAP);
- outw(val, dev->iobase + PCNET_BDP);
+ void __iomem *base = (void __iomem *)dev->iobase;
+
+ writew(index, base + PCNET_RAP);
+ writew(val, base + PCNET_BDP);
}
static void pcnet_reset(struct eth_device *dev)
{
- inw(dev->iobase + PCNET_RESET);
+ void __iomem *base = (void __iomem *)dev->iobase;
+
+ readw(base + PCNET_RESET);
}
static int pcnet_check(struct eth_device *dev)
{
- outw(88, dev->iobase + PCNET_RAP);
- return inw(dev->iobase + PCNET_RAP) == 88;
+ void __iomem *base = (void __iomem *)dev->iobase;
+
+ writew(88, base + PCNET_RAP);
+ return readw(base + PCNET_RAP) == 88;
}
static int pcnet_init (struct eth_device *dev, bd_t * bis);
@@ -183,14 +191,14 @@ int pcnet_initialize(bd_t *bis)
/*
* Setup the PCI device.
*/
- pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &bar);
- dev->iobase = pci_io_to_phys(devbusfn, bar);
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &bar);
+ dev->iobase = pci_mem_to_phys(devbusfn, bar);
dev->iobase &= ~0xf;
PCNET_DEBUG1("%s: devbusfn=0x%x iobase=0x%lx: ",
dev->name, devbusfn, (unsigned long)dev->iobase);
- command = PCI_COMMAND_IO | PCI_COMMAND_MASTER;
+ command = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
pci_write_config_word(devbusfn, PCI_COMMAND, command);
pci_read_config_word(devbusfn, PCI_COMMAND, &status);
if ((status & command) != command) {
@@ -254,16 +262,12 @@ static int pcnet_probe(struct eth_device *dev, bd_t *bis, int dev_nr)
case 0x2621:
chipname = "PCnet/PCI II 79C970A"; /* PCI */
break;
-#ifdef CONFIG_PCNET_79C973
case 0x2625:
chipname = "PCnet/FAST III 79C973"; /* PCI */
break;
-#endif
-#ifdef CONFIG_PCNET_79C975
case 0x2627:
chipname = "PCnet/FAST III 79C975"; /* PCI */
break;
-#endif
default:
printf("%s: PCnet version %#x not supported\n",
dev->name, chip_version);
@@ -340,7 +344,9 @@ static int pcnet_init(struct eth_device *dev, bd_t *bis)
addr = (unsigned long)memalign(ARCH_DMA_MINALIGN,
sizeof(*lp->uc));
flush_dcache_range(addr, addr + sizeof(*lp->uc));
- addr = UNCACHED_SDRAM(addr);
+ addr = (unsigned long)map_physmem(addr,
+ roundup(sizeof(*lp->uc), ARCH_DMA_MINALIGN),
+ MAP_NOCACHE);
lp->uc = (struct pcnet_uncached_priv *)addr;
addr = (unsigned long)memalign(ARCH_DMA_MINALIGN,
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
index bb59629f81..1f08397291 100644
--- a/drivers/net/rtl8139.c
+++ b/drivers/net/rtl8139.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* rtl8139.c : U-Boot driver for the RealTek RTL8139
*
@@ -8,71 +9,68 @@
*/
/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
-
- ported from the linux driver written by Donald Becker
- by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
-
- This software may be used and distributed according to the terms
- of the GNU Public License, incorporated herein by reference.
-
- changes to the original driver:
- - removed support for interrupts, switching to polling mode (yuck!)
- - removed support for the 8129 chip (external MII)
-
-*/
+ *
+ * ported from the linux driver written by Donald Becker
+ * by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
+ *
+ * changes to the original driver:
+ * - removed support for interrupts, switching to polling mode (yuck!)
+ * - removed support for the 8129 chip (external MII)
+ */
/*********************************************************************/
/* Revision History */
/*********************************************************************/
/*
- 28 Dec 2002 ken_yap@users.sourceforge.net (Ken Yap)
- Put in virt_to_bus calls to allow Etherboot relocation.
-
- 06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap)
- Following email from Hyun-Joon Cha, added a disable routine, otherwise
- NIC remains live and can crash the kernel later.
-
- 4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
- Shuffled things around, removed the leftovers from the 8129 support
- that was in the Linux driver and added a bit more 8139 definitions.
- Moved the 8K receive buffer to a fixed, available address outside the
- 0x98000-0x9ffff range. This is a bit of a hack, but currently the only
- way to make room for the Etherboot features that need substantial amounts
- of code like the ANSI console support. Currently the buffer is just below
- 0x10000, so this even conforms to the tagged boot image specification,
- which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My
- interpretation of this "reserved" is that Etherboot may do whatever it
- likes, as long as its environment is kept intact (like the BIOS
- variables). Hopefully fixed rtl_poll() once and for all. The symptoms
- were that if Etherboot was left at the boot menu for several minutes, the
- first eth_poll failed. Seems like I am the only person who does this.
- First of all I fixed the debugging code and then set out for a long bug
- hunting session. It took me about a week full time work - poking around
- various places in the driver, reading Don Becker's and Jeff Garzik's Linux
- driver and even the FreeBSD driver (what a piece of crap!) - and
- eventually spotted the nasty thing: the transmit routine was acknowledging
- each and every interrupt pending, including the RxOverrun and RxFIFIOver
- interrupts. This confused the RTL8139 thoroughly. It destroyed the
- Rx ring contents by dumping the 2K FIFO contents right where we wanted to
- get the next packet. Oh well, what fun.
-
- 18 Jan 2000 mdc@thinguin.org (Marty Connor)
- Drastically simplified error handling. Basically, if any error
- in transmission or reception occurs, the card is reset.
- Also, pointed all transmit descriptors to the same buffer to
- save buffer space. This should decrease driver size and avoid
- corruption because of exceeding 32K during runtime.
-
- 28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
- rtl_poll was quite broken: it used the RxOK interrupt flag instead
- of the RxBufferEmpty flag which often resulted in very bad
- transmission performace - below 1kBytes/s.
-
-*/
+ * 28 Dec 2002 ken_yap@users.sourceforge.net (Ken Yap)
+ * Put in virt_to_bus calls to allow Etherboot relocation.
+ *
+ * 06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap)
+ * Following email from Hyun-Joon Cha, added a disable routine, otherwise
+ * NIC remains live and can crash the kernel later.
+ *
+ * 4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
+ * Shuffled things around, removed the leftovers from the 8129 support
+ * that was in the Linux driver and added a bit more 8139 definitions.
+ * Moved the 8K receive buffer to a fixed, available address outside the
+ * 0x98000-0x9ffff range. This is a bit of a hack, but currently the only
+ * way to make room for the Etherboot features that need substantial amounts
+ * of code like the ANSI console support. Currently the buffer is just below
+ * 0x10000, so this even conforms to the tagged boot image specification,
+ * which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My
+ * interpretation of this "reserved" is that Etherboot may do whatever it
+ * likes, as long as its environment is kept intact (like the BIOS
+ * variables). Hopefully fixed rtl8139_recv() once and for all. The symptoms
+ * were that if Etherboot was left at the boot menu for several minutes, the
+ * first eth_poll failed. Seems like I am the only person who does this.
+ * First of all I fixed the debugging code and then set out for a long bug
+ * hunting session. It took me about a week full time work - poking around
+ * various places in the driver, reading Don Becker's and Jeff Garzik's Linux
+ * driver and even the FreeBSD driver (what a piece of crap!) - and
+ * eventually spotted the nasty thing: the transmit routine was acknowledging
+ * each and every interrupt pending, including the RxOverrun and RxFIFIOver
+ * interrupts. This confused the RTL8139 thoroughly. It destroyed the
+ * Rx ring contents by dumping the 2K FIFO contents right where we wanted to
+ * get the next packet. Oh well, what fun.
+ *
+ * 18 Jan 2000 mdc@thinguin.org (Marty Connor)
+ * Drastically simplified error handling. Basically, if any error
+ * in transmission or reception occurs, the card is reset.
+ * Also, pointed all transmit descriptors to the same buffer to
+ * save buffer space. This should decrease driver size and avoid
+ * corruption because of exceeding 32K during runtime.
+ *
+ * 28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
+ * rtl8139_recv was quite broken: it used the RxOK interrupt flag instead
+ * of the RxBufferEmpty flag which often resulted in very bad
+ * transmission performace - below 1kBytes/s.
+ *
+ */
#include <common.h>
#include <cpu_func.h>
+#include <linux/types.h>
#include <malloc.h>
#include <net.h>
#include <netdev.h>
@@ -81,8 +79,8 @@
#define RTL_TIMEOUT 100000
-/* PCI Tuning Parameters
- Threshold is bytes transferred to chip before transmission starts. */
+/* PCI Tuning Parameters */
+/* Threshold is bytes transferred to chip before transmission starts. */
#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
@@ -99,173 +97,103 @@
#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
/* Symbolic offsets to registers. */
-enum RTL8139_registers {
- MAC0=0, /* Ethernet hardware address. */
- MAR0=8, /* Multicast filter. */
- TxStatus0=0x10, /* Transmit status (four 32bit registers). */
- TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
- RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
- ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
- IntrMask=0x3C, IntrStatus=0x3E,
- TxConfig=0x40, RxConfig=0x44,
- Timer=0x48, /* general-purpose counter. */
- RxMissed=0x4C, /* 24 bits valid, write clears. */
- Cfg9346=0x50, Config0=0x51, Config1=0x52,
- TimerIntrReg=0x54, /* intr if gp counter reaches this value */
- MediaStatus=0x58,
- Config3=0x59,
- MultiIntr=0x5C,
- RevisionID=0x5E, /* revision of the RTL8139 chip */
- TxSummary=0x60,
- MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
- NWayExpansion=0x6A,
- DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
- NWayTestReg=0x70,
- RxCnt=0x72, /* packet received counter */
- CSCR=0x74, /* chip status and configuration register */
- PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80, /* undocumented */
- /* from 0x84 onwards are a number of power management/wakeup frame
- * definitions we will probably never need to know about. */
-};
-
-enum ChipCmdBits {
- CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
- PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
- RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
- TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
-};
-enum TxStatusBits {
- TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
- TxOutOfWindow=0x20000000, TxAborted=0x40000000,
- TxCarrierLost=0x80000000,
-};
-enum RxStatusBits {
- RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
- RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
- RxBadAlign=0x0002, RxStatusOK=0x0001,
-};
-
-enum MediaStatusBits {
- MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
- MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
-};
-
-enum MIIBMCRBits {
- BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
- BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
-};
-
-enum CSCRBits {
- CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
- CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
- CSCR_LinkDownCmd=0x0f3c0,
-};
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
- RxCfgWrap=0x80,
- AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
- AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
-};
+/* Ethernet hardware address. */
+#define RTL_REG_MAC0 0x00
+/* Multicast filter. */
+#define RTL_REG_MAR0 0x08
+/* Transmit status (four 32bit registers). */
+#define RTL_REG_TXSTATUS0 0x10
+/* Tx descriptors (also four 32bit). */
+#define RTL_REG_TXADDR0 0x20
+#define RTL_REG_RXBUF 0x30
+#define RTL_REG_RXEARLYCNT 0x34
+#define RTL_REG_RXEARLYSTATUS 0x36
+#define RTL_REG_CHIPCMD 0x37
+#define RTL_REG_CHIPCMD_CMDRESET BIT(4)
+#define RTL_REG_CHIPCMD_CMDRXENB BIT(3)
+#define RTL_REG_CHIPCMD_CMDTXENB BIT(2)
+#define RTL_REG_CHIPCMD_RXBUFEMPTY BIT(0)
+#define RTL_REG_RXBUFPTR 0x38
+#define RTL_REG_RXBUFADDR 0x3A
+#define RTL_REG_INTRMASK 0x3C
+#define RTL_REG_INTRSTATUS 0x3E
+#define RTL_REG_INTRSTATUS_PCIERR BIT(15)
+#define RTL_REG_INTRSTATUS_PCSTIMEOUT BIT(14)
+#define RTL_REG_INTRSTATUS_CABLELENCHANGE BIT(13)
+#define RTL_REG_INTRSTATUS_RXFIFOOVER BIT(6)
+#define RTL_REG_INTRSTATUS_RXUNDERRUN BIT(5)
+#define RTL_REG_INTRSTATUS_RXOVERFLOW BIT(4)
+#define RTL_REG_INTRSTATUS_TXERR BIT(3)
+#define RTL_REG_INTRSTATUS_TXOK BIT(2)
+#define RTL_REG_INTRSTATUS_RXERR BIT(1)
+#define RTL_REG_INTRSTATUS_RXOK BIT(0)
+#define RTL_REG_TXCONFIG 0x40
+#define RTL_REG_RXCONFIG 0x44
+#define RTL_REG_RXCONFIG_RXCFGWRAP BIT(7)
+#define RTL_REG_RXCONFIG_ACCEPTERR BIT(5)
+#define RTL_REG_RXCONFIG_ACCEPTRUNT BIT(4)
+#define RTL_REG_RXCONFIG_ACCEPTBROADCAST BIT(3)
+#define RTL_REG_RXCONFIG_ACCEPTMULTICAST BIT(2)
+#define RTL_REG_RXCONFIG_ACCEPTMYPHYS BIT(1)
+#define RTL_REG_RXCONFIG_ACCEPTALLPHYS BIT(0)
+/* general-purpose counter. */
+#define RTL_REG_TIMER 0x48
+/* 24 bits valid, write clears. */
+#define RTL_REG_RXMISSED 0x4C
+#define RTL_REG_CFG9346 0x50
+#define RTL_REG_CONFIG0 0x51
+#define RTL_REG_CONFIG1 0x52
+/* intr if gp counter reaches this value */
+#define RTL_REG_TIMERINTRREG 0x54
+#define RTL_REG_MEDIASTATUS 0x58
+#define RTL_REG_MEDIASTATUS_MSRTXFLOWENABLE BIT(7)
+#define RTL_REG_MEDIASTATUS_MSRRXFLOWENABLE BIT(6)
+#define RTL_REG_MEDIASTATUS_MSRSPEED10 BIT(3)
+#define RTL_REG_MEDIASTATUS_MSRLINKFAIL BIT(2)
+#define RTL_REG_MEDIASTATUS_MSRRXPAUSEFLAG BIT(1)
+#define RTL_REG_MEDIASTATUS_MSRTXPAUSEFLAG BIT(0)
+#define RTL_REG_CONFIG3 0x59
+#define RTL_REG_MULTIINTR 0x5C
+/* revision of the RTL8139 chip */
+#define RTL_REG_REVISIONID 0x5E
+#define RTL_REG_TXSUMMARY 0x60
+#define RTL_REG_MII_BMCR 0x62
+#define RTL_REG_MII_BMSR 0x64
+#define RTL_REG_NWAYADVERT 0x66
+#define RTL_REG_NWAYLPAR 0x68
+#define RTL_REG_NWAYEXPANSION 0x6A
+#define RTL_REG_DISCONNECTCNT 0x6C
+#define RTL_REG_FALSECARRIERCNT 0x6E
+#define RTL_REG_NWAYTESTREG 0x70
+/* packet received counter */
+#define RTL_REG_RXCNT 0x72
+/* chip status and configuration register */
+#define RTL_REG_CSCR 0x74
+#define RTL_REG_PHYPARM1 0x78
+#define RTL_REG_TWISTERPARM 0x7c
+/* undocumented */
+#define RTL_REG_PHYPARM2 0x80
+/*
+ * from 0x84 onwards are a number of power management/wakeup frame
+ * definitions we will probably never need to know about.
+ */
+#define RTL_STS_RXMULTICAST BIT(15)
+#define RTL_STS_RXPHYSICAL BIT(14)
+#define RTL_STS_RXBROADCAST BIT(13)
+#define RTL_STS_RXBADSYMBOL BIT(5)
+#define RTL_STS_RXRUNT BIT(4)
+#define RTL_STS_RXTOOLONG BIT(3)
+#define RTL_STS_RXCRCERR BIT(2)
+#define RTL_STS_RXBADALIGN BIT(1)
+#define RTL_STS_RXSTATUSOK BIT(0)
+
+static unsigned int cur_rx, cur_tx;
static int ioaddr;
-static unsigned int cur_rx,cur_tx;
/* The RTL8139 can only transmit from a contiguous, aligned memory block. */
-static unsigned char tx_buffer[TX_BUF_SIZE] __attribute__((aligned(4)));
-static unsigned char rx_ring[RX_BUF_LEN+16] __attribute__((aligned(4)));
-
-static int rtl8139_probe(struct eth_device *dev, bd_t *bis);
-static int read_eeprom(int location, int addr_len);
-static void rtl_reset(struct eth_device *dev);
-static int rtl_transmit(struct eth_device *dev, void *packet, int length);
-static int rtl_poll(struct eth_device *dev);
-static void rtl_disable(struct eth_device *dev);
-static int rtl_bcast_addr(struct eth_device *dev, const u8 *bcast_mac, int join)
-{
- return (0);
-}
-
-static struct pci_device_id supported[] = {
- {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139},
- {PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139},
- {}
-};
-
-int rtl8139_initialize(bd_t *bis)
-{
- pci_dev_t devno;
- int card_number = 0;
- struct eth_device *dev;
- u32 iobase;
- int idx=0;
-
- while(1){
- /* Find RTL8139 */
- if ((devno = pci_find_devices(supported, idx++)) < 0)
- break;
-
- pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
- iobase &= ~0xf;
-
- debug ("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
-
- dev = (struct eth_device *)malloc(sizeof *dev);
- if (!dev) {
- printf("Can not allocate memory of rtl8139\n");
- break;
- }
- memset(dev, 0, sizeof(*dev));
-
- sprintf (dev->name, "RTL8139#%d", card_number);
-
- dev->priv = (void *) devno;
- dev->iobase = (int)bus_to_phys(iobase);
- dev->init = rtl8139_probe;
- dev->halt = rtl_disable;
- dev->send = rtl_transmit;
- dev->recv = rtl_poll;
- dev->mcast = rtl_bcast_addr;
-
- eth_register (dev);
-
- card_number++;
-
- pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20);
-
- udelay (10 * 1000);
- }
-
- return card_number;
-}
-
-static int rtl8139_probe(struct eth_device *dev, bd_t *bis)
-{
- int i;
- int addr_len;
- unsigned short *ap = (unsigned short *)dev->enetaddr;
-
- ioaddr = dev->iobase;
-
- /* Bring the chip out of low-power mode. */
- outb(0x00, ioaddr + Config1);
-
- addr_len = read_eeprom(0,8) == 0x8129 ? 8 : 6;
- for (i = 0; i < 3; i++)
- *ap++ = le16_to_cpu (read_eeprom(i + 7, addr_len));
-
- rtl_reset(dev);
-
- if (inb(ioaddr + MediaStatus) & MSRLinkFail) {
- printf("Cable not connected or other link failure\n");
- return -1 ;
- }
-
- return 0;
-}
+static unsigned char tx_buffer[TX_BUF_SIZE] __aligned(4);
+static unsigned char rx_ring[RX_BUF_LEN + 16] __aligned(4);
/* Serial EEPROM section. */
@@ -278,51 +206,57 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis)
#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
#define EE_ENB (0x80 | EE_CS)
-/*
- Delay between EEPROM clock transitions.
- No extra delay is needed with 33MHz PCI, but 66MHz may change this.
-*/
-
-#define eeprom_delay() inl(ee_addr)
-
/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5)
-#define EE_READ_CMD (6)
-#define EE_ERASE_CMD (7)
+#define EE_WRITE_CMD 5
+#define EE_READ_CMD 6
+#define EE_ERASE_CMD 7
-static int read_eeprom(int location, int addr_len)
+static void rtl8139_eeprom_delay(uintptr_t regbase)
{
- int i;
+ /*
+ * Delay between EEPROM clock transitions.
+ * No extra delay is needed with 33MHz PCI, but 66MHz may change this.
+ */
+ inl(regbase + RTL_REG_CFG9346);
+}
+
+static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len)
+{
+ unsigned int read_cmd = location | (EE_READ_CMD << addr_len);
+ uintptr_t ee_addr = ioaddr + RTL_REG_CFG9346;
unsigned int retval = 0;
- long ee_addr = ioaddr + Cfg9346;
- int read_cmd = location | (EE_READ_CMD << addr_len);
+ u8 dataval;
+ int i;
outb(EE_ENB & ~EE_CS, ee_addr);
outb(EE_ENB, ee_addr);
- eeprom_delay();
+ rtl8139_eeprom_delay(ioaddr);
/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ dataval = (read_cmd & BIT(i)) ? EE_DATA_WRITE : 0;
outb(EE_ENB | dataval, ee_addr);
- eeprom_delay();
+ rtl8139_eeprom_delay(ioaddr);
outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
- eeprom_delay();
+ rtl8139_eeprom_delay(ioaddr);
}
+
outb(EE_ENB, ee_addr);
- eeprom_delay();
+ rtl8139_eeprom_delay(ioaddr);
for (i = 16; i > 0; i--) {
outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay();
- retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ rtl8139_eeprom_delay(ioaddr);
+ retval <<= 1;
+ retval |= inb(ee_addr) & EE_DATA_READ;
outb(EE_ENB, ee_addr);
- eeprom_delay();
+ rtl8139_eeprom_delay(ioaddr);
}
/* Terminate the EEPROM access. */
outb(~EE_CS, ee_addr);
- eeprom_delay();
+ rtl8139_eeprom_delay(ioaddr);
+
return retval;
}
@@ -331,149 +265,174 @@ static const unsigned int rtl8139_rx_config =
(RX_FIFO_THRESH << 13) |
(RX_DMA_BURST << 8);
-static void set_rx_mode(struct eth_device *dev) {
- unsigned int mc_filter[2];
- int rx_mode;
+static void rtl8139_set_rx_mode(struct eth_device *dev)
+{
/* !IFF_PROMISC */
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
+ unsigned int rx_mode = RTL_REG_RXCONFIG_ACCEPTBROADCAST |
+ RTL_REG_RXCONFIG_ACCEPTMULTICAST |
+ RTL_REG_RXCONFIG_ACCEPTMYPHYS;
- outl(rtl8139_rx_config | rx_mode, ioaddr + RxConfig);
+ outl(rtl8139_rx_config | rx_mode, ioaddr + RTL_REG_RXCONFIG);
- outl(mc_filter[0], ioaddr + MAR0 + 0);
- outl(mc_filter[1], ioaddr + MAR0 + 4);
+ outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 0);
+ outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 4);
}
-static void rtl_reset(struct eth_device *dev)
+static void rtl8139_hw_reset(struct eth_device *dev)
{
+ u8 reg;
int i;
- outb(CmdReset, ioaddr + ChipCmd);
-
- cur_rx = 0;
- cur_tx = 0;
+ outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD);
/* Give the chip 10ms to finish the reset. */
- for (i=0; i<100; ++i){
- if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;
- udelay (100); /* wait 100us */
+ for (i = 0; i < 100; i++) {
+ reg = inb(ioaddr + RTL_REG_CHIPCMD);
+ if (!(reg & RTL_REG_CHIPCMD_CMDRESET))
+ break;
+
+ udelay(100);
}
+}
+
+static void rtl8139_reset(struct eth_device *dev)
+{
+ int i;
+
+ cur_rx = 0;
+ cur_tx = 0;
+ rtl8139_hw_reset(dev);
for (i = 0; i < ETH_ALEN; i++)
- outb(dev->enetaddr[i], ioaddr + MAC0 + i);
+ outb(dev->enetaddr[i], ioaddr + RTL_REG_MAC0 + i);
/* Must enable Tx/Rx before setting transfer thresholds! */
- outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
- outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8),
- ioaddr + RxConfig); /* accept no frames yet! */
- outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
-
- /* The Linux driver changes Config1 here to use a different LED pattern
- * for half duplex or full/autodetect duplex (for full/autodetect, the
- * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
- * TX/RX, Link100, Link10). This is messy, because it doesn't match
- * the inscription on the mounting bracket. It should not be changed
- * from the configuration EEPROM default, because the card manufacturer
- * should have set that to match the card. */
-
- debug_cond(DEBUG_RX,
- "rx ring address is %lX\n",(unsigned long)rx_ring);
- flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
- outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);
+ outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB,
+ ioaddr + RTL_REG_CHIPCMD);
+
+ /* accept no frames yet! */
+ outl(rtl8139_rx_config, ioaddr + RTL_REG_RXCONFIG);
+ outl((TX_DMA_BURST << 8) | 0x03000000, ioaddr + RTL_REG_TXCONFIG);
+
+ /*
+ * The Linux driver changes RTL_REG_CONFIG1 here to use a different
+ * LED pattern for half duplex or full/autodetect duplex (for
+ * full/autodetect, the outputs are TX/RX, Link10/100, FULL, while
+ * for half duplex it uses TX/RX, Link100, Link10). This is messy,
+ * because it doesn't match the inscription on the mounting bracket.
+ * It should not be changed from the configuration EEPROM default,
+ * because the card manufacturer should have set that to match the
+ * card.
+ */
+ debug_cond(DEBUG_RX, "rx ring address is %p\n", rx_ring);
- /* If we add multicast support, the MAR0 register would have to be
- * initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot
- * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */
+ flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
+ outl(phys_to_bus((int)rx_ring), ioaddr + RTL_REG_RXBUF);
- outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+ /*
+ * If we add multicast support, the RTL_REG_MAR0 register would have
+ * to be initialized to 0xffffffffffffffff (two 32 bit accesses).
+ * Etherboot only needs broadcast (for ARP/RARP/BOOTP/DHCP) and
+ * unicast.
+ */
+ outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB,
+ ioaddr + RTL_REG_CHIPCMD);
- outl(rtl8139_rx_config, ioaddr + RxConfig);
+ outl(rtl8139_rx_config, ioaddr + RTL_REG_RXCONFIG);
/* Start the chip's Tx and Rx process. */
- outl(0, ioaddr + RxMissed);
+ outl(0, ioaddr + RTL_REG_RXMISSED);
- /* set_rx_mode */
- set_rx_mode(dev);
+ rtl8139_set_rx_mode(dev);
/* Disable all known interrupts by setting the interrupt mask. */
- outw(0, ioaddr + IntrMask);
+ outw(0, ioaddr + RTL_REG_INTRMASK);
}
-static int rtl_transmit(struct eth_device *dev, void *packet, int length)
+static int rtl8139_send(struct eth_device *dev, void *packet, int length)
{
- unsigned int status;
- unsigned long txstatus;
unsigned int len = length;
+ unsigned long txstatus;
+ unsigned int status;
int i = 0;
ioaddr = dev->iobase;
- memcpy((char *)tx_buffer, (char *)packet, (int)length);
+ memcpy(tx_buffer, packet, length);
debug_cond(DEBUG_TX, "sending %d bytes\n", len);
- /* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
- * bytes are sent automatically for the FCS, totalling to 64 bytes). */
- while (len < ETH_ZLEN) {
+ /*
+ * Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
+ * bytes are sent automatically for the FCS, totalling to 64 bytes).
+ */
+ while (len < ETH_ZLEN)
tx_buffer[len++] = '\0';
- }
flush_cache((unsigned long)tx_buffer, length);
- outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4);
- outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
- ioaddr + TxStatus0 + cur_tx*4);
+ outl(phys_to_bus((unsigned long)tx_buffer),
+ ioaddr + RTL_REG_TXADDR0 + cur_tx * 4);
+ outl(((TX_FIFO_THRESH << 11) & 0x003f0000) | len,
+ ioaddr + RTL_REG_TXSTATUS0 + cur_tx * 4);
do {
- status = inw(ioaddr + IntrStatus);
- /* Only acknlowledge interrupt sources we can properly handle
- * here - the RxOverflow/RxFIFOOver MUST be handled in the
- * rtl_poll() function. */
- outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
- if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
+ status = inw(ioaddr + RTL_REG_INTRSTATUS);
+ /*
+ * Only acknlowledge interrupt sources we can properly
+ * handle here - the RTL_REG_INTRSTATUS_RXOVERFLOW/
+ * RTL_REG_INTRSTATUS_RXFIFOOVER MUST be handled in the
+ * rtl8139_recv() function.
+ */
+ status &= RTL_REG_INTRSTATUS_TXOK | RTL_REG_INTRSTATUS_TXERR |
+ RTL_REG_INTRSTATUS_PCIERR;
+ outw(status, ioaddr + RTL_REG_INTRSTATUS);
+ if (status)
+ break;
+
udelay(10);
} while (i++ < RTL_TIMEOUT);
- txstatus = inl(ioaddr + TxStatus0 + cur_tx*4);
-
- if (status & TxOK) {
- cur_tx = (cur_tx + 1) % NUM_TX_DESC;
+ txstatus = inl(ioaddr + RTL_REG_TXSTATUS0 + cur_tx * 4);
+ if (!(status & RTL_REG_INTRSTATUS_TXOK)) {
debug_cond(DEBUG_TX,
- "tx done, status %hX txstatus %lX\n",
- status, txstatus);
+ "tx timeout/error (%d usecs), status %hX txstatus %lX\n",
+ 10 * i, status, txstatus);
- return length;
- } else {
-
- debug_cond(DEBUG_TX,
- "tx timeout/error (%d usecs), status %hX txstatus %lX\n",
- 10*i, status, txstatus);
-
- rtl_reset(dev);
+ rtl8139_reset(dev);
return 0;
}
+
+ cur_tx = (cur_tx + 1) % NUM_TX_DESC;
+
+ debug_cond(DEBUG_TX, "tx done, status %hX txstatus %lX\n",
+ status, txstatus);
+
+ return length;
}
-static int rtl_poll(struct eth_device *dev)
+static int rtl8139_recv(struct eth_device *dev)
{
- unsigned int status;
- unsigned int ring_offs;
+ const unsigned int rxstat = RTL_REG_INTRSTATUS_RXFIFOOVER |
+ RTL_REG_INTRSTATUS_RXOVERFLOW |
+ RTL_REG_INTRSTATUS_RXOK;
unsigned int rx_size, rx_status;
- int length=0;
+ unsigned int ring_offs;
+ unsigned int status;
+ int length = 0;
ioaddr = dev->iobase;
- if (inb(ioaddr + ChipCmd) & RxBufEmpty) {
+ if (inb(ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY)
return 0;
- }
- status = inw(ioaddr + IntrStatus);
+ status = inw(ioaddr + RTL_REG_INTRSTATUS);
/* See below for the rest of the interrupt acknowledges. */
- outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
+ outw(status & ~rxstat, ioaddr + RTL_REG_INTRSTATUS);
- debug_cond(DEBUG_RX, "rtl_poll: int %hX ", status);
+ debug_cond(DEBUG_RX, "%s: int %hX ", __func__, status);
ring_offs = cur_rx % RX_BUF_LEN;
/* ring_offs is guaranteed being 4-byte aligned */
@@ -481,52 +440,137 @@ static int rtl_poll(struct eth_device *dev)
rx_size = rx_status >> 16;
rx_status &= 0xffff;
- if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) ||
- (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) {
+ if ((rx_status & (RTL_STS_RXBADSYMBOL | RTL_STS_RXRUNT |
+ RTL_STS_RXTOOLONG | RTL_STS_RXCRCERR |
+ RTL_STS_RXBADALIGN)) ||
+ (rx_size < ETH_ZLEN) ||
+ (rx_size > ETH_FRAME_LEN + 4)) {
printf("rx error %hX\n", rx_status);
- rtl_reset(dev); /* this clears all interrupts still pending */
+ /* this clears all interrupts still pending */
+ rtl8139_reset(dev);
return 0;
}
/* Received a good packet */
length = rx_size - 4; /* no one cares about the FCS */
- if (ring_offs+4+rx_size-4 > RX_BUF_LEN) {
- int semi_count = RX_BUF_LEN - ring_offs - 4;
+ if (ring_offs + 4 + rx_size - 4 > RX_BUF_LEN) {
unsigned char rxdata[RX_BUF_LEN];
+ int semi_count = RX_BUF_LEN - ring_offs - 4;
memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);
- memcpy(&(rxdata[semi_count]), rx_ring, rx_size-4-semi_count);
+ memcpy(&rxdata[semi_count], rx_ring,
+ rx_size - 4 - semi_count);
net_process_received_packet(rxdata, length);
debug_cond(DEBUG_RX, "rx packet %d+%d bytes",
- semi_count, rx_size-4-semi_count);
+ semi_count, rx_size - 4 - semi_count);
} else {
net_process_received_packet(rx_ring + ring_offs + 4, length);
- debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size-4);
+ debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size - 4);
}
flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
- cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
- outw(cur_rx - 16, ioaddr + RxBufPtr);
- /* See RTL8139 Programming Guide V0.1 for the official handling of
- * Rx overflow situations. The document itself contains basically no
- * usable information, except for a few exception handling rules. */
- outw(status & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
+ cur_rx = ROUND(cur_rx + rx_size + 4, 4);
+ outw(cur_rx - 16, ioaddr + RTL_REG_RXBUFPTR);
+ /*
+ * See RTL8139 Programming Guide V0.1 for the official handling of
+ * Rx overflow situations. The document itself contains basically
+ * no usable information, except for a few exception handling rules.
+ */
+ outw(status & rxstat, ioaddr + RTL_REG_INTRSTATUS);
+
return length;
}
-static void rtl_disable(struct eth_device *dev)
+static int rtl8139_init(struct eth_device *dev, bd_t *bis)
{
- int i;
+ unsigned short *ap = (unsigned short *)dev->enetaddr;
+ int addr_len, i;
+ u8 reg;
ioaddr = dev->iobase;
- /* reset the chip */
- outb(CmdReset, ioaddr + ChipCmd);
+ /* Bring the chip out of low-power mode. */
+ outb(0x00, ioaddr + RTL_REG_CONFIG1);
- /* Give the chip 10ms to finish the reset. */
- for (i=0; i<100; ++i){
- if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;
- udelay (100); /* wait 100us */
+ addr_len = rtl8139_read_eeprom(0, 8) == 0x8129 ? 8 : 6;
+ for (i = 0; i < 3; i++)
+ *ap++ = le16_to_cpu(rtl8139_read_eeprom(i + 7, addr_len));
+
+ rtl8139_reset(dev);
+
+ reg = inb(ioaddr + RTL_REG_MEDIASTATUS);
+ if (reg & RTL_REG_MEDIASTATUS_MSRLINKFAIL) {
+ printf("Cable not connected or other link failure\n");
+ return -1;
}
+
+ return 0;
+}
+
+static void rtl8139_stop(struct eth_device *dev)
+{
+ ioaddr = dev->iobase;
+
+ rtl8139_hw_reset(dev);
+}
+
+static int rtl8139_bcast_addr(struct eth_device *dev, const u8 *bcast_mac,
+ int join)
+{
+ return 0;
+}
+
+static struct pci_device_id supported[] = {
+ { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139 },
+ { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139 },
+ { }
+};
+
+int rtl8139_initialize(bd_t *bis)
+{
+ struct eth_device *dev;
+ int card_number = 0;
+ pci_dev_t devno;
+ int idx = 0;
+ u32 iobase;
+
+ while (1) {
+ /* Find RTL8139 */
+ devno = pci_find_devices(supported, idx++);
+ if (devno < 0)
+ break;
+
+ pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
+ iobase &= ~0xf;
+
+ debug("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
+
+ dev = (struct eth_device *)malloc(sizeof(*dev));
+ if (!dev) {
+ printf("Can not allocate memory of rtl8139\n");
+ break;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ sprintf(dev->name, "RTL8139#%d", card_number);
+
+ dev->priv = (void *)devno;
+ dev->iobase = (int)bus_to_phys(iobase);
+ dev->init = rtl8139_init;
+ dev->halt = rtl8139_stop;
+ dev->send = rtl8139_send;
+ dev->recv = rtl8139_recv;
+ dev->mcast = rtl8139_bcast_addr;
+
+ eth_register(dev);
+
+ card_number++;
+
+ pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20);
+
+ udelay(10 * 1000);
+ }
+
+ return card_number;
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 257b0385c2..45ecd6a263 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -10,84 +10,239 @@
#include <malloc.h>
#include <net.h>
#include <miiphy.h>
+#include <linux/io.h>
+#include <linux/types.h>
#include "smc911x.h"
-u32 pkt_data_pull(struct eth_device *dev, u32 addr) \
- __attribute__ ((weak, alias ("smc911x_reg_read")));
-void pkt_data_push(struct eth_device *dev, u32 addr, u32 val) \
- __attribute__ ((weak, alias ("smc911x_reg_write")));
+struct chip_id {
+ u16 id;
+ char *name;
+};
-static void smc911x_handle_mac_address(struct eth_device *dev)
+struct smc911x_priv {
+#ifndef CONFIG_DM_ETH
+ struct eth_device dev;
+#endif
+ phys_addr_t iobase;
+ const struct chip_id *chipid;
+ unsigned char enetaddr[6];
+};
+
+static const struct chip_id chip_ids[] = {
+ { CHIP_89218, "LAN89218" },
+ { CHIP_9115, "LAN9115" },
+ { CHIP_9116, "LAN9116" },
+ { CHIP_9117, "LAN9117" },
+ { CHIP_9118, "LAN9118" },
+ { CHIP_9211, "LAN9211" },
+ { CHIP_9215, "LAN9215" },
+ { CHIP_9216, "LAN9216" },
+ { CHIP_9217, "LAN9217" },
+ { CHIP_9218, "LAN9218" },
+ { CHIP_9220, "LAN9220" },
+ { CHIP_9221, "LAN9221" },
+ { 0, NULL },
+};
+
+#define DRIVERNAME "smc911x"
+
+#if defined (CONFIG_SMC911X_32_BIT) && \
+ defined (CONFIG_SMC911X_16_BIT)
+#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
+ CONFIG_SMC911X_16_BIT shall be set"
+#endif
+
+#if defined (CONFIG_SMC911X_32_BIT)
+static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset)
+{
+ return readl(priv->iobase + offset);
+}
+
+static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val)
+{
+ writel(val, priv->iobase + offset);
+}
+#elif defined (CONFIG_SMC911X_16_BIT)
+static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset)
+{
+ return (readw(priv->iobase + offset) & 0xffff) |
+ (readw(priv->iobase + offset + 2) << 16);
+}
+static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val)
+{
+ writew(val & 0xffff, priv->iobase + offset);
+ writew(val >> 16, priv->iobase + offset + 2);
+}
+#else
+#error "SMC911X: undefined bus width"
+#endif /* CONFIG_SMC911X_16_BIT */
+
+static u32 smc911x_get_mac_csr(struct smc911x_priv *priv, u8 reg)
+{
+ while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(priv, MAC_CSR_CMD,
+ MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
+ while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+
+ return smc911x_reg_read(priv, MAC_CSR_DATA);
+}
+
+static void smc911x_set_mac_csr(struct smc911x_priv *priv, u8 reg, u32 data)
+{
+ while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(priv, MAC_CSR_DATA, data);
+ smc911x_reg_write(priv, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
+ while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+}
+
+static int smc911x_detect_chip(struct smc911x_priv *priv)
+{
+ unsigned long val, i;
+
+ val = smc911x_reg_read(priv, BYTE_TEST);
+ if (val == 0xffffffff) {
+ /* Special case -- no chip present */
+ return -1;
+ } else if (val != 0x87654321) {
+ printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
+ return -1;
+ }
+
+ val = smc911x_reg_read(priv, ID_REV) >> 16;
+ for (i = 0; chip_ids[i].id != 0; i++) {
+ if (chip_ids[i].id == val) break;
+ }
+ if (!chip_ids[i].id) {
+ printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
+ return -1;
+ }
+
+ priv->chipid = &chip_ids[i];
+
+ return 0;
+}
+
+static void smc911x_reset(struct smc911x_priv *priv)
+{
+ int timeout;
+
+ /*
+ * Take out of PM setting first
+ * Device is already wake up if PMT_CTRL_READY bit is set
+ */
+ if ((smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY) == 0) {
+ /* Write to the bytetest will take out of powerdown */
+ smc911x_reg_write(priv, BYTE_TEST, 0x0);
+
+ timeout = 10;
+
+ while (timeout-- &&
+ !(smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY))
+ udelay(10);
+ if (timeout < 0) {
+ printf(DRIVERNAME
+ ": timeout waiting for PM restore\n");
+ return;
+ }
+ }
+
+ /* Disable interrupts */
+ smc911x_reg_write(priv, INT_EN, 0);
+
+ smc911x_reg_write(priv, HW_CFG, HW_CFG_SRST);
+
+ timeout = 1000;
+ while (timeout-- && smc911x_reg_read(priv, E2P_CMD) & E2P_CMD_EPC_BUSY)
+ udelay(10);
+
+ if (timeout < 0) {
+ printf(DRIVERNAME ": reset timeout\n");
+ return;
+ }
+
+ /* Reset the FIFO level and flow control settings */
+ smc911x_set_mac_csr(priv, FLOW, FLOW_FCPT | FLOW_FCEN);
+ smc911x_reg_write(priv, AFC_CFG, 0x0050287F);
+
+ /* Set to LED outputs */
+ smc911x_reg_write(priv, GPIO_CFG, 0x70070000);
+}
+
+static void smc911x_handle_mac_address(struct smc911x_priv *priv)
{
unsigned long addrh, addrl;
- uchar *m = dev->enetaddr;
+ unsigned char *m = priv->enetaddr;
addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
addrh = m[4] | (m[5] << 8);
- smc911x_set_mac_csr(dev, ADDRL, addrl);
- smc911x_set_mac_csr(dev, ADDRH, addrh);
+ smc911x_set_mac_csr(priv, ADDRL, addrl);
+ smc911x_set_mac_csr(priv, ADDRH, addrh);
printf(DRIVERNAME ": MAC %pM\n", m);
}
-static int smc911x_eth_phy_read(struct eth_device *dev,
+static int smc911x_eth_phy_read(struct smc911x_priv *priv,
u8 phy, u8 reg, u16 *val)
{
- while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
;
- smc911x_set_mac_csr(dev, MII_ACC, phy << 11 | reg << 6 |
+ smc911x_set_mac_csr(priv, MII_ACC, phy << 11 | reg << 6 |
MII_ACC_MII_BUSY);
- while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
;
- *val = smc911x_get_mac_csr(dev, MII_DATA);
+ *val = smc911x_get_mac_csr(priv, MII_DATA);
return 0;
}
-static int smc911x_eth_phy_write(struct eth_device *dev,
+static int smc911x_eth_phy_write(struct smc911x_priv *priv,
u8 phy, u8 reg, u16 val)
{
- while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
;
- smc911x_set_mac_csr(dev, MII_DATA, val);
- smc911x_set_mac_csr(dev, MII_ACC,
+ smc911x_set_mac_csr(priv, MII_DATA, val);
+ smc911x_set_mac_csr(priv, MII_ACC,
phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE);
- while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
+ while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
;
return 0;
}
-static int smc911x_phy_reset(struct eth_device *dev)
+static int smc911x_phy_reset(struct smc911x_priv *priv)
{
u32 reg;
- reg = smc911x_reg_read(dev, PMT_CTRL);
+ reg = smc911x_reg_read(priv, PMT_CTRL);
reg &= ~0xfffff030;
reg |= PMT_CTRL_PHY_RST;
- smc911x_reg_write(dev, PMT_CTRL, reg);
+ smc911x_reg_write(priv, PMT_CTRL, reg);
mdelay(100);
return 0;
}
-static void smc911x_phy_configure(struct eth_device *dev)
+static void smc911x_phy_configure(struct smc911x_priv *priv)
{
int timeout;
u16 status;
- smc911x_phy_reset(dev);
+ smc911x_phy_reset(priv);
- smc911x_eth_phy_write(dev, 1, MII_BMCR, BMCR_RESET);
+ smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_RESET);
mdelay(1);
- smc911x_eth_phy_write(dev, 1, MII_ADVERTISE, 0x01e1);
- smc911x_eth_phy_write(dev, 1, MII_BMCR, BMCR_ANENABLE |
+ smc911x_eth_phy_write(priv, 1, MII_ADVERTISE, 0x01e1);
+ smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_ANENABLE |
BMCR_ANRESTART);
timeout = 5000;
@@ -96,7 +251,7 @@ static void smc911x_phy_configure(struct eth_device *dev)
if ((timeout--) == 0)
goto err_out;
- if (smc911x_eth_phy_read(dev, 1, MII_BMSR, &status) != 0)
+ if (smc911x_eth_phy_read(priv, 1, MII_BMSR, &status) != 0)
goto err_out;
} while (!(status & BMSR_LSTATUS));
@@ -108,65 +263,65 @@ err_out:
printf(DRIVERNAME ": autonegotiation timed out\n");
}
-static void smc911x_enable(struct eth_device *dev)
+static void smc911x_enable(struct smc911x_priv *priv)
{
/* Enable TX */
- smc911x_reg_write(dev, HW_CFG, 8 << 16 | HW_CFG_SF);
+ smc911x_reg_write(priv, HW_CFG, 8 << 16 | HW_CFG_SF);
- smc911x_reg_write(dev, GPT_CFG, GPT_CFG_TIMER_EN | 10000);
+ smc911x_reg_write(priv, GPT_CFG, GPT_CFG_TIMER_EN | 10000);
- smc911x_reg_write(dev, TX_CFG, TX_CFG_TX_ON);
+ smc911x_reg_write(priv, TX_CFG, TX_CFG_TX_ON);
/* no padding to start of packets */
- smc911x_reg_write(dev, RX_CFG, 0);
+ smc911x_reg_write(priv, RX_CFG, 0);
- smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
+ smc911x_set_mac_csr(priv, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
MAC_CR_HBDIS);
-
}
-static int smc911x_init(struct eth_device *dev, bd_t * bd)
+static int smc911x_init_common(struct smc911x_priv *priv)
{
- struct chip_id *id = dev->priv;
+ const struct chip_id *id = priv->chipid;
printf(DRIVERNAME ": detected %s controller\n", id->name);
- smc911x_reset(dev);
+ smc911x_reset(priv);
/* Configure the PHY, initialize the link state */
- smc911x_phy_configure(dev);
+ smc911x_phy_configure(priv);
- smc911x_handle_mac_address(dev);
+ smc911x_handle_mac_address(priv);
/* Turn on Tx + Rx */
- smc911x_enable(dev);
+ smc911x_enable(priv);
return 0;
}
-static int smc911x_send(struct eth_device *dev, void *packet, int length)
+static int smc911x_send_common(struct smc911x_priv *priv,
+ void *packet, int length)
{
u32 *data = (u32*)packet;
u32 tmplen;
u32 status;
- smc911x_reg_write(dev, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG |
+ smc911x_reg_write(priv, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG |
TX_CMD_A_INT_LAST_SEG | length);
- smc911x_reg_write(dev, TX_DATA_FIFO, length);
+ smc911x_reg_write(priv, TX_DATA_FIFO, length);
tmplen = (length + 3) / 4;
while (tmplen--)
- pkt_data_push(dev, TX_DATA_FIFO, *data++);
+ smc911x_reg_write(priv, TX_DATA_FIFO, *data++);
/* wait for transmission */
- while (!((smc911x_reg_read(dev, TX_FIFO_INF) &
+ while (!((smc911x_reg_read(priv, TX_FIFO_INF) &
TX_FIFO_INF_TSUSED) >> 16));
/* get status. Ignore 'no carrier' error, it has no meaning for
* full duplex operation
*/
- status = smc911x_reg_read(dev, TX_STATUS_FIFO) &
+ status = smc911x_reg_read(priv, TX_STATUS_FIFO) &
(TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL |
TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
@@ -183,117 +338,296 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length)
return -1;
}
-static void smc911x_halt(struct eth_device *dev)
+static void smc911x_halt_common(struct smc911x_priv *priv)
{
- smc911x_reset(dev);
- smc911x_handle_mac_address(dev);
+ smc911x_reset(priv);
+ smc911x_handle_mac_address(priv);
}
-static int smc911x_rx(struct eth_device *dev)
+static int smc911x_recv_common(struct smc911x_priv *priv, u32 *data)
{
- u32 *data = (u32 *)net_rx_packets[0];
u32 pktlen, tmplen;
u32 status;
- if ((smc911x_reg_read(dev, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
- status = smc911x_reg_read(dev, RX_STATUS_FIFO);
- pktlen = (status & RX_STS_PKT_LEN) >> 16;
+ status = smc911x_reg_read(priv, RX_FIFO_INF);
+ if (!(status & RX_FIFO_INF_RXSUSED))
+ return 0;
- smc911x_reg_write(dev, RX_CFG, 0);
+ status = smc911x_reg_read(priv, RX_STATUS_FIFO);
+ pktlen = (status & RX_STS_PKT_LEN) >> 16;
- tmplen = (pktlen + 3) / 4;
- while (tmplen--)
- *data++ = pkt_data_pull(dev, RX_DATA_FIFO);
+ smc911x_reg_write(priv, RX_CFG, 0);
- if (status & RX_STS_ES)
- printf(DRIVERNAME
- ": dropped bad packet. Status: 0x%08x\n",
- status);
- else
- net_process_received_packet(net_rx_packets[0], pktlen);
+ tmplen = (pktlen + 3) / 4;
+ while (tmplen--)
+ *data++ = smc911x_reg_read(priv, RX_DATA_FIFO);
+
+ if (status & RX_STS_ES) {
+ printf(DRIVERNAME
+ ": dropped bad packet. Status: 0x%08x\n",
+ status);
+ return 0;
}
- return 0;
+ return pktlen;
}
+#ifndef CONFIG_DM_ETH
+
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
/* wrapper for smc911x_eth_phy_read */
static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad,
int reg)
{
- u16 val = 0;
struct eth_device *dev = eth_get_dev_by_name(bus->name);
- if (dev) {
- int retval = smc911x_eth_phy_read(dev, phy, reg, &val);
- if (retval < 0)
- return retval;
- return val;
- }
- return -ENODEV;
+ struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
+ u16 val = 0;
+ int ret;
+
+ if (!dev || !priv)
+ return -ENODEV;
+
+ ret = smc911x_eth_phy_read(priv, phy, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ return val;
}
+
/* wrapper for smc911x_eth_phy_write */
static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad,
int reg, u16 val)
{
struct eth_device *dev = eth_get_dev_by_name(bus->name);
- if (dev)
- return smc911x_eth_phy_write(dev, phy, reg, val);
- return -ENODEV;
+ struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
+
+ if (!dev || !priv)
+ return -ENODEV;
+
+ return smc911x_eth_phy_write(priv, phy, reg, val);
+}
+
+static int smc911x_initialize_mii(struct smc911x_priv *priv)
+{
+ struct mii_dev *mdiodev = mdio_alloc();
+ int ret;
+
+ if (!mdiodev)
+ return -ENOMEM;
+
+ strncpy(mdiodev->name, priv->dev.name, MDIO_NAME_LEN);
+ mdiodev->read = smc911x_miiphy_read;
+ mdiodev->write = smc911x_miiphy_write;
+
+ ret = mdio_register(mdiodev);
+ if (ret < 0) {
+ mdio_free(mdiodev);
+ return ret;
+ }
+
+ return 0;
+}
+#else
+static int smc911x_initialize_mii(struct smc911x_priv *priv)
+{
+ return 0;
}
#endif
+static int smc911x_init(struct eth_device *dev, bd_t *bd)
+{
+ struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
+
+ return smc911x_init_common(priv);
+}
+
+static void smc911x_halt(struct eth_device *dev)
+{
+ struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
+
+ smc911x_halt_common(priv);
+}
+
+static int smc911x_send(struct eth_device *dev, void *packet, int length)
+{
+ struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
+
+ return smc911x_send_common(priv, packet, length);
+}
+
+static int smc911x_recv(struct eth_device *dev)
+{
+ struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
+ u32 *data = (u32 *)net_rx_packets[0];
+ int ret;
+
+ ret = smc911x_recv_common(priv, data);
+ if (ret)
+ net_process_received_packet(net_rx_packets[0], ret);
+
+ return ret;
+}
+
int smc911x_initialize(u8 dev_num, int base_addr)
{
unsigned long addrl, addrh;
- struct eth_device *dev;
+ struct smc911x_priv *priv;
+ int ret;
- dev = malloc(sizeof(*dev));
- if (!dev) {
- return -1;
- }
- memset(dev, 0, sizeof(*dev));
+ priv = calloc(1, sizeof(*priv));
+ if (!priv)
+ return -ENOMEM;
- dev->iobase = base_addr;
+ priv->iobase = base_addr;
+ priv->dev.iobase = base_addr;
/* Try to detect chip. Will fail if not present. */
- if (smc911x_detect_chip(dev)) {
- free(dev);
- return 0;
+ ret = smc911x_detect_chip(priv);
+ if (ret) {
+ ret = 0; /* Card not detected is not an error */
+ goto err_detect;
}
- addrh = smc911x_get_mac_csr(dev, ADDRH);
- addrl = smc911x_get_mac_csr(dev, ADDRL);
+ addrh = smc911x_get_mac_csr(priv, ADDRH);
+ addrl = smc911x_get_mac_csr(priv, ADDRL);
if (!(addrl == 0xffffffff && addrh == 0x0000ffff)) {
/* address is obtained from optional eeprom */
- dev->enetaddr[0] = addrl;
- dev->enetaddr[1] = addrl >> 8;
- dev->enetaddr[2] = addrl >> 16;
- dev->enetaddr[3] = addrl >> 24;
- dev->enetaddr[4] = addrh;
- dev->enetaddr[5] = addrh >> 8;
+ priv->enetaddr[0] = addrl;
+ priv->enetaddr[1] = addrl >> 8;
+ priv->enetaddr[2] = addrl >> 16;
+ priv->enetaddr[3] = addrl >> 24;
+ priv->enetaddr[4] = addrh;
+ priv->enetaddr[5] = addrh >> 8;
+ memcpy(priv->dev.enetaddr, priv->enetaddr, 6);
}
- dev->init = smc911x_init;
- dev->halt = smc911x_halt;
- dev->send = smc911x_send;
- dev->recv = smc911x_rx;
- sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
+ priv->dev.init = smc911x_init;
+ priv->dev.halt = smc911x_halt;
+ priv->dev.send = smc911x_send;
+ priv->dev.recv = smc911x_recv;
+ sprintf(priv->dev.name, "%s-%hu", DRIVERNAME, dev_num);
- eth_register(dev);
+ eth_register(&priv->dev);
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- int retval;
- struct mii_dev *mdiodev = mdio_alloc();
- if (!mdiodev)
- return -ENOMEM;
- strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
- mdiodev->read = smc911x_miiphy_read;
- mdiodev->write = smc911x_miiphy_write;
-
- retval = mdio_register(mdiodev);
- if (retval < 0)
- return retval;
-#endif
+ ret = smc911x_initialize_mii(priv);
+ if (ret)
+ goto err_mii;
return 1;
+
+err_mii:
+ eth_unregister(&priv->dev);
+err_detect:
+ free(priv);
+ return ret;
+}
+
+#else /* ifdef CONFIG_DM_ETH */
+
+static int smc911x_start(struct udevice *dev)
+{
+ struct eth_pdata *plat = dev_get_platdata(dev);
+ struct smc911x_priv *priv = dev_get_priv(dev);
+
+ memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
+
+ return smc911x_init_common(priv);
+}
+
+static void smc911x_stop(struct udevice *dev)
+{
+ struct smc911x_priv *priv = dev_get_priv(dev);
+
+ smc911x_halt_common(priv);
+}
+
+static int smc911x_send(struct udevice *dev, void *packet, int length)
+{
+ struct smc911x_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = smc911x_send_common(priv, packet, length);
+
+ return ret ? 0 : -ETIMEDOUT;
+}
+
+static int smc911x_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct smc911x_priv *priv = dev_get_priv(dev);
+ u32 *data = (u32 *)net_rx_packets[0];
+ int ret;
+
+ ret = smc911x_recv_common(priv, data);
+ if (ret)
+ *packetp = (void *)data;
+
+ return ret ? ret : -EAGAIN;
+}
+
+static int smc911x_bind(struct udevice *dev)
+{
+ return device_set_name(dev, dev->name);
}
+
+static int smc911x_probe(struct udevice *dev)
+{
+ struct smc911x_priv *priv = dev_get_priv(dev);
+ unsigned long addrh, addrl;
+ int ret;
+
+ /* Try to detect chip. Will fail if not present. */
+ ret = smc911x_detect_chip(priv);
+ if (ret)
+ return ret;
+
+ addrh = smc911x_get_mac_csr(priv, ADDRH);
+ addrl = smc911x_get_mac_csr(priv, ADDRL);
+ if (!(addrl == 0xffffffff && addrh == 0x0000ffff)) {
+ /* address is obtained from optional eeprom */
+ priv->enetaddr[0] = addrl;
+ priv->enetaddr[1] = addrl >> 8;
+ priv->enetaddr[2] = addrl >> 16;
+ priv->enetaddr[3] = addrl >> 24;
+ priv->enetaddr[4] = addrh;
+ priv->enetaddr[5] = addrh >> 8;
+ }
+
+ return 0;
+}
+
+static int smc911x_ofdata_to_platdata(struct udevice *dev)
+{
+ struct smc911x_priv *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ pdata->iobase = devfdt_get_addr(dev);
+ priv->iobase = pdata->iobase;
+
+ return 0;
+}
+
+static const struct eth_ops smc911x_ops = {
+ .start = smc911x_start,
+ .send = smc911x_send,
+ .recv = smc911x_recv,
+ .stop = smc911x_stop,
+};
+
+static const struct udevice_id smc911x_ids[] = {
+ { .compatible = "smsc,lan9115" },
+ { }
+};
+
+U_BOOT_DRIVER(smc911x) = {
+ .name = "eth_smc911x",
+ .id = UCLASS_ETH,
+ .of_match = smc911x_ids,
+ .bind = smc911x_bind,
+ .ofdata_to_platdata = smc911x_ofdata_to_platdata,
+ .probe = smc911x_probe,
+ .ops = &smc911x_ops,
+ .priv_auto_alloc_size = sizeof(struct smc911x_priv),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 3145fbde2b..ce66900f4c 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -8,47 +8,6 @@
#ifndef _SMC911X_H_
#define _SMC911X_H_
-#include <linux/types.h>
-
-#define DRIVERNAME "smc911x"
-
-#if defined (CONFIG_SMC911X_32_BIT) && \
- defined (CONFIG_SMC911X_16_BIT)
-#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
- CONFIG_SMC911X_16_BIT shall be set"
-#endif
-
-#if defined (CONFIG_SMC911X_32_BIT)
-static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset)
-{
- return *(volatile u32*)(dev->iobase + offset);
-}
-u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
- __attribute__((weak, alias("__smc911x_reg_read")));
-
-static inline void __smc911x_reg_write(struct eth_device *dev,
- u32 offset, u32 val)
-{
- *(volatile u32*)(dev->iobase + offset) = val;
-}
-void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
- __attribute__((weak, alias("__smc911x_reg_write")));
-#elif defined (CONFIG_SMC911X_16_BIT)
-static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
-{
- volatile u16 *addr_16 = (u16 *)(dev->iobase + offset);
- return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16));
-}
-static inline void smc911x_reg_write(struct eth_device *dev,
- u32 offset, u32 val)
-{
- *(volatile u16 *)(dev->iobase + offset) = (u16)val;
- *(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16);
-}
-#else
-#error "SMC911X: undefined bus width"
-#endif /* CONFIG_SMC911X_16_BIT */
-
/* Below are the register offsets and bit definitions
* of the Lan911x memory space
*/
@@ -380,120 +339,4 @@ static inline void smc911x_reg_write(struct eth_device *dev,
#define CHIP_9220 0x9220
#define CHIP_9221 0x9221
-struct chip_id {
- u16 id;
- char *name;
-};
-
-static const struct chip_id chip_ids[] = {
- { CHIP_89218, "LAN89218" },
- { CHIP_9115, "LAN9115" },
- { CHIP_9116, "LAN9116" },
- { CHIP_9117, "LAN9117" },
- { CHIP_9118, "LAN9118" },
- { CHIP_9211, "LAN9211" },
- { CHIP_9215, "LAN9215" },
- { CHIP_9216, "LAN9216" },
- { CHIP_9217, "LAN9217" },
- { CHIP_9218, "LAN9218" },
- { CHIP_9220, "LAN9220" },
- { CHIP_9221, "LAN9221" },
- { 0, NULL },
-};
-
-static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg)
-{
- while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
- ;
- smc911x_reg_write(dev, MAC_CSR_CMD,
- MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
- while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
- ;
-
- return smc911x_reg_read(dev, MAC_CSR_DATA);
-}
-
-static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data)
-{
- while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
- ;
- smc911x_reg_write(dev, MAC_CSR_DATA, data);
- smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
- while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
- ;
-}
-
-static int smc911x_detect_chip(struct eth_device *dev)
-{
- unsigned long val, i;
-
- val = smc911x_reg_read(dev, BYTE_TEST);
- if (val == 0xffffffff) {
- /* Special case -- no chip present */
- return -1;
- } else if (val != 0x87654321) {
- printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
- return -1;
- }
-
- val = smc911x_reg_read(dev, ID_REV) >> 16;
- for (i = 0; chip_ids[i].id != 0; i++) {
- if (chip_ids[i].id == val) break;
- }
- if (!chip_ids[i].id) {
- printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
- return -1;
- }
-
- dev->priv = (void *)&chip_ids[i];
-
- return 0;
-}
-
-static void smc911x_reset(struct eth_device *dev)
-{
- int timeout;
-
- /*
- * Take out of PM setting first
- * Device is already wake up if PMT_CTRL_READY bit is set
- */
- if ((smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) == 0) {
- /* Write to the bytetest will take out of powerdown */
- smc911x_reg_write(dev, BYTE_TEST, 0x0);
-
- timeout = 10;
-
- while (timeout-- &&
- !(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY))
- udelay(10);
- if (timeout < 0) {
- printf(DRIVERNAME
- ": timeout waiting for PM restore\n");
- return;
- }
- }
-
- /* Disable interrupts */
- smc911x_reg_write(dev, INT_EN, 0);
-
- smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST);
-
- timeout = 1000;
- while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
- udelay(10);
-
- if (timeout < 0) {
- printf(DRIVERNAME ": reset timeout\n");
- return;
- }
-
- /* Reset the FIFO level and flow control settings */
- smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN);
- smc911x_reg_write(dev, AFC_CFG, 0x0050287F);
-
- /* Set to LED outputs */
- smc911x_reg_write(dev, GPIO_CFG, 0x70070000);
-}
-
#endif
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
index edb6152bb9..e4b22d79eb 100644
--- a/drivers/rng/Kconfig
+++ b/drivers/rng/Kconfig
@@ -31,4 +31,12 @@ config RNG_STM32MP1
help
Enable STM32MP1 rng driver.
+config RNG_ROCKCHIP
+ bool "Enable random number generator for rockchip crypto rng"
+ depends on ARCH_ROCKCHIP && DM_RNG
+ default n
+ help
+ Enable random number generator for rockchip.This driver is
+ support rng module of crypto v1 and crypto v2.
+
endif
diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile
index 6a8a66779b..44a0003917 100644
--- a/drivers/rng/Makefile
+++ b/drivers/rng/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_DM_RNG) += rng-uclass.o
obj-$(CONFIG_RNG_MESON) += meson-rng.o
obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o
obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_rng.o
+obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o
diff --git a/drivers/rng/rockchip_rng.c b/drivers/rng/rockchip_rng.c
new file mode 100644
index 0000000000..47fb140077
--- /dev/null
+++ b/drivers/rng/rockchip_rng.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 Fuzhou Rockchip Electronics Co., Ltd
+ */
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <linux/iopoll.h>
+#include <linux/string.h>
+#include <rng.h>
+
+#define RK_HW_RNG_MAX 32
+
+#define _SBF(s, v) ((v) << (s))
+
+/* start of CRYPTO V1 register define */
+#define CRYPTO_V1_CTRL 0x0008
+#define CRYPTO_V1_RNG_START BIT(8)
+#define CRYPTO_V1_RNG_FLUSH BIT(9)
+
+#define CRYPTO_V1_TRNG_CTRL 0x0200
+#define CRYPTO_V1_OSC_ENABLE BIT(16)
+#define CRYPTO_V1_TRNG_SAMPLE_PERIOD(x) (x)
+
+#define CRYPTO_V1_TRNG_DOUT_0 0x0204
+/* end of CRYPTO V1 register define */
+
+/* start of CRYPTO V2 register define */
+#define CRYPTO_V2_RNG_CTL 0x0400
+#define CRYPTO_V2_RNG_64_BIT_LEN _SBF(4, 0x00)
+#define CRYPTO_V2_RNG_128_BIT_LEN _SBF(4, 0x01)
+#define CRYPTO_V2_RNG_192_BIT_LEN _SBF(4, 0x02)
+#define CRYPTO_V2_RNG_256_BIT_LEN _SBF(4, 0x03)
+#define CRYPTO_V2_RNG_FATESY_SOC_RING _SBF(2, 0x00)
+#define CRYPTO_V2_RNG_SLOWER_SOC_RING_0 _SBF(2, 0x01)
+#define CRYPTO_V2_RNG_SLOWER_SOC_RING_1 _SBF(2, 0x02)
+#define CRYPTO_V2_RNG_SLOWEST_SOC_RING _SBF(2, 0x03)
+#define CRYPTO_V2_RNG_ENABLE BIT(1)
+#define CRYPTO_V2_RNG_START BIT(0)
+#define CRYPTO_V2_RNG_SAMPLE_CNT 0x0404
+#define CRYPTO_V2_RNG_DOUT_0 0x0410
+/* end of CRYPTO V2 register define */
+
+#define RK_RNG_TIME_OUT 50000 /* max 50ms */
+
+struct rk_rng_soc_data {
+ int (*rk_rng_read)(struct udevice *dev, void *data, size_t len);
+};
+
+struct rk_rng_platdata {
+ fdt_addr_t base;
+ struct rk_rng_soc_data *soc_data;
+};
+
+static int rk_rng_read_regs(fdt_addr_t addr, void *buf, size_t size)
+{
+ u32 count = RK_HW_RNG_MAX / sizeof(u32);
+ u32 reg, tmp_len;
+
+ if (size > RK_HW_RNG_MAX)
+ return -EINVAL;
+
+ while (size && count) {
+ reg = readl(addr);
+ tmp_len = min(size, sizeof(u32));
+ memcpy(buf, &reg, tmp_len);
+ addr += sizeof(u32);
+ buf += tmp_len;
+ size -= tmp_len;
+ count--;
+ }
+
+ return 0;
+}
+
+static int rk_v1_rng_read(struct udevice *dev, void *data, size_t len)
+{
+ struct rk_rng_platdata *pdata = dev_get_priv(dev);
+ u32 reg = 0;
+ int retval;
+
+ if (len > RK_HW_RNG_MAX)
+ return -EINVAL;
+
+ /* enable osc_ring to get entropy, sample period is set as 100 */
+ writel(CRYPTO_V1_OSC_ENABLE | CRYPTO_V1_TRNG_SAMPLE_PERIOD(100),
+ pdata->base + CRYPTO_V1_TRNG_CTRL);
+
+ rk_clrsetreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START,
+ CRYPTO_V1_RNG_START);
+
+ retval = readl_poll_timeout(pdata->base + CRYPTO_V1_CTRL, reg,
+ !(reg & CRYPTO_V1_RNG_START),
+ RK_RNG_TIME_OUT);
+ if (retval)
+ goto exit;
+
+ rk_rng_read_regs(pdata->base + CRYPTO_V1_TRNG_DOUT_0, data, len);
+
+exit:
+ /* close TRNG */
+ rk_clrreg(pdata->base + CRYPTO_V1_CTRL, CRYPTO_V1_RNG_START);
+
+ return 0;
+}
+
+static int rk_v2_rng_read(struct udevice *dev, void *data, size_t len)
+{
+ struct rk_rng_platdata *pdata = dev_get_priv(dev);
+ u32 reg = 0;
+ int retval;
+
+ if (len > RK_HW_RNG_MAX)
+ return -EINVAL;
+
+ /* enable osc_ring to get entropy, sample period is set as 100 */
+ writel(100, pdata->base + CRYPTO_V2_RNG_SAMPLE_CNT);
+
+ reg |= CRYPTO_V2_RNG_256_BIT_LEN;
+ reg |= CRYPTO_V2_RNG_SLOWER_SOC_RING_0;
+ reg |= CRYPTO_V2_RNG_ENABLE;
+ reg |= CRYPTO_V2_RNG_START;
+
+ rk_clrsetreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff, reg);
+
+ retval = readl_poll_timeout(pdata->base + CRYPTO_V2_RNG_CTL, reg,
+ !(reg & CRYPTO_V2_RNG_START),
+ RK_RNG_TIME_OUT);
+ if (retval)
+ goto exit;
+
+ rk_rng_read_regs(pdata->base + CRYPTO_V2_RNG_DOUT_0, data, len);
+
+exit:
+ /* close TRNG */
+ rk_clrreg(pdata->base + CRYPTO_V2_RNG_CTL, 0xffff);
+
+ return retval;
+}
+
+static int rockchip_rng_read(struct udevice *dev, void *data, size_t len)
+{
+ unsigned char *buf = data;
+ unsigned int i;
+ int ret = -EIO;
+
+ struct rk_rng_platdata *pdata = dev_get_priv(dev);
+
+ if (!len)
+ return 0;
+
+ if (!pdata->soc_data || !pdata->soc_data->rk_rng_read)
+ return -EINVAL;
+
+ for (i = 0; i < len / RK_HW_RNG_MAX; i++, buf += RK_HW_RNG_MAX) {
+ ret = pdata->soc_data->rk_rng_read(dev, buf, RK_HW_RNG_MAX);
+ if (ret)
+ goto exit;
+ }
+
+ if (len % RK_HW_RNG_MAX)
+ ret = pdata->soc_data->rk_rng_read(dev, buf,
+ len % RK_HW_RNG_MAX);
+
+exit:
+ return ret;
+}
+
+static int rockchip_rng_ofdata_to_platdata(struct udevice *dev)
+{
+ struct rk_rng_platdata *pdata = dev_get_priv(dev);
+
+ memset(pdata, 0x00, sizeof(*pdata));
+
+ pdata->base = (fdt_addr_t)dev_read_addr_ptr(dev);
+ if (!pdata->base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int rockchip_rng_probe(struct udevice *dev)
+{
+ struct rk_rng_platdata *pdata = dev_get_priv(dev);
+
+ pdata->soc_data = (struct rk_rng_soc_data *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+static const struct rk_rng_soc_data rk_rng_v1_soc_data = {
+ .rk_rng_read = rk_v1_rng_read,
+};
+
+static const struct rk_rng_soc_data rk_rng_v2_soc_data = {
+ .rk_rng_read = rk_v2_rng_read,
+};
+
+static const struct dm_rng_ops rockchip_rng_ops = {
+ .read = rockchip_rng_read,
+};
+
+static const struct udevice_id rockchip_rng_match[] = {
+ {
+ .compatible = "rockchip,cryptov1-rng",
+ .data = (ulong)&rk_rng_v1_soc_data,
+ },
+ {
+ .compatible = "rockchip,cryptov2-rng",
+ .data = (ulong)&rk_rng_v2_soc_data,
+ },
+ {},
+};
+
+U_BOOT_DRIVER(rockchip_rng) = {
+ .name = "rockchip-rng",
+ .id = UCLASS_RNG,
+ .of_match = rockchip_rng_match,
+ .ops = &rockchip_rng_ops,
+ .probe = rockchip_rng_probe,
+ .ofdata_to_platdata = rockchip_rng_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct rk_rng_platdata),
+};
diff --git a/drivers/rtc/pcf2127.c b/drivers/rtc/pcf2127.c
index f6953505a5..b34ed63bf0 100644
--- a/drivers/rtc/pcf2127.c
+++ b/drivers/rtc/pcf2127.c
@@ -56,7 +56,7 @@ static int pcf2127_rtc_set(struct udevice *dev, const struct rtc_time *tm)
buf[i++] = tm->tm_wday & 0x07;
/* month, 1 - 12 */
- buf[i++] = bin2bcd(tm->tm_mon + 1);
+ buf[i++] = bin2bcd(tm->tm_mon);
/* year */
buf[i++] = bin2bcd(tm->tm_year % 100);
@@ -83,7 +83,7 @@ static int pcf2127_rtc_get(struct udevice *dev, struct rtc_time *tm)
tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F);
tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F);
tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F);
- tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1;
+ tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F);
tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]) + 1900;
if (tm->tm_year < 1970)
tm->tm_year += 100; /* assume we are in 1970...2069 */
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 83b114ffe7..994a5948f1 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -166,11 +166,28 @@ static int cadence_spi_probe(struct udevice *bus)
{
struct cadence_spi_platdata *plat = bus->platdata;
struct cadence_spi_priv *priv = dev_get_priv(bus);
+ struct clk clk;
int ret;
priv->regbase = plat->regbase;
priv->ahbbase = plat->ahbbase;
+ if (plat->ref_clk_hz == 0) {
+ ret = clk_get_by_index(bus, 0, &clk);
+ if (ret) {
+#ifdef CONFIG_CQSPI_REF_CLK
+ plat->ref_clk_hz = CONFIG_CQSPI_REF_CLK;
+#else
+ return ret;
+#endif
+ } else {
+ plat->ref_clk_hz = clk_get_rate(&clk);
+ clk_free(&clk);
+ if (IS_ERR_VALUE(plat->ref_clk_hz))
+ return plat->ref_clk_hz;
+ }
+ }
+
ret = reset_get_bulk(bus, &priv->resets);
if (ret)
dev_warn(bus, "Can't get reset: %d\n", ret);
@@ -268,8 +285,6 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
{
struct cadence_spi_platdata *plat = bus->platdata;
ofnode subnode;
- struct clk clk;
- int ret;
plat->regbase = (void *)devfdt_get_addr_index(bus, 0);
plat->ahbbase = (void *)devfdt_get_addr_size_index(bus, 1,
@@ -305,20 +320,6 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
plat->tchsh_ns = ofnode_read_u32_default(subnode, "cdns,tchsh-ns", 20);
plat->tslch_ns = ofnode_read_u32_default(subnode, "cdns,tslch-ns", 20);
- ret = clk_get_by_index(bus, 0, &clk);
- if (ret) {
-#ifdef CONFIG_CQSPI_REF_CLK
- plat->ref_clk_hz = CONFIG_CQSPI_REF_CLK;
-#else
- return ret;
-#endif
- } else {
- plat->ref_clk_hz = clk_get_rate(&clk);
- clk_free(&clk);
- if (IS_ERR_VALUE(plat->ref_clk_hz))
- return plat->ref_clk_hz;
- }
-
debug("%s: regbase=%p ahbbase=%p max-frequency=%d page-size=%d\n",
__func__, plat->regbase, plat->ahbbase, plat->max_hz,
plat->page_size);
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 8e2a09df36..ee2c8b67dc 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -1,1142 +1,781 @@
// SPDX-License-Identifier: GPL-2.0+
+
/*
- * Copyright 2013-2015 Freescale Semiconductor, Inc.
+ * Freescale QuadSPI driver.
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2018 Bootlin
+ * Copyright (C) 2018 exceet electronics GmbH
+ * Copyright (C) 2018 Kontron Electronics GmbH
+ * Copyright 2019-2020 NXP
+ *
+ * This driver is a ported version of Linux Freescale QSPI driver taken from
+ * v5.5-rc1 tag having following information.
*
- * Freescale Quad Serial Peripheral Interface (QSPI) driver
+ * Transition to SPI MEM interface:
+ * Authors:
+ * Boris Brezillon <bbrezillon@kernel.org>
+ * Frieder Schrempf <frieder.schrempf@kontron.de>
+ * Yogesh Gaur <yogeshnarayan.gaur@nxp.com>
+ * Suresh Gupta <suresh.gupta@nxp.com>
+ *
+ * Based on the original fsl-quadspi.c spi-nor driver.
+ * Transition to spi-mem in spi-fsl-qspi.c
*/
#include <common.h>
-#include <malloc.h>
-#include <spi.h>
#include <asm/io.h>
-#include <linux/sizes.h>
-#include <linux/iopoll.h>
#include <dm.h>
-#include <errno.h>
-#include <watchdog.h>
-#include <wait_bit.h>
-#include "fsl_qspi.h"
+#include <linux/iopoll.h>
+#include <linux/sizes.h>
+#include <linux/err.h>
+#include <spi.h>
+#include <spi-mem.h>
DECLARE_GLOBAL_DATA_PTR;
-#define OFFSET_BITS_MASK GENMASK(23, 0)
-
-#define FLASH_STATUS_WEL 0x02
-
-/* SEQID */
-#define SEQID_WREN 1
-#define SEQID_FAST_READ 2
-#define SEQID_RDSR 3
-#define SEQID_SE 4
-#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
-#define SEQID_WRAR 13
-#define SEQID_RDAR 14
-
-/* 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 */
-
-/* Used for Spansion S25FS-S family flash only. */
-#define QSPI_CMD_RDAR 0x65 /* Read any device register */
-#define QSPI_CMD_WRAR 0x71 /* Write any device register */
-
-/* 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) */
-
-/* fsl_qspi_platdata flags */
-#define QSPI_FLAG_REGMAP_ENDIAN_BIG BIT(0)
-
-/* default SCK frequency, unit: HZ */
-#define FSL_QSPI_DEFAULT_SCK_FREQ 50000000
-
-/* QSPI max chipselect signals number */
-#define FSL_QSPI_MAX_CHIPSELECT_NUM 4
-
-/* Controller needs driver to swap endian */
+/*
+ * The driver only uses one single LUT entry, that is updated on
+ * each call of exec_op(). Index 0 is preset at boot with a basic
+ * read operation, so let's use the last entry (15).
+ */
+#define SEQID_LUT 15
+
+/* Registers used by the driver */
+#define QUADSPI_MCR 0x00
+#define QUADSPI_MCR_RESERVED_MASK GENMASK(19, 16)
+#define QUADSPI_MCR_MDIS_MASK BIT(14)
+#define QUADSPI_MCR_CLR_TXF_MASK BIT(11)
+#define QUADSPI_MCR_CLR_RXF_MASK BIT(10)
+#define QUADSPI_MCR_DDR_EN_MASK BIT(7)
+#define QUADSPI_MCR_END_CFG_MASK GENMASK(3, 2)
+#define QUADSPI_MCR_SWRSTHD_MASK BIT(1)
+#define QUADSPI_MCR_SWRSTSD_MASK BIT(0)
+
+#define QUADSPI_IPCR 0x08
+#define QUADSPI_IPCR_SEQID(x) ((x) << 24)
+#define QUADSPI_FLSHCR 0x0c
+#define QUADSPI_FLSHCR_TCSS_MASK GENMASK(3, 0)
+#define QUADSPI_FLSHCR_TCSH_MASK GENMASK(11, 8)
+#define QUADSPI_FLSHCR_TDH_MASK GENMASK(17, 16)
+
+#define QUADSPI_BUF3CR 0x1c
+#define QUADSPI_BUF3CR_ALLMST_MASK BIT(31)
+#define QUADSPI_BUF3CR_ADATSZ(x) ((x) << 8)
+#define QUADSPI_BUF3CR_ADATSZ_MASK GENMASK(15, 8)
+
+#define QUADSPI_BFGENCR 0x20
+#define QUADSPI_BFGENCR_SEQID(x) ((x) << 12)
+
+#define QUADSPI_BUF0IND 0x30
+#define QUADSPI_BUF1IND 0x34
+#define QUADSPI_BUF2IND 0x38
+#define QUADSPI_SFAR 0x100
+
+#define QUADSPI_SMPR 0x108
+#define QUADSPI_SMPR_DDRSMP_MASK GENMASK(18, 16)
+#define QUADSPI_SMPR_FSDLY_MASK BIT(6)
+#define QUADSPI_SMPR_FSPHS_MASK BIT(5)
+#define QUADSPI_SMPR_HSENA_MASK BIT(0)
+
+#define QUADSPI_RBCT 0x110
+#define QUADSPI_RBCT_WMRK_MASK GENMASK(4, 0)
+#define QUADSPI_RBCT_RXBRD_USEIPS BIT(8)
+
+#define QUADSPI_TBDR 0x154
+
+#define QUADSPI_SR 0x15c
+#define QUADSPI_SR_IP_ACC_MASK BIT(1)
+#define QUADSPI_SR_AHB_ACC_MASK BIT(2)
+
+#define QUADSPI_FR 0x160
+#define QUADSPI_FR_TFF_MASK BIT(0)
+
+#define QUADSPI_RSER 0x164
+#define QUADSPI_RSER_TFIE BIT(0)
+
+#define QUADSPI_SPTRCLR 0x16c
+#define QUADSPI_SPTRCLR_IPPTRC BIT(8)
+#define QUADSPI_SPTRCLR_BFPTRC BIT(0)
+
+#define QUADSPI_SFA1AD 0x180
+#define QUADSPI_SFA2AD 0x184
+#define QUADSPI_SFB1AD 0x188
+#define QUADSPI_SFB2AD 0x18c
+#define QUADSPI_RBDR(x) (0x200 + ((x) * 4))
+
+#define QUADSPI_LUTKEY 0x300
+#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0
+
+#define QUADSPI_LCKCR 0x304
+#define QUADSPI_LCKER_LOCK BIT(0)
+#define QUADSPI_LCKER_UNLOCK BIT(1)
+
+#define QUADSPI_LUT_BASE 0x310
+#define QUADSPI_LUT_OFFSET (SEQID_LUT * 4 * 4)
+#define QUADSPI_LUT_REG(idx) \
+ (QUADSPI_LUT_BASE + QUADSPI_LUT_OFFSET + (idx) * 4)
+
+/* Instruction set for the LUT register */
+#define LUT_STOP 0
+#define LUT_CMD 1
+#define LUT_ADDR 2
+#define LUT_DUMMY 3
+#define LUT_MODE 4
+#define LUT_MODE2 5
+#define LUT_MODE4 6
+#define LUT_FSL_READ 7
+#define LUT_FSL_WRITE 8
+#define LUT_JMP_ON_CS 9
+#define LUT_ADDR_DDR 10
+#define LUT_MODE_DDR 11
+#define LUT_MODE2_DDR 12
+#define LUT_MODE4_DDR 13
+#define LUT_FSL_READ_DDR 14
+#define LUT_FSL_WRITE_DDR 15
+#define LUT_DATA_LEARN 16
+
+/*
+ * The PAD definitions for LUT register.
+ *
+ * The pad stands for the number of IO lines [0:3].
+ * For example, the quad read needs four IO lines,
+ * so you should use LUT_PAD(4).
+ */
+#define LUT_PAD(x) (fls(x) - 1)
+
+/*
+ * Macro for constructing the LUT entries with the following
+ * register layout:
+ *
+ * ---------------------------------------------------
+ * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ * ---------------------------------------------------
+ */
+#define LUT_DEF(idx, ins, pad, opr) \
+ ((((ins) << 10) | ((pad) << 8) | (opr)) << (((idx) % 2) * 16))
+
+/* Controller needs driver to swap endianness */
#define QUADSPI_QUIRK_SWAP_ENDIAN BIT(0)
-enum fsl_qspi_devtype {
- FSL_QUADSPI_VYBRID,
- FSL_QUADSPI_IMX6SX,
- FSL_QUADSPI_IMX6UL_7D,
- FSL_QUADSPI_IMX7ULP,
-};
+/* Controller needs 4x internal clock */
+#define QUADSPI_QUIRK_4X_INT_CLK BIT(1)
-struct fsl_qspi_devtype_data {
- enum fsl_qspi_devtype devtype;
- u32 rxfifo;
- u32 txfifo;
- u32 ahb_buf_size;
- u32 driver_data;
-};
+/*
+ * TKT253890, the controller needs the driver to fill the txfifo with
+ * 16 bytes at least to trigger a data transfer, even though the extra
+ * data won't be transferred.
+ */
+#define QUADSPI_QUIRK_TKT253890 BIT(2)
-/**
- * struct fsl_qspi_platdata - platform data for Freescale QSPI
- *
- * @flags: Flags for QSPI QSPI_FLAG_...
- * @speed_hz: Default SCK frequency
- * @reg_base: Base address of QSPI registers
- * @amba_base: Base address of QSPI memory mapping
- * @amba_total_size: size of QSPI memory mapping
- * @flash_num: Number of active slave devices
- * @num_chipselect: Number of QSPI chipselect signals
+/* TKT245618, the controller cannot wake up from wait mode */
+#define QUADSPI_QUIRK_TKT245618 BIT(3)
+
+/*
+ * Controller adds QSPI_AMBA_BASE (base address of the mapped memory)
+ * internally. No need to add it when setting SFXXAD and SFAR registers
*/
-struct fsl_qspi_platdata {
- u32 flags;
- u32 speed_hz;
- fdt_addr_t reg_base;
- fdt_addr_t amba_base;
- fdt_size_t amba_total_size;
- u32 flash_num;
- u32 num_chipselect;
-};
+#define QUADSPI_QUIRK_BASE_INTERNAL BIT(4)
-/**
- * struct fsl_qspi_priv - private data for Freescale QSPI
- *
- * @flags: Flags for QSPI QSPI_FLAG_...
- * @bus_clk: QSPI input clk frequency
- * @speed_hz: Default SCK frequency
- * @cur_seqid: current LUT table sequence id
- * @sf_addr: flash access offset
- * @amba_base: Base address of QSPI memory mapping of every CS
- * @amba_total_size: size of QSPI memory mapping
- * @cur_amba_base: Base address of QSPI memory mapping of current CS
- * @flash_num: Number of active slave devices
- * @num_chipselect: Number of QSPI chipselect signals
- * @regs: Point to QSPI register structure for I/O access
+/*
+ * Controller uses TDH bits in register QUADSPI_FLSHCR.
+ * They need to be set in accordance with the DDR/SDR mode.
*/
-struct fsl_qspi_priv {
- u32 flags;
- u32 bus_clk;
- u32 speed_hz;
- u32 cur_seqid;
- u32 sf_addr;
- u32 amba_base[FSL_QSPI_MAX_CHIPSELECT_NUM];
- u32 amba_total_size;
- u32 cur_amba_base;
- u32 flash_num;
- u32 num_chipselect;
- struct fsl_qspi_regs *regs;
- struct fsl_qspi_devtype_data *devtype_data;
+#define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
+
+struct fsl_qspi_devtype_data {
+ unsigned int rxfifo;
+ unsigned int txfifo;
+ unsigned int ahb_buf_size;
+ unsigned int quirks;
+ bool little_endian;
};
static const struct fsl_qspi_devtype_data vybrid_data = {
- .devtype = FSL_QUADSPI_VYBRID,
- .rxfifo = 128,
- .txfifo = 64,
- .ahb_buf_size = 1024,
- .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
+ .rxfifo = SZ_128,
+ .txfifo = SZ_64,
+ .ahb_buf_size = SZ_1K,
+ .quirks = QUADSPI_QUIRK_SWAP_ENDIAN,
+ .little_endian = true,
};
static const struct fsl_qspi_devtype_data imx6sx_data = {
- .devtype = FSL_QUADSPI_IMX6SX,
- .rxfifo = 128,
- .txfifo = 512,
- .ahb_buf_size = 1024,
- .driver_data = 0,
+ .rxfifo = SZ_128,
+ .txfifo = SZ_512,
+ .ahb_buf_size = SZ_1K,
+ .quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618,
+ .little_endian = true,
+};
+
+static const struct fsl_qspi_devtype_data imx7d_data = {
+ .rxfifo = SZ_128,
+ .txfifo = SZ_512,
+ .ahb_buf_size = SZ_1K,
+ .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+ QUADSPI_QUIRK_USE_TDH_SETTING,
+ .little_endian = true,
};
-static const struct fsl_qspi_devtype_data imx6ul_7d_data = {
- .devtype = FSL_QUADSPI_IMX6UL_7D,
- .rxfifo = 128,
- .txfifo = 512,
- .ahb_buf_size = 1024,
- .driver_data = 0,
+static const struct fsl_qspi_devtype_data imx6ul_data = {
+ .rxfifo = SZ_128,
+ .txfifo = SZ_512,
+ .ahb_buf_size = SZ_1K,
+ .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+ QUADSPI_QUIRK_USE_TDH_SETTING,
+ .little_endian = true,
};
-static const struct fsl_qspi_devtype_data imx7ulp_data = {
- .devtype = FSL_QUADSPI_IMX7ULP,
- .rxfifo = 64,
- .txfifo = 64,
- .ahb_buf_size = 128,
- .driver_data = 0,
+static const struct fsl_qspi_devtype_data ls1021a_data = {
+ .rxfifo = SZ_128,
+ .txfifo = SZ_64,
+ .ahb_buf_size = SZ_1K,
+ .quirks = 0,
+ .little_endian = false,
};
-static u32 qspi_read32(u32 flags, u32 *addr)
+static const struct fsl_qspi_devtype_data ls1088a_data = {
+ .rxfifo = SZ_128,
+ .txfifo = SZ_128,
+ .ahb_buf_size = SZ_1K,
+ .quirks = QUADSPI_QUIRK_TKT253890,
+ .little_endian = true,
+};
+
+static const struct fsl_qspi_devtype_data ls2080a_data = {
+ .rxfifo = SZ_128,
+ .txfifo = SZ_64,
+ .ahb_buf_size = SZ_1K,
+ .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL,
+ .little_endian = true,
+};
+
+struct fsl_qspi {
+ struct udevice *dev;
+ void __iomem *iobase;
+ void __iomem *ahb_addr;
+ u32 memmap_phy;
+ const struct fsl_qspi_devtype_data *devtype_data;
+ int selected;
+};
+
+static inline int needs_swap_endian(struct fsl_qspi *q)
{
- return flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
- in_be32(addr) : in_le32(addr);
+ return q->devtype_data->quirks & QUADSPI_QUIRK_SWAP_ENDIAN;
}
-static void qspi_write32(u32 flags, u32 *addr, u32 val)
+static inline int needs_4x_clock(struct fsl_qspi *q)
{
- flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
- out_be32(addr, val) : out_le32(addr, val);
+ return q->devtype_data->quirks & QUADSPI_QUIRK_4X_INT_CLK;
}
-static inline int is_controller_busy(const struct fsl_qspi_priv *priv)
+static inline int needs_fill_txfifo(struct fsl_qspi *q)
{
- u32 val;
- u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
- QSPI_SR_IP_ACC_MASK;
-
- if (priv->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG)
- mask = (u32)cpu_to_be32(mask);
-
- return readl_poll_timeout(&priv->regs->sr, val, !(val & mask), 1000);
+ return q->devtype_data->quirks & QUADSPI_QUIRK_TKT253890;
}
-/* QSPI support swapping the flash read/write data
- * in hardware for LS102xA, but not for VF610 */
-static inline u32 qspi_endian_xchg(struct fsl_qspi_priv *priv, u32 data)
+static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
{
- if (priv->devtype_data->driver_data & QUADSPI_QUIRK_SWAP_ENDIAN)
- return swab32(data);
- else
- return data;
+ return q->devtype_data->quirks & QUADSPI_QUIRK_TKT245618;
}
-static void qspi_set_lut(struct fsl_qspi_priv *priv)
+static inline int needs_amba_base_offset(struct fsl_qspi *q)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 lut_base;
-
- /* Unlock the LUT */
- qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_UNLOCK);
-
- /* Write Enable */
- lut_base = SEQID_WREN * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* Fast Read */
- lut_base = SEQID_FAST_READ * 4;
-#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(priv->flags, &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(priv->flags, &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(priv->flags, &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(priv->flags, &regs->lut[lut_base + 1],
- OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) |
- OPRND1(priv->devtype_data->rxfifo) | PAD1(LUT_PAD1) |
- INSTR1(LUT_READ));
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* Read Status */
- lut_base = SEQID_RDSR * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
- PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* Erase a sector */
- lut_base = SEQID_SE * 4;
-#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(priv->flags, &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(priv->flags, &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(priv->flags, &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(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* Erase the whole chip */
- lut_base = SEQID_CHIP_ERASE * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base],
- OPRND0(QSPI_CMD_CHIP_ERASE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* Page Program */
- lut_base = SEQID_PP * 4;
-#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(priv->flags, &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(priv->flags, &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(priv->flags, &regs->lut[lut_base],
- OPRND0(QSPI_CMD_PP_4B) | PAD0(LUT_PAD1) |
- INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
-#endif
- /* Use IDATSZ in IPCR to determine the size and here set 0. */
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], OPRND0(0) |
- PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* READ ID */
- lut_base = SEQID_RDID * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) |
- PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* SUB SECTOR 4K ERASE */
- lut_base = SEQID_BE_4K * 4;
- qspi_write32(priv->flags, &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(priv->flags, &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(priv->flags, &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(priv->flags, &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(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
- PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
-#endif
-
- /*
- * Read any device register.
- * Used for Spansion S25FS-S family flash only.
- */
- lut_base = SEQID_RDAR * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base],
- OPRND0(QSPI_CMD_RDAR) | PAD0(LUT_PAD1) |
- INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1],
- OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) |
- OPRND1(1) | PAD1(LUT_PAD1) |
- INSTR1(LUT_READ));
+ return !(q->devtype_data->quirks & QUADSPI_QUIRK_BASE_INTERNAL);
+}
- /*
- * Write any device register.
- * Used for Spansion S25FS-S family flash only.
- */
- lut_base = SEQID_WRAR * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base],
- OPRND0(QSPI_CMD_WRAR) | PAD0(LUT_PAD1) |
- INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1],
- OPRND0(1) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
-
- /* Lock the LUT */
- qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_LOCK);
+static inline int needs_tdh_setting(struct fsl_qspi *q)
+{
+ return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING;
}
-#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.
+ * An IC bug makes it necessary to rearrange the 32-bit data.
+ * Later chips, such as IMX6SLX, have fixed this bug.
*/
-static inline void qspi_ahb_invalid(struct fsl_qspi_priv *priv)
+static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 reg;
-
- reg = qspi_read32(priv->flags, &regs->mcr);
- reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
- qspi_write32(priv->flags, &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(priv->flags, &regs->mcr, reg);
+ return needs_swap_endian(q) ? __swab32(a) : a;
}
-/* Read out the data from the AHB buffer. */
-static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len)
+/*
+ * R/W functions for big- or little-endian registers:
+ * The QSPI controller's endianness is independent of
+ * the CPU core's endianness. So far, although the CPU
+ * core is little-endian the QSPI controller can use
+ * big-endian or little-endian.
+ */
+static void qspi_writel(struct fsl_qspi *q, u32 val, void __iomem *addr)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg;
- void *rx_addr;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
-
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- mcr_reg);
+ if (q->devtype_data->little_endian)
+ out_le32(addr, val);
+ else
+ out_be32(addr, val);
+}
- rx_addr = (void *)(uintptr_t)(priv->cur_amba_base + priv->sf_addr);
- /* Read out the data directly from the AHB buffer. */
- memcpy(rxbuf, rx_addr, len);
+static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr)
+{
+ if (q->devtype_data->little_endian)
+ return in_le32(addr);
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ return in_be32(addr);
}
-static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv)
+static int fsl_qspi_check_buswidth(struct fsl_qspi *q, u8 width)
{
- u32 reg, reg2;
- struct fsl_qspi_regs *regs = priv->regs;
+ switch (width) {
+ case 1:
+ case 2:
+ case 4:
+ return 0;
+ }
- reg = qspi_read32(priv->flags, &regs->mcr);
- /* Disable the module */
- qspi_write32(priv->flags, &regs->mcr, reg | QSPI_MCR_MDIS_MASK);
-
- /* Set the Sampling Register for DDR */
- reg2 = qspi_read32(priv->flags, &regs->smpr);
- reg2 &= ~QSPI_SMPR_DDRSMP_MASK;
- reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT);
- qspi_write32(priv->flags, &regs->smpr, reg2);
-
- /* Enable the module again (enable the DDR too) */
- reg |= QSPI_MCR_DDR_EN_MASK;
- /* Enable bit 29 for imx6sx */
- reg |= BIT(29);
- qspi_write32(priv->flags, &regs->mcr, reg);
-
- /* Enable the TDH to 1 for some platforms like imx6ul, imx7d, etc
- * These two bits are reserved on other platforms
- */
- reg = qspi_read32(priv->flags, &regs->flshcr);
- reg &= ~(BIT(17));
- reg |= BIT(16);
- qspi_write32(priv->flags, &regs->flshcr, reg);
+ return -ENOTSUPP;
}
-/*
- * 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_priv *priv)
+static bool fsl_qspi_supports_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
{
- struct fsl_qspi_regs *regs = priv->regs;
+ struct fsl_qspi *q = dev_get_priv(slave->dev->parent);
+ int ret;
+
+ ret = fsl_qspi_check_buswidth(q, op->cmd.buswidth);
+
+ if (op->addr.nbytes)
+ ret |= fsl_qspi_check_buswidth(q, op->addr.buswidth);
+
+ if (op->dummy.nbytes)
+ ret |= fsl_qspi_check_buswidth(q, op->dummy.buswidth);
- /* AHB configuration for access buffer 0/1/2 .*/
- qspi_write32(priv->flags, &regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(priv->flags, &regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(priv->flags, &regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(priv->flags, &regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
- ((priv->devtype_data->ahb_buf_size >> 3) << QSPI_BUF3CR_ADATSZ_SHIFT));
+ if (op->data.nbytes)
+ ret |= fsl_qspi_check_buswidth(q, op->data.buswidth);
- /* We only use the buffer3 */
- qspi_write32(priv->flags, &regs->buf0ind, 0);
- qspi_write32(priv->flags, &regs->buf1ind, 0);
- qspi_write32(priv->flags, &regs->buf2ind, 0);
+ if (ret)
+ return false;
/*
- * Set the default lut sequence for AHB Read.
- * Parallel mode is disabled.
+ * The number of instructions needed for the op, needs
+ * to fit into a single LUT entry.
*/
- qspi_write32(priv->flags, &regs->bfgencr,
- SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT);
-
- /*Enable DDR Mode*/
- qspi_enable_ddr_mode(priv);
+ if (op->addr.nbytes +
+ (op->dummy.nbytes ? 1 : 0) +
+ (op->data.nbytes ? 1 : 0) > 6)
+ return false;
+
+ /* Max 64 dummy clock cycles supported */
+ if (op->dummy.nbytes &&
+ (op->dummy.nbytes * 8 / op->dummy.buswidth > 64))
+ return false;
+
+ /* Max data length, check controller limits and alignment */
+ if (op->data.dir == SPI_MEM_DATA_IN &&
+ (op->data.nbytes > q->devtype_data->ahb_buf_size ||
+ (op->data.nbytes > q->devtype_data->rxfifo - 4 &&
+ !IS_ALIGNED(op->data.nbytes, 8))))
+ return false;
+
+ if (op->data.dir == SPI_MEM_DATA_OUT &&
+ op->data.nbytes > q->devtype_data->txfifo)
+ return false;
+
+ return true;
}
-#endif
-#ifdef CONFIG_SPI_FLASH_BAR
-/* Bank register read/write, EAR register read/write */
-static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len)
+static void fsl_qspi_prepare_lut(struct fsl_qspi *q,
+ const struct spi_mem_op *op)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 reg, mcr_reg, data, seqid;
+ void __iomem *base = q->iobase;
+ u32 lutval[4] = {};
+ int lutidx = 1, i;
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- mcr_reg);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth),
+ op->cmd.opcode);
- qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
+ /*
+ * For some unknown reason, using LUT_ADDR doesn't work in some
+ * cases (at least with only one byte long addresses), so
+ * let's use LUT_MODE to write the address bytes one by one
+ */
+ for (i = 0; i < op->addr.nbytes; i++) {
+ u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
- if (priv->cur_seqid == QSPI_CMD_BRRD)
- seqid = SEQID_BRRD;
- else
- seqid = SEQID_RDEAR;
-
- qspi_write32(priv->flags, &regs->ipcr,
- (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
-
- /* Wait previous command complete */
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- while (1) {
- WATCHDOG_RESET();
-
- reg = qspi_read32(priv->flags, &regs->rbsr);
- if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(priv->flags, &regs->rbdr[0]);
- data = qspi_endian_xchg(priv, data);
- memcpy(rxbuf, &data, len);
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
- break;
- }
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE,
+ LUT_PAD(op->addr.buswidth),
+ addrbyte);
+ lutidx++;
}
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
-}
-#endif
-
-static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
-{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg, rbsr_reg, data, size;
- int i;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- mcr_reg);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- i = 0;
- while ((priv->devtype_data->rxfifo >= len) && (len > 0)) {
- WATCHDOG_RESET();
-
- rbsr_reg = qspi_read32(priv->flags, &regs->rbsr);
- if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(priv->flags, &regs->rbdr[i]);
- data = qspi_endian_xchg(priv, data);
- size = (len < 4) ? len : 4;
- memcpy(rxbuf, &data, size);
- len -= size;
- rxbuf++;
- i++;
- }
+ if (op->dummy.nbytes) {
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_DUMMY,
+ LUT_PAD(op->dummy.buswidth),
+ op->dummy.nbytes * 8 /
+ op->dummy.buswidth);
+ lutidx++;
}
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
-}
-
-/* If not use AHB read, read data from ip interface */
-static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
-{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg, data;
- int i, size;
- u32 to_or_from;
- u32 seqid;
-
- if (priv->cur_seqid == QSPI_CMD_RDAR)
- seqid = SEQID_RDAR;
- else
- seqid = SEQID_FAST_READ;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- mcr_reg);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- to_or_from = priv->sf_addr + priv->cur_amba_base;
-
- while (len > 0) {
- WATCHDOG_RESET();
-
- qspi_write32(priv->flags, &regs->sfar, to_or_from);
-
- size = (len > priv->devtype_data->rxfifo) ?
- priv->devtype_data->rxfifo : len;
-
- qspi_write32(priv->flags, &regs->ipcr,
- (seqid << QSPI_IPCR_SEQID_SHIFT) |
- size);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- to_or_from += size;
- len -= size;
-
- i = 0;
- while ((priv->devtype_data->rxfifo >= size) && (size > 0)) {
- data = qspi_read32(priv->flags, &regs->rbdr[i]);
- data = qspi_endian_xchg(priv, data);
- if (size < 4)
- memcpy(rxbuf, &data, size);
- else
- memcpy(rxbuf, &data, 4);
- rxbuf++;
- size -= 4;
- i++;
- }
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
+ if (op->data.nbytes) {
+ lutval[lutidx / 2] |= LUT_DEF(lutidx,
+ op->data.dir == SPI_MEM_DATA_IN ?
+ LUT_FSL_READ : LUT_FSL_WRITE,
+ LUT_PAD(op->data.buswidth),
+ 0);
+ lutidx++;
}
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
-}
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_STOP, 0, 0);
-static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len)
-{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg, data, reg, status_reg, seqid;
- int i, size, tx_size;
- u32 to_or_from = 0;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- mcr_reg);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- status_reg = 0;
- while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
- WATCHDOG_RESET();
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- reg = qspi_read32(priv->flags, &regs->rbsr);
- if (reg & QSPI_RBSR_RDBFL_MASK) {
- status_reg = qspi_read32(priv->flags, &regs->rbdr[0]);
- status_reg = qspi_endian_xchg(priv, status_reg);
- }
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
- }
+ /* unlock LUT */
+ qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+ qspi_writel(q, QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
+
+ dev_dbg(q->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x]\n",
+ op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3]);
- /* Default is page programming */
- seqid = SEQID_PP;
- if (priv->cur_seqid == QSPI_CMD_WRAR)
- seqid = SEQID_WRAR;
-#ifdef CONFIG_SPI_FLASH_BAR
- if (priv->cur_seqid == QSPI_CMD_BRWR)
- seqid = SEQID_BRWR;
- else if (priv->cur_seqid == QSPI_CMD_WREAR)
- seqid = SEQID_WREAR;
-#endif
+ /* fill LUT */
+ for (i = 0; i < ARRAY_SIZE(lutval); i++)
+ qspi_writel(q, lutval[i], base + QUADSPI_LUT_REG(i));
- to_or_from = priv->sf_addr + priv->cur_amba_base;
+ /* lock LUT */
+ qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+ qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
+}
- qspi_write32(priv->flags, &regs->sfar, to_or_from);
+/*
+ * If we have changed the content of the flash by writing or erasing, or if we
+ * read from flash with a different offset into the page buffer, 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 void fsl_qspi_invalidate(struct fsl_qspi *q)
+{
+ u32 reg;
- tx_size = (len > priv->devtype_data->txfifo) ?
- priv->devtype_data->txfifo : len;
+ reg = qspi_readl(q, q->iobase + QUADSPI_MCR);
+ reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
+ qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
- size = tx_size / 16;
/*
- * There must be atleast 128bit data
- * available in TX FIFO for any pop operation
+ * The minimum delay : 1 AHB + 2 SFCK clocks.
+ * Delay 1 us is enough.
*/
- if (tx_size % 16)
- size++;
- for (i = 0; i < size * 4; i++) {
- memcpy(&data, txbuf, 4);
- data = qspi_endian_xchg(priv, data);
- qspi_write32(priv->flags, &regs->tbdr, data);
- txbuf += 4;
- }
-
- qspi_write32(priv->flags, &regs->ipcr,
- (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
+ udelay(1);
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
+ qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
}
-static void qspi_op_rdsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len)
+static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_slave *slave)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg, reg, data;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- mcr_reg);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- while (1) {
- WATCHDOG_RESET();
-
- reg = qspi_read32(priv->flags, &regs->rbsr);
- if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(priv->flags, &regs->rbdr[0]);
- data = qspi_endian_xchg(priv, data);
- memcpy(rxbuf, &data, len);
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
- break;
- }
- }
+ struct dm_spi_slave_platdata *plat =
+ dev_get_parent_platdata(slave->dev);
+
+ if (q->selected == plat->cs)
+ return;
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ q->selected = plat->cs;
+ fsl_qspi_invalidate(q);
}
-static void qspi_op_erase(struct fsl_qspi_priv *priv)
+static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg;
- u32 to_or_from = 0;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- mcr_reg);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- to_or_from = priv->sf_addr + priv->cur_amba_base;
- qspi_write32(priv->flags, &regs->sfar, to_or_from);
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- if (priv->cur_seqid == QSPI_CMD_SE) {
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
- } else if (priv->cur_seqid == QSPI_CMD_BE_4K) {
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0);
- }
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ memcpy_fromio(op->data.buf.in,
+ q->ahb_addr + q->selected * q->devtype_data->ahb_buf_size,
+ op->data.nbytes);
}
-int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
+static void fsl_qspi_fill_txfifo(struct fsl_qspi *q,
+ const struct spi_mem_op *op)
{
- u32 bytes = DIV_ROUND_UP(bitlen, 8);
- static u32 wr_sfaddr;
- u32 txbuf;
-
- WATCHDOG_RESET();
-
- if (dout) {
- if (flags & SPI_XFER_BEGIN) {
- priv->cur_seqid = *(u8 *)dout;
- memcpy(&txbuf, dout, 4);
- }
-
- if (flags == SPI_XFER_END) {
- priv->sf_addr = wr_sfaddr;
- qspi_op_write(priv, (u8 *)dout, bytes);
- return 0;
- }
-
- if (priv->cur_seqid == QSPI_CMD_FAST_READ ||
- priv->cur_seqid == QSPI_CMD_RDAR) {
- priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- } else if ((priv->cur_seqid == QSPI_CMD_SE) ||
- (priv->cur_seqid == QSPI_CMD_BE_4K)) {
- priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- qspi_op_erase(priv);
- } else if (priv->cur_seqid == QSPI_CMD_PP ||
- priv->cur_seqid == QSPI_CMD_WRAR) {
- wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
- } else if ((priv->cur_seqid == QSPI_CMD_BRWR) ||
- (priv->cur_seqid == QSPI_CMD_WREAR)) {
-#ifdef CONFIG_SPI_FLASH_BAR
- wr_sfaddr = 0;
-#endif
- }
- }
+ void __iomem *base = q->iobase;
+ int i;
+ u32 val;
- if (din) {
- if (priv->cur_seqid == QSPI_CMD_FAST_READ) {
-#ifdef CONFIG_SYS_FSL_QSPI_AHB
- qspi_ahb_read(priv, din, bytes);
-#else
- qspi_op_read(priv, din, bytes);
-#endif
- } else if (priv->cur_seqid == QSPI_CMD_RDAR) {
- qspi_op_read(priv, din, bytes);
- } else if (priv->cur_seqid == QSPI_CMD_RDID)
- qspi_op_rdid(priv, din, bytes);
- else if (priv->cur_seqid == QSPI_CMD_RDSR)
- qspi_op_rdsr(priv, din, bytes);
-#ifdef CONFIG_SPI_FLASH_BAR
- else if ((priv->cur_seqid == QSPI_CMD_BRRD) ||
- (priv->cur_seqid == QSPI_CMD_RDEAR)) {
- priv->sf_addr = 0;
- qspi_op_rdbank(priv, din, bytes);
- }
-#endif
+ for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 4); i += 4) {
+ memcpy(&val, op->data.buf.out + i, 4);
+ val = fsl_qspi_endian_xchg(q, val);
+ qspi_writel(q, val, base + QUADSPI_TBDR);
}
-#ifdef CONFIG_SYS_FSL_QSPI_AHB
- if ((priv->cur_seqid == QSPI_CMD_SE) ||
- (priv->cur_seqid == QSPI_CMD_PP) ||
- (priv->cur_seqid == QSPI_CMD_BE_4K) ||
- (priv->cur_seqid == QSPI_CMD_WREAR) ||
- (priv->cur_seqid == QSPI_CMD_BRWR))
- qspi_ahb_invalid(priv);
-#endif
+ if (i < op->data.nbytes) {
+ memcpy(&val, op->data.buf.out + i, op->data.nbytes - i);
+ val = fsl_qspi_endian_xchg(q, val);
+ qspi_writel(q, val, base + QUADSPI_TBDR);
+ }
- return 0;
+ if (needs_fill_txfifo(q)) {
+ for (i = op->data.nbytes; i < 16; i += 4)
+ qspi_writel(q, 0, base + QUADSPI_TBDR);
+ }
}
-void qspi_module_disable(struct fsl_qspi_priv *priv, u8 disable)
+static void fsl_qspi_read_rxfifo(struct fsl_qspi *q,
+ const struct spi_mem_op *op)
{
- u32 mcr_val;
+ void __iomem *base = q->iobase;
+ int i;
+ u8 *buf = op->data.buf.in;
+ u32 val;
- mcr_val = qspi_read32(priv->flags, &priv->regs->mcr);
- if (disable)
- mcr_val |= QSPI_MCR_MDIS_MASK;
- else
- mcr_val &= ~QSPI_MCR_MDIS_MASK;
- qspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+ for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 4); i += 4) {
+ val = qspi_readl(q, base + QUADSPI_RBDR(i / 4));
+ val = fsl_qspi_endian_xchg(q, val);
+ memcpy(buf + i, &val, 4);
+ }
+
+ if (i < op->data.nbytes) {
+ val = qspi_readl(q, base + QUADSPI_RBDR(i / 4));
+ val = fsl_qspi_endian_xchg(q, val);
+ memcpy(buf + i, &val, op->data.nbytes - i);
+ }
}
-void qspi_cfg_smpr(struct fsl_qspi_priv *priv, u32 clear_bits, u32 set_bits)
+static int fsl_qspi_readl_poll_tout(struct fsl_qspi *q, void __iomem *base,
+ u32 mask, u32 delay_us, u32 timeout_us)
{
- u32 smpr_val;
+ u32 reg;
- smpr_val = qspi_read32(priv->flags, &priv->regs->smpr);
- smpr_val &= ~clear_bits;
- smpr_val |= set_bits;
- qspi_write32(priv->flags, &priv->regs->smpr, smpr_val);
+ if (!q->devtype_data->little_endian)
+ mask = (u32)cpu_to_be32(mask);
+
+ return readl_poll_timeout(base, reg, !(reg & mask), timeout_us);
}
-static int fsl_qspi_child_pre_probe(struct udevice *dev)
+static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op)
{
- struct spi_slave *slave = dev_get_parent_priv(dev);
- struct fsl_qspi_priv *priv = dev_get_priv(dev_get_parent(dev));
+ void __iomem *base = q->iobase;
+ int err = 0;
- slave->max_write_size = priv->devtype_data->txfifo;
+ /*
+ * Always start the sequence at the same index since we update
+ * the LUT at each exec_op() call. And also specify the DATA
+ * length, since it's has not been specified in the LUT.
+ */
+ qspi_writel(q, op->data.nbytes | QUADSPI_IPCR_SEQID(SEQID_LUT),
+ base + QUADSPI_IPCR);
- return 0;
+ /* wait for the controller being ready */
+ err = fsl_qspi_readl_poll_tout(q, base + QUADSPI_SR,
+ (QUADSPI_SR_IP_ACC_MASK |
+ QUADSPI_SR_AHB_ACC_MASK),
+ 10, 1000);
+
+ if (!err && op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN)
+ fsl_qspi_read_rxfifo(q, op);
+
+ return err;
}
-static int fsl_qspi_probe(struct udevice *bus)
+static int fsl_qspi_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
{
- u32 amba_size_per_chip;
- struct fsl_qspi_platdata *plat = dev_get_platdata(bus);
- struct fsl_qspi_priv *priv = dev_get_priv(bus);
- struct dm_spi_bus *dm_spi_bus;
- int i, ret;
+ struct fsl_qspi *q = dev_get_priv(slave->dev->parent);
+ void __iomem *base = q->iobase;
+ u32 addr_offset = 0;
+ int err = 0;
- dm_spi_bus = bus->uclass_priv;
+ /* wait for the controller being ready */
+ fsl_qspi_readl_poll_tout(q, base + QUADSPI_SR, (QUADSPI_SR_IP_ACC_MASK |
+ QUADSPI_SR_AHB_ACC_MASK), 10, 1000);
- dm_spi_bus->max_hz = plat->speed_hz;
+ fsl_qspi_select_mem(q, slave);
- priv->regs = (struct fsl_qspi_regs *)(uintptr_t)plat->reg_base;
- priv->flags = plat->flags;
+ if (needs_amba_base_offset(q))
+ addr_offset = q->memmap_phy;
+
+ qspi_writel(q,
+ q->selected * q->devtype_data->ahb_buf_size + addr_offset,
+ base + QUADSPI_SFAR);
+
+ qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) |
+ QUADSPI_MCR_CLR_RXF_MASK | QUADSPI_MCR_CLR_TXF_MASK,
+ base + QUADSPI_MCR);
+
+ qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC | QUADSPI_SPTRCLR_IPPTRC,
+ base + QUADSPI_SPTRCLR);
+
+ fsl_qspi_prepare_lut(q, op);
- priv->speed_hz = plat->speed_hz;
/*
- * QSPI SFADR width is 32bits, the max dest addr is 4GB-1.
- * AMBA memory zone should be located on the 0~4GB space
- * even on a 64bits cpu.
+ * If we have large chunks of data, we read them through the AHB bus
+ * by accessing the mapped memory. In all other cases we use
+ * IP commands to access the flash.
*/
- priv->amba_base[0] = (u32)plat->amba_base;
- priv->amba_total_size = (u32)plat->amba_total_size;
- priv->flash_num = plat->flash_num;
- priv->num_chipselect = plat->num_chipselect;
-
- priv->devtype_data = (struct fsl_qspi_devtype_data *)dev_get_driver_data(bus);
- if (!priv->devtype_data) {
- printf("ERROR : No devtype_data found\n");
- return -ENODEV;
+ if (op->data.nbytes > (q->devtype_data->rxfifo - 4) &&
+ op->data.dir == SPI_MEM_DATA_IN) {
+ fsl_qspi_read_ahb(q, op);
+ } else {
+ qspi_writel(q, QUADSPI_RBCT_WMRK_MASK |
+ QUADSPI_RBCT_RXBRD_USEIPS, base + QUADSPI_RBCT);
+
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
+ fsl_qspi_fill_txfifo(q, op);
+
+ err = fsl_qspi_do_op(q, op);
}
- debug("devtype=%d, txfifo=%d, rxfifo=%d, ahb=%d, data=0x%x\n",
- priv->devtype_data->devtype,
- priv->devtype_data->txfifo,
- priv->devtype_data->rxfifo,
- priv->devtype_data->ahb_buf_size,
- priv->devtype_data->driver_data);
+ /* Invalidate the data in the AHB buffer. */
+ fsl_qspi_invalidate(q);
- /* make sure controller is not busy anywhere */
- ret = is_controller_busy(priv);
+ return err;
+}
- if (ret) {
- debug("ERROR : The controller is busy\n");
- return ret;
+static int fsl_qspi_adjust_op_size(struct spi_slave *slave,
+ struct spi_mem_op *op)
+{
+ struct fsl_qspi *q = dev_get_priv(slave->dev->parent);
+
+ if (op->data.dir == SPI_MEM_DATA_OUT) {
+ if (op->data.nbytes > q->devtype_data->txfifo)
+ op->data.nbytes = q->devtype_data->txfifo;
+ } else {
+ if (op->data.nbytes > q->devtype_data->ahb_buf_size)
+ op->data.nbytes = q->devtype_data->ahb_buf_size;
+ else if (op->data.nbytes > (q->devtype_data->rxfifo - 4))
+ op->data.nbytes = ALIGN_DOWN(op->data.nbytes, 8);
}
- qspi_write32(priv->flags, &priv->regs->mcr,
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK |
- QSPI_MCR_END_CFD_LE);
+ return 0;
+}
+
+static int fsl_qspi_default_setup(struct fsl_qspi *q)
+{
+ void __iomem *base = q->iobase;
+ u32 reg, addr_offset = 0;
+
+ /* Reset the module */
+ qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
+ base + QUADSPI_MCR);
+ udelay(1);
- qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
- QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
+ /* Disable the module */
+ qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
+ base + QUADSPI_MCR);
/*
- * Assign AMBA memory zone for every chipselect
- * QuadSPI has two channels, every channel has two chipselects.
- * If the property 'num-cs' in dts is 2, the AMBA memory will be divided
- * into two parts and assign to every channel. This indicate that every
- * channel only has one valid chipselect.
- * If the property 'num-cs' in dts is 4, the AMBA memory will be divided
- * into four parts and assign to every chipselect.
- * Every channel will has two valid chipselects.
+ * Previous boot stages (BootROM, bootloader) might have used DDR
+ * mode and did not clear the TDH bits. As we currently use SDR mode
+ * only, clear the TDH bits if necessary.
*/
- amba_size_per_chip = priv->amba_total_size >>
- (priv->num_chipselect >> 1);
- for (i = 1 ; i < priv->num_chipselect ; i++)
- priv->amba_base[i] =
- amba_size_per_chip + priv->amba_base[i - 1];
+ if (needs_tdh_setting(q))
+ qspi_writel(q, qspi_readl(q, base + QUADSPI_FLSHCR) &
+ ~QUADSPI_FLSHCR_TDH_MASK,
+ base + QUADSPI_FLSHCR);
+
+ reg = qspi_readl(q, base + QUADSPI_SMPR);
+ qspi_writel(q, reg & ~(QUADSPI_SMPR_FSDLY_MASK
+ | QUADSPI_SMPR_FSPHS_MASK
+ | QUADSPI_SMPR_HSENA_MASK
+ | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR);
+
+ /* We only use the buffer3 for AHB read */
+ qspi_writel(q, 0, base + QUADSPI_BUF0IND);
+ qspi_writel(q, 0, base + QUADSPI_BUF1IND);
+ qspi_writel(q, 0, base + QUADSPI_BUF2IND);
+
+ qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT),
+ q->iobase + QUADSPI_BFGENCR);
+ qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, base + QUADSPI_RBCT);
+ qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
+ QUADSPI_BUF3CR_ADATSZ(q->devtype_data->ahb_buf_size / 8),
+ base + QUADSPI_BUF3CR);
+
+ if (needs_amba_base_offset(q))
+ addr_offset = q->memmap_phy;
/*
- * 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.
+ * In HW there can be a maximum of four chips on two buses with
+ * two chip selects on each bus. We use four chip selects in SW
+ * to differentiate between the four chips.
+ * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD,
+ * SFB2AD accordingly.
*/
- qspi_write32(priv->flags, &priv->regs->sfa1ad,
- priv->amba_base[0] + amba_size_per_chip);
- switch (priv->num_chipselect) {
- case 1:
- break;
- case 2:
- qspi_write32(priv->flags, &priv->regs->sfa2ad,
- priv->amba_base[1]);
- qspi_write32(priv->flags, &priv->regs->sfb1ad,
- priv->amba_base[1] + amba_size_per_chip);
- qspi_write32(priv->flags, &priv->regs->sfb2ad,
- priv->amba_base[1] + amba_size_per_chip);
- break;
- case 4:
- qspi_write32(priv->flags, &priv->regs->sfa2ad,
- priv->amba_base[2]);
- qspi_write32(priv->flags, &priv->regs->sfb1ad,
- priv->amba_base[3]);
- qspi_write32(priv->flags, &priv->regs->sfb2ad,
- priv->amba_base[3] + amba_size_per_chip);
- break;
- default:
- debug("Error: Unsupported chipselect number %u!\n",
- priv->num_chipselect);
- qspi_module_disable(priv, 1);
- return -EINVAL;
- }
-
- qspi_set_lut(priv);
-
-#ifdef CONFIG_SYS_FSL_QSPI_AHB
- qspi_init_ahb_read(priv);
-#endif
-
- qspi_module_disable(priv, 0);
-
+ qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset,
+ base + QUADSPI_SFA1AD);
+ qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset,
+ base + QUADSPI_SFA2AD);
+ qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset,
+ base + QUADSPI_SFB1AD);
+ qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset,
+ base + QUADSPI_SFB2AD);
+
+ q->selected = -1;
+
+ /* Enable the module */
+ qspi_writel(q, QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
+ base + QUADSPI_MCR);
return 0;
}
-static int fsl_qspi_ofdata_to_platdata(struct udevice *bus)
+static const struct spi_controller_mem_ops fsl_qspi_mem_ops = {
+ .adjust_op_size = fsl_qspi_adjust_op_size,
+ .supports_op = fsl_qspi_supports_op,
+ .exec_op = fsl_qspi_exec_op,
+};
+
+static int fsl_qspi_probe(struct udevice *bus)
{
- struct fdt_resource res_regs, res_mem;
- struct fsl_qspi_platdata *plat = bus->platdata;
+ struct dm_spi_bus *dm_bus = bus->uclass_priv;
+ struct fsl_qspi *q = dev_get_priv(bus);
const void *blob = gd->fdt_blob;
int node = dev_of_offset(bus);
- int ret, flash_num = 0, subnode;
+ struct fdt_resource res;
+ int ret;
- if (fdtdec_get_bool(blob, node, "big-endian"))
- plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
+ q->dev = bus;
+ q->devtype_data = (struct fsl_qspi_devtype_data *)
+ dev_get_driver_data(bus);
- ret = fdt_get_named_resource(blob, node, "reg", "reg-names",
- "QuadSPI", &res_regs);
+ /* find the resources */
+ ret = fdt_get_named_resource(blob, node, "reg", "reg-names", "QuadSPI",
+ &res);
if (ret) {
- debug("Error: can't get regs base addresses(ret = %d)!\n", ret);
+ dev_err(bus, "Can't get regs base addresses(ret = %d)!\n", ret);
return -ENOMEM;
}
+
+ q->iobase = map_physmem(res.start, res.end - res.start, MAP_NOCACHE);
+
ret = fdt_get_named_resource(blob, node, "reg", "reg-names",
- "QuadSPI-memory", &res_mem);
+ "QuadSPI-memory", &res);
if (ret) {
- debug("Error: can't get AMBA base addresses(ret = %d)!\n", ret);
+ dev_err(bus, "Can't get AMBA base addresses(ret = %d)!\n", ret);
return -ENOMEM;
}
- /* Count flash numbers */
- fdt_for_each_subnode(subnode, blob, node)
- ++flash_num;
+ q->ahb_addr = map_physmem(res.start, res.end - res.start, MAP_NOCACHE);
+ q->memmap_phy = res.start;
- if (flash_num == 0) {
- debug("Error: Missing flashes!\n");
- return -ENODEV;
- }
+ dm_bus->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
+ 66000000);
- plat->speed_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
- FSL_QSPI_DEFAULT_SCK_FREQ);
- plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs",
- FSL_QSPI_MAX_CHIPSELECT_NUM);
-
- plat->reg_base = res_regs.start;
- plat->amba_base = res_mem.start;
- plat->amba_total_size = res_mem.end - res_mem.start + 1;
- plat->flash_num = flash_num;
-
- debug("%s: regs=<0x%llx> <0x%llx, 0x%llx>, max-frequency=%d, endianess=%s\n",
- __func__,
- (u64)plat->reg_base,
- (u64)plat->amba_base,
- (u64)plat->amba_total_size,
- plat->speed_hz,
- plat->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le"
- );
+ fsl_qspi_default_setup(q);
return 0;
}
static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
+ const void *dout, void *din, unsigned long flags)
{
- struct fsl_qspi_priv *priv;
- struct udevice *bus;
-
- bus = dev->parent;
- priv = dev_get_priv(bus);
-
- return qspi_xfer(priv, bitlen, dout, din, flags);
+ return 0;
}
static int fsl_qspi_claim_bus(struct udevice *dev)
{
- struct fsl_qspi_priv *priv;
- struct udevice *bus;
- struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
- int ret;
-
- bus = dev->parent;
- priv = dev_get_priv(bus);
-
- /* make sure controller is not busy anywhere */
- ret = is_controller_busy(priv);
-
- if (ret) {
- debug("ERROR : The controller is busy\n");
- return ret;
- }
-
- priv->cur_amba_base = priv->amba_base[slave_plat->cs];
-
- qspi_module_disable(priv, 0);
-
return 0;
}
static int fsl_qspi_release_bus(struct udevice *dev)
{
- struct fsl_qspi_priv *priv;
- struct udevice *bus;
-
- bus = dev->parent;
- priv = dev_get_priv(bus);
-
- qspi_module_disable(priv, 1);
-
return 0;
}
static int fsl_qspi_set_speed(struct udevice *bus, uint speed)
{
- /* Nothing to do */
return 0;
}
static int fsl_qspi_set_mode(struct udevice *bus, uint mode)
{
- /* Nothing to do */
return 0;
}
@@ -1146,14 +785,17 @@ static const struct dm_spi_ops fsl_qspi_ops = {
.xfer = fsl_qspi_xfer,
.set_speed = fsl_qspi_set_speed,
.set_mode = fsl_qspi_set_mode,
+ .mem_ops = &fsl_qspi_mem_ops,
};
static const struct udevice_id fsl_qspi_ids[] = {
- { .compatible = "fsl,vf610-qspi", .data = (ulong)&vybrid_data },
- { .compatible = "fsl,imx6sx-qspi", .data = (ulong)&imx6sx_data },
- { .compatible = "fsl,imx6ul-qspi", .data = (ulong)&imx6ul_7d_data },
- { .compatible = "fsl,imx7d-qspi", .data = (ulong)&imx6ul_7d_data },
- { .compatible = "fsl,imx7ulp-qspi", .data = (ulong)&imx7ulp_data },
+ { .compatible = "fsl,vf610-qspi", .data = (ulong)&vybrid_data, },
+ { .compatible = "fsl,imx6sx-qspi", .data = (ulong)&imx6sx_data, },
+ { .compatible = "fsl,imx6ul-qspi", .data = (ulong)&imx6ul_data, },
+ { .compatible = "fsl,imx7d-qspi", .data = (ulong)&imx7d_data, },
+ { .compatible = "fsl,ls1021a-qspi", .data = (ulong)&ls1021a_data, },
+ { .compatible = "fsl,ls1088a-qspi", .data = (ulong)&ls1088a_data, },
+ { .compatible = "fsl,ls2080a-qspi", .data = (ulong)&ls2080a_data, },
{ }
};
@@ -1162,9 +804,6 @@ U_BOOT_DRIVER(fsl_qspi) = {
.id = UCLASS_SPI,
.of_match = fsl_qspi_ids,
.ops = &fsl_qspi_ops,
- .ofdata_to_platdata = fsl_qspi_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct fsl_qspi_platdata),
- .priv_auto_alloc_size = sizeof(struct fsl_qspi_priv),
+ .priv_auto_alloc_size = sizeof(struct fsl_qspi),
.probe = fsl_qspi_probe,
- .child_pre_probe = fsl_qspi_child_pre_probe,
};
diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h
deleted file mode 100644
index 9e61a852b5..0000000000
--- a/drivers/spi/fsl_qspi.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright 2013-2014 Freescale Semiconductor, Inc.
- *
- * Register definitions for Freescale QSPI
- */
-
-#ifndef _FSL_QSPI_H_
-#define _FSL_QSPI_H_
-
-struct fsl_qspi_regs {
- u32 mcr;
- u32 rsvd0[1];
- u32 ipcr;
- u32 flshcr;
- u32 buf0cr;
- u32 buf1cr;
- u32 buf2cr;
- u32 buf3cr;
- u32 bfgencr;
- u32 soccr;
- u32 rsvd1[2];
- u32 buf0ind;
- u32 buf1ind;
- u32 buf2ind;
- u32 rsvd2[49];
- u32 sfar;
- u32 rsvd3[1];
- u32 smpr;
- u32 rbsr;
- u32 rbct;
- u32 rsvd4[15];
- u32 tbsr;
- u32 tbdr;
- u32 rsvd5[1];
- u32 sr;
- u32 fr;
- u32 rser;
- u32 spndst;
- u32 sptrclr;
- u32 rsvd6[4];
- u32 sfa1ad;
- u32 sfa2ad;
- u32 sfb1ad;
- u32 sfb2ad;
- u32 rsvd7[28];
- u32 rbdr[32];
- u32 rsvd8[32];
- u32 lutkey;
- u32 lckcr;
- u32 rsvd9[2];
- u32 lut[64];
-};
-
-#define QSPI_IPCR_SEQID_SHIFT 24
-#define QSPI_IPCR_SEQID_MASK (0xf << QSPI_IPCR_SEQID_SHIFT)
-
-#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
-#define QSPI_MCR_CLR_RXF_MASK (1 << QSPI_MCR_CLR_RXF_SHIFT)
-#define QSPI_MCR_CLR_TXF_SHIFT 11
-#define QSPI_MCR_CLR_TXF_MASK (1 << QSPI_MCR_CLR_TXF_SHIFT)
-#define QSPI_MCR_MDIS_SHIFT 14
-#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)
-#define QSPI_SMPR_FSPHS_SHIFT 5
-#define QSPI_SMPR_FSPHS_MASK (1 << QSPI_SMPR_FSPHS_SHIFT)
-#define QSPI_SMPR_FSDLY_SHIFT 6
-#define QSPI_SMPR_FSDLY_MASK (1 << QSPI_SMPR_FSDLY_SHIFT)
-#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
-#define QSPI_BFGENCR_PAR_EN_MASK (1 << QSPI_BFGENCR_PAR_EN_SHIFT)
-
-#define QSPI_RBSR_RDBFL_SHIFT 8
-#define QSPI_RBSR_RDBFL_MASK (0x3f << QSPI_RBSR_RDBFL_SHIFT)
-
-#define QSPI_RBCT_RXBRD_SHIFT 8
-#define QSPI_RBCT_RXBRD_USEIPS (1 << QSPI_RBCT_RXBRD_SHIFT)
-
-#define QSPI_SR_AHB_ACC_SHIFT 2
-#define QSPI_SR_AHB_ACC_MASK (1 << QSPI_SR_AHB_ACC_SHIFT)
-#define QSPI_SR_IP_ACC_SHIFT 1
-#define QSPI_SR_IP_ACC_MASK (1 << QSPI_SR_IP_ACC_SHIFT)
-#define QSPI_SR_BUSY_SHIFT 0
-#define QSPI_SR_BUSY_MASK (1 << QSPI_SR_BUSY_SHIFT)
-
-#define QSPI_LCKCR_LOCK 0x1
-#define QSPI_LCKCR_UNLOCK 0x2
-
-#define LUT_KEY_VALUE 0x5af05af0
-
-#define OPRND0_SHIFT 0
-#define OPRND0(x) ((x) << OPRND0_SHIFT)
-#define PAD0_SHIFT 8
-#define PAD0(x) ((x) << PAD0_SHIFT)
-#define INSTR0_SHIFT 10
-#define INSTR0(x) ((x) << INSTR0_SHIFT)
-#define OPRND1_SHIFT 16
-#define OPRND1(x) ((x) << OPRND1_SHIFT)
-#define PAD1_SHIFT 24
-#define PAD1(x) ((x) << PAD1_SHIFT)
-#define INSTR1_SHIFT 26
-#define INSTR1(x) ((x) << INSTR1_SHIFT)
-
-#define LUT_CMD 1
-#define LUT_ADDR 2
-#define LUT_DUMMY 3
-#define LUT_READ 7
-#define LUT_WRITE 8
-
-#define LUT_PAD1 0
-#define LUT_PAD2 1
-#define LUT_PAD4 2
-
-#define ADDR24BIT 0x18
-#define ADDR32BIT 0x20
-
-#endif /* _FSL_QSPI_H_ */
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index e900c997bd..ffbe20c5b1 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -153,7 +153,7 @@ bool spi_mem_default_supports_op(struct spi_slave *slave,
spi_check_buswidth_req(slave, op->dummy.buswidth, true))
return false;
- if (op->data.nbytes &&
+ if (op->data.dir != SPI_MEM_NO_DATA &&
spi_check_buswidth_req(slave, op->data.buswidth,
op->data.dir == SPI_MEM_DATA_OUT))
return false;
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
index 969bd4b75c..4cab0391f7 100644
--- a/drivers/spi/spi-sifive.c
+++ b/drivers/spi/spi-sifive.c
@@ -8,8 +8,10 @@
#include <common.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <malloc.h>
-#include <spi.h>
+#include <spi-mem.h>
+#include <wait_bit.h>
#include <asm/io.h>
#include <linux/log2.h>
#include <clk.h>
@@ -85,6 +87,11 @@
#define SIFIVE_SPI_IP_TXWM BIT(0)
#define SIFIVE_SPI_IP_RXWM BIT(1)
+/* format protocol */
+#define SIFIVE_SPI_PROTO_QUAD 4 /* 4 lines I/O protocol transfer */
+#define SIFIVE_SPI_PROTO_DUAL 2 /* 2 lines I/O protocol transfer */
+#define SIFIVE_SPI_PROTO_SINGLE 1 /* 1 line I/O protocol transfer */
+
struct sifive_spi {
void *regs; /* base address of the registers */
u32 fifo_depth;
@@ -92,28 +99,29 @@ struct sifive_spi {
u32 cs_inactive; /* Level of the CS pins when inactive*/
u32 freq;
u32 num_cs;
+ u8 fmt_proto;
};
static void sifive_spi_prep_device(struct sifive_spi *spi,
- struct dm_spi_slave_platdata *slave)
+ struct dm_spi_slave_platdata *slave_plat)
{
/* Update the chip select polarity */
- if (slave->mode & SPI_CS_HIGH)
- spi->cs_inactive &= ~BIT(slave->cs);
+ if (slave_plat->mode & SPI_CS_HIGH)
+ spi->cs_inactive &= ~BIT(slave_plat->cs);
else
- spi->cs_inactive |= BIT(slave->cs);
+ spi->cs_inactive |= BIT(slave_plat->cs);
writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
/* Select the correct device */
- writel(slave->cs, spi->regs + SIFIVE_SPI_REG_CSID);
+ writel(slave_plat->cs, spi->regs + SIFIVE_SPI_REG_CSID);
}
static int sifive_spi_set_cs(struct sifive_spi *spi,
- struct dm_spi_slave_platdata *slave)
+ struct dm_spi_slave_platdata *slave_plat)
{
u32 cs_mode = SIFIVE_SPI_CSMODE_MODE_HOLD;
- if (slave->mode & SPI_CS_HIGH)
+ if (slave_plat->mode & SPI_CS_HIGH)
cs_mode = SIFIVE_SPI_CSMODE_MODE_AUTO;
writel(cs_mode, spi->regs + SIFIVE_SPI_REG_CSMODE);
@@ -127,8 +135,8 @@ static void sifive_spi_clear_cs(struct sifive_spi *spi)
}
static void sifive_spi_prep_transfer(struct sifive_spi *spi,
- bool is_rx_xfer,
- struct dm_spi_slave_platdata *slave)
+ struct dm_spi_slave_platdata *slave_plat,
+ u8 *rx_ptr)
{
u32 cr;
@@ -141,21 +149,26 @@ static void sifive_spi_prep_transfer(struct sifive_spi *spi,
/* LSB first? */
cr &= ~SIFIVE_SPI_FMT_ENDIAN;
- if (slave->mode & SPI_LSB_FIRST)
+ if (slave_plat->mode & SPI_LSB_FIRST)
cr |= SIFIVE_SPI_FMT_ENDIAN;
/* Number of wires ? */
cr &= ~SIFIVE_SPI_FMT_PROTO_MASK;
- if ((slave->mode & SPI_TX_QUAD) || (slave->mode & SPI_RX_QUAD))
+ switch (spi->fmt_proto) {
+ case SIFIVE_SPI_PROTO_QUAD:
cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
- else if ((slave->mode & SPI_TX_DUAL) || (slave->mode & SPI_RX_DUAL))
+ break;
+ case SIFIVE_SPI_PROTO_DUAL:
cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
- else
+ break;
+ default:
cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
+ break;
+ }
/* SPI direction in/out ? */
cr &= ~SIFIVE_SPI_FMT_DIR;
- if (!is_rx_xfer)
+ if (!rx_ptr)
cr |= SIFIVE_SPI_FMT_DIR;
writel(cr, spi->regs + SIFIVE_SPI_REG_FMT);
@@ -186,50 +199,62 @@ static void sifive_spi_tx(struct sifive_spi *spi, const u8 *tx_ptr)
writel(tx_data, spi->regs + SIFIVE_SPI_REG_TXDATA);
}
+static int sifive_spi_wait(struct sifive_spi *spi, u32 bit)
+{
+ return wait_for_bit_le32(spi->regs + SIFIVE_SPI_REG_IP,
+ bit, true, 100, false);
+}
+
static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct udevice *bus = dev->parent;
struct sifive_spi *spi = dev_get_priv(bus);
- struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev);
- const unsigned char *tx_ptr = dout;
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+ const u8 *tx_ptr = dout;
u8 *rx_ptr = din;
u32 remaining_len;
int ret;
if (flags & SPI_XFER_BEGIN) {
- sifive_spi_prep_device(spi, slave);
+ sifive_spi_prep_device(spi, slave_plat);
- ret = sifive_spi_set_cs(spi, slave);
+ ret = sifive_spi_set_cs(spi, slave_plat);
if (ret)
return ret;
}
- sifive_spi_prep_transfer(spi, true, slave);
+ sifive_spi_prep_transfer(spi, slave_plat, rx_ptr);
remaining_len = bitlen / 8;
while (remaining_len) {
- int n_words, tx_words, rx_words;
-
- n_words = min(remaining_len, spi->fifo_depth);
+ unsigned int n_words = min(remaining_len, spi->fifo_depth);
+ unsigned int tx_words, rx_words;
/* Enqueue n_words for transmission */
- if (tx_ptr) {
- for (tx_words = 0; tx_words < n_words; ++tx_words) {
- sifive_spi_tx(spi, tx_ptr);
- sifive_spi_rx(spi, NULL);
- tx_ptr++;
- }
+ for (tx_words = 0; tx_words < n_words; tx_words++) {
+ if (!tx_ptr)
+ sifive_spi_tx(spi, NULL);
+ else
+ sifive_spi_tx(spi, tx_ptr++);
}
- /* Read out all the data from the RX FIFO */
if (rx_ptr) {
- for (rx_words = 0; rx_words < n_words; ++rx_words) {
- sifive_spi_tx(spi, NULL);
- sifive_spi_rx(spi, rx_ptr);
- rx_ptr++;
- }
+ /* Wait for transmission + reception to complete */
+ writel(n_words - 1, spi->regs + SIFIVE_SPI_REG_RXMARK);
+ ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_RXWM);
+ if (ret)
+ return ret;
+
+ /* Read out all the data from the RX FIFO */
+ for (rx_words = 0; rx_words < n_words; rx_words++)
+ sifive_spi_rx(spi, rx_ptr++);
+ } else {
+ /* Wait for transmission to complete */
+ ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_TXWM);
+ if (ret)
+ return ret;
}
remaining_len -= n_words;
@@ -241,6 +266,80 @@ static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen,
return 0;
}
+static int sifive_spi_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ struct udevice *dev = slave->dev;
+ struct sifive_spi *spi = dev_get_priv(dev->parent);
+ unsigned long flags = SPI_XFER_BEGIN;
+ u8 opcode = op->cmd.opcode;
+ unsigned int pos = 0;
+ const void *tx_buf = NULL;
+ void *rx_buf = NULL;
+ int op_len, i;
+ int ret;
+
+ if (!op->addr.nbytes && !op->dummy.nbytes && !op->data.nbytes)
+ flags |= SPI_XFER_END;
+
+ spi->fmt_proto = op->cmd.buswidth;
+
+ /* send the opcode */
+ ret = sifive_spi_xfer(dev, 8, (void *)&opcode, NULL, flags);
+ if (ret < 0) {
+ dev_err(dev, "failed to xfer opcode\n");
+ return ret;
+ }
+
+ op_len = op->addr.nbytes + op->dummy.nbytes;
+ u8 op_buf[op_len];
+
+ /* send the addr + dummy */
+ if (op->addr.nbytes) {
+ /* fill address */
+ for (i = 0; i < op->addr.nbytes; i++)
+ op_buf[pos + i] = op->addr.val >>
+ (8 * (op->addr.nbytes - i - 1));
+
+ pos += op->addr.nbytes;
+
+ /* fill dummy */
+ if (op->dummy.nbytes)
+ memset(op_buf + pos, 0xff, op->dummy.nbytes);
+
+ /* make sure to set end flag, if no data bytes */
+ if (!op->data.nbytes)
+ flags |= SPI_XFER_END;
+
+ spi->fmt_proto = op->addr.buswidth;
+
+ ret = sifive_spi_xfer(dev, op_len * 8, op_buf, NULL, flags);
+ if (ret < 0) {
+ dev_err(dev, "failed to xfer addr + dummy\n");
+ return ret;
+ }
+ }
+
+ /* send/received the data */
+ if (op->data.nbytes) {
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ rx_buf = op->data.buf.in;
+ else
+ tx_buf = op->data.buf.out;
+
+ spi->fmt_proto = op->data.buswidth;
+
+ ret = sifive_spi_xfer(dev, op->data.nbytes * 8,
+ tx_buf, rx_buf, SPI_XFER_END);
+ if (ret) {
+ dev_err(dev, "failed to xfer data\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int sifive_spi_set_speed(struct udevice *bus, uint speed)
{
struct sifive_spi *spi = dev_get_priv(bus);
@@ -309,6 +408,10 @@ static void sifive_spi_init_hw(struct sifive_spi *spi)
/* Watermark interrupts are disabled by default */
writel(0, spi->regs + SIFIVE_SPI_REG_IE);
+ /* Default watermark FIFO threshold values */
+ writel(1, spi->regs + SIFIVE_SPI_REG_TXMARK);
+ writel(0, spi->regs + SIFIVE_SPI_REG_RXMARK);
+
/* Set CS/SCK Delays and Inactive Time to defaults */
writel(SIFIVE_SPI_DELAY0_CSSCK(1) | SIFIVE_SPI_DELAY0_SCKCS(1),
spi->regs + SIFIVE_SPI_REG_DELAY0);
@@ -348,11 +451,16 @@ static int sifive_spi_probe(struct udevice *bus)
return 0;
}
+static const struct spi_controller_mem_ops sifive_spi_mem_ops = {
+ .exec_op = sifive_spi_exec_op,
+};
+
static const struct dm_spi_ops sifive_spi_ops = {
.xfer = sifive_spi_xfer,
.set_speed = sifive_spi_set_speed,
.set_mode = sifive_spi_set_mode,
.cs_info = sifive_spi_cs_info,
+ .mem_ops = &sifive_spi_mem_ops,
};
static const struct udevice_id sifive_spi_ids[] = {
diff --git a/drivers/timer/mtk_timer.c b/drivers/timer/mtk_timer.c
index b5e76bd358..e99135e5be 100644
--- a/drivers/timer/mtk_timer.c
+++ b/drivers/timer/mtk_timer.c
@@ -71,6 +71,7 @@ static const struct timer_ops mtk_timer_ops = {
static const struct udevice_id mtk_timer_ids[] = {
{ .compatible = "mediatek,timer" },
+ { .compatible = "mediatek,mt6577-timer" },
{ }
};
diff --git a/drivers/video/rockchip/rk3288_mipi.c b/drivers/video/rockchip/rk3288_mipi.c
index f4444b9c34..71d3faf169 100644
--- a/drivers/video/rockchip/rk3288_mipi.c
+++ b/drivers/video/rockchip/rk3288_mipi.c
@@ -8,7 +8,6 @@
#include <clk.h>
#include <display.h>
#include <dm.h>
-#include <fdtdec.h>
#include <panel.h>
#include <regmap.h>
#include "rk_mipi.h"
diff --git a/drivers/video/rockchip/rk3399_mipi.c b/drivers/video/rockchip/rk3399_mipi.c
index 74ebe770a9..cfaa37797e 100644
--- a/drivers/video/rockchip/rk3399_mipi.c
+++ b/drivers/video/rockchip/rk3399_mipi.c
@@ -8,7 +8,6 @@
#include <clk.h>
#include <display.h>
#include <dm.h>
-#include <fdtdec.h>
#include <panel.h>
#include <regmap.h>
#include "rk_mipi.h"
diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c
index cf84b886e7..99b16cd95e 100644
--- a/drivers/video/rockchip/rk_edp.c
+++ b/drivers/video/rockchip/rk_edp.c
@@ -997,7 +997,7 @@ static int rk_edp_ofdata_to_platdata(struct udevice *dev)
{
struct rk_edp_priv *priv = dev_get_priv(dev);
- priv->regs = (struct rk3288_edp *)devfdt_get_addr(dev);
+ priv->regs = dev_read_addr_ptr(dev);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
return 0;
diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c
index 79e24baf53..c92c2e3c6c 100644
--- a/drivers/video/rockchip/rk_lvds.c
+++ b/drivers/video/rockchip/rk_lvds.c
@@ -161,8 +161,7 @@ int rk_lvds_enable(struct udevice *dev, int panel_bpp,
int rk_lvds_read_timing(struct udevice *dev, struct display_timing *timing)
{
- if (fdtdec_decode_display_timing
- (gd->fdt_blob, dev_of_offset(dev), 0, timing)) {
+ if (ofnode_decode_display_timing(dev_ofnode(dev), 0, timing)) {
debug("%s: Failed to decode display timing\n", __func__);
return -EINVAL;
}
@@ -173,13 +172,11 @@ int rk_lvds_read_timing(struct udevice *dev, struct display_timing *timing)
static int rk_lvds_ofdata_to_platdata(struct udevice *dev)
{
struct rk_lvds_priv *priv = dev_get_priv(dev);
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(dev);
int ret;
- priv->regs = (void *)devfdt_get_addr(dev);
+ priv->regs = dev_read_addr_ptr(dev);
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
- ret = fdtdec_get_int(blob, node, "rockchip,output", -1);
+ ret = dev_read_s32_default(dev, "rockchip,output", -1);
if (ret != -1) {
priv->output = ret;
debug("LVDS output : %d\n", ret);
@@ -188,7 +185,7 @@ static int rk_lvds_ofdata_to_platdata(struct udevice *dev)
priv->output = LVDS_OUTPUT_RGB;
}
- ret = fdtdec_get_int(blob, node, "rockchip,data-mapping", -1);
+ ret = dev_read_s32_default(dev, "rockchip,data-mapping", -1);
if (ret != -1) {
priv->format = ret;
debug("LVDS data-mapping : %d\n", ret);
@@ -197,7 +194,7 @@ static int rk_lvds_ofdata_to_platdata(struct udevice *dev)
priv->format = LVDS_FORMAT_JEIDA;
}
- ret = fdtdec_get_int(blob, node, "rockchip,data-width", -1);
+ ret = dev_read_s32_default(dev, "rockchip,data-width", -1);
if (ret != -1) {
debug("LVDS data-width : %d\n", ret);
if (ret == 24) {
diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c
index f9280e8607..f1c21bb8d7 100644
--- a/drivers/video/rockchip/rk_mipi.c
+++ b/drivers/video/rockchip/rk_mipi.c
@@ -8,7 +8,6 @@
#include <clk.h>
#include <display.h>
#include <dm.h>
-#include <fdtdec.h>
#include <panel.h>
#include <regmap.h>
#include "rk_mipi.h"
@@ -29,8 +28,7 @@ int rk_mipi_read_timing(struct udevice *dev,
{
int ret;
- ret = fdtdec_decode_display_timing(gd->fdt_blob, dev_of_offset(dev),
- 0, timing);
+ ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, timing);
if (ret) {
debug("%s: Failed to decode display timing (ret=%d)\n",
__func__, ret);
@@ -77,7 +75,7 @@ static void rk_mipi_dsi_write(uintptr_t regs, u32 reg, u32 val)
int rk_mipi_dsi_enable(struct udevice *dev,
const struct display_timing *timing)
{
- int node, timing_node;
+ ofnode node, timing_node;
int val;
struct rk_mipi_priv *priv = dev_get_priv(dev);
uintptr_t regs = priv->regs;
@@ -120,10 +118,10 @@ int rk_mipi_dsi_enable(struct udevice *dev,
rk_mipi_dsi_write(regs, VID_PKT_SIZE, 0x4b0);
/* Set dpi color coding depth 24 bit */
- timing_node = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
- "display-timings");
- node = fdt_first_subnode(gd->fdt_blob, timing_node);
- val = fdtdec_get_int(gd->fdt_blob, node, "bits-per-pixel", -1);
+ timing_node = ofnode_find_subnode(dev->node, "display-timings");
+ node = ofnode_first_subnode(timing_node);
+
+ val = ofnode_read_u32_default(node, "bits-per-pixel", -1);
switch (val) {
case 16:
rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_16BIT_CFG_1);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 6cafd243e0..bf06180cdd 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -49,6 +49,7 @@ config ULP_WATCHDOG
config DESIGNWARE_WATCHDOG
bool "Designware watchdog timer support"
select HW_WATCHDOG if !WDT
+ default y if WDT && ROCKCHIP_RK3399
help
Enable this to support Designware Watchdog Timer IP, present e.g.
on Altera SoCFPGA SoCs.
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index 669a32320d..b3c597e1d0 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -143,6 +143,7 @@ static const struct wdt_ops mtk_wdt_ops = {
static const struct udevice_id mtk_wdt_ids[] = {
{ .compatible = "mediatek,wdt"},
+ { .compatible = "mediatek,mt6589-wdt"},
{}
};