From 32466c445c49b489b09f99b4ae9b440d76d4720f Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 29 Dec 2017 15:55:55 +0100 Subject: [PATCH 01/35] doc: bindings: soft-spi: update documentation to match the code Linux bindings have been introduced in the code (removing the U-Boot specific ones) without documentation update. Compatible string has changed, as well as the four GPIO properties. Reflect this by updating the soft-spi.txt documentation. Fixes: 102412c415 ("dm: spi: soft_spi: switch to use linux compatible string") Signed-off-by: Miquel Raynal Reviewed-by: Jagan Teki --- doc/device-tree-bindings/spi/soft-spi.txt | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/doc/device-tree-bindings/spi/soft-spi.txt b/doc/device-tree-bindings/spi/soft-spi.txt index d09c1a5076..dfb5066473 100644 --- a/doc/device-tree-bindings/spi/soft-spi.txt +++ b/doc/device-tree-bindings/spi/soft-spi.txt @@ -6,11 +6,15 @@ performance will typically be much lower than a real SPI bus. The soft SPI node requires the following properties: -compatible: "u-boot,soft-spi" -soft_spi_cs: GPIO number to use for SPI chip select (output) -soft_spi_sclk: GPIO number to use for SPI clock (output) -soft_spi_mosi: GPIO number to use for SPI MOSI line (output) -soft_spi_miso GPIO number to use for SPI MISO line (input) +Mandatory properties: +compatible: "spi-gpio" +cs-gpios: GPIOs to use for SPI chip select (output) +gpio-sck: GPIO to use for SPI clock (output) +And at least one of: +gpio-mosi: GPIO to use for SPI MOSI line (output) +gpio-miso: GPIO to use for SPI MISO line (input) + +Optional propertie: spi-delay-us: Number of microseconds of delay between each CS transition The GPIOs should be specified as required by the GPIO controller referenced. @@ -21,11 +25,11 @@ typically holds the GPIO number. Example: soft-spi { - compatible = "u-boot,soft-spi"; - cs-gpio = <&gpio 235 0>; /* Y43 */ - sclk-gpio = <&gpio 225 0>; /* Y31 */ - mosi-gpio = <&gpio 227 0>; /* Y33 */ - miso-gpio = <&gpio 224 0>; /* Y30 */ + compatible = "spi-gpio"; + cs-gpios = <&gpio 235 0>; /* Y43 */ + gpio-sck = <&gpio 225 0>; /* Y31 */ + gpio-mosi = <&gpio 227 0>; /* Y33 */ + gpio-miso = <&gpio 224 0>; /* Y30 */ spi-delay-us = <1>; #address-cells = <1>; #size-cells = <0>; From 91fe458bbfcd6485b9413cf398bbfeb6947861ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:14:54 +0100 Subject: [PATCH 02/35] wait_bit: add 8/16/32 BE/LE versions of wait_for_bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 8/16/32 bits and BE/LE versions of wait_for_bit. This is needed for reading registers that are not aligned to 32 bits, and for Big Endian platforms. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- include/wait_bit.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/include/wait_bit.h b/include/wait_bit.h index 06ad43a122..e8acfa5776 100644 --- a/include/wait_bit.h +++ b/include/wait_bit.h @@ -69,5 +69,70 @@ static inline int wait_for_bit(const char *prefix, const u32 *reg, return -ETIMEDOUT; } +/** + * wait_for_bit_x() waits for bit set/cleared in register + * + * Function polls register waiting for specific bit(s) change + * (either 0->1 or 1->0). It can fail under two conditions: + * - Timeout + * - User interaction (CTRL-C) + * Function succeeds only if all bits of masked register are set/cleared + * (depending on set option). + * + * @param reg Register that will be read (using read_x()) + * @param mask Bit(s) of register that must be active + * @param set Selects wait condition (bit set or clear) + * @param timeout_ms Timeout (in milliseconds) + * @param breakable Enables CTRL-C interruption + * @return 0 on success, -ETIMEDOUT or -EINTR on failure + */ + +#define BUILD_WAIT_FOR_BIT(sfx, type, read) \ + \ +static inline int wait_for_bit_##sfx(const void *reg, \ + const type mask, \ + const bool set, \ + const unsigned int timeout_ms, \ + const bool breakable) \ +{ \ + type val; \ + unsigned long start = get_timer(0); \ + \ + while (1) { \ + val = read(reg); \ + \ + if (!set) \ + val = ~val; \ + \ + if ((val & mask) == mask) \ + return 0; \ + \ + if (get_timer(start) > timeout_ms) \ + break; \ + \ + if (breakable && ctrlc()) { \ + puts("Abort\n"); \ + return -EINTR; \ + } \ + \ + udelay(1); \ + WATCHDOG_RESET(); \ + } \ + \ + debug("%s: Timeout (reg=%p mask=%x wait_set=%i)\n", __func__, \ + reg, mask, set); \ + \ + return -ETIMEDOUT; \ +} + +BUILD_WAIT_FOR_BIT(8, u8, readb) +BUILD_WAIT_FOR_BIT(le16, u16, readw) +#ifdef readw_be +BUILD_WAIT_FOR_BIT(be16, u16, readw_be) +#endif +BUILD_WAIT_FOR_BIT(le32, u32, readl) +#ifdef readl_be +BUILD_WAIT_FOR_BIT(be32, u32, readl_be) +#endif #endif From 48263504c8d501678acaa90c075f3f7cda17c316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:14:55 +0100 Subject: [PATCH 03/35] wait_bit: use wait_for_bit_le32 and remove wait_for_bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wait_for_bit callers use the 32 bit LE version Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- arch/arm/mach-imx/mx6/ddr.c | 22 +++---- arch/arm/mach-socfpga/clock_manager.c | 4 +- arch/arm/mach-socfpga/clock_manager_gen5.c | 6 +- arch/arm/mach-socfpga/reset_manager_arria10.c | 36 +++++------ arch/mips/mach-ath79/ar934x/clk.c | 2 +- board/samtec/vining_2000/vining_2000.c | 4 +- drivers/clk/clk_pic32.c | 12 ++-- drivers/clk/renesas/clk-rcar-gen3.c | 4 +- drivers/ddr/microchip/ddr2.c | 8 +-- drivers/fpga/socfpga_arria10.c | 17 ++--- drivers/mmc/msm_sdhci.c | 8 +-- drivers/mtd/pic32_flash.c | 4 +- drivers/net/ag7xxx.c | 16 ++--- drivers/net/dwc_eth_qos.c | 17 ++--- drivers/net/ethoc.c | 8 +-- drivers/net/pic32_eth.c | 12 ++-- drivers/net/pic32_mdio.c | 28 ++++---- drivers/net/ravb.c | 4 +- drivers/net/xilinx_axi_emac.c | 4 +- drivers/net/zynq_gem.c | 12 ++-- drivers/reset/sti-reset.c | 4 +- drivers/serial/serial_pic32.c | 4 +- drivers/spi/atmel_spi.c | 4 +- drivers/spi/cadence_qspi_apb.c | 14 ++-- drivers/spi/fsl_qspi.c | 20 +++--- drivers/spi/mvebu_a3700_spi.c | 20 +++--- drivers/usb/host/dwc2.c | 24 +++---- drivers/usb/host/ehci-msm.c | 3 +- drivers/usb/host/ehci-mx6.c | 5 +- drivers/usb/host/ohci-lpc32xx.c | 12 ++-- drivers/usb/host/xhci-rcar.c | 12 ++-- drivers/video/atmel_hlcdfb.c | 64 +++++++++---------- include/wait_bit.h | 54 ---------------- 33 files changed, 205 insertions(+), 263 deletions(-) diff --git a/arch/arm/mach-imx/mx6/ddr.c b/arch/arm/mach-imx/mx6/ddr.c index 52a9a25904..f07f938c65 100644 --- a/arch/arm/mach-imx/mx6/ddr.c +++ b/arch/arm/mach-imx/mx6/ddr.c @@ -21,10 +21,10 @@ static void reset_read_data_fifos(void) /* Reset data FIFOs twice. */ setbits_le32(&mmdc0->mpdgctrl0, 1 << 31); - wait_for_bit("MMDC", &mmdc0->mpdgctrl0, 1 << 31, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mpdgctrl0, 1 << 31, 0, 100, 0); setbits_le32(&mmdc0->mpdgctrl0, 1 << 31); - wait_for_bit("MMDC", &mmdc0->mpdgctrl0, 1 << 31, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mpdgctrl0, 1 << 31, 0, 100, 0); } static void precharge_all(const bool cs0_enable, const bool cs1_enable) @@ -39,12 +39,12 @@ static void precharge_all(const bool cs0_enable, const bool cs1_enable) */ if (cs0_enable) { /* CS0 */ writel(0x04008050, &mmdc0->mdscr); - wait_for_bit("MMDC", &mmdc0->mdscr, 1 << 14, 1, 100, 0); + wait_for_bit_le32(&mmdc0->mdscr, 1 << 14, 1, 100, 0); } if (cs1_enable) { /* CS1 */ writel(0x04008058, &mmdc0->mdscr); - wait_for_bit("MMDC", &mmdc0->mdscr, 1 << 14, 1, 100, 0); + wait_for_bit_le32(&mmdc0->mdscr, 1 << 14, 1, 100, 0); } } @@ -146,7 +146,7 @@ int mmdc_do_write_level_calibration(struct mx6_ddr_sysinfo const *sysinfo) * 7. Upon completion of this process the MMDC de-asserts * the MPWLGCR[HW_WL_EN] */ - wait_for_bit("MMDC", &mmdc0->mpwlgcr, 1 << 0, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mpwlgcr, 1 << 0, 0, 100, 0); /* * 8. check for any errors: check both PHYs for x64 configuration, @@ -278,7 +278,7 @@ int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo) writel(0x00008028, &mmdc0->mdscr); /* poll to make sure the con_ack bit was asserted */ - wait_for_bit("MMDC", &mmdc0->mdscr, 1 << 14, 1, 100, 0); + wait_for_bit_le32(&mmdc0->mdscr, 1 << 14, 1, 100, 0); /* * Check MDMISC register CALIB_PER_CS to see which CS calibration @@ -312,7 +312,7 @@ int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo) * this bit until it clears to indicate completion of the write access. */ setbits_le32(&mmdc0->mpswdar0, 1); - wait_for_bit("MMDC", &mmdc0->mpswdar0, 1 << 0, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mpswdar0, 1 << 0, 0, 100, 0); /* Set the RD_DL_ABS# bits to their default values * (will be calibrated later in the read delay-line calibration). @@ -359,7 +359,7 @@ int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo) setbits_le32(&mmdc0->mpdgctrl0, 5 << 28); /* Poll for completion. MPDGCTRL0[HW_DG_EN] should be 0 */ - wait_for_bit("MMDC", &mmdc0->mpdgctrl0, 1 << 28, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mpdgctrl0, 1 << 28, 0, 100, 0); /* * Check to see if any errors were encountered during calibration @@ -423,7 +423,7 @@ int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo) * setting MPRDDLHWCTL[HW_RD_DL_EN] = 0. Also, ensure that * no error bits were set. */ - wait_for_bit("MMDC", &mmdc0->mprddlhwctl, 1 << 4, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mprddlhwctl, 1 << 4, 0, 100, 0); /* check both PHYs for x64 configuration, if x32, check only PHY0 */ if (readl(&mmdc0->mprddlhwctl) & 0x0000000f) @@ -477,7 +477,7 @@ int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo) * by setting MPWRDLHWCTL[HW_WR_DL_EN] = 0. * Also, ensure that no error bits were set. */ - wait_for_bit("MMDC", &mmdc0->mpwrdlhwctl, 1 << 4, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mpwrdlhwctl, 1 << 4, 0, 100, 0); /* Check both PHYs for x64 configuration, if x32, check only PHY0 */ if (readl(&mmdc0->mpwrdlhwctl) & 0x0000000f) @@ -526,7 +526,7 @@ int mmdc_do_dqs_calibration(struct mx6_ddr_sysinfo const *sysinfo) writel(0x0, &mmdc0->mdscr); /* CS0 */ /* Poll to make sure the con_ack bit is clear */ - wait_for_bit("MMDC", &mmdc0->mdscr, 1 << 14, 0, 100, 0); + wait_for_bit_le32(&mmdc0->mdscr, 1 << 14, 0, 100, 0); /* * Print out the registers that were updated as a result diff --git a/arch/arm/mach-socfpga/clock_manager.c b/arch/arm/mach-socfpga/clock_manager.c index cb6ae03696..c740c9f648 100644 --- a/arch/arm/mach-socfpga/clock_manager.c +++ b/arch/arm/mach-socfpga/clock_manager.c @@ -37,8 +37,8 @@ void cm_wait_for_lock(u32 mask) /* function to poll in the fsm busy bit */ int cm_wait_for_fsm(void) { - return wait_for_bit(__func__, (const u32 *)&clock_manager_base->stat, - CLKMGR_STAT_BUSY, false, 20000, false); + return wait_for_bit_le32(&clock_manager_base->stat, + CLKMGR_STAT_BUSY, false, 20000, false); } int set_cpu_clk_info(void) diff --git a/arch/arm/mach-socfpga/clock_manager_gen5.c b/arch/arm/mach-socfpga/clock_manager_gen5.c index 31fd51097a..a23f3fc5d0 100644 --- a/arch/arm/mach-socfpga/clock_manager_gen5.c +++ b/arch/arm/mach-socfpga/clock_manager_gen5.c @@ -37,15 +37,13 @@ static int cm_write_with_phase(u32 value, u32 reg_address, u32 mask) int ret; /* poll until phase is zero */ - ret = wait_for_bit(__func__, (const u32 *)reg_address, mask, - false, 20000, false); + ret = wait_for_bit_le32(reg_address, mask, false, 20000, false); if (ret) return ret; writel(value, reg_address); - return wait_for_bit(__func__, (const u32 *)reg_address, mask, - false, 20000, false); + return wait_for_bit_le32(reg_address, mask, false, 20000, false); } /* diff --git a/arch/arm/mach-socfpga/reset_manager_arria10.c b/arch/arm/mach-socfpga/reset_manager_arria10.c index ae16897494..54f0ddb255 100644 --- a/arch/arm/mach-socfpga/reset_manager_arria10.c +++ b/arch/arm/mach-socfpga/reset_manager_arria10.c @@ -222,8 +222,8 @@ int socfpga_reset_deassert_bridges_handoff(void) clrbits_le32(&reset_manager_base->brgmodrst, mask_rstmgr); /* Poll until all idleack to 0, timeout at 1000ms */ - return wait_for_bit(__func__, &sysmgr_regs->noc_idleack, mask_noc, - false, 1000, false); + return wait_for_bit_le32(&sysmgr_regs->noc_idleack, mask_noc, + false, 1000, false); } void socfpga_reset_assert_fpga_connected_peripherals(void) @@ -343,26 +343,26 @@ int socfpga_bridges_reset(void) writel(ALT_SYSMGR_NOC_TMO_EN_SET_MSK, &sysmgr_regs->noc_timeout); /* Poll until all idleack to 1 */ - ret = wait_for_bit(__func__, &sysmgr_regs->noc_idleack, - ALT_SYSMGR_NOC_H2F_SET_MSK | - ALT_SYSMGR_NOC_LWH2F_SET_MSK | - ALT_SYSMGR_NOC_F2H_SET_MSK | - ALT_SYSMGR_NOC_F2SDR0_SET_MSK | - ALT_SYSMGR_NOC_F2SDR1_SET_MSK | - ALT_SYSMGR_NOC_F2SDR2_SET_MSK, - true, 10000, false); + ret = wait_for_bit_le32(&sysmgr_regs->noc_idleack, + ALT_SYSMGR_NOC_H2F_SET_MSK | + ALT_SYSMGR_NOC_LWH2F_SET_MSK | + ALT_SYSMGR_NOC_F2H_SET_MSK | + ALT_SYSMGR_NOC_F2SDR0_SET_MSK | + ALT_SYSMGR_NOC_F2SDR1_SET_MSK | + ALT_SYSMGR_NOC_F2SDR2_SET_MSK, + true, 10000, false); if (ret) return ret; /* Poll until all idlestatus to 1 */ - ret = wait_for_bit(__func__, &sysmgr_regs->noc_idlestatus, - ALT_SYSMGR_NOC_H2F_SET_MSK | - ALT_SYSMGR_NOC_LWH2F_SET_MSK | - ALT_SYSMGR_NOC_F2H_SET_MSK | - ALT_SYSMGR_NOC_F2SDR0_SET_MSK | - ALT_SYSMGR_NOC_F2SDR1_SET_MSK | - ALT_SYSMGR_NOC_F2SDR2_SET_MSK, - true, 10000, false); + ret = wait_for_bit_le32(&sysmgr_regs->noc_idlestatus, + ALT_SYSMGR_NOC_H2F_SET_MSK | + ALT_SYSMGR_NOC_LWH2F_SET_MSK | + ALT_SYSMGR_NOC_F2H_SET_MSK | + ALT_SYSMGR_NOC_F2SDR0_SET_MSK | + ALT_SYSMGR_NOC_F2SDR1_SET_MSK | + ALT_SYSMGR_NOC_F2SDR2_SET_MSK, + true, 10000, false); if (ret) return ret; diff --git a/arch/mips/mach-ath79/ar934x/clk.c b/arch/mips/mach-ath79/ar934x/clk.c index 9b41d3de60..ba2243c9be 100644 --- a/arch/mips/mach-ath79/ar934x/clk.c +++ b/arch/mips/mach-ath79/ar934x/clk.c @@ -90,7 +90,7 @@ static void ar934x_srif_pll_cfg(void __iomem *pll_reg_base, const u32 srif_val) setbits_be32(pll_reg_base + 0x8, BIT(30)); udelay(5); - wait_for_bit("clk", pll_reg_base + 0xc, BIT(3), 1, 10, 0); + wait_for_bit_le32(pll_reg_base + 0xc, BIT(3), 1, 10, 0); clrbits_be32(pll_reg_base + 0x8, BIT(30)); udelay(5); diff --git a/board/samtec/vining_2000/vining_2000.c b/board/samtec/vining_2000/vining_2000.c index af1a3e75cb..cced08b8b8 100644 --- a/board/samtec/vining_2000/vining_2000.c +++ b/board/samtec/vining_2000/vining_2000.c @@ -378,7 +378,7 @@ static int read_adc(u32 *val) /* start auto calibration */ setbits_le32(b + ADCx_GC, ADCx_GC_CAL); - ret = wait_for_bit("ADC", b + ADCx_GC, ADCx_GC_CAL, ADCx_GC_CAL, 10, 0); + ret = wait_for_bit_le32(b + ADCx_GC, ADCx_GC_CAL, ADCx_GC_CAL, 10, 0); if (ret) goto adc_exit; @@ -386,7 +386,7 @@ static int read_adc(u32 *val) writel(0, b + ADCx_HC0); /* wait for conversion */ - ret = wait_for_bit("ADC", b + ADCx_HS, ADCx_HS_C0, ADCx_HS_C0, 10, 0); + ret = wait_for_bit_le32(b + ADCx_HS, ADCx_HS_C0, ADCx_HS_C0, 10, 0); if (ret) goto adc_exit; diff --git a/drivers/clk/clk_pic32.c b/drivers/clk/clk_pic32.c index f6eef314ec..177803943d 100644 --- a/drivers/clk/clk_pic32.c +++ b/drivers/clk/clk_pic32.c @@ -197,8 +197,8 @@ static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int periph, writel(REFO_ON | REFO_OE, reg + _CLR_OFFSET); /* wait till previous src change is active */ - wait_for_bit(__func__, reg, REFO_DIVSW_EN | REFO_ACTIVE, - false, CONFIG_SYS_HZ, false); + wait_for_bit_le32(reg, REFO_DIVSW_EN | REFO_ACTIVE, + false, CONFIG_SYS_HZ, false); /* parent_id */ v = readl(reg); @@ -223,8 +223,8 @@ static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int periph, writel(REFO_DIVSW_EN, reg + _SET_OFFSET); /* wait for divider switching to complete */ - return wait_for_bit(__func__, reg, REFO_DIVSW_EN, false, - CONFIG_SYS_HZ, false); + return wait_for_bit_le32(reg, REFO_DIVSW_EN, false, + CONFIG_SYS_HZ, false); } static ulong pic32_get_refclk(struct pic32_clk_priv *priv, int periph) @@ -311,8 +311,8 @@ static int pic32_mpll_init(struct pic32_clk_priv *priv) /* Wait for ready */ mask = MPLL_RDY | MPLL_VREG_RDY; - return wait_for_bit(__func__, priv->syscfg_base + CFGMPLL, mask, - true, get_tbclk(), false); + return wait_for_bit_le32(priv->syscfg_base + CFGMPLL, mask, + true, get_tbclk(), false); } static void pic32_clk_init(struct udevice *dev) diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index b26bbcc59f..22828fd470 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -1046,8 +1046,8 @@ static int gen3_clk_endisable(struct clk *clk, bool enable) if (ret) return ret; clrbits_le32(priv->base + SMSTPCR(reg), bitmask); - return wait_for_bit("MSTP", priv->base + MSTPSR(reg), - bitmask, 0, 100, 0); + return wait_for_bit_le32(priv->base + MSTPSR(reg), + bitmask, 0, 100, 0); } else { setbits_le32(priv->base + SMSTPCR(reg), bitmask); return 0; diff --git a/drivers/ddr/microchip/ddr2.c b/drivers/ddr/microchip/ddr2.c index 6056418588..a52427c3d6 100644 --- a/drivers/ddr/microchip/ddr2.c +++ b/drivers/ddr/microchip/ddr2.c @@ -57,8 +57,8 @@ static int ddr2_phy_calib_start(void) writel(SCL_START | SCL_EN, &ddr2_phy->scl_start); /* Wait for SCL for data byte to pass */ - return wait_for_bit(__func__, &ddr2_phy->scl_start, SCL_LUBPASS, - true, CONFIG_SYS_HZ, false); + return wait_for_bit_le32(&ddr2_phy->scl_start, SCL_LUBPASS, + true, CONFIG_SYS_HZ, false); } /* DDR2 Controller initialization */ @@ -256,8 +256,8 @@ void ddr2_ctrl_init(void) writel(INIT_START, &ctrl->memcon); /* wait for all host cmds to be transmitted */ - wait_for_bit(__func__, &ctrl->cmdissue, CMD_VALID, false, - CONFIG_SYS_HZ, false); + wait_for_bit_le32(&ctrl->cmdissue, CMD_VALID, false, + CONFIG_SYS_HZ, false); /* inform all cmds issued, ready for normal operation */ writel(INIT_START | INIT_DONE, &ctrl->memcon); diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c index 5c1a68a009..d5763965dd 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -62,8 +62,7 @@ int is_fpgamgr_user_mode(void) static int wait_for_user_mode(void) { - return wait_for_bit(__func__, - &fpga_manager_base->imgcfg_stat, + return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat, ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK, 1, FPGA_TIMEOUT_MSEC, false); } @@ -115,19 +114,17 @@ static int wait_for_nconfig_pin_and_nstatus_pin(void) /* Poll until f2s_nconfig_pin and f2s_nstatus_pin; loop until de-asserted, * timeout at 1000ms */ - return wait_for_bit(__func__, - &fpga_manager_base->imgcfg_stat, - mask, - false, FPGA_TIMEOUT_MSEC, false); + return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat, + mask, + false, FPGA_TIMEOUT_MSEC, false); } static int wait_for_f2s_nstatus_pin(unsigned long value) { /* Poll until f2s to specific value, timeout at 1000ms */ - return wait_for_bit(__func__, - &fpga_manager_base->imgcfg_stat, - ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK, - value, FPGA_TIMEOUT_MSEC, false); + return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat, + ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK, + value, FPGA_TIMEOUT_MSEC, false); } /* set CD ratio */ diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index 9117ab6bf9..f0661bd96c 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -109,15 +109,15 @@ static int msm_sdc_probe(struct udevice *dev) /* Wait for reset to be written to register */ - if (wait_for_bit(__func__, prv->base + SDCC_MCI_STATUS2, - SDCC_MCI_STATUS2_MCI_ACT, false, 10, false)) { + if (wait_for_bit_le32(prv->base + SDCC_MCI_STATUS2, + SDCC_MCI_STATUS2_MCI_ACT, false, 10, false)) { printf("msm_sdhci: reset request failed\n"); return -EIO; } /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */ - if (wait_for_bit(__func__, prv->base + SDCC_MCI_POWER, - SDCC_MCI_POWER_SW_RST, false, 2, false)) { + if (wait_for_bit_le32(prv->base + SDCC_MCI_POWER, + SDCC_MCI_POWER_SW_RST, false, 2, false)) { printf("msm_sdhci: stuck in reset\n"); return -ETIMEDOUT; } diff --git a/drivers/mtd/pic32_flash.c b/drivers/mtd/pic32_flash.c index e1a8d3bc4b..8bbf2fa9a2 100644 --- a/drivers/mtd/pic32_flash.c +++ b/drivers/mtd/pic32_flash.c @@ -66,8 +66,8 @@ static inline void flash_initiate_operation(u32 nvmop) static int flash_wait_till_busy(const char *func, ulong timeout) { - int ret = wait_for_bit(__func__, &nvm_regs_p->ctrl.raw, - NVM_WR, false, timeout, false); + int ret = wait_for_bit_le32(&nvm_regs_p->ctrl.raw, + NVM_WR, false, timeout, false); return ret ? ERR_TIMOUT : ERR_OK; } diff --git a/drivers/net/ag7xxx.c b/drivers/net/ag7xxx.c index 00e6806892..f28187058e 100644 --- a/drivers/net/ag7xxx.c +++ b/drivers/net/ag7xxx.c @@ -164,8 +164,8 @@ static int ag7xxx_switch_read(struct mii_dev *bus, int addr, int reg, u16 *val) writel(AG7XXX_ETH_MII_MGMT_CMD_READ, regs + AG7XXX_ETH_MII_MGMT_CMD); - ret = wait_for_bit("ag7xxx", regs + AG7XXX_ETH_MII_MGMT_IND, - AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0); + ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND, + AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0); if (ret) return ret; @@ -185,8 +185,8 @@ static int ag7xxx_switch_write(struct mii_dev *bus, int addr, int reg, u16 val) regs + AG7XXX_ETH_MII_MGMT_ADDRESS); writel(val, regs + AG7XXX_ETH_MII_MGMT_CTRL); - ret = wait_for_bit("ag7xxx", regs + AG7XXX_ETH_MII_MGMT_IND, - AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0); + ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND, + AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0); return ret; } @@ -510,13 +510,13 @@ static void ag7xxx_eth_stop(struct udevice *dev) /* Stop the TX DMA. */ writel(0, priv->regs + AG7XXX_ETH_DMA_TX_CTRL); - wait_for_bit("ag7xxx", priv->regs + AG7XXX_ETH_DMA_TX_CTRL, ~0, 0, - 1000, 0); + wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_TX_CTRL, ~0, 0, + 1000, 0); /* Stop the RX DMA. */ writel(0, priv->regs + AG7XXX_ETH_DMA_RX_CTRL); - wait_for_bit("ag7xxx", priv->regs + AG7XXX_ETH_DMA_RX_CTRL, ~0, 0, - 1000, 0); + wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_RX_CTRL, ~0, 0, + 1000, 0); } /* diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 00076cffbe..232e8034df 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -361,8 +361,9 @@ static void eqos_flush_buffer(void *buf, size_t size) static int eqos_mdio_wait_idle(struct eqos_priv *eqos) { - return wait_for_bit(__func__, &eqos->mac_regs->mdio_address, - EQOS_MAC_MDIO_ADDRESS_GB, false, 1000000, true); + return wait_for_bit_le32(&eqos->mac_regs->mdio_address, + EQOS_MAC_MDIO_ADDRESS_GB, false, + 1000000, true); } static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, @@ -588,15 +589,15 @@ static int eqos_calibrate_pads_tegra186(struct udevice *dev) setbits_le32(&eqos->tegra186_regs->auto_cal_config, EQOS_AUTO_CAL_CONFIG_START | EQOS_AUTO_CAL_CONFIG_ENABLE); - ret = wait_for_bit(__func__, &eqos->tegra186_regs->auto_cal_status, - EQOS_AUTO_CAL_STATUS_ACTIVE, true, 10, false); + ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status, + EQOS_AUTO_CAL_STATUS_ACTIVE, true, 10, false); if (ret) { pr_err("calibrate didn't start"); goto failed; } - ret = wait_for_bit(__func__, &eqos->tegra186_regs->auto_cal_status, - EQOS_AUTO_CAL_STATUS_ACTIVE, false, 10, false); + ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status, + EQOS_AUTO_CAL_STATUS_ACTIVE, false, 10, false); if (ret) { pr_err("calibrate didn't finish"); goto failed; @@ -862,8 +863,8 @@ static int eqos_start(struct udevice *dev) eqos->reg_access_ok = true; - ret = wait_for_bit(__func__, &eqos->dma_regs->mode, - EQOS_DMA_MODE_SWR, false, 10, false); + ret = wait_for_bit_le32(&eqos->dma_regs->mode, + EQOS_DMA_MODE_SWR, false, 10, false); if (ret) { pr_err("EQOS_DMA_MODE_SWR stuck"); goto err_stop_resets; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index a6df950081..51a6c97550 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -548,8 +548,8 @@ static int ethoc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(addr, reg)); ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ); - rc = wait_for_bit(__func__, ethoc_reg(priv, MIISTATUS), - MIISTATUS_BUSY, false, CONFIG_SYS_HZ, false); + rc = wait_for_bit_le32(ethoc_reg(priv, MIISTATUS), + MIISTATUS_BUSY, false, CONFIG_SYS_HZ, false); if (rc == 0) { u32 data = ethoc_read(priv, MIIRX_DATA); @@ -571,8 +571,8 @@ static int ethoc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, ethoc_write(priv, MIITX_DATA, val); ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE); - rc = wait_for_bit(__func__, ethoc_reg(priv, MIISTATUS), - MIISTATUS_BUSY, false, CONFIG_SYS_HZ, false); + rc = wait_for_bit_le32(ethoc_reg(priv, MIISTATUS), + MIISTATUS_BUSY, false, CONFIG_SYS_HZ, false); if (rc == 0) { /* reset MII command register */ diff --git a/drivers/net/pic32_eth.c b/drivers/net/pic32_eth.c index 0b89911f04..7129372790 100644 --- a/drivers/net/pic32_eth.c +++ b/drivers/net/pic32_eth.c @@ -64,8 +64,8 @@ static int pic32_mii_init(struct pic32eth_dev *priv) writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr); /* wait till busy */ - wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false, - CONFIG_SYS_HZ, false); + wait_for_bit_le32(&ectl_p->stat.raw, ETHSTAT_BUSY, false, + CONFIG_SYS_HZ, false); /* turn controller ON to access PHY over MII */ writel(ETHCON_ON, &ectl_p->con1.set); @@ -239,8 +239,8 @@ static void pic32_ctrl_reset(struct pic32eth_dev *priv) writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr); /* wait till busy */ - wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false, - CONFIG_SYS_HZ, false); + wait_for_bit_le32(&ectl_p->stat.raw, ETHSTAT_BUSY, false, + CONFIG_SYS_HZ, false); /* decrement received buffcnt to zero. */ while (readl(&ectl_p->stat.raw) & ETHSTAT_BUFCNT) writel(ETHCON_BUFCDEC, &ectl_p->con1.set); @@ -375,8 +375,8 @@ static void pic32_eth_stop(struct udevice *dev) mdelay(10); /* wait until everything is down */ - wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false, - 2 * CONFIG_SYS_HZ, false); + wait_for_bit_le32(&ectl_p->stat.raw, ETHSTAT_BUSY, false, + 2 * CONFIG_SYS_HZ, false); /* clear any existing interrupt event */ writel(0xffffffff, &ectl_p->irq.clr); diff --git a/drivers/net/pic32_mdio.c b/drivers/net/pic32_mdio.c index 578fc96905..6ae5c40fa3 100644 --- a/drivers/net/pic32_mdio.c +++ b/drivers/net/pic32_mdio.c @@ -22,8 +22,8 @@ static int pic32_mdio_write(struct mii_dev *bus, struct pic32_mii_regs *mii_regs = bus->priv; /* Wait for the previous operation to finish */ - wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY, - false, CONFIG_SYS_HZ, true); + wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, + false, CONFIG_SYS_HZ, true); /* Put phyaddr and regaddr into MIIMADD */ v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR); @@ -36,8 +36,8 @@ static int pic32_mdio_write(struct mii_dev *bus, udelay(12); /* Wait for write to complete */ - wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY, - false, CONFIG_SYS_HZ, true); + wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, + false, CONFIG_SYS_HZ, true); return 0; } @@ -48,8 +48,8 @@ static int pic32_mdio_read(struct mii_dev *bus, int addr, int devaddr, int reg) struct pic32_mii_regs *mii_regs = bus->priv; /* Wait for the previous operation to finish */ - wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY, - false, CONFIG_SYS_HZ, true); + wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, + false, CONFIG_SYS_HZ, true); /* Put phyaddr and regaddr into MIIMADD */ v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR); @@ -62,9 +62,9 @@ static int pic32_mdio_read(struct mii_dev *bus, int addr, int devaddr, int reg) udelay(12); /* Wait for read to complete */ - wait_for_bit(__func__, &mii_regs->mind.raw, - MIIMIND_NOTVALID | MIIMIND_BUSY, - false, CONFIG_SYS_HZ, false); + wait_for_bit_le32(&mii_regs->mind.raw, + MIIMIND_NOTVALID | MIIMIND_BUSY, + false, CONFIG_SYS_HZ, false); /* Clear the command register */ writel(0, &mii_regs->mcmd.raw); @@ -82,22 +82,22 @@ static int pic32_mdio_reset(struct mii_dev *bus) writel(MIIMCFG_RSTMGMT, &mii_regs->mcfg.raw); /* Wait for the operation to finish */ - wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY, + wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, false, CONFIG_SYS_HZ, true); /* Clear reset bit */ writel(0, &mii_regs->mcfg); /* Wait for the operation to finish */ - wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY, - false, CONFIG_SYS_HZ, true); + wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, + false, CONFIG_SYS_HZ, true); /* Set the MII Management Clock (MDC) - no faster than 2.5 MHz */ writel(MIIMCFG_CLKSEL_DIV40, &mii_regs->mcfg.raw); /* Wait for the operation to finish */ - wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY, - false, CONFIG_SYS_HZ, true); + wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, + false, CONFIG_SYS_HZ, true); return 0; } diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index dc743e113d..26bd915291 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -222,8 +222,8 @@ static int ravb_reset(struct udevice *dev) writel(CCC_OPC_CONFIG, eth->iobase + RAVB_REG_CCC); /* Check the operating mode is changed to the config mode. */ - return wait_for_bit(dev->name, (void *)eth->iobase + RAVB_REG_CSR, - CSR_OPS_CONFIG, true, 100, true); + return wait_for_bit_le32(eth->iobase + RAVB_REG_CSR, + CSR_OPS_CONFIG, true, 100, true); } static void ravb_base_desc_init(struct ravb_priv *eth) diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index 9a2a578ff9..70a2e95a8e 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -366,8 +366,8 @@ static int axi_ethernet_init(struct axidma_priv *priv) * processor mode and hence bypass in this mode */ if (!priv->eth_hasnobuf) { - err = wait_for_bit(__func__, (const u32 *)®s->is, - XAE_INT_MGTRDY_MASK, true, 200, false); + err = wait_for_bit_le32(®s->is, XAE_INT_MGTRDY_MASK, + true, 200, false); if (err) { printf("%s: Timeout\n", __func__); return 1; diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 1dfd631e1a..2cc49bca92 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -192,8 +192,8 @@ static u32 phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum, struct zynq_gem_regs *regs = priv->iobase; int err; - err = wait_for_bit(__func__, ®s->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK, - true, 20000, false); + err = wait_for_bit_le32(®s->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK, + true, 20000, false); if (err) return err; @@ -205,8 +205,8 @@ static u32 phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum, /* Write mgtcr and wait for completion */ writel(mgtcr, ®s->phymntnc); - err = wait_for_bit(__func__, ®s->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK, - true, 20000, false); + err = wait_for_bit_le32(®s->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK, + true, 20000, false); if (err) return err; @@ -514,8 +514,8 @@ static int zynq_gem_send(struct udevice *dev, void *ptr, int len) if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED) printf("TX buffers exhausted in mid frame\n"); - return wait_for_bit(__func__, ®s->txsr, ZYNQ_GEM_TSR_DONE, - true, 20000, true); + return wait_for_bit_le32(®s->txsr, ZYNQ_GEM_TSR_DONE, + true, 20000, true); } /* Do not check frame_recd flag in rx_status register 0x20 - just poll BD */ diff --git a/drivers/reset/sti-reset.c b/drivers/reset/sti-reset.c index 17786f976a..0fc5a28802 100644 --- a/drivers/reset/sti-reset.c +++ b/drivers/reset/sti-reset.c @@ -266,8 +266,8 @@ static int sti_reset_program_hw(struct reset_ctl *reset_ctl, int assert) return 0; reg = (void __iomem *)base + ch->ack_offset; - if (wait_for_bit(__func__, reg, BIT(ch->ack_bit), ctrl_val, - 1000, false)) { + if (wait_for_bit_le32(reg, BIT(ch->ack_bit), ctrl_val, + 1000, false)) { pr_err("Stuck on waiting ack reset_ctl=%p dev=%p id=%lu\n", reset_ctl, reset_ctl->dev, reset_ctl->id); diff --git a/drivers/serial/serial_pic32.c b/drivers/serial/serial_pic32.c index b0e01aa0e5..0632d26211 100644 --- a/drivers/serial/serial_pic32.c +++ b/drivers/serial/serial_pic32.c @@ -51,8 +51,8 @@ static int pic32_serial_init(void __iomem *base, ulong clk, u32 baudrate) u32 div = DIV_ROUND_CLOSEST(clk, baudrate * 16); /* wait for TX FIFO to empty */ - wait_for_bit(__func__, base + U_STA, UART_TX_EMPTY, - true, CONFIG_SYS_HZ, false); + wait_for_bit_le32(base + U_STA, UART_TX_EMPTY, + true, CONFIG_SYS_HZ, false); /* send break */ writel(UART_TX_BRK, base + U_STASET); diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 228e714e09..8010ab434c 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -394,8 +394,8 @@ out: * Wait until the transfer is completely done before * we deactivate CS. */ - wait_for_bit(__func__, ®_base->sr, - ATMEL_SPI_SR_TXEMPTY, true, 1000, false); + wait_for_bit_le32(®_base->sr, + ATMEL_SPI_SR_TXEMPTY, true, 1000, false); atmel_spi_cs_deactivate(dev); } diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index e02f2217f4..dca3fdfdea 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -675,8 +675,8 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, } /* Check indirect done status */ - ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_INDIRECTRD, - CQSPI_REG_INDIRECTRD_DONE, 1, 10, 0); + ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTRD, + CQSPI_REG_INDIRECTRD_DONE, 1, 10, 0); if (ret) { printf("Indirect read completion error (%i)\n", ret); goto failrd; @@ -762,9 +762,9 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, bb_txbuf + rounddown(write_bytes, 4), write_bytes % 4); - ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_SDRAMLEVEL, - CQSPI_REG_SDRAMLEVEL_WR_MASK << - CQSPI_REG_SDRAMLEVEL_WR_LSB, 0, 10, 0); + ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_SDRAMLEVEL, + CQSPI_REG_SDRAMLEVEL_WR_MASK << + CQSPI_REG_SDRAMLEVEL_WR_LSB, 0, 10, 0); if (ret) { printf("Indirect write timed out (%i)\n", ret); goto failwr; @@ -775,8 +775,8 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, } /* Check indirect done status */ - ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_INDIRECTWR, - CQSPI_REG_INDIRECTWR_DONE, 1, 10, 0); + ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTWR, + CQSPI_REG_INDIRECTWR_DONE, 1, 10, 0); if (ret) { printf("Indirect write completion error (%i)\n", ret); goto failwr; diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 0f3f7d97f0..eed52c15c8 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -1011,11 +1011,11 @@ static int fsl_qspi_probe(struct udevice *bus) priv->num_chipselect = plat->num_chipselect; /* make sure controller is not busy anywhere */ - ret = wait_for_bit(__func__, &priv->regs->sr, - QSPI_SR_BUSY_MASK | - QSPI_SR_AHB_ACC_MASK | - QSPI_SR_IP_ACC_MASK, - false, 100, false); + ret = wait_for_bit_le32(&priv->regs->sr, + QSPI_SR_BUSY_MASK | + QSPI_SR_AHB_ACC_MASK | + QSPI_SR_IP_ACC_MASK, + false, 100, false); if (ret) { debug("ERROR : The controller is busy\n"); @@ -1173,11 +1173,11 @@ static int fsl_qspi_claim_bus(struct udevice *dev) priv = dev_get_priv(bus); /* make sure controller is not busy anywhere */ - ret = wait_for_bit(__func__, &priv->regs->sr, - QSPI_SR_BUSY_MASK | - QSPI_SR_AHB_ACC_MASK | - QSPI_SR_IP_ACC_MASK, - false, 100, false); + ret = wait_for_bit_le32(&priv->regs->sr, + QSPI_SR_BUSY_MASK | + QSPI_SR_AHB_ACC_MASK | + QSPI_SR_IP_ACC_MASK, + false, 100, false); if (ret) { debug("ERROR : The controller is busy\n"); diff --git a/drivers/spi/mvebu_a3700_spi.c b/drivers/spi/mvebu_a3700_spi.c index ec4907391c..d1708a8d56 100644 --- a/drivers/spi/mvebu_a3700_spi.c +++ b/drivers/spi/mvebu_a3700_spi.c @@ -95,8 +95,9 @@ static int spi_legacy_shift_byte(struct spi_reg *reg, unsigned int bytelen, din_8 = din; while (bytelen) { - ret = wait_for_bit(__func__, ®->ctrl, - MVEBU_SPI_A3700_XFER_RDY, true, 100, false); + ret = wait_for_bit_le32(®->ctrl, + MVEBU_SPI_A3700_XFER_RDY, + true,100, false); if (ret) return ret; @@ -109,9 +110,9 @@ static int spi_legacy_shift_byte(struct spi_reg *reg, unsigned int bytelen, writel(pending_dout, ®->dout); if (din) { - ret = wait_for_bit(__func__, ®->ctrl, - MVEBU_SPI_A3700_XFER_RDY, - true, 100, false); + ret = wait_for_bit_le32(®->ctrl, + MVEBU_SPI_A3700_XFER_RDY, + true, 100, false); if (ret) return ret; @@ -160,8 +161,9 @@ static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Deactivate CS */ if (flags & SPI_XFER_END) { - ret = wait_for_bit(__func__, ®->ctrl, - MVEBU_SPI_A3700_XFER_RDY, true, 100, false); + ret = wait_for_bit_le32(®->ctrl, + MVEBU_SPI_A3700_XFER_RDY, + true, 100, false); if (ret) return ret; @@ -231,8 +233,8 @@ static int mvebu_spi_probe(struct udevice *bus) /* Flush read/write FIFO */ data = readl(®->cfg); writel(data | MVEBU_SPI_A3700_FIFO_FLUSH, ®->cfg); - ret = wait_for_bit(__func__, ®->cfg, MVEBU_SPI_A3700_FIFO_FLUSH, - false, 1000, false); + ret = wait_for_bit_le32(®->cfg, MVEBU_SPI_A3700_FIFO_FLUSH, + false, 1000, false); if (ret) return ret; diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 1293e18f75..540c016412 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -108,8 +108,8 @@ static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num) writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET), ®s->grstctl); - ret = wait_for_bit(__func__, ®s->grstctl, DWC2_GRSTCTL_TXFFLSH, - false, 1000, false); + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_TXFFLSH, + false, 1000, false); if (ret) printf("%s: Timeout!\n", __func__); @@ -127,8 +127,8 @@ static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs) int ret; writel(DWC2_GRSTCTL_RXFFLSH, ®s->grstctl); - ret = wait_for_bit(__func__, ®s->grstctl, DWC2_GRSTCTL_RXFFLSH, - false, 1000, false); + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_RXFFLSH, + false, 1000, false); if (ret) printf("%s: Timeout!\n", __func__); @@ -145,15 +145,15 @@ static void dwc_otg_core_reset(struct dwc2_core_regs *regs) int ret; /* Wait for AHB master IDLE state. */ - ret = wait_for_bit(__func__, ®s->grstctl, DWC2_GRSTCTL_AHBIDLE, - true, 1000, false); + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_AHBIDLE, + true, 1000, false); if (ret) printf("%s: Timeout!\n", __func__); /* Core Soft Reset */ writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); - ret = wait_for_bit(__func__, ®s->grstctl, DWC2_GRSTCTL_CSFTRST, - false, 1000, false); + ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_CSFTRST, + false, 1000, false); if (ret) printf("%s: Timeout!\n", __func__); @@ -267,8 +267,8 @@ static void dwc_otg_core_host_init(struct udevice *dev, clrsetbits_le32(®s->hc_regs[i].hcchar, DWC2_HCCHAR_EPDIR, DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS); - ret = wait_for_bit(__func__, ®s->hc_regs[i].hcchar, - DWC2_HCCHAR_CHEN, false, 1000, false); + ret = wait_for_bit_le32(®s->hc_regs[i].hcchar, + DWC2_HCCHAR_CHEN, false, 1000, false); if (ret) printf("%s: Timeout!\n", __func__); } @@ -783,8 +783,8 @@ int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle) int ret; uint32_t hcint, hctsiz; - ret = wait_for_bit(__func__, &hc_regs->hcint, DWC2_HCINT_CHHLTD, true, - 1000, false); + ret = wait_for_bit_le32(&hc_regs->hcint, DWC2_HCINT_CHHLTD, true, + 1000, false); if (ret) return ret; diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 2c0c63322c..f5320ca298 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -133,8 +133,7 @@ static int ehci_usb_remove(struct udevice *dev) setbits_le32(&ehci->usbcmd, CMD_RESET); /* Wait for reset */ - if (wait_for_bit(__func__, &ehci->usbcmd, CMD_RESET, false, 30, - false)) { + if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) { printf("Stuck on USB reset.\n"); return -ETIMEDOUT; } diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index fe2627ea93..2c8fc3c4b1 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -142,13 +142,12 @@ static int usb_phy_enable(int index, struct usb_ehci *ehci) /* Stop then Reset */ clrbits_le32(usb_cmd, UCMD_RUN_STOP); - ret = wait_for_bit(__func__, usb_cmd, UCMD_RUN_STOP, false, 10000, - false); + ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false); if (ret) return ret; setbits_le32(usb_cmd, UCMD_RESET); - ret = wait_for_bit(__func__, usb_cmd, UCMD_RESET, false, 10000, false); + ret = wait_for_bit_le32(usb_cmd, UCMD_RESET, false, 10000, false); if (ret) return ret; diff --git a/drivers/usb/host/ohci-lpc32xx.c b/drivers/usb/host/ohci-lpc32xx.c index 2f2b4b90de..44a49807a4 100644 --- a/drivers/usb/host/ohci-lpc32xx.c +++ b/drivers/usb/host/ohci-lpc32xx.c @@ -143,8 +143,8 @@ static int usbpll_setup(void) setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_POSTDIV_2POW(0x01)); setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_PWRUP); - ret = wait_for_bit(__func__, &clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_STS, - true, CONFIG_SYS_HZ, false); + ret = wait_for_bit_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_STS, + true, CONFIG_SYS_HZ, false); if (ret) return ret; @@ -178,8 +178,8 @@ int usb_cpu_init(void) /* enable I2C clock */ writel(OTG_CLK_I2C_EN, &otg->otg_clk_ctrl); - ret = wait_for_bit(__func__, &otg->otg_clk_sts, OTG_CLK_I2C_EN, true, - CONFIG_SYS_HZ, false); + ret = wait_for_bit_le32(&otg->otg_clk_sts, OTG_CLK_I2C_EN, true, + CONFIG_SYS_HZ, false); if (ret) return ret; @@ -199,8 +199,8 @@ int usb_cpu_init(void) OTG_CLK_I2C_EN | OTG_CLK_HOST_EN; writel(mask, &otg->otg_clk_ctrl); - ret = wait_for_bit(__func__, &otg->otg_clk_sts, mask, true, - CONFIG_SYS_HZ, false); + ret = wait_for_bit_le32(&otg->otg_clk_sts, mask, true, + CONFIG_SYS_HZ, false); if (ret) return ret; diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index d47c99644d..71202d7b03 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -55,18 +55,18 @@ static int xhci_rcar_download_fw(struct rcar_xhci *ctx, const u32 *fw_data, setbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_FW_SET_DATA0); - ret = wait_for_bit("xhci-rcar", regs + RCAR_USB3_DL_CTRL, - RCAR_USB3_DL_CTRL_FW_SET_DATA0, false, - 10, false); + ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL, + RCAR_USB3_DL_CTRL_FW_SET_DATA0, false, + 10, false); if (ret) break; } clrbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_ENABLE); - ret = wait_for_bit("xhci-rcar", regs + RCAR_USB3_DL_CTRL, - RCAR_USB3_DL_CTRL_FW_SUCCESS, true, - 10, false); + ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL, + RCAR_USB3_DL_CTRL_FW_SUCCESS, true, + 10, false); return ret; } diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c index f77da2ec97..c0dd689e7c 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -70,26 +70,26 @@ void lcd_ctrl_init(void *lcdbase) /* Disable DISP signal */ writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable synchronization */ writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable pixel clock */ writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable PWM */ writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); @@ -215,26 +215,26 @@ void lcd_ctrl_init(void *lcdbase) /* Enable LCD */ value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); @@ -299,26 +299,26 @@ static void atmel_hlcdc_init(struct udevice *dev) /* Disable DISP signal */ writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable synchronization */ writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable pixel clock */ writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable PWM */ writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, - false, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + false, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); @@ -451,26 +451,26 @@ static void atmel_hlcdc_init(struct udevice *dev) /* Enable LCD */ value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); value = readl(®s->lcdc_lcden); writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); - ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, - true, 1000, false); + ret = wait_for_bit_le32(®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + true, 1000, false); if (ret) printf("%s: %d: Timeout!\n", __func__, __LINE__); } diff --git a/include/wait_bit.h b/include/wait_bit.h index e8acfa5776..bd021baa48 100644 --- a/include/wait_bit.h +++ b/include/wait_bit.h @@ -15,60 +15,6 @@ #include #include -/** - * wait_for_bit() waits for bit set/cleared in register - * - * Function polls register waiting for specific bit(s) change - * (either 0->1 or 1->0). It can fail under two conditions: - * - Timeout - * - User interaction (CTRL-C) - * Function succeeds only if all bits of masked register are set/cleared - * (depending on set option). - * - * @param prefix Prefix added to timeout messagge (message visible only - * with debug enabled) - * @param reg Register that will be read (using readl()) - * @param mask Bit(s) of register that must be active - * @param set Selects wait condition (bit set or clear) - * @param timeout_ms Timeout (in miliseconds) - * @param breakable Enables CTRL-C interruption - * @return 0 on success, -ETIMEDOUT or -EINTR on failure - */ -static inline int wait_for_bit(const char *prefix, const u32 *reg, - const u32 mask, const bool set, - const unsigned int timeout_ms, - const bool breakable) -{ - u32 val; - unsigned long start = get_timer(0); - - while (1) { - val = readl(reg); - - if (!set) - val = ~val; - - if ((val & mask) == mask) - return 0; - - if (get_timer(start) > timeout_ms) - break; - - if (breakable && ctrlc()) { - puts("Abort\n"); - return -EINTR; - } - - udelay(1); - WATCHDOG_RESET(); - } - - debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n", prefix, reg, mask, - set); - - return -ETIMEDOUT; -} - /** * wait_for_bit_x() waits for bit set/cleared in register * From 8af74edc30bb60a90a5c4d2769ff3129b187796e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:14:56 +0100 Subject: [PATCH 04/35] drivers: spi: allow limiting reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some SPI controllers it's not possible to keep the CS active between transfers and they are limited to a known number of bytes. This splits spi_flash reads into different iterations in order to respect the SPI controller limits. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi_flash.c | 3 +++ include/spi.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 51e28bf07b..e40e1c01de 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -516,6 +516,9 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, else read_len = remain_len; + if (spi->max_read_size) + read_len = min(read_len, spi->max_read_size); + spi_flash_addr(read_addr, cmd); ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); diff --git a/include/spi.h b/include/spi.h index 08c7480fda..4787454e59 100644 --- a/include/spi.h +++ b/include/spi.h @@ -86,6 +86,8 @@ struct dm_spi_slave_platdata { * @cs: ID of the chip select connected to the slave. * @mode: SPI mode to use for this slave (see SPI mode flags) * @wordlen: Size of SPI word in number of bits + * @max_read_size: If non-zero, the maximum number of bytes which can + * be read at once. * @max_write_size: If non-zero, the maximum number of bytes which can * be written at once, excluding command bytes. * @memory_map: Address of read-only SPI flash access. @@ -102,6 +104,7 @@ struct spi_slave { #endif uint mode; unsigned int wordlen; + unsigned int max_read_size; unsigned int max_write_size; void *memory_map; From 6c94bd12c4adca45033ef89daafa66fbfc9acd17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:14:57 +0100 Subject: [PATCH 05/35] drivers: spi: consider command bytes when sending transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Command bytes are part of the written bytes and they should be taken into account when sending a spi transfer. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi_flash.c | 2 +- include/spi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index e40e1c01de..294d9f9d79 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -405,7 +405,7 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, if (spi->max_write_size) chunk_len = min(chunk_len, - (size_t)spi->max_write_size); + spi->max_write_size - sizeof(cmd)); spi_flash_addr(write_addr, cmd); diff --git a/include/spi.h b/include/spi.h index 4787454e59..5a7df1c706 100644 --- a/include/spi.h +++ b/include/spi.h @@ -89,7 +89,7 @@ struct dm_spi_slave_platdata { * @max_read_size: If non-zero, the maximum number of bytes which can * be read at once. * @max_write_size: If non-zero, the maximum number of bytes which can - * be written at once, excluding command bytes. + * be written at once. * @memory_map: Address of read-only SPI flash access. * @flags: Indication of SPI flags. */ From 5ac07d2969e7f1ea2582f97ccacbe9ad9c9d62fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:14:58 +0100 Subject: [PATCH 06/35] dm: spi: add BCM63xx SPI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver is a simplified version of linux/drivers/spi/spi-bcm63xx.c Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/bcm63xx_spi.c | 433 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 442 insertions(+) create mode 100644 drivers/spi/bcm63xx_spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 494639fb01..ebc71c2e42 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -40,6 +40,14 @@ config ATMEL_SPI many AT91 (ARM) chips. This driver can be used to access the SPI Flash, such as AT25DF321. +config BCM63XX_SPI + bool "BCM6348 SPI driver" + depends on ARCH_BMIPS + help + Enable the BCM6348/BCM6358 SPI driver. This driver can be used to + access the SPI NOR flash on platforms embedding these Broadcom + SPI cores. + config CADENCE_QSPI bool "Cadence QSPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index e3184db67f..5770b3f7cc 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -18,6 +18,7 @@ endif obj-$(CONFIG_ALTERA_SPI) += altera_spi.o obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o +obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o obj-$(CONFIG_CF_SPI) += cf_spi.o obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o diff --git a/drivers/spi/bcm63xx_spi.c b/drivers/spi/bcm63xx_spi.c new file mode 100644 index 0000000000..f0df6871d8 --- /dev/null +++ b/drivers/spi/bcm63xx_spi.c @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2017 Álvaro Fernández Rojas + * + * Derived from linux/drivers/spi/spi-bcm63xx.c: + * Copyright (C) 2009-2012 Florian Fainelli + * Copyright (C) 2010 Tanguy Bouzeloc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* BCM6348 SPI core */ +#define SPI_6348_CLK 0x06 +#define SPI_6348_CMD 0x00 +#define SPI_6348_CTL 0x40 +#define SPI_6348_CTL_SHIFT 6 +#define SPI_6348_FILL 0x07 +#define SPI_6348_IR_MASK 0x04 +#define SPI_6348_IR_STAT 0x02 +#define SPI_6348_RX 0x80 +#define SPI_6348_RX_SIZE 0x3f +#define SPI_6348_TX 0x41 +#define SPI_6348_TX_SIZE 0x3f + +/* BCM6358 SPI core */ +#define SPI_6358_CLK 0x706 +#define SPI_6358_CMD 0x700 +#define SPI_6358_CTL 0x000 +#define SPI_6358_CTL_SHIFT 14 +#define SPI_6358_FILL 0x707 +#define SPI_6358_IR_MASK 0x702 +#define SPI_6358_IR_STAT 0x704 +#define SPI_6358_RX 0x400 +#define SPI_6358_RX_SIZE 0x220 +#define SPI_6358_TX 0x002 +#define SPI_6358_TX_SIZE 0x21e + +/* SPI Clock register */ +#define SPI_CLK_SHIFT 0 +#define SPI_CLK_20MHZ (0 << SPI_CLK_SHIFT) +#define SPI_CLK_0_391MHZ (1 << SPI_CLK_SHIFT) +#define SPI_CLK_0_781MHZ (2 << SPI_CLK_SHIFT) +#define SPI_CLK_1_563MHZ (3 << SPI_CLK_SHIFT) +#define SPI_CLK_3_125MHZ (4 << SPI_CLK_SHIFT) +#define SPI_CLK_6_250MHZ (5 << SPI_CLK_SHIFT) +#define SPI_CLK_12_50MHZ (6 << SPI_CLK_SHIFT) +#define SPI_CLK_25MHZ (7 << SPI_CLK_SHIFT) +#define SPI_CLK_MASK (7 << SPI_CLK_SHIFT) +#define SPI_CLK_SSOFF_SHIFT 3 +#define SPI_CLK_SSOFF_2 (2 << SPI_CLK_SSOFF_SHIFT) +#define SPI_CLK_SSOFF_MASK (7 << SPI_CLK_SSOFF_SHIFT) +#define SPI_CLK_BSWAP_SHIFT 7 +#define SPI_CLK_BSWAP_MASK (1 << SPI_CLK_BSWAP_SHIFT) + +/* SPI Command register */ +#define SPI_CMD_OP_SHIFT 0 +#define SPI_CMD_OP_START (0x3 << SPI_CMD_OP_SHIFT) +#define SPI_CMD_SLAVE_SHIFT 4 +#define SPI_CMD_SLAVE_MASK (0xf << SPI_CMD_SLAVE_SHIFT) +#define SPI_CMD_PREPEND_SHIFT 8 +#define SPI_CMD_PREPEND_BYTES 0xf +#define SPI_CMD_3WIRE_SHIFT 12 +#define SPI_CMD_3WIRE_MASK (1 << SPI_CMD_3WIRE_SHIFT) + +/* SPI Control register */ +#define SPI_CTL_TYPE_FD_RW 0 +#define SPI_CTL_TYPE_HD_W 1 +#define SPI_CTL_TYPE_HD_R 2 + +/* SPI Interrupt registers */ +#define SPI_IR_DONE_SHIFT 0 +#define SPI_IR_DONE_MASK (1 << SPI_IR_DONE_SHIFT) +#define SPI_IR_RXOVER_SHIFT 1 +#define SPI_IR_RXOVER_MASK (1 << SPI_IR_RXOVER_SHIFT) +#define SPI_IR_TXUNDER_SHIFT 2 +#define SPI_IR_TXUNDER_MASK (1 << SPI_IR_TXUNDER_SHIFT) +#define SPI_IR_TXOVER_SHIFT 3 +#define SPI_IR_TXOVER_MASK (1 << SPI_IR_TXOVER_SHIFT) +#define SPI_IR_RXUNDER_SHIFT 4 +#define SPI_IR_RXUNDER_MASK (1 << SPI_IR_RXUNDER_SHIFT) +#define SPI_IR_CLEAR_MASK (SPI_IR_DONE_MASK |\ + SPI_IR_RXOVER_MASK |\ + SPI_IR_TXUNDER_MASK |\ + SPI_IR_TXOVER_MASK |\ + SPI_IR_RXUNDER_MASK) + +enum bcm63xx_regs_spi { + SPI_CLK, + SPI_CMD, + SPI_CTL, + SPI_CTL_SHIFT, + SPI_FILL, + SPI_IR_MASK, + SPI_IR_STAT, + SPI_RX, + SPI_RX_SIZE, + SPI_TX, + SPI_TX_SIZE, +}; + +struct bcm63xx_spi_priv { + const unsigned long *regs; + void __iomem *base; + size_t tx_bytes; + uint8_t num_cs; +}; + +#define SPI_CLK_CNT 8 +static const unsigned bcm63xx_spi_freq_table[SPI_CLK_CNT][2] = { + { 25000000, SPI_CLK_25MHZ }, + { 20000000, SPI_CLK_20MHZ }, + { 12500000, SPI_CLK_12_50MHZ }, + { 6250000, SPI_CLK_6_250MHZ }, + { 3125000, SPI_CLK_3_125MHZ }, + { 1563000, SPI_CLK_1_563MHZ }, + { 781000, SPI_CLK_0_781MHZ }, + { 391000, SPI_CLK_0_391MHZ } +}; + +static int bcm63xx_spi_cs_info(struct udevice *bus, uint cs, + struct spi_cs_info *info) +{ + struct bcm63xx_spi_priv *priv = dev_get_priv(bus); + + if (cs >= priv->num_cs) { + printf("no cs %u\n", cs); + return -ENODEV; + } + + return 0; +} + +static int bcm63xx_spi_set_mode(struct udevice *bus, uint mode) +{ + struct bcm63xx_spi_priv *priv = dev_get_priv(bus); + const unsigned long *regs = priv->regs; + + if (mode & SPI_LSB_FIRST) + setbits_8(priv->base + regs[SPI_CLK], SPI_CLK_BSWAP_MASK); + else + clrbits_8(priv->base + regs[SPI_CLK], SPI_CLK_BSWAP_MASK); + + return 0; +} + +static int bcm63xx_spi_set_speed(struct udevice *bus, uint speed) +{ + struct bcm63xx_spi_priv *priv = dev_get_priv(bus); + const unsigned long *regs = priv->regs; + uint8_t clk_cfg; + int i; + + /* default to lowest clock configuration */ + clk_cfg = SPI_CLK_0_391MHZ; + + /* find the closest clock configuration */ + for (i = 0; i < SPI_CLK_CNT; i++) { + if (speed >= bcm63xx_spi_freq_table[i][0]) { + clk_cfg = bcm63xx_spi_freq_table[i][1]; + break; + } + } + + /* write clock configuration */ + clrsetbits_8(priv->base + regs[SPI_CLK], + SPI_CLK_SSOFF_MASK | SPI_CLK_MASK, + clk_cfg | SPI_CLK_SSOFF_2); + + return 0; +} + +/* + * BCM63xx SPI driver doesn't allow keeping CS active between transfers since + * they are HW controlled. + * However, it provides a mechanism to prepend write transfers prior to read + * transfers (with a maximum prepend of 15 bytes), which is usually enough for + * SPI-connected flashes since reading requires prepending a write transfer of + * 5 bytes. + * + * This implementation takes advantage of the prepend mechanism and combines + * multiple transfers into a single one where possible (single/multiple write + * transfer(s) followed by a final read/write transfer). + * However, it's not possible to buffer reads, which means that read transfers + * should always be done as the final ones. + * On the other hand, take into account that combining write transfers into + * a single one is just buffering and doesn't require prepend mechanism. + */ +static int bcm63xx_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct bcm63xx_spi_priv *priv = dev_get_priv(dev->parent); + const unsigned long *regs = priv->regs; + size_t data_bytes = bitlen / 8; + + if (flags & SPI_XFER_BEGIN) { + /* clear prepends */ + priv->tx_bytes = 0; + + /* initialize hardware */ + writeb_be(0, priv->base + regs[SPI_IR_MASK]); + } + + if (din) { + /* buffering reads not possible since cs is hw controlled */ + if (!(flags & SPI_XFER_END)) { + printf("unable to buffer reads\n"); + return -EINVAL; + } + + /* check rx size */ + if (data_bytes > regs[SPI_RX_SIZE]) { + printf("max rx bytes exceeded\n"); + return -EMSGSIZE; + } + } + + if (dout) { + /* check tx size */ + if (priv->tx_bytes + data_bytes > regs[SPI_TX_SIZE]) { + printf("max tx bytes exceeded\n"); + return -EMSGSIZE; + } + + /* copy tx data */ + memcpy_toio(priv->base + regs[SPI_TX] + priv->tx_bytes, + dout, data_bytes); + priv->tx_bytes += data_bytes; + } + + if (flags & SPI_XFER_END) { + struct dm_spi_slave_platdata *plat = + dev_get_parent_platdata(dev); + uint16_t val, cmd; + int ret; + + /* determine control config */ + if (dout && !din) { + /* buffered write transfers */ + val = priv->tx_bytes; + val |= (SPI_CTL_TYPE_HD_W << regs[SPI_CTL_SHIFT]); + priv->tx_bytes = 0; + } else { + if (dout && din && (flags & SPI_XFER_ONCE)) { + /* full duplex read/write */ + val = data_bytes; + val |= (SPI_CTL_TYPE_FD_RW << + regs[SPI_CTL_SHIFT]); + priv->tx_bytes = 0; + } else { + /* prepended write transfer */ + val = data_bytes; + val |= (SPI_CTL_TYPE_HD_R << + regs[SPI_CTL_SHIFT]); + if (priv->tx_bytes > SPI_CMD_PREPEND_BYTES) { + printf("max prepend bytes exceeded\n"); + return -EMSGSIZE; + } + } + } + + if (regs[SPI_CTL_SHIFT] >= 8) + writew_be(val, priv->base + regs[SPI_CTL]); + else + writeb_be(val, priv->base + regs[SPI_CTL]); + + /* clear interrupts */ + writeb_be(SPI_IR_CLEAR_MASK, priv->base + regs[SPI_IR_STAT]); + + /* issue the transfer */ + cmd = SPI_CMD_OP_START; + cmd |= (plat->cs << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK; + cmd |= (priv->tx_bytes << SPI_CMD_PREPEND_SHIFT); + if (plat->mode & SPI_3WIRE) + cmd |= SPI_CMD_3WIRE_MASK; + writew_be(cmd, priv->base + regs[SPI_CMD]); + + /* enable interrupts */ + writeb_be(SPI_IR_DONE_MASK, priv->base + regs[SPI_IR_MASK]); + + ret = wait_for_bit_8(priv->base + regs[SPI_IR_STAT], + SPI_IR_DONE_MASK, true, 1000, false); + if (ret) { + printf("interrupt timeout\n"); + return ret; + } + + /* copy rx data */ + if (din) + memcpy_fromio(din, priv->base + regs[SPI_RX], + data_bytes); + } + + return 0; +} + +static const struct dm_spi_ops bcm63xx_spi_ops = { + .cs_info = bcm63xx_spi_cs_info, + .set_mode = bcm63xx_spi_set_mode, + .set_speed = bcm63xx_spi_set_speed, + .xfer = bcm63xx_spi_xfer, +}; + +static const unsigned long bcm6348_spi_regs[] = { + [SPI_CLK] = SPI_6348_CLK, + [SPI_CMD] = SPI_6348_CMD, + [SPI_CTL] = SPI_6348_CTL, + [SPI_CTL_SHIFT] = SPI_6348_CTL_SHIFT, + [SPI_FILL] = SPI_6348_FILL, + [SPI_IR_MASK] = SPI_6348_IR_MASK, + [SPI_IR_STAT] = SPI_6348_IR_STAT, + [SPI_RX] = SPI_6348_RX, + [SPI_RX_SIZE] = SPI_6348_RX_SIZE, + [SPI_TX] = SPI_6348_TX, + [SPI_TX_SIZE] = SPI_6348_TX_SIZE, +}; + +static const unsigned long bcm6358_spi_regs[] = { + [SPI_CLK] = SPI_6358_CLK, + [SPI_CMD] = SPI_6358_CMD, + [SPI_CTL] = SPI_6358_CTL, + [SPI_CTL_SHIFT] = SPI_6358_CTL_SHIFT, + [SPI_FILL] = SPI_6358_FILL, + [SPI_IR_MASK] = SPI_6358_IR_MASK, + [SPI_IR_STAT] = SPI_6358_IR_STAT, + [SPI_RX] = SPI_6358_RX, + [SPI_RX_SIZE] = SPI_6358_RX_SIZE, + [SPI_TX] = SPI_6358_TX, + [SPI_TX_SIZE] = SPI_6358_TX_SIZE, +}; + +static const struct udevice_id bcm63xx_spi_ids[] = { + { + .compatible = "brcm,bcm6348-spi", + .data = (ulong)&bcm6348_spi_regs, + }, { + .compatible = "brcm,bcm6358-spi", + .data = (ulong)&bcm6358_spi_regs, + }, { /* sentinel */ } +}; + +static int bcm63xx_spi_child_pre_probe(struct udevice *dev) +{ + struct bcm63xx_spi_priv *priv = dev_get_priv(dev->parent); + const unsigned long *regs = priv->regs; + struct spi_slave *slave = dev_get_parent_priv(dev); + struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); + + /* check cs */ + if (plat->cs >= priv->num_cs) { + printf("no cs %u\n", plat->cs); + return -ENODEV; + } + + /* max read/write sizes */ + slave->max_read_size = regs[SPI_RX_SIZE]; + slave->max_write_size = regs[SPI_TX_SIZE]; + + return 0; +} + +static int bcm63xx_spi_probe(struct udevice *dev) +{ + struct bcm63xx_spi_priv *priv = dev_get_priv(dev); + const unsigned long *regs = + (const unsigned long *)dev_get_driver_data(dev); + struct reset_ctl rst_ctl; + struct clk clk; + fdt_addr_t addr; + fdt_size_t size; + int ret; + + addr = devfdt_get_addr_size_index(dev, 0, &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = regs; + priv->base = ioremap(addr, size); + priv->num_cs = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), + "num-cs", 8); + + /* enable clock */ + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret < 0) + return ret; + + ret = clk_free(&clk); + if (ret < 0) + return ret; + + /* perform reset */ + ret = reset_get_by_index(dev, 0, &rst_ctl); + if (ret < 0) + return ret; + + ret = reset_deassert(&rst_ctl); + if (ret < 0) + return ret; + + ret = reset_free(&rst_ctl); + if (ret < 0) + return ret; + + /* initialize hardware */ + writeb_be(0, priv->base + regs[SPI_IR_MASK]); + + /* set fill register */ + writeb_be(0xff, priv->base + regs[SPI_FILL]); + + return 0; +} + +U_BOOT_DRIVER(bcm63xx_spi) = { + .name = "bcm63xx_spi", + .id = UCLASS_SPI, + .of_match = bcm63xx_spi_ids, + .ops = &bcm63xx_spi_ops, + .priv_auto_alloc_size = sizeof(struct bcm63xx_spi_priv), + .child_pre_probe = bcm63xx_spi_child_pre_probe, + .probe = bcm63xx_spi_probe, +}; From 0adfb199cead1c170a1d4cd4d3b90f4a3cd8ef52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:14:59 +0100 Subject: [PATCH 07/35] mips: bmips: add bcm63xx-spi driver support for BCM6338 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver manages the SPI controller present on this SoC. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki Reviewed-by: Simon Glass --- arch/mips/dts/brcm,bcm6338.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi index eb51a4372b..0cab44cb8d 100644 --- a/arch/mips/dts/brcm,bcm6338.dtsi +++ b/arch/mips/dts/brcm,bcm6338.dtsi @@ -12,6 +12,10 @@ / { compatible = "brcm,bcm6338"; + aliases { + spi0 = &spi; + }; + cpus { reg = <0xfffe0000 0x4>; #address-cells = <1>; @@ -109,6 +113,19 @@ status = "disabled"; }; + spi: spi@fffe0c00 { + compatible = "brcm,bcm6348-spi"; + reg = <0xfffe0c00 0xc0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&periph_clk BCM6338_CLK_SPI>; + resets = <&periph_rst BCM6338_RST_SPI>; + spi-max-frequency = <20000000>; + num-cs = <4>; + + status = "disabled"; + }; + memory-controller@fffe3100 { compatible = "brcm,bcm6338-mc"; reg = <0xfffe3100 0x38>; From ff159286a760b09090e46de04dd0d1ad5f70679a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:15:00 +0100 Subject: [PATCH 08/35] mips: bmips: add bcm63xx-spi driver support for BCM6348 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver manages the SPI controller present on this SoC. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki Reviewed-by: Simon Glass --- arch/mips/dts/brcm,bcm6348.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi index 711b643b5a..540b9fea5b 100644 --- a/arch/mips/dts/brcm,bcm6348.dtsi +++ b/arch/mips/dts/brcm,bcm6348.dtsi @@ -12,6 +12,10 @@ / { compatible = "brcm,bcm6348"; + aliases { + spi0 = &spi; + }; + cpus { reg = <0xfffe0000 0x4>; #address-cells = <1>; @@ -118,6 +122,19 @@ status = "disabled"; }; + spi: spi@fffe0c00 { + compatible = "brcm,bcm6348-spi"; + reg = <0xfffe0c00 0xc0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&periph_clk BCM6348_CLK_SPI>; + resets = <&periph_rst BCM6348_RST_SPI>; + spi-max-frequency = <20000000>; + num-cs = <4>; + + status = "disabled"; + }; + memory-controller@fffe2300 { compatible = "brcm,bcm6338-mc"; reg = <0xfffe2300 0x38>; From 076c1aacbacca87e576191d23eb2b516a7ef4e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:15:01 +0100 Subject: [PATCH 09/35] mips: bmips: add bcm63xx-spi driver support for BCM6358 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver manages the SPI controller present on this SoC. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki Reviewed-by: Simon Glass --- arch/mips/dts/brcm,bcm6358.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi index 4f63cf80e0..1662783279 100644 --- a/arch/mips/dts/brcm,bcm6358.dtsi +++ b/arch/mips/dts/brcm,bcm6358.dtsi @@ -12,6 +12,10 @@ / { compatible = "brcm,bcm6358"; + aliases { + spi0 = &spi; + }; + cpus { reg = <0xfffe0000 0x4>; #address-cells = <1>; @@ -142,6 +146,19 @@ status = "disabled"; }; + spi: spi@fffe0800 { + compatible = "brcm,bcm6358-spi"; + reg = <0xfffe0800 0x70c>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&periph_clk BCM6358_CLK_SPI>; + resets = <&periph_rst BCM6358_RST_SPI>; + spi-max-frequency = <20000000>; + num-cs = <4>; + + status = "disabled"; + }; + memory-controller@fffe1200 { compatible = "brcm,bcm6358-mc"; reg = <0xfffe1200 0x4c>; From 1c2479a5fa17ae68dcf23fffebd4f467629e60c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:15:02 +0100 Subject: [PATCH 10/35] mips: bmips: add bcm63xx-spi driver support for BCM3380 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver manages the SPI controller present on this SoC. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki Reviewed-by: Simon Glass --- arch/mips/dts/brcm,bcm3380.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/mips/dts/brcm,bcm3380.dtsi b/arch/mips/dts/brcm,bcm3380.dtsi index 64245eb048..f83a6ea8df 100644 --- a/arch/mips/dts/brcm,bcm3380.dtsi +++ b/arch/mips/dts/brcm,bcm3380.dtsi @@ -12,6 +12,10 @@ / { compatible = "brcm,bcm3380"; + aliases { + spi0 = &spi; + }; + cpus { reg = <0x14e00000 0x4>; #address-cells = <1>; @@ -142,6 +146,19 @@ status = "disabled"; }; + spi: spi@14e02000 { + compatible = "brcm,bcm6358-spi"; + reg = <0x14e02000 0x70c>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&periph_clk0 BCM3380_CLK0_SPI>; + resets = <&periph_rst0 BCM3380_RST0_SPI>; + spi-max-frequency = <25000000>; + num-cs = <6>; + + status = "disabled"; + }; + leds: led-controller@14e00f00 { compatible = "brcm,bcm6328-leds"; reg = <0x14e00f00 0x1c>; From 26cee0ecc7cff7eec9ce8efce1125d12d60e928b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:15:03 +0100 Subject: [PATCH 11/35] mips: bmips: add bcm63xx-spi driver support for BCM63268 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver manages the low speed SPI controller present on this SoC. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki Reviewed-by: Simon Glass --- arch/mips/dts/brcm,bcm63268.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/mips/dts/brcm,bcm63268.dtsi b/arch/mips/dts/brcm,bcm63268.dtsi index 113a96bef8..6e3d9c3820 100644 --- a/arch/mips/dts/brcm,bcm63268.dtsi +++ b/arch/mips/dts/brcm,bcm63268.dtsi @@ -13,6 +13,10 @@ / { compatible = "brcm,bcm63268"; + aliases { + spi0 = &lsspi; + }; + cpus { reg = <0x10000000 0x4>; #address-cells = <1>; @@ -136,6 +140,19 @@ #power-domain-cells = <1>; }; + lsspi: spi@10000800 { + compatible = "brcm,bcm6358-spi"; + reg = <0x10000800 0x70c>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&periph_clk BCM63268_CLK_SPI>; + resets = <&periph_rst BCM63268_RST_SPI>; + spi-max-frequency = <20000000>; + num-cs = <8>; + + status = "disabled"; + }; + leds: led-controller@10001900 { compatible = "brcm,bcm6328-leds"; reg = <0x10001900 0x24>; From e4a06fa3308926ca6997d49b888baf8cc903e6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:15:04 +0100 Subject: [PATCH 12/35] mips: bmips: enable the SPI flash on the Sagem F@ST1704 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a Winbond (w25x32) 4 MB SPI flash. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki Reviewed-by: Simon Glass --- arch/mips/dts/sagem,f@st1704.dts | 12 ++++++++++++ configs/sagem_f@st1704_ram_defconfig | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/mips/dts/sagem,f@st1704.dts b/arch/mips/dts/sagem,f@st1704.dts index be15fe5551..dd0e5b8b7c 100644 --- a/arch/mips/dts/sagem,f@st1704.dts +++ b/arch/mips/dts/sagem,f@st1704.dts @@ -44,6 +44,18 @@ status = "okay"; }; +&spi { + status = "okay"; + + spi-flash@0 { + compatible = "spi-flash"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <20000000>; + }; +}; + &uart0 { u-boot,dm-pre-reloc; status = "okay"; diff --git a/configs/sagem_f@st1704_ram_defconfig b/configs/sagem_f@st1704_ram_defconfig index cfc56cba37..07a125cec6 100644 --- a/configs/sagem_f@st1704_ram_defconfig +++ b/configs/sagem_f@st1704_ram_defconfig @@ -26,6 +26,8 @@ CONFIG_CMD_MEMINFO=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_FPGA is not set # CONFIG_CMD_LOADS is not set +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y # CONFIG_CMD_NET is not set # CONFIG_CMD_NFS is not set # CONFIG_CMD_MISC is not set @@ -34,8 +36,14 @@ CONFIG_DM_GPIO=y CONFIG_BCM6345_GPIO=y CONFIG_LED=y CONFIG_LED_GPIO=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_MTD=y CONFIG_DM_RESET=y CONFIG_RESET_BCM6345=y # CONFIG_SPL_SERIAL_PRESENT is not set CONFIG_DM_SERIAL=y CONFIG_BCM6345_SERIAL=y +CONFIG_DM_SPI=y +CONFIG_BCM63XX_SPI=y From 46fe9dcfffbcac79b320a18733cdb29b452774d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Tue, 23 Jan 2018 17:15:05 +0100 Subject: [PATCH 13/35] mips: bmips: enable the SPI flash on the Netgear CG3100D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a Spansion (s25fl064a) 8 MB SPI flash. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki Reviewed-by: Simon Glass --- arch/mips/dts/netgear,cg3100d.dts | 12 ++++++++++++ configs/netgear_cg3100d_ram_defconfig | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/mips/dts/netgear,cg3100d.dts b/arch/mips/dts/netgear,cg3100d.dts index db1e2e7616..5f85c7346f 100644 --- a/arch/mips/dts/netgear,cg3100d.dts +++ b/arch/mips/dts/netgear,cg3100d.dts @@ -90,6 +90,18 @@ status = "okay"; }; +&spi { + status = "okay"; + + spi-flash@0 { + compatible = "spi-flash"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <25000000>; + }; +}; + &uart0 { u-boot,dm-pre-reloc; status = "okay"; diff --git a/configs/netgear_cg3100d_ram_defconfig b/configs/netgear_cg3100d_ram_defconfig index 7665c78d3f..fb998f03bf 100644 --- a/configs/netgear_cg3100d_ram_defconfig +++ b/configs/netgear_cg3100d_ram_defconfig @@ -25,6 +25,8 @@ CONFIG_CMD_MEMINFO=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_FPGA is not set # CONFIG_CMD_LOADS is not set +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y # CONFIG_CMD_NET is not set # CONFIG_CMD_NFS is not set # CONFIG_CMD_MISC is not set @@ -35,9 +37,15 @@ CONFIG_LED=y CONFIG_LED_BCM6328=y CONFIG_LED_BLINK=y CONFIG_LED_GPIO=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_MTD=y CONFIG_DM_RESET=y CONFIG_RESET_BCM6345=y # CONFIG_SPL_SERIAL_PRESENT is not set CONFIG_DM_SERIAL=y CONFIG_BCM6345_SERIAL=y +CONFIG_DM_SPI=y +CONFIG_BCM63XX_SPI=y CONFIG_WDT_BCM6345=y From 29cc4368ad4b8d67ae457681e9249e2008d6fee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 20 Jan 2018 02:13:38 +0100 Subject: [PATCH 14/35] dm: spi: add BCM63xx HSSPI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver is a simplified version of linux/drivers/spi/spi-bcm63xx-hsspi.c Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/bcm63xx_hsspi.c | 414 ++++++++++++++++++++++++++++++++++++ 3 files changed, 423 insertions(+) create mode 100644 drivers/spi/bcm63xx_hsspi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ebc71c2e42..28ddcf85a3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -40,6 +40,14 @@ config ATMEL_SPI many AT91 (ARM) chips. This driver can be used to access the SPI Flash, such as AT25DF321. +config BCM63XX_HSSPI + bool "BCM63XX HSSPI driver" + depends on ARCH_BMIPS + help + Enable the BCM6328 HSSPI driver. This driver can be used to + access the SPI NOR flash on platforms embedding this Broadcom + SPI core. + config BCM63XX_SPI bool "BCM6348 SPI driver" depends on ARCH_BMIPS diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 5770b3f7cc..4b6000fd9a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -18,6 +18,7 @@ endif obj-$(CONFIG_ALTERA_SPI) += altera_spi.o obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o +obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o obj-$(CONFIG_CF_SPI) += cf_spi.o diff --git a/drivers/spi/bcm63xx_hsspi.c b/drivers/spi/bcm63xx_hsspi.c new file mode 100644 index 0000000000..3393166a1e --- /dev/null +++ b/drivers/spi/bcm63xx_hsspi.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2017 Álvaro Fernández Rojas + * + * Derived from linux/drivers/spi/spi-bcm63xx-hsspi.c: + * Copyright (C) 2000-2010 Broadcom Corporation + * Copyright (C) 2012-2013 Jonas Gorski + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define HSSPI_PP 0 + +#define SPI_MAX_SYNC_CLOCK 30000000 + +/* SPI Control register */ +#define SPI_CTL_REG 0x000 +#define SPI_CTL_CS_POL_SHIFT 0 +#define SPI_CTL_CS_POL_MASK (0xff << SPI_CTL_CS_POL_SHIFT) +#define SPI_CTL_CLK_GATE_SHIFT 16 +#define SPI_CTL_CLK_GATE_MASK (1 << SPI_CTL_CLK_GATE_SHIFT) +#define SPI_CTL_CLK_POL_SHIFT 17 +#define SPI_CTL_CLK_POL_MASK (1 << SPI_CTL_CLK_POL_SHIFT) + +/* SPI Interrupts registers */ +#define SPI_IR_STAT_REG 0x008 +#define SPI_IR_ST_MASK_REG 0x00c +#define SPI_IR_MASK_REG 0x010 + +#define SPI_IR_CLEAR_ALL 0xff001f1f + +/* SPI Ping-Pong Command registers */ +#define SPI_CMD_REG (0x080 + (0x40 * (HSSPI_PP)) + 0x00) +#define SPI_CMD_OP_SHIFT 0 +#define SPI_CMD_OP_START (0x1 << SPI_CMD_OP_SHIFT) +#define SPI_CMD_PFL_SHIFT 8 +#define SPI_CMD_PFL_MASK (0x7 << SPI_CMD_PFL_SHIFT) +#define SPI_CMD_SLAVE_SHIFT 12 +#define SPI_CMD_SLAVE_MASK (0x7 << SPI_CMD_SLAVE_SHIFT) + +/* SPI Ping-Pong Status registers */ +#define SPI_STAT_REG (0x080 + (0x40 * (HSSPI_PP)) + 0x04) +#define SPI_STAT_SRCBUSY_SHIFT 1 +#define SPI_STAT_SRCBUSY_MASK (1 << SPI_STAT_SRCBUSY_SHIFT) + +/* SPI Profile Clock registers */ +#define SPI_PFL_CLK_REG(x) (0x100 + (0x20 * (x)) + 0x00) +#define SPI_PFL_CLK_FREQ_SHIFT 0 +#define SPI_PFL_CLK_FREQ_MASK (0x3fff << SPI_PFL_CLK_FREQ_SHIFT) +#define SPI_PFL_CLK_RSTLOOP_SHIFT 15 +#define SPI_PFL_CLK_RSTLOOP_MASK (1 << SPI_PFL_CLK_RSTLOOP_SHIFT) + +/* SPI Profile Signal registers */ +#define SPI_PFL_SIG_REG(x) (0x100 + (0x20 * (x)) + 0x04) +#define SPI_PFL_SIG_LATCHRIS_SHIFT 12 +#define SPI_PFL_SIG_LATCHRIS_MASK (1 << SPI_PFL_SIG_LATCHRIS_SHIFT) +#define SPI_PFL_SIG_LAUNCHRIS_SHIFT 13 +#define SPI_PFL_SIG_LAUNCHRIS_MASK (1 << SPI_PFL_SIG_LAUNCHRIS_SHIFT) +#define SPI_PFL_SIG_ASYNCIN_SHIFT 16 +#define SPI_PFL_SIG_ASYNCIN_MASK (1 << SPI_PFL_SIG_ASYNCIN_SHIFT) + +/* SPI Profile Mode registers */ +#define SPI_PFL_MODE_REG(x) (0x100 + (0x20 * (x)) + 0x08) +#define SPI_PFL_MODE_FILL_SHIFT 0 +#define SPI_PFL_MODE_FILL_MASK (0xff << SPI_PFL_MODE_FILL_SHIFT) +#define SPI_PFL_MODE_MDRDSZ_SHIFT 16 +#define SPI_PFL_MODE_MDRDSZ_MASK (1 << SPI_PFL_MODE_MDRDSZ_SHIFT) +#define SPI_PFL_MODE_MDWRSZ_SHIFT 18 +#define SPI_PFL_MODE_MDWRSZ_MASK (1 << SPI_PFL_MODE_MDWRSZ_SHIFT) +#define SPI_PFL_MODE_3WIRE_SHIFT 20 +#define SPI_PFL_MODE_3WIRE_MASK (1 << SPI_PFL_MODE_3WIRE_SHIFT) + +/* SPI Ping-Pong FIFO registers */ +#define HSSPI_FIFO_SIZE 0x200 +#define HSSPI_FIFO_BASE (0x200 + \ + (HSSPI_FIFO_SIZE * HSSPI_PP)) + +/* SPI Ping-Pong FIFO OP register */ +#define HSSPI_FIFO_OP_SIZE 0x2 +#define HSSPI_FIFO_OP_REG (HSSPI_FIFO_BASE + 0x00) +#define HSSPI_FIFO_OP_BYTES_SHIFT 0 +#define HSSPI_FIFO_OP_BYTES_MASK (0x3ff << HSSPI_FIFO_OP_BYTES_SHIFT) +#define HSSPI_FIFO_OP_MBIT_SHIFT 11 +#define HSSPI_FIFO_OP_MBIT_MASK (1 << HSSPI_FIFO_OP_MBIT_SHIFT) +#define HSSPI_FIFO_OP_CODE_SHIFT 13 +#define HSSPI_FIFO_OP_READ_WRITE (1 << HSSPI_FIFO_OP_CODE_SHIFT) +#define HSSPI_FIFO_OP_CODE_W (2 << HSSPI_FIFO_OP_CODE_SHIFT) +#define HSSPI_FIFO_OP_CODE_R (3 << HSSPI_FIFO_OP_CODE_SHIFT) + +struct bcm63xx_hsspi_priv { + void __iomem *regs; + ulong clk_rate; + uint8_t num_cs; + uint8_t cs_pols; + uint speed; +}; + +static int bcm63xx_hsspi_cs_info(struct udevice *bus, uint cs, + struct spi_cs_info *info) +{ + struct bcm63xx_hsspi_priv *priv = dev_get_priv(bus); + + if (cs >= priv->num_cs) { + printf("no cs %u\n", cs); + return -ENODEV; + } + + return 0; +} + +static int bcm63xx_hsspi_set_mode(struct udevice *bus, uint mode) +{ + struct bcm63xx_hsspi_priv *priv = dev_get_priv(bus); + + /* clock polarity */ + if (mode & SPI_CPOL) + setbits_be32(priv->regs + SPI_CTL_REG, SPI_CTL_CLK_POL_MASK); + else + clrbits_be32(priv->regs + SPI_CTL_REG, SPI_CTL_CLK_POL_MASK); + + return 0; +} + +static int bcm63xx_hsspi_set_speed(struct udevice *bus, uint speed) +{ + struct bcm63xx_hsspi_priv *priv = dev_get_priv(bus); + + priv->speed = speed; + + return 0; +} + +static void bcm63xx_hsspi_activate_cs(struct bcm63xx_hsspi_priv *priv, + struct dm_spi_slave_platdata *plat) +{ + uint32_t clr, set; + + /* profile clock */ + set = DIV_ROUND_UP(priv->clk_rate, priv->speed); + set = DIV_ROUND_UP(2048, set); + set &= SPI_PFL_CLK_FREQ_MASK; + set |= SPI_PFL_CLK_RSTLOOP_MASK; + writel_be(set, priv->regs + SPI_PFL_CLK_REG(plat->cs)); + + /* profile signal */ + set = 0; + clr = SPI_PFL_SIG_LAUNCHRIS_MASK | + SPI_PFL_SIG_LATCHRIS_MASK | + SPI_PFL_SIG_ASYNCIN_MASK; + + /* latch/launch config */ + if (plat->mode & SPI_CPHA) + set |= SPI_PFL_SIG_LAUNCHRIS_MASK; + else + set |= SPI_PFL_SIG_LATCHRIS_MASK; + + /* async clk */ + if (priv->speed > SPI_MAX_SYNC_CLOCK) + set |= SPI_PFL_SIG_ASYNCIN_MASK; + + clrsetbits_be32(priv->regs + SPI_PFL_SIG_REG(plat->cs), clr, set); + + /* global control */ + set = 0; + clr = 0; + + /* invert cs polarity */ + if (priv->cs_pols & BIT(plat->cs)) + clr |= BIT(plat->cs); + else + set |= BIT(plat->cs); + + /* invert dummy cs polarity */ + if (priv->cs_pols & BIT(!plat->cs)) + clr |= BIT(!plat->cs); + else + set |= BIT(!plat->cs); + + clrsetbits_be32(priv->regs + SPI_CTL_REG, clr, set); +} + +static void bcm63xx_hsspi_deactivate_cs(struct bcm63xx_hsspi_priv *priv) +{ + /* restore cs polarities */ + clrsetbits_be32(priv->regs + SPI_CTL_REG, SPI_CTL_CS_POL_MASK, + priv->cs_pols); +} + +/* + * BCM63xx HSSPI driver doesn't allow keeping CS active between transfers + * because they are controlled by HW. + * However, it provides a mechanism to prepend write transfers prior to read + * transfers (with a maximum prepend of 15 bytes), which is usually enough for + * SPI-connected flashes since reading requires prepending a write transfer of + * 5 bytes. On the other hand it also provides a way to invert each CS + * polarity, not only between transfers like the older BCM63xx SPI driver, but + * also the rest of the time. + * + * Instead of using the prepend mechanism, this implementation inverts the + * polarity of both the desired CS and another dummy CS when the bus is + * claimed. This way, the dummy CS is restored to its inactive value when + * transfers are issued and the desired CS is preserved in its active value + * all the time. This hack is also used in the upstream linux driver and + * allows keeping CS active between trasnfers even if the HW doesn't give + * this possibility. + */ +static int bcm63xx_hsspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct bcm63xx_hsspi_priv *priv = dev_get_priv(dev->parent); + struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); + size_t data_bytes = bitlen / 8; + size_t step_size = HSSPI_FIFO_SIZE; + uint16_t opcode = 0; + uint32_t val; + const uint8_t *tx = dout; + uint8_t *rx = din; + + if (flags & SPI_XFER_BEGIN) + bcm63xx_hsspi_activate_cs(priv, plat); + + /* fifo operation */ + if (tx && rx) + opcode = HSSPI_FIFO_OP_READ_WRITE; + else if (rx) + opcode = HSSPI_FIFO_OP_CODE_R; + else if (tx) + opcode = HSSPI_FIFO_OP_CODE_W; + + if (opcode != HSSPI_FIFO_OP_CODE_R) + step_size -= HSSPI_FIFO_OP_SIZE; + + /* dual mode */ + if ((opcode == HSSPI_FIFO_OP_CODE_R && plat->mode == SPI_RX_DUAL) || + (opcode == HSSPI_FIFO_OP_CODE_W && plat->mode == SPI_TX_DUAL)) + opcode |= HSSPI_FIFO_OP_MBIT_MASK; + + /* profile mode */ + val = SPI_PFL_MODE_FILL_MASK | + SPI_PFL_MODE_MDRDSZ_MASK | + SPI_PFL_MODE_MDWRSZ_MASK; + if (plat->mode & SPI_3WIRE) + val |= SPI_PFL_MODE_3WIRE_MASK; + writel_be(val, priv->regs + SPI_PFL_MODE_REG(plat->cs)); + + /* transfer loop */ + while (data_bytes > 0) { + size_t curr_step = min(step_size, data_bytes); + int ret; + + /* copy tx data */ + if (tx) { + memcpy_toio(priv->regs + HSSPI_FIFO_BASE + + HSSPI_FIFO_OP_SIZE, tx, curr_step); + tx += curr_step; + } + + /* set fifo operation */ + writew_be(opcode | (curr_step & HSSPI_FIFO_OP_BYTES_MASK), + priv->regs + HSSPI_FIFO_OP_REG); + + /* issue the transfer */ + val = SPI_CMD_OP_START; + val |= (plat->cs << SPI_CMD_PFL_SHIFT) & + SPI_CMD_PFL_MASK; + val |= (!plat->cs << SPI_CMD_SLAVE_SHIFT) & + SPI_CMD_SLAVE_MASK; + writel_be(val, priv->regs + SPI_CMD_REG); + + /* wait for completion */ + ret = wait_for_bit_be32(priv->regs + SPI_STAT_REG, + SPI_STAT_SRCBUSY_MASK, false, + 1000, false); + if (ret) { + printf("interrupt timeout\n"); + return ret; + } + + /* copy rx data */ + if (rx) { + memcpy_fromio(rx, priv->regs + HSSPI_FIFO_BASE, + curr_step); + rx += curr_step; + } + + data_bytes -= curr_step; + } + + if (flags & SPI_XFER_END) + bcm63xx_hsspi_deactivate_cs(priv); + + return 0; +} + +static const struct dm_spi_ops bcm63xx_hsspi_ops = { + .cs_info = bcm63xx_hsspi_cs_info, + .set_mode = bcm63xx_hsspi_set_mode, + .set_speed = bcm63xx_hsspi_set_speed, + .xfer = bcm63xx_hsspi_xfer, +}; + +static const struct udevice_id bcm63xx_hsspi_ids[] = { + { .compatible = "brcm,bcm6328-hsspi", }, + { /* sentinel */ } +}; + +static int bcm63xx_hsspi_child_pre_probe(struct udevice *dev) +{ + struct bcm63xx_hsspi_priv *priv = dev_get_priv(dev->parent); + struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); + + /* check cs */ + if (plat->cs >= priv->num_cs) { + printf("no cs %u\n", plat->cs); + return -ENODEV; + } + + /* cs polarity */ + if (plat->mode & SPI_CS_HIGH) + priv->cs_pols |= BIT(plat->cs); + else + priv->cs_pols &= ~BIT(plat->cs); + + return 0; +} + +static int bcm63xx_hsspi_probe(struct udevice *dev) +{ + struct bcm63xx_hsspi_priv *priv = dev_get_priv(dev); + struct reset_ctl rst_ctl; + struct clk clk; + fdt_addr_t addr; + fdt_size_t size; + int ret; + + addr = devfdt_get_addr_size_index(dev, 0, &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = ioremap(addr, size); + priv->num_cs = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), + "num-cs", 8); + + /* enable clock */ + ret = clk_get_by_name(dev, "hsspi", &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret < 0) + return ret; + + ret = clk_free(&clk); + if (ret < 0) + return ret; + + /* get clock rate */ + ret = clk_get_by_name(dev, "pll", &clk); + if (ret < 0) + return ret; + + priv->clk_rate = clk_get_rate(&clk); + + ret = clk_free(&clk); + if (ret < 0) + return ret; + + /* perform reset */ + ret = reset_get_by_index(dev, 0, &rst_ctl); + if (ret < 0) + return ret; + + ret = reset_deassert(&rst_ctl); + if (ret < 0) + return ret; + + ret = reset_free(&rst_ctl); + if (ret < 0) + return ret; + + /* initialize hardware */ + writel_be(0, priv->regs + SPI_IR_MASK_REG); + + /* clear pending interrupts */ + writel_be(SPI_IR_CLEAR_ALL, priv->regs + SPI_IR_STAT_REG); + + /* enable clk gate */ + setbits_be32(priv->regs + SPI_CTL_REG, SPI_CTL_CLK_GATE_MASK); + + /* read default cs polarities */ + priv->cs_pols = readl_be(priv->regs + SPI_CTL_REG) & + SPI_CTL_CS_POL_MASK; + + return 0; +} + +U_BOOT_DRIVER(bcm63xx_hsspi) = { + .name = "bcm63xx_hsspi", + .id = UCLASS_SPI, + .of_match = bcm63xx_hsspi_ids, + .ops = &bcm63xx_hsspi_ops, + .priv_auto_alloc_size = sizeof(struct bcm63xx_hsspi_priv), + .child_pre_probe = bcm63xx_hsspi_child_pre_probe, + .probe = bcm63xx_hsspi_probe, +}; From 80be057c729b7cfb608a2de5294816f3d1660d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 20 Jan 2018 02:13:39 +0100 Subject: [PATCH 15/35] mips: bmips: add bcm63xx-hsspi driver support for BCM6328 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver manages the SPI controller present on this SoC. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- arch/mips/dts/brcm,bcm6328.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/mips/dts/brcm,bcm6328.dtsi b/arch/mips/dts/brcm,bcm6328.dtsi index a996075743..67d9278be4 100644 --- a/arch/mips/dts/brcm,bcm6328.dtsi +++ b/arch/mips/dts/brcm,bcm6328.dtsi @@ -13,6 +13,10 @@ / { compatible = "brcm,bcm6328"; + aliases { + spi0 = &spi; + }; + cpus { reg = <0x10000000 0x4>; #address-cells = <1>; @@ -40,6 +44,12 @@ #size-cells = <1>; u-boot,dm-pre-reloc; + hsspi_pll: hsspi-pll { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133333333>; + }; + periph_osc: periph-osc { compatible = "fixed-clock"; #clock-cells = <0>; @@ -123,6 +133,20 @@ status = "disabled"; }; + spi: spi@10001000 { + compatible = "brcm,bcm6328-hsspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10001000 0x600>; + clocks = <&periph_clk BCM6328_CLK_HSSPI>, <&hsspi_pll>; + clock-names = "hsspi", "pll"; + resets = <&periph_rst BCM6328_RST_SPI>; + spi-max-frequency = <33333334>; + num-cs = <3>; + + status = "disabled"; + }; + periph_pwr: power-controller@10001848 { compatible = "brcm,bcm6328-power-domain"; reg = <0x10001848 0x4>; From 727839b4913e5cc94142d1dea14829010df59c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 20 Jan 2018 02:13:40 +0100 Subject: [PATCH 16/35] mips: bmips: add bcm63xx-hsspi driver support for BCM63268 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver manages the high speed SPI controller present on this SoC. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- arch/mips/dts/brcm,bcm63268.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/mips/dts/brcm,bcm63268.dtsi b/arch/mips/dts/brcm,bcm63268.dtsi index 6e3d9c3820..4d4e36cccc 100644 --- a/arch/mips/dts/brcm,bcm63268.dtsi +++ b/arch/mips/dts/brcm,bcm63268.dtsi @@ -15,6 +15,7 @@ aliases { spi0 = &lsspi; + spi1 = &hsspi; }; cpus { @@ -44,6 +45,12 @@ #size-cells = <1>; u-boot,dm-pre-reloc; + hsspi_pll: hsspi-pll { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <400000000>; + }; + periph_osc: periph-osc { compatible = "fixed-clock"; #clock-cells = <0>; @@ -153,6 +160,20 @@ status = "disabled"; }; + hsspi: spi@10001000 { + compatible = "brcm,bcm6328-hsspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10001000 0x600>; + clocks = <&periph_clk BCM63268_CLK_HSSPI>, <&hsspi_pll>; + clock-names = "hsspi", "pll"; + resets = <&periph_rst BCM63268_RST_SPI>; + spi-max-frequency = <50000000>; + num-cs = <8>; + + status = "disabled"; + }; + leds: led-controller@10001900 { compatible = "brcm,bcm6328-leds"; reg = <0x10001900 0x24>; From 13129064161c1e90cb6f9e53c9501dc98a1f3c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 20 Jan 2018 02:13:41 +0100 Subject: [PATCH 17/35] mips: bmips: enable the SPI flash on the Comtrend AR-5387un MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a Macronix (mx25l12805d) 16 MB SPI flash. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Simon Glass Reviewed-by: Daniel Schwierzeck Reviewed-by: Jagan Teki --- arch/mips/dts/comtrend,ar-5387un.dts | 12 ++++++++++++ configs/comtrend_ar5387un_ram_defconfig | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/mips/dts/comtrend,ar-5387un.dts b/arch/mips/dts/comtrend,ar-5387un.dts index 73f2b49b76..6067881a78 100644 --- a/arch/mips/dts/comtrend,ar-5387un.dts +++ b/arch/mips/dts/comtrend,ar-5387un.dts @@ -51,6 +51,18 @@ }; }; +&spi { + status = "okay"; + + spi-flash@0 { + compatible = "spi-flash"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <33333334>; + }; +}; + &uart0 { u-boot,dm-pre-reloc; status = "okay"; diff --git a/configs/comtrend_ar5387un_ram_defconfig b/configs/comtrend_ar5387un_ram_defconfig index b64018ae71..352f01d65b 100644 --- a/configs/comtrend_ar5387un_ram_defconfig +++ b/configs/comtrend_ar5387un_ram_defconfig @@ -26,6 +26,8 @@ CONFIG_CMD_MEMINFO=y # CONFIG_CMD_FLASH is not set # CONFIG_CMD_FPGA is not set # CONFIG_CMD_LOADS is not set +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y # CONFIG_CMD_NET is not set # CONFIG_CMD_NFS is not set # CONFIG_CMD_MISC is not set @@ -34,6 +36,10 @@ CONFIG_DM_GPIO=y CONFIG_LED=y CONFIG_LED_BCM6328=y CONFIG_LED_BLINK=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_MTD=y CONFIG_POWER_DOMAIN=y CONFIG_BCM6328_POWER_DOMAIN=y CONFIG_DM_RESET=y @@ -41,3 +47,5 @@ CONFIG_RESET_BCM6345=y # CONFIG_SPL_SERIAL_PRESENT is not set CONFIG_DM_SERIAL=y CONFIG_BCM6345_SERIAL=y +CONFIG_DM_SPI=y +CONFIG_BCM63XX_HSSPI=y From 547bcc3d18ddcc107b8aa7ca393830590c27978f Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:35 +0100 Subject: [PATCH 18/35] spi: Fix style violation and improve code This patch fixes a printf specifier style violation, reduces the scope of a variable, and turns a void pointer that is used with pointer arithmetic into a u8 pointer. Signed-off-by: Mario Six Reviewed-by: Jagan Teki --- drivers/spi/spi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7d81fbd7f8..dea8dcda5b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -12,7 +12,7 @@ int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) { if (wordlen == 0 || wordlen > 32) { - printf("spi: invalid wordlen %d\n", wordlen); + printf("spi: invalid wordlen %u\n", wordlen); return -1; } @@ -24,11 +24,12 @@ int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) void *spi_do_alloc_slave(int offset, int size, unsigned int bus, unsigned int cs) { - struct spi_slave *slave; - void *ptr; + u8 *ptr; ptr = malloc(size); if (ptr) { + struct spi_slave *slave; + memset(ptr, '\0', size); slave = (struct spi_slave *)(ptr + offset); slave->bus = bus; From c5b88f29ba46997e1cae39153980cae475b87b82 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:36 +0100 Subject: [PATCH 19/35] spi: Remove obsolete spi_base_setup_slave_fdt 0efc024 ("spi_flash: Add spi_flash_probe_fdt() to locate SPI by FDT node") added a helper function spi_base_setup_slave_fdt to to set up a SPI slave from a given FDT blob. The only user was the exynos SPI driver. But commit 73186c9 ("dm: exynos: Convert SPI to driver model") removed the use of this function, hence rendering it obsolete. Remove this function, as well as the CONFIG_OF_SPI option, which guarded only this function. Reviewed-by: Simon Glass Reviewed-by: Jagan Teki Signed-off-by: Mario Six --- drivers/spi/spi.c | 20 -------------------- include/spi.h | 14 -------------- scripts/config_whitelist.txt | 1 - 3 files changed, 35 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index dea8dcda5b..45e73d28e4 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -39,23 +39,3 @@ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, return ptr; } - -#ifdef CONFIG_OF_SPI -struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum, - int node) -{ - int cs, max_hz, mode = 0; - - cs = fdtdec_get_int(blob, node, "reg", -1); - max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 100000); - if (fdtdec_get_bool(blob, node, "spi-cpol")) - mode |= SPI_CPOL; - if (fdtdec_get_bool(blob, node, "spi-cpha")) - mode |= SPI_CPHA; - if (fdtdec_get_bool(blob, node, "spi-cs-high")) - mode |= SPI_CS_HIGH; - if (fdtdec_get_bool(blob, node, "spi-half-duplex")) - mode |= SPI_PREAMBLE; - return spi_setup_slave(busnum, cs, max_hz, mode); -} -#endif diff --git a/include/spi.h b/include/spi.h index 5a7df1c706..b2a80a5609 100644 --- a/include/spi.h +++ b/include/spi.h @@ -330,20 +330,6 @@ static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) */ struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node, int spi_node); - -/** - * spi_base_setup_slave_fdt() - helper function to set up a SPI slace - * - * This decodes SPI properties from the slave node to determine the - * chip select and SPI parameters. - * - * @blob: Device tree blob - * @busnum: Bus number to use - * @node: Device tree node for the SPI bus - */ -struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum, - int node); - #ifdef CONFIG_DM_SPI /** diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index a27dc4fc38..6704745305 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1554,7 +1554,6 @@ CONFIG_NUM_PAMU CONFIG_ODROID_REV_AIN CONFIG_OFF_PADCONF CONFIG_OF_ -CONFIG_OF_SPI CONFIG_OF_SPI_FLASH CONFIG_OF_STDOUT_PATH CONFIG_OMAP_EHCI_PHY1_RESET_GPIO From 74ea6e82f8f626c8c3098dea72f008e8ec0357f9 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:37 +0100 Subject: [PATCH 20/35] spi: Remove spi_flash_probe_fdt Commit ba45756 ("dm: x86: spi: Convert ICH SPI driver to driver model") removed the last usage of the spi_flash_probe_fdt function, rendering it obsolete. This patch removes the function. Reviewed-by: Simon Glass Reviewed-by: Jagan Teki Signed-off-by: Mario Six --- drivers/mtd/spi/sf_probe.c | 13 ------------- include/spi_flash.h | 12 ------------ 2 files changed, 25 deletions(-) diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 7b296378d2..e25513b77a 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -87,19 +87,6 @@ struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, return spi_flash_probe_tail(bus); } -#ifdef CONFIG_OF_SPI_FLASH -struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, - int spi_node) -{ - struct spi_slave *bus; - - bus = spi_setup_slave_fdt(blob, slave_node, spi_node); - if (!bus) - return NULL; - return spi_flash_probe_tail(bus); -} -#endif - void spi_flash_free(struct spi_flash *flash) { #ifdef CONFIG_SPI_FLASH_MTD diff --git a/include/spi_flash.h b/include/spi_flash.h index be2fe3f84c..f3c4e83424 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -194,18 +194,6 @@ void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs); struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int spi_mode); -/** - * Set up a new SPI flash from an fdt node - * - * @param blob Device tree blob - * @param slave_node Pointer to this SPI slave node in the device tree - * @param spi_node Cached pointer to the SPI interface this node belongs - * to - * @return 0 if ok, -1 on error - */ -struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, - int spi_node); - void spi_flash_free(struct spi_flash *flash); static inline int spi_flash_read(struct spi_flash *flash, u32 offset, From 184fa1c8da54d3c5305b3e1975e284e01de68bea Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:38 +0100 Subject: [PATCH 21/35] spi: Remove spi_setup_slave_fdt A previous patch removed the spi_flash_probe_fdt function, which contained the last call of the spi_setup_slave_fdt function, which is now equally obsolete. This patch removes the function. Reviewed-by: Simon Glass Reviewed-by: Jagan Teki Signed-off-by: Mario Six --- drivers/spi/spi-uclass.c | 16 ---------------- include/spi.h | 13 ------------- 2 files changed, 29 deletions(-) diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index e06a603ab1..6db0eb02b4 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -347,22 +347,6 @@ err: return ret; } -/* Compatibility function - to be removed */ -struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, - int bus_node) -{ - struct udevice *bus, *dev; - int ret; - - ret = uclass_get_device_by_of_offset(UCLASS_SPI, bus_node, &bus); - if (ret) - return NULL; - ret = device_get_child_by_of_offset(bus, node, &dev); - if (ret) - return NULL; - return dev_get_parent_priv(dev); -} - /* Compatibility function - to be removed */ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, unsigned int speed, unsigned int mode) diff --git a/include/spi.h b/include/spi.h index b2a80a5609..f5bac8d002 100644 --- a/include/spi.h +++ b/include/spi.h @@ -317,19 +317,6 @@ static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) return ret < 0 ? ret : din[1]; } -/** - * Set up a SPI slave for a particular device tree node - * - * This calls spi_setup_slave() with the correct bus number. Call - * spi_free_slave() to free it later. - * - * @param blob: Device tree blob - * @param slave_node: Slave node to use - * @param spi_node: SPI peripheral node to use - * @return pointer to new spi_slave structure - */ -struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node, - int spi_node); #ifdef CONFIG_DM_SPI /** From 8ceb40c752979da7169256b41be424f07b5a3045 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:39 +0100 Subject: [PATCH 22/35] spi: Remove CONFIG_OF_SPI_FLASH Previous patches removed the last usages of this config variable, so that it is now obsolete. This patch removes it from the whitelist. Reviewed-by: Simon Glass Reviewed-by: Jagan Teki Signed-off-by: Mario Six --- scripts/config_whitelist.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 6704745305..b3e0b713ad 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1554,7 +1554,6 @@ CONFIG_NUM_PAMU CONFIG_ODROID_REV_AIN CONFIG_OFF_PADCONF CONFIG_OF_ -CONFIG_OF_SPI_FLASH CONFIG_OF_STDOUT_PATH CONFIG_OMAP_EHCI_PHY1_RESET_GPIO CONFIG_OMAP_EHCI_PHY2_RESET_GPIO From a3e32c5038aa674535ba1e48e994e9368ad47055 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:40 +0100 Subject: [PATCH 23/35] spi: sf_probe: Fix style violations Fix two indention-related style violations. Signed-off-by: Mario Six Reviewed-by: Jagan Teki --- drivers/mtd/spi/sf_probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index e25513b77a..68009a6328 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -77,7 +77,7 @@ static struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) } struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode) + unsigned int max_hz, unsigned int spi_mode) { struct spi_slave *bus; @@ -107,7 +107,7 @@ static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, } static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, - const void *buf) + const void *buf) { struct spi_flash *flash = dev_get_uclass_priv(dev); From 24fc1ec2ee71cd852e556f90bd352cc809ddeef9 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:41 +0100 Subject: [PATCH 24/35] spi: spi-uclass: Fix style violations Remove a superfluous newline, and reduce the scope of a variable. Reviewed-by: Simon Glass Reviewed-by: Jagan Teki Signed-off-by: Mario Six --- drivers/spi/spi-uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 6db0eb02b4..15d90a54a1 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -50,7 +50,6 @@ int dm_spi_claim_bus(struct udevice *dev) struct dm_spi_bus *spi = dev_get_uclass_priv(bus); struct spi_slave *slave = dev_get_parent_priv(dev); int speed; - int ret; speed = slave->max_hz; if (spi->max_hz) { @@ -62,7 +61,8 @@ int dm_spi_claim_bus(struct udevice *dev) if (!speed) speed = 100000; if (speed != slave->speed) { - ret = spi_set_speed_mode(bus, speed, slave->mode); + int ret = spi_set_speed_mode(bus, speed, slave->mode); + if (ret) return ret; slave->speed = speed; @@ -129,7 +129,6 @@ static int spi_post_probe(struct udevice *bus) #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct dm_spi_ops *ops = spi_get_ops(bus); - if (ops->claim_bus) ops->claim_bus += gd->reloc_off; if (ops->release_bus) From 36890ff0d00f6c44631a6453b355f8af1b5ddd53 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Mon, 15 Jan 2018 11:08:42 +0100 Subject: [PATCH 25/35] sf_probe: Merge spi_flash_probe_tail into spi_flash_probe spi_flash_probe_tail is now only called from spi_flash_probe, hence we can merge its body into spi_flash_probe. Reviewed-by: Jagan Teki Reviewed-by: Simon Glass Signed-off-by: Mario Six --- drivers/mtd/spi/sf_probe.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 68009a6328..09143d7868 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -55,10 +55,16 @@ err_read_id: } #ifndef CONFIG_DM_SPI_FLASH -static struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) +struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) { + struct spi_slave *bus; struct spi_flash *flash; + bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); + if (!bus) + return NULL; + /* Allocate space if needed (not used by sf-uclass */ flash = calloc(1, sizeof(*flash)); if (!flash) { @@ -76,17 +82,6 @@ static struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) return flash; } -struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode) -{ - struct spi_slave *bus; - - bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); - if (!bus) - return NULL; - return spi_flash_probe_tail(bus); -} - void spi_flash_free(struct spi_flash *flash) { #ifdef CONFIG_SPI_FLASH_MTD From df16881cea50a787c37591bd2168c8ea656217bd Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Mon, 22 Jan 2018 22:44:20 +1300 Subject: [PATCH 26/35] spi: kirkwood_spi: implement workaround for FE-9144572 Erratum NO. FE-9144572: The device SPI interface supports frequencies of up to 50 MHz. However, due to this erratum, when the device core clock is 250 MHz and the SPI interfaces is configured for 50MHz SPI clock and CPOL=CPHA=1 there might occur data corruption on reads from the SPI device. Implement the workaround by setting the TMISO_SAMPLE value to 0x2 in the timing1 register. Signed-off-by: Chris Packham Reviewed-by: Stefan Roese Reviewed-by: Jagan Teki --- arch/arm/include/asm/arch-mvebu/spi.h | 6 +++ drivers/spi/kirkwood_spi.c | 69 +++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/arch/arm/include/asm/arch-mvebu/spi.h b/arch/arm/include/asm/arch-mvebu/spi.h index 3545aed173..1de510ea6d 100644 --- a/arch/arm/include/asm/arch-mvebu/spi.h +++ b/arch/arm/include/asm/arch-mvebu/spi.h @@ -57,6 +57,12 @@ struct kwspi_registers { #define KWSPI_TXLSBF (1 << 13) #define KWSPI_RXLSBF (1 << 14) +/* Timing Parameters 1 Register */ +#define KW_SPI_TMISO_SAMPLE_OFFSET 6 +#define KW_SPI_TMISO_SAMPLE_MASK (0x3 << KW_SPI_TMISO_SAMPLE_OFFSET) +#define KW_SPI_TMISO_SAMPLE_1 (1 << KW_SPI_TMISO_SAMPLE_OFFSET) +#define KW_SPI_TMISO_SAMPLE_2 (2 << KW_SPI_TMISO_SAMPLE_OFFSET) + #define KWSPI_IRQUNMASK 1 /* unmask SPI interrupt */ #define KWSPI_IRQMASK 0 /* mask SPI interrupt */ #define KWSPI_SMEMRDIRQ 1 /* SerMem data xfer ready irq */ diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c index 0c6bd295cd..1ad8cdee64 100644 --- a/drivers/spi/kirkwood_spi.c +++ b/drivers/spi/kirkwood_spi.c @@ -243,6 +243,10 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, /* Here now the DM part */ +struct mvebu_spi_dev { + bool is_errata_50mhz_ac; +}; + struct mvebu_spi_platdata { struct kwspi_registers *spireg; }; @@ -269,10 +273,44 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz) return 0; } +static void mvebu_spi_50mhz_ac_timing_erratum(struct udevice *bus, uint mode) +{ + struct mvebu_spi_platdata *plat = dev_get_platdata(bus); + struct kwspi_registers *reg = plat->spireg; + u32 data; + + /* + * Erratum description: (Erratum NO. FE-9144572) The device + * SPI interface supports frequencies of up to 50 MHz. + * However, due to this erratum, when the device core clock is + * 250 MHz and the SPI interfaces is configured for 50MHz SPI + * clock and CPOL=CPHA=1 there might occur data corruption on + * reads from the SPI device. + * Erratum Workaround: + * Work in one of the following configurations: + * 1. Set CPOL=CPHA=0 in "SPI Interface Configuration + * Register". + * 2. Set TMISO_SAMPLE value to 0x2 in "SPI Timing Parameters 1 + * Register" before setting the interface. + */ + data = readl(®->timing1); + data &= ~KW_SPI_TMISO_SAMPLE_MASK; + + if (CONFIG_SYS_TCLK == 250000000 && + mode & SPI_CPOL && + mode & SPI_CPHA) + data |= KW_SPI_TMISO_SAMPLE_2; + else + data |= KW_SPI_TMISO_SAMPLE_1; + + writel(data, ®->timing1); +} + static int mvebu_spi_set_mode(struct udevice *bus, uint mode) { struct mvebu_spi_platdata *plat = dev_get_platdata(bus); struct kwspi_registers *reg = plat->spireg; + const struct mvebu_spi_dev *drvdata; u32 data = readl(®->cfg); data &= ~(KWSPI_CPHA | KWSPI_CPOL | KWSPI_RXLSBF | KWSPI_TXLSBF); @@ -286,6 +324,10 @@ static int mvebu_spi_set_mode(struct udevice *bus, uint mode) writel(data, ®->cfg); + drvdata = (struct mvebu_spi_dev *)dev_get_driver_data(bus); + if (drvdata->is_errata_50mhz_ac) + mvebu_spi_50mhz_ac_timing_erratum(bus, mode); + return 0; } @@ -343,10 +385,31 @@ static const struct dm_spi_ops mvebu_spi_ops = { */ }; +static const struct mvebu_spi_dev armada_xp_spi_dev_data = { + .is_errata_50mhz_ac = false, +}; + +static const struct mvebu_spi_dev armada_375_spi_dev_data = { + .is_errata_50mhz_ac = false, +}; + +static const struct mvebu_spi_dev armada_380_spi_dev_data = { + .is_errata_50mhz_ac = true, +}; + static const struct udevice_id mvebu_spi_ids[] = { - { .compatible = "marvell,armada-375-spi" }, - { .compatible = "marvell,armada-380-spi" }, - { .compatible = "marvell,armada-xp-spi" }, + { + .compatible = "marvell,armada-375-spi", + .data = (ulong)&armada_375_spi_dev_data + }, + { + .compatible = "marvell,armada-380-spi", + .data = (ulong)&armada_380_spi_dev_data + }, + { + .compatible = "marvell,armada-xp-spi", + .data = (ulong)&armada_xp_spi_dev_data + }, { } }; From 15a70a5da33229de884f60684a562ea60fe505b2 Mon Sep 17 00:00:00 2001 From: Jason Rush Date: Tue, 23 Jan 2018 17:13:09 -0600 Subject: [PATCH 27/35] spi: cadence_spi: Sync DT bindings with Linux Adopt the Linux DT bindings. This also fixes an issue with the indaddrtrig register on the Cadence QSPI device being programmed with the wrong value for the socfpga arch. Tested on TI K2G platform: Tested-by: Vignesh R Tested on a socfpga-cyclonev board: Tested-by: Simon Goldschmidt Signed-off-by: Jason Rush Reviewed-by: Jagan Teki Acked-by: Simon Goldschmidt Acked-by: Marek Vasut --- drivers/spi/cadence_qspi.c | 20 ++++++++++++-------- drivers/spi/cadence_qspi.h | 6 +++++- drivers/spi/cadence_qspi_apb.c | 15 ++++----------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 9a6e41f330..7b312f8e3e 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -212,7 +212,7 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Set Chip select */ cadence_qspi_apb_chipselect(base, spi_chip_select(dev), - CONFIG_CQSPI_DECODER); + plat->is_decoded_cs); if ((flags & SPI_XFER_END) || (flags == 0)) { if (priv->cmd_len == 0) { @@ -296,7 +296,11 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus) plat->regbase = (void *)data[0]; plat->ahbbase = (void *)data[2]; - plat->sram_size = fdtdec_get_int(blob, node, "sram-size", 128); + plat->is_decoded_cs = fdtdec_get_bool(blob, node, "cdns,is-decoded-cs"); + plat->fifo_depth = fdtdec_get_uint(blob, node, "cdns,fifo-depth", 128); + plat->fifo_width = fdtdec_get_uint(blob, node, "cdns,fifo-width", 4); + plat->trigger_address = fdtdec_get_uint(blob, node, + "cdns,trigger-address", 0); /* All other paramters are embedded in the child node */ subnode = fdt_first_subnode(blob, node); @@ -310,12 +314,12 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus) 500000); /* Read other parameters from DT */ - plat->page_size = fdtdec_get_int(blob, subnode, "page-size", 256); - plat->block_size = fdtdec_get_int(blob, subnode, "block-size", 16); - plat->tshsl_ns = fdtdec_get_int(blob, subnode, "tshsl-ns", 200); - plat->tsd2d_ns = fdtdec_get_int(blob, subnode, "tsd2d-ns", 255); - plat->tchsh_ns = fdtdec_get_int(blob, subnode, "tchsh-ns", 20); - plat->tslch_ns = fdtdec_get_int(blob, subnode, "tslch-ns", 20); + plat->page_size = fdtdec_get_uint(blob, subnode, "page-size", 256); + plat->block_size = fdtdec_get_uint(blob, subnode, "block-size", 16); + plat->tshsl_ns = fdtdec_get_uint(blob, subnode, "cdns,tshsl-ns", 200); + plat->tsd2d_ns = fdtdec_get_uint(blob, subnode, "cdns,tsd2d-ns", 255); + plat->tchsh_ns = fdtdec_get_uint(blob, subnode, "cdns,tchsh-ns", 20); + plat->tslch_ns = fdtdec_get_uint(blob, subnode, "cdns,tslch-ns", 20); debug("%s: regbase=%p ahbbase=%p max-frequency=%d page-size=%d\n", __func__, plat->regbase, plat->ahbbase, plat->max_hz, diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index d1927a4003..9106b09d29 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -18,14 +18,18 @@ struct cadence_spi_platdata { unsigned int max_hz; void *regbase; void *ahbbase; + bool is_decoded_cs; + u32 fifo_depth; + u32 fifo_width; + u32 trigger_address; + /* Flash parameters */ u32 page_size; u32 block_size; u32 tshsl_ns; u32 tsd2d_ns; u32 tchsh_ns; u32 tslch_ns; - u32 sram_size; }; struct cadence_spi_priv { diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index dca3fdfdea..c3dd32912e 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -37,10 +37,6 @@ #define CQSPI_REG_RETRY 10000 #define CQSPI_POLL_IDLE_RETRY 3 -#define CQSPI_FIFO_WIDTH 4 - -#define CQSPI_REG_SRAM_THRESHOLD_WORDS 50 - /* Transfer mode */ #define CQSPI_INST_TYPE_SINGLE 0 #define CQSPI_INST_TYPE_DUAL 1 @@ -51,9 +47,6 @@ #define CQSPI_DUMMY_CLKS_PER_BYTE 8 #define CQSPI_DUMMY_BYTES_MAX 4 -#define CQSPI_REG_SRAM_FILL_THRESHOLD \ - ((CQSPI_REG_SRAM_SIZE_WORD / 2) * CQSPI_FIFO_WIDTH) - /**************************************************************************** * Controller's configuration and status register (offset from QSPI_BASE) ****************************************************************************/ @@ -400,7 +393,7 @@ void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat) writel(0, plat->regbase + CQSPI_REG_REMAP); /* Indirect mode configurations */ - writel((plat->sram_size/2), plat->regbase + CQSPI_REG_SRAMPARTITION); + writel(plat->fifo_depth / 2, plat->regbase + CQSPI_REG_SRAMPARTITION); /* Disable all interrupts */ writel(0, plat->regbase + CQSPI_REG_IRQMASK); @@ -560,7 +553,7 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, addr_bytes = cmdlen - 1; /* Setup the indirect trigger address */ - writel((u32)plat->ahbbase, + writel(plat->trigger_address, plat->regbase + CQSPI_REG_INDIRECTTRIGGER); /* Configure the opcode */ @@ -659,7 +652,7 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, bytes_to_read = ret; while (bytes_to_read != 0) { - bytes_to_read *= CQSPI_FIFO_WIDTH; + bytes_to_read *= plat->fifo_width; bytes_to_read = bytes_to_read > remaining ? remaining : bytes_to_read; readsl(plat->ahbbase, bb_rxbuf, bytes_to_read >> 2); @@ -710,7 +703,7 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, return -EINVAL; } /* Setup the indirect trigger address */ - writel((u32)plat->ahbbase, + writel(plat->trigger_address, plat->regbase + CQSPI_REG_INDIRECTTRIGGER); /* Configure the opcode */ From 6e62b178e18dfbe78a973b80e4e6f1f498bbdbc5 Mon Sep 17 00:00:00 2001 From: Jason Rush Date: Tue, 23 Jan 2018 17:13:10 -0600 Subject: [PATCH 28/35] dts: cadence_spi: Sync DT bindings with Linux Adopt the Linux DT bindings and clean-up duplicate and unused values. Fix indentation of the QSPI node in the keystone k2g device tree. Tested on TI K2G platform: Tested-by: Vignesh R Tested on a socfpga-cyclonev board: Tested-by: Simon Goldschmidt Signed-off-by: Jason Rush Reviewed-by: Jagan Teki Acked-by: Simon Goldschmidt Acked-by: Marek Vasut --- arch/arm/dts/keystone-k2g-evm.dts | 75 +++++++++---------- arch/arm/dts/keystone-k2g.dtsi | 5 +- arch/arm/dts/socfpga.dtsi | 5 +- arch/arm/dts/socfpga_arria10.dtsi | 4 +- arch/arm/dts/socfpga_arria5_socdk.dts | 9 +-- arch/arm/dts/socfpga_cyclone5_is1.dts | 9 +-- arch/arm/dts/socfpga_cyclone5_socdk.dts | 9 +-- arch/arm/dts/socfpga_cyclone5_sockit.dts | 9 +-- arch/arm/dts/socfpga_cyclone5_socrates.dts | 9 +-- arch/arm/dts/socfpga_cyclone5_sr1500.dts | 9 +-- arch/arm/dts/socfpga_cyclone5_vining_fpga.dts | 18 ++--- arch/arm/dts/stv0991.dts | 12 +-- 12 files changed, 84 insertions(+), 89 deletions(-) diff --git a/arch/arm/dts/keystone-k2g-evm.dts b/arch/arm/dts/keystone-k2g-evm.dts index de208b3613..ad746c7311 100644 --- a/arch/arm/dts/keystone-k2g-evm.dts +++ b/arch/arm/dts/keystone-k2g-evm.dts @@ -68,46 +68,45 @@ &qspi { status = "okay"; - flash0: m25p80@0 { - compatible = "s25fl512s","spi-flash"; - reg = <0>; - spi-tx-bus-width = <1>; - spi-rx-bus-width = <4>; - spi-max-frequency = <96000000>; - #address-cells = <1>; - #size-cells = <1>; - tshsl-ns = <392>; - tsd2d-ns = <392>; - tchsh-ns = <100>; - tslch-ns = <100>; + flash0: m25p80@0 { + compatible = "s25fl512s","spi-flash"; + reg = <0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <96000000>; + #address-cells = <1>; + #size-cells = <1>; + cdns,tshsl-ns = <392>; + cdns,tsd2d-ns = <392>; + cdns,tchsh-ns = <100>; + cdns,tslch-ns = <100>; block-size = <18>; - - partition@0 { - label = "QSPI.u-boot-spl-os"; - reg = <0x00000000 0x00100000>; - }; - partition@1 { - label = "QSPI.u-boot-env"; - reg = <0x00100000 0x00040000>; - }; - partition@2 { - label = "QSPI.skern"; - reg = <0x00140000 0x0040000>; - }; - partition@3 { - label = "QSPI.pmmc-firmware"; - reg = <0x00180000 0x0040000>; - }; - partition@4 { - label = "QSPI.kernel"; - reg = <0x001C0000 0x0800000>; - }; - partition@5 { - label = "QSPI.file-system"; - reg = <0x009C0000 0x3640000>; - }; - }; + partition@0 { + label = "QSPI.u-boot-spl-os"; + reg = <0x00000000 0x00100000>; + }; + partition@1 { + label = "QSPI.u-boot-env"; + reg = <0x00100000 0x00040000>; + }; + partition@2 { + label = "QSPI.skern"; + reg = <0x00140000 0x0040000>; + }; + partition@3 { + label = "QSPI.pmmc-firmware"; + reg = <0x00180000 0x0040000>; + }; + partition@4 { + label = "QSPI.kernel"; + reg = <0x001C0000 0x0800000>; + }; + partition@5 { + label = "QSPI.file-system"; + reg = <0x009C0000 0x3640000>; + }; + }; }; &mmc0 { diff --git a/arch/arm/dts/keystone-k2g.dtsi b/arch/arm/dts/keystone-k2g.dtsi index 7b2fae6860..9bcfea6d86 100644 --- a/arch/arm/dts/keystone-k2g.dtsi +++ b/arch/arm/dts/keystone-k2g.dtsi @@ -92,8 +92,9 @@ <0x24000000 0x4000000>; interrupts = ; num-cs = <4>; - fifo-depth = <256>; - sram-size = <256>; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x24000000>; status = "disabled"; }; diff --git a/arch/arm/dts/socfpga.dtsi b/arch/arm/dts/socfpga.dtsi index 8588221e57..7557aa01e5 100644 --- a/arch/arm/dts/socfpga.dtsi +++ b/arch/arm/dts/socfpga.dtsi @@ -644,8 +644,9 @@ clocks = <&qspi_clk>; ext-decoder = <0>; /* external decoder */ num-cs = <4>; - fifo-depth = <128>; - sram-size = <128>; + cdns,fifo-depth = <128>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x00000000>; bus-num = <2>; status = "disabled"; }; diff --git a/arch/arm/dts/socfpga_arria10.dtsi b/arch/arm/dts/socfpga_arria10.dtsi index 377700df11..abfd0bc4f8 100644 --- a/arch/arm/dts/socfpga_arria10.dtsi +++ b/arch/arm/dts/socfpga_arria10.dtsi @@ -734,8 +734,8 @@ clocks = <&l4_main_clk>; ext-decoder = <0>; /* external decoder */ num-chipselect = <4>; - fifo-depth = <128>; - sram-size = <512>; + cdns,fifo-depth = <128>; + cdns,fifo-width = <4>; bus-num = <2>; status = "disabled"; }; diff --git a/arch/arm/dts/socfpga_arria5_socdk.dts b/arch/arm/dts/socfpga_arria5_socdk.dts index 726505821f..1e91a65af6 100644 --- a/arch/arm/dts/socfpga_arria5_socdk.dts +++ b/arch/arm/dts/socfpga_arria5_socdk.dts @@ -94,10 +94,9 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; diff --git a/arch/arm/dts/socfpga_cyclone5_is1.dts b/arch/arm/dts/socfpga_cyclone5_is1.dts index 16a3283710..2e2b71fefb 100644 --- a/arch/arm/dts/socfpga_cyclone5_is1.dts +++ b/arch/arm/dts/socfpga_cyclone5_is1.dts @@ -93,11 +93,10 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; diff --git a/arch/arm/dts/socfpga_cyclone5_socdk.dts b/arch/arm/dts/socfpga_cyclone5_socdk.dts index f175ef2ead..95a8e653d7 100644 --- a/arch/arm/dts/socfpga_cyclone5_socdk.dts +++ b/arch/arm/dts/socfpga_cyclone5_socdk.dts @@ -104,11 +104,10 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; diff --git a/arch/arm/dts/socfpga_cyclone5_sockit.dts b/arch/arm/dts/socfpga_cyclone5_sockit.dts index e45c2abbc2..6f42b88130 100644 --- a/arch/arm/dts/socfpga_cyclone5_sockit.dts +++ b/arch/arm/dts/socfpga_cyclone5_sockit.dts @@ -84,11 +84,10 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; diff --git a/arch/arm/dts/socfpga_cyclone5_socrates.dts b/arch/arm/dts/socfpga_cyclone5_socrates.dts index bdd93248fb..e3ae8a8207 100644 --- a/arch/arm/dts/socfpga_cyclone5_socrates.dts +++ b/arch/arm/dts/socfpga_cyclone5_socrates.dts @@ -74,11 +74,10 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; diff --git a/arch/arm/dts/socfpga_cyclone5_sr1500.dts b/arch/arm/dts/socfpga_cyclone5_sr1500.dts index 739bbb7f3d..e24830af57 100644 --- a/arch/arm/dts/socfpga_cyclone5_sr1500.dts +++ b/arch/arm/dts/socfpga_cyclone5_sr1500.dts @@ -92,10 +92,9 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; diff --git a/arch/arm/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/dts/socfpga_cyclone5_vining_fpga.dts index f168e4ff99..a0febe91b0 100644 --- a/arch/arm/dts/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/dts/socfpga_cyclone5_vining_fpga.dts @@ -79,11 +79,10 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; flash1: n25q00@1 { @@ -96,11 +95,10 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; diff --git a/arch/arm/dts/stv0991.dts b/arch/arm/dts/stv0991.dts index fa3fd641b2..bceac09154 100644 --- a/arch/arm/dts/stv0991.dts +++ b/arch/arm/dts/stv0991.dts @@ -32,7 +32,9 @@ reg = <0x80203000 0x100>, <0x40000000 0x1000000>; clocks = <3750000>; - sram-size = <256>; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x40000000>; status = "okay"; flash0: n25q32@0 { @@ -44,10 +46,10 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - tshsl-ns = <50>; - tsd2d-ns = <50>; - tchsh-ns = <4>; - tslch-ns = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; }; }; }; From 5a15ec19c84ebcca0a45870d28c3a3f7f5c085f5 Mon Sep 17 00:00:00 2001 From: Jason Rush Date: Tue, 23 Jan 2018 17:13:11 -0600 Subject: [PATCH 29/35] config: cadence_spi: Remove defines read from DT Cleanup unused #define values that are read from the DT. Tested on TI K2G platform: Tested-by: Vignesh R Tested on a socfpga-cyclonev board: Tested-by: Simon Goldschmidt Signed-off-by: Jason Rush Reviewed-by: Jagan Teki Acked-by: Simon Goldschmidt Acked-by: Marek Vasut --- include/configs/k2g_evm.h | 1 - include/configs/socfpga_common.h | 1 - include/configs/stv0991.h | 1 - 3 files changed, 3 deletions(-) diff --git a/include/configs/k2g_evm.h b/include/configs/k2g_evm.h index df81c09d86..535e7124fc 100644 --- a/include/configs/k2g_evm.h +++ b/include/configs/k2g_evm.h @@ -93,7 +93,6 @@ #ifndef CONFIG_SPL_BUILD #define CONFIG_CADENCE_QSPI #define CONFIG_CQSPI_REF_CLK 384000000 -#define CONFIG_CQSPI_DECODER 0x0 #define CONFIG_BOUNCE_BUFFER #endif diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h index 66e7c4fc8b..ec8bb50050 100644 --- a/include/configs/socfpga_common.h +++ b/include/configs/socfpga_common.h @@ -184,7 +184,6 @@ unsigned int cm_get_l4_sp_clk_hz(void); unsigned int cm_get_qspi_controller_clk_hz(void); #define CONFIG_CQSPI_REF_CLK cm_get_qspi_controller_clk_hz() #endif -#define CONFIG_CQSPI_DECODER 0 #define CONFIG_BOUNCE_BUFFER /* diff --git a/include/configs/stv0991.h b/include/configs/stv0991.h index c99fb676cb..fd96979bf8 100644 --- a/include/configs/stv0991.h +++ b/include/configs/stv0991.h @@ -63,7 +63,6 @@ + * QSPI support + */ #ifdef CONFIG_OF_CONTROL /* QSPI is controlled via DT */ -#define CONFIG_CQSPI_DECODER 0 #define CONFIG_CQSPI_REF_CLK ((30/4)/2)*1000*1000 #define CONFIG_BOUNCE_BUFFER From c58f300628b9037b9f3f82910a5c6b9590882c11 Mon Sep 17 00:00:00 2001 From: Jason Rush Date: Tue, 23 Jan 2018 17:13:12 -0600 Subject: [PATCH 30/35] dts: cadence_spi: Update documentation for DT bindings Update documentation to reflect adopting the Linux DT bindings. Tested on TI K2G platform: Tested-by: Vignesh R Tested on a socfpga-cyclonev board: Tested-by: Simon Goldschmidt Signed-off-by: Jason Rush Reviewed-by: Jagan Teki Acked-by: Simon Goldschmidt Acked-by: Marek Vasut --- doc/device-tree-bindings/spi/spi-cadence.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/device-tree-bindings/spi/spi-cadence.txt b/doc/device-tree-bindings/spi/spi-cadence.txt index c1e2233d7c..74c82080fc 100644 --- a/doc/device-tree-bindings/spi/spi-cadence.txt +++ b/doc/device-tree-bindings/spi/spi-cadence.txt @@ -6,7 +6,10 @@ Required properties: - reg : 1.Physical base address and size of SPI registers map. 2. Physical base address & size of NOR Flash. - clocks : Clock phandles (see clock bindings for details). -- sram-size : spi controller sram size. +- cdns,fifo-depth : Size of the data FIFO in words. +- cdns,fifo-width : Bus width of the data FIFO in bytes. +- cdns,trigger-address : 32-bit indirect AHB trigger address. +- cdns,is-decoded-cs : Flag to indicate whether decoder is used or not. - status : enable in requried dts. connected flash properties @@ -15,14 +18,14 @@ connected flash properties - spi-max-frequency : Max supported spi frequency. - page-size : Flash page size. - block-size : Flash memory block size. -- tshsl-ns : Added delay in master reference clocks (ref_clk) for +- cdns,tshsl-ns : Added delay in master reference clocks (ref_clk) for the length that the master mode chip select outputs are de-asserted between transactions. -- tsd2d-ns : Delay in master reference clocks (ref_clk) between one +- cdns,tsd2d-ns : Delay in master reference clocks (ref_clk) between one chip select being de-activated and the activation of another. -- tchsh-ns : Delay in master reference clocks between last bit of +- cdns,tchsh-ns : Delay in master reference clocks between last bit of current transaction and de-asserting the device chip select (n_ss_out). -- tslch-ns : Delay in master reference clocks between setting +- cdns,tslch-ns : Delay in master reference clocks between setting n_ss_out low and first bit transfer From 948ad4f07598a729a0de523ed3d779115b2fa2f2 Mon Sep 17 00:00:00 2001 From: Goldschmidt Simon Date: Wed, 24 Jan 2018 10:44:05 +0530 Subject: [PATCH 31/35] Revert "spi: cadence_qspi_apb: Use 32 bit indirect read transaction when possible" This reverts commit b63b46313ed29e9b0c36b3d6b9407f6eade40c8f. This commit changed cadence_qspi_apb to use bouncebuf.c, which invalidates the data cache after reading. This is meant for dma transfers only and breaks the cadence_qspi driver which copies via cpu only: data that is copied by the cpu is in cache only and the cache invalidation at the end throws away this data. Signed-off-by: Simon Goldschmidt Signed-off-by: Vignesh R Acked-by: Marek Vasut Reviewed-by: Jason Rush Acked-by: Jason Rush Reviewed-by: Jagan Teki --- drivers/spi/cadence_qspi_apb.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index c3dd32912e..128c41d715 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -627,8 +627,6 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, { unsigned int remaining = n_rx; unsigned int bytes_to_read = 0; - struct bounce_buffer bb; - u8 *bb_rxbuf; int ret; writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); @@ -637,11 +635,6 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, writel(CQSPI_REG_INDIRECTRD_START, plat->regbase + CQSPI_REG_INDIRECTRD); - ret = bounce_buffer_start(&bb, (void *)rxbuf, n_rx, GEN_BB_WRITE); - if (ret) - return ret; - bb_rxbuf = bb.bounce_buffer; - while (remaining > 0) { ret = cadence_qspi_wait_for_data(plat); if (ret < 0) { @@ -655,13 +648,16 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, bytes_to_read *= plat->fifo_width; bytes_to_read = bytes_to_read > remaining ? remaining : bytes_to_read; - readsl(plat->ahbbase, bb_rxbuf, bytes_to_read >> 2); - if (bytes_to_read % 4) - readsb(plat->ahbbase, - bb_rxbuf + rounddown(bytes_to_read, 4), - bytes_to_read % 4); - - bb_rxbuf += bytes_to_read; + /* + * Handle non-4-byte aligned access to avoid + * data abort. + */ + if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4)) + readsb(plat->ahbbase, rxbuf, bytes_to_read); + else + readsl(plat->ahbbase, rxbuf, + bytes_to_read >> 2); + rxbuf += bytes_to_read; remaining -= bytes_to_read; bytes_to_read = cadence_qspi_get_rd_sram_level(plat); } @@ -678,7 +674,6 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, /* Clear indirect completion status */ writel(CQSPI_REG_INDIRECTRD_DONE, plat->regbase + CQSPI_REG_INDIRECTRD); - bounce_buffer_stop(&bb); return 0; @@ -686,7 +681,6 @@ failrd: /* Cancel the indirect read */ writel(CQSPI_REG_INDIRECTRD_CANCEL, plat->regbase + CQSPI_REG_INDIRECTRD); - bounce_buffer_stop(&bb); return ret; } From a743e2ba3837db5e8499b03f0f57c3610d03a570 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Wed, 24 Jan 2018 10:44:06 +0530 Subject: [PATCH 32/35] Revert "spi: cadence_qspi_apb: Use 32 bit indirect write transaction when possible" This reverts commit 57897c13de03ac0136d64641a3eab526c6810387. Using bounce_buf.c to handle non-DMA alignment problems is bad as bounce_buf.c does cache manipulations which is not required. Therefore revert this patch in favour of local bounce buffer solution in the next patch. Signed-off-by: Vignesh R Acked-by: Marek Vasut Acked-by: Simon Goldschmidt Reviewed-by: Jason Rush Acked-by: Jason Rush Reviewed-by: Jagan Teki --- drivers/spi/cadence_qspi_apb.c | 26 ++++++-------------------- include/configs/k2g_evm.h | 1 - include/configs/socfpga_common.h | 1 - include/configs/stv0991.h | 1 - 4 files changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 128c41d715..70d0f431ad 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "cadence_qspi.h" #define CQSPI_REG_POLL_US 1 /* 1us */ @@ -722,17 +721,6 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, unsigned int remaining = n_tx; unsigned int write_bytes; int ret; - struct bounce_buffer bb; - u8 *bb_txbuf; - - /* - * Handle non-4-byte aligned accesses via bounce buffer to - * avoid data abort. - */ - ret = bounce_buffer_start(&bb, (void *)txbuf, n_tx, GEN_BB_READ); - if (ret) - return ret; - bb_txbuf = bb.bounce_buffer; /* Configure the indirect read transfer bytes */ writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES); @@ -743,11 +731,11 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, while (remaining > 0) { write_bytes = remaining > page_size ? page_size : remaining; - writesl(plat->ahbbase, bb_txbuf, write_bytes >> 2); - if (write_bytes % 4) - writesb(plat->ahbbase, - bb_txbuf + rounddown(write_bytes, 4), - write_bytes % 4); + /* Handle non-4-byte aligned access to avoid data abort. */ + if (((uintptr_t)txbuf % 4) || (write_bytes % 4)) + writesb(plat->ahbbase, txbuf, write_bytes); + else + writesl(plat->ahbbase, txbuf, write_bytes >> 2); ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_SDRAMLEVEL, CQSPI_REG_SDRAMLEVEL_WR_MASK << @@ -757,7 +745,7 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, goto failwr; } - bb_txbuf += write_bytes; + txbuf += write_bytes; remaining -= write_bytes; } @@ -768,7 +756,6 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, printf("Indirect write completion error (%i)\n", ret); goto failwr; } - bounce_buffer_stop(&bb); /* Clear indirect completion status */ writel(CQSPI_REG_INDIRECTWR_DONE, @@ -779,7 +766,6 @@ failwr: /* Cancel the indirect write */ writel(CQSPI_REG_INDIRECTWR_CANCEL, plat->regbase + CQSPI_REG_INDIRECTWR); - bounce_buffer_stop(&bb); return ret; } diff --git a/include/configs/k2g_evm.h b/include/configs/k2g_evm.h index 535e7124fc..0a38922a51 100644 --- a/include/configs/k2g_evm.h +++ b/include/configs/k2g_evm.h @@ -93,7 +93,6 @@ #ifndef CONFIG_SPL_BUILD #define CONFIG_CADENCE_QSPI #define CONFIG_CQSPI_REF_CLK 384000000 -#define CONFIG_BOUNCE_BUFFER #endif #define SPI_MTD_PARTS KEYSTONE_SPI1_MTD_PARTS diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h index ec8bb50050..f6607b101e 100644 --- a/include/configs/socfpga_common.h +++ b/include/configs/socfpga_common.h @@ -184,7 +184,6 @@ unsigned int cm_get_l4_sp_clk_hz(void); unsigned int cm_get_qspi_controller_clk_hz(void); #define CONFIG_CQSPI_REF_CLK cm_get_qspi_controller_clk_hz() #endif -#define CONFIG_BOUNCE_BUFFER /* * Designware SPI support diff --git a/include/configs/stv0991.h b/include/configs/stv0991.h index fd96979bf8..beb8f1ae9a 100644 --- a/include/configs/stv0991.h +++ b/include/configs/stv0991.h @@ -64,7 +64,6 @@ + */ #ifdef CONFIG_OF_CONTROL /* QSPI is controlled via DT */ #define CONFIG_CQSPI_REF_CLK ((30/4)/2)*1000*1000 -#define CONFIG_BOUNCE_BUFFER #endif From aaa21d3ffc023623a3a8247e5fa25d0db2bfb630 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Wed, 24 Jan 2018 10:44:07 +0530 Subject: [PATCH 33/35] spi: cadence_qspi_apb: Make flash writes 32 bit aligned Make flash writes 32 bit aligned by using bounce buffers to deal with non 32 bit aligned buffers. This is required because as per TI K2G TRM[1], the external master is only permitted to issue 32-bit data interface writes until the last word of an indirect transfer. Otherwise indirect writes is known to fail sometimes. [1] http://www.ti.com/lit/ug/spruhy8g/spruhy8g.pdf Signed-off-by: Vignesh R Acked-by: Marek Vasut Acked-by: Simon Goldschmidt Reviewed-by: Jason Rush Acked-by: Jason Rush Reviewed-by: Jagan Teki --- drivers/spi/cadence_qspi_apb.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 70d0f431ad..aa3a9ff5fa 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "cadence_qspi.h" #define CQSPI_REG_POLL_US 1 /* 1us */ @@ -719,9 +720,23 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, { unsigned int page_size = plat->page_size; unsigned int remaining = n_tx; + const u8 *bb_txbuf = txbuf; + void *bounce_buf = NULL; unsigned int write_bytes; int ret; + /* + * Use bounce buffer for non 32 bit aligned txbuf to avoid data + * aborts + */ + if ((uintptr_t)txbuf % 4) { + bounce_buf = malloc(n_tx); + if (!bounce_buf) + return -ENOMEM; + memcpy(bounce_buf, txbuf, n_tx); + bb_txbuf = bounce_buf; + } + /* Configure the indirect read transfer bytes */ writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES); @@ -731,11 +746,11 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, while (remaining > 0) { write_bytes = remaining > page_size ? page_size : remaining; - /* Handle non-4-byte aligned access to avoid data abort. */ - if (((uintptr_t)txbuf % 4) || (write_bytes % 4)) - writesb(plat->ahbbase, txbuf, write_bytes); - else - writesl(plat->ahbbase, txbuf, write_bytes >> 2); + writesl(plat->ahbbase, bb_txbuf, write_bytes >> 2); + if (write_bytes % 4) + writesb(plat->ahbbase, + bb_txbuf + rounddown(write_bytes, 4), + write_bytes % 4); ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_SDRAMLEVEL, CQSPI_REG_SDRAMLEVEL_WR_MASK << @@ -745,7 +760,7 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, goto failwr; } - txbuf += write_bytes; + bb_txbuf += write_bytes; remaining -= write_bytes; } @@ -760,12 +775,16 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, /* Clear indirect completion status */ writel(CQSPI_REG_INDIRECTWR_DONE, plat->regbase + CQSPI_REG_INDIRECTWR); + if (bounce_buf) + free(bounce_buf); return 0; failwr: /* Cancel the indirect write */ writel(CQSPI_REG_INDIRECTWR_CANCEL, plat->regbase + CQSPI_REG_INDIRECTWR); + if (bounce_buf) + free(bounce_buf); return ret; } From 21143ce127b953356bd6174fb4e4892af3a92d0f Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 28 Dec 2017 15:09:02 +0300 Subject: [PATCH 34/35] SOCFPGA: clock manager: implement dw_spi_get_clk function Implement dw_spi_get_clk function to override its weak implementation in designware_spi.c driver. We need this change to get rid of cm_get_spi_controller_clk_hz function and clock_manager.h include in designware_spi.c driver. Reviewed-by: Marek Vasut Signed-off-by: Eugeniy Paltsev Reviewed-by: Jagan Teki --- arch/arm/mach-socfpga/clock_manager_arria10.c | 9 +++++++++ arch/arm/mach-socfpga/clock_manager_gen5.c | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/mach-socfpga/clock_manager_arria10.c b/arch/arm/mach-socfpga/clock_manager_arria10.c index 482b8543f4..623a266f80 100644 --- a/arch/arm/mach-socfpga/clock_manager_arria10.c +++ b/arch/arm/mach-socfpga/clock_manager_arria10.c @@ -7,6 +7,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -1076,6 +1077,14 @@ unsigned int cm_get_qspi_controller_clk_hz(void) return cm_get_l4_noc_hz(CLKMGR_MAINPLL_NOCDIV_L4MAINCLK_LSB); } +/* Override weak dw_spi_get_clk implementation in designware_spi.c driver */ +int dw_spi_get_clk(struct udevice *bus, ulong *rate) +{ + *rate = cm_get_spi_controller_clk_hz(); + + return 0; +} + void cm_print_clock_quick_summary(void) { printf("MPU %10ld kHz\n", cm_get_mpu_clk_hz() / 1000); diff --git a/arch/arm/mach-socfpga/clock_manager_gen5.c b/arch/arm/mach-socfpga/clock_manager_gen5.c index a23f3fc5d0..3d048ba3e4 100644 --- a/arch/arm/mach-socfpga/clock_manager_gen5.c +++ b/arch/arm/mach-socfpga/clock_manager_gen5.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -507,6 +508,14 @@ unsigned int cm_get_spi_controller_clk_hz(void) return clock; } +/* Override weak dw_spi_get_clk implementation in designware_spi.c driver */ +int dw_spi_get_clk(struct udevice *bus, ulong *rate) +{ + *rate = cm_get_spi_controller_clk_hz(); + + return 0; +} + void cm_print_clock_quick_summary(void) { printf("MPU %10ld kHz\n", cm_get_mpu_clk_hz() / 1000); From 58c125b9e2b232ce73ed7b24ba7b1ca5ff41c5bd Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 28 Dec 2017 15:09:03 +0300 Subject: [PATCH 35/35] DW SPI: Get clock value from Device Tree Add option to set spi controller clock frequency via device tree using standard clock bindings. Define dw_spi_get_clk function as 'weak' as some targets (like SOCFPGA_GEN5 and SOCFPGA_ARRIA10) don't use standard clock API and implement dw_spi_get_clk their own way in their clock manager. Get rid of clock_manager.h include as we don't use cm_get_spi_controller_clk_hz function anymore. (we use redefined dw_spi_get_clk in SOCFPGA clock managers instead) Reviewed-by: Marek Vasut Signed-off-by: Eugeniy Paltsev Reviewed-by: Jagan Teki --- drivers/spi/designware_spi.c | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index 5aa507b2d8..c501aeea16 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -94,6 +94,8 @@ struct dw_spi_priv { void __iomem *regs; unsigned int freq; /* Default frequency */ unsigned int mode; + struct clk clk; + unsigned long bus_clk_rate; int bits_per_word; u8 cs; /* chip select pin */ @@ -176,14 +178,53 @@ static void spi_hw_init(struct dw_spi_priv *priv) debug("%s: fifo_len=%d\n", __func__, priv->fifo_len); } +/* + * We define dw_spi_get_clk function as 'weak' as some targets + * (like SOCFPGA_GEN5 and SOCFPGA_ARRIA10) don't use standard clock API + * and implement dw_spi_get_clk their own way in their clock manager. + */ +__weak int dw_spi_get_clk(struct udevice *bus, ulong *rate) +{ + struct dw_spi_priv *priv = dev_get_priv(bus); + int ret; + + ret = clk_get_by_index(bus, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) + return ret; + + *rate = clk_get_rate(&priv->clk); + if (!*rate) + goto err_rate; + + debug("%s: get spi controller clk via device tree: %lu Hz\n", + __func__, *rate); + + return 0; + +err_rate: + clk_disable(&priv->clk); + clk_free(&priv->clk); + + return -EINVAL; +} + static int dw_spi_probe(struct udevice *bus) { struct dw_spi_platdata *plat = dev_get_platdata(bus); struct dw_spi_priv *priv = dev_get_priv(bus); + int ret; priv->regs = plat->regs; priv->freq = plat->frequency; + ret = dw_spi_get_clk(bus, &priv->bus_clk_rate); + if (ret) + return ret; + /* Currently only bits_per_word == 8 supported */ priv->bits_per_word = 8; @@ -369,7 +410,7 @@ static int dw_spi_set_speed(struct udevice *bus, uint speed) spi_enable_chip(priv, 0); /* clk_div doesn't support odd number */ - clk_div = cm_get_spi_controller_clk_hz() / speed; + clk_div = priv->bus_clk_rate / speed; clk_div = (clk_div + 1) & 0xfffe; dw_writel(priv, DW_SPI_BAUDR, clk_div);