From c3d31af6d6c2cd63d4de173a00a72c7f009e6443 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Wed, 19 Feb 2020 09:45:37 +0800 Subject: rockchip: video: Use ofnode_decode_display_timing() to parse timing Use ofnode_decode_display_timing() instead of fdtdec_decode_display_timing() to parse display timing, so that we can support live DT. Signed-off-by: Kever Yang Reviewed-by: Simon Glass --- drivers/video/rockchip/rk_lvds.c | 3 +-- drivers/video/rockchip/rk_mipi.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c index 79e24baf53b..404af7eb6e8 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; } diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c index f9280e86070..a77bdfd24dd 100644 --- a/drivers/video/rockchip/rk_mipi.c +++ b/drivers/video/rockchip/rk_mipi.c @@ -29,8 +29,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); -- cgit v1.3.1 From 653ac184ee8c785564d70ee9ccceffbd9a48b737 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Wed, 19 Feb 2020 09:45:38 +0800 Subject: rockchip: video: Convert to use APIs which support live DT Use ofnode_ or dev_ APIs instead of fdt_ and fdtdec_ APIs so that the driver can support live DT. Signed-off-by: Kever Yang Reviewed-by: Simon Glass --- drivers/video/rockchip/rk3288_mipi.c | 1 - drivers/video/rockchip/rk3399_mipi.c | 1 - drivers/video/rockchip/rk_edp.c | 2 +- drivers/video/rockchip/rk_lvds.c | 10 ++++------ drivers/video/rockchip/rk_mipi.c | 11 +++++------ 5 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/video/rockchip/rk3288_mipi.c b/drivers/video/rockchip/rk3288_mipi.c index f4444b9c348..71d3faf169d 100644 --- a/drivers/video/rockchip/rk3288_mipi.c +++ b/drivers/video/rockchip/rk3288_mipi.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include "rk_mipi.h" diff --git a/drivers/video/rockchip/rk3399_mipi.c b/drivers/video/rockchip/rk3399_mipi.c index 74ebe770a95..cfaa37797ed 100644 --- a/drivers/video/rockchip/rk3399_mipi.c +++ b/drivers/video/rockchip/rk3399_mipi.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include "rk_mipi.h" diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c index cf84b886e72..99b16cd95ed 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 404af7eb6e8..c92c2e3c6c0 100644 --- a/drivers/video/rockchip/rk_lvds.c +++ b/drivers/video/rockchip/rk_lvds.c @@ -172,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); @@ -187,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); @@ -196,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 a77bdfd24dd..f1c21bb8d7e 100644 --- a/drivers/video/rockchip/rk_mipi.c +++ b/drivers/video/rockchip/rk_mipi.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include "rk_mipi.h" @@ -76,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; @@ -119,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); -- cgit v1.3.1 From 91afd36f3802aee001a2f551ea1d77aca428b0a9 Mon Sep 17 00:00:00 2001 From: Kuldeep Singh Date: Thu, 20 Feb 2020 22:57:52 +0530 Subject: spi: Transform the FSL QuadSPI driver to use the SPI MEM API To support the SPI MEM API, instead of modifying the existing U-Boot driver, this patch adds a port of the existing Linux driver. This also has the advantage that porting changes and fixes from Linux will be easier. Porting of driver left most of the functions unchanged while few of the changes are: -Remove lock(mutexes) and irq handler as u-boot is a single core execution. -Remove invalid masterid as it was required specially for multicore execution in LS2088ARDB which is not the case in u-boot. -Remove clock support as changing spi speed is not supported in uboot and nor in linux. Currently tested on LS1088ARDB, LS1012ARDB, LS1046ARDB, LS1046AFRWY, LS1043AQDS, LS1021ATWR, LS2088ARDB, I.MX6ULL EVK. Signed-off-by: Frieder Schrempf Signed-off-by: Ashish Kumar Signed-off-by: Kuldeep Singh Reviewed-by: Stefan Roese Tested-by: Stefan Roese Acked-by: Vignesh Raghavendra Acked-by: Jagan Teki --- drivers/spi/fsl_qspi.c | 1577 +++++++++++++++++++----------------------------- drivers/spi/fsl_qspi.h | 145 ----- 2 files changed, 608 insertions(+), 1114 deletions(-) delete mode 100644 drivers/spi/fsl_qspi.h (limited to 'drivers') diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 8e2a09df366..ee2c8b67dc9 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 + * Frieder Schrempf + * Yogesh Gaur + * Suresh Gupta + * + * Based on the original fsl-quadspi.c spi-nor driver. + * Transition to spi-mem in spi-fsl-qspi.c */ #include -#include -#include #include -#include -#include #include -#include -#include -#include -#include "fsl_qspi.h" +#include +#include +#include +#include +#include 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 9e61a852b5a..00000000000 --- 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_ */ -- cgit v1.3.1 From 7ddea756540b5adddfde3b890fa46a40c649e68f Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 13 Mar 2020 01:06:38 +0100 Subject: spi: use is_power_of_2 instead of hweight32 in spi_nor_write() hweight32 is a somewhat expensive way to check for power-of-2. Use the is_power_of_2 helper, which does the standard and cheap idiom foo&(foo-1)==0. add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-96 (-96) Function old new delta spi_nor_write 388 292 -96 Signed-off-by: Rasmus Villemoes Acked-by: Vignesh Raghavendra Acked-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 7b6ad495ace..3bf8ddfb9df 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1246,11 +1246,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; -- cgit v1.3.1 From 0a9c2874978a8468c92ed0dafe7a0cf239dc6a35 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 24 Feb 2020 12:40:51 +0530 Subject: spi: cadence-qspi: Move ref clock calculation to probe "assigned-clock-parents" and "assigned-clock-rates" DT properties take effect only after ofdata_to_platdata() when clk_set_defaults() is called in device_probe(). Therefore clk get rate() would return a wrong value in ofdata_to_platdata() when compared with probe. Hence it needs to be moved to probe. Tested on u-boot-ti/next. Signed-off-by: Pratyush Yadav Acked-by: Vignesh Raghavendra Acked-by: Simon Goldschmidt Reviewed-by: Jagan Teki --- drivers/spi/cadence_qspi.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 83b114ffe74..994a5948f1e 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); -- cgit v1.3.1 From cae3c7cc581c441d822e18c0d14dd3c230beef80 Mon Sep 17 00:00:00 2001 From: Kuldeep Singh Date: Sat, 14 Mar 2020 18:23:54 +0530 Subject: mtd: spi-nor-ids: Enable SPI_NOR_OCTAL_READ flag for mt35xu* Commit 658df8bd9464 ("mtd: spi-nor-core: Add octal mode support") enables octal mode(1-1-8) support in spi-nor framework. mt35xu512aba and mt35xu02g supports SINGLE and OCTAL I/O. Hence, enable SPI_NOR_OCTAL_READ flag for these flashes. Signed-off-by: Kuldeep Singh Reviewed-by: Vignesh Raghavendra Reviewed-by: Priyanka Jain Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-ids.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index abdf560e020..30b9fa8110e 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -183,8 +183,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 -- cgit v1.3.1 From 6f3b1f4a1dea5b733b03445c2a3eff2e4a47eafb Mon Sep 17 00:00:00 2001 From: Bacem Daassi Date: Fri, 27 Mar 2020 19:58:14 +0100 Subject: mtd: spi-nor: Enable dual and quad read for s25fl256s0 The s25fl256s0 supports dual and quad read like s25fl256s1. Enable it by adding SPI_NOR_DUAL_READ and SPI_NOR_QUAD_READ flags to the flash_info entry. Tested on real silicon and confirmed to be working. Signed-off-by: Bacem Daassi Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-ids.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 30b9fa8110e..218385f50a1 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -192,7 +192,7 @@ 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) }, { INFO("s25fl512s_256k", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, -- cgit v1.3.1 From 89127104848cea38bac5d40e3d6973fc203e2df6 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Tue, 3 Mar 2020 20:25:40 +0100 Subject: mtd: spi-nand: Import Toshiba SPI-NAND support Linux has good support for Toshiba SPI-NAND, so lets import it. Signed-off-by: Robert Marko Tested-by: Luka Kovacic Cc: Luka Perkov Reviewed-by: Jagan Teki --- drivers/mtd/nand/spi/Makefile | 2 +- drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/toshiba.c | 191 +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/spi/toshiba.c (limited to 'drivers') diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index dd6bacae34d..6c65b187e86 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 cd624ec6ae6..397dfa41789 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 00000000000..571104a5d94 --- /dev/null +++ b/drivers/mtd/nand/spi/toshiba.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 exceet electronics GmbH + * Copyright (c) 2018 Kontron Electronics GmbH + * + * Author: Frieder Schrempf + */ + +#ifndef __UBOOT__ +#include +#include +#include +#endif +#include + +#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)), + /* 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/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index be01e1e82e5..83eafb184e6 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -204,6 +204,7 @@ struct spinand_manufacturer { extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; extern const struct spinand_manufacturer micron_spinand_manufacturer; +extern const struct spinand_manufacturer toshiba_spinand_manufacturer; extern const struct spinand_manufacturer winbond_spinand_manufacturer; /** -- cgit v1.3.1 From f5fba6e85bf15ae43d73f66730ebf32918445be4 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Tue, 3 Mar 2020 20:25:42 +0100 Subject: mtd: nand: spi: add support for Toshiba TC58CVG2S0HRAIJ Toshiba recently launched new revisions of their serial SLC NAND series. TC58CVG2S0HRAIJ is a refresh of previous series with minor improvements. Basic parameters are same so lets add support for this new revision. Datasheet: https://business.kioxia.com/info/docget.jsp?did=58601&prodName=TC58CVG2S0HRAIJ Signed-off-by: Robert Marko Tested-by: Luka Kovacic Cc: Luka Perkov Reviewed-by: Jagan Teki --- drivers/mtd/nand/spi/toshiba.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c index 571104a5d94..77c25398fcc 100644 --- a/drivers/mtd/nand/spi/toshiba.c +++ b/drivers/mtd/nand/spi/toshiba.c @@ -127,6 +127,16 @@ static const struct spinand_info toshiba_spinand_table[] = { 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), -- cgit v1.3.1 From 790c1699b2c0ca40809c43b3ddb9fc4a46939d18 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 20 Mar 2020 09:35:31 +0000 Subject: spi: spi-mem: Add SPI_MEM_NO_DATA to the spi_mem_data_dir enum Commit: 0ebb261a0b2d ("spi: spi-mem: Add SPI_MEM_NO_DATA to the spi_mem_data_dir enum") in linux. When defining spi_mem_op templates we don't necessarily know the size that will be passed when the template is actually used, and basing the supports_op() check on op->data.nbytes to know whether there will be data transferred for a specific operation is not possible. Add SPI_MEM_NO_DATA to the spi_mem_data_dir enum so that we can base our checks on op->data.dir instead of op->data.nbytes. This also fixes a bug identified with the atmel-quaspi driver. The spi-nor core, when erasing sectors, fills the spi_mem_op template using SPI_MEM_OP_NO_DATA, which initializes all the data members with value zero. This is wrong because data.dir is treated as SPI_MEM_DATA_IN, which translates in our driver to read accesses for erases (RICR), while the controller expects write accesses (WICR). Signed-off-by: Tudor Ambarus Reviewed-by: Jagan Teki --- drivers/spi/spi-mem.c | 2 +- include/spi-mem.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index e900c997bd7..ffbe20c5b1e 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/include/spi-mem.h b/include/spi-mem.h index 36814efa861..893f7bd7337 100644 --- a/include/spi-mem.h +++ b/include/spi-mem.h @@ -60,10 +60,12 @@ /** * enum spi_mem_data_dir - describes the direction of a SPI memory data * transfer from the controller perspective + * @SPI_MEM_NO_DATA: no data transferred * @SPI_MEM_DATA_IN: data coming from the SPI memory * @SPI_MEM_DATA_OUT: data sent the SPI memory */ enum spi_mem_data_dir { + SPI_MEM_NO_DATA, SPI_MEM_DATA_IN, SPI_MEM_DATA_OUT, }; -- cgit v1.3.1 From 6e7353e3d9929d34c3fc1422503923aedbf6f972 Mon Sep 17 00:00:00 2001 From: Lin Jinhan Date: Tue, 31 Mar 2020 17:39:59 +0800 Subject: rockchip: rng: Add a driver for random number generator(rng) device Add a driver for the rng device found on rockchip platforms. Support rng module of crypto v1 and crypto v2. Signed-off-by: Lin Jinhan Tested-by: Peter Robinson Reviewed-by: Kever Yang --- drivers/rng/Kconfig | 8 ++ drivers/rng/Makefile | 1 + drivers/rng/rockchip_rng.c | 224 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 drivers/rng/rockchip_rng.c (limited to 'drivers') diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index edb6152bb9d..e4b22d79ebc 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 6a8a66779b5..44a00039173 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 00000000000..47fb140077d --- /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 +#include +#include +#include +#include +#include +#include + +#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), +}; -- cgit v1.3.1 From e67cd814ee2d00e1b8651bc1cd889ac6f45ed26b Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 20 Apr 2020 16:03:46 +0530 Subject: spi: sifive: Tidy up dm_spi_slave_platdata variable Usually variable name slave is used for spi_slave structure and slave_plat for the dm_spi_slave_platdata. Let's follow this meaningful notation by replacing slave with slave_plat for dm_spi_slave_platdata structure. Signed-off-by: Jagan Teki Reviewed-by: Bin Meng --- drivers/spi/spi-sifive.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 969bd4b75cb..8f5efb51a37 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -95,25 +95,25 @@ struct sifive_spi { }; 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); @@ -128,7 +128,7 @@ 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) { u32 cr; @@ -141,14 +141,14 @@ 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)) + if ((slave_plat->mode & SPI_TX_QUAD) || (slave_plat->mode & SPI_RX_QUAD)) cr |= SIFIVE_SPI_FMT_PROTO_QUAD; - else if ((slave->mode & SPI_TX_DUAL) || (slave->mode & SPI_RX_DUAL)) + else if ((slave_plat->mode & SPI_TX_DUAL) || (slave_plat->mode & SPI_RX_DUAL)) cr |= SIFIVE_SPI_FMT_PROTO_DUAL; else cr |= SIFIVE_SPI_FMT_PROTO_SINGLE; @@ -191,21 +191,21 @@ static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen, { struct udevice *bus = dev->parent; struct sifive_spi *spi = dev_get_priv(bus); - struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev); + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); const unsigned char *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, true, slave_plat); remaining_len = bitlen / 8; -- cgit v1.3.1 From 5bf3f3dd11db4048d7ad60f2ee210dc50da26051 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 20 Apr 2020 15:36:06 +0530 Subject: mtd: spi-nor: Enable QE bit for ISSI flash Enable QE bit for ISSI flash chips. QE enablement logic is similar to what Macronix has, so reuse the existing code itself. Cc: Sagar Shrikant Kadam Signed-off-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 1 + include/linux/mtd/spi-nor.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 3bf8ddfb9df..e840c60f275 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) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index ec144a08d8f..233fdc341a7 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -22,6 +22,7 @@ #define SNOR_MFR_INTEL CFI_MFR_INTEL #define SNOR_MFR_ST CFI_MFR_ST /* ST Micro <--> Micron */ #define SNOR_MFR_MICRON CFI_MFR_MICRON /* ST Micro <--> Micron */ +#define SNOR_MFR_ISSI CFI_MFR_PMC #define SNOR_MFR_MACRONIX CFI_MFR_MACRONIX #define SNOR_MFR_SPANSION CFI_MFR_AMD #define SNOR_MFR_SST CFI_MFR_SST -- cgit v1.3.1 From a976238de39c6adc34b2505a147c93acc6e27124 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 20 Apr 2020 15:36:07 +0530 Subject: mtd: spi-nor-ids: Enable 4B_OPCODES for is25wp256 IS25WP256 flash chips do support 4byte address opcodes, so enable support for it. Signed-off-by: Jagan Teki Reviewed-by: Sagar Kadam --- drivers/mtd/spi/spi-nor-ids.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 218385f50a1..804ec6307a7 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 */ -- cgit v1.3.1 From 0a08a614b05e8dd199ba15179e2cb8b55a3f8e32 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 20 Apr 2020 23:34:13 +0530 Subject: watchdog: kconfig: Enable designware for rk3399 Enable designware watchdog driver for rk3399 if WDT defined. Cc: Marek Vasut Signed-off-by: Jagan Teki Reviewed-by: Kever Yang --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 6cafd243e04..bf06180cddf 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. -- cgit v1.3.1 From 685465fbba4f502190f9d1ccd28443f5e0e4ec20 Mon Sep 17 00:00:00 2001 From: Kuldeep Singh Date: Fri, 3 Apr 2020 12:27:42 +0530 Subject: mtd: spi-nor-ids: Add Spansion s25fs512s flash entry Spansion "s25fs512s" flash is incorrectly decoded as "s25fl512s" on various platforms as former is not present. Add the entry. Linux already has both the flashes present. A snippet below: { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256...}, { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256...}, Signed-off-by: Kuldeep Singh Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-ids.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 804ec6307a7..e5e71029231 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -195,7 +195,8 @@ const struct flash_info spi_nor_ids[] = { { INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { 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) }, -- cgit v1.3.1 From b7d6e104fbfd54b7ffe9e0a00200e98dd2904a65 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Thu, 23 Apr 2020 22:30:53 +0530 Subject: spi: sifive: Add spi-mem exec op SiFive SPI controller is responsible to handle the slave devices like mmc spi and spi nor flash. The controller is designed such a way that it would handle the slave transactions based on the I/O protocol numbers, example if spi nor slave send quad write opcode it has to send alone with I/O protocol number of 4 and if it try to send data it has to send I/O protocol number along with 4 line data. But the current spi-xfer code from spi-mem is combining the opcode and address in a single transaction, so the SPI controller will be unable to identify the I/O protocol number of opcode vs address. So, add the spi-mem exec_op with spi-xfer of opcode, address and data as a separate transaction. This doesn't remove the .xfer of dm_spi_ops since mmc spi will make use of it. Note: This code might have moved to the spi-mem core area once we have done the dedicated tests on other controllers and have real reason to move. Cc: Vignesh R Signed-off-by: Jagan Teki Tested-by: Sagar Kadam --- drivers/spi/spi-sifive.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 8f5efb51a37..5e612edcff7 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -8,8 +8,9 @@ #include #include +#include #include -#include +#include #include #include #include @@ -241,6 +242,73 @@ 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; + 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; + + /* 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; + + 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; + + 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); @@ -348,11 +416,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[] = { -- cgit v1.3.1 From 622b913ea179645a37dc4fcb75cea6f54d3b505f Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Thu, 23 Apr 2020 22:30:54 +0530 Subject: spi: sifive: Fix format register proto field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SiFive SPI controller has a proto bit field in frame format register which would be used to configure the SPI I/O protocol lines used on specific transfer.  Right now the driver is configuring this proto using slave->mode, for all types of transctions. This makes the driver unable to function since the proto needs to configure dynamically for each and every transaction separately at runtime. Now, the controller driver supports per transfer via spi-mem exec_opo, so add the fmt_proto flag and fill the per transfer buswidth so that the controller configures the proto bit at runtime. This patch fixes the SPI controller works with SPI NOR flash on quad read with page program. Cc: Vignesh R Signed-off-by: Jagan Teki Tested-by: Sagar Kadam --- drivers/spi/spi-sifive.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 5e612edcff7..0ea4930a0a3 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -86,6 +86,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; @@ -93,6 +98,7 @@ 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, @@ -147,12 +153,17 @@ static void sifive_spi_prep_transfer(struct sifive_spi *spi, /* Number of wires ? */ cr &= ~SIFIVE_SPI_FMT_PROTO_MASK; - if ((slave_plat->mode & SPI_TX_QUAD) || (slave_plat->mode & SPI_RX_QUAD)) + switch (spi->fmt_proto) { + case SIFIVE_SPI_PROTO_QUAD: cr |= SIFIVE_SPI_FMT_PROTO_QUAD; - else if ((slave_plat->mode & SPI_TX_DUAL) || (slave_plat->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; @@ -246,6 +257,7 @@ 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; @@ -257,6 +269,8 @@ static int sifive_spi_exec_op(struct spi_slave *slave, 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) { @@ -284,6 +298,8 @@ static int sifive_spi_exec_op(struct spi_slave *slave, 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"); @@ -298,6 +314,8 @@ static int sifive_spi_exec_op(struct spi_slave *slave, 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) { -- cgit v1.3.1 From 25e4d94f45611bfc5f1ff71cf29a8d41bb6e9e9f Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Thu, 23 Apr 2020 22:30:55 +0530 Subject: spi: sifive: Fix QPP transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The guessed reason is that the existing logic of filling tx fifo with data, rx fifo with NULL for tx transfer and filling rx fifo with data, tx fifo with NULL for rx transfer is not clear enough to support the Quad Page Program.     SiFive SPI controllers have specific sets of watermark registers and SPI I/O directions bits in order to program SPI controllers clear enough to support all sets of operating modes.     Here is the exact programing sequence that would follow on this patch and tested via SPI-NOR and MMC_SPI.     - set the frame format proto, endian - set the frame format dir, set it for tx and clear it for rx - TX transfer:   fill tx fifo with data.   wait for TX watermark bit to clear. - RX transfer:   fill tx fifo with 0xff.   write nbytes to rx watermark register   wait for rx watermark bit to clear.   read the rx fifo data. So, this patch adopts this program sequence and fixes the existing I/O direction bit. Cc: Vignesh R Signed-off-by: Jagan Teki Tested-by: Sagar Kadam --- drivers/spi/spi-sifive.c | 57 +++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 0ea4930a0a3..4cab0391f7d 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -134,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_plat) + struct dm_spi_slave_platdata *slave_plat, + u8 *rx_ptr) { u32 cr; @@ -167,7 +168,7 @@ static void sifive_spi_prep_transfer(struct sifive_spi *spi, /* 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); @@ -198,13 +199,19 @@ 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_plat = dev_get_parent_platdata(dev); - const unsigned char *tx_ptr = dout; + const u8 *tx_ptr = dout; u8 *rx_ptr = din; u32 remaining_len; int ret; @@ -217,31 +224,37 @@ static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen, return ret; } - sifive_spi_prep_transfer(spi, true, slave_plat); + 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; @@ -395,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); -- cgit v1.3.1 From 96993d7c358e9d87871a3c92fb3af081b2e3ff48 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Tue, 28 Apr 2020 15:30:16 +0530 Subject: clk: rk3399: Set empty for HCLK_SD assigned-clocks Due to v5.7-rc1 sync the SD controller nodes in rk3399.dtsi have HCLK_SD assigned-clocks which are usually required for Linux and don't require to handle them in U-Boot. assigned-clocks = <&cru HCLK_SD>; So, mark them as empty in clock otherwise device probe on those SD controllers would fail. Signed-off-by: Jagan Teki Reviewed-by: Kever Yang --- drivers/clk/rockchip/clk_rk3399.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 1f623765956..d822acace14 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. -- cgit v1.3.1 From 635a76b703f3bd5b20e28bfc86caee9889f536c2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 18 Apr 2020 01:44:12 +0200 Subject: net: pcnet: Remove CONFIG_PCNET_79C97x These macros guard one switch-case statement, which grows mips malta by some 20 bytes if debug is enabled, and even less if it is not. To make the code simpler, just support all the NICs and be done with it. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/pcnet.c | 8 -------- include/configs/malta.h | 1 - scripts/config_whitelist.txt | 2 -- 3 files changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index b4ad11d3fa5..59241c95bcd 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. @@ -254,16 +250,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); diff --git a/include/configs/malta.h b/include/configs/malta.h index bb8a44433eb..d41b80c7dc2 100644 --- a/include/configs/malta.h +++ b/include/configs/malta.h @@ -16,7 +16,6 @@ #define CONFIG_PCI_GT64120 #define CONFIG_PCI_MSC01 #define CONFIG_PCNET -#define CONFIG_PCNET_79C973 #define PCNET_HAS_PROM #define CONFIG_SYS_ISA_IO_BASE_ADDRESS 0 diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 12a6698958e..27125d7b8af 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1292,8 +1292,6 @@ CONFIG_PCI_SYS_BUS CONFIG_PCI_SYS_PHYS CONFIG_PCI_SYS_SIZE CONFIG_PCNET -CONFIG_PCNET_79C973 -CONFIG_PCNET_79C975 CONFIG_PEN_ADDR_BIG_ENDIAN CONFIG_PERIF1_FREQ CONFIG_PERIF2_FREQ -- cgit v1.3.1 From 171f5e580e3388090d589aa4c0f123576948ab52 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 18 Apr 2020 01:56:51 +0200 Subject: net: tulip: Remove CONFIG_TULIP_* These macros are not used by any board, remove them to simplify the driver. The EEPROM accessors are still retained however, as those might still be useful. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- README | 2 - drivers/net/dc2114x.c | 88 +++----------------------------------------- scripts/config_whitelist.txt | 3 -- 3 files changed, 5 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/README b/README index 08348506765..2e8ad3bc0cb 100644 --- a/README +++ b/README @@ -896,8 +896,6 @@ The following options need to be configured: CONFIG_TULIP Support for Digital 2114x chips. - Optional CONFIG_TULIP_SELECT_MEDIA for board specific - modem chip initialisation (KS8761/QS6611). CONFIG_NATSEMI Support for National dp83815 chips. diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 43c2253f10d..40bfc5281b2 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -77,15 +77,6 @@ #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);\ -} -#else #define RESET_DE4X5(dev) {\ int i;\ i=INL(dev, DE4X5_BMR);\ @@ -97,7 +88,6 @@ for (i=0;i<5;i++) {INL(dev, DE4X5_BMR); udelay(10000);}\ udelay(1000);\ } -#endif #define START_DE4X5(dev) {\ s32 omr; \ @@ -114,11 +104,7 @@ } #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 @@ -140,29 +126,22 @@ static int tx_new; /* TX descriptor ring pointer */ static char rxRingSize; static char txRingSize; -#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) @@ -183,9 +162,6 @@ static void OUTL(struct eth_device* dev, int command, u_long addr) 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 { } }; @@ -209,35 +185,22 @@ int dc21x4x_initialize(bd_t *bis) /* 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"); @@ -251,15 +214,9 @@ int dc21x4x_initialize(bd_t *bis) 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); @@ -270,17 +227,9 @@ int dc21x4x_initialize(bd_t *bis) } 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; @@ -292,9 +241,8 @@ int dc21x4x_initialize(bd_t *bis) udelay(10 * 1000); -#ifndef CONFIG_TULIP_FIX_DAVICOM read_hw_addr(dev, bis); -#endif + eth_register(dev); card_number++; @@ -311,46 +259,28 @@ static int dc21x4x_init(struct eth_device* dev, bd_t* bis) /* 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; @@ -520,9 +450,7 @@ Done: return; } -#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM) -/* SROM Read and write routines. - */ +/* SROM Read and write routines. */ static void sendto_srom(struct eth_device* dev, u_int command, u_long addr) { @@ -594,13 +522,12 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, i 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) { unsigned retval = 0; @@ -636,9 +563,7 @@ static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, int cmd 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; @@ -647,7 +572,6 @@ static int read_srom(struct eth_device *dev, u_long ioaddr, int index) (((SROM_READ_CMD << ee_addr_size) | index) << 16) | 0xffff, 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) @@ -695,7 +619,6 @@ static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_ } #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]); @@ -721,7 +644,6 @@ Done: #endif return; } -#endif /* CONFIG_TULIP_FIX_DAVICOM */ #ifdef UPDATE_SROM static void update_srom(struct eth_device *dev, bd_t *bis) diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 27125d7b8af..9b9f7df8c42 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -4076,9 +4076,6 @@ CONFIG_TSECV2_1 CONFIG_TSEC_TBI CONFIG_TSEC_TBICR_SETTINGS CONFIG_TULIP -CONFIG_TULIP_FIX_DAVICOM -CONFIG_TULIP_SELECT_MEDIA -CONFIG_TULIP_USE_IO CONFIG_TWL6030_INPUT CONFIG_TWL6030_POWER CONFIG_TWR -- cgit v1.3.1 From 3c0bcb97d6d7ed7f9b4c46eb2a6dd0e910214faf Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 18 Apr 2020 02:32:19 +0200 Subject: net: pcnet: Replace mips-specific accessors Replace mips-specific UNCACHED_SDRAM() macro with standard map_physmem(), which permits the driver to work on other systems than mips. Signed-off-by: Marek Vasut Cc: Daniel Schwierzeck Cc: Joe Hershberger --- drivers/net/pcnet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 59241c95bcd..e7d6c8d714c 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -332,7 +332,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, -- cgit v1.3.1 From 69529c912059ed4585f648cc6cde1a2fbd5b722b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 18 Apr 2020 05:11:05 +0200 Subject: net: pcnet: Switch to PCI memory access Replace the PCI IO access with PCI memory access, the card supports both, but the former does not work with QEMU SH4. Signed-off-by: Marek Vasut Cc: Daniel Schwierzeck Cc: Joe Hershberger --- drivers/net/pcnet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index e7d6c8d714c..34a5a16cfe8 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -179,14 +179,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) { -- cgit v1.3.1 From ca5cb04b7fef31d66461cb58872d9ea32a24628b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:09:47 +0200 Subject: net: dc2114x: Clean up init code Clean up the driver init code to bring it up to standards with U-Boot coding style, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 66 +++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 40bfc5281b2..d302d0362a9 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -167,33 +167,30 @@ static struct pci_device_id supported[] = { int dc21x4x_initialize(bd_t *bis) { - 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) { + 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 ) { + 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; + status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; pci_write_config_word(devbusfn, PCI_COMMAND, status); pci_read_config_word(devbusfn, PCI_COMMAND, &status); @@ -211,30 +208,31 @@ int dc21x4x_initialize(bd_t *bis) pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer); if (timer < 0x60) { - pci_write_config_byte(devbusfn, PCI_LATENCY_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); + 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; + 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); @@ -251,10 +249,10 @@ int dc21x4x_initialize(bd_t *bis) return card_number; } -static int dc21x4x_init(struct eth_device* dev, bd_t* bis) +static int dc21x4x_init(struct eth_device *dev, bd_t *bis) { - int i; - int devbusfn = (int) dev->priv; + int i; + int devbusfn = (int)dev->priv; /* Ensure we're not sleeping. */ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP); @@ -271,12 +269,12 @@ static int dc21x4x_init(struct eth_device* dev, bd_t* bis) 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].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++) { + for (i = 0; i < NUM_TX_DESC; i++) { tx_ring[i].status = 0; tx_ring[i].des1 = 0; tx_ring[i].buf = 0; @@ -291,8 +289,8 @@ static int dc21x4x_init(struct eth_device* dev, bd_t* bis) 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); + OUTL(dev, phys_to_bus((u32)&rx_ring), DE4X5_RRBA); + OUTL(dev, phys_to_bus((u32)&tx_ring), DE4X5_TRBA); START_DE4X5(dev); -- cgit v1.3.1 From 7c53e3364e4dc7dc4752a75f18a3d72548098365 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:10:14 +0200 Subject: net: dc2114x: Clean up dc21x4x_send() Clean up the driver send code to bring it up to standards with U-Boot coding style, invert the loops where applicable to cut down the level of indent. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index d302d0362a9..11ebea9c1a6 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -304,47 +304,45 @@ static int dc21x4x_init(struct eth_device *dev, bd_t *bis) static int dc21x4x_send(struct eth_device *dev, void *packet, int length) { - int status = -1; - int i; + int status = -1; + int i; if (length <= 0) { printf("%s: bad packet size: %d\n", dev->name, length); - goto Done; + 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; - } + 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].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; - } + 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) { -#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; + goto done; } status = length; - Done: - tx_new = (tx_new+1) % NUM_TX_DESC; +done: + tx_new = (tx_new + 1) % NUM_TX_DESC; return status; } -- cgit v1.3.1 From 9308df81a206e73687a8ba7a1f1b3753e2f2fd79 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:10:25 +0200 Subject: net: dc2114x: Clean up dc21x4x_recv() Clean up the driver recv code to bring it up to standards with U-Boot coding style. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 11ebea9c1a6..4d2e11672e1 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -346,46 +346,40 @@ done: return status; } -static int dc21x4x_recv(struct eth_device* dev) +static int dc21x4x_recv(struct eth_device *dev) { - s32 status; - int length = 0; + int length = 0; + u32 status; - for ( ; ; ) { - status = (s32)le32_to_cpu(rx_ring[rx_new].status); + while (true) { + status = le32_to_cpu(rx_ring[rx_new].status); - if (status & R_OWN) { + if (status & R_OWN) break; - } if (status & RD_LS) { - /* Valid frame status. - */ + /* Valid frame status. */ if (status & RD_ES) { - - /* There was an error. - */ + /* 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); + /* 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. + /* + * Change buffer ownership for this frame, + * back to the adapter. */ rx_ring[rx_new].status = cpu_to_le32(R_OWN); } - /* Update entry information. - */ + /* Update entry information. */ rx_new = (rx_new + 1) % rxRingSize; } -- cgit v1.3.1 From 5b4e7dfb879c4b127f27bd92bac68e114d5e0b70 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:10:30 +0200 Subject: net: dc2114x: Clean up dc21x4x_halt() Clean up the driver halt code to bring it up to standards with U-Boot coding style. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 4d2e11672e1..6fe05113cae 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -386,9 +386,9 @@ static int dc21x4x_recv(struct eth_device *dev) return length; } -static void dc21x4x_halt(struct eth_device* dev) +static void dc21x4x_halt(struct eth_device *dev) { - int devbusfn = (int) dev->priv; + int devbusfn = (int)dev->priv; STOP_DE4X5(dev); OUTL(dev, 0, DE4X5_SICR); -- cgit v1.3.1 From 5a0c332a8a6fee7deadda5c8439782aa5f7b9ca2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:10:50 +0200 Subject: net: dc2114x: Clean up send_setup_frame() Clean up the send_setup_frame() to bring it up to standards with U-Boot coding style, invert the loops where applicable to cut down the level of indent. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 6fe05113cae..bd64c75af4c 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -396,48 +396,48 @@ static void dc21x4x_halt(struct eth_device *dev) pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP); } -static void send_setup_frame(struct eth_device* dev, bd_t *bis) +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]; + 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) { + 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; - } + 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].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; - } + 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)); + 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; + tx_new = (tx_new + 1) % NUM_TX_DESC; } /* SROM Read and write routines. */ -- cgit v1.3.1 From 2e5c2a103edeed19bfbf393e8550a7bd77e62dfa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:11:06 +0200 Subject: net: dc2114x: Clean up SROM operations Clean up the SROM accessors to bring them up to standards with U-Boot coding style. Sort variable into reverse xmas tree. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 117 +++++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index bd64c75af4c..b375906e27d 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -441,30 +441,27 @@ static void send_setup_frame(struct eth_device *dev, bd_t *bis) } /* SROM Read and write routines. */ -static void -sendto_srom(struct eth_device* dev, u_int command, u_long addr) +static void sendto_srom(struct eth_device *dev, u_int command, u_long addr) { 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; + s32 tmp = 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); @@ -476,14 +473,18 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, i /* 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); + retval = (retval << 1) | + !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); } sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); @@ -498,7 +499,8 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, i #ifdef DEBUG_SROM2 printf("%X", getfrom_srom(dev, ioaddr) & 15); #endif - retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0); + retval = (retval << 1) | + !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); udelay(10); } @@ -518,34 +520,38 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, i * enable. It returns the data output from the EEPROM, and thus may * also be used for reads. */ -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 - 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); + printf("%X", getfrom_srom(dev, ioaddr) & 15); #endif - 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); @@ -556,21 +562,26 @@ static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, int cmd 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); } #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; + + udelay(10 * 1000); /* test-only */ #ifdef DEBUG_SROM printf("ee_addr_size=%d.\n", ee_addr_size); @@ -578,33 +589,37 @@ static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_ #endif /* 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<> 1); i++) { - tmp = read_srom(dev, DE4X5_APROM, ((SROM_HWADD >> 1) + i)); + tmp = read_srom(dev, DE4X5_APROM, (SROM_HWADD >> 1) + i); *p = le16_to_cpu(tmp); j += *p++; } - 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: + 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); + update_srom(dev, bis); #endif - return; + } } #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 */ @@ -658,16 +666,17 @@ 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 */ +#endif /* UPDATE_SROM */ -- cgit v1.3.1 From eb216f1e0005ea1b3e125efeb32d72d1691eea2d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:09:26 +0200 Subject: net: dc2114x: Clean up remaining driver code Clean up the remaining driver code, macro space alignment, function declaration indent, replace __attribute__((aligned(32))) with plain __aligned(32). No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 86 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index b375906e27d..007e4cecb69 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -12,19 +12,17 @@ #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 +32,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 +42,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 +59,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 */ @@ -79,13 +75,13 @@ #define RESET_DE4X5(dev) {\ int i;\ - i=INL(dev, DE4X5_BMR);\ + 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);}\ + for (i = 0; i < 5; i++) {INL(dev, DE4X5_BMR); udelay(10000); } \ udelay(1000);\ } @@ -99,7 +95,7 @@ #define STOP_DE4X5(dev) {\ s32 omr; \ omr = INL(dev, DE4X5_OMR);\ - omr &= ~(OMR_ST|OMR_SR);\ + omr &= ~(OMR_ST | OMR_SR);\ OUTL(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ \ } @@ -118,30 +114,34 @@ 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 */ - -static char rxRingSize; -static char txRingSize; - -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); +/* 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 rx_ring_size; +static char tx_ring_size; + +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); #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); static void update_srom(struct eth_device *dev, bd_t *bis); #endif 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); -static void send_setup_frame(struct eth_device* dev, bd_t * bis); +static void read_hw_addr(struct eth_device *dev, bd_t *bis); +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_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); +static int dc21x4x_recv(struct eth_device *dev); +static void dc21x4x_halt(struct eth_device *dev); #if defined(CONFIG_E500) #define phys_to_bus(a) (a) @@ -149,12 +149,12 @@ static void dc21x4x_halt(struct eth_device* dev); #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 int INL(struct eth_device *dev, u_long addr) { return le32_to_cpu(*(volatile u_long *)(addr + dev->iobase)); } -static void OUTL(struct eth_device* dev, int command, u_long addr) +static void OUTL(struct eth_device *dev, int command, u_long addr) { *(volatile u_long *)(addr + dev->iobase) = cpu_to_le32(command); } @@ -281,12 +281,12 @@ static int dc21x4x_init(struct eth_device *dev, bd_t *bis) tx_ring[i].next = 0; } - rxRingSize = NUM_RX_DESC; - txRingSize = NUM_TX_DESC; + rx_ring_size = NUM_RX_DESC; + tx_ring_size = 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); + 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. */ OUTL(dev, phys_to_bus((u32)&rx_ring), DE4X5_RRBA); @@ -380,7 +380,7 @@ static int dc21x4x_recv(struct eth_device *dev) } /* Update entry information. */ - rx_new = (rx_new + 1) % rxRingSize; + rx_new = (rx_new + 1) % rx_ring_size; } return length; -- cgit v1.3.1 From 04da06120909729bc9d0d3974d06dc2ef758e821 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:36:46 +0200 Subject: net: dc2114x: Clean up DE4X5 macros Replace these macros with static functions to permit the compiler to do type checking on the functions. The INL()/OUTL() functions have to be moved in this patch as well, as those DE4X5 macros are using them. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 89 +++++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 007e4cecb69..a85fb76d53c 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -73,30 +73,57 @@ #define POLL_DEMAND 1 -#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);\ +#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) +{ + return le32_to_cpu(*(volatile u_long *)(addr + dev->iobase)); +} + +static void OUTL(struct eth_device *dev, int command, u_long addr) +{ + *(volatile u_long *)(addr + dev->iobase) = cpu_to_le32(command); +} + +static void reset_de4x5(struct eth_device *dev) +{ + int i; + + i = INL(dev, DE4X5_BMR); + mdelay(1); + OUTL(dev, i | BMR_SWR, DE4X5_BMR); + mdelay(1); + OUTL(dev, i, DE4X5_BMR); + mdelay(1); + + for (i = 0; i < 5; i++) { + INL(dev, DE4X5_BMR); + mdelay(10); + } + + mdelay(1); } -#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 */\ +static void start_de4x5(struct eth_device *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 */ \ +static void stop_de4x5(struct eth_device *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 @@ -143,22 +170,6 @@ 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); -#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) -{ - return le32_to_cpu(*(volatile u_long *)(addr + dev->iobase)); -} - -static void OUTL(struct eth_device *dev, int command, u_long addr) -{ - *(volatile u_long *)(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 }, @@ -257,7 +268,7 @@ static int dc21x4x_init(struct eth_device *dev, bd_t *bis) /* Ensure we're not sleeping. */ pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP); - RESET_DE4X5(dev); + reset_de4x5(dev); if ((INL(dev, DE4X5_STS) & (STS_TS | STS_RS)) != 0) { printf("Error: Cannot reset ethernet controller.\n"); @@ -292,7 +303,7 @@ static int dc21x4x_init(struct eth_device *dev, bd_t *bis) OUTL(dev, phys_to_bus((u32)&rx_ring), DE4X5_RRBA); OUTL(dev, phys_to_bus((u32)&tx_ring), DE4X5_TRBA); - START_DE4X5(dev); + start_de4x5(dev); tx_new = 0; rx_new = 0; @@ -390,7 +401,7 @@ static void dc21x4x_halt(struct eth_device *dev) { int devbusfn = (int)dev->priv; - STOP_DE4X5(dev); + stop_de4x5(dev); OUTL(dev, 0, DE4X5_SICR); pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP); -- cgit v1.3.1 From 3b7b9e2e71e7334198d696a03f3552bbc812ce9b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 03:40:03 +0200 Subject: net: dc2114x: Clean up INL/OUTL functions Rename these functions to dc2114x_{inl,outl}(), use u32 values in them instead of plain signed integers as all those values are in fact register values and the driver code does bitwise operations on them. No functional change intended. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index a85fb76d53c..2bbe4e5d602 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -79,29 +79,29 @@ #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 void reset_de4x5(struct eth_device *dev) { - int i; + u32 i; - i = INL(dev, DE4X5_BMR); + i = dc2114x_inl(dev, DE4X5_BMR); mdelay(1); - OUTL(dev, i | BMR_SWR, DE4X5_BMR); + dc2114x_outl(dev, i | BMR_SWR, DE4X5_BMR); mdelay(1); - OUTL(dev, i, DE4X5_BMR); + dc2114x_outl(dev, i, DE4X5_BMR); mdelay(1); for (i = 0; i < 5; i++) { - INL(dev, DE4X5_BMR); + dc2114x_inl(dev, DE4X5_BMR); mdelay(10); } @@ -110,20 +110,20 @@ static void reset_de4x5(struct eth_device *dev) static void start_de4x5(struct eth_device *dev) { - s32 omr; + u32 omr; - omr = INL(dev, DE4X5_OMR); + omr = dc2114x_inl(dev, DE4X5_OMR); omr |= OMR_ST | OMR_SR; - OUTL(dev, omr, DE4X5_OMR); /* Enable the TX and/or RX */ + dc2114x_outl(dev, omr, DE4X5_OMR); /* Enable the TX and/or RX */ } static void stop_de4x5(struct eth_device *dev) { - s32 omr; + u32 omr; - omr = INL(dev, DE4X5_OMR); + omr = dc2114x_inl(dev, DE4X5_OMR); omr &= ~(OMR_ST | OMR_SR); - OUTL(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ + dc2114x_outl(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ } #define NUM_RX_DESC PKTBUFSRX @@ -270,12 +270,12 @@ static int dc21x4x_init(struct eth_device *dev, bd_t *bis) reset_de4x5(dev); - if ((INL(dev, DE4X5_STS) & (STS_TS | STS_RS)) != 0) { + if (dc2114x_inl(dev, DE4X5_STS) & (STS_TS | STS_RS)) { printf("Error: Cannot reset ethernet controller.\n"); return -1; } - OUTL(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); + 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); @@ -300,8 +300,8 @@ static int dc21x4x_init(struct eth_device *dev, bd_t *bis) tx_ring[tx_ring_size - 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); + 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); @@ -335,7 +335,7 @@ static int dc21x4x_send(struct eth_device *dev, void *packet, int length) 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); + 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) @@ -402,7 +402,7 @@ static void dc21x4x_halt(struct eth_device *dev) int devbusfn = (int)dev->priv; stop_de4x5(dev); - OUTL(dev, 0, DE4X5_SICR); + dc2114x_outl(dev, 0, DE4X5_SICR); pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP); } @@ -433,7 +433,7 @@ static void send_setup_frame(struct eth_device *dev, bd_t *bis) 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); + 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) @@ -454,13 +454,13 @@ static void send_setup_frame(struct eth_device *dev, bd_t *bis) /* 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) { - s32 tmp = INL(dev, addr); + u32 tmp = dc2114x_inl(dev, addr); udelay(1); return tmp; -- cgit v1.3.1 From dbe9c0c1457dad8446f1d9aac5f4cbd4ee6db060 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 04:00:49 +0200 Subject: net: dc2114x: Reorganize driver Move the functions in the driver around to better fit future DM conversion, drop function forward declarations. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 736 ++++++++++++++++++++++++-------------------------- 1 file changed, 357 insertions(+), 379 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 2bbe4e5d602..9de9634cd51 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -79,6 +79,30 @@ #define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a) #endif +#define NUM_RX_DESC PKTBUFSRX +#define NUM_TX_DESC 1 /* Number of TX descriptors */ +#define RX_BUFF_SZ PKTSIZE_ALIGN + +#define TOUT_LOOP 1000000 + +#define SETUP_FRAME_LEN 192 + +struct de4x5_desc { + volatile s32 status; + u32 des1; + u32 buf; + u32 next; +}; + +/* 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 rx_ring_size; +static char tx_ring_size; + static u32 dc2114x_inl(struct eth_device *dev, u32 addr) { return le32_to_cpu(*(volatile u32 *)(addr + dev->iobase)); @@ -126,191 +150,267 @@ static void stop_de4x5(struct eth_device *dev) dc2114x_outl(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ } -#define NUM_RX_DESC PKTBUFSRX -#define NUM_TX_DESC 1 /* Number of TX descriptors */ -#define RX_BUFF_SZ PKTSIZE_ALIGN - -#define TOUT_LOOP 1000000 +/* SROM Read and write routines. */ +static void sendto_srom(struct eth_device *dev, u_int command, u_long addr) +{ + dc2114x_outl(dev, command, addr); + udelay(1); +} -#define SETUP_FRAME_LEN 192 +static int getfrom_srom(struct eth_device *dev, u_long addr) +{ + u32 tmp = dc2114x_inl(dev, addr); -struct de4x5_desc { - volatile s32 status; - u32 des1; - u32 buf; - u32 next; -}; + udelay(1); + return tmp; +} -/* 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 */ +/* 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) +{ + int read_cmd = location | (SROM_READ_CMD << addr_len); + unsigned int retval = 0; + int i; -static char rx_ring_size; -static char tx_ring_size; + sendto_srom(dev, SROM_RD | SROM_SR, ioaddr); + sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); -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); -#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); +#ifdef DEBUG_SROM + printf(" EEPROM read at %d ", location); #endif -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); -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); + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; -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 }, - { } -}; + 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); + udelay(10); +#ifdef DEBUG_SROM2 + printf("%X", getfrom_srom(dev, ioaddr) & 15); +#endif + retval = (retval << 1) | + !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); + } -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; + sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); - while (1) { - devbusfn = pci_find_devices(supported, idx++); - if (devbusfn == -1) - break; +#ifdef DEBUG_SROM2 + printf(" :%X:", getfrom_srom(dev, ioaddr) & 15); +#endif - /* Get the chip configuration revision register. */ - pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv); + 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); + sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); + udelay(10); + } - if ((cfrv & CFRV_RN) < DC2114x_BRK) { - printf("Error: The chip is not DC21143.\n"); - continue; - } + /* Terminate the EEPROM access. */ + sendto_srom(dev, SROM_RD | SROM_SR, ioaddr); - pci_read_config_word(devbusfn, PCI_COMMAND, &status); - status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - pci_write_config_word(devbusfn, PCI_COMMAND, status); +#ifdef DEBUG_SROM2 + printf(" EEPROM value at %d is %5.5x.\n", location, retval); +#endif - pci_read_config_word(devbusfn, PCI_COMMAND, &status); - if (!(status & PCI_COMMAND_MEMORY)) { - printf("Error: Can not enable MEMORY access.\n"); - continue; - } + return retval; +} - if (!(status & PCI_COMMAND_MASTER)) { - printf("Error: Can not enable Bus Mastering.\n"); - continue; - } +/* + * 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. + */ +static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, + int cmd_len) +{ + unsigned int retval = 0; - /* Check the latency timer for values >= 0x60. */ - pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer); +#ifdef DEBUG_SROM + printf(" EEPROM op 0x%x: ", cmd); +#endif - if (timer < 0x60) { - pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, - 0x60); - } + sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr); - /* 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); + /* Shift the command bits out. */ + do { + short dataval = (cmd & BIT(cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; - dev = (struct eth_device *)malloc(sizeof(*dev)); - if (!dev) { - printf("Can not allocalte memory of dc21x4x\n"); - break; - } + sendto_srom(dev, dataval, ioaddr); + udelay(10); - memset(dev, 0, sizeof(*dev)); +#ifdef DEBUG_SROM2 + printf("%X", getfrom_srom(dev, ioaddr) & 15); +#endif - sprintf(dev->name, "dc21x4x#%d", card_number); + sendto_srom(dev, dataval | DT_CLK, ioaddr); + udelay(10); + retval = (retval << 1) | + !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); + } while (--cmd_len >= 0); - 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; + sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); - /* Ensure we're not sleeping. */ - pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP); + /* Terminate the EEPROM access. */ + sendto_srom(dev, SROM_RD | SROM_SR, ioaddr); - udelay(10 * 1000); +#ifdef DEBUG_SROM + printf(" EEPROM result is 0x%5.5x.\n", retval); +#endif - read_hw_addr(dev, bis); + return retval; +} - eth_register(dev); +static int read_srom(struct eth_device *dev, u_long ioaddr, int index) +{ + int ee_addr_size; - card_number++; - } + ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6; - return card_number; + return do_eeprom_cmd(dev, ioaddr, 0xffff | + (((SROM_READ_CMD << ee_addr_size) | index) << 16), + 3 + ee_addr_size + 16); } -static int dc21x4x_init(struct eth_device *dev, bd_t *bis) +#ifdef UPDATE_SROM +static int write_srom(struct eth_device *dev, u_long ioaddr, int index, + int new_value) { + unsigned short newval; + int ee_addr_size; int i; - int devbusfn = (int)dev->priv; - /* Ensure we're not sleeping. */ - pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP); + ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6; - reset_de4x5(dev); + udelay(10 * 1000); /* test-only */ - if (dc2114x_inl(dev, DE4X5_STS) & (STS_TS | STS_RS)) { - printf("Error: Cannot reset ethernet controller.\n"); - return -1; - } +#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 - dc2114x_outl(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); + /* Enable programming modes. */ + do_eeprom_cmd(dev, ioaddr, 0x4f << (ee_addr_size - 4), + 3 + ee_addr_size); - 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; + /* Do the actual write. */ + 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 */ + if (getfrom_srom(dev, ioaddr) & EE_DATA_READ) + break; } - 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; +#ifdef DEBUG_SROM + printf(" Write finished after %d ticks.\n", i); +#endif + + /* Disable programming. */ + 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) + | 0xffff, 3 + ee_addr_size + 16); +#ifdef DEBUG_SROM + printf(" New value at offset %d is %4.4x.\n", index, newval); +#endif + + return 1; +} + +static void update_srom(struct eth_device *dev, bd_t *bis) +{ + static unsigned short eeprom[0x40] = { + 0x140b, 0x6610, 0x0000, 0x0000, /* 00 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 04 */ + 0x00a3, 0x0103, 0x0000, 0x0000, /* 08 */ + 0x0000, 0x1f00, 0x0000, 0x0000, /* 0c */ + 0x0108, 0x038d, 0x0000, 0x0000, /* 10 */ + 0xe078, 0x0001, 0x0040, 0x0018, /* 14 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 18 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 1c */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 20 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 2c */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 34 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 38 */ + 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++) + 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; } - rx_ring_size = NUM_RX_DESC; - tx_ring_size = NUM_TX_DESC; + for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + if (i < TOUT_LOOP) + continue; - /* 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); + printf("%s: tx error buffer not ready\n", dev->name); + return; + } - /* 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); + 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); - start_de4x5(dev); + dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD); - tx_new = 0; - rx_new = 0; + for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + if (i < TOUT_LOOP) + continue; - send_setup_frame(dev, bis); + printf("%s: tx buffer not ready\n", dev->name); + return; + } - return 0; + 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) @@ -397,297 +497,175 @@ static int dc21x4x_recv(struct eth_device *dev) return length; } -static void dc21x4x_halt(struct eth_device *dev) +static int dc21x4x_init(struct eth_device *dev, bd_t *bis) { + int i; int devbusfn = (int)dev->priv; - stop_de4x5(dev); - dc2114x_outl(dev, 0, DE4X5_SICR); + /* Ensure we're not sleeping. */ + pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP); - pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP); -} + reset_de4x5(dev); -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; + if (dc2114x_inl(dev, DE4X5_STS) & (STS_TS | STS_RS)) { + printf("Error: Cannot reset ethernet controller.\n"); + return -1; + } - memset(pa, 0xff, SETUP_FRAME_LEN); + dc2114x_outl(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); - for (i = 0; i < ETH_ALEN; i++) { - *(pa + (i & 1)) = dev->enetaddr[i]; - if (i & 0x01) - pa += 4; + 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; 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; + 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; } - 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); + rx_ring_size = NUM_RX_DESC; + tx_ring_size = NUM_TX_DESC; - dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD); + /* 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); - for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { - if (i < TOUT_LOOP) - continue; + /* 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); - printf("%s: tx buffer not ready\n", dev->name); - return; - } + start_de4x5(dev); - 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 = 0; + rx_new = 0; - tx_new = (tx_new + 1) % NUM_TX_DESC; -} + send_setup_frame(dev, bis); -/* SROM Read and write routines. */ -static void sendto_srom(struct eth_device *dev, u_int command, u_long addr) -{ - dc2114x_outl(dev, command, addr); - udelay(1); + return 0; } -static int getfrom_srom(struct eth_device *dev, u_long addr) +static void dc21x4x_halt(struct eth_device *dev) { - u32 tmp = dc2114x_inl(dev, addr); + int devbusfn = (int)dev->priv; - udelay(1); - return tmp; + stop_de4x5(dev); + dc2114x_outl(dev, 0, DE4X5_SICR); + + pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP); } -/* 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 void read_hw_addr(struct eth_device *dev, bd_t *bis) { - 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 - - /* Shift the read command bits out. */ - for (i = 4 + addr_len; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + u_short tmp, *p = (u_short *)(&dev->enetaddr[0]); + int i, j = 0; - 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); - udelay(10); -#ifdef DEBUG_SROM2 - printf("%X", getfrom_srom(dev, ioaddr) & 15); -#endif - retval = (retval << 1) | - !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); + 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++; } - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); - -#ifdef DEBUG_SROM2 - printf(" :%X:", getfrom_srom(dev, ioaddr) & 15); -#endif - - 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); + 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 - retval = (retval << 1) | - !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); - udelay(10); } - - /* 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 - - return retval; } -/* - * 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. - */ -static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, - int cmd_len) -{ - unsigned int retval = 0; - -#ifdef DEBUG_SROM - printf(" EEPROM op 0x%x: ", cmd); -#endif - - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr); - - /* Shift the command bits out. */ - do { - 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 - - sendto_srom(dev, dataval | DT_CLK, ioaddr); - udelay(10); - retval = (retval << 1) | - !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); - } while (--cmd_len >= 0); - - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); - - /* Terminate the EEPROM access. */ - sendto_srom(dev, SROM_RD | SROM_SR, ioaddr); - -#ifdef DEBUG_SROM - printf(" EEPROM result is 0x%5.5x.\n", retval); -#endif - - return retval; -} +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 }, + { } +}; -static int read_srom(struct eth_device *dev, u_long ioaddr, int index) +int dc21x4x_initialize(bd_t *bis) { - int ee_addr_size; - - ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6; + 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; - return do_eeprom_cmd(dev, ioaddr, 0xffff | - (((SROM_READ_CMD << ee_addr_size) | index) << 16), - 3 + ee_addr_size + 16); -} + while (1) { + devbusfn = pci_find_devices(supported, idx++); + if (devbusfn == -1) + break; -#ifdef UPDATE_SROM -static int write_srom(struct eth_device *dev, u_long ioaddr, int index, - int new_value) -{ - unsigned short newval; - int ee_addr_size; - int i; + /* Get the chip configuration revision register. */ + pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv); - ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6; + if ((cfrv & CFRV_RN) < DC2114x_BRK) { + printf("Error: The chip is not DC21143.\n"); + continue; + } - udelay(10 * 1000); /* test-only */ + pci_read_config_word(devbusfn, PCI_COMMAND, &status); + status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(devbusfn, PCI_COMMAND, status); -#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 + pci_read_config_word(devbusfn, PCI_COMMAND, &status); + if (!(status & PCI_COMMAND_MEMORY)) { + printf("Error: Can not enable MEMORY access.\n"); + continue; + } - /* Enable programming modes. */ - do_eeprom_cmd(dev, ioaddr, 0x4f << (ee_addr_size - 4), - 3 + ee_addr_size); + if (!(status & PCI_COMMAND_MASTER)) { + printf("Error: Can not enable Bus Mastering.\n"); + continue; + } - /* Do the actual write. */ - do_eeprom_cmd(dev, ioaddr, new_value | - (((SROM_WRITE_CMD << ee_addr_size) | index) << 16), - 3 + ee_addr_size + 16); + /* Check the latency timer for values >= 0x60. */ + pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer); - /* Poll for write finished. */ - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); - for (i = 0; i < 10000; i++) { /* Typical 2000 ticks */ - if (getfrom_srom(dev, ioaddr) & EE_DATA_READ) - break; - } + if (timer < 0x60) { + pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, + 0x60); + } -#ifdef DEBUG_SROM - printf(" Write finished after %d ticks.\n", i); -#endif + /* 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); - /* Disable programming. */ - do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size - 4)), - 3 + ee_addr_size); + dev = (struct eth_device *)malloc(sizeof(*dev)); + if (!dev) { + printf("Can not allocalte memory of dc21x4x\n"); + break; + } - /* And read the result. */ - newval = do_eeprom_cmd(dev, ioaddr, - (((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 + memset(dev, 0, sizeof(*dev)); - return 1; -} -#endif + sprintf(dev->name, "dc21x4x#%d", card_number); -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; + 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; - 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++; - } + /* Ensure we're not sleeping. */ + pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP); - 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 - } -} + udelay(10 * 1000); -#ifdef UPDATE_SROM -static void update_srom(struct eth_device *dev, bd_t *bis) -{ - static unsigned short eeprom[0x40] = { - 0x140b, 0x6610, 0x0000, 0x0000, /* 00 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 04 */ - 0x00a3, 0x0103, 0x0000, 0x0000, /* 08 */ - 0x0000, 0x1f00, 0x0000, 0x0000, /* 0c */ - 0x0108, 0x038d, 0x0000, 0x0000, /* 10 */ - 0xe078, 0x0001, 0x0040, 0x0018, /* 14 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 18 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 1c */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 2c */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 34 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 38 */ - 0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */ - }; - uchar enetaddr[6]; - int i; + read_hw_addr(dev, bis); - /* Ethernet Addr... */ - if (!eth_env_get_enetaddr("ethaddr", enetaddr)) - return; + eth_register(dev); - eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0]; - eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2]; - eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4]; + card_number++; + } - for (i = 0; i < 0x40; i++) - write_srom(dev, DE4X5_APROM, i, eeprom[i]); + return card_number; } -#endif /* UPDATE_SROM */ -- cgit v1.3.1 From c2abfca9be3a62a98c1a1b77a11cd01092c0160f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 19 Apr 2020 04:05:44 +0200 Subject: net: dc2114x: Switch DEBUG_SROM{,2} to debug_cond() Replace the adhoc debugging ifdeffery with debug_cond() and an internal SROM_DEBUG macro to select the debug level. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/dc2114x.c | 57 +++++++++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 9de9634cd51..d008696b0ff 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -7,8 +7,7 @@ #include #include -#undef DEBUG_SROM -#undef DEBUG_SROM2 +#define SROM_DLEVEL 0 #undef UPDATE_SROM @@ -176,9 +175,7 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, 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--) { @@ -190,25 +187,21 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, 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 + 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 + 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); @@ -218,9 +211,8 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, /* 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; } @@ -235,9 +227,7 @@ static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, { 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); @@ -248,9 +238,8 @@ static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, 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); udelay(10); @@ -263,9 +252,7 @@ static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, /* Terminate the EEPROM access. */ 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; } @@ -293,10 +280,10 @@ static int write_srom(struct eth_device *dev, u_long ioaddr, int index, udelay(10 * 1000); /* test-only */ -#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 + 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), @@ -314,9 +301,7 @@ static int write_srom(struct eth_device *dev, u_long ioaddr, int index, 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)), @@ -326,9 +311,9 @@ static int write_srom(struct eth_device *dev, u_long ioaddr, int index, newval = do_eeprom_cmd(dev, ioaddr, (((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 + + debug_cond(SROM_DLEVEL >= 1, " New value at offset %d is %4.4x.\n", + index, newval); return 1; } -- cgit v1.3.1 From 4332d8061785b697ae7bdf3945adb55ba4da696b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Mar 2020 02:02:57 +0100 Subject: net: dwc_eth_qos: Fully rewrite RX descriptor field 3 The RX descriptor field 3 should contain only OWN and BUF1V bits before being used for receiving data by the DMA engine. However, right now, if the descriptor was already used for receiving data and is being cleared, the field 3 is only modified and the aforementioned two bits are ORRed into the field. This could lead to a residual dirty bits being left in the field 3 from previous transfer, and it generally does. Fully set the field 3 instead to clear those residual dirty bits. Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren --- drivers/net/dwc_eth_qos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 63f2086dece..4f245206910 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1288,7 +1288,7 @@ 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(eqos->descs); @@ -1482,7 +1482,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); -- cgit v1.3.1 From 83858d87954627af7a576ccc7c93034b055faa7b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Mar 2020 02:03:50 +0100 Subject: net: dwc_eth_qos: Correctly wrap around TX descriptor tail pointer This code programs the next descriptor in the TX descriptor ring into the hardware as the last valid TX descriptor. The problem is that if the currenty descriptor is the last one in the array, the code will not wrap around correctly and use TX descriptor 0 again, but instead will use TX descriptor at address right past the TX descriptor ring, which is the first descriptor in the RX ring. Fix this by adding the necessary wrap-around. Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren --- drivers/net/dwc_eth_qos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 4f245206910..e2fb690a1c2 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -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); -- cgit v1.3.1 From dd90c2e1ea0a7abdfa501e604523c23d6f77ffdd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Mar 2020 02:09:01 +0100 Subject: net: dwc_eth_qos: Flush the RX descriptors on init Currently the code only flushes the first RX descriptor, not every entry in the RX descriptor ring. Fix this, to make sure the DMA engine can pick the RX descriptors correctly. Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren --- drivers/net/dwc_eth_qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index e2fb690a1c2..e33f3045fea 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1289,8 +1289,8 @@ static int eqos_start(struct udevice *dev) rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + (i * EQOS_MAX_PACKET_SIZE)); 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); -- cgit v1.3.1 From 738ee270fe17ea9e48fee8823eb356ed03656e7c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Mar 2020 02:09:21 +0100 Subject: net: dwc_eth_qos: Invalidate RX descriptor before reading The current code polls the RX desciptor ring for new packets by reading the RX descriptor status. This works by accident, as the RX descriptors are often in non-cacheable memory. However, the driver does support use of RX descriptors in cacheable memory. This patch adds a missing RX descriptor invalidation, which assures the CPU will read a fresh copy of the RX descriptor instead of a cached one. Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren --- drivers/net/dwc_eth_qos.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index e33f3045fea..2b37cc3cded 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1443,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; -- cgit v1.3.1 From a83ca0c280dd41dda576d6a8f15a8534a84b782c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Mar 2020 02:09:55 +0100 Subject: net: dwc_eth_qos: Invalidate RX packet DMA buffer This patch prevents an issue where the RX packet might have been accessed by the CPU, which now has cached data from the packet in the caches and possibly various write buffers, and these data may be evicted from the caches into the DRAM while the buffer is also written by the DMA. By invalidating the buffer after the CPU accessed it and before the DMA populates the buffer, it is assured that the buffer will not be corrupted. Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren --- drivers/net/dwc_eth_qos.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 2b37cc3cded..a195fe5c275 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1476,6 +1476,9 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) } rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); + + eqos->config->ops->eqos_inval_buffer(packet, length); + rx_desc->des0 = (u32)(ulong)packet; rx_desc->des1 = 0; rx_desc->des2 = 0; @@ -1538,6 +1541,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; -- cgit v1.3.1 From 24891dd8d40d71c034023d2a037c97df1714393b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Mar 2020 02:11:46 +0100 Subject: net: dwc_eth_qos: Prevent DMA from writing updated RX DMA descriptor The DMA may attempt to write a DMA descriptor in the ring while it is being updated. By writing the DMA descriptor buffer address to 0, it is assured the DMA will not use such a buffer and the buffer can be updated without any interference. Reviewed-by: Patrick Delaunay Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren --- drivers/net/dwc_eth_qos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index a195fe5c275..60dfd17a74d 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1477,8 +1477,10 @@ 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; -- cgit v1.3.1 From a5e66e515b0e6615d6e6fed91e20361d9a476831 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 20:47:26 +0200 Subject: net: rtl8139: Register macro cleanup Clean up the horrible register definitions in the RTL8139 driver. This does create a couple of checkpatch errors, but the driver is full of them anyway, and those will be cleaned up later. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 263 +++++++++++++++++++++++++++++--------------------- 1 file changed, 152 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index bb59629f81c..9898f20c391 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -99,77 +99,96 @@ #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, -}; +/* 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. + */ -/* Bits in RxConfig. */ -enum rx_mode_bits { - RxCfgWrap=0x80, - AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, - AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01, -}; +#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 int ioaddr; static unsigned int cur_rx,cur_tx; @@ -251,7 +270,7 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis) ioaddr = dev->iobase; /* Bring the chip out of low-power mode. */ - outb(0x00, ioaddr + Config1); + outb(0x00, ioaddr + RTL_REG_CONFIG1); addr_len = read_eeprom(0,8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) @@ -259,7 +278,7 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis) rtl_reset(dev); - if (inb(ioaddr + MediaStatus) & MSRLinkFail) { + if (inb(ioaddr + RTL_REG_MEDIASTATUS) & RTL_REG_MEDIASTATUS_MSRLINKFAIL) { printf("Cable not connected or other link failure\n"); return -1 ; } @@ -286,15 +305,15 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis) #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) { int i; unsigned int retval = 0; - long ee_addr = ioaddr + Cfg9346; + long ee_addr = ioaddr + RTL_REG_CFG9346; int read_cmd = location | (EE_READ_CMD << addr_len); outb(EE_ENB & ~EE_CS, ee_addr); @@ -335,41 +354,46 @@ static void set_rx_mode(struct eth_device *dev) { unsigned int mc_filter[2]; int rx_mode; /* !IFF_PROMISC */ - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + rx_mode = RTL_REG_RXCONFIG_ACCEPTBROADCAST | + RTL_REG_RXCONFIG_ACCEPTMULTICAST | + RTL_REG_RXCONFIG_ACCEPTMYPHYS; mc_filter[1] = mc_filter[0] = 0xffffffff; - 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(mc_filter[0], ioaddr + RTL_REG_MAR0 + 0); + outl(mc_filter[1], ioaddr + RTL_REG_MAR0 + 4); } static void rtl_reset(struct eth_device *dev) { int i; - outb(CmdReset, ioaddr + ChipCmd); + outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD); cur_rx = 0; cur_tx = 0; /* Give the chip 10ms to finish the reset. */ for (i=0; i<100; ++i){ - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break; + if ((inb(ioaddr + RTL_REG_CHIPCMD) & + RTL_REG_CHIPCMD_CMDRESET) == 0) + break; udelay (100); /* wait 100us */ } 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); + outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB, + ioaddr + RTL_REG_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); + ioaddr + RTL_REG_RXCONFIG); /* accept no frames yet! */ + outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + RTL_REG_TXCONFIG); - /* The Linux driver changes Config1 here to use a different LED pattern + /* 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 @@ -380,24 +404,25 @@ static void rtl_reset(struct eth_device *dev) 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); + outl(phys_to_bus((int)rx_ring), ioaddr + RTL_REG_RXBUF); - /* If we add multicast support, the MAR0 register would have to be + /* 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(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); + 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); /* 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) @@ -420,23 +445,32 @@ static int rtl_transmit(struct eth_device *dev, void *packet, int length) } flush_cache((unsigned long)tx_buffer, length); - outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4); + outl(phys_to_bus((int)tx_buffer), ioaddr + RTL_REG_TXADDR0 + cur_tx*4); outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len, - ioaddr + TxStatus0 + cur_tx*4); + 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 + * rtl_poll() function. + */ + outw(status & (RTL_REG_INTRSTATUS_TXOK | + RTL_REG_INTRSTATUS_TXERR | + RTL_REG_INTRSTATUS_PCIERR), + ioaddr + RTL_REG_INTRSTATUS); + if ((status & (RTL_REG_INTRSTATUS_TXOK | + RTL_REG_INTRSTATUS_TXERR | + RTL_REG_INTRSTATUS_PCIERR)) != 0) + break; udelay(10); } while (i++ < RTL_TIMEOUT); - txstatus = inl(ioaddr + TxStatus0 + cur_tx*4); + txstatus = inl(ioaddr + RTL_REG_TXSTATUS0 + cur_tx*4); - if (status & TxOK) { + if (status & RTL_REG_INTRSTATUS_TXOK) { cur_tx = (cur_tx + 1) % NUM_TX_DESC; debug_cond(DEBUG_TX, @@ -465,13 +499,16 @@ static int rtl_poll(struct eth_device *dev) 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 & ~(RTL_REG_INTRSTATUS_RXFIFOOVER | + RTL_REG_INTRSTATUS_RXOVERFLOW | + RTL_REG_INTRSTATUS_RXOK), + ioaddr + RTL_REG_INTRSTATUS); debug_cond(DEBUG_RX, "rtl_poll: int %hX ", status); @@ -481,7 +518,9 @@ static int rtl_poll(struct eth_device *dev) rx_size = rx_status >> 16; rx_status &= 0xffff; - if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) || + 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 */ @@ -507,11 +546,13 @@ static int rtl_poll(struct eth_device *dev) flush_cache((unsigned long)rx_ring, RX_BUF_LEN); cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - outw(cur_rx - 16, ioaddr + RxBufPtr); + 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 & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus); + outw(status & (RTL_REG_INTRSTATUS_RXFIFOOVER | + RTL_REG_INTRSTATUS_RXOVERFLOW | + RTL_REG_INTRSTATUS_RXOK), ioaddr + RTL_REG_INTRSTATUS); return length; } @@ -522,11 +563,11 @@ static void rtl_disable(struct eth_device *dev) ioaddr = dev->iobase; /* reset the chip */ - outb(CmdReset, ioaddr + ChipCmd); + 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; + if ((inb(ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_CMDRESET) == 0) break; udelay (100); /* wait 100us */ } } -- cgit v1.3.1 From f80f4e4d729252eb6124e1afb5dde9f74c35c994 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 21:20:31 +0200 Subject: net: rtl8139: Rework eeprom_delay() macro The macro assumes ee_addr variable to be present when it's being used. Rework the macro into a function instead and pass it an argument specifying the register base address, to make it future proof for DM conversion. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 9898f20c391..ff014ade88b 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -73,6 +73,7 @@ #include #include +#include #include #include #include @@ -297,18 +298,20 @@ 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 +static void rtl8139_eeprom_delay(uintptr_t regbase) +{ + /* + * 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 read_eeprom(int location, int addr_len) { int i; @@ -318,30 +321,30 @@ static int read_eeprom(int location, int addr_len) 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; 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(); + rtl8139_eeprom_delay(ioaddr); retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); 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; } -- cgit v1.3.1 From 17dc95e5277cdbad1281b6b5605b1eef74729463 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 21:28:30 +0200 Subject: net: rtl8139: Minor cleanup of read_eeprom() Rename the function to rtl8139_read_eeprom() to keep the naming consistent, keep the variables sorted in reverse xmas tree. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index ff014ade88b..90e9f1272c3 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -199,7 +199,7 @@ 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 int rtl8139_read_eeprom(unsigned int location, unsigned 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); @@ -273,9 +273,9 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis) /* Bring the chip out of low-power mode. */ outb(0x00, ioaddr + RTL_REG_CONFIG1); - addr_len = read_eeprom(0,8) == 0x8129 ? 8 : 6; + addr_len = rtl8139_read_eeprom(0,8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) - *ap++ = le16_to_cpu (read_eeprom(i + 7, addr_len)); + *ap++ = le16_to_cpu (rtl8139_read_eeprom(i + 7, addr_len)); rtl_reset(dev); @@ -312,12 +312,13 @@ static void rtl8139_eeprom_delay(uintptr_t regbase) inl(regbase + RTL_REG_CFG9346); } -static int read_eeprom(int location, int addr_len) +static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len) { - int i; + 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 + RTL_REG_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); @@ -325,19 +326,21 @@ static int read_eeprom(int location, int addr_len) /* 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); rtl8139_eeprom_delay(ioaddr); outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); rtl8139_eeprom_delay(ioaddr); } + outb(EE_ENB, ee_addr); rtl8139_eeprom_delay(ioaddr); for (i = 16; i > 0; i--) { outb(EE_ENB | EE_SHIFT_CLK, ee_addr); rtl8139_eeprom_delay(ioaddr); - retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); + retval <<= 1; + retval |= inb(ee_addr) & EE_DATA_READ; outb(EE_ENB, ee_addr); rtl8139_eeprom_delay(ioaddr); } @@ -345,6 +348,7 @@ static int read_eeprom(int location, int addr_len) /* Terminate the EEPROM access. */ outb(~EE_CS, ee_addr); rtl8139_eeprom_delay(ioaddr); + return retval; } -- cgit v1.3.1 From 198e6b571b58de54803a92743970c8f5dea77782 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 21:30:38 +0200 Subject: net: rtl8139: Consistently use rtl8139_rx_config This string of macros is exactly the same thing as rtl8139_rx_config, so just use rtl8139_rx_config. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 90e9f1272c3..7a2829a1633 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -396,8 +396,8 @@ static void rtl_reset(struct eth_device *dev) /* Must enable Tx/Rx before setting transfer thresholds! */ outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB, ioaddr + RTL_REG_CHIPCMD); - outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8), - ioaddr + RTL_REG_RXCONFIG); /* accept no frames yet! */ + /* 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 -- cgit v1.3.1 From 89f3facffb8b35f45d405716dce63f6bc944a082 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 21:35:12 +0200 Subject: net: rtl8139: Minor cleanup of set_rx_mode() Rename the function to rtl8139_set_rx_mode(), use unsigned variables where applicable and inline mc_filter[] values. No functional chanage. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 7a2829a1633..4dfb709fa9a 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -357,19 +357,17 @@ 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 = RTL_REG_RXCONFIG_ACCEPTBROADCAST | - RTL_REG_RXCONFIG_ACCEPTMULTICAST | - RTL_REG_RXCONFIG_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 + RTL_REG_RXCONFIG); - outl(mc_filter[0], ioaddr + RTL_REG_MAR0 + 0); - outl(mc_filter[1], ioaddr + RTL_REG_MAR0 + 4); + outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 0); + outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 4); } static void rtl_reset(struct eth_device *dev) @@ -425,8 +423,7 @@ static void rtl_reset(struct eth_device *dev) /* Start the chip's Tx and Rx process. */ 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 + RTL_REG_INTRMASK); -- cgit v1.3.1 From c7a3e35d768ddc6b6d3a9a0e061bba0741deaa52 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 21:41:56 +0200 Subject: net: rtl8139: Minor cleanup of rtl_reset() Rename the function to rtl8139_reset(), clean up the reset polling and various line-over-80 problems. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 4dfb709fa9a..d9d8aae7a94 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -200,7 +200,7 @@ 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 rtl8139_read_eeprom(unsigned int location, unsigned int addr_len); -static void rtl_reset(struct eth_device *dev); +static void rtl8139_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); @@ -277,7 +277,7 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis) for (i = 0; i < 3; i++) *ap++ = le16_to_cpu (rtl8139_read_eeprom(i + 7, addr_len)); - rtl_reset(dev); + rtl8139_reset(dev); if (inb(ioaddr + RTL_REG_MEDIASTATUS) & RTL_REG_MEDIASTATUS_MSRLINKFAIL) { printf("Cable not connected or other link failure\n"); @@ -370,8 +370,9 @@ static void rtl8139_set_rx_mode(struct eth_device *dev) outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 4); } -static void rtl_reset(struct eth_device *dev) +static void rtl8139_reset(struct eth_device *dev) { + u8 reg; int i; outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD); @@ -380,11 +381,12 @@ static void rtl_reset(struct eth_device *dev) cur_tx = 0; /* Give the chip 10ms to finish the reset. */ - for (i=0; i<100; ++i){ - if ((inb(ioaddr + RTL_REG_CHIPCMD) & - RTL_REG_CHIPCMD_CMDRESET) == 0) + for (i = 0; i < 100; i++) { + reg = inb(ioaddr + RTL_REG_CHIPCMD); + if (!(reg & RTL_REG_CHIPCMD_CMDRESET)) break; - udelay (100); /* wait 100us */ + + udelay(100); } @@ -393,30 +395,35 @@ static void rtl_reset(struct eth_device *dev) /* Must enable Tx/Rx before setting transfer thresholds! */ outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB, - ioaddr + RTL_REG_CHIPCMD); + 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 %lX\n",(unsigned long)rx_ring); + 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); + flush_cache((unsigned long)rx_ring, RX_BUF_LEN); outl(phys_to_bus((int)rx_ring), ioaddr + RTL_REG_RXBUF); - /* 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. */ - + /* + * 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); + ioaddr + RTL_REG_CHIPCMD); outl(rtl8139_rx_config, ioaddr + RTL_REG_RXCONFIG); @@ -488,7 +495,7 @@ static int rtl_transmit(struct eth_device *dev, void *packet, int length) "tx timeout/error (%d usecs), status %hX txstatus %lX\n", 10*i, status, txstatus); - rtl_reset(dev); + rtl8139_reset(dev); return 0; } @@ -527,7 +534,7 @@ static int rtl_poll(struct eth_device *dev) 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 */ + rtl8139_reset(dev); /* this clears all interrupts still pending */ return 0; } -- cgit v1.3.1 From 67fdbc06be27728e41aa9682d6aaf5618d959765 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 22:40:45 +0200 Subject: net: rtl8139: Minor cleanup of rtl_transmit() Rename the function to rtl8139_send(), clean up the TX polling, the TX OK condition at the end, overuse of typecasts, and various line-over-80 problems. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 64 +++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index d9d8aae7a94..cb1166ead2d 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -201,7 +201,7 @@ 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 rtl8139_read_eeprom(unsigned int location, unsigned int addr_len); static void rtl8139_reset(struct eth_device *dev); -static int rtl_transmit(struct eth_device *dev, void *packet, int length); +static int rtl8139_send(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) @@ -246,7 +246,7 @@ int rtl8139_initialize(bd_t *bis) dev->iobase = (int)bus_to_phys(iobase); dev->init = rtl8139_probe; dev->halt = rtl_disable; - dev->send = rtl_transmit; + dev->send = rtl8139_send; dev->recv = rtl_poll; dev->mcast = rtl_bcast_addr; @@ -436,29 +436,31 @@ static void rtl8139_reset(struct eth_device *dev) 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 + RTL_REG_TXADDR0 + cur_tx*4); - outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len, - ioaddr + RTL_REG_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 + RTL_REG_INTRSTATUS); @@ -468,37 +470,33 @@ static int rtl_transmit(struct eth_device *dev, void *packet, int length) * RTL_REG_INTRSTATUS_RXFIFOOVER MUST be handled in the * rtl_poll() function. */ - outw(status & (RTL_REG_INTRSTATUS_TXOK | - RTL_REG_INTRSTATUS_TXERR | - RTL_REG_INTRSTATUS_PCIERR), - ioaddr + RTL_REG_INTRSTATUS); - if ((status & (RTL_REG_INTRSTATUS_TXOK | - RTL_REG_INTRSTATUS_TXERR | - RTL_REG_INTRSTATUS_PCIERR)) != 0) + 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 + RTL_REG_TXSTATUS0 + cur_tx*4); - - if (status & RTL_REG_INTRSTATUS_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); - - return length; - } else { - - debug_cond(DEBUG_TX, - "tx timeout/error (%d usecs), status %hX txstatus %lX\n", - 10*i, status, txstatus); + "tx timeout/error (%d usecs), status %hX txstatus %lX\n", + 10 * i, status, txstatus); 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) -- cgit v1.3.1 From 468fd955626b650ebb7975d061d415682c91f041 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 22:43:16 +0200 Subject: net: rtl8139: Minor cleanup of rtl_poll() Rename the function to rtl8139_recv(), clean up various checkpatch errors, line-over-80 conditions, and malformed comments. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 63 +++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index cb1166ead2d..d942ccf6273 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -44,7 +44,7 @@ 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 + 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 @@ -65,7 +65,7 @@ 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 + 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. @@ -202,7 +202,7 @@ static int rtl8139_probe(struct eth_device *dev, bd_t *bis); static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len); static void rtl8139_reset(struct eth_device *dev); static int rtl8139_send(struct eth_device *dev, void *packet, int length); -static int rtl_poll(struct eth_device *dev); +static int rtl8139_recv(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) { @@ -247,7 +247,7 @@ int rtl8139_initialize(bd_t *bis) dev->init = rtl8139_probe; dev->halt = rtl_disable; dev->send = rtl8139_send; - dev->recv = rtl_poll; + dev->recv = rtl8139_recv; dev->mcast = rtl_bcast_addr; eth_register (dev); @@ -468,7 +468,7 @@ static int rtl8139_send(struct eth_device *dev, void *packet, int length) * Only acknlowledge interrupt sources we can properly * handle here - the RTL_REG_INTRSTATUS_RXOVERFLOW/ * RTL_REG_INTRSTATUS_RXFIFOOVER MUST be handled in the - * rtl_poll() function. + * rtl8139_recv() function. */ status &= RTL_REG_INTRSTATUS_TXOK | RTL_REG_INTRSTATUS_TXERR | RTL_REG_INTRSTATUS_PCIERR; @@ -499,27 +499,26 @@ static int rtl8139_send(struct eth_device *dev, void *packet, int length) 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 + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY) { + if (inb(ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY) return 0; - } status = inw(ioaddr + RTL_REG_INTRSTATUS); /* See below for the rest of the interrupt acknowledges. */ - outw(status & ~(RTL_REG_INTRSTATUS_RXFIFOOVER | - RTL_REG_INTRSTATUS_RXOVERFLOW | - RTL_REG_INTRSTATUS_RXOK), - ioaddr + RTL_REG_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 */ @@ -530,38 +529,42 @@ static int rtl_poll(struct eth_device *dev) 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)) { + (rx_size < ETH_ZLEN) || + (rx_size > ETH_FRAME_LEN + 4)) { printf("rx error %hX\n", rx_status); - rtl8139_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; + 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 & (RTL_REG_INTRSTATUS_RXFIFOOVER | - RTL_REG_INTRSTATUS_RXOVERFLOW | - RTL_REG_INTRSTATUS_RXOK), ioaddr + RTL_REG_INTRSTATUS); + /* + * 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; } -- cgit v1.3.1 From 661479ffc1a0b7ea159dae1ca34d61d009896870 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 22:55:40 +0200 Subject: net: rtl8139: Minor cleanup of rtl_disable() Rename the function to rtl8139_stop(), clean up checkpatch errors in the stop polling function. No functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index d942ccf6273..6aed7bd8957 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -203,7 +203,7 @@ static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len); static void rtl8139_reset(struct eth_device *dev); static int rtl8139_send(struct eth_device *dev, void *packet, int length); static int rtl8139_recv(struct eth_device *dev); -static void rtl_disable(struct eth_device *dev); +static void rtl8139_stop(struct eth_device *dev); static int rtl_bcast_addr(struct eth_device *dev, const u8 *bcast_mac, int join) { return (0); @@ -245,7 +245,7 @@ int rtl8139_initialize(bd_t *bis) dev->priv = (void *) devno; dev->iobase = (int)bus_to_phys(iobase); dev->init = rtl8139_probe; - dev->halt = rtl_disable; + dev->halt = rtl8139_stop; dev->send = rtl8139_send; dev->recv = rtl8139_recv; dev->mcast = rtl_bcast_addr; @@ -568,8 +568,9 @@ static int rtl8139_recv(struct eth_device *dev) return length; } -static void rtl_disable(struct eth_device *dev) +static void rtl8139_stop(struct eth_device *dev) { + u8 reg; int i; ioaddr = dev->iobase; @@ -578,8 +579,10 @@ static void rtl_disable(struct eth_device *dev) 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 + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_CMDRESET) == 0) break; + for (i = 0; i < 100; i++) { + reg = inb(ioaddr + RTL_REG_CHIPCMD); + if (!(reg & RTL_REG_CHIPCMD_CMDRESET)) + break; udelay (100); /* wait 100us */ } } -- cgit v1.3.1 From 38b306db2334a6565b326874eb4ff536e28654ba Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 22:58:27 +0200 Subject: net: rtl8139: Factor out hardware reset This hardware reset and reset-wait implementation was twice in the driver, factor it out into a separate function. This really should use wait_for_bit() eventually and return -ETIMEDOUT, but thus far, handling of any of this is missing from the driver. This must be added later. Thus far, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 6aed7bd8957..68ef9eea250 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -370,16 +370,13 @@ static void rtl8139_set_rx_mode(struct eth_device *dev) outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 4); } -static void rtl8139_reset(struct eth_device *dev) +static void rtl8139_hw_reset(struct eth_device *dev) { u8 reg; int i; outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD); - cur_rx = 0; - cur_tx = 0; - /* Give the chip 10ms to finish the reset. */ for (i = 0; i < 100; i++) { reg = inb(ioaddr + RTL_REG_CHIPCMD); @@ -388,7 +385,16 @@ static void rtl8139_reset(struct eth_device *dev) 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 + RTL_REG_MAC0 + i); @@ -570,19 +576,7 @@ static int rtl8139_recv(struct eth_device *dev) static void rtl8139_stop(struct eth_device *dev) { - u8 reg; - int i; - ioaddr = dev->iobase; - /* reset the chip */ - outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD); - - /* Give the chip 10ms to finish the reset. */ - for (i = 0; i < 100; i++) { - reg = inb(ioaddr + RTL_REG_CHIPCMD); - if (!(reg & RTL_REG_CHIPCMD_CMDRESET)) - break; - udelay (100); /* wait 100us */ - } + rtl8139_hw_reset(dev); } -- cgit v1.3.1 From 0e5a4117a58b8d47b502d7e5536ca6b36d568806 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 23:01:45 +0200 Subject: net: rtl8139: Finish cleanup Finish the checkpatch cleanup of the driver, fix the remaining issues in probe and init function and in global variables, rename the probe function to rtl8139_init(), no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 173 +++++++++++++++++++++++++------------------------- 1 file changed, 87 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 68ef9eea250..b901e3a79b7 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -8,68 +8,67 @@ */ /* 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 + * + * 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) + */ /*********************************************************************/ /* 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 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. - -*/ + * 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 #include @@ -82,8 +81,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 */ @@ -192,13 +191,13 @@ #define RTL_STS_RXSTATUSOK BIT(0) static int ioaddr; -static unsigned int cur_rx,cur_tx; +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 unsigned char tx_buffer[TX_BUF_SIZE] __aligned(4); +static unsigned char rx_ring[RX_BUF_LEN + 16] __aligned(4); -static int rtl8139_probe(struct eth_device *dev, bd_t *bis); +static int rtl8139_init(struct eth_device *dev, bd_t *bis); static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len); static void rtl8139_reset(struct eth_device *dev); static int rtl8139_send(struct eth_device *dev, void *packet, int length); @@ -206,82 +205,84 @@ static int rtl8139_recv(struct eth_device *dev); static void rtl8139_stop(struct eth_device *dev); static int rtl_bcast_addr(struct eth_device *dev, const u8 *bcast_mac, int join) { - return (0); + 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}, - {} + { 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; + int card_number = 0; + pci_dev_t devno; + int idx = 0; u32 iobase; - int idx=0; - while(1){ + while (1) { /* Find RTL8139 */ - if ((devno = pci_find_devices(supported, idx++)) < 0) + 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); + debug("rtl8139: REALTEK RTL8139 @0x%x\n", iobase); - dev = (struct eth_device *)malloc(sizeof *dev); + 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); + sprintf(dev->name, "RTL8139#%d", card_number); - dev->priv = (void *) devno; + dev->priv = (void *)devno; dev->iobase = (int)bus_to_phys(iobase); - dev->init = rtl8139_probe; + dev->init = rtl8139_init; dev->halt = rtl8139_stop; dev->send = rtl8139_send; dev->recv = rtl8139_recv; dev->mcast = rtl_bcast_addr; - eth_register (dev); + eth_register(dev); card_number++; - pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20); + pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20); - udelay (10 * 1000); + udelay(10 * 1000); } return card_number; } -static int rtl8139_probe(struct eth_device *dev, bd_t *bis) +static int rtl8139_init(struct eth_device *dev, bd_t *bis) { - int i; - int addr_len; unsigned short *ap = (unsigned short *)dev->enetaddr; + int addr_len, i; + u8 reg; ioaddr = dev->iobase; /* Bring the chip out of low-power mode. */ outb(0x00, ioaddr + RTL_REG_CONFIG1); - addr_len = rtl8139_read_eeprom(0,8) == 0x8129 ? 8 : 6; + 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)); + *ap++ = le16_to_cpu(rtl8139_read_eeprom(i + 7, addr_len)); rtl8139_reset(dev); - if (inb(ioaddr + RTL_REG_MEDIASTATUS) & RTL_REG_MEDIASTATUS_MSRLINKFAIL) { + reg = inb(ioaddr + RTL_REG_MEDIASTATUS); + if (reg & RTL_REG_MEDIASTATUS_MSRLINKFAIL) { printf("Cable not connected or other link failure\n"); - return -1 ; + return -1; } return 0; -- cgit v1.3.1 From 6ee6caaf035063dc376eeb3385f7f08f87549b1e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 23:12:11 +0200 Subject: net: rtl8139: Move functions around Just move functions around in preparation for easy DM conversion, rename rtl_bcast_addr() to rtl8139_bcast_addr(), no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 179 ++++++++++++++++++++++++-------------------------- 1 file changed, 87 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index b901e3a79b7..66591d03cec 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -190,104 +190,13 @@ #define RTL_STS_RXBADALIGN BIT(1) #define RTL_STS_RXSTATUSOK BIT(0) -static int ioaddr; static unsigned int cur_rx, cur_tx; +static int ioaddr; /* The RTL8139 can only transmit from a contiguous, aligned memory block. */ static unsigned char tx_buffer[TX_BUF_SIZE] __aligned(4); static unsigned char rx_ring[RX_BUF_LEN + 16] __aligned(4); -static int rtl8139_init(struct eth_device *dev, bd_t *bis); -static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len); -static void rtl8139_reset(struct eth_device *dev); -static int rtl8139_send(struct eth_device *dev, void *packet, int length); -static int rtl8139_recv(struct eth_device *dev); -static void rtl8139_stop(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) -{ - 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 = 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_init(struct eth_device *dev, bd_t *bis) -{ - unsigned short *ap = (unsigned short *)dev->enetaddr; - int addr_len, i; - u8 reg; - - ioaddr = dev->iobase; - - /* Bring the chip out of low-power mode. */ - outb(0x00, ioaddr + RTL_REG_CONFIG1); - - 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; -} - /* Serial EEPROM section. */ /* EEPROM_Ctrl bits. */ @@ -575,9 +484,95 @@ static int rtl8139_recv(struct eth_device *dev) return length; } +static int rtl8139_init(struct eth_device *dev, bd_t *bis) +{ + unsigned short *ap = (unsigned short *)dev->enetaddr; + int addr_len, i; + u8 reg; + + ioaddr = dev->iobase; + + /* Bring the chip out of low-power mode. */ + outb(0x00, ioaddr + RTL_REG_CONFIG1); + + 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; +} -- cgit v1.3.1 From e7ab86d9b2f24c92552be62b0447abab4f8644a2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Apr 2020 23:49:25 +0200 Subject: net: rtl8139: Fill in SPDX tag The rtl8139 driver is derived from Etherboot driver, which is in turn derived from Linux 8139too driver added in Linux 2.2.18pre14. An undocumented change in Linux 2.4.10.2 added a new field to the driver, MODULE_LICENSE("GPL"); . According to current Linux kernel licensing rules, Documentation/process/license-rules.rst, quote: "GPL" Module is licensed under GPL version 2. This does not express any distinction between GPL-2.0-only or GPL-2.0-or-later. The exact license information can only be determined via the license information in the corresponding source files. And since the code does not contain any "future" clause, the tag is therefore GPL-2.0 only. Signed-off-by: Marek Vasut Cc: Joe Hershberger --- drivers/net/rtl8139.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 66591d03cec..1f083972917 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 * @@ -12,9 +13,6 @@ * 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) -- cgit v1.3.1 From 9c211e3b055ce809ac81ea4f849594ffb6f77df4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 00:08:31 +0100 Subject: net: smc911x: Remove pkt_data_{push,pull} These functions are never used and are likely a pre-DM remnant from times long past, just remove them. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 257b0385c2a..24b4eaeb3fd 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -13,11 +13,6 @@ #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"))); - static void smc911x_handle_mac_address(struct eth_device *dev) { unsigned long addrh, addrl; @@ -157,7 +152,7 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length) tmplen = (length + 3) / 4; while (tmplen--) - pkt_data_push(dev, TX_DATA_FIFO, *data++); + smc911x_reg_write(dev, TX_DATA_FIFO, *data++); /* wait for transmission */ while (!((smc911x_reg_read(dev, TX_FIFO_INF) & @@ -203,7 +198,7 @@ static int smc911x_rx(struct eth_device *dev) tmplen = (pktlen + 3) / 4; while (tmplen--) - *data++ = pkt_data_pull(dev, RX_DATA_FIFO); + *data++ = smc911x_reg_read(dev, RX_DATA_FIFO); if (status & RX_STS_ES) printf(DRIVERNAME -- cgit v1.3.1 From 882d5f6983ff23b6f09899bb43d6dfd90ed7492f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 15:14:18 +0100 Subject: net: smc911x: Replace malloc()+memset() with calloc() Replace combination of malloc()+memset() with calloc() as the behavior is exactly the same and the amount of code is reduced. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 24b4eaeb3fd..2c72e3469d5 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -242,11 +242,9 @@ int smc911x_initialize(u8 dev_num, int base_addr) unsigned long addrl, addrh; struct eth_device *dev; - dev = malloc(sizeof(*dev)); - if (!dev) { - return -1; - } - memset(dev, 0, sizeof(*dev)); + dev = calloc(1, sizeof(*dev)); + if (!dev) + return -ENOMEM; dev->iobase = base_addr; -- cgit v1.3.1 From 49af0cb5a61c821d416ef069c6950d82523db585 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 15:40:15 +0100 Subject: net: smc911x: Rename smc911x_rx() to smc911x_recv() Rename the function to keep the naming scheme consistent, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2c72e3469d5..6da6c895469 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -184,7 +184,7 @@ static void smc911x_halt(struct eth_device *dev) smc911x_handle_mac_address(dev); } -static int smc911x_rx(struct eth_device *dev) +static int smc911x_recv(struct eth_device *dev) { u32 *data = (u32 *)net_rx_packets[0]; u32 pktlen, tmplen; @@ -269,7 +269,7 @@ int smc911x_initialize(u8 dev_num, int base_addr) dev->init = smc911x_init; dev->halt = smc911x_halt; dev->send = smc911x_send; - dev->recv = smc911x_rx; + dev->recv = smc911x_recv; sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); eth_register(dev); -- cgit v1.3.1 From 6f6cf0083f466c49c97c175b0169a0cd31c35d63 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 15:43:20 +0100 Subject: net: smc911x: Invert the logic in smc911x_miiphy_{read,write}() Invert the logic in the aforementioned functions to reduce indent, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 6da6c895469..ceb4f812152 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -216,24 +216,29 @@ static int smc911x_recv(struct eth_device *dev) 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; + u16 val = 0; + int ret; + + if (!dev) + return -ENODEV; + + ret = smc911x_eth_phy_read(dev, 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; + + if (!dev) + return -ENODEV; + + return smc911x_eth_phy_write(dev, phy, reg, val); } #endif -- cgit v1.3.1 From 9741795408d2fb907256899cd9403dd57b917358 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 15:57:14 +0100 Subject: net: smc911x: Fix potential memleak() in init fail path Fix memleak in the init fail path, where if allocation or registration of MDIO bus fails, then ethernet interface is not unregistered and the private data are not freed, yet the probe function reports a failure. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index ceb4f812152..4459da5945d 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -282,15 +282,23 @@ int smc911x_initialize(u8 dev_num, int base_addr) #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) int retval; struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) + if (!mdiodev) { + eth_unregister(dev); + free(dev); 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) + if (retval < 0) { + mdio_free(mdiodev); + eth_unregister(dev); + free(dev); return retval; + } #endif return 1; -- cgit v1.3.1 From f51a2f84969a1c88fb96414835a3b04883f3d8eb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 21 Mar 2020 17:25:41 +0100 Subject: net: smc911x: Pull MII registration into separate function Pull the MII interface registration into separate function to avoid the ifdeffery in smc911x_initialize(). Moreover, adjust the fail path such that we use goto labels. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 64 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 4459da5945d..65c25f3bfd3 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -240,12 +240,39 @@ static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad, return smc911x_eth_phy_write(dev, phy, reg, val); } + +static int smc911x_initialize_mii(struct eth_device *dev) +{ + struct mii_dev *mdiodev = mdio_alloc(); + int ret; + + if (!mdiodev) + return -ENOMEM; + + strncpy(mdiodev->name, 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 eth_device *dev) +{ + return 0; +} #endif int smc911x_initialize(u8 dev_num, int base_addr) { unsigned long addrl, addrh; struct eth_device *dev; + int ret; dev = calloc(1, sizeof(*dev)); if (!dev) @@ -254,9 +281,10 @@ int smc911x_initialize(u8 dev_num, int base_addr) 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(dev); + if (ret) { + ret = 0; /* Card not detected is not an error */ + goto err_detect; } addrh = smc911x_get_mac_csr(dev, ADDRH); @@ -279,27 +307,15 @@ int smc911x_initialize(u8 dev_num, int base_addr) eth_register(dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) { - eth_unregister(dev); - free(dev); - 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) { - mdio_free(mdiodev); - eth_unregister(dev); - free(dev); - return retval; - } -#endif + ret = smc911x_initialize_mii(dev); + if (ret) + goto err_mii; return 1; + +err_mii: + eth_unregister(dev); +err_detect: + free(dev); + return ret; } -- cgit v1.3.1 From eb46efa381d6dedb03af77d74b896ff40f1591b8 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 15:03:07 +0100 Subject: net: smc911x: Inline all functions from header file Inline all the functions from the header file, as they are not used outside of the driver or the standalone EEPROM example. Note that this does introduce considerable amount of duplication in the standalone EEPROM example, however that one has to be rewritten anyway, roughly such that the SMC911x driver would expose DM EEPROM interface and the standalone example would use that. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 157 ++++++++++++++++++++++++++++++++++- drivers/net/smc911x.h | 157 ----------------------------------- examples/standalone/smc911x_eeprom.c | 156 ++++++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+), 158 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 65c25f3bfd3..ff285f14b4b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -10,9 +10,165 @@ #include #include #include +#include #include "smc911x.h" +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 }, +}; + +#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 */ + +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); +} + static void smc911x_handle_mac_address(struct eth_device *dev) { unsigned long addrh, addrl; @@ -117,7 +273,6 @@ static void smc911x_enable(struct eth_device *dev) smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS); - } static int smc911x_init(struct eth_device *dev, bd_t * bd) diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 3145fbde2bd..ce66900f4cf 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -8,47 +8,6 @@ #ifndef _SMC911X_H_ #define _SMC911X_H_ -#include - -#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/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c index 2c05ed902d0..19ad9e6297c 100644 --- a/examples/standalone/smc911x_eeprom.c +++ b/examples/standalone/smc911x_eeprom.c @@ -18,8 +18,164 @@ #include #include #include +#include #include "../drivers/net/smc911x.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 + +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 }, +}; + +#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 */ + +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); +} + /** * smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?) */ -- cgit v1.3.1 From f0d73f5cd0ec0967fffcdf130a8c016262a216c4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 14:38:59 +0100 Subject: net: smc911x: Drop weak alias from 32bit accessors These accessors are not overridden by any board, and even if they were, this is something which should be handled via DM now, so remove the weak alias option. Moreover, drop the inline keyword, as the compiler can decide better. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 14 ++++---------- examples/standalone/smc911x_eeprom.c | 16 +++++----------- 2 files changed, 9 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index ff285f14b4b..effee5367ca 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -44,28 +44,22 @@ static const struct chip_id chip_ids[] = { #endif #if defined (CONFIG_SMC911X_32_BIT) -static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset) +static 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) +static 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) +static 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) +static 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); diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c index 19ad9e6297c..270588bcf5e 100644 --- a/examples/standalone/smc911x_eeprom.c +++ b/examples/standalone/smc911x_eeprom.c @@ -51,28 +51,22 @@ static const struct chip_id chip_ids[] = { }; #if defined (CONFIG_SMC911X_32_BIT) -static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset) +static 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) +static 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) +static 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)); + return (*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16); } -static inline void smc911x_reg_write(struct eth_device *dev, - u32 offset, u32 val) +static 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); -- cgit v1.3.1 From ba267c781da73ab0df4a7a57c05ef21c19aee609 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 14:42:23 +0100 Subject: net: smc911x: Convert IO accessors to {read,write}{w,l}() Convert the IO accessors to standard ones instead of using volatile void pointers, as those do not cover all the bus access details. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index effee5367ca..364f8c5da8d 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "smc911x.h" @@ -46,23 +47,23 @@ static const struct chip_id chip_ids[] = { #if defined (CONFIG_SMC911X_32_BIT) static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) { - return *(volatile u32*)(dev->iobase + offset); + return readl(dev->iobase + offset); } static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) { - *(volatile u32*)(dev->iobase + offset) = val; + writel(val, dev->iobase + offset); } #elif defined (CONFIG_SMC911X_16_BIT) static 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)); + return (readw(dev->iobase + offset) & 0xffff) | + (readw(dev->iobase + offset + 2) << 16); } static 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); + writew(val & 0xffff, dev->iobase + offset); + writew(val >> 16, dev->iobase + offset + 2); } #else #error "SMC911X: undefined bus width" -- cgit v1.3.1 From 3dbab926031fe77d794670c05d6c7badcfa77291 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 15:36:09 +0100 Subject: net: smc911x: Pass around driver private data Introduce a private data structure for this driver with embedded struct eth_device and pass it around. This prepares the driver to work with both DM and non-DM systems. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 232 +++++++++++++++++++++++++++----------------------- 1 file changed, 124 insertions(+), 108 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 364f8c5da8d..07066ce1083 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -20,6 +20,13 @@ struct chip_id { char *name; }; +struct smc911x_priv { + struct eth_device dev; + 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" }, @@ -45,57 +52,57 @@ static const struct chip_id chip_ids[] = { #endif #if defined (CONFIG_SMC911X_32_BIT) -static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset) { - return readl(dev->iobase + offset); + return readl(priv->iobase + offset); } -static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) +static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val) { - writel(val, dev->iobase + offset); + writel(val, priv->iobase + offset); } #elif defined (CONFIG_SMC911X_16_BIT) -static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset) { - return (readw(dev->iobase + offset) & 0xffff) | - (readw(dev->iobase + offset + 2) << 16); + return (readw(priv->iobase + offset) & 0xffff) | + (readw(priv->iobase + offset + 2) << 16); } -static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) +static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val) { - writew(val & 0xffff, dev->iobase + offset); - writew(val >> 16, dev->iobase + offset + 2); + 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 eth_device *dev, u8 reg) +static u32 smc911x_get_mac_csr(struct smc911x_priv *priv, u8 reg) { - while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - smc911x_reg_write(dev, MAC_CSR_CMD, + smc911x_reg_write(priv, 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) + while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - return smc911x_reg_read(dev, MAC_CSR_DATA); + return smc911x_reg_read(priv, MAC_CSR_DATA); } -static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data) +static void smc911x_set_mac_csr(struct smc911x_priv *priv, u8 reg, u32 data) { - while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(priv, 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) + 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 eth_device *dev) +static int smc911x_detect_chip(struct smc911x_priv *priv) { unsigned long val, i; - val = smc911x_reg_read(dev, BYTE_TEST); + val = smc911x_reg_read(priv, BYTE_TEST); if (val == 0xffffffff) { /* Special case -- no chip present */ return -1; @@ -104,7 +111,7 @@ static int smc911x_detect_chip(struct eth_device *dev) return -1; } - val = smc911x_reg_read(dev, ID_REV) >> 16; + val = smc911x_reg_read(priv, ID_REV) >> 16; for (i = 0; chip_ids[i].id != 0; i++) { if (chip_ids[i].id == val) break; } @@ -113,12 +120,12 @@ static int smc911x_detect_chip(struct eth_device *dev) return -1; } - dev->priv = (void *)&chip_ids[i]; + priv->chipid = &chip_ids[i]; return 0; } -static void smc911x_reset(struct eth_device *dev) +static void smc911x_reset(struct smc911x_priv *priv) { int timeout; @@ -126,14 +133,14 @@ static void smc911x_reset(struct eth_device *dev) * 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) { + if ((smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY) == 0) { /* Write to the bytetest will take out of powerdown */ - smc911x_reg_write(dev, BYTE_TEST, 0x0); + smc911x_reg_write(priv, BYTE_TEST, 0x0); timeout = 10; while (timeout-- && - !(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY)) + !(smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY)) udelay(10); if (timeout < 0) { printf(DRIVERNAME @@ -143,12 +150,12 @@ static void smc911x_reset(struct eth_device *dev) } /* Disable interrupts */ - smc911x_reg_write(dev, INT_EN, 0); + smc911x_reg_write(priv, INT_EN, 0); - smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST); + smc911x_reg_write(priv, HW_CFG, HW_CFG_SRST); timeout = 1000; - while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) + while (timeout-- && smc911x_reg_read(priv, E2P_CMD) & E2P_CMD_EPC_BUSY) udelay(10); if (timeout < 0) { @@ -157,83 +164,83 @@ static void smc911x_reset(struct eth_device *dev) } /* 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); + smc911x_set_mac_csr(priv, FLOW, FLOW_FCPT | FLOW_FCEN); + smc911x_reg_write(priv, AFC_CFG, 0x0050287F); /* Set to LED outputs */ - smc911x_reg_write(dev, GPIO_CFG, 0x70070000); + smc911x_reg_write(priv, GPIO_CFG, 0x70070000); } -static void smc911x_handle_mac_address(struct eth_device *dev) +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; @@ -242,7 +249,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)); @@ -254,64 +261,66 @@ 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) { - struct chip_id *id = dev->priv; + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + 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) { + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); 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--) - smc911x_reg_write(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); @@ -330,25 +339,28 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length) static void smc911x_halt(struct eth_device *dev) { - smc911x_reset(dev); - smc911x_handle_mac_address(dev); + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + + smc911x_reset(priv); + smc911x_handle_mac_address(priv); } 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]; 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); + if ((smc911x_reg_read(priv, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { + status = smc911x_reg_read(priv, RX_STATUS_FIFO); pktlen = (status & RX_STS_PKT_LEN) >> 16; - smc911x_reg_write(dev, RX_CFG, 0); + smc911x_reg_write(priv, RX_CFG, 0); tmplen = (pktlen + 3) / 4; while (tmplen--) - *data++ = smc911x_reg_read(dev, RX_DATA_FIFO); + *data++ = smc911x_reg_read(priv, RX_DATA_FIFO); if (status & RX_STS_ES) printf(DRIVERNAME @@ -367,31 +379,34 @@ static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad, int reg) { struct eth_device *dev = eth_get_dev_by_name(bus->name); + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); u16 val = 0; int ret; - if (!dev) + if (!dev || !priv) return -ENODEV; - ret = smc911x_eth_phy_read(dev, phy, reg, &val); + 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); + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); - if (!dev) + if (!dev || !priv) return -ENODEV; - return smc911x_eth_phy_write(dev, phy, reg, val); + return smc911x_eth_phy_write(priv, phy, reg, val); } -static int smc911x_initialize_mii(struct eth_device *dev) +static int smc911x_initialize_mii(struct smc911x_priv *priv) { struct mii_dev *mdiodev = mdio_alloc(); int ret; @@ -399,7 +414,7 @@ static int smc911x_initialize_mii(struct eth_device *dev) if (!mdiodev) return -ENOMEM; - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); + strncpy(mdiodev->name, priv->dev.name, MDIO_NAME_LEN); mdiodev->read = smc911x_miiphy_read; mdiodev->write = smc911x_miiphy_write; @@ -412,7 +427,7 @@ static int smc911x_initialize_mii(struct eth_device *dev) return 0; } #else -static int smc911x_initialize_mii(struct eth_device *dev) +static int smc911x_initialize_mii(struct smc911x_priv *priv) { return 0; } @@ -421,51 +436,52 @@ static int smc911x_initialize_mii(struct eth_device *dev) int smc911x_initialize(u8 dev_num, int base_addr) { unsigned long addrl, addrh; - struct eth_device *dev; + struct smc911x_priv *priv; int ret; - dev = calloc(1, sizeof(*dev)); - if (!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. */ - ret = smc911x_detect_chip(dev); + 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; } - dev->init = smc911x_init; - dev->halt = smc911x_halt; - dev->send = smc911x_send; - dev->recv = smc911x_recv; - 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); - ret = smc911x_initialize_mii(dev); + ret = smc911x_initialize_mii(priv); if (ret) goto err_mii; return 1; err_mii: - eth_unregister(dev); + eth_unregister(&priv->dev); err_detect: - free(dev); + free(priv); return ret; } -- cgit v1.3.1 From b11c8bbfafa998e90fe93ab4e9b08c1a4959bd65 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 17:02:05 +0100 Subject: net: smc911x: Clean up the status handling in smc911x_recv() Invert the status handling logic in smc911x_recv(), to make the function easier to read, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 07066ce1083..2d1a9e0f5a9 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -352,23 +352,25 @@ static int smc911x_recv(struct eth_device *dev) u32 pktlen, tmplen; u32 status; - if ((smc911x_reg_read(priv, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { - status = smc911x_reg_read(priv, 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(priv, 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++ = smc911x_reg_read(priv, 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); + else + net_process_received_packet(net_rx_packets[0], pktlen); return 0; } -- cgit v1.3.1 From 8eb4fef11b5420020518486ef0305aada0a02467 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 17:25:27 +0100 Subject: net: smc911x: Split non-DM specific bits from common code Split network handling functions into non-DM specific parts and common code in preparation for conversion to DM. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada Acked-by: Joe Hershberger --- drivers/net/smc911x.c | 57 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2d1a9e0f5a9..95f955f6d8a 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -277,9 +277,8 @@ static void smc911x_enable(struct smc911x_priv *priv) MAC_CR_HBDIS); } -static int smc911x_init(struct eth_device *dev, bd_t * bd) +static int smc911x_init_common(struct smc911x_priv *priv) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); const struct chip_id *id = priv->chipid; printf(DRIVERNAME ": detected %s controller\n", id->name); @@ -297,9 +296,9 @@ static int smc911x_init(struct eth_device *dev, bd_t * bd) 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) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); u32 *data = (u32*)packet; u32 tmplen; u32 status; @@ -337,18 +336,14 @@ 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) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); - smc911x_reset(priv); smc911x_handle_mac_address(priv); } -static int smc911x_recv(struct eth_device *dev) +static int smc911x_recv_common(struct smc911x_priv *priv, u32 *data) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); - u32 *data = (u32 *)net_rx_packets[0]; u32 pktlen, tmplen; u32 status; @@ -365,14 +360,14 @@ static int smc911x_recv(struct eth_device *dev) while (tmplen--) *data++ = smc911x_reg_read(priv, RX_DATA_FIFO); - if (status & RX_STS_ES) + 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); + return 0; + } - return 0; + return pktlen; } #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) @@ -435,6 +430,40 @@ static int smc911x_initialize_mii(struct smc911x_priv *priv) } #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; -- cgit v1.3.1 From 8148693b988fb36463dbc12cef4b7947acae9846 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 17:39:01 +0100 Subject: net: smc911x: Add DM support Add support for U-Boot DM and DT probing. Furthermore, build the SMC911x standalone EEPROM example only for the non-DM case, as it is not converted yet. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/Kconfig | 2 + drivers/net/smc911x.c | 115 +++++++++++++++++++++++++++++++++++++++++++ examples/standalone/Makefile | 5 +- 3 files changed, 121 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bc518f218da..a2587a29e16 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/smc911x.c b/drivers/net/smc911x.c index 95f955f6d8a..45ecd6a2633 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -21,7 +21,9 @@ struct chip_id { }; 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]; @@ -370,6 +372,8 @@ static int smc911x_recv_common(struct smc911x_priv *priv, u32 *data) 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, @@ -494,6 +498,7 @@ int smc911x_initialize(u8 dev_num, int base_addr) priv->enetaddr[3] = addrl >> 24; priv->enetaddr[4] = addrh; priv->enetaddr[5] = addrh >> 8; + memcpy(priv->dev.enetaddr, priv->enetaddr, 6); } priv->dev.init = smc911x_init; @@ -516,3 +521,113 @@ 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/examples/standalone/Makefile b/examples/standalone/Makefile index 779e2528b77..4a34813804f 100644 --- a/examples/standalone/Makefile +++ b/examples/standalone/Makefile @@ -5,10 +5,13 @@ extra-y := hello_world extra-$(CONFIG_SMC91111) += smc91111_eeprom -extra-$(CONFIG_SMC911X) += smc911x_eeprom extra-$(CONFIG_SPI_FLASH_ATMEL) += atmel_df_pow2 extra-$(CONFIG_PPC) += sched +ifndef CONFIG_DM_ETH +extra-$(CONFIG_SMC911X) += smc911x_eeprom +endif + # # Some versions of make do not handle trailing white spaces properly; # leading to build failures. The problem was found with GNU Make 3.80. -- cgit v1.3.1 From b8a42e0fcb94b335e0661ff4d2366ee3edf7f883 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 1 May 2020 15:24:50 +0200 Subject: rtc: pcf2127: don't add/subtract 1 to tm_mon As noted in rtc_def.h, the tm_mon field in struct rtc_time is 1-12, unlike in struct tm where it is 0-11. Currently, running "date" prints the wrong Date: 2020-04-01 (Friday) Time: 13:05:30 and setting the RTC via the date command is also broken. Signed-off-by: Rasmus Villemoes --- drivers/rtc/pcf2127.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/pcf2127.c b/drivers/rtc/pcf2127.c index f6953505a5a..b34ed63bf05 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 */ -- cgit v1.3.1 From 6609d123ce48ca5d46bb1c8e285fe009acf491ca Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Sun, 26 Apr 2020 01:17:44 +0200 Subject: timer MediaTek use upstream compatible The timers compatible string in upstream is called mt6577-timer. Add this compatible to the driver. Signed-off-by: Matthias Brugger --- drivers/timer/mtk_timer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/timer/mtk_timer.c b/drivers/timer/mtk_timer.c index b5e76bd3586..e99135e5bec 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" }, { } }; -- cgit v1.3.1 From 2ef35fcb34b97fefc693f638be2ad18be3298d08 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Sun, 26 Apr 2020 01:17:45 +0200 Subject: watchdog MediaTek add upstream compatible The upstream compatible is called mt6589-wdt. Add this compatible to the driver. Signed-off-by: Matthias Brugger --- drivers/watchdog/mtk_wdt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 669a32320d4..b3c597e1d03 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"}, {} }; -- cgit v1.3.1 From 89b84b85e9c5d80e1b5eb5b52cc6596ba32135c7 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:09 +0200 Subject: dm: core: Add function to get child count of ofnode or device This patch add function used to get the child count of a ofnode or a device Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao Reviewed-by: Simon Glass --- drivers/core/ofnode.c | 11 +++++++++++ drivers/core/read.c | 5 +++++ include/dm/ofnode.h | 8 ++++++++ include/dm/read.h | 13 +++++++++++++ 4 files changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 20871a68155..e3c42dae5c6 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -474,6 +474,17 @@ ofnode ofnode_get_chosen_node(const char *name) return ofnode_path(prop); } +int ofnode_get_child_count(ofnode parent) +{ + ofnode child; + int num = 0; + + ofnode_for_each_subnode(child, parent) + num++; + + return num; +} + static int decode_timing_property(ofnode node, const char *name, struct timing_entry *result) { diff --git a/drivers/core/read.c b/drivers/core/read.c index 47b8e034465..3d421f7a69c 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -352,3 +352,8 @@ fdt_addr_t dev_read_addr_pci(const struct udevice *dev) return addr; } + +int dev_get_child_count(const struct udevice *dev) +{ + return ofnode_get_child_count(dev_ofnode(dev)); +} diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 618fc10390e..a0d3df77868 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -879,6 +879,14 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname, ofnode_valid(node); \ node = ofnode_next_subnode(node)) +/** + * ofnode_get_child_count() - get the child count of a ofnode + * + * @node: valid node to get its child count + * @return the number of subnodes + */ +int ofnode_get_child_count(ofnode parent); + /** * ofnode_translate_address() - Translate a device-tree address * diff --git a/include/dm/read.h b/include/dm/read.h index 03c15b85506..b952551d555 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -669,6 +669,14 @@ u64 dev_translate_dma_address(const struct udevice *dev, */ int dev_read_alias_highest_id(const char *stem); +/** + * dev_get_child_count() - get the child count of a device + * + * @dev: device to use for interation (struct udevice *) + * @return the count of child subnode + */ +int dev_get_child_count(const struct udevice *dev); + #else /* CONFIG_DM_DEV_READ_INLINE is enabled */ static inline int dev_read_u32(const struct udevice *dev, @@ -978,6 +986,11 @@ static inline int dev_read_alias_highest_id(const char *stem) return fdtdec_get_alias_highest_id(gd->fdt_blob, stem); } +static inline int dev_get_child_count(const struct udevice *dev) +{ + return ofnode_get_child_count(dev_ofnode(dev)); +} + #endif /* CONFIG_DM_DEV_READ_INLINE */ /** -- cgit v1.3.1 From b13307b470f4fdfad42aa4c1adcaf1960837d0c4 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:11 +0200 Subject: phy: Add API for a bulk of phys This patch adds a "bulk" API to the phy API in order to get/init/exit/power on/off a group of phys associated with a device. The bulk API will avoid adding a copy of the same code to manage a group of phys in drivers. Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao Reviewed-by: Jagan Teki --- drivers/phy/phy-uclass.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ include/generic-phy.h | 92 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) (limited to 'drivers') diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index e463b0b400e..6ab78448af3 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -6,6 +6,7 @@ #include #include +#include #include static inline struct phy_ops *phy_dev_ops(struct udevice *dev) @@ -167,6 +168,102 @@ int generic_phy_power_off(struct phy *phy) return ops->power_off ? ops->power_off(phy) : 0; } +int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + int i, ret, count; + + bulk->count = 0; + + /* Return if no phy declared */ + if (!dev_read_prop(dev, "phys", NULL)) + return 0; + + count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); + if (count < 1) + return count; + + bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL); + if (!bulk->phys) + return -ENOMEM; + + for (i = 0; i < count; i++) { + ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]); + if (ret) { + pr_err("Failed to get PHY%d for %s\n", i, dev->name); + return ret; + } + bulk->count++; + } + + return 0; +} + +int generic_phy_init_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = generic_phy_init(&phys[i]); + if (ret) { + pr_err("Can't init PHY%d\n", i); + goto phys_init_err; + } + } + + return 0; + +phys_init_err: + for (; i > 0; i--) + generic_phy_exit(&phys[i - 1]); + + return ret; +} + +int generic_phy_exit_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret = 0; + + for (i = 0; i < bulk->count; i++) + ret |= generic_phy_exit(&phys[i]); + + return ret; +} + +int generic_phy_power_on_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = generic_phy_power_on(&phys[i]); + if (ret) { + pr_err("Can't power on PHY%d\n", i); + goto phys_poweron_err; + } + } + + return 0; + +phys_poweron_err: + for (; i > 0; i--) + generic_phy_power_off(&phys[i - 1]); + + return ret; +} + +int generic_phy_power_off_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret = 0; + + for (i = 0; i < bulk->count; i++) + ret |= generic_phy_power_off(&phys[i]); + + return ret; +} + UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index 73537025c2c..55629ae0b41 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -124,6 +124,23 @@ struct phy_ops { int (*power_off)(struct phy *phy); }; +/** + * struct phy_bulk - A handle to (allowing control of) a bulk of phys. + * + * Consumers provide storage for the phy bulk. The content of the structure is + * managed solely by the phy API. A phy bulk struct is initialized + * by "get"ing the phy bulk struct. + * The phy bulk struct is passed to all other bulk phy APIs to apply + * the API to all the phy in the bulk struct. + * + * @phys: An array of phy handles. + * @count: The number of phy handles in the phys array. + */ +struct phy_bulk { + struct phy *phys; + unsigned int count; +}; + #ifdef CONFIG_PHY /** @@ -250,6 +267,55 @@ int generic_phy_get_by_node(ofnode node, int index, struct phy *phy); int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy); +/** + * generic_phy_get_bulk - Get all phys of a device. + * + * This looks up and gets all phys of the consumer device; each device is + * assumed to have n phys associated with it somehow, and this function finds + * and gets all of them in a separate structure. + * + * @dev: The consumer device. + * @bulk A pointer to a phy bulk struct to initialize. + * @return 0 if OK, or a negative error code. + */ +int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk); + +/** + * generic_phy_init_bulk() - Initialize all phys in a phy bulk struct. + * + * @bulk: A phy bulk struct that was previously successfully requested + * by generic_phy_get_bulk(). + * @return 0 if OK, or negative error code. + */ +int generic_phy_init_bulk(struct phy_bulk *bulk); + +/** + * generic_phy_exit_bulk() - de-initialize all phys in a phy bulk struct. + * + * @bulk: A phy bulk struct that was previously successfully requested + * by generic_phy_get_bulk(). + * @return 0 if OK, or negative error code. + */ +int generic_phy_exit_bulk(struct phy_bulk *bulk); + +/** + * generic_phy_power_on_bulk() - Power on all phys in a phy bulk struct. + * + * @bulk: A phy bulk struct that was previously successfully requested + * by generic_phy_get_bulk(). + * @return 0 if OK, or negative error code. + */ +int generic_phy_power_on_bulk(struct phy_bulk *bulk); + +/** + * generic_phy_power_off_bulk() - Power off all phys in a phy bulk struct. + * + * @bulk: A phy bulk struct that was previously successfully requested + * by generic_phy_get_bulk(). + * @return 0 if OK, or negative error code. + */ +int generic_phy_power_off_bulk(struct phy_bulk *bulk); + #else /* CONFIG_PHY */ static inline int generic_phy_init(struct phy *phy) @@ -289,6 +355,32 @@ static inline int generic_phy_get_by_name(struct udevice *user, const char *phy_ return 0; } +static inline int +generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + return 0; +} + +static inline int generic_phy_init_bulk(struct phy_bulk *bulk) +{ + return 0; +} + +static inline int generic_phy_exit_bulk(struct phy_bulk *bulk) +{ + return 0; +} + +static inline int generic_phy_power_on_bulk(struct phy_bulk *bulk) +{ + return 0; +} + +static inline int generic_phy_power_off_bulk(struct phy_bulk *bulk) +{ + return 0; +} + #endif /* CONFIG_PHY */ /** -- cgit v1.3.1 From 6dfb8a8052ee024fd20150b558477ab5c3e6f0f9 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:13 +0200 Subject: usb: dwc3: use the phy bulk API to get phys Get a group of phys by the phy bulk API Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao --- drivers/usb/dwc3/core.c | 87 ++++++++--------------------------------- drivers/usb/dwc3/dwc3-generic.c | 7 ++-- drivers/usb/host/xhci-dwc3.c | 7 ++-- include/dwc3-uboot.h | 11 +++--- 4 files changed, 27 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4ec3f6df6a9..a8982bdc094 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -838,87 +838,32 @@ MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); #if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) -int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys) +int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys) { - int i, ret, count; - struct phy *usb_phys; - - /* Return if no phy declared */ - if (!dev_read_prop(dev, "phys", NULL)) - return 0; - count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); - if (count <= 0) - return count; - - usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), - GFP_KERNEL); - if (!usb_phys) - return -ENOMEM; - - for (i = 0; i < count; i++) { - ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); - if (ret && ret != -ENOENT) { - pr_err("Failed to get USB PHY%d for %s\n", - i, dev->name); - return ret; - } - } - - for (i = 0; i < count; i++) { - ret = generic_phy_init(&usb_phys[i]); - if (ret) { - pr_err("Can't init USB PHY%d for %s\n", - i, dev->name); - goto phys_init_err; - } - } - - for (i = 0; i < count; i++) { - ret = generic_phy_power_on(&usb_phys[i]); - if (ret) { - pr_err("Can't power USB PHY%d for %s\n", - i, dev->name); - goto phys_poweron_err; - } - } - - *array = usb_phys; - *num_phys = count; - return 0; - -phys_poweron_err: - for (i = count - 1; i >= 0; i--) - generic_phy_power_off(&usb_phys[i]); + int ret; - for (i = 0; i < count; i++) - generic_phy_exit(&usb_phys[i]); + ret = generic_phy_get_bulk(dev, phys); + if (ret) + return ret; - return ret; + ret = generic_phy_init_bulk(phys); + if (ret) + return ret; -phys_init_err: - for (; i >= 0; i--) - generic_phy_exit(&usb_phys[i]); + ret = generic_phy_power_on_bulk(phys); + if (ret) + generic_phy_exit_bulk(phys); return ret; } -int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys) +int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys) { - int i, ret; - - for (i = 0; i < num_phys; i++) { - if (!generic_phy_valid(&usb_phys[i])) - continue; - - ret = generic_phy_power_off(&usb_phys[i]); - ret |= generic_phy_exit(&usb_phys[i]); - if (ret) { - pr_err("Can't shutdown USB PHY%d for %s\n", - i, dev->name); - } - } + int ret; - return 0; + ret = generic_phy_power_off_bulk(phys); + ret |= generic_phy_exit_bulk(phys); + return ret; } #endif diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index febcfc0f54c..eabd53a36dc 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -33,8 +33,7 @@ struct dwc3_generic_plat { struct dwc3_generic_priv { void *base; struct dwc3 dwc3; - struct phy *phys; - int num_phys; + struct phy_bulk phys; }; struct dwc3_generic_host_priv { @@ -56,7 +55,7 @@ static int dwc3_generic_probe(struct udevice *dev, dwc3_of_parse(dwc3); #endif - rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys); + rc = dwc3_setup_phy(dev, &priv->phys); if (rc) return rc; @@ -79,7 +78,7 @@ static int dwc3_generic_remove(struct udevice *dev, struct dwc3 *dwc3 = &priv->dwc3; dwc3_remove(dwc3); - dwc3_shutdown_phy(dev, priv->phys, priv->num_phys); + dwc3_shutdown_phy(dev, &priv->phys); unmap_physmem(dwc3->regs, MAP_NOCACHE); return 0; diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 9fcfa39d4b5..563db1a4260 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -19,8 +19,7 @@ #include struct xhci_dwc3_platdata { - struct phy *usb_phys; - int num_phys; + struct phy_bulk *usb_phys; }; void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) @@ -125,7 +124,7 @@ static int xhci_dwc3_probe(struct udevice *dev) hcor = (struct xhci_hcor *)((uintptr_t)hccr + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); - ret = dwc3_setup_phy(dev, &plat->usb_phys, &plat->num_phys); + ret = dwc3_setup_phy(dev, plat->usb_phys); if (ret && (ret != -ENOTSUPP)) return ret; @@ -168,7 +167,7 @@ static int xhci_dwc3_remove(struct udevice *dev) { struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); - dwc3_shutdown_phy(dev, plat->usb_phys, plat->num_phys); + dwc3_shutdown_phy(dev, plat->usb_phys); return xhci_deregister(dev); } diff --git a/include/dwc3-uboot.h b/include/dwc3-uboot.h index 3c9e204cf07..ce835fd1b2b 100644 --- a/include/dwc3-uboot.h +++ b/include/dwc3-uboot.h @@ -9,6 +9,7 @@ #ifndef __DWC3_UBOOT_H_ #define __DWC3_UBOOT_H_ +#include #include #include @@ -43,17 +44,15 @@ void dwc3_uboot_handle_interrupt(int index); struct phy; #if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) -int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys); -int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys); +int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys); +int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys); #else -static inline int dwc3_setup_phy(struct udevice *dev, struct phy **array, - int *num_phys) +static inline int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys) { return -ENOTSUPP; } -static inline int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, - int num_phys) +static inline int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys) { return -ENOTSUPP; } -- cgit v1.3.1 From cf67e451790aca04a969265495bb2a3ca1cbf47a Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:14 +0200 Subject: usb: dwc2_udc_otg: use the phy bulk API to get phys Use the phy bulk API to get a group of phys Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao --- drivers/usb/gadget/dwc2_udc_otg.c | 93 +++++++-------------------------------- 1 file changed, 17 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index b9c814cf73e..9f21af2923d 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -943,8 +943,7 @@ int usb_gadget_handle_interrupts(int index) struct dwc2_priv_data { struct clk_bulk clks; struct reset_ctl_bulk resets; - struct phy *phys; - int num_phys; + struct phy_bulk phys; struct udevice *usb33d_supply; }; @@ -953,87 +952,29 @@ int dm_usb_gadget_handle_interrupts(struct udevice *dev) return dwc2_udc_handle_interrupt(); } -int dwc2_phy_setup(struct udevice *dev, struct phy **array, int *num_phys) +static int dwc2_phy_setup(struct udevice *dev, struct phy_bulk *phys) { - int i, ret, count; - struct phy *usb_phys; - - /* Return if no phy declared */ - if (!dev_read_prop(dev, "phys", NULL)) - return 0; - - count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); - if (count <= 0) - return count; - - usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), - GFP_KERNEL); - if (!usb_phys) - return -ENOMEM; - - for (i = 0; i < count; i++) { - ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); - if (ret && ret != -ENOENT) { - dev_err(dev, "Failed to get USB PHY%d for %s\n", - i, dev->name); - return ret; - } - } - - for (i = 0; i < count; i++) { - ret = generic_phy_init(&usb_phys[i]); - if (ret) { - dev_err(dev, "Can't init USB PHY%d for %s\n", - i, dev->name); - goto phys_init_err; - } - } - - for (i = 0; i < count; i++) { - ret = generic_phy_power_on(&usb_phys[i]); - if (ret) { - dev_err(dev, "Can't power USB PHY%d for %s\n", - i, dev->name); - goto phys_poweron_err; - } - } - - *array = usb_phys; - *num_phys = count; - - return 0; - -phys_poweron_err: - for (i = count - 1; i >= 0; i--) - generic_phy_power_off(&usb_phys[i]); + int ret; - for (i = 0; i < count; i++) - generic_phy_exit(&usb_phys[i]); + ret = generic_phy_get_bulk(dev, phys); + if (ret) + return ret; - return ret; + ret = generic_phy_init_bulk(phys); + if (ret) + return ret; -phys_init_err: - for (; i >= 0; i--) - generic_phy_exit(&usb_phys[i]); + ret = generic_phy_power_on_bulk(phys); + if (ret) + generic_phy_exit_bulk(phys); return ret; } -void dwc2_phy_shutdown(struct udevice *dev, struct phy *usb_phys, int num_phys) +static void dwc2_phy_shutdown(struct udevice *dev, struct phy_bulk *phys) { - int i, ret; - - for (i = 0; i < num_phys; i++) { - if (!generic_phy_valid(&usb_phys[i])) - continue; - - ret = generic_phy_power_off(&usb_phys[i]); - ret |= generic_phy_exit(&usb_phys[i]); - if (ret) { - dev_err(dev, "Can't shutdown USB PHY%d for %s\n", - i, dev->name); - } - } + generic_phy_power_off_bulk(phys); + generic_phy_exit_bulk(phys); } static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev) @@ -1158,7 +1099,7 @@ static int dwc2_udc_otg_probe(struct udevice *dev) if (ret) return ret; - ret = dwc2_phy_setup(dev, &priv->phys, &priv->num_phys); + ret = dwc2_phy_setup(dev, &priv->phys); if (ret) return ret; @@ -1208,7 +1149,7 @@ static int dwc2_udc_otg_remove(struct udevice *dev) clk_release_bulk(&priv->clks); - dwc2_phy_shutdown(dev, priv->phys, priv->num_phys); + dwc2_phy_shutdown(dev, &priv->phys); return dm_scan_fdt_dev(dev); } -- cgit v1.3.1 From ee6eabbedda47b4cff68861e34c21d992a4586e2 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:15 +0200 Subject: phy: phy-mtk-tphy: add support USB phys Support USB2 and USB3 PHY with shared banks when support multi-phys Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao --- drivers/phy/phy-mtk-tphy.c | 227 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 218 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-mtk-tphy.c b/drivers/phy/phy-mtk-tphy.c index bd089b7a435..71bc706c6e9 100644 --- a/drivers/phy/phy-mtk-tphy.c +++ b/drivers/phy/phy-mtk-tphy.c @@ -20,11 +20,66 @@ /* version V1 sub-banks offset base address */ /* banks shared by multiple phys */ #define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */ +#define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */ #define SSUSB_SIFSLV_V1_CHIP 0x300 /* shared by u3 phys */ +/* u2 phy bank */ +#define SSUSB_SIFSLV_V1_U2PHY_COM 0x000 /* u3/pcie/sata phy banks */ #define SSUSB_SIFSLV_V1_U3PHYD 0x000 #define SSUSB_SIFSLV_V1_U3PHYA 0x200 +#define U3P_USBPHYACR0 0x000 +#define PA0_RG_U2PLL_FORCE_ON BIT(15) +#define PA0_RG_USB20_INTR_EN BIT(5) + +#define U3P_USBPHYACR5 0x014 +#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15) +#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12) +#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12) +#define PA5_RG_U2_HS_100U_U3_EN BIT(11) + +#define U3P_USBPHYACR6 0x018 +#define PA6_RG_U2_BC11_SW_EN BIT(23) +#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20) +#define PA6_RG_U2_SQTH GENMASK(3, 0) +#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x)) + +#define U3P_U2PHYACR4 0x020 +#define P2C_RG_USB20_GPIO_CTL BIT(9) +#define P2C_USB20_GPIO_MODE BIT(8) +#define P2C_U2_GPIO_CTR_MSK \ + (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE) + +#define U3P_U2PHYDTM0 0x068 +#define P2C_FORCE_UART_EN BIT(26) +#define P2C_FORCE_DATAIN BIT(23) +#define P2C_FORCE_DM_PULLDOWN BIT(21) +#define P2C_FORCE_DP_PULLDOWN BIT(20) +#define P2C_FORCE_XCVRSEL BIT(19) +#define P2C_FORCE_SUSPENDM BIT(18) +#define P2C_FORCE_TERMSEL BIT(17) +#define P2C_RG_DATAIN GENMASK(13, 10) +#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10) +#define P2C_RG_DMPULLDOWN BIT(7) +#define P2C_RG_DPPULLDOWN BIT(6) +#define P2C_RG_XCVRSEL GENMASK(5, 4) +#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4) +#define P2C_RG_SUSPENDM BIT(3) +#define P2C_RG_TERMSEL BIT(2) +#define P2C_DTM0_PART_MASK \ + (P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \ + P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \ + P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \ + P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL) + +#define U3P_U2PHYDTM1 0x06C +#define P2C_RG_UART_EN BIT(16) +#define P2C_FORCE_IDDIG BIT(9) +#define P2C_RG_VBUSVALID BIT(5) +#define P2C_RG_SESSEND BIT(4) +#define P2C_RG_AVALID BIT(2) +#define P2C_RG_IDDIG BIT(1) + #define U3P_U3_CHIP_GPIO_CTLD 0x0c #define P3C_REG_IP_SW_RST BIT(31) #define P3C_MCU_BUS_CK_GATE_EN BIT(30) @@ -42,6 +97,14 @@ #define P3A_RG_CLKDRV_AMP GENMASK(31, 29) #define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29) +#define U3P_U3_PHYA_REG6 0x018 +#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28) +#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28) + +#define U3P_U3_PHYA_REG9 0x024 +#define P3A_RG_RX_DAC_MUX GENMASK(5, 1) +#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1) + #define U3P_U3_PHYA_DA_REG0 0x100 #define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16) #define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16) @@ -77,6 +140,16 @@ #define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0) #define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x)) +#define U3P_U3_PHYD_LFPS1 0x00c +#define P3D_RG_FWAKE_TH GENMASK(21, 16) +#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16) + +#define U3P_U3_PHYD_CDR1 0x05c +#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24) +#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24) +#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8) +#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8) + #define U3P_U3_PHYD_RXDET1 0x128 #define P3D_RG_RXDET_STB2_SET GENMASK(17, 9) #define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9) @@ -85,6 +158,16 @@ #define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0) #define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x)) +#define U3P_SPLLC_XTALCTL3 0x018 +#define XC3_RG_U3_XTAL_RX_PWD BIT(9) +#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8) + +struct u2phy_banks { + void __iomem *misc; + void __iomem *fmreg; + void __iomem *com; +}; + struct u3phy_banks { void __iomem *spllc; void __iomem *chip; @@ -95,21 +178,127 @@ struct u3phy_banks { struct mtk_phy_instance { void __iomem *port_base; const struct device_node *np; - - struct u3phy_banks u3_banks; + union { + struct u2phy_banks u2_banks; + struct u3phy_banks u3_banks; + }; /* reference clock of anolog phy */ struct clk ref_clk; u32 index; - u8 type; + u32 type; }; struct mtk_tphy { + struct udevice *dev; void __iomem *sif_base; struct mtk_phy_instance **phys; int nphys; }; +static void u2_phy_instance_init(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) +{ + struct u2phy_banks *u2_banks = &instance->u2_banks; + + /* switch to USB function, and enable usb pll */ + clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM0, + P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM, + P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0)); + + clrbits_le32(u2_banks->com + U3P_U2PHYDTM1, P2C_RG_UART_EN); + setbits_le32(u2_banks->com + U3P_USBPHYACR0, PA0_RG_USB20_INTR_EN); + + /* disable switch 100uA current to SSUSB */ + clrbits_le32(u2_banks->com + U3P_USBPHYACR5, PA5_RG_U2_HS_100U_U3_EN); + + clrbits_le32(u2_banks->com + U3P_U2PHYACR4, P2C_U2_GPIO_CTR_MSK); + + /* DP/DM BC1.1 path Disable */ + clrsetbits_le32(u2_banks->com + U3P_USBPHYACR6, + PA6_RG_U2_BC11_SW_EN | PA6_RG_U2_SQTH, + PA6_RG_U2_SQTH_VAL(2)); + + /* set HS slew rate */ + clrsetbits_le32(u2_banks->com + U3P_USBPHYACR5, + PA5_RG_U2_HSTX_SRCTRL, PA5_RG_U2_HSTX_SRCTRL_VAL(4)); + + dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); +} + +static void u2_phy_instance_power_on(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) +{ + struct u2phy_banks *u2_banks = &instance->u2_banks; + + clrbits_le32(u2_banks->com + U3P_U2PHYDTM0, + P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK); + + /* OTG Enable */ + setbits_le32(u2_banks->com + U3P_USBPHYACR6, + PA6_RG_U2_OTG_VBUSCMP_EN); + + clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM1, + P2C_RG_SESSEND, P2C_RG_VBUSVALID | P2C_RG_AVALID); + + dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); +} + +static void u2_phy_instance_power_off(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) +{ + struct u2phy_banks *u2_banks = &instance->u2_banks; + + clrbits_le32(u2_banks->com + U3P_U2PHYDTM0, + P2C_RG_XCVRSEL | P2C_RG_DATAIN); + + /* OTG Disable */ + clrbits_le32(u2_banks->com + U3P_USBPHYACR6, + PA6_RG_U2_OTG_VBUSCMP_EN); + + clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM1, + P2C_RG_VBUSVALID | P2C_RG_AVALID, P2C_RG_SESSEND); + + dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); +} + +static void u3_phy_instance_init(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) +{ + struct u3phy_banks *u3_banks = &instance->u3_banks; + + /* gating PCIe Analog XTAL clock */ + setbits_le32(u3_banks->spllc + U3P_SPLLC_XTALCTL3, + XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD); + + /* gating XSQ */ + clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0, + P3A_RG_XTAL_EXT_EN_U3, P3A_RG_XTAL_EXT_EN_U3_VAL(2)); + + clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG9, + P3A_RG_RX_DAC_MUX, P3A_RG_RX_DAC_MUX_VAL(4)); + + clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG6, + P3A_RG_TX_EIDLE_CM, P3A_RG_TX_EIDLE_CM_VAL(0xe)); + + clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_CDR1, + P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1, + P3D_RG_CDR_BIR_LTD0_VAL(0xc) | + P3D_RG_CDR_BIR_LTD1_VAL(0x3)); + + clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_LFPS1, + P3D_RG_FWAKE_TH, P3D_RG_FWAKE_TH_VAL(0x34)); + + clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET1, + P3D_RG_RXDET_STB2_SET, P3D_RG_RXDET_STB2_SET_VAL(0x10)); + + clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET2, + P3D_RG_RXDET_STB2_SET_P3, + P3D_RG_RXDET_STB2_SET_P3_VAL(0x10)); + + dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); +} + static void pcie_phy_instance_init(struct mtk_tphy *tphy, struct mtk_phy_instance *instance) { @@ -187,9 +376,16 @@ static void pcie_phy_instance_power_off(struct mtk_tphy *tphy, static void phy_v1_banks_init(struct mtk_tphy *tphy, struct mtk_phy_instance *instance) { + struct u2phy_banks *u2_banks = &instance->u2_banks; struct u3phy_banks *u3_banks = &instance->u3_banks; switch (instance->type) { + case PHY_TYPE_USB2: + u2_banks->misc = NULL; + u2_banks->fmreg = tphy->sif_base + SSUSB_SIFSLV_V1_U2FREQ; + u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM; + break; + case PHY_TYPE_USB3: case PHY_TYPE_PCIE: u3_banks->spllc = tphy->sif_base + SSUSB_SIFSLV_V1_SPLLC; u3_banks->chip = tphy->sif_base + SSUSB_SIFSLV_V1_CHIP; @@ -197,6 +393,7 @@ static void phy_v1_banks_init(struct mtk_tphy *tphy, u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA; break; default: + dev_err(tphy->dev, "incompatible PHY type\n"); return; } } @@ -212,10 +409,17 @@ static int mtk_phy_init(struct phy *phy) return ret; switch (instance->type) { + case PHY_TYPE_USB2: + u2_phy_instance_init(tphy, instance); + break; + case PHY_TYPE_USB3: + u3_phy_instance_init(tphy, instance); + break; case PHY_TYPE_PCIE: pcie_phy_instance_init(tphy, instance); break; default: + dev_err(tphy->dev, "incompatible PHY type\n"); return -EINVAL; } @@ -227,7 +431,10 @@ static int mtk_phy_power_on(struct phy *phy) struct mtk_tphy *tphy = dev_get_priv(phy->dev); struct mtk_phy_instance *instance = tphy->phys[phy->id]; - pcie_phy_instance_power_on(tphy, instance); + if (instance->type == PHY_TYPE_USB2) + u2_phy_instance_power_on(tphy, instance); + else if (instance->type == PHY_TYPE_PCIE) + pcie_phy_instance_power_on(tphy, instance); return 0; } @@ -237,7 +444,10 @@ static int mtk_phy_power_off(struct phy *phy) struct mtk_tphy *tphy = dev_get_priv(phy->dev); struct mtk_phy_instance *instance = tphy->phys[phy->id]; - pcie_phy_instance_power_off(tphy, instance); + if (instance->type == PHY_TYPE_USB2) + u2_phy_instance_power_off(tphy, instance); + else if (instance->type == PHY_TYPE_PCIE) + pcie_phy_instance_power_off(tphy, instance); return 0; } @@ -285,8 +495,7 @@ static int mtk_phy_xlate(struct phy *phy, instance->type = args->args[1]; if (!(instance->type == PHY_TYPE_USB2 || instance->type == PHY_TYPE_USB3 || - instance->type == PHY_TYPE_PCIE || - instance->type == PHY_TYPE_SATA)) { + instance->type == PHY_TYPE_PCIE)) { dev_err(phy->dev, "unsupported device type\n"); return -EINVAL; } @@ -310,14 +519,14 @@ static int mtk_tphy_probe(struct udevice *dev) ofnode subnode; int index = 0; - dev_for_each_subnode(subnode, dev) - tphy->nphys++; + tphy->nphys = dev_get_child_count(dev); tphy->phys = devm_kcalloc(dev, tphy->nphys, sizeof(*tphy->phys), GFP_KERNEL); if (!tphy->phys) return -ENOMEM; + tphy->dev = dev; tphy->sif_base = dev_read_addr_ptr(dev); if (!tphy->sif_base) return -ENOENT; -- cgit v1.3.1 From d1ae8445adf7b84e948e9f09f728254922b7afa4 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:16 +0200 Subject: phy: phy-mtk-tphy: add support new version The new version removes all shared banks between multi-phys Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao --- drivers/phy/phy-mtk-tphy.c | 68 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-mtk-tphy.c b/drivers/phy/phy-mtk-tphy.c index 71bc706c6e9..20167fe7cb9 100644 --- a/drivers/phy/phy-mtk-tphy.c +++ b/drivers/phy/phy-mtk-tphy.c @@ -28,6 +28,17 @@ #define SSUSB_SIFSLV_V1_U3PHYD 0x000 #define SSUSB_SIFSLV_V1_U3PHYA 0x200 +/* version V2 sub-banks offset base address */ +/* u2 phy banks */ +#define SSUSB_SIFSLV_V2_MISC 0x000 +#define SSUSB_SIFSLV_V2_U2FREQ 0x100 +#define SSUSB_SIFSLV_V2_U2PHY_COM 0x300 +/* u3/pcie/sata phy banks */ +#define SSUSB_SIFSLV_V2_SPLLC 0x000 +#define SSUSB_SIFSLV_V2_CHIP 0x100 +#define SSUSB_SIFSLV_V2_U3PHYD 0x200 +#define SSUSB_SIFSLV_V2_U3PHYA 0x400 + #define U3P_USBPHYACR0 0x000 #define PA0_RG_U2PLL_FORCE_ON BIT(15) #define PA0_RG_USB20_INTR_EN BIT(5) @@ -162,6 +173,11 @@ #define XC3_RG_U3_XTAL_RX_PWD BIT(9) #define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8) +enum mtk_phy_version { + MTK_TPHY_V1 = 1, + MTK_TPHY_V2, +}; + struct u2phy_banks { void __iomem *misc; void __iomem *fmreg; @@ -192,6 +208,7 @@ struct mtk_phy_instance { struct mtk_tphy { struct udevice *dev; void __iomem *sif_base; + enum mtk_phy_version version; struct mtk_phy_instance **phys; int nphys; }; @@ -304,6 +321,9 @@ static void pcie_phy_instance_init(struct mtk_tphy *tphy, { struct u3phy_banks *u3_banks = &instance->u3_banks; + if (tphy->version != MTK_TPHY_V1) + return; + clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0, P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H, P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | @@ -398,6 +418,31 @@ static void phy_v1_banks_init(struct mtk_tphy *tphy, } } +static void phy_v2_banks_init(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) +{ + struct u2phy_banks *u2_banks = &instance->u2_banks; + struct u3phy_banks *u3_banks = &instance->u3_banks; + + switch (instance->type) { + case PHY_TYPE_USB2: + u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC; + u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ; + u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM; + break; + case PHY_TYPE_USB3: + case PHY_TYPE_PCIE: + u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC; + u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP; + u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD; + u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA; + break; + default: + dev_err(tphy->dev, "incompatible PHY type\n"); + return; + } +} + static int mtk_phy_init(struct phy *phy) { struct mtk_tphy *tphy = dev_get_priv(phy->dev); @@ -500,7 +545,14 @@ static int mtk_phy_xlate(struct phy *phy, return -EINVAL; } - phy_v1_banks_init(tphy, instance); + if (tphy->version == MTK_TPHY_V1) { + phy_v1_banks_init(tphy, instance); + } else if (tphy->version == MTK_TPHY_V2) { + phy_v2_banks_init(tphy, instance); + } else { + dev_err(phy->dev, "phy version is not supported\n"); + return -EINVAL; + } return 0; } @@ -527,9 +579,14 @@ static int mtk_tphy_probe(struct udevice *dev) return -ENOMEM; tphy->dev = dev; - tphy->sif_base = dev_read_addr_ptr(dev); - if (!tphy->sif_base) - return -ENOENT; + tphy->version = dev_get_driver_data(dev); + + /* v1 has shared banks */ + if (tphy->version == MTK_TPHY_V1) { + tphy->sif_base = dev_read_addr_ptr(dev); + if (!tphy->sif_base) + return -ENOENT; + } dev_for_each_subnode(subnode, dev) { struct mtk_phy_instance *instance; @@ -560,7 +617,8 @@ static int mtk_tphy_probe(struct udevice *dev) } static const struct udevice_id mtk_tphy_id_table[] = { - { .compatible = "mediatek,generic-tphy-v1", }, + { .compatible = "mediatek,generic-tphy-v1", .data = MTK_TPHY_V1, }, + { .compatible = "mediatek,generic-tphy-v2", .data = MTK_TPHY_V2, }, { } }; -- cgit v1.3.1 From 4d4abbd783688f08da2e3e525d19917744d75a81 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:17 +0200 Subject: phy: phy-mtk-tphy: add a new reference clock Usually the digital and analog phys use the same reference clock, but some platforms have two separate reference clocks for each of them, so add another optional clock to support them. In order to keep the clock names consistent with PHY IP's, change the da_ref for analog phy and ref clock for digital phy. Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao --- drivers/phy/phy-mtk-tphy.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-mtk-tphy.c b/drivers/phy/phy-mtk-tphy.c index 20167fe7cb9..81525a48b70 100644 --- a/drivers/phy/phy-mtk-tphy.c +++ b/drivers/phy/phy-mtk-tphy.c @@ -199,8 +199,8 @@ struct mtk_phy_instance { struct u3phy_banks u3_banks; }; - /* reference clock of anolog phy */ - struct clk ref_clk; + struct clk ref_clk; /* reference clock of (digital) phy */ + struct clk da_ref_clk; /* reference clock of analog phy */ u32 index; u32 type; }; @@ -450,8 +450,17 @@ static int mtk_phy_init(struct phy *phy) int ret; ret = clk_enable(&instance->ref_clk); - if (ret) + if (ret < 0) { + dev_err(tphy->dev, "failed to enable ref_clk\n"); return ret; + } + + ret = clk_enable(&instance->da_ref_clk); + if (ret < 0) { + dev_err(tphy->dev, "failed to enable da_ref_clk %d\n", ret); + clk_disable(&instance->ref_clk); + return ret; + } switch (instance->type) { case PHY_TYPE_USB2: @@ -502,6 +511,7 @@ static int mtk_phy_exit(struct phy *phy) struct mtk_tphy *tphy = dev_get_priv(phy->dev); struct mtk_phy_instance *instance = tphy->phys[phy->id]; + clk_disable(&instance->da_ref_clk); clk_disable(&instance->ref_clk); return 0; @@ -611,6 +621,11 @@ static int mtk_tphy_probe(struct udevice *dev) &instance->ref_clk); if (err) return err; + + err = clk_get_optional_nodev(subnode, "da_ref", + &instance->da_ref_clk); + if (err) + return err; } return 0; -- cgit v1.3.1 From 74102834154c2e575c14e050a62f63e2e52f96de Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Sat, 2 May 2020 11:35:18 +0200 Subject: xhci: mediatek: Add support for MTK xHCI host controller This patch is used to support the on-chip xHCI controller on MediaTek SoCs, currently control/bulk/interrupt transfers are supported. Signed-off-by: Chunfeng Yun Signed-off-by: Frank Wunderlich Reviewed-by: Weijie Gao Reviewed-by: Jagan Teki --- drivers/usb/host/Kconfig | 6 + drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-mtk.c | 303 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.c | 10 ++ include/usb/xhci.h | 3 + 5 files changed, 323 insertions(+) create mode 100644 drivers/usb/host/xhci-mtk.c (limited to 'drivers') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 94ac969058e..2f381dc9580 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -30,6 +30,12 @@ config USB_XHCI_DWC3_OF_SIMPLE Support USB2/3 functionality in simple SoC integrations with USB controller based on the DesignWare USB3 IP Core. +config USB_XHCI_MTK + bool "Support for MediaTek on-chip xHCI USB controller" + depends on ARCH_MEDIATEK + help + Enables support for the on-chip xHCI controller on MediaTek SoCs. + config USB_XHCI_MVEBU bool "MVEBU USB 3.0 support" default y diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index b62f346094f..e8e3b17e42c 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_XHCI_ROCKCHIP) += xhci-rockchip.o obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o +obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c new file mode 100644 index 00000000000..8ff71854fcd --- /dev/null +++ b/drivers/usb/host/xhci-mtk.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 MediaTek, Inc. + * Authors: Chunfeng Yun + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* IPPC (IP Port Control) registers */ +#define IPPC_IP_PW_CTRL0 0x00 +#define CTRL0_IP_SW_RST BIT(0) + +#define IPPC_IP_PW_CTRL1 0x04 +#define CTRL1_IP_HOST_PDN BIT(0) + +#define IPPC_IP_PW_STS1 0x10 +#define STS1_IP_SLEEP_STS BIT(30) +#define STS1_U3_MAC_RST BIT(16) +#define STS1_XHCI_RST BIT(11) +#define STS1_SYS125_RST BIT(10) +#define STS1_REF_RST BIT(8) +#define STS1_SYSPLL_STABLE BIT(0) + +#define IPPC_IP_XHCI_CAP 0x24 +#define CAP_U3_PORT_NUM(p) ((p) & 0xff) +#define CAP_U2_PORT_NUM(p) (((p) >> 8) & 0xff) + +#define IPPC_U3_CTRL_0P 0x30 +#define CTRL_U3_PORT_HOST_SEL BIT(2) +#define CTRL_U3_PORT_PDN BIT(1) +#define CTRL_U3_PORT_DIS BIT(0) + +#define IPPC_U2_CTRL_0P 0x50 +#define CTRL_U2_PORT_HOST_SEL BIT(2) +#define CTRL_U2_PORT_PDN BIT(1) +#define CTRL_U2_PORT_DIS BIT(0) + +#define IPPC_U3_CTRL(p) (IPPC_U3_CTRL_0P + ((p) * 0x08)) +#define IPPC_U2_CTRL(p) (IPPC_U2_CTRL_0P + ((p) * 0x08)) + +struct mtk_xhci { + struct xhci_ctrl ctrl; /* Needs to come first in this struct! */ + struct xhci_hccr *hcd; + void __iomem *ippc; + struct udevice *dev; + struct udevice *vusb33_supply; + struct udevice *vbus_supply; + struct clk_bulk clks; + struct phy_bulk phys; + int num_u2ports; + int num_u3ports; +}; + +static int xhci_mtk_host_enable(struct mtk_xhci *mtk) +{ + u32 value; + u32 check_val; + int ret; + int i; + + /* power on host ip */ + clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); + + /* power on and enable all u3 ports */ + for (i = 0; i < mtk->num_u3ports; i++) { + clrsetbits_le32(mtk->ippc + IPPC_U3_CTRL(i), + CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS, + CTRL_U3_PORT_HOST_SEL); + } + + /* power on and enable all u2 ports */ + for (i = 0; i < mtk->num_u2ports; i++) { + clrsetbits_le32(mtk->ippc + IPPC_U2_CTRL(i), + CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS, + CTRL_U2_PORT_HOST_SEL); + } + + /* + * wait for clocks to be stable, and clock domains reset to + * be inactive after power on and enable ports + */ + check_val = STS1_SYSPLL_STABLE | STS1_REF_RST | + STS1_SYS125_RST | STS1_XHCI_RST; + + if (mtk->num_u3ports) + check_val |= STS1_U3_MAC_RST; + + ret = readl_poll_timeout(mtk->ippc + IPPC_IP_PW_STS1, value, + (check_val == (value & check_val)), 20000); + if (ret) + dev_err(mtk->dev, "clocks are not stable 0x%x!\n", value); + + return ret; +} + +static int xhci_mtk_host_disable(struct mtk_xhci *mtk) +{ + int i; + + /* power down all u3 ports */ + for (i = 0; i < mtk->num_u3ports; i++) + setbits_le32(mtk->ippc + IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN); + + /* power down all u2 ports */ + for (i = 0; i < mtk->num_u2ports; i++) + setbits_le32(mtk->ippc + IPPC_U2_CTRL(i), CTRL_U2_PORT_PDN); + + /* power down host ip */ + setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); + + return 0; +} + +static int xhci_mtk_ssusb_init(struct mtk_xhci *mtk) +{ + u32 value; + + /* reset whole ip */ + setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST); + udelay(1); + clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST); + + value = readl(mtk->ippc + IPPC_IP_XHCI_CAP); + mtk->num_u3ports = CAP_U3_PORT_NUM(value); + mtk->num_u2ports = CAP_U2_PORT_NUM(value); + dev_info(mtk->dev, "u2p:%d, u3p:%d\n", + mtk->num_u2ports, mtk->num_u3ports); + + return xhci_mtk_host_enable(mtk); +} + +static int xhci_mtk_ofdata_get(struct mtk_xhci *mtk) +{ + struct udevice *dev = mtk->dev; + int ret = 0; + + mtk->hcd = devfdt_remap_addr_name(dev, "mac"); + if (!mtk->hcd) { + dev_err(dev, "failed to get xHCI base address\n"); + return -ENXIO; + } + + mtk->ippc = devfdt_remap_addr_name(dev, "ippc"); + if (!mtk->ippc) { + dev_err(dev, "failed to get IPPC base address\n"); + return -ENXIO; + } + + dev_info(dev, "hcd: 0x%p, ippc: 0x%p\n", mtk->hcd, mtk->ippc); + + ret = clk_get_bulk(dev, &mtk->clks); + if (ret) { + dev_err(dev, "failed to get clocks %d!\n", ret); + return ret; + } + + ret = device_get_supply_regulator(dev, "vusb33-supply", + &mtk->vusb33_supply); + if (ret) + debug("can't get vusb33 regulator %d!\n", ret); + + ret = device_get_supply_regulator(dev, "vbus-supply", + &mtk->vbus_supply); + if (ret) + debug("can't get vbus regulator %d!\n", ret); + + return 0; +} + +static int xhci_mtk_ldos_enable(struct mtk_xhci *mtk) +{ + int ret; + + ret = regulator_set_enable(mtk->vusb33_supply, true); + if (ret < 0 && ret != -ENOSYS) { + dev_err(mtk->dev, "failed to enable vusb33 %d!\n", ret); + return ret; + } + + ret = regulator_set_enable(mtk->vbus_supply, true); + if (ret < 0 && ret != -ENOSYS) { + dev_err(mtk->dev, "failed to enable vbus %d!\n", ret); + regulator_set_enable(mtk->vusb33_supply, false); + return ret; + } + + return 0; +} + +static void xhci_mtk_ldos_disable(struct mtk_xhci *mtk) +{ + regulator_set_enable(mtk->vbus_supply, false); + regulator_set_enable(mtk->vusb33_supply, false); +} + +static int xhci_mtk_phy_setup(struct mtk_xhci *mtk) +{ + struct udevice *dev = mtk->dev; + struct phy_bulk *phys = &mtk->phys; + int ret; + + ret = generic_phy_get_bulk(dev, phys); + if (ret) + return ret; + + ret = generic_phy_init_bulk(phys); + if (ret) + return ret; + + ret = generic_phy_power_on_bulk(phys); + if (ret) + generic_phy_exit_bulk(phys); + + return ret; +} + +static void xhci_mtk_phy_shutdown(struct mtk_xhci *mtk) +{ + generic_phy_power_off_bulk(&mtk->phys); + generic_phy_exit_bulk(&mtk->phys); +} + +static int xhci_mtk_probe(struct udevice *dev) +{ + struct mtk_xhci *mtk = dev_get_priv(dev); + struct xhci_hcor *hcor; + int ret; + + mtk->dev = dev; + ret = xhci_mtk_ofdata_get(mtk); + if (ret) + return ret; + + ret = xhci_mtk_ldos_enable(mtk); + if (ret) + goto ldos_err; + + ret = clk_enable_bulk(&mtk->clks); + if (ret) + goto clks_err; + + ret = xhci_mtk_phy_setup(mtk); + if (ret) + goto phys_err; + + ret = xhci_mtk_ssusb_init(mtk); + if (ret) + goto ssusb_init_err; + + hcor = (struct xhci_hcor *)((uintptr_t)mtk->hcd + + HC_LENGTH(xhci_readl(&mtk->hcd->cr_capbase))); + + return xhci_register(dev, mtk->hcd, hcor); + +ssusb_init_err: + xhci_mtk_phy_shutdown(mtk); +phys_err: + clk_disable_bulk(&mtk->clks); +clks_err: + xhci_mtk_ldos_disable(mtk); +ldos_err: + return ret; +} + +static int xhci_mtk_remove(struct udevice *dev) +{ + struct mtk_xhci *mtk = dev_get_priv(dev); + + xhci_deregister(dev); + xhci_mtk_host_disable(mtk); + xhci_mtk_ldos_disable(mtk); + clk_disable_bulk(&mtk->clks); + + return 0; +} + +static const struct udevice_id xhci_mtk_ids[] = { + { .compatible = "mediatek,mtk-xhci" }, + { } +}; + +U_BOOT_DRIVER(usb_xhci) = { + .name = "xhci-mtk", + .id = UCLASS_USB, + .of_match = xhci_mtk_ids, + .probe = xhci_mtk_probe, + .remove = xhci_mtk_remove, + .ops = &xhci_usb_ops, + .bind = dm_scan_fdt_dev, + .priv_auto_alloc_size = sizeof(struct mtk_xhci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 40dee2e6d9b..c370eb63942 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -610,6 +610,16 @@ static int xhci_set_configuration(struct usb_device *udev) ep_ctx[ep_index]->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) | EP_AVG_TRB_LENGTH(avg_trb_len)); + + /* + * The MediaTek xHCI defines some extra SW parameters which + * are put into reserved DWs in Slot and Endpoint Contexts + * for synchronous endpoints. + */ + if (IS_ENABLED(CONFIG_USB_XHCI_MTK)) { + ep_ctx[ep_index]->reserved[0] = + cpu_to_le32(EP_BPKTS(1) | EP_BBM(1)); + } } return xhci_configure_endpoints(udev, false); diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 60175044884..20e4a21066f 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -670,6 +670,9 @@ struct xhci_ep_ctx { /* deq bitmasks */ #define EP_CTX_CYCLE_MASK (1 << 0) +/* reserved[0] bitmasks, MediaTek xHCI used */ +#define EP_BPKTS(p) (((p) & 0x7f) << 0) +#define EP_BBM(p) (((p) & 0x1) << 11) /** * struct xhci_input_control_context -- cgit v1.3.1 From 3bebb4f3589fc447dddaf687d7fb9d503a65eaa4 Mon Sep 17 00:00:00 2001 From: Biwen Li Date: Fri, 1 May 2020 20:03:56 +0800 Subject: rtc: ds1337: Add driver model support Add support of driver model of ds1337 Signed-off-by: Biwen Li Reviewed-by: Priyanka Jain --- drivers/rtc/ds1337.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/ds1337.c b/drivers/rtc/ds1337.c index 9b31048e972..af94bcfdf44 100644 --- a/drivers/rtc/ds1337.c +++ b/drivers/rtc/ds1337.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2001-2008 + * Copyright 2020 NXP * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * Keith Outwater, keith_outwater@mvis.com` */ @@ -12,6 +13,7 @@ #include #include +#include #include #include @@ -60,6 +62,7 @@ #define RTC_STAT_BIT_OSF 0x80 /* Oscillator stop flag */ +#if !CONFIG_IS_ENABLED(DM_RTC) static uchar rtc_read (uchar reg); static void rtc_write (uchar reg, uchar val); @@ -188,3 +191,128 @@ static void rtc_write (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } +#else +static uchar rtc_read(struct udevice *dev, uchar reg) +{ + return dm_i2c_reg_read(dev, reg); +} + +static void rtc_write(struct udevice *dev, uchar reg, uchar val) +{ + dm_i2c_reg_write(dev, reg, val); +} + +static int ds1337_rtc_get(struct udevice *dev, struct rtc_time *tmp) +{ + int rel = 0; + uchar sec, min, hour, mday, wday, mon_cent, year, control, status; + + control = rtc_read(dev, RTC_CTL_REG_ADDR); + status = rtc_read(dev, RTC_STAT_REG_ADDR); + sec = rtc_read(dev, RTC_SEC_REG_ADDR); + min = rtc_read(dev, RTC_MIN_REG_ADDR); + hour = rtc_read(dev, RTC_HR_REG_ADDR); + wday = rtc_read(dev, RTC_DAY_REG_ADDR); + mday = rtc_read(dev, RTC_DATE_REG_ADDR); + mon_cent = rtc_read(dev, RTC_MON_REG_ADDR); + year = rtc_read(dev, RTC_YR_REG_ADDR); + + /* No century bit, assume year 2000 */ +#ifdef CONFIG_RTC_DS1388 + mon_cent |= 0x80; +#endif + + debug("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x\n", + year, mon_cent, mday, wday); + debug("hr: %02x min: %02x sec: %02x control: %02x status: %02x\n", + hour, min, sec, control, status); + + if (status & RTC_STAT_BIT_OSF) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + rtc_write(dev, RTC_STAT_REG_ADDR, + rtc_read(dev, RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF); + rel = -1; + } + + tmp->tm_sec = bcd2bin(sec & 0x7F); + tmp->tm_min = bcd2bin(min & 0x7F); + tmp->tm_hour = bcd2bin(hour & 0x3F); + tmp->tm_mday = bcd2bin(mday & 0x3F); + tmp->tm_mon = bcd2bin(mon_cent & 0x1F); + tmp->tm_year = bcd2bin(year) + ((mon_cent & 0x80) ? 2000 : 1900); + tmp->tm_wday = bcd2bin((wday - 1) & 0x07); + tmp->tm_yday = 0; + tmp->tm_isdst = 0; + + debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; +} + +static int ds1337_rtc_set(struct udevice *dev, const struct rtc_time *tmp) +{ + uchar century; + + debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + rtc_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100)); + + century = (tmp->tm_year >= 2000) ? 0x80 : 0; + rtc_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon) | century); + + rtc_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1)); + rtc_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday)); + rtc_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour)); + rtc_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min)); + rtc_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec)); + + return 0; +} + +#ifdef CONFIG_RTC_DS1337_NOOSC + #define RTC_DS1337_RESET_VAL \ + (RTC_CTL_BIT_INTCN | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2) +#else + #define RTC_DS1337_RESET_VAL (RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2) +#endif +static int ds1337_rtc_reset(struct udevice *dev) +{ +#ifdef CONFIG_RTC_DS1337 + rtc_write(dev, RTC_CTL_REG_ADDR, RTC_DS1337_RESET_VAL); +#elif defined CONFIG_RTC_DS1388 + rtc_write(dev, RTC_CTL_REG_ADDR, 0x0); /* hw default */ +#endif +#ifdef CONFIG_RTC_DS1339_TCR_VAL + rtc_write(dev, RTC_TC_REG_ADDR, CONFIG_RTC_DS1339_TCR_VAL); +#endif +#ifdef CONFIG_RTC_DS1388_TCR_VAL + rtc_write(dev, RTC_TC_REG_ADDR, CONFIG_RTC_DS1388_TCR_VAL); +#endif + return 0; +} + +static const struct rtc_ops ds1337_rtc_ops = { + .get = ds1337_rtc_get, + .set = ds1337_rtc_set, + .reset = ds1337_rtc_reset, +}; + +static const struct udevice_id ds1337_rtc_ids[] = { + { .compatible = "ds1337" }, + { .compatible = "ds1338" }, + { .compatible = "ds1338" }, + { } +}; + +U_BOOT_DRIVER(rtc_ds1337) = { + .name = "rtc-ds1337", + .id = UCLASS_RTC, + .of_match = ds1337_rtc_ids, + .ops = &ds1337_rtc_ops, +}; +#endif -- cgit v1.3.1 From 22e0a840727825eb5b1b2d510bfd2d48972e9c5d Mon Sep 17 00:00:00 2001 From: Biwen Li Date: Fri, 1 May 2020 20:03:57 +0800 Subject: rtc: pt7c4338: Add driver model support Add support of driver model of pt7c4338 Signed-off-by: Biwen Li Reviewed-by: Priyanka Jain --- drivers/rtc/pt7c4338.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/pt7c4338.c b/drivers/rtc/pt7c4338.c index 6a19fe1d23f..5211d075868 100644 --- a/drivers/rtc/pt7c4338.c +++ b/drivers/rtc/pt7c4338.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2010 Freescale Semiconductor, Inc. + * Copyright 2020 NXP * * Author: Priyanka Jain */ @@ -19,6 +20,7 @@ #include #include +#include #include #include @@ -46,6 +48,7 @@ #define RTC_PT7C4338_RESET_VAL \ (RTC_CTL_STAT_BIT_RS0 | RTC_CTL_STAT_BIT_RS1 | RTC_CTL_STAT_BIT_OUT) +#if !CONFIG_IS_ENABLED(DM_RTC) /****** Helper functions ****************************************/ static u8 rtc_read(u8 reg) { @@ -125,3 +128,100 @@ void rtc_reset(void) rtc_write(RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */ rtc_write(RTC_CTL_STAT_REG_ADDR, RTC_PT7C4338_RESET_VAL); } +#else +static u8 rtc_read(struct udevice *dev, u8 reg) +{ + return dm_i2c_reg_read(dev, reg); +} + +static void rtc_write(struct udevice *dev, u8 reg, u8 val) +{ + dm_i2c_reg_write(dev, reg, val); +} + +static int pt7c4338_rtc_get(struct udevice *dev, struct rtc_time *tmp) +{ + int ret = 0; + u8 sec, min, hour, mday, wday, mon, year, ctl_stat; + + ctl_stat = rtc_read(dev, RTC_CTL_STAT_REG_ADDR); + sec = rtc_read(dev, RTC_SEC_REG_ADDR); + min = rtc_read(dev, RTC_MIN_REG_ADDR); + hour = rtc_read(dev, RTC_HR_REG_ADDR); + wday = rtc_read(dev, RTC_DAY_REG_ADDR); + mday = rtc_read(dev, RTC_DATE_REG_ADDR); + mon = rtc_read(dev, RTC_MON_REG_ADDR); + year = rtc_read(dev, RTC_YR_REG_ADDR); + debug("Get RTC year: %02x mon: %02x mday: %02x wday: %02x\n", + year, mon, mday, wday); + debug("hr: %02x min: %02x sec: %02x control_status: %02x\n", + hour, min, sec, ctl_stat); + + if (ctl_stat & RTC_CTL_STAT_BIT_OSF) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + rtc_write(dev, RTC_CTL_STAT_REG_ADDR, + rtc_read(dev, + RTC_CTL_STAT_REG_ADDR) + & ~RTC_CTL_STAT_BIT_OSF); + ret = -1; + } + + tmp->tm_sec = bcd2bin(sec & 0x7F); + tmp->tm_min = bcd2bin(min & 0x7F); + tmp->tm_hour = bcd2bin(hour & 0x3F); + tmp->tm_mday = bcd2bin(mday & 0x3F); + tmp->tm_mon = bcd2bin(mon & 0x1F); + tmp->tm_year = bcd2bin(year) + 2000; + tmp->tm_wday = bcd2bin((wday - 1) & 0x07); + tmp->tm_yday = 0; + tmp->tm_isdst = 0; + debug("Get DATE: %4d-%02d-%02d [wday=%d] TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return ret; +} + +static int pt7c4338_rtc_set(struct udevice *dev, const struct rtc_time *tmp) +{ + debug("Set DATE: %4d-%02d-%02d [wday=%d] TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + rtc_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100)); + rtc_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon)); + rtc_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1)); + rtc_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday)); + rtc_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour)); + rtc_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min)); + rtc_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec)); + + return 0; +} + +static int pt7c4338_rtc_reset(struct udevice *dev) +{ + rtc_write(dev, RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */ + rtc_write(dev, RTC_CTL_STAT_REG_ADDR, RTC_PT7C4338_RESET_VAL); + return 0; +} + +static const struct rtc_ops pt7c4338_rtc_ops = { + .get = pt7c4338_rtc_get, + .set = pt7c4338_rtc_set, + .reset = pt7c4338_rtc_reset, +}; + +static const struct udevice_id pt7c4338_rtc_ids[] = { + { .compatible = "pericom,pt7c4338" }, + { } +}; + +U_BOOT_DRIVER(rtc_pt7c4338) = { + .name = "rtc-pt7c4338", + .id = UCLASS_RTC, + .of_match = pt7c4338_rtc_ids, + .ops = &pt7c4338_rtc_ops, +}; +#endif -- cgit v1.3.1 From d76485b9411a680be2a25e1bc4f8da36619815dd Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 19 Apr 2020 09:19:04 +0200 Subject: doc: fix references to README.qe_firmware In two files README.qe_firmware is referenced which never made it into the U-Boot tree. The README is available in the Linux kernel tree. Update the references. Cc: Timur Tabi Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Reviewed-by: Priyanka Jain --- drivers/qe/qe.c | 6 ++++-- include/fsl_qe.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index 24549ece653..fbad124b51c 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -440,7 +440,8 @@ static void qe_upload_microcode(const void *base, /* * Upload a microcode to the I-RAM at a specific address. * - * See docs/README.qe_firmware for information on QE microcode uploading. + * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for + * information on QE microcode uploading. * * Currently, only version 1 is supported, so the 'version' field must be * set to 1. @@ -579,7 +580,8 @@ int qe_upload_firmware(const struct qe_firmware *firmware) /* * Upload a microcode to the I-RAM at a specific address. * - * See docs/README.qe_firmware for information on QE microcode uploading. + * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for + * information on QE microcode uploading. * * Currently, only version 1 is supported, so the 'version' field must be * set to 1. diff --git a/include/fsl_qe.h b/include/fsl_qe.h index d4eba824365..6e44cbdb562 100644 --- a/include/fsl_qe.h +++ b/include/fsl_qe.h @@ -227,7 +227,8 @@ typedef enum qe_clock { /* Structure that defines QE firmware binary files. * - * See doc/README.qe_firmware for a description of these fields. + * See Documentation/powerpc/qe_firmware.rst in the Linux kernel tree for + * a description of these fields. */ struct qe_firmware { struct qe_header { -- cgit v1.3.1 From 8510580f2e85a8687b40fe5fc3d8c060e5278505 Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 3 May 2020 19:43:32 +0200 Subject: net: pcnet: fix I/O primitives for memory access Commit 69529c912059 ("net: pcnet: Switch to PCI memory access") switched from PCI IO access to PCI memory access without updating the I/O primitives. Contrary to SH, the primitives for memory access and IO access are implemented differently. Thus doing memory access with IO port primitives breaks the driver on MIPS Malta board. Signed-off-by: Daniel Schwierzeck --- drivers/net/pcnet.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 34a5a16cfe8..f97e7f8c6a3 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -91,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); -- cgit v1.3.1 From 653f7c44677cd13bb106673bb7c46542e217fa13 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Mon, 4 May 2020 18:41:55 +0800 Subject: cache: l2x0: Fix missing write to Auxiliary Control Register In commit f62782fb2999 ("cache: l2x0: Fix write to incorrect shared-override bit") we removed writel to regs->pl310_aux_ctrl by accident. This commit restores it back. Fixes: f62782fb2999 ("cache: l2x0: Fix write to incorrect shared-override bit") Signed-off-by: Ley Foon Tan --- drivers/cache/cache-l2x0.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/cache/cache-l2x0.c b/drivers/cache/cache-l2x0.c index 226824c2832..a1556fbf174 100644 --- a/drivers/cache/cache-l2x0.c +++ b/drivers/cache/cache-l2x0.c @@ -36,6 +36,8 @@ static void l2c310_of_parse_and_init(struct udevice *dev) if (dev_read_bool(dev, "arm,shared-override")) saved_reg |= L310_SHARED_ATT_OVERRIDE_ENABLE; + writel(saved_reg, ®s->pl310_aux_ctrl); + saved_reg = readl(®s->pl310_tag_latency_ctrl); if (!dev_read_u32_array(dev, "arm,tag-latency", tag, 3)) saved_reg |= L310_LATENCY_CTRL_RD(tag[0] - 1) | -- cgit v1.3.1 From e3e2d662a273d5ac67998f390529966a8d8c8a3b Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 27 Apr 2020 19:17:59 +0100 Subject: uart: pl011: Add proper DM clock support Even though the PL011 UART driver claims to be DM compliant, it does not really a good job with parsing DT nodes. U-Boot seems to adhere to a non-standard binding, either requiring to have a "skip-init" property in the node, or to have an extra "clock" property holding the base *frequency* value for the baud rate generator. DTs in the U-Boot tree seem to have been hacked to match this requirement. The official binding does not mention any of these properties, instead recommends a standard "clocks" property to point to the baud base clock. Some boards use simple "fixed-clock" providers, which U-Boot readily supports, so let's add some simple DM clock code to the PL011 driver to learn the rate of the first clock, as described by the official binding. These clock nodes seem to be not ready very early in the boot process, so provide a fallback value, by re-using the already existing CONFIG_PL011_CLOCK variable. Signed-off-by: Andre Przywara [trini: Add for get_bus_freq() for layerscape platforms] Signed-off-by: Tom Rini Reviewed-by: Simon Glass --- drivers/serial/serial_pl01x.c | 49 +++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 2a5f256184f..6e5d81ce34a 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -11,7 +11,10 @@ /* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ #include +/* For get_bus_freq() */ +#include #include +#include #include #include #include @@ -149,21 +152,24 @@ static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type, unsigned int remainder; unsigned int fraction; - /* - * Set baud rate - * - * IBRD = UART_CLK / (16 * BAUD_RATE) - * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) - * / (16 * BAUD_RATE)) - */ - temp = 16 * baudrate; - divider = clock / temp; - remainder = clock % temp; - temp = (8 * remainder) / baudrate; - fraction = (temp >> 1) + (temp & 1); - - writel(divider, ®s->pl011_ibrd); - writel(fraction, ®s->pl011_fbrd); + /* Without a valid clock rate we cannot set up the baudrate. */ + if (clock) { + /* + * Set baud rate + * + * IBRD = UART_CLK / (16 * BAUD_RATE) + * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) + * / (16 * BAUD_RATE)) + */ + temp = 16 * baudrate; + divider = clock / temp; + remainder = clock % temp; + temp = (8 * remainder) / baudrate; + fraction = (temp >> 1) + (temp & 1); + + writel(divider, ®s->pl011_ibrd); + writel(fraction, ®s->pl011_fbrd); + } pl011_set_line_control(regs); /* Finally, enable the UART */ @@ -337,17 +343,28 @@ static const struct udevice_id pl01x_serial_id[] ={ {} }; +#ifndef CONFIG_PL011_CLOCK +#define CONFIG_PL011_CLOCK 0 +#endif + int pl01x_serial_ofdata_to_platdata(struct udevice *dev) { struct pl01x_serial_platdata *plat = dev_get_platdata(dev); + struct clk clk; fdt_addr_t addr; + int ret; addr = devfdt_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; plat->base = addr; - plat->clock = dev_read_u32_default(dev, "clock", 1); + plat->clock = dev_read_u32_default(dev, "clock", CONFIG_PL011_CLOCK); + ret = clk_get_by_index(dev, 0, &clk); + if (!ret) { + clk_enable(&clk); + plat->clock = clk_get_rate(&clk); + } plat->type = dev_get_driver_data(dev); plat->skip_init = dev_read_bool(dev, "skip-init"); -- cgit v1.3.1 From 4346df3392c0e795ce458bc86e9e8ed24a3afa0f Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 7 May 2020 00:11:48 +0200 Subject: phy: atheros: Make RGMII Tx delays actually configurable for AR8035 Delete the extraneous write to debug reg 5 that enables Tx delay When the driver was originally introduced in commit "6027384a phylib: Add Atheros AR8035 GETH PHY support", the Tx delay was being unconditionally enabled. Then during "2ec4d10b phy: atheros: add support for RGMII_ID, RGMII_TXID and RGMII_RXID", the author did not notice that code for enabling Tx delay code was already. Therefore, the if condition for Tx delay has always been useless for this PHY since this commit introduced it. Prior to this patch, every AR8035 PHY in U-boot had Tx delay enabled. After this patch, only those who define the interface as RGMII_TXID or RGMII_ID will. This is to be expected, but will nonetheless break the setups of those who didn't know they rely on Tx delay implicitly. Signed-off-by: Vladimir Oltean Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 3783d155e79..537c1a91251 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -63,10 +63,6 @@ static int ar8035_config(struct phy_device *phydev) regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018)); - phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); - regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e); - phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100)); - if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { /* select debug reg 5 */ -- cgit v1.3.1 From 29602f9c4b8efd9afcb2212eda0e13483ca6ec5d Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 7 May 2020 00:11:49 +0200 Subject: phy: atheros: Use common functions for RGMII internal delays Signed-off-by: Vladimir Oltean Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 69 ++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 537c1a91251..c0c2b4db396 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -12,16 +12,45 @@ #define AR803x_PHY_DEBUG_DATA_REG 0x1e #define AR803x_DEBUG_REG_5 0x5 -#define AR803x_RGMII_TX_CLK_DLY 0x100 +#define AR803x_RGMII_TX_CLK_DLY BIT(8) #define AR803x_DEBUG_REG_0 0x0 -#define AR803x_RGMII_RX_CLK_DLY 0x8000 +#define AR803x_RGMII_RX_CLK_DLY BIT(15) + +static void ar803x_enable_rx_delay(struct phy_device *phydev, bool on) +{ + int regval; + + phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, + AR803x_DEBUG_REG_0); + regval = phy_read(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG); + if (on) + regval |= AR803x_RGMII_RX_CLK_DLY; + else + regval &= ~AR803x_RGMII_RX_CLK_DLY; + phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, regval); +} + +static void ar803x_enable_tx_delay(struct phy_device *phydev, bool on) +{ + int regval; + + phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, + AR803x_DEBUG_REG_5); + regval = phy_read(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG); + if (on) + regval |= AR803x_RGMII_TX_CLK_DLY; + else + regval &= ~AR803x_RGMII_TX_CLK_DLY; + phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, regval); +} static int ar8021_config(struct phy_device *phydev) { phy_write(phydev, MDIO_DEVAD_NONE, 0x00, 0x1200); - phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); - phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x3D47); + phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, + AR803x_DEBUG_REG_5); + phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, 0x3D47); phydev->supported = phydev->drv->features; return 0; @@ -30,20 +59,12 @@ static int ar8021_config(struct phy_device *phydev) static int ar8031_config(struct phy_device *phydev) { if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, - AR803x_DEBUG_REG_5); - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, - AR803x_RGMII_TX_CLK_DLY); - } + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + ar803x_enable_tx_delay(phydev, true); if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, - AR803x_DEBUG_REG_0); - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, - AR803x_RGMII_RX_CLK_DLY); - } + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + ar803x_enable_rx_delay(phydev, true); phydev->supported = phydev->drv->features; @@ -64,20 +85,12 @@ static int ar8035_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018)); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { - /* select debug reg 5 */ - phy_write(phydev, MDIO_DEVAD_NONE, 0x1D, 0x5); - /* enable tx delay */ - phy_write(phydev, MDIO_DEVAD_NONE, 0x1E, 0x0100); - } + (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) + ar803x_enable_tx_delay(phydev, true); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) { - /* select debug reg 0 */ - phy_write(phydev, MDIO_DEVAD_NONE, 0x1D, 0x0); - /* enable rx delay */ - phy_write(phydev, MDIO_DEVAD_NONE, 0x1E, 0x8000); - } + (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) + ar803x_enable_rx_delay(phydev, true); phydev->supported = phydev->drv->features; -- cgit v1.3.1 From a234ae863a413d371a0abc36f9e0aa9c1726e331 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 7 May 2020 00:11:50 +0200 Subject: phy: atheros: Clarify the configuration of the CLK_25M output pin Also take the opportunity to use the phy_read_mmd and phy_write_mmd convenience functions. Signed-off-by: Vladimir Oltean Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index c0c2b4db396..1da18eb5d45 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -17,6 +17,15 @@ #define AR803x_DEBUG_REG_0 0x0 #define AR803x_RGMII_RX_CLK_DLY BIT(15) +/* CLK_25M register is at MMD 7, address 0x8016 */ +#define AR803x_CLK_25M_SEL_REG 0x8016 +/* AR8035: Select frequency on CLK_25M pin through bits 4:3 */ +#define AR8035_CLK_25M_FREQ_25M (0 | 0) +#define AR8035_CLK_25M_FREQ_50M (0 | BIT(3)) +#define AR8035_CLK_25M_FREQ_62M (BIT(4) | 0) +#define AR8035_CLK_25M_FREQ_125M (BIT(4) | BIT(3)) +#define AR8035_CLK_25M_MASK GENMASK(4, 3) + static void ar803x_enable_rx_delay(struct phy_device *phydev, bool on) { int regval; @@ -78,11 +87,11 @@ static int ar8035_config(struct phy_device *phydev) { int regval; - phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007); - phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016); - phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007); - regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); - phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018)); + /* Configure CLK_25M output clock at 125 MHz */ + regval = phy_read_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG); + regval &= ~AR8035_CLK_25M_MASK; /* No surprises */ + regval |= AR8035_CLK_25M_FREQ_125M; + phy_write_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG, regval); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) -- cgit v1.3.1 From 13114f38e2ccea9386726d8b9831dfc310589548 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 7 May 2020 00:11:51 +0200 Subject: phy: atheros: Explicitly disable RGMII delays To eliminate any doubts about the out-of-reset value of the PHY, that the driver previously relied on. If bisecting shows that this commit breaks your board you probably have a wrong PHY interface mode. You probably want the PHY_INTERFACE_MODE_RGMII_RXID or PHY_INTERFACE_MODE_RGMII_ID mode. Signed-off-by: Vladimir Oltean Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 1da18eb5d45..3e59c3f3915 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -70,10 +70,14 @@ static int ar8031_config(struct phy_device *phydev) if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ar803x_enable_tx_delay(phydev, true); + else + ar803x_enable_tx_delay(phydev, false); if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ar803x_enable_rx_delay(phydev, true); + else + ar803x_enable_rx_delay(phydev, false); phydev->supported = phydev->drv->features; @@ -96,10 +100,14 @@ static int ar8035_config(struct phy_device *phydev) if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) ar803x_enable_tx_delay(phydev, true); + else + ar803x_enable_tx_delay(phydev, false); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) ar803x_enable_rx_delay(phydev, true); + else + ar803x_enable_rx_delay(phydev, false); phydev->supported = phydev->drv->features; -- cgit v1.3.1 From 4d4e4cf7798276bcb047b65cf80fde63fd347903 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 7 May 2020 00:11:52 +0200 Subject: phy: atheros: Clarify the intention of ar8021_config Debug register 5 contains TX_CLK DELAY at bit 8 and reserved values at the other bit positions, just like the other PHYs in the family do. Therefore, it is not necessary to hardcode the reserved values, but instead simply follow the read-modify-write procedure from the common function. Signed-off-by: Vladimir Oltean Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 3e59c3f3915..3cc162828ca 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -56,10 +56,10 @@ static void ar803x_enable_tx_delay(struct phy_device *phydev, bool on) static int ar8021_config(struct phy_device *phydev) { - phy_write(phydev, MDIO_DEVAD_NONE, 0x00, 0x1200); - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, - AR803x_DEBUG_REG_5); - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, 0x3D47); + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART); + + ar803x_enable_tx_delay(phydev, true); phydev->supported = phydev->drv->features; return 0; -- cgit v1.3.1 From f4d48f43b29756dac0f306eec3ca7ddf2821dd4e Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 May 2020 00:11:53 +0200 Subject: phy: atheros: fix AR8021 PHY ID mask The upper bits are all the OUI. Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 3cc162828ca..01953a13902 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -120,7 +120,7 @@ static int ar8035_config(struct phy_device *phydev) static struct phy_driver AR8021_driver = { .name = "AR8021", .uid = 0x4dd040, - .mask = 0x4ffff0, + .mask = 0xfffffff0, .features = PHY_GBIT_FEATURES, .config = ar8021_config, .startup = genphy_startup, -- cgit v1.3.1 From 30e3193128f95d7276311b50f4215f9a8625c3ba Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 May 2020 00:11:54 +0200 Subject: phy: atheros: use defines for PHY IDs Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 01953a13902..5ff5875d3df 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -26,6 +26,10 @@ #define AR8035_CLK_25M_FREQ_125M (BIT(4) | BIT(3)) #define AR8035_CLK_25M_MASK GENMASK(4, 3) +#define AR8021_PHY_ID 0x004dd040 +#define AR8031_PHY_ID 0x004dd074 +#define AR8035_PHY_ID 0x004dd072 + static void ar803x_enable_rx_delay(struct phy_device *phydev, bool on) { int regval; @@ -119,7 +123,7 @@ static int ar8035_config(struct phy_device *phydev) static struct phy_driver AR8021_driver = { .name = "AR8021", - .uid = 0x4dd040, + .uid = AR8021_PHY_ID, .mask = 0xfffffff0, .features = PHY_GBIT_FEATURES, .config = ar8021_config, @@ -129,7 +133,7 @@ static struct phy_driver AR8021_driver = { static struct phy_driver AR8031_driver = { .name = "AR8031/AR8033", - .uid = 0x4dd074, + .uid = AR8031_PHY_ID, .mask = 0xffffffef, .features = PHY_GBIT_FEATURES, .config = ar8031_config, @@ -139,7 +143,7 @@ static struct phy_driver AR8031_driver = { static struct phy_driver AR8035_driver = { .name = "AR8035", - .uid = 0x4dd072, + .uid = AR8035_PHY_ID, .mask = 0xffffffef, .features = PHY_GBIT_FEATURES, .config = ar8035_config, -- cgit v1.3.1 From f6ae47be1ac5f3b16ac2b702ffa89e5709711ce5 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 May 2020 00:11:55 +0200 Subject: phy: atheros: introduce debug read and write functions Provide functions to read and write the Atheros debug registers. Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 57 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 5ff5875d3df..660dcd9491d 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -30,32 +30,57 @@ #define AR8031_PHY_ID 0x004dd074 #define AR8035_PHY_ID 0x004dd072 -static void ar803x_enable_rx_delay(struct phy_device *phydev, bool on) +static int ar803x_debug_reg_read(struct phy_device *phydev, u16 reg) { - int regval; + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, + reg); + if (ret < 0) + return ret; + + return phy_read(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG); +} + +static int ar803x_debug_reg_mask(struct phy_device *phydev, u16 reg, + u16 clear, u16 set) +{ + int val; + + val = ar803x_debug_reg_read(phydev, reg); + if (val < 0) + return val; + + val &= 0xffff; + val &= ~clear; + val |= set; + + return phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, + val); +} + +static int ar803x_enable_rx_delay(struct phy_device *phydev, bool on) +{ + u16 clear = 0, set = 0; - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, - AR803x_DEBUG_REG_0); - regval = phy_read(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG); if (on) - regval |= AR803x_RGMII_RX_CLK_DLY; + set = AR803x_RGMII_RX_CLK_DLY; else - regval &= ~AR803x_RGMII_RX_CLK_DLY; - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, regval); + clear = AR803x_RGMII_RX_CLK_DLY; + + return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_0, clear, set); } -static void ar803x_enable_tx_delay(struct phy_device *phydev, bool on) +static int ar803x_enable_tx_delay(struct phy_device *phydev, bool on) { - int regval; + u16 clear = 0, set = 0; - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, - AR803x_DEBUG_REG_5); - regval = phy_read(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG); if (on) - regval |= AR803x_RGMII_TX_CLK_DLY; + set = AR803x_RGMII_TX_CLK_DLY; else - regval &= ~AR803x_RGMII_TX_CLK_DLY; - phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, regval); + clear = AR803x_RGMII_TX_CLK_DLY; + + return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_5, clear, set); } static int ar8021_config(struct phy_device *phydev) -- cgit v1.3.1 From 2b7721552a4cb4046a365a665fba3a3a848eb966 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 May 2020 00:11:56 +0200 Subject: phy: atheros: move delay config to common function Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 660dcd9491d..22035c2496d 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -94,19 +94,32 @@ static int ar8021_config(struct phy_device *phydev) return 0; } -static int ar8031_config(struct phy_device *phydev) +static int ar803x_delay_config(struct phy_device *phydev) { + int ret; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - ar803x_enable_tx_delay(phydev, true); + ret = ar803x_enable_tx_delay(phydev, true); else - ar803x_enable_tx_delay(phydev, false); + ret = ar803x_enable_tx_delay(phydev, false); if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - ar803x_enable_rx_delay(phydev, true); + ret = ar803x_enable_rx_delay(phydev, true); else - ar803x_enable_rx_delay(phydev, false); + ret = ar803x_enable_rx_delay(phydev, false); + + return ret; +} + +static int ar8031_config(struct phy_device *phydev) +{ + int ret; + + ret = ar803x_delay_config(phydev); + if (ret < 0) + return ret; phydev->supported = phydev->drv->features; @@ -118,6 +131,7 @@ static int ar8031_config(struct phy_device *phydev) static int ar8035_config(struct phy_device *phydev) { + int ret; int regval; /* Configure CLK_25M output clock at 125 MHz */ @@ -126,17 +140,9 @@ static int ar8035_config(struct phy_device *phydev) regval |= AR8035_CLK_25M_FREQ_125M; phy_write_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG, regval); - if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) - ar803x_enable_tx_delay(phydev, true); - else - ar803x_enable_tx_delay(phydev, false); - - if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) - ar803x_enable_rx_delay(phydev, true); - else - ar803x_enable_rx_delay(phydev, false); + ret = ar803x_delay_config(phydev); + if (ret < 0) + return ret; phydev->supported = phydev->drv->features; -- cgit v1.3.1 From fe6293a8095998affd5e46e7968485fcc332e0fa Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 May 2020 00:11:57 +0200 Subject: phy: atheros: add device tree bindings and config Add support for configuring the CLK_25M pin as well as the RGMII I/O voltage by the device tree. By default the AT803x PHYs outputs the 25MHz clock of the XTAL input. But this output can also be changed by software to other frequencies. This commit introduces a generic way to configure this output. Also the PHY supports different RGMII I/O voltages: 1.5V, 1.8V and 2.5V. An internal LDO is able to provide 1.5V (default) and 1.8V. The 2.5V option needs an external supply voltage. This commit adds support to switch the internal LDO to 1.8V. Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- doc/device-tree-bindings/net/phy/atheros.txt | 35 +++++ drivers/net/phy/atheros.c | 224 ++++++++++++++++++++++++++- include/dt-bindings/net/qca-ar803x.h | 13 ++ 3 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 doc/device-tree-bindings/net/phy/atheros.txt create mode 100644 include/dt-bindings/net/qca-ar803x.h (limited to 'drivers') diff --git a/doc/device-tree-bindings/net/phy/atheros.txt b/doc/device-tree-bindings/net/phy/atheros.txt new file mode 100644 index 00000000000..97e97b8c13d --- /dev/null +++ b/doc/device-tree-bindings/net/phy/atheros.txt @@ -0,0 +1,35 @@ +* Qualcomm Atheros PHY Device Tree binding + +Required properties: +- reg: PHY address + +Optional properties: +- qca,clk-out-frequency: Clock frequency of the CLK_25M pin in Hz. + Either 25000000, 50000000, 62500000 or 125000000. +- qca,clk-out-strength: Clock output buffer driver strength. + Supported values are defined in dt-bindings/net/qca-ar803x.h +- qca,keep-pll-enabled: Keep the PLL running if no link is present. + Don't go into hibernation mode. + Only supported on the AR8031/AR8033. +- vddio-supply: RGMII I/O voltage regulator + Only supported on the AR8031/AR8033. + +Optional subnodes: +- vddio-regulator: Initial data for the VDDIO regulator, as covered + doc/device-tree-bindings/regulator/regulator.txt + +Example: + #include + + ethernet-phy@0 { + reg = <0>; + qca-clk-out-frequency = <125000000>; + qca,keep-pll-enabled; + + vddio-supply = <&vddio>; + + vddio: vddio-regulator { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 22035c2496d..3cd301c50ed 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -4,21 +4,41 @@ * * Copyright 2011, 2013 Freescale Semiconductor, Inc. * author Andy Fleming + * Copyright (c) 2019 Michael Walle */ #include #include +#include +#include +#include #define AR803x_PHY_DEBUG_ADDR_REG 0x1d #define AR803x_PHY_DEBUG_DATA_REG 0x1e +/* Debug registers */ +#define AR803x_DEBUG_REG_0 0x0 +#define AR803x_RGMII_RX_CLK_DLY BIT(15) + #define AR803x_DEBUG_REG_5 0x5 #define AR803x_RGMII_TX_CLK_DLY BIT(8) -#define AR803x_DEBUG_REG_0 0x0 -#define AR803x_RGMII_RX_CLK_DLY BIT(15) +#define AR803x_DEBUG_REG_1F 0x1f +#define AR803x_PLL_ON BIT(2) +#define AR803x_RGMII_1V8 BIT(3) /* CLK_25M register is at MMD 7, address 0x8016 */ #define AR803x_CLK_25M_SEL_REG 0x8016 + +#define AR803x_CLK_25M_MASK GENMASK(4, 2) +#define AR803x_CLK_25M_25MHZ_XTAL 0 +#define AR803x_CLK_25M_25MHZ_DSP 1 +#define AR803x_CLK_25M_50MHZ_PLL 2 +#define AR803x_CLK_25M_50MHZ_DSP 3 +#define AR803x_CLK_25M_62_5MHZ_PLL 4 +#define AR803x_CLK_25M_62_5MHZ_DSP 5 +#define AR803x_CLK_25M_125MHZ_PLL 6 +#define AR803x_CLK_25M_125MHZ_DSP 7 + /* AR8035: Select frequency on CLK_25M pin through bits 4:3 */ #define AR8035_CLK_25M_FREQ_25M (0 | 0) #define AR8035_CLK_25M_FREQ_50M (0 | BIT(3)) @@ -26,10 +46,23 @@ #define AR8035_CLK_25M_FREQ_125M (BIT(4) | BIT(3)) #define AR8035_CLK_25M_MASK GENMASK(4, 3) +#define AR803x_CLK_25M_DR_MASK GENMASK(8, 7) +#define AR803x_CLK_25M_DR_FULL 0 +#define AR803x_CLK_25M_DR_HALF 1 +#define AR803x_CLK_25M_DR_QUARTER 2 + #define AR8021_PHY_ID 0x004dd040 #define AR8031_PHY_ID 0x004dd074 #define AR8035_PHY_ID 0x004dd072 +struct ar803x_priv { + int flags; +#define AR803x_FLAG_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */ +#define AR803x_FLAG_RGMII_1V8 BIT(1) /* use 1.8V RGMII I/O voltage */ + u16 clk_25m_reg; + u16 clk_25m_mask; +}; + static int ar803x_debug_reg_read(struct phy_device *phydev, u16 reg) { int ret; @@ -113,14 +146,193 @@ static int ar803x_delay_config(struct phy_device *phydev) return ret; } +static int ar803x_regs_config(struct phy_device *phydev) +{ + struct ar803x_priv *priv = phydev->priv; + u16 set = 0, clear = 0; + int val; + int ret; + + /* no configuration available */ + if (!priv) + return 0; + + /* + * Only supported on the AR8031, AR8035 has strappings for the PLL mode + * as well as the RGMII voltage. + */ + if (phydev->drv->uid == AR8031_PHY_ID) { + if (priv->flags & AR803x_FLAG_KEEP_PLL_ENABLED) + set |= AR803x_PLL_ON; + else + clear |= AR803x_PLL_ON; + + if (priv->flags & AR803x_FLAG_RGMII_1V8) + set |= AR803x_RGMII_1V8; + else + clear |= AR803x_RGMII_1V8; + + ret = ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_1F, clear, + set); + if (ret < 0) + return ret; + } + + /* save the write access if the mask is empty */ + if (priv->clk_25m_mask) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG); + if (val < 0) + return val; + val &= ~priv->clk_25m_mask; + val |= priv->clk_25m_reg; + ret = phy_write_mmd(phydev, MDIO_MMD_AN, + AR803x_CLK_25M_SEL_REG, val); + if (ret < 0) + return ret; + } + + return 0; +} + +static int ar803x_of_init(struct phy_device *phydev) +{ +#if defined(CONFIG_DM_ETH) + struct ar803x_priv *priv; + ofnode node, vddio_reg_node; + u32 strength, freq, min_uV, max_uV; + int sel; + + node = phy_get_ofnode(phydev); + if (!ofnode_valid(node)) + return -EINVAL; + + priv = malloc(sizeof(*priv)); + if (!priv) + return -ENOMEM; + memset(priv, 0, sizeof(*priv)); + + phydev->priv = priv; + + debug("%s: found PHY node: %s\n", __func__, ofnode_get_name(node)); + + if (ofnode_read_bool(node, "qca,keep-pll-enabled")) + priv->flags |= AR803x_FLAG_KEEP_PLL_ENABLED; + + /* + * We can't use the regulator framework because the regulator is + * a subnode of the PHY. So just read the two properties we are + * interested in. + */ + vddio_reg_node = ofnode_find_subnode(node, "vddio-regulator"); + if (ofnode_valid(vddio_reg_node)) { + min_uV = ofnode_read_u32_default(vddio_reg_node, + "regulator-min-microvolt", 0); + max_uV = ofnode_read_u32_default(vddio_reg_node, + "regulator-max-microvolt", 0); + + if (min_uV != max_uV) { + free(priv); + return -EINVAL; + } + + switch (min_uV) { + case 1500000: + break; + case 1800000: + priv->flags |= AR803x_FLAG_RGMII_1V8; + break; + default: + free(priv); + return -EINVAL; + } + } + + /* + * Get the CLK_25M frequency from the device tree. Only XTAL and PLL + * sources are supported right now. There is also the possibilty to use + * the DSP as frequency reference, this is used for synchronous + * ethernet. + */ + if (!ofnode_read_u32(node, "qca,clk-out-frequency", &freq)) { + switch (freq) { + case 25000000: + sel = AR803x_CLK_25M_25MHZ_XTAL; + break; + case 50000000: + sel = AR803x_CLK_25M_50MHZ_PLL; + break; + case 62500000: + sel = AR803x_CLK_25M_62_5MHZ_PLL; + break; + case 125000000: + sel = AR803x_CLK_25M_125MHZ_PLL; + break; + default: + dev_err(phydev->dev, + "invalid qca,clk-out-frequency\n"); + free(priv); + return -EINVAL; + } + + priv->clk_25m_mask |= AR803x_CLK_25M_MASK; + priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_MASK, sel); + /* + * Fixup for the AR8035 which only has two bits. The two + * remaining bits map to the same frequencies. + */ + if (phydev->drv->uid == AR8035_PHY_ID) { + u16 clear = AR803x_CLK_25M_MASK & AR8035_CLK_25M_MASK; + + priv->clk_25m_mask &= ~clear; + priv->clk_25m_reg &= ~clear; + } + } + + if (phydev->drv->uid == AR8031_PHY_ID && + !ofnode_read_u32(node, "qca,clk-out-strength", &strength)) { + switch (strength) { + case AR803X_STRENGTH_FULL: + sel = AR803x_CLK_25M_DR_FULL; + break; + case AR803X_STRENGTH_HALF: + sel = AR803x_CLK_25M_DR_HALF; + break; + case AR803X_STRENGTH_QUARTER: + sel = AR803x_CLK_25M_DR_QUARTER; + break; + default: + dev_err(phydev->dev, + "invalid qca,clk-out-strength\n"); + free(priv); + return -EINVAL; + } + priv->clk_25m_mask |= AR803x_CLK_25M_DR_MASK; + priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_DR_MASK, sel); + } + + debug("%s: flags=%x clk_25m_reg=%04x clk_25m_mask=%04x\n", __func__, + priv->flags, priv->clk_25m_reg, priv->clk_25m_mask); +#endif + + return 0; +} + static int ar8031_config(struct phy_device *phydev) { int ret; + ret = ar803x_of_init(phydev); + if (ret < 0) + return ret; + ret = ar803x_delay_config(phydev); if (ret < 0) return ret; + ret = ar803x_regs_config(phydev); + if (ret < 0) + return ret; + phydev->supported = phydev->drv->features; genphy_config_aneg(phydev); @@ -134,6 +346,10 @@ static int ar8035_config(struct phy_device *phydev) int ret; int regval; + ret = ar803x_of_init(phydev); + if (ret < 0) + return ret; + /* Configure CLK_25M output clock at 125 MHz */ regval = phy_read_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG); regval &= ~AR8035_CLK_25M_MASK; /* No surprises */ @@ -144,6 +360,10 @@ static int ar8035_config(struct phy_device *phydev) if (ret < 0) return ret; + ret = ar803x_regs_config(phydev); + if (ret < 0) + return ret; + phydev->supported = phydev->drv->features; genphy_config_aneg(phydev); diff --git a/include/dt-bindings/net/qca-ar803x.h b/include/dt-bindings/net/qca-ar803x.h new file mode 100644 index 00000000000..9c046c7242e --- /dev/null +++ b/include/dt-bindings/net/qca-ar803x.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Device Tree constants for the Qualcomm Atheros AR803x PHYs + */ + +#ifndef _DT_BINDINGS_QCA_AR803X_H +#define _DT_BINDINGS_QCA_AR803X_H + +#define AR803X_STRENGTH_FULL 0 +#define AR803X_STRENGTH_HALF 1 +#define AR803X_STRENGTH_QUARTER 2 + +#endif -- cgit v1.3.1 From 6333cbb3817ed551cd7d4e92f7359c73ccc567fc Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 May 2020 00:11:58 +0200 Subject: phy: atheros: ar8035: remove static clock config We can configure the clock output in the device tree. Disable the hardcoded one in here. This is highly board-specific and should have never been enabled in the PHY driver. If bisecting shows that this commit breaks your board it probably depends on the clock output of your Atheros AR8035 PHY. Please have a look at doc/device-tree-bindings/net/phy/atheros.txt. You need to set "clk-out-frequency = <125000000>" because that value was the hardcoded value until this commit. Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 3cd301c50ed..31427331052 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -38,12 +38,6 @@ #define AR803x_CLK_25M_62_5MHZ_DSP 5 #define AR803x_CLK_25M_125MHZ_PLL 6 #define AR803x_CLK_25M_125MHZ_DSP 7 - -/* AR8035: Select frequency on CLK_25M pin through bits 4:3 */ -#define AR8035_CLK_25M_FREQ_25M (0 | 0) -#define AR8035_CLK_25M_FREQ_50M (0 | BIT(3)) -#define AR8035_CLK_25M_FREQ_62M (BIT(4) | 0) -#define AR8035_CLK_25M_FREQ_125M (BIT(4) | BIT(3)) #define AR8035_CLK_25M_MASK GENMASK(4, 3) #define AR803x_CLK_25M_DR_MASK GENMASK(8, 7) @@ -344,18 +338,11 @@ static int ar8031_config(struct phy_device *phydev) static int ar8035_config(struct phy_device *phydev) { int ret; - int regval; ret = ar803x_of_init(phydev); if (ret < 0) return ret; - /* Configure CLK_25M output clock at 125 MHz */ - regval = phy_read_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG); - regval &= ~AR8035_CLK_25M_MASK; /* No surprises */ - regval |= AR8035_CLK_25M_FREQ_125M; - phy_write_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG, regval); - ret = ar803x_delay_config(phydev); if (ret < 0) return ret; -- cgit v1.3.1 From 8737c65fe4e315af923efde05e5f30041944be08 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 May 2020 00:11:59 +0200 Subject: phy: atheros: consolidate {ar8031|ar8035}_config() The two functions are now exactly the same, remove one of them. Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- drivers/net/phy/atheros.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 31427331052..47ff9f8d44c 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -311,31 +311,7 @@ static int ar803x_of_init(struct phy_device *phydev) return 0; } -static int ar8031_config(struct phy_device *phydev) -{ - int ret; - - ret = ar803x_of_init(phydev); - if (ret < 0) - return ret; - - ret = ar803x_delay_config(phydev); - if (ret < 0) - return ret; - - ret = ar803x_regs_config(phydev); - if (ret < 0) - return ret; - - phydev->supported = phydev->drv->features; - - genphy_config_aneg(phydev); - genphy_restart_aneg(phydev); - - return 0; -} - -static int ar8035_config(struct phy_device *phydev) +static int ar803x_config(struct phy_device *phydev) { int ret; @@ -374,7 +350,7 @@ static struct phy_driver AR8031_driver = { .uid = AR8031_PHY_ID, .mask = 0xffffffef, .features = PHY_GBIT_FEATURES, - .config = ar8031_config, + .config = ar803x_config, .startup = genphy_startup, .shutdown = genphy_shutdown, }; @@ -384,7 +360,7 @@ static struct phy_driver AR8035_driver = { .uid = AR8035_PHY_ID, .mask = 0xffffffef, .features = PHY_GBIT_FEATURES, - .config = ar8035_config, + .config = ar803x_config, .startup = genphy_startup, .shutdown = genphy_shutdown, }; -- cgit v1.3.1 From 8cc28146f55340777a48c44e948a8ff1143e1c17 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 26 Feb 2020 10:28:41 +0100 Subject: configs: migrate CONFIG_SET_DFU_ALT_INFO to defconfigs Move CONFIG_SET_DFU_ALT_INFO into Kconfig done by moveconfig.py. Signed-off-by: Patrick Delaunay Acked-by: Lukasz Majewski Reviewed-by: Jaehoon Chung --- configs/odroid-xu3_defconfig | 1 + configs/odroid_defconfig | 1 + configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_dhcom_basic_defconfig | 1 + configs/stm32mp15_optee_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + drivers/dfu/Kconfig | 5 +++++ include/configs/odroid.h | 1 - include/configs/odroid_xu3.h | 1 - include/configs/stm32mp1.h | 2 -- scripts/config_whitelist.txt | 1 - 11 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 2e982e1b533..1a2183ce195 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -39,6 +39,7 @@ CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y CONFIG_ADC=y CONFIG_ADC_EXYNOS=y CONFIG_DFU_MMC=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_DW=y CONFIG_MTD=y diff --git a/configs/odroid_defconfig b/configs/odroid_defconfig index e4392e477ed..345cc3b9400 100644 --- a/configs/odroid_defconfig +++ b/configs/odroid_defconfig @@ -40,6 +40,7 @@ CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid" CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y CONFIG_DFU_MMC=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_SYS_I2C_S3C24X0=y CONFIG_MMC_DW=y CONFIG_MMC_SDHCI=y diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 100f174a579..d42153a9566 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -68,6 +68,7 @@ CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_MTD=y CONFIG_DFU_VIRT=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 CONFIG_FASTBOOT_BUF_SIZE=0x02000000 diff --git a/configs/stm32mp15_dhcom_basic_defconfig b/configs/stm32mp15_dhcom_basic_defconfig index 5f3813e515c..753b88463c5 100644 --- a/configs/stm32mp15_dhcom_basic_defconfig +++ b/configs/stm32mp15_dhcom_basic_defconfig @@ -67,6 +67,7 @@ CONFIG_SPL_BLOCK_CACHE=y CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_VIRT=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_DM_HWSPINLOCK=y CONFIG_HWSPINLOCK_STM32=y CONFIG_DM_I2C=y diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index 596fe190af2..53175048431 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -59,6 +59,7 @@ CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_MTD=y CONFIG_DFU_VIRT=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 CONFIG_FASTBOOT_BUF_SIZE=0x02000000 diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index f9df13a6c3b..cff11333481 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -55,6 +55,7 @@ CONFIG_DFU_MMC=y CONFIG_DFU_RAM=y CONFIG_DFU_MTD=y CONFIG_DFU_VIRT=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 CONFIG_FASTBOOT_BUF_SIZE=0x02000000 diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index 174fb588a6e..5d45d7d7c2d 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -81,5 +81,10 @@ config DFU_VIRT used at board level to manage specific behavior (OTP update for example). +config SET_DFU_ALT_INFO + bool "Dynamic set of DFU alternate information" + help + This option allows to call the function set_dfu_alt_info to + dynamically build dfu_alt_info in board. endif endmenu diff --git a/include/configs/odroid.h b/include/configs/odroid.h index a7e2a3d9a23..4044365328f 100644 --- a/include/configs/odroid.h +++ b/include/configs/odroid.h @@ -64,7 +64,6 @@ ""PARTS_BOOT" part 0 1;" \ ""PARTS_ROOT" part 0 2\0" \ -#define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K) #define CONFIG_DFU_ALT_BOOT_EMMC \ diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 47c30543f8f..564319c2311 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -76,7 +76,6 @@ /* Enable: board/samsung/common/misc.c to use set_dfu_alt_info() */ #define CONFIG_MISC_COMMON -#define CONFIG_SET_DFU_ALT_INFO #define CONFIG_SET_DFU_ALT_BUF_LEN (SZ_1K) /* Set soc_rev, soc_id, board_rev, board_name, fdtfile */ diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 2ba4fb1305a..baec6d7e6f0 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -90,8 +90,6 @@ #define CONFIG_SYS_MTDPARTS_RUNTIME #endif -#define CONFIG_SET_DFU_ALT_INFO - #ifdef CONFIG_DM_VIDEO #define CONFIG_VIDEO_BMP_RLE8 #define CONFIG_BMP_16BPP diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 19c92180609..7c18b2481ce 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1523,7 +1523,6 @@ CONFIG_SETUP_MEMORY_TAGS CONFIG_SET_BIST CONFIG_SET_BOOTARGS CONFIG_SET_DFU_ALT_BUF_LEN -CONFIG_SET_DFU_ALT_INFO CONFIG_SFIO CONFIG_SF_DATAFLASH CONFIG_SGI_IP28 -- cgit v1.3.1 From c39e19a9b07807936b8df5925757e0a512effb92 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 26 Feb 2020 10:28:42 +0100 Subject: configs: migrate CONFIG_SYS_MTDPARTS_RUNTIME to defconfigs Move CONFIG_SYS_MTDPARTS_RUNTIME into Kconfig done by moveconfig.py. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- configs/igep00x0_defconfig | 1 + configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_dhcom_basic_defconfig | 1 + configs/stm32mp15_optee_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + drivers/mtd/Kconfig | 7 +++++++ include/configs/omap3_igep00x0.h | 2 -- include/configs/stm32mp1.h | 5 ----- scripts/config_whitelist.txt | 1 - 9 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/configs/igep00x0_defconfig b/configs/igep00x0_defconfig index e273f35e840..a5c301dbdbf 100644 --- a/configs/igep00x0_defconfig +++ b/configs/igep00x0_defconfig @@ -52,6 +52,7 @@ CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM_MMC=y CONFIG_MMC_OMAP_HS=y CONFIG_MTD=y +CONFIG_SYS_MTDPARTS_RUNTIME=y CONFIG_MTD_RAW_NAND=y CONFIG_SYS_NAND_BUSWIDTH_16BIT=y CONFIG_SPL_NAND_SIMPLE=y diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index d42153a9566..a9b996c0a3f 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -88,6 +88,7 @@ CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_STM32_SDMMC2=y CONFIG_MTD=y CONFIG_DM_MTD=y +CONFIG_SYS_MTDPARTS_RUNTIME=y CONFIG_MTD_RAW_NAND=y CONFIG_NAND_STM32_FMC2=y CONFIG_MTD_SPI_NAND=y diff --git a/configs/stm32mp15_dhcom_basic_defconfig b/configs/stm32mp15_dhcom_basic_defconfig index 753b88463c5..661c0544948 100644 --- a/configs/stm32mp15_dhcom_basic_defconfig +++ b/configs/stm32mp15_dhcom_basic_defconfig @@ -81,6 +81,7 @@ CONFIG_DM_MMC=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_STM32_SDMMC2=y CONFIG_MTD=y +CONFIG_SYS_MTDPARTS_RUNTIME=y CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH_MACRONIX=y CONFIG_SPI_FLASH_SPANSION=y diff --git a/configs/stm32mp15_optee_defconfig b/configs/stm32mp15_optee_defconfig index 53175048431..9f886fb0e7d 100644 --- a/configs/stm32mp15_optee_defconfig +++ b/configs/stm32mp15_optee_defconfig @@ -79,6 +79,7 @@ CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_STM32_SDMMC2=y CONFIG_MTD=y CONFIG_DM_MTD=y +CONFIG_SYS_MTDPARTS_RUNTIME=y CONFIG_MTD_RAW_NAND=y CONFIG_NAND_STM32_FMC2=y CONFIG_MTD_SPI_NAND=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index cff11333481..a4ea8c82297 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -75,6 +75,7 @@ CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_STM32_SDMMC2=y CONFIG_MTD=y CONFIG_DM_MTD=y +CONFIG_SYS_MTDPARTS_RUNTIME=y CONFIG_MTD_RAW_NAND=y CONFIG_NAND_STM32_FMC2=y CONFIG_MTD_SPI_NAND=y diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5e7571cf3da..348b43e653f 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -22,6 +22,13 @@ config MTD_NOR_FLASH help Enable support for parallel NOR flash. +config SYS_MTDPARTS_RUNTIME + bool "Allow MTDPARTS to be configured at runtime" + depends on MTD + help + This option allows to call the function board_mtdparts_default to + dynamically build the variables mtdids and mtdparts at runtime. + config FLASH_CFI_DRIVER bool "Enable CFI Flash driver" help diff --git a/include/configs/omap3_igep00x0.h b/include/configs/omap3_igep00x0.h index 4ad7dc18b10..8dc30be8b72 100644 --- a/include/configs/omap3_igep00x0.h +++ b/include/configs/omap3_igep00x0.h @@ -71,8 +71,6 @@ #endif -#define CONFIG_SYS_MTDPARTS_RUNTIME - /* OneNAND config */ #define CONFIG_USE_ONENAND_BOARD_INIT #define CONFIG_SYS_ONENAND_BASE ONENAND_MAP diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index baec6d7e6f0..ae9631ebccd 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -85,11 +85,6 @@ #define CONFIG_SYS_AUTOLOAD "no" #endif -/* Dynamic MTD partition support */ -#if defined(CONFIG_STM32_QSPI) || defined(CONFIG_NAND_STM32_FMC2) -#define CONFIG_SYS_MTDPARTS_RUNTIME -#endif - #ifdef CONFIG_DM_VIDEO #define CONFIG_VIDEO_BMP_RLE8 #define CONFIG_BMP_16BPP diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 7c18b2481ce..2678626b59d 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -3191,7 +3191,6 @@ CONFIG_SYS_MRAM_SIZE CONFIG_SYS_MSC0_VAL CONFIG_SYS_MSC1_VAL CONFIG_SYS_MSC2_VAL -CONFIG_SYS_MTDPARTS_RUNTIME CONFIG_SYS_MX5_CLK32 CONFIG_SYS_MX5_HCLK CONFIG_SYS_MX6_CLK32 -- cgit v1.3.1 From bf38cbf9a289c41a0db6697c280ede73340191e7 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sun, 3 May 2020 22:27:00 +0800 Subject: sata: ahsata: Fix resource leak Fix coverity issue CID 3606684: Resource leak (RESOURCE_LEAK) leaked_storage: Variable uc_priv going out of scope leaks the storage it points to Signed-off-by: Ye Li Signed-off-by: Peng Fan Reviewed-by: Simon Glass --- drivers/ata/dwc_ahsata.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c index c2e28fe518e..a7752147928 100644 --- a/drivers/ata/dwc_ahsata.c +++ b/drivers/ata/dwc_ahsata.c @@ -847,6 +847,9 @@ static int ahci_init_one(int pdev) struct ahci_uc_priv *uc_priv = NULL; uc_priv = malloc(sizeof(struct ahci_uc_priv)); + if (!uc_priv) + return -ENOMEM; + memset(uc_priv, 0, sizeof(struct ahci_uc_priv)); uc_priv->dev = pdev; @@ -871,6 +874,8 @@ static int ahci_init_one(int pdev) return 0; err_out: + if (uc_priv) + free(uc_priv); return rc; } -- cgit v1.3.1 From 87e2cb530fc147676319b7c639e7ce138ddf385e Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sun, 3 May 2020 22:27:01 +0800 Subject: sata: ahsata: Fix wrong operand for checking SERR DIAG_X Fix coverity issue CID 3261683: Wrong operator used (CONSTANT_EXPRESSION_RESULT) operator_confusion: ({...; __v;}) | 67108864 is always 1/true regardless of the values of its operand. This occurs as the logical operand of ! When DIAG_X is set, the PHY COMINIT signal is detected, so should use '&' to check whether it is set. Signed-off-by: Ye Li Signed-off-by: Peng Fan Reviewed-by: Simon Glass --- drivers/ata/dwc_ahsata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c index a7752147928..4b37a023380 100644 --- a/drivers/ata/dwc_ahsata.c +++ b/drivers/ata/dwc_ahsata.c @@ -223,7 +223,7 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv) /* Wait for COMINIT bit 26 (DIAG_X) in SERR */ timeout = 1000; - while (!(readl(&port_mmio->serr) | SATA_PORT_SERR_DIAG_X) + while (!(readl(&port_mmio->serr) & SATA_PORT_SERR_DIAG_X) && --timeout) ; if (timeout <= 0) { -- cgit v1.3.1 From cdff6fba32db88943be2b04639ad6e7746a2be11 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sun, 3 May 2020 22:27:02 +0800 Subject: sata: dwc_ahsata: Fix incorrect free Fix coverity issue CID 43665: Free of address-of expression (BAD_FREE) incorrect_free: free frees incorrect pointer pp. pp points the port array field of struct ahci_uc_priv, should not free it. Acked-by: Peng Fan Signed-off-by: Ye Li Signed-off-by: Peng Fan Reviewed-by: Simon Glass --- drivers/ata/dwc_ahsata.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c index 4b37a023380..82fbb50da62 100644 --- a/drivers/ata/dwc_ahsata.c +++ b/drivers/ata/dwc_ahsata.c @@ -450,7 +450,6 @@ static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port) mem = (u32)malloc(AHCI_PORT_PRIV_DMA_SZ + 1024); if (!mem) { - free(pp); printf("No mem for table!\n"); return -ENOMEM; } -- cgit v1.3.1 From 6b6c620c824e10a03da3c617aa9f2c6486f7f57a Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sun, 3 May 2020 22:27:03 +0800 Subject: sata: dwc_ahsata: Fix memory issue in reset_sata The reset_sata should reset the sata device info and free the probe_ent memory. Otherwise, it will cause memory leak if we init the sata again. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/ata/dwc_ahsata.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c index 82fbb50da62..2bc1de8b98a 100644 --- a/drivers/ata/dwc_ahsata.c +++ b/drivers/ata/dwc_ahsata.c @@ -918,6 +918,9 @@ int reset_sata(int dev) while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) udelay(100); + free(uc_priv); + memset(&sata_dev_desc[dev], 0, sizeof(struct blk_desc)); + return 0; } -- cgit v1.3.1