From b95938117cb2bd9b020305a58bd748a48e58d30a Mon Sep 17 00:00:00 2001 From: Martin Fuzzey Date: Fri, 23 Nov 2018 10:53:06 +0100 Subject: w1: fix occasional enumeration failure Sometimes enumeration fails (about 1 in 50 times on my custom board). The underlying reason is probably electrical but Linux does not have the problem. Comparing the Linux / u-boot implementations shows that Linux retries the error case whereas u-boot aborts early. Removing the early abort in u-boot fixes the problem. Signed-off-by: Martin Fuzzey --- drivers/w1/w1-uclass.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/w1/w1-uclass.c b/drivers/w1/w1-uclass.c index cb41b68eff..042b3b5ce0 100644 --- a/drivers/w1/w1-uclass.c +++ b/drivers/w1/w1-uclass.c @@ -84,10 +84,6 @@ static int w1_enumerate(struct udevice *bus) rn |= (tmp64 << i); } - /* last device or error, aborting here */ - if ((triplet_ret & 0x03) == 0x03) - last_device = true; - if ((triplet_ret & 0x03) != 0x03) { if (desc_bit == last_zero || last_zero < 0) { last_device = 1; -- cgit From 291da96b8e11d015d7725747bb8da677dcf01006 Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Mon, 26 Nov 2018 20:20:19 +0100 Subject: clk: Allow clock defaults to be set during re-reloc state for SPL only In commit e5e06b65ad65 ("clk: Allow clock defaults to be set also during re-reloc state") the earlier guard against setting clock defaults in pre-reloc state was removed. While it is easy to filter 'assigned-clocks' properties for SPL using CONFIG_OF_SPL_REMOVE_PROPS, no such mechanism exists for the pre-reloc stage of the full U-Boot. With the default defconfig for the RK3399-Q7 (which filter the 'assigned-clocks' property for the DTS used by SPL anyway), this caused a pause during startup of the full U-Boot stage that lasted for almost 10s (due to the CPU not having been clocked up yet). This reintroduces the guard from commit f4fcba5c5baa ("clk: Allow clock defaults to be set also during re-reloc state") and extends it to only apply outside of a TPL/SPL build: i.e. clk_set_defaults will now run in pre-reloc state for SPL, but only after reloc for the full U-Boot. References: commit f4fcba5c5baa ("clk: implement clk_set_defaults()") References: commit e5e06b65ad65 ("clk: Allow clock defaults to be set also during re-reloc state") Signed-off-by: Philipp Tomsich --- drivers/clk/clk-uclass.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 04b369aa5a..6d7a514006 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -243,6 +243,10 @@ int clk_set_defaults(struct udevice *dev) { int ret; + /* If this not in SPL and pre-reloc state, don't take any action. */ + if (!(IS_ENABLED(CONFIG_SPL_BUILD) || (gd->flags & GD_FLG_RELOC))) + return 0; + debug("%s(%s)\n", __func__, dev_read_name(dev)); ret = clk_set_default_parents(dev); -- cgit From 7f84fc670b17fca3d8d1b7c9472a19bb8085c890 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 27 Nov 2018 13:49:50 +0100 Subject: dm: Add Hardware Spinlock class This is uclass for Hardware Spinlocks. It implements two mandatory operations: lock and unlock and one optional relax operation. Signed-off-by: Benjamin Gaignard Reviewed-by: Simon Glass Reviewed-by: Patrice Chotard --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/hwspinlock/Kconfig | 16 ++++ drivers/hwspinlock/Makefile | 6 ++ drivers/hwspinlock/hwspinlock-uclass.c | 144 ++++++++++++++++++++++++++++++++ drivers/hwspinlock/sandbox_hwspinlock.c | 56 +++++++++++++ 6 files changed, 225 insertions(+) create mode 100644 drivers/hwspinlock/Kconfig create mode 100644 drivers/hwspinlock/Makefile create mode 100644 drivers/hwspinlock/hwspinlock-uclass.c create mode 100644 drivers/hwspinlock/sandbox_hwspinlock.c (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index 4ac823d962..e9fbadd13d 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -40,6 +40,8 @@ source "drivers/fpga/Kconfig" source "drivers/gpio/Kconfig" +source "drivers/hwspinlock/Kconfig" + source "drivers/i2c/Kconfig" source "drivers/input/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 55de10926e..c425831b58 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -113,4 +113,5 @@ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_W1_EEPROM) += w1-eeprom/ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/ +obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/ endif diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig new file mode 100644 index 0000000000..de367fd2a9 --- /dev/null +++ b/drivers/hwspinlock/Kconfig @@ -0,0 +1,16 @@ +menu "Hardware Spinlock Support" + +config DM_HWSPINLOCK + bool "Enable U-Boot hardware spinlock support" + help + This option enables U-Boot hardware spinlock support + +config HWSPINLOCK_SANDBOX + bool "Enable Hardware Spinlock support for Sandbox" + depends on SANDBOX && DM_HWSPINLOCK + help + Enable hardware spinlock support in Sandbox. This is a dummy device that + can be probed and support all the methods of HWSPINLOCK, but does not + really do anything. + +endmenu diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile new file mode 100644 index 0000000000..2704d6814f --- /dev/null +++ b/drivers/hwspinlock/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +# +# Copyright (C) 2018, STMicroelectronics - All Rights Reserved + +obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o +obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o diff --git a/drivers/hwspinlock/hwspinlock-uclass.c b/drivers/hwspinlock/hwspinlock-uclass.c new file mode 100644 index 0000000000..195f079707 --- /dev/null +++ b/drivers/hwspinlock/hwspinlock-uclass.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include + +static inline const struct hwspinlock_ops * +hwspinlock_dev_ops(struct udevice *dev) +{ + return (const struct hwspinlock_ops *)dev->driver->ops; +} + +static int hwspinlock_of_xlate_default(struct hwspinlock *hws, + struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + hws->id = args->args[0]; + else + hws->id = 0; + + return 0; +} + +int hwspinlock_get_by_index(struct udevice *dev, int index, + struct hwspinlock *hws) +{ + int ret; + struct ofnode_phandle_args args; + struct udevice *dev_hws; + const struct hwspinlock_ops *ops; + + assert(hws); + hws->dev = NULL; + + ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1, + index, &args); + if (ret) { + dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK, + args.node, &dev_hws); + if (ret) { + dev_dbg(dev, + "%s: uclass_get_device_by_of_offset failed: err=%d\n", + __func__, ret); + return ret; + } + + hws->dev = dev_hws; + + ops = hwspinlock_dev_ops(dev_hws); + + if (ops->of_xlate) + ret = ops->of_xlate(hws, &args); + else + ret = hwspinlock_of_xlate_default(hws, &args); + if (ret) + dev_dbg(dev, "of_xlate() failed: %d\n", ret); + + return ret; +} + +int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout) +{ + const struct hwspinlock_ops *ops; + ulong start; + int ret; + + assert(hws); + + if (!hws->dev) + return -EINVAL; + + ops = hwspinlock_dev_ops(hws->dev); + if (!ops->lock) + return -ENOSYS; + + start = get_timer(0); + do { + ret = ops->lock(hws->dev, hws->id); + if (!ret) + return ret; + + if (ops->relax) + ops->relax(hws->dev); + } while (get_timer(start) < timeout); + + return -ETIMEDOUT; +} + +int hwspinlock_unlock(struct hwspinlock *hws) +{ + const struct hwspinlock_ops *ops; + + assert(hws); + + if (!hws->dev) + return -EINVAL; + + ops = hwspinlock_dev_ops(hws->dev); + if (!ops->unlock) + return -ENOSYS; + + return ops->unlock(hws->dev, hws->id); +} + +static int hwspinlock_post_bind(struct udevice *dev) +{ +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct hwspinlock_ops *ops = device_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->lock) + ops->lock += gd->reloc_off; + if (ops->unlock) + ops->unlock += gd->reloc_off; + if (ops->relax) + ops->relax += gd->reloc_off; + + reloc_done++; + } +#endif + return 0; +} + +UCLASS_DRIVER(hwspinlock) = { + .id = UCLASS_HWSPINLOCK, + .name = "hwspinlock", + .post_bind = hwspinlock_post_bind, +}; diff --git a/drivers/hwspinlock/sandbox_hwspinlock.c b/drivers/hwspinlock/sandbox_hwspinlock.c new file mode 100644 index 0000000000..be920f5f99 --- /dev/null +++ b/drivers/hwspinlock/sandbox_hwspinlock.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include + +static int sandbox_lock(struct udevice *dev, int index) +{ + struct sandbox_state *state = state_get_current(); + + if (index != 0) + return -1; + + if (state->hwspinlock) + return -1; + + state->hwspinlock = true; + + return 0; +} + +static int sandbox_unlock(struct udevice *dev, int index) +{ + struct sandbox_state *state = state_get_current(); + + if (index != 0) + return -1; + + if (!state->hwspinlock) + return -1; + + state->hwspinlock = false; + + return 0; +} + +static const struct hwspinlock_ops sandbox_hwspinlock_ops = { + .lock = sandbox_lock, + .unlock = sandbox_unlock, +}; + +static const struct udevice_id sandbox_hwspinlock_ids[] = { + { .compatible = "sandbox,hwspinlock" }, + {} +}; + +U_BOOT_DRIVER(hwspinlock_sandbox) = { + .name = "hwspinlock_sandbox", + .id = UCLASS_HWSPINLOCK, + .of_match = sandbox_hwspinlock_ids, + .ops = &sandbox_hwspinlock_ops, +}; -- cgit From 283bcd9a341dcc344113daad82d8e5ab978ed260 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 27 Nov 2018 13:49:51 +0100 Subject: clk: stm32: add hardware spinlock clock Add hardware spinlock in the list of the clocks. Signed-off-by: Benjamin Gaignard Reviewed-by: Simon Glass Reviewed-by: Patrice Chotard --- drivers/clk/clk_stm32mp1.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 6a8c7b754f..b7c5d34fe0 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -104,6 +104,7 @@ #define RCC_MP_APB2ENSETR 0XA08 #define RCC_MP_APB3ENSETR 0xA10 #define RCC_MP_AHB2ENSETR 0xA18 +#define RCC_MP_AHB3ENSETR 0xA20 #define RCC_MP_AHB4ENSETR 0xA28 /* used for most of SELR register */ @@ -534,6 +535,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB3ENSETR, 11, HSEM, _UNKNOWN_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), -- cgit From 9119f547d3e9b9f488055b90572a8ff83125b3e2 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 27 Nov 2018 13:49:52 +0100 Subject: hwspinlock: add stm32 hardware spinlock support Implement hardware spinlock support for STM32MP1. Signed-off-by: Benjamin Gaignard Reviewed-by: Simon Glass Reviewed-by: Patrice Chotard --- drivers/hwspinlock/Kconfig | 8 +++ drivers/hwspinlock/Makefile | 1 + drivers/hwspinlock/stm32_hwspinlock.c | 92 +++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c (limited to 'drivers') diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index de367fd2a9..96d4f5d6ca 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -13,4 +13,12 @@ config HWSPINLOCK_SANDBOX can be probed and support all the methods of HWSPINLOCK, but does not really do anything. +config HWSPINLOCK_STM32 + bool "Enable Hardware Spinlock support for STM32" + depends on ARCH_STM32MP && DM_HWSPINLOCK + help + Enable hardware spinlock support in STM32MP. Hardware spinlocks are + hardware mutex which provide a synchronisation mechanism for the + various processors on the SoC. + endmenu diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index 2704d6814f..289b12a256 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock-uclass.o obj-$(CONFIG_HWSPINLOCK_SANDBOX) += sandbox_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c new file mode 100644 index 0000000000..a32bde4906 --- /dev/null +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include + +#define STM32_MUTEX_COREID BIT(8) +#define STM32_MUTEX_LOCK_BIT BIT(31) +#define STM32_MUTEX_NUM_LOCKS 32 + +struct stm32mp1_hws_priv { + fdt_addr_t base; +}; + +static int stm32mp1_lock(struct udevice *dev, int index) +{ + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); + u32 status; + + if (index >= STM32_MUTEX_NUM_LOCKS) + return -EINVAL; + + status = readl(priv->base + index * sizeof(u32)); + if (status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) + return -EBUSY; + + writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, + priv->base + index * sizeof(u32)); + + status = readl(priv->base + index * sizeof(u32)); + if (status != (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID)) + return -EINVAL; + + return 0; +} + +static int stm32mp1_unlock(struct udevice *dev, int index) +{ + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); + + if (index >= STM32_MUTEX_NUM_LOCKS) + return -EINVAL; + + writel(STM32_MUTEX_COREID, priv->base + index * sizeof(u32)); + + return 0; +} + +static int stm32mp1_hwspinlock_probe(struct udevice *dev) +{ + struct stm32mp1_hws_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + clk_free(&clk); + + return ret; +} + +static const struct hwspinlock_ops stm32mp1_hwspinlock_ops = { + .lock = stm32mp1_lock, + .unlock = stm32mp1_unlock, +}; + +static const struct udevice_id stm32mp1_hwspinlock_ids[] = { + { .compatible = "st,stm32-hwspinlock" }, + {} +}; + +U_BOOT_DRIVER(hwspinlock_stm32mp1) = { + .name = "hwspinlock_stm32mp1", + .id = UCLASS_HWSPINLOCK, + .of_match = stm32mp1_hwspinlock_ids, + .ops = &stm32mp1_hwspinlock_ops, + .probe = stm32mp1_hwspinlock_probe, + .priv_auto_alloc_size = sizeof(struct stm32mp1_hws_priv), +}; -- cgit From 075b0185b6e785f08391802dccd3293ce8517a93 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 27 Nov 2018 13:49:53 +0100 Subject: pinctrl: stm32: make pinctrl use hwspinlock Protect configuration registers with a hardware spinlock. If a hwspinlock is defined in the device-tree node used it to be sure that none of the others processors on the SoC could change the configuration at the same time. Signed-off-by: Benjamin Gaignard Reviewed-by: Simon Glass Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl_stm32.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 6d4117d941..bb63da3739 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -14,8 +15,8 @@ DECLARE_GLOBAL_DATA_PTR; #define OTYPE_MSK 1 #define AFR_MASK 0xF -#ifndef CONFIG_SPL_BUILD struct stm32_pinctrl_priv { + struct hwspinlock hws; int pinctrl_ngpios; struct list_head gpio_dev; }; @@ -25,6 +26,8 @@ struct stm32_gpio_bank { struct list_head list; }; +#ifndef CONFIG_SPL_BUILD + #define MAX_PIN_PER_BANK 16 static char pin_name[PINNAME_SIZE]; @@ -166,6 +169,8 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, return 0; } +#endif + int stm32_pinctrl_probe(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); @@ -198,21 +203,35 @@ int stm32_pinctrl_probe(struct udevice *dev) list_add_tail(&gpio_bank->list, &priv->gpio_dev); } + /* hwspinlock property is optional, just log the error */ + ret = hwspinlock_get_by_index(dev, 0, &priv->hws); + if (ret) + debug("%s: hwspinlock_get_by_index may have failed (%d)\n", + __func__, ret); + return 0; } -#endif static int stm32_gpio_config(struct gpio_desc *desc, const struct stm32_gpio_ctl *ctl) { struct stm32_gpio_priv *priv = dev_get_priv(desc->dev); struct stm32_gpio_regs *regs = priv->regs; + struct stm32_pinctrl_priv *ctrl_priv; + int ret; u32 index; if (!ctl || ctl->af > 15 || ctl->mode > 3 || ctl->otype > 1 || ctl->pupd > 2 || ctl->speed > 3) return -EINVAL; + ctrl_priv = dev_get_priv(dev_get_parent(desc->dev)); + ret = hwspinlock_lock_timeout(&ctrl_priv->hws, 10); + if (ret == -ETIME) { + dev_err(desc->dev, "HWSpinlock timeout\n"); + return ret; + } + index = (desc->offset & 0x07) * 4; clrsetbits_le32(®s->afr[desc->offset >> 3], AFR_MASK << index, ctl->af << index); @@ -227,6 +246,8 @@ static int stm32_gpio_config(struct gpio_desc *desc, index = desc->offset; clrsetbits_le32(®s->otyper, OTYPE_MSK << index, ctl->otype << index); + hwspinlock_unlock(&ctrl_priv->hws); + return 0; } @@ -393,8 +414,6 @@ U_BOOT_DRIVER(pinctrl_stm32) = { .of_match = stm32_pinctrl_ids, .ops = &stm32_pinctrl_ops, .bind = dm_scan_fdt_dev, -#ifndef CONFIG_SPL_BUILD .probe = stm32_pinctrl_probe, .priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv), -#endif }; -- cgit From 10b4dc520811fdfc5a31f6067be2b0cd0753998d Mon Sep 17 00:00:00 2001 From: Álvaro Fernández Rojas Date: Wed, 28 Nov 2018 19:17:49 +0100 Subject: dma: move dma_ops to dma-uclass.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move dma_ops to a separate header file, following other uclass implementations. While doing so, this patch also improves dma_ops documentation. Reviewed-by: Tom Rini Reviewed-by: Simon Glass Signed-off-by: Álvaro Fernández Rojas Signed-off-by: Grygorii Strashko --- drivers/dma/dma-uclass.c | 2 +- drivers/dma/ti-edma3.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index a33f7d52da..6c3506c302 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -9,10 +9,10 @@ */ #include -#include #include #include #include +#include #include int dma_get_device(u32 transfer_type, struct udevice **devp) diff --git a/drivers/dma/ti-edma3.c b/drivers/dma/ti-edma3.c index 2131e10a40..7e11b13e45 100644 --- a/drivers/dma/ti-edma3.c +++ b/drivers/dma/ti-edma3.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include -- cgit From 27ab27f85057801953d65d563f2340a22859bbbe Mon Sep 17 00:00:00 2001 From: Álvaro Fernández Rojas Date: Wed, 28 Nov 2018 19:17:50 +0100 Subject: dma: add channels support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds channels support for dma controllers that have multiple channels which can transfer data to/from different devices (enet, usb...). DMA channle API: dma_get_by_index() dma_get_by_name() dma_request() dma_free() dma_enable() dma_disable() dma_prepare_rcv_buf() dma_receive() dma_send() Reviewed-by: Tom Rini Signed-off-by: Álvaro Fernández Rojas [grygorii.strashko@ti.com: drop unused dma_get_by_index_platdata(), add metadata to send/receive ops, add dma_prepare_rcv_buf(), minor clean up] Signed-off-by: Grygorii Strashko Reviewed-by: Simon Glass --- drivers/dma/Kconfig | 7 ++ drivers/dma/dma-uclass.c | 181 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 184 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 4ee6afad35..b9b85c65fc 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -12,6 +12,13 @@ config DMA buses that is used to transfer data to and from memory. The uclass interface is defined in include/dma.h. +config DMA_CHANNELS + bool "Enable DMA channels support" + depends on DMA + help + Enable channels support for DMA. Some DMA controllers have multiple + channels which can either transfer data to/from different devices. + config TI_EDMA3 bool "TI EDMA3 driver" help diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index 6c3506c302..9c961cf1e2 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -2,19 +2,192 @@ /* * Direct Memory Access U-Class driver * - * (C) Copyright 2015 - * Texas Instruments Incorporated, + * Copyright (C) 2018 Álvaro Fernández Rojas + * Copyright (C) 2015 - 2018 Texas Instruments Incorporated + * Written by Mugunthan V N * * Author: Mugunthan V N */ #include #include -#include -#include +#include #include +#include #include +#ifdef CONFIG_DMA_CHANNELS +static inline struct dma_ops *dma_dev_ops(struct udevice *dev) +{ + return (struct dma_ops *)dev->driver->ops; +} + +# if CONFIG_IS_ENABLED(OF_CONTROL) +static int dma_of_xlate_default(struct dma *dma, + struct ofnode_phandle_args *args) +{ + debug("%s(dma=%p)\n", __func__, dma); + + if (args->args_count > 1) { + pr_err("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + dma->id = args->args[0]; + else + dma->id = 0; + + return 0; +} + +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma) +{ + int ret; + struct ofnode_phandle_args args; + struct udevice *dev_dma; + const struct dma_ops *ops; + + debug("%s(dev=%p, index=%d, dma=%p)\n", __func__, dev, index, dma); + + assert(dma); + dma->dev = NULL; + + ret = dev_read_phandle_with_args(dev, "dmas", "#dma-cells", 0, index, + &args); + if (ret) { + pr_err("%s: dev_read_phandle_with_args failed: err=%d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_ofnode(UCLASS_DMA, args.node, &dev_dma); + if (ret) { + pr_err("%s: uclass_get_device_by_ofnode failed: err=%d\n", + __func__, ret); + return ret; + } + + dma->dev = dev_dma; + + ops = dma_dev_ops(dev_dma); + + if (ops->of_xlate) + ret = ops->of_xlate(dma, &args); + else + ret = dma_of_xlate_default(dma, &args); + if (ret) { + pr_err("of_xlate() failed: %d\n", ret); + return ret; + } + + return dma_request(dev_dma, dma); +} + +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma) +{ + int index; + + debug("%s(dev=%p, name=%s, dma=%p)\n", __func__, dev, name, dma); + dma->dev = NULL; + + index = dev_read_stringlist_search(dev, "dma-names", name); + if (index < 0) { + pr_err("dev_read_stringlist_search() failed: %d\n", index); + return index; + } + + return dma_get_by_index(dev, index, dma); +} +# endif /* OF_CONTROL */ + +int dma_request(struct udevice *dev, struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dev); + + debug("%s(dev=%p, dma=%p)\n", __func__, dev, dma); + + dma->dev = dev; + + if (!ops->request) + return 0; + + return ops->request(dma); +} + +int dma_free(struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->free) + return 0; + + return ops->free(dma); +} + +int dma_enable(struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->enable) + return -ENOSYS; + + return ops->enable(dma); +} + +int dma_disable(struct dma *dma) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->disable) + return -ENOSYS; + + return ops->disable(dma); +} + +int dma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->prepare_rcv_buf) + return -1; + + return ops->prepare_rcv_buf(dma, dst, size); +} + +int dma_receive(struct dma *dma, void **dst, void *metadata) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->receive) + return -ENOSYS; + + return ops->receive(dma, dst, metadata); +} + +int dma_send(struct dma *dma, void *src, size_t len, void *metadata) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->send) + return -ENOSYS; + + return ops->send(dma, src, len, metadata); +} +#endif /* CONFIG_DMA_CHANNELS */ + int dma_get_device(u32 transfer_type, struct udevice **devp) { struct udevice *dev; -- cgit From b3309918740f00735d414c44ed2a3f26c418715b Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 28 Nov 2018 19:17:51 +0100 Subject: test: dma: add dma-uclass test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a sandbox DMA driver implementation (provider) and corresponding DM test. Reviewed-by: Tom Rini Signed-off-by: Grygorii Strashko Reviewed-by: Simon Glass Acked-by: Álvaro Fernández Rojas --- drivers/dma/Kconfig | 7 + drivers/dma/Makefile | 1 + drivers/dma/sandbox-dma-test.c | 282 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+) create mode 100644 drivers/dma/sandbox-dma-test.c (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index b9b85c65fc..8a4162eccd 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -19,6 +19,13 @@ config DMA_CHANNELS Enable channels support for DMA. Some DMA controllers have multiple channels which can either transfer data to/from different devices. +config SANDBOX_DMA + bool "Enable the sandbox DMA test driver" + depends on DMA && DMA_CHANNELS && SANDBOX + help + Enable support for a test DMA uclass implementation. It stimulates + DMA transfer by simple copying data between channels. + config TI_EDMA3 bool "TI EDMA3 driver" help diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 4eaef8ac65..aff31f986a 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DMA) += dma-uclass.o obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o obj-$(CONFIG_APBH_DMA) += apbh_dma.o obj-$(CONFIG_FSL_DMA) += fsl_dma.o +obj-$(CONFIG_SANDBOX_DMA) += sandbox-dma-test.o obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o obj-$(CONFIG_TI_EDMA3) += ti-edma3.o obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o diff --git a/drivers/dma/sandbox-dma-test.c b/drivers/dma/sandbox-dma-test.c new file mode 100644 index 0000000000..8fcef1863e --- /dev/null +++ b/drivers/dma/sandbox-dma-test.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Direct Memory Access U-Class Simulation driver + * + * Copyright (C) 2018 Texas Instruments Incorporated + * + * Author: Grygorii Strashko + */ + +#include +#include +#include +#include +#include +#include + +#define SANDBOX_DMA_CH_CNT 3 +#define SANDBOX_DMA_BUF_SIZE 1024 + +struct sandbox_dma_chan { + struct sandbox_dma_dev *ud; + char name[20]; + u32 id; + enum dma_direction dir; + bool in_use; + bool enabled; +}; + +struct sandbox_dma_dev { + struct device *dev; + u32 ch_count; + struct sandbox_dma_chan channels[SANDBOX_DMA_CH_CNT]; + uchar buf[SANDBOX_DMA_BUF_SIZE]; + uchar *buf_rx; + size_t data_len; + u32 meta; +}; + +static int sandbox_dma_transfer(struct udevice *dev, int direction, + void *dst, void *src, size_t len) +{ + memcpy(dst, src, len); + + return 0; +} + +static int sandbox_dma_of_xlate(struct dma *dma, + struct ofnode_phandle_args *args) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + debug("%s(dma id=%u)\n", __func__, args->args[0]); + + if (args->args[0] >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + dma->id = args->args[0]; + + uc = &ud->channels[dma->id]; + + if (dma->id == 1) + uc->dir = DMA_MEM_TO_DEV; + else if (dma->id == 2) + uc->dir = DMA_DEV_TO_MEM; + else + uc->dir = DMA_MEM_TO_MEM; + debug("%s(dma id=%lu dir=%d)\n", __func__, dma->id, uc->dir); + + return 0; +} + +static int sandbox_dma_request(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (uc->in_use) + return -EBUSY; + + uc->in_use = true; + debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); + + return 0; +} + +static int sandbox_dma_free(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + + uc->in_use = false; + ud->buf_rx = NULL; + ud->data_len = 0; + debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); + + return 0; +} + +static int sandbox_dma_enable(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + if (uc->enabled) + return -EINVAL; + + uc->enabled = true; + debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); + + return 0; +} + +static int sandbox_dma_disable(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + + uc->enabled = false; + debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); + + return 0; +} + +static int sandbox_dma_send(struct dma *dma, + void *src, size_t len, void *metadata) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + if (!src || !metadata) + return -EINVAL; + + debug("%s(dma id=%lu)\n", __func__, dma->id); + + uc = &ud->channels[dma->id]; + if (uc->dir != DMA_MEM_TO_DEV) + return -EINVAL; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + if (len >= SANDBOX_DMA_BUF_SIZE) + return -EINVAL; + + memcpy(ud->buf, src, len); + ud->data_len = len; + ud->meta = *((u32 *)metadata); + + debug("%s(dma id=%lu len=%zu meta=%08x)\n", + __func__, dma->id, len, ud->meta); + + return 0; +} + +static int sandbox_dma_receive(struct dma *dma, void **dst, void *metadata) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + if (!dst || !metadata) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (uc->dir != DMA_DEV_TO_MEM) + return -EINVAL; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + if (!ud->data_len) + return 0; + + if (ud->buf_rx) { + memcpy(ud->buf_rx, ud->buf, ud->data_len); + *dst = ud->buf_rx; + } else { + memcpy(*dst, ud->buf, ud->data_len); + } + + *((u32 *)metadata) = ud->meta; + + debug("%s(dma id=%lu len=%zu meta=%08x %p)\n", + __func__, dma->id, ud->data_len, ud->meta, *dst); + + return ud->data_len; +} + +static int sandbox_dma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + + ud->buf_rx = dst; + + return 0; +} + +static const struct dma_ops sandbox_dma_ops = { + .transfer = sandbox_dma_transfer, + .of_xlate = sandbox_dma_of_xlate, + .request = sandbox_dma_request, + .free = sandbox_dma_free, + .enable = sandbox_dma_enable, + .disable = sandbox_dma_disable, + .send = sandbox_dma_send, + .receive = sandbox_dma_receive, + .prepare_rcv_buf = sandbox_dma_prepare_rcv_buf, +}; + +static int sandbox_dma_probe(struct udevice *dev) +{ + struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct sandbox_dma_dev *ud = dev_get_priv(dev); + int i, ret = 0; + + uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM | + DMA_SUPPORTS_MEM_TO_DEV | + DMA_SUPPORTS_DEV_TO_MEM; + + ud->ch_count = SANDBOX_DMA_CH_CNT; + ud->buf_rx = NULL; + ud->meta = 0; + ud->data_len = 0; + + pr_err("Number of channels: %u\n", ud->ch_count); + + for (i = 0; i < ud->ch_count; i++) { + struct sandbox_dma_chan *uc = &ud->channels[i]; + + uc->ud = ud; + uc->id = i; + sprintf(uc->name, "DMA chan%d\n", i); + uc->in_use = false; + uc->enabled = false; + } + + return ret; +} + +static const struct udevice_id sandbox_dma_ids[] = { + { .compatible = "sandbox,dma" }, + { } +}; + +U_BOOT_DRIVER(sandbox_dma) = { + .name = "sandbox-dma", + .id = UCLASS_DMA, + .of_match = sandbox_dma_ids, + .ops = &sandbox_dma_ops, + .probe = sandbox_dma_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_dma_dev), +}; -- cgit From 09ace9161b95ad3a04b33d1d6a65a929901d28c8 Mon Sep 17 00:00:00 2001 From: Álvaro Fernández Rojas Date: Sat, 1 Dec 2018 18:42:07 +0100 Subject: serial: bcm6345: switch to raw I/O functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Fernández Rojas --- drivers/serial/serial_bcm6345.c | 99 ++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_bcm6345.c b/drivers/serial/serial_bcm6345.c index a0e709a11e..9ad8c770d5 100644 --- a/drivers/serial/serial_bcm6345.c +++ b/drivers/serial/serial_bcm6345.c @@ -89,26 +89,26 @@ struct bcm6345_serial_priv { /* enable rx & tx operation on uart */ static void bcm6345_serial_enable(void __iomem *base) { - setbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); + setbits_32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | + UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); } /* disable rx & tx operation on uart */ static void bcm6345_serial_disable(void __iomem *base) { - clrbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); + clrbits_32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | + UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); } /* clear all unread data in rx fifo and unsent data in tx fifo */ static void bcm6345_serial_flush(void __iomem *base) { /* empty rx and tx fifo */ - setbits_be32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK | - UART_CTL_RSTTXFIFO_MASK); + setbits_32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK | + UART_CTL_RSTTXFIFO_MASK); /* read any pending char to make sure all irq status are cleared */ - readl_be(base + UART_FIFO_REG); + readl(base + UART_FIFO_REG); } static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) @@ -120,40 +120,40 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) bcm6345_serial_flush(base); /* set uart control config */ - clrsetbits_be32(base + UART_CTL_REG, - /* clear rx timeout */ - UART_CTL_RXTIMEOUT_MASK | - /* clear stop bits */ - UART_CTL_STOPBITS_MASK | - /* clear bits per symbol */ - UART_CTL_BITSPERSYM_MASK | - /* clear xmit break */ - UART_CTL_XMITBRK_MASK | - /* clear reserved bit */ - UART_CTL_RSVD_MASK | - /* disable parity */ - UART_CTL_RXPAREN_MASK | - UART_CTL_TXPAREN_MASK | - /* disable loopback */ - UART_CTL_LOOPBACK_MASK, - /* set timeout to 5 */ - UART_CTL_RXTIMEOUT_5 | - /* set 8 bits/symbol */ - UART_CTL_BITSPERSYM_8 | - /* set 1 stop bit */ - UART_CTL_STOPBITS_1 | - /* set parity to even */ - UART_CTL_RXPAREVEN_MASK | - UART_CTL_TXPAREVEN_MASK); + clrsetbits_32(base + UART_CTL_REG, + /* clear rx timeout */ + UART_CTL_RXTIMEOUT_MASK | + /* clear stop bits */ + UART_CTL_STOPBITS_MASK | + /* clear bits per symbol */ + UART_CTL_BITSPERSYM_MASK | + /* clear xmit break */ + UART_CTL_XMITBRK_MASK | + /* clear reserved bit */ + UART_CTL_RSVD_MASK | + /* disable parity */ + UART_CTL_RXPAREN_MASK | + UART_CTL_TXPAREN_MASK | + /* disable loopback */ + UART_CTL_LOOPBACK_MASK, + /* set timeout to 5 */ + UART_CTL_RXTIMEOUT_5 | + /* set 8 bits/symbol */ + UART_CTL_BITSPERSYM_8 | + /* set 1 stop bit */ + UART_CTL_STOPBITS_1 | + /* set parity to even */ + UART_CTL_RXPAREVEN_MASK | + UART_CTL_TXPAREVEN_MASK); /* set uart fifo config */ - clrsetbits_be32(base + UART_FIFO_CFG_REG, - /* clear fifo config */ - UART_FIFO_CFG_RX_MASK | - UART_FIFO_CFG_TX_MASK, - /* set fifo config to 4 */ - UART_FIFO_CFG_RX_4 | - UART_FIFO_CFG_TX_4); + clrsetbits_32(base + UART_FIFO_CFG_REG, + /* clear fifo config */ + UART_FIFO_CFG_RX_MASK | + UART_FIFO_CFG_TX_MASK, + /* set fifo config to 4 */ + UART_FIFO_CFG_RX_4 | + UART_FIFO_CFG_TX_4); /* set baud rate */ val = ((clk / baudrate) >> 4); @@ -161,10 +161,10 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) val = (val >> 1); else val = (val >> 1) - 1; - writel_be(val, base + UART_BAUD_REG); + writel(val, base + UART_BAUD_REG); /* clear interrupts */ - writel_be(0, base + UART_IR_REG); + writel(0, base + UART_IR_REG); /* enable uart */ bcm6345_serial_enable(base); @@ -175,7 +175,7 @@ static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate) static int bcm6345_serial_pending(struct udevice *dev, bool input) { struct bcm6345_serial_priv *priv = dev_get_priv(dev); - u32 val = readl_be(priv->base + UART_IR_REG); + u32 val = readl(priv->base + UART_IR_REG); if (input) return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)); @@ -195,11 +195,11 @@ static int bcm6345_serial_putc(struct udevice *dev, const char ch) struct bcm6345_serial_priv *priv = dev_get_priv(dev); u32 val; - val = readl_be(priv->base + UART_IR_REG); + val = readl(priv->base + UART_IR_REG); if (!(val & UART_IR_STAT(UART_IR_TXEMPTY))) return -EAGAIN; - writel_be(ch, priv->base + UART_FIFO_REG); + writel(ch, priv->base + UART_FIFO_REG); return 0; } @@ -209,14 +209,13 @@ static int bcm6345_serial_getc(struct udevice *dev) struct bcm6345_serial_priv *priv = dev_get_priv(dev); u32 val; - val = readl_be(priv->base + UART_IR_REG); + val = readl(priv->base + UART_IR_REG); if (val & UART_IR_STAT(UART_IR_RXOVER)) - setbits_be32(priv->base + UART_CTL_REG, - UART_CTL_RSTRXFIFO_MASK); + setbits_32(priv->base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK); if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY))) return -EAGAIN; - val = readl_be(priv->base + UART_FIFO_REG); + val = readl(priv->base + UART_FIFO_REG); if (val & UART_FIFO_ANYERR_MASK) return -EAGAIN; @@ -277,7 +276,7 @@ static inline void _debug_uart_init(void) static inline void wait_xfered(void __iomem *base) { do { - u32 val = readl_be(base + UART_IR_REG); + u32 val = readl(base + UART_IR_REG); if (val & UART_IR_STAT(UART_IR_TXEMPTY)) break; } while (1); @@ -288,7 +287,7 @@ static inline void _debug_uart_putc(int ch) void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; wait_xfered(base); - writel_be(ch, base + UART_FIFO_REG); + writel(ch, base + UART_FIFO_REG); wait_xfered(base); } -- cgit From e9e8d80d8c74f38cd259c60bd6128b294ede4975 Mon Sep 17 00:00:00 2001 From: Álvaro Fernández Rojas Date: Sat, 1 Dec 2018 18:42:09 +0100 Subject: serial: bcm6858: remove driver and switch to bcm6345 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Fernández Rojas --- drivers/serial/Kconfig | 8 +- drivers/serial/Makefile | 1 - drivers/serial/serial_bcm6858.c | 300 ---------------------------------------- 3 files changed, 1 insertion(+), 308 deletions(-) delete mode 100644 drivers/serial/serial_bcm6858.c (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3bcc61e731..6252dd8c4b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -506,16 +506,10 @@ config BCM283X_PL011_SERIAL config BCM6345_SERIAL bool "Support for BCM6345 UART" - depends on DM_SERIAL && ARCH_BMIPS + depends on DM_SERIAL help Select this to enable UART on BCM6345 SoCs. -config BCM6858_SERIAL - bool "Support for BCM6858 UART" - depends on DM_SERIAL && ARCH_BCM6858 - help - Select this to enable UART on BCM6358 SoCs. - config FSL_LINFLEXUART bool "Freescale Linflex UART support" depends on DM_SERIAL diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index b6377b1076..2f8d065a4c 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_AR933X_UART) += serial_ar933x.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o -obj-$(CONFIG_BCM6858_SERIAL) += serial_bcm6858.o obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o diff --git a/drivers/serial/serial_bcm6858.c b/drivers/serial/serial_bcm6858.c deleted file mode 100644 index 8aa37055f0..0000000000 --- a/drivers/serial/serial_bcm6858.c +++ /dev/null @@ -1,300 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018 Philippe Reynes - * - * Derived from linux/drivers/tty/serial/bcm63xx_uart.c: - * Copyright (C) 2008 Maxime Bizon - * Derived from linux/drivers/tty/serial/serial_bcm6345.c - * Copyright (C) 2017 Álvaro Fernández Rojas - */ - -#include -#include -#include -#include -#include -#include -#include - -/* UART Control register */ -#define UART_CTL_REG 0x0 -#define UART_CTL_RXTIMEOUT_MASK 0x1f -#define UART_CTL_RXTIMEOUT_5 0x5 -#define UART_CTL_RSTRXFIFO_SHIFT 6 -#define UART_CTL_RSTRXFIFO_MASK (1 << UART_CTL_RSTRXFIFO_SHIFT) -#define UART_CTL_RSTTXFIFO_SHIFT 7 -#define UART_CTL_RSTTXFIFO_MASK (1 << UART_CTL_RSTTXFIFO_SHIFT) -#define UART_CTL_STOPBITS_SHIFT 8 -#define UART_CTL_STOPBITS_MASK (0xf << UART_CTL_STOPBITS_SHIFT) -#define UART_CTL_STOPBITS_1 (0x7 << UART_CTL_STOPBITS_SHIFT) -#define UART_CTL_BITSPERSYM_SHIFT 12 -#define UART_CTL_BITSPERSYM_MASK (0x3 << UART_CTL_BITSPERSYM_SHIFT) -#define UART_CTL_BITSPERSYM_8 (0x3 << UART_CTL_BITSPERSYM_SHIFT) -#define UART_CTL_XMITBRK_SHIFT 14 -#define UART_CTL_XMITBRK_MASK (1 << UART_CTL_XMITBRK_SHIFT) -#define UART_CTL_RSVD_SHIFT 15 -#define UART_CTL_RSVD_MASK (1 << UART_CTL_RSVD_SHIFT) -#define UART_CTL_RXPAREVEN_SHIFT 16 -#define UART_CTL_RXPAREVEN_MASK (1 << UART_CTL_RXPAREVEN_SHIFT) -#define UART_CTL_RXPAREN_SHIFT 17 -#define UART_CTL_RXPAREN_MASK (1 << UART_CTL_RXPAREN_SHIFT) -#define UART_CTL_TXPAREVEN_SHIFT 18 -#define UART_CTL_TXPAREVEN_MASK (1 << UART_CTL_TXPAREVEN_SHIFT) -#define UART_CTL_TXPAREN_SHIFT 19 -#define UART_CTL_TXPAREN_MASK (1 << UART_CTL_TXPAREN_SHIFT) -#define UART_CTL_LOOPBACK_SHIFT 20 -#define UART_CTL_LOOPBACK_MASK (1 << UART_CTL_LOOPBACK_SHIFT) -#define UART_CTL_RXEN_SHIFT 21 -#define UART_CTL_RXEN_MASK (1 << UART_CTL_RXEN_SHIFT) -#define UART_CTL_TXEN_SHIFT 22 -#define UART_CTL_TXEN_MASK (1 << UART_CTL_TXEN_SHIFT) -#define UART_CTL_BRGEN_SHIFT 23 -#define UART_CTL_BRGEN_MASK (1 << UART_CTL_BRGEN_SHIFT) - -/* UART Baudword register */ -#define UART_BAUD_REG 0x4 - -/* UART FIFO Config register */ -#define UART_FIFO_CFG_REG 0x8 -#define UART_FIFO_CFG_RX_SHIFT 8 -#define UART_FIFO_CFG_RX_MASK (0xf << UART_FIFO_CFG_RX_SHIFT) -#define UART_FIFO_CFG_RX_4 (0x4 << UART_FIFO_CFG_RX_SHIFT) -#define UART_FIFO_CFG_TX_SHIFT 12 -#define UART_FIFO_CFG_TX_MASK (0xf << UART_FIFO_CFG_TX_SHIFT) -#define UART_FIFO_CFG_TX_4 (0x4 << UART_FIFO_CFG_TX_SHIFT) - -/* UART Interrupt register */ -#define UART_IR_REG 0x10 -#define UART_IR_STAT(x) (1 << (x)) -#define UART_IR_TXEMPTY 5 -#define UART_IR_RXOVER 7 -#define UART_IR_RXNOTEMPTY 11 - -/* UART FIFO register */ -#define UART_FIFO_REG 0x14 -#define UART_FIFO_VALID_MASK 0xff -#define UART_FIFO_FRAMEERR_SHIFT 8 -#define UART_FIFO_FRAMEERR_MASK (1 << UART_FIFO_FRAMEERR_SHIFT) -#define UART_FIFO_PARERR_SHIFT 9 -#define UART_FIFO_PARERR_MASK (1 << UART_FIFO_PARERR_SHIFT) -#define UART_FIFO_BRKDET_SHIFT 10 -#define UART_FIFO_BRKDET_MASK (1 << UART_FIFO_BRKDET_SHIFT) -#define UART_FIFO_ANYERR_MASK (UART_FIFO_FRAMEERR_MASK | \ - UART_FIFO_PARERR_MASK | \ - UART_FIFO_BRKDET_MASK) - -struct bcm6858_serial_priv { - void __iomem *base; - ulong uartclk; -}; - -/* enable rx & tx operation on uart */ -static void bcm6858_serial_enable(void __iomem *base) -{ - setbits_le32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); -} - -/* disable rx & tx operation on uart */ -static void bcm6858_serial_disable(void __iomem *base) -{ - clrbits_le32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | - UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); -} - -/* clear all unread data in rx fifo and unsent data in tx fifo */ -static void bcm6858_serial_flush(void __iomem *base) -{ - /* empty rx and tx fifo */ - setbits_le32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK | - UART_CTL_RSTTXFIFO_MASK); - - /* read any pending char to make sure all irq status are cleared */ - readl(base + UART_FIFO_REG); -} - -static int bcm6858_serial_init(void __iomem *base, ulong clk, u32 baudrate) -{ - u32 val; - - /* mask all irq and flush port */ - bcm6858_serial_disable(base); - bcm6858_serial_flush(base); - - /* set uart control config */ - clrsetbits_le32(base + UART_CTL_REG, - /* clear rx timeout */ - UART_CTL_RXTIMEOUT_MASK | - /* clear stop bits */ - UART_CTL_STOPBITS_MASK | - /* clear bits per symbol */ - UART_CTL_BITSPERSYM_MASK | - /* clear xmit break */ - UART_CTL_XMITBRK_MASK | - /* clear reserved bit */ - UART_CTL_RSVD_MASK | - /* disable parity */ - UART_CTL_RXPAREN_MASK | - UART_CTL_TXPAREN_MASK | - /* disable loopback */ - UART_CTL_LOOPBACK_MASK, - /* set timeout to 5 */ - UART_CTL_RXTIMEOUT_5 | - /* set 8 bits/symbol */ - UART_CTL_BITSPERSYM_8 | - /* set 1 stop bit */ - UART_CTL_STOPBITS_1 | - /* set parity to even */ - UART_CTL_RXPAREVEN_MASK | - UART_CTL_TXPAREVEN_MASK); - - /* set uart fifo config */ - clrsetbits_le32(base + UART_FIFO_CFG_REG, - /* clear fifo config */ - UART_FIFO_CFG_RX_MASK | - UART_FIFO_CFG_TX_MASK, - /* set fifo config to 4 */ - UART_FIFO_CFG_RX_4 | - UART_FIFO_CFG_TX_4); - - /* set baud rate */ - val = ((clk / baudrate) >> 4); - if (val & 0x1) - val = (val >> 1); - else - val = (val >> 1) - 1; - writel(val, base + UART_BAUD_REG); - - /* clear interrupts */ - writel(0, base + UART_IR_REG); - - /* enable uart */ - bcm6858_serial_enable(base); - - return 0; -} - -static int bcm6858_serial_pending(struct udevice *dev, bool input) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - u32 val = readl(priv->base + UART_IR_REG); - - if (input) - return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)); - else - return !(val & UART_IR_STAT(UART_IR_TXEMPTY)); -} - -static int bcm6858_serial_setbrg(struct udevice *dev, int baudrate) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - - return bcm6858_serial_init(priv->base, priv->uartclk, baudrate); -} - -static int bcm6858_serial_putc(struct udevice *dev, const char ch) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - u32 val; - - val = readl(priv->base + UART_IR_REG); - if (!(val & UART_IR_STAT(UART_IR_TXEMPTY))) - return -EAGAIN; - - writel(ch, priv->base + UART_FIFO_REG); - - return 0; -} - -static int bcm6858_serial_getc(struct udevice *dev) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - u32 val; - - val = readl(priv->base + UART_IR_REG); - if (val & UART_IR_STAT(UART_IR_RXOVER)) - setbits_le32(priv->base + UART_CTL_REG, - UART_CTL_RSTRXFIFO_MASK); - - if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY))) - return -EAGAIN; - - val = readl(priv->base + UART_FIFO_REG); - if (val & UART_FIFO_ANYERR_MASK) - return -EAGAIN; - - return val & UART_FIFO_VALID_MASK; -} - -static int bcm6858_serial_probe(struct udevice *dev) -{ - struct bcm6858_serial_priv *priv = dev_get_priv(dev); - struct clk clk; - int ret; - - /* get address */ - priv->base = dev_remap_addr(dev); - if (!priv->base) - return -EINVAL; - - /* get clock rate */ - ret = clk_get_by_index(dev, 0, &clk); - if (ret < 0) - return ret; - priv->uartclk = clk_get_rate(&clk); - clk_free(&clk); - - /* initialize serial */ - return bcm6858_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE); -} - -static const struct dm_serial_ops bcm6858_serial_ops = { - .putc = bcm6858_serial_putc, - .pending = bcm6858_serial_pending, - .getc = bcm6858_serial_getc, - .setbrg = bcm6858_serial_setbrg, -}; - -static const struct udevice_id bcm6858_serial_ids[] = { - { .compatible = "brcm,bcm6858-uart" }, - { /* sentinel */ } -}; - -U_BOOT_DRIVER(bcm6858_serial) = { - .name = "bcm6858-uart", - .id = UCLASS_SERIAL, - .of_match = bcm6858_serial_ids, - .probe = bcm6858_serial_probe, - .priv_auto_alloc_size = sizeof(struct bcm6858_serial_priv), - .ops = &bcm6858_serial_ops, - .flags = DM_FLAG_PRE_RELOC, -}; - -#ifdef CONFIG_DEBUG_UART_BCM6858 -static inline void _debug_uart_init(void) -{ - void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; - - bcm6858_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); -} - -static inline void wait_xfered(void __iomem *base) -{ - do { - u32 val = readl(base + UART_IR_REG); - if (val & UART_IR_STAT(UART_IR_TXEMPTY)) - break; - } while (1); -} - -static inline void _debug_uart_putc(int ch) -{ - void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; - - wait_xfered(base); - writel(ch, base + UART_FIFO_REG); - wait_xfered(base); -} - -DEBUG_UART_FUNCS -#endif -- cgit From 043550415b09c6ffd2d9c0af28cc977bfae9f166 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 3 Dec 2018 10:52:50 +0100 Subject: pinctrl: stm32: Move gpio_dev list filling outside probe() Move gpio_dev list filling outside probe() to speed-up U-boot boot sequence execution. This list is populated only when needed. Signed-off-by: Patrice Chotard --- drivers/pinctrl/pinctrl_stm32.c | 63 +++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index bb63da3739..aa92c90b89 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -54,6 +54,39 @@ static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset) return af; } +static int stm32_populate_gpio_dev_list(struct udevice *dev) +{ + struct stm32_pinctrl_priv *priv = dev_get_priv(dev); + struct udevice *gpio_dev; + struct udevice *child; + struct stm32_gpio_bank *gpio_bank; + int ret; + + /* + * parse pin-controller sub-nodes (ie gpio bank nodes) and fill + * a list with all gpio device reference which belongs to the + * current pin-controller. This list is used to find pin_name and + * pin muxing + */ + list_for_each_entry(child, &dev->child_head, sibling_node) { + ret = uclass_get_device_by_name(UCLASS_GPIO, child->name, + &gpio_dev); + if (ret < 0) + continue; + + gpio_bank = malloc(sizeof(*gpio_bank)); + if (!gpio_bank) { + dev_err(dev, "Not enough memory\n"); + return -ENOMEM; + } + + gpio_bank->gpio_dev = gpio_dev; + list_add_tail(&gpio_bank->list, &priv->gpio_dev); + } + + return 0; +} + static int stm32_pinctrl_get_pins_count(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); @@ -67,6 +100,8 @@ static int stm32_pinctrl_get_pins_count(struct udevice *dev) if (priv->pinctrl_ngpios) return priv->pinctrl_ngpios; + if (list_empty(&priv->gpio_dev)) + stm32_populate_gpio_dev_list(dev); /* * walk through all banks to retrieve the pin-controller * pins number @@ -88,6 +123,9 @@ static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, struct gpio_dev_priv *uc_priv; int first_pin = 0; + if (list_empty(&priv->gpio_dev)) + stm32_populate_gpio_dev_list(dev); + /* look up for the bank which owns the requested pin */ list_for_each_entry(gpio_bank, &priv->gpio_dev, list) { uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev); @@ -174,35 +212,10 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, int stm32_pinctrl_probe(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); - struct udevice *gpio_dev; - struct udevice *child; - struct stm32_gpio_bank *gpio_bank; int ret; INIT_LIST_HEAD(&priv->gpio_dev); - /* - * parse pin-controller sub-nodes (ie gpio bank nodes) and fill - * a list with all gpio device reference which belongs to the - * current pin-controller. This list is used to find pin_name and - * pin muxing - */ - list_for_each_entry(child, &dev->child_head, sibling_node) { - ret = uclass_get_device_by_name(UCLASS_GPIO, child->name, - &gpio_dev); - if (ret < 0) - continue; - - gpio_bank = malloc(sizeof(*gpio_bank)); - if (!gpio_bank) { - dev_err(dev, "Not enough memory\n"); - return -ENOMEM; - } - - gpio_bank->gpio_dev = gpio_dev; - list_add_tail(&gpio_bank->list, &priv->gpio_dev); - } - /* hwspinlock property is optional, just log the error */ ret = hwspinlock_get_by_index(dev, 0, &priv->hws); if (ret) -- cgit From dbf928dd2634a682e6d549e6dd61e3f2a0e5db90 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 3 Dec 2018 10:52:51 +0100 Subject: gpio: stm32f7: Add gpio bank holes management In some STM32 SoC packages, GPIO bank has not always 16 gpios. Several cases can occur, gpio hole can be located at the beginning, middle or end of the gpio bank or a combination of these 3 configurations. For that, gpio bindings offer the gpio-ranges DT property which described the gpio bank mapping. Signed-off-by: Patrice Chotard --- drivers/gpio/stm32f7_gpio.c | 99 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index a690c437eb..55553c9477 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -20,12 +20,41 @@ #define MODE_BITS_MASK 3 #define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16)) +/* + * convert gpio offset to gpio index taking into account gpio holes + * into gpio bank + */ +int stm32_offset_to_index(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + int idx = 0; + int i; + + for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { + if (priv->gpio_range & BIT(i)) { + if (idx == offset) + return idx; + idx++; + } + } + /* shouldn't happen */ + return -EINVAL; +} + static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); @@ -37,12 +66,20 @@ static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); - writel(BSRR_BIT(offset, value), ®s->bsrr); + writel(BSRR_BIT(idx, value), ®s->bsrr); return 0; } @@ -51,16 +88,26 @@ static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; - return readl(®s->idr) & BIT(offset) ? 1 : 0; + return readl(®s->idr) & BIT(idx) ? 1 : 0; } static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx; - writel(BSRR_BIT(offset, value), ®s->bsrr); + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + writel(BSRR_BIT(idx, value), ®s->bsrr); return 0; } @@ -69,10 +116,18 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; u32 mode; + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + mode = (readl(®s->moder) & mask) >> bits_index; if (mode == STM32_GPIO_MODE_OUT) return GPIOF_OUTPUT; @@ -96,8 +151,11 @@ static int gpio_stm32_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; fdt_addr_t addr; const char *name; + int ret; + int i; addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) @@ -108,14 +166,27 @@ static int gpio_stm32_probe(struct udevice *dev) if (!name) return -EINVAL; uc_priv->bank_name = name; - uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", - STM32_GPIOS_PER_BANK); - debug("%s, addr = 0x%p, bank_name = %s\n", __func__, (u32 *)priv->regs, - uc_priv->bank_name); + + i = 0; + ret = dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, i, &args); + + while (ret != -ENOENT) { + priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1, + args.args[0]); + + uc_priv->gpio_count += args.args[2]; + + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + ++i, &args); + } + + dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", + (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, + priv->gpio_range); #ifdef CONFIG_CLK struct clk clk; - int ret; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret; -- cgit From b2f84e37e25c93c74a133ba57652291d771ab438 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 3 Dec 2018 10:52:52 +0100 Subject: gpio: stm32f7: Move STM32_GPIOS_PER_BANK into gpio.h To allow access to this define by other driver, move it into gpio.h Signed-off-by: Patrice Chotard --- drivers/gpio/stm32f7_gpio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index 55553c9477..34cdafa1e4 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -15,7 +15,6 @@ #include #include -#define STM32_GPIOS_PER_BANK 16 #define MODE_BITS(gpio_pin) (gpio_pin * 2) #define MODE_BITS_MASK 3 #define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16)) -- cgit From 8b6d45ab6457704cb9b47d7aef02a40192a43da7 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 3 Dec 2018 10:52:53 +0100 Subject: gpio: stm32f7: Remove CONFIG_CLK flag. As all STM32 SoCs supports CONFIG_CLK flag, it becomes useless in this driver, remove it. Signed-off-by: Patrice Chotard --- drivers/gpio/stm32f7_gpio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index 34cdafa1e4..f160b4e689 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -151,6 +151,7 @@ static int gpio_stm32_probe(struct udevice *dev) struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_gpio_priv *priv = dev_get_priv(dev); struct ofnode_phandle_args args; + struct clk clk; fdt_addr_t addr; const char *name; int ret; @@ -184,8 +185,6 @@ static int gpio_stm32_probe(struct udevice *dev) (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, priv->gpio_range); -#ifdef CONFIG_CLK - struct clk clk; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret; @@ -197,7 +196,6 @@ static int gpio_stm32_probe(struct udevice *dev) return ret; } debug("clock enabled for device %s\n", dev->name); -#endif return 0; } -- cgit From 530b63c2286d8c19b20a15ca57e20af6c0f08739 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 3 Dec 2018 10:52:54 +0100 Subject: pinctrl: stm32: Update stm32_pinctrl_get_gpio_dev() Due to gpio holes management, stm32_pinctrl_get_gpio_dev() must be updated. stm32_pinctrl_get_gpio_dev() returns from a given pin selectors the corresponding bank gpio device and the gpio_offset inside this gpio bank. Update also all functions which makes usage of stm32_pinctrl_get_gpio_dev. Signed-off-by: Patrice Chotard --- drivers/pinctrl/pinctrl_stm32.c | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index aa92c90b89..24affe0414 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -28,8 +28,6 @@ struct stm32_gpio_bank { #ifndef CONFIG_SPL_BUILD -#define MAX_PIN_PER_BANK 16 - static char pin_name[PINNAME_SIZE]; #define PINMUX_MODE_COUNT 5 static const char * const pinmux_mode[PINMUX_MODE_COUNT] = { @@ -116,12 +114,13 @@ static int stm32_pinctrl_get_pins_count(struct udevice *dev) } static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, - unsigned int selector) + unsigned int selector, + unsigned int *idx) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); struct stm32_gpio_bank *gpio_bank; struct gpio_dev_priv *uc_priv; - int first_pin = 0; + int pin_count = 0; if (list_empty(&priv->gpio_dev)) stm32_populate_gpio_dev_list(dev); @@ -130,11 +129,19 @@ static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, list_for_each_entry(gpio_bank, &priv->gpio_dev, list) { uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev); - if (selector < (first_pin + uc_priv->gpio_count)) - /* we found the bank */ - return gpio_bank->gpio_dev; + if (selector < (pin_count + uc_priv->gpio_count)) { + /* + * we found the bank, convert pin selector to + * gpio bank index + */ + *idx = stm32_offset_to_index(gpio_bank->gpio_dev, + selector - pin_count); + if (*idx < 0) + return NULL; - first_pin += uc_priv->gpio_count; + return gpio_bank->gpio_dev; + } + pin_count += uc_priv->gpio_count; } return NULL; @@ -145,9 +152,10 @@ static const char *stm32_pinctrl_get_pin_name(struct udevice *dev, { struct gpio_dev_priv *uc_priv; struct udevice *gpio_dev; + unsigned int gpio_idx; /* look up for the bank which owns the requested pin */ - gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector); + gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); if (!gpio_dev) { snprintf(pin_name, PINNAME_SIZE, "Error"); } else { @@ -155,7 +163,7 @@ static const char *stm32_pinctrl_get_pin_name(struct udevice *dev, snprintf(pin_name, PINNAME_SIZE, "%s%d", uc_priv->bank_name, - selector % MAX_PIN_PER_BANK); + gpio_idx); } return pin_name; @@ -168,23 +176,21 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, { struct udevice *gpio_dev; const char *label; - int gpio_pin; int mode; int af_num; + unsigned int gpio_idx; /* look up for the bank which owns the requested pin */ - gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector); + gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); if (!gpio_dev) return -ENODEV; - /* translate pin-controller pin number to gpio pin number */ - gpio_pin = selector % MAX_PIN_PER_BANK; + mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label); - mode = gpio_get_raw_function(gpio_dev, gpio_pin, &label); + dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n", + selector, gpio_idx, mode); - dev_dbg(dev, "selector = %d gpio_pin = %d mode = %d\n", - selector, gpio_pin, mode); switch (mode) { case GPIOF_UNKNOWN: @@ -194,7 +200,7 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, snprintf(buf, size, "%s", pinmux_mode[mode]); break; case GPIOF_FUNC: - af_num = stm32_pinctrl_get_af(gpio_dev, gpio_pin); + af_num = stm32_pinctrl_get_af(gpio_dev, gpio_idx); snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num); break; case GPIOF_OUTPUT: -- cgit From 5eca073ae6b105bd010b5381984f591c1d0b2c87 Mon Sep 17 00:00:00 2001 From: Felix Brack Date: Mon, 3 Dec 2018 15:12:25 +0100 Subject: serial: omap: Add code for early debugging This patch adds code missing when CONFIG_DEBUG_UART_OMAP is enabled as early debugging UART. The code is basically copied from the ns16550 driver. Signed-off-by: Felix Brack --- drivers/serial/serial_omap.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c index ee6ad9c9e5..a31d73766d 100644 --- a/drivers/serial/serial_omap.c +++ b/drivers/serial/serial_omap.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -20,6 +19,47 @@ #ifdef CONFIG_DEBUG_UART_OMAP +#ifndef CONFIG_SYS_NS16550_IER +#define CONFIG_SYS_NS16550_IER 0x00 +#endif + +#define UART_MCRVAL 0x00 +#define UART_LCRVAL UART_LCR_8N1 + +static inline void serial_out_shift(void *addr, int shift, int value) +{ +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED + outb(value, (ulong)addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN) + out_le32(addr, value); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) + out_be32(addr, value); +#elif defined(CONFIG_SYS_NS16550_MEM32) + writel(value, addr); +#elif defined(CONFIG_SYS_BIG_ENDIAN) + writeb(value, addr + (1 << shift) - 1); +#else + writeb(value, addr); +#endif +} + +static inline int serial_in_shift(void *addr, int shift) +{ +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED + return inb((ulong)addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN) + return in_le32(addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) + return in_be32(addr); +#elif defined(CONFIG_SYS_NS16550_MEM32) + return readl(addr); +#elif defined(CONFIG_SYS_BIG_ENDIAN) + return readb(addr + (1 << shift) - 1); +#else + return readb(addr); +#endif +} + #include static inline void _debug_uart_init(void) -- cgit