diff options
Diffstat (limited to 'drivers')
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, ¯onix_spinand_manufacturer, µn_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, ®, 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, ®s->lutkey, LUT_KEY_VALUE); - qspi_write32(priv->flags, ®s->lckcr, QSPI_LCKCR_UNLOCK); - - /* Write Enable */ - lut_base = SEQID_WREN * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_WREN) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); - qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* Fast Read */ - lut_base = SEQID_FAST_READ * 4; -#ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->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, ®s->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, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* Read Status */ - lut_base = SEQID_RDSR * 4; - qspi_write32(priv->flags, ®s->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, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* Erase a sector */ - lut_base = SEQID_SE * 4; -#ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->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, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* Erase the whole chip */ - lut_base = SEQID_CHIP_ERASE * 4; - qspi_write32(priv->flags, ®s->lut[lut_base], - OPRND0(QSPI_CMD_CHIP_ERASE) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); - qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* Page Program */ - lut_base = SEQID_PP * 4; -#ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->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, ®s->lut[lut_base + 1], OPRND0(0) | - PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* READ ID */ - lut_base = SEQID_RDID * 4; - qspi_write32(priv->flags, ®s->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, ®s->lut[lut_base + 1], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); - qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); - - /* SUB SECTOR 4K ERASE */ - lut_base = SEQID_BE_4K * 4; - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->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, ®s->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, ®s->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, ®s->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, ®s->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, ®s->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, ®s->lut[lut_base + 1], - OPRND0(1) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); - - /* Lock the LUT */ - qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); - qspi_write32(priv->flags, ®s->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, ®s->mcr); - reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->mcr); - - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->mcr); - /* Disable the module */ - qspi_write32(priv->flags, ®s->mcr, reg | QSPI_MCR_MDIS_MASK); - - /* Set the Sampling Register for DDR */ - reg2 = qspi_read32(priv->flags, ®s->smpr); - reg2 &= ~QSPI_SMPR_DDRSMP_MASK; - reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT); - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->flshcr); - reg &= ~(BIT(17)); - reg |= BIT(16); - qspi_write32(priv->flags, ®s->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, ®s->buf0cr, QSPI_BUFXCR_INVALID_MSTRID); - qspi_write32(priv->flags, ®s->buf1cr, QSPI_BUFXCR_INVALID_MSTRID); - qspi_write32(priv->flags, ®s->buf2cr, QSPI_BUFXCR_INVALID_MSTRID); - qspi_write32(priv->flags, ®s->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, ®s->buf0ind, 0); - qspi_write32(priv->flags, ®s->buf1ind, 0); - qspi_write32(priv->flags, ®s->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, ®s->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, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - mcr_reg); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth), + op->cmd.opcode); - qspi_write32(priv->flags, ®s->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, ®s->ipcr, - (seqid << QSPI_IPCR_SEQID_SHIFT) | len); - - /* Wait previous command complete */ - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - while (1) { - WATCHDOG_RESET(); - - reg = qspi_read32(priv->flags, ®s->rbsr); - if (reg & QSPI_RBSR_RDBFL_MASK) { - data = qspi_read32(priv->flags, ®s->rbdr[0]); - data = qspi_endian_xchg(priv, data); - memcpy(rxbuf, &data, len); - qspi_write32(priv->flags, ®s->mcr, - qspi_read32(priv->flags, ®s->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, ®s->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, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - mcr_reg); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - i = 0; - while ((priv->devtype_data->rxfifo >= len) && (len > 0)) { - WATCHDOG_RESET(); - - rbsr_reg = qspi_read32(priv->flags, ®s->rbsr); - if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) { - data = qspi_read32(priv->flags, ®s->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, ®s->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, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - mcr_reg); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - to_or_from = priv->sf_addr + priv->cur_amba_base; - - while (len > 0) { - WATCHDOG_RESET(); - - qspi_write32(priv->flags, ®s->sfar, to_or_from); - - size = (len > priv->devtype_data->rxfifo) ? - priv->devtype_data->rxfifo : len; - - qspi_write32(priv->flags, ®s->ipcr, - (seqid << QSPI_IPCR_SEQID_SHIFT) | - size); - while (qspi_read32(priv->flags, ®s->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, ®s->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, ®s->mcr, - qspi_read32(priv->flags, ®s->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, ®s->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, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - mcr_reg); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - status_reg = 0; - while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) { - WATCHDOG_RESET(); - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - reg = qspi_read32(priv->flags, ®s->rbsr); - if (reg & QSPI_RBSR_RDBFL_MASK) { - status_reg = qspi_read32(priv->flags, ®s->rbdr[0]); - status_reg = qspi_endian_xchg(priv, status_reg); - } - qspi_write32(priv->flags, ®s->mcr, - qspi_read32(priv->flags, ®s->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, ®s->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, ®s->tbdr, data); - txbuf += 4; - } - - qspi_write32(priv->flags, ®s->ipcr, - (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; + udelay(1); - qspi_write32(priv->flags, ®s->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, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - mcr_reg); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - while (1) { - WATCHDOG_RESET(); - - reg = qspi_read32(priv->flags, ®s->rbsr); - if (reg & QSPI_RBSR_RDBFL_MASK) { - data = qspi_read32(priv->flags, ®s->rbdr[0]); - data = qspi_endian_xchg(priv, data); - memcpy(rxbuf, &data, len); - qspi_write32(priv->flags, ®s->mcr, - qspi_read32(priv->flags, ®s->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, ®s->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, ®s->mcr); - qspi_write32(priv->flags, ®s->mcr, - QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | - mcr_reg); - qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); - - to_or_from = priv->sf_addr + priv->cur_amba_base; - qspi_write32(priv->flags, ®s->sfar, to_or_from); - - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - if (priv->cur_seqid == QSPI_CMD_SE) { - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); - } else if (priv->cur_seqid == QSPI_CMD_BE_4K) { - qspi_write32(priv->flags, ®s->ipcr, - (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0); - } - while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) - ; - - qspi_write32(priv->flags, ®s->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"}, {} }; |