diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/bootcount/Kconfig | 3 | ||||
-rw-r--r-- | drivers/clk/mediatek/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpio/pca953x_gpio.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/atmel/nand-controller.c | 13 | ||||
-rw-r--r-- | drivers/net/designware.c | 30 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-at91.c | 52 | ||||
-rw-r--r-- | drivers/remoteproc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/remoteproc/Makefile | 1 | ||||
-rw-r--r-- | drivers/remoteproc/ti_k3_dsp_rproc.c | 36 | ||||
-rw-r--r-- | drivers/remoteproc/ti_k3_m4_rproc.c | 371 | ||||
-rw-r--r-- | drivers/remoteproc/ti_k3_r5f_rproc.c | 2 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 4 | ||||
-rw-r--r-- | drivers/spi/atmel-quadspi.c | 294 | ||||
-rw-r--r-- | drivers/spi/soft_spi.c | 19 | ||||
-rw-r--r-- | drivers/timer/sandbox_timer.c | 5 |
15 files changed, 754 insertions, 91 deletions
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 0080d2a165c..99b6c7534fd 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -183,6 +183,9 @@ config BOOTCOUNT_BOOTLIMIT counter being cleared. If set to 0, do not set a boot limit in the environment. +config BOOTCOUNT_ALTBOOTCMD + string "Alternative boot command when BOOTLIMIT is reached" + config SYS_BOOTCOUNT_SINGLEWORD bool "Use single word to pack boot count and magic value" depends on BOOTCOUNT_GENERIC diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index e412c92cafc..12893687b68 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -3,7 +3,6 @@ obj-$(CONFIG_ARCH_MEDIATEK) += clk-mtk.o # SoC Drivers -obj-$(CONFIG_MT8512) += clk-mt8512.o obj-$(CONFIG_TARGET_MT7623) += clk-mt7623.o obj-$(CONFIG_TARGET_MT7622) += clk-mt7622.o obj-$(CONFIG_TARGET_MT7629) += clk-mt7629.o @@ -13,5 +12,6 @@ obj-$(CONFIG_TARGET_MT7988) += clk-mt7988.o obj-$(CONFIG_TARGET_MT7987) += clk-mt7987.o obj-$(CONFIG_TARGET_MT8183) += clk-mt8183.o obj-$(CONFIG_TARGET_MT8365) += clk-mt8365.o +obj-$(CONFIG_TARGET_MT8512) += clk-mt8512.o obj-$(CONFIG_TARGET_MT8516) += clk-mt8516.o obj-$(CONFIG_TARGET_MT8518) += clk-mt8518.o diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c index e84038f312e..523ca8473a8 100644 --- a/drivers/gpio/pca953x_gpio.c +++ b/drivers/gpio/pca953x_gpio.c @@ -393,6 +393,8 @@ static const struct udevice_id pca953x_ids[] = { { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), }, { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), }, + { .compatible = "nxp,pcal6408", .data = OF_953X(8, PCA_LATCH_INT), }, + { .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), }, { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), }, { .compatible = "maxim,max7310", .data = OF_953X(8, 0), }, diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 56fbd64ef68..c90a4eab8df 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1127,7 +1127,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, const struct nand_data_interface *conf, struct atmel_smc_cs_conf *smcconf) { - u32 ncycles, totalcycles, timeps, mckperiodps; + u32 ncycles, totalcycles, timeps, mckperiodps, pulse; struct atmel_nand_controller *nc; int ret; @@ -1253,11 +1253,16 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, ATMEL_SMC_MODE_TDFMODE_OPTIMIZED; /* - * Read pulse timing directly matches tRP: + * Read pulse timing would directly match tRP, + * but some NAND flash chips (S34ML01G2 and W29N02KVxxAF) + * do not work properly in timing mode 3. + * The workaround is to extend the SMC NRD pulse to meet tREA + * timing. * - * NRD_PULSE = tRP + * NRD_PULSE = max(tRP, tREA) */ - ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps); + pulse = max(conf->timings.sdr.tRP_min, conf->timings.sdr.tREA_max); + ncycles = DIV_ROUND_UP(pulse, mckperiodps); totalcycles += ncycles; ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT, ncycles); diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 0a1fff38727..2ab03015ffa 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -33,6 +33,9 @@ #include <linux/printk.h> #include <power/regulator.h> #include "designware.h" +#if IS_ENABLED(CONFIG_ARCH_NPCM8XX) +#include <asm/arch/gmac.h> +#endif static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) { @@ -352,10 +355,35 @@ static int dw_adjust_link(struct dw_eth_dev *priv, struct eth_mac_regs *mac_p, (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); #ifdef CONFIG_ARCH_NPCM8XX + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + unsigned int start; + + /* Indirect access to VR_MII_MMD registers */ + writew((VR_MII_MMD >> 9), PCS_BA + PCS_IND_AC); + /* Set PCS_Mode to SGMII */ + clrsetbits_le16(PCS_BA + VR_MII_MMD_AN_CTRL, BIT(1), BIT(2)); + /* Set Auto Speed Mode Change */ + setbits_le16(PCS_BA + VR_MII_MMD_CTRL1, BIT(9)); + /* Indirect access to SR_MII_MMD registers */ + writew((SR_MII_MMD >> 9), PCS_BA + PCS_IND_AC); + /* Restart Auto-Negotiation */ + setbits_le16(PCS_BA + SR_MII_MMD_CTRL, BIT(9) | BIT(12)); + + printf("SGMII PHY Wait for link up \n"); + /* SGMII PHY Wait for link up */ + start = get_timer(0); + while (!(readw(PCS_BA + SR_MII_MMD_STS) & BIT(2))) { + if (get_timer(start) >= LINK_UP_TIMEOUT) { + printf("PHY link up timeout\n"); + return -ETIMEDOUT; + } + mdelay(1); + }; + } /* Pass all Multicast Frames */ setbits_le32(&mac_p->framefilt, BIT(4)); - #endif + return 0; } diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 5038cb535e3..2938635ed95 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -9,6 +9,8 @@ #include <dm.h> #include <log.h> #include <asm/global_data.h> +#include <dm/device-internal.h> +#include <dm/lists.h> #include <dm/pinctrl.h> #include <asm/hardware.h> #include <linux/bitops.h> @@ -492,21 +494,58 @@ const struct pinctrl_ops at91_pinctrl_ops = { .set_state = at91_pinctrl_set_state, }; +/** + * at91_pinctrl_bind() - Iterates through all subnodes of the pinctrl device + * in the DT and binds them to U-Boot's device model. Each subnode + * typically represents a GPIO controller or pin configuration data. + * + * @dev: Pointer to the pinctrl device + * + * Returns 0 on success or negative error on failure + */ +static int at91_pinctrl_bind(struct udevice *dev) +{ + ofnode gpio_node; + struct udevice *gpio; + int ret; + + ofnode_for_each_subnode(gpio_node, dev_ofnode(dev)) { + ret = lists_bind_fdt(dev, gpio_node, &gpio, NULL, false); + if (ret) + return ret; + } + + return 0; +} + static int at91_pinctrl_probe(struct udevice *dev) { struct at91_pinctrl_priv *priv = dev_get_priv(dev); fdt_addr_t addr_base; + struct udevice *gpio_node; int index; - for (index = 0; index < MAX_GPIO_BANKS; index++) { - addr_base = devfdt_get_addr_index(dev, index); - if (addr_base == FDT_ADDR_T_NONE) - break; + if (list_empty(&dev->child_head)) { + for (index = 0; index < MAX_GPIO_BANKS; index++) { + addr_base = devfdt_get_addr_index(dev, index); + if (addr_base == FDT_ADDR_T_NONE) + break; - priv->reg_base[index] = (struct at91_port *)addr_base; + priv->reg_base[index] = (struct at91_port *)addr_base; + } + } else { + index = 0; + list_for_each_entry(gpio_node, &dev->child_head, sibling_node) { + addr_base = dev_read_addr(gpio_node); + if (addr_base == FDT_ADDR_T_NONE) + break; + + priv->reg_base[index] = (struct at91_port *)addr_base; + index++; + } } - priv->nbanks = index; + priv->nbanks = index < MAX_GPIO_BANKS ? index : MAX_GPIO_BANKS; return 0; } @@ -524,6 +563,7 @@ U_BOOT_DRIVER(atmel_sama5d3_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = at91_pinctrl_match, .probe = at91_pinctrl_probe, + .bind = at91_pinctrl_bind, .priv_auto = sizeof(struct at91_pinctrl_priv), .ops = &at91_pinctrl_ops, }; diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 2790b168b19..3d2831a3e36 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -55,6 +55,7 @@ config REMOTEPROC_TI_K3_ARM64 depends on DM depends on ARCH_K3 depends on OF_CONTROL + default y if SYS_K3_SPL_ATF help Say y here to support TI's ARM64 processor subsystems on various TI K3 family of SoCs through the remote processor @@ -70,6 +71,16 @@ config REMOTEPROC_TI_K3_DSP on various TI K3 family of SoCs through the remote processor framework. +config REMOTEPROC_TI_K3_M4F + bool "TI K3 M4F remoteproc support" + select REMOTEPROC + depends on ARCH_K3 + depends on TI_SCI_PROTOCOL + help + Say y here to support TI's M4F remote processor subsystems + on various TI K3 family of SoCs through the remote processor + framework. + config REMOTEPROC_TI_K3_R5F bool "TI K3 R5F remoteproc support" select REMOTEPROC diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 3a092b7660e..f81e5009c5e 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o +obj-$(CONFIG_REMOTEPROC_TI_K3_M4F) += ti_k3_m4_rproc.o obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o obj-$(CONFIG_REMOTEPROC_TI_PRU) += pru_rproc.o diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c index e90f75a188c..5a7d6377283 100644 --- a/drivers/remoteproc/ti_k3_dsp_rproc.c +++ b/drivers/remoteproc/ti_k3_dsp_rproc.c @@ -15,6 +15,7 @@ #include <clk.h> #include <reset.h> #include <asm/io.h> +#include <asm/system.h> #include <power-domain.h> #include <dm/device_compat.h> #include <linux/err.h> @@ -56,7 +57,9 @@ struct k3_dsp_boot_data { * @data: Pointer to DSP specific boot data structure * @mem: Array of available memories * @num_mem: Number of available memories - * @in_use: flag to tell if the core is already in use. + * @cached_addr: Cached memory address + * @cached_size: Cached memory size + * @in_use: flag to tell if the core is already in use. */ struct k3_dsp_privdata { struct reset_ctl dsp_rst; @@ -64,6 +67,8 @@ struct k3_dsp_privdata { struct k3_dsp_boot_data *data; struct k3_dsp_mem *mem; int num_mems; + void __iomem *cached_addr; + size_t cached_size; bool in_use; }; @@ -158,6 +163,13 @@ static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size) goto unprepare; } + if (dsp->cached_addr && IS_ENABLED(CONFIG_SYS_DISABLE_DCACHE_OPS)) { + dev_dbg(dev, "final flush 0x%lx to 0x%lx\n", + (ulong)dsp->cached_addr, dsp->cached_size); + __asm_invalidate_dcache_range((u64)dsp->cached_addr, + (u64)dsp->cached_addr + (u64)dsp->cached_size); + } + boot_vector = rproc_elf_get_boot_addr(dev, addr); if (boot_vector & (data->boot_align_addr - 1)) { ret = -EINVAL; @@ -253,7 +265,6 @@ static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len) { struct k3_dsp_privdata *dsp = dev_get_priv(dev); phys_addr_t bus_addr, dev_addr; - void __iomem *va = NULL; size_t size; u32 offset; int i; @@ -263,6 +274,16 @@ static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len) if (len <= 0) return NULL; + if (dsp->cached_addr && IS_ENABLED(CONFIG_SYS_DISABLE_DCACHE_OPS)) { + dev_dbg(dev, "flush 0x%lx to 0x%lx\n", (ulong)dsp->cached_addr, + dsp->cached_size); + __asm_invalidate_dcache_range((u64)dsp->cached_addr, + (u64)dsp->cached_addr + (u64)dsp->cached_size); + } + + dsp->cached_size = len; + dsp->cached_addr = NULL; + for (i = 0; i < dsp->num_mems; i++) { bus_addr = dsp->mem[i].bus_addr; dev_addr = dsp->mem[i].dev_addr; @@ -270,19 +291,20 @@ static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len) if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { offset = da - dev_addr; - va = dsp->mem[i].cpu_addr + offset; - return (__force void *)va; + dsp->cached_addr = dsp->mem[i].cpu_addr + offset; } if (da >= bus_addr && (da + len) <= (bus_addr + size)) { offset = da - bus_addr; - va = dsp->mem[i].cpu_addr + offset; - return (__force void *)va; + dsp->cached_addr = dsp->mem[i].cpu_addr + offset; } } /* Assume it is DDR region and return da */ - return map_physmem(da, len, MAP_NOCACHE); + if (!dsp->cached_addr) + dsp->cached_addr = map_physmem(da, len, MAP_NOCACHE); + + return dsp->cached_addr; } static const struct dm_rproc_ops k3_dsp_ops = { diff --git a/drivers/remoteproc/ti_k3_m4_rproc.c b/drivers/remoteproc/ti_k3_m4_rproc.c new file mode 100644 index 00000000000..31b9de71579 --- /dev/null +++ b/drivers/remoteproc/ti_k3_m4_rproc.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Texas Instruments' K3 M4 Remoteproc driver + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + * Hari Nagalla <hnagalla@ti.com> + */ + +#include <dm.h> +#include <log.h> +#include <malloc.h> +#include <remoteproc.h> +#include <errno.h> +#include <clk.h> +#include <reset.h> +#include <asm/io.h> +#include <power-domain.h> +#include <dm/device_compat.h> +#include <linux/err.h> +#include <linux/sizes.h> +#include <linux/soc/ti/ti_sci_protocol.h> +#include "ti_sci_proc.h" +#include <mach/security.h> + +/** + * struct k3_m4_mem - internal memory structure + * @cpu_addr: MPU virtual address of the memory region + * @bus_addr: Bus address used to access the memory region + * @dev_addr: Device address from remoteproc view + * @size: Size of the memory region + */ +struct k3_m4_mem { + void __iomem *cpu_addr; + phys_addr_t bus_addr; + phys_addr_t dev_addr; + size_t size; +}; + +/** + * struct k3_m4_mem_data - memory definitions for m4 remote core + * @name: name for this memory entry + * @dev_addr: device address for the memory entry + */ +struct k3_m4_mem_data { + const char *name; + const u32 dev_addr; +}; + +/** + * struct k3_m4_boot_data - internal data structure used for boot + * @boot_align_addr: Boot vector address alignment granularity + */ +struct k3_m4_boot_data { + u32 boot_align_addr; +}; + +/** + * struct k3_m4_privdata - Structure representing Remote processor data. + * @m4_rst: m4 rproc reset control data + * @tsp: Pointer to TISCI proc contrl handle + * @data: Pointer to DSP specific boot data structure + * @mem: Array of available memories + * @num_mem: Number of available memories + */ +struct k3_m4_privdata { + struct reset_ctl m4_rst; + struct ti_sci_proc tsp; + struct k3_m4_boot_data *data; + struct k3_m4_mem *mem; + int num_mems; +}; + +/* + * The M4 cores have a local reset that affects only the CPU, and a + * generic module reset that powers on the device and allows the M4 internal + * memories to be accessed while the local reset is asserted. This function is + * used to release the global reset on M4F to allow loading into the M4F + * internal RAMs. This helper function is invoked in k3_m4_load() before any + * actual firmware loading happens and is undone only in k3_m4_stop(). The local + * reset cannot be released on M4 cores until after the firmware images are loaded. + */ +static int k3_m4_prepare(struct udevice *dev) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + int ret; + + ret = ti_sci_proc_power_domain_on(&m4->tsp); + if (ret) + dev_err(dev, "cannot enable internal RAM loading, ret = %d\n", + ret); + + return ret; +} + +/* + * This function is the counterpart to k3_m4_prepare() and is used to assert + * the global reset on M4 cores. This completes the second step of powering + * down the M4 cores. The cores themselves are halted through the local reset + * in first step. This function is invoked in k3_m4_stop() after the local + * reset is asserted. + */ +static int k3_m4_unprepare(struct udevice *dev) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + + return ti_sci_proc_power_domain_off(&m4->tsp); +} + +/** + * k3_m4_load() - Load up the Remote processor image + * @dev: rproc device pointer + * @addr: Address at which image is available + * @size: size of the image + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int k3_m4_load(struct udevice *dev, ulong addr, ulong size) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + void *image_addr = (void *)addr; + int ret; + + ret = ti_sci_proc_request(&m4->tsp); + if (ret) + return ret; + + ret = k3_m4_prepare(dev); + if (ret) { + dev_err(dev, "Prepare failed for core %d\n", + m4->tsp.proc_id); + goto proc_release; + } + + ti_secure_image_post_process(&image_addr, &size); + + ret = rproc_elf_load_image(dev, addr, size); + if (ret < 0) { + dev_err(dev, "Loading elf failed %d\n", ret); + goto unprepare; + } + +unprepare: + if (ret) + k3_m4_unprepare(dev); +proc_release: + ti_sci_proc_release(&m4->tsp); + return ret; +} + +/** + * k3_m4_start() - Start the remote processor + * @dev: rproc device pointer + * + * Return: 0 if all went ok, else return appropriate error + */ +static int k3_m4_start(struct udevice *dev) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + int ret; + + ret = ti_sci_proc_request(&m4->tsp); + if (ret) + return ret; + + ret = reset_deassert(&m4->m4_rst); + + ti_sci_proc_release(&m4->tsp); + + return ret; +} + +static int k3_m4_stop(struct udevice *dev) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + + ti_sci_proc_request(&m4->tsp); + reset_assert(&m4->m4_rst); + k3_m4_unprepare(dev); + ti_sci_proc_release(&m4->tsp); + + return 0; +} + +static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + phys_addr_t bus_addr, dev_addr; + void __iomem *va = NULL; + size_t size; + u32 offset; + int i; + + if (len <= 0) + return NULL; + + for (i = 0; i < m4->num_mems; i++) { + bus_addr = m4->mem[i].bus_addr; + dev_addr = m4->mem[i].dev_addr; + size = m4->mem[i].size; + + if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { + offset = da - dev_addr; + va = m4->mem[i].cpu_addr + offset; + return (__force void *)va; + } + + if (da >= bus_addr && (da + len) <= (bus_addr + size)) { + offset = da - bus_addr; + va = m4->mem[i].cpu_addr + offset; + return (__force void *)va; + } + } + + /* Assume it is DDR region and return da */ + return map_physmem(da, len, MAP_NOCACHE); +} + +static const struct dm_rproc_ops k3_m4_ops = { + .load = k3_m4_load, + .start = k3_m4_start, + .stop = k3_m4_stop, + .device_to_virt = k3_m4_da_to_va, +}; + +static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp) +{ + u32 ids[2]; + int ret; + + tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci"); + if (IS_ERR(tsp->sci)) { + dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci)); + return PTR_ERR(tsp->sci); + } + + ret = dev_read_u32_array(dev, "ti,sci-proc-ids", ids, 2); + if (ret) { + dev_err(dev, "Proc IDs not populated %d\n", ret); + return ret; + } + + tsp->ops = &tsp->sci->ops.proc_ops; + tsp->proc_id = ids[0]; + tsp->host_id = ids[1]; + tsp->dev_id = dev_read_u32_default(dev, "ti,sci-dev-id", + TI_SCI_RESOURCE_NULL); + if (tsp->dev_id == TI_SCI_RESOURCE_NULL) { + dev_err(dev, "Device ID not populated %d\n", ret); + return -ENODEV; + } + + return 0; +} + +static const struct k3_m4_mem_data am6_m4_mems[] = { + { .name = "iram", .dev_addr = 0x0 }, + { .name = "dram", .dev_addr = 0x30000 }, +}; + +static int k3_m4_of_get_memories(struct udevice *dev) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + int i; + + m4->num_mems = ARRAY_SIZE(am6_m4_mems); + m4->mem = calloc(m4->num_mems, sizeof(*m4->mem)); + if (!m4->mem) + return -ENOMEM; + + for (i = 0; i < m4->num_mems; i++) { + m4->mem[i].bus_addr = dev_read_addr_size_name(dev, + am6_m4_mems[i].name, + (fdt_addr_t *)&m4->mem[i].size); + if (m4->mem[i].bus_addr == FDT_ADDR_T_NONE) { + dev_err(dev, "%s bus address not found\n", + am6_m4_mems[i].name); + return -EINVAL; + } + m4->mem[i].cpu_addr = map_physmem(m4->mem[i].bus_addr, + m4->mem[i].size, + MAP_NOCACHE); + m4->mem[i].dev_addr = am6_m4_mems[i].dev_addr; + } + + return 0; +} + +/** + * k3_of_to_priv() - generate private data from device tree + * @dev: corresponding k3 m4 processor device + * @m4: pointer to driver specific private data + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int k3_m4_of_to_priv(struct udevice *dev, struct k3_m4_privdata *m4) +{ + int ret; + + ret = reset_get_by_index(dev, 0, &m4->m4_rst); + if (ret) { + dev_err(dev, "reset_get() failed: %d\n", ret); + return ret; + } + + ret = ti_sci_proc_of_to_priv(dev, &m4->tsp); + if (ret) + return ret; + + ret = k3_m4_of_get_memories(dev); + if (ret) + return ret; + + m4->data = (struct k3_m4_boot_data *)dev_get_driver_data(dev); + + return 0; +} + +/** + * k3_m4_probe() - Basic probe + * @dev: corresponding k3 remote processor device + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int k3_m4_probe(struct udevice *dev) +{ + struct k3_m4_privdata *m4; + int ret; + + m4 = dev_get_priv(dev); + ret = k3_m4_of_to_priv(dev, m4); + if (ret) + return ret; + + /* + * The M4 local resets are deasserted by default on Power-On-Reset. + * Assert the local resets to ensure the M4s don't execute bogus code + * in .load() callback when the module reset is released to support + * internal memory loading. This is needed for M4 cores. + */ + reset_assert(&m4->m4_rst); + + return 0; +} + +static int k3_m4_remove(struct udevice *dev) +{ + struct k3_m4_privdata *m4 = dev_get_priv(dev); + + free(m4->mem); + + return 0; +} + +static const struct k3_m4_boot_data m4_data = { + .boot_align_addr = SZ_1K, +}; + +static const struct udevice_id k3_m4_ids[] = { + { .compatible = "ti,am64-m4fss", .data = (ulong)&m4_data, }, + {} +}; + +U_BOOT_DRIVER(k3_m4) = { + .name = "k3_m4", + .of_match = k3_m4_ids, + .id = UCLASS_REMOTEPROC, + .ops = &k3_m4_ops, + .probe = k3_m4_probe, + .remove = k3_m4_remove, + .priv_auto = sizeof(struct k3_m4_privdata), +}; diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index d78b3fa1bbd..57268e7f8ff 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -886,6 +886,7 @@ static const struct udevice_id k3_r5f_rproc_ids[] = { { .compatible = "ti,j7200-r5f", .data = (ulong)&j7200_j721s2_data, }, { .compatible = "ti,j721s2-r5f", .data = (ulong)&j7200_j721s2_data, }, { .compatible = "ti,am62-r5f", .data = (ulong)&am62_data, }, + { .compatible = "ti,am64-r5f", .data = (ulong)&j7200_j721s2_data, }, {} }; @@ -930,6 +931,7 @@ static const struct udevice_id k3_r5fss_ids[] = { { .compatible = "ti,j7200-r5fss"}, { .compatible = "ti,j721s2-r5fss"}, { .compatible = "ti,am62-r5fss"}, + { .compatible = "ti,am64-r5fss"}, {} }; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 96ea033082b..a916b711ba8 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -85,7 +85,7 @@ config ATH79_SPI config ATMEL_QSPI bool "Atmel Quad SPI Controller" - depends on ARCH_AT91 + depends on ARCH_AT91 && SPI_MEM help Enable the Atmel Quad SPI controller in master mode. This driver does not support generic SPI. The implementation supports only the @@ -135,7 +135,7 @@ config BCMSTB_SPI config CORTINA_SFLASH bool "Cortina-Access Serial Flash controller driver" - depends on DM_SPI && SPI_MEM + depends on SPI_MEM help Enable the Cortina-Access Serial Flash controller driver. This driver can be used to access the SPI NOR/NAND flash on platforms embedding this diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 3efb661803b..8aa7a83aef4 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -10,11 +10,13 @@ */ #include <malloc.h> +#include <asm/gpio.h> #include <asm/io.h> #include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> +#include <log.h> #include <dm/device_compat.h> #include <linux/bitfield.h> #include <linux/bitops.h> @@ -258,6 +260,7 @@ struct atmel_qspi_caps { struct atmel_qspi_priv_ops; +#define MAX_CS_COUNT 2 struct atmel_qspi { void __iomem *regs; void __iomem *mem; @@ -267,6 +270,7 @@ struct atmel_qspi { struct udevice *dev; ulong bus_clk_rate; u32 mr; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; }; struct atmel_qspi_priv_ops { @@ -395,6 +399,26 @@ static void atmel_qspi_write(u32 value, struct atmel_qspi *aq, u32 offset) writel(value, aq->regs + offset); } +static int atmel_qspi_reg_sync(struct atmel_qspi *aq) +{ + u32 val; + + return readl_poll_timeout(aq->regs + QSPI_SR2, val, + !(val & QSPI_SR2_SYNCBSY), + ATMEL_QSPI_SYNC_TIMEOUT); +} + +static int atmel_qspi_update_config(struct atmel_qspi *aq) +{ + int ret; + + ret = atmel_qspi_reg_sync(aq); + if (ret) + return ret; + atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR); + return atmel_qspi_reg_sync(aq); +} + static inline bool atmel_qspi_is_compatible(const struct spi_mem_op *op, const struct atmel_qspi_mode *mode) { @@ -458,6 +482,29 @@ static bool atmel_qspi_supports_op(struct spi_slave *slave, return true; } +/* + * Switch QSPI controller between regular SPI mode or Serial Memory Mode (SMM). + */ +static int atmel_qspi_set_serial_memory_mode(struct atmel_qspi *aq, + bool enable) +{ + int ret = 0; + + /* only write if designated state differs from current state */ + if (!!(aq->mr & QSPI_MR_SMM) != enable) { + if (enable) + aq->mr |= QSPI_MR_SMM; + else + aq->mr &= ~QSPI_MR_SMM; + atmel_qspi_write(aq->mr, aq, QSPI_MR); + + if (aq->caps->has_gclk) + ret = atmel_qspi_update_config(aq); + } + + return ret; +} + static int atmel_qspi_set_cfg(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 *offset) { @@ -474,7 +521,7 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq, return mode; ifr |= atmel_qspi_modes[mode].config; - if (op->dummy.buswidth && op->dummy.nbytes) + if (op->dummy.nbytes) dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; /* @@ -529,43 +576,39 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq, if (dummy_cycles) ifr |= QSPI_IFR_NBDUM(dummy_cycles); - /* Set data enable */ - if (op->data.nbytes) + /* Set data enable and data transfer type. */ + if (op->data.nbytes) { ifr |= QSPI_IFR_DATAEN; - /* - * If the QSPI controller is set in regular SPI mode, set it in - * Serial Memory Mode (SMM). - */ - if (aq->mr != QSPI_MR_SMM) { - atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR); - aq->mr = QSPI_MR_SMM; + if (op->addr.nbytes) + ifr |= QSPI_IFR_TFRTYP_MEM; } + mode = atmel_qspi_set_serial_memory_mode(aq, true); + if (mode < 0) + return mode; + /* Clear pending interrupts */ (void)atmel_qspi_read(aq, QSPI_SR); - if (aq->caps->has_ricr) { - if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN) - ifr |= QSPI_IFR_APBTFRTYP_READ; - - /* Set QSPI Instruction Frame registers */ + /* Set QSPI Instruction Frame registers. */ + if (op->addr.nbytes && !op->data.nbytes) atmel_qspi_write(iar, aq, QSPI_IAR); + + if (aq->caps->has_ricr) { if (op->data.dir == SPI_MEM_DATA_IN) atmel_qspi_write(icr, aq, QSPI_RICR); else atmel_qspi_write(icr, aq, QSPI_WICR); - atmel_qspi_write(ifr, aq, QSPI_IFR); } else { - if (op->data.dir == SPI_MEM_DATA_OUT) + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR; - /* Set QSPI Instruction Frame registers */ - atmel_qspi_write(iar, aq, QSPI_IAR); atmel_qspi_write(icr, aq, QSPI_ICR); - atmel_qspi_write(ifr, aq, QSPI_IFR); } + atmel_qspi_write(ifr, aq, QSPI_IFR); + return 0; } @@ -597,26 +640,6 @@ static int atmel_qspi_transfer(struct atmel_qspi *aq, ATMEL_QSPI_TIMEOUT); } -static int atmel_qspi_reg_sync(struct atmel_qspi *aq) -{ - u32 val; - - return readl_poll_timeout(aq->regs + QSPI_SR2, val, - !(val & QSPI_SR2_SYNCBSY), - ATMEL_QSPI_SYNC_TIMEOUT); -} - -static int atmel_qspi_update_config(struct atmel_qspi *aq) -{ - int ret; - - ret = atmel_qspi_reg_sync(aq); - if (ret) - return ret; - atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR); - return atmel_qspi_reg_sync(aq); -} - static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 *offset) { @@ -668,17 +691,9 @@ static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq, ifr |= QSPI_IFR_TFRTYP_MEM; } - /* - * If the QSPI controller is set in regular SPI mode, set it in - * Serial Memory Mode (SMM). - */ - if (aq->mr != QSPI_MR_SMM) { - atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR); - ret = atmel_qspi_update_config(aq); - if (ret) - return ret; - aq->mr = QSPI_MR_SMM; - } + ret = atmel_qspi_set_serial_memory_mode(aq, true); + if (ret < 0) + return ret; /* Clear pending interrupts */ (void)atmel_qspi_read(aq, QSPI_SR); @@ -902,11 +917,10 @@ static int atmel_qspi_sama7g5_set_speed(struct udevice *bus, uint hz) } /* Set the QSPI controller by default in Serial Memory Mode */ - atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR); - ret = atmel_qspi_update_config(aq); - if (ret) + aq->mr |= QSPI_MR_DQSDLYEN; + ret = atmel_qspi_set_serial_memory_mode(aq, true); + if (ret < 0) return ret; - aq->mr = QSPI_MR_SMM; /* Enable the QSPI controller. */ ret = atmel_qspi_reg_sync(aq); @@ -930,6 +944,135 @@ static int atmel_qspi_sama7g5_set_speed(struct udevice *bus, uint hz) return ret; } +static int atmel_qspi_claim_bus(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct atmel_qspi *aq = dev_get_priv(bus); + int ret; + + aq->mr &= ~QSPI_MR_CSMODE_MASK; + aq->mr |= QSPI_MR_CSMODE_LASTXFER | QSPI_MR_WDRBT; + atmel_qspi_write(aq->mr, aq, QSPI_MR); + + ret = atmel_qspi_set_serial_memory_mode(aq, false); + if (ret) + return log_ret(ret); + + /* de-assert all chip selects */ + if (IS_ENABLED(CONFIG_DM_GPIO)) { + for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) { + if (dm_gpio_is_valid(&aq->cs_gpios[i])) + dm_gpio_set_value(&aq->cs_gpios[i], 0); + } + } + + atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR); + + return 0; +} + +static int atmel_qspi_release_bus(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct atmel_qspi *aq = dev_get_priv(bus); + + /* de-assert all chip selects */ + if (IS_ENABLED(CONFIG_DM_GPIO)) { + for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) { + if (dm_gpio_is_valid(&aq->cs_gpios[i])) + dm_gpio_set_value(&aq->cs_gpios[i], 0); + } + } + + atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR); + + return 0; +} + +static int atmel_qspi_set_cs(struct udevice *dev, int value) +{ + struct udevice *bus = dev_get_parent(dev); + struct atmel_qspi *aq = dev_get_priv(bus); + int cs = spi_chip_select(dev); + + if (IS_ENABLED(CONFIG_DM_GPIO)) { + if (!dm_gpio_is_valid(&aq->cs_gpios[cs])) + return log_ret(-ENOENT); + + return dm_gpio_set_value(&aq->cs_gpios[cs], value); + } else { + return -ENOENT; + } +} + +static int atmel_qspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(dev); + struct atmel_qspi *aq = dev_get_priv(bus); + unsigned int len, len_rx, len_tx; + const u8 *txp = dout; + u8 *rxp = din; + u32 reg; + int ret; + + if (bitlen == 0) + goto out; + + if (bitlen % 8) { + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + if (flags & SPI_XFER_BEGIN) { + ret = atmel_qspi_set_cs(dev, 1); + if (ret) + return log_ret(ret); + reg = atmel_qspi_read(aq, QSPI_RD); + } + + for (len_tx = 0, len_rx = 0; len_rx < len; ) { + u32 status = atmel_qspi_read(aq, QSPI_SR); + u8 value; + + if (status & QSPI_SR_OVRES) + return log_ret(-1); + + if (len_tx < len && (status & QSPI_SR_TDRE)) { + if (txp) + value = *txp++; + else + value = 0; + atmel_qspi_write(value, aq, QSPI_TD); + len_tx++; + } + + if (status & QSPI_SR_RDRF) { + value = atmel_qspi_read(aq, QSPI_RD); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + +out: + if (flags & SPI_XFER_END) { + readl_poll_timeout(aq->regs + QSPI_SR, reg, + reg & QSPI_SR_TXEMPTY, + ATMEL_QSPI_TIMEOUT); + + atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR); + + ret = atmel_qspi_set_cs(dev, 0); + if (ret) + return log_ret(ret); + } + + return 0; +} + static int atmel_qspi_set_speed(struct udevice *bus, uint hz) { struct atmel_qspi *aq = dev_get_priv(bus); @@ -939,6 +1082,7 @@ static int atmel_qspi_set_speed(struct udevice *bus, uint hz) return atmel_qspi_sama7g5_set_speed(bus, hz); /* Compute the QSPI baudrate */ + dev_dbg(bus, "bus_clk_rate: %lu, hz: %u\n", aq->bus_clk_rate, hz); scbr = DIV_ROUND_UP(aq->bus_clk_rate, hz); if (scbr > 0) scbr--; @@ -1046,10 +1190,6 @@ static int atmel_qspi_init(struct atmel_qspi *aq) /* Reset the QSPI controller */ atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR); - /* Set the QSPI controller by default in Serial Memory Mode */ - atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR); - aq->mr = QSPI_MR_SMM; - /* Enable the QSPI controller */ atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR); @@ -1075,7 +1215,7 @@ static int atmel_qspi_probe(struct udevice *dev) aq->caps = (struct atmel_qspi_caps *)dev_get_driver_data(dev); if (!aq->caps) { dev_err(dev, "Could not retrieve QSPI caps\n"); - return -EINVAL; + return log_ret(-EINVAL); }; if (aq->caps->has_gclk) @@ -1083,36 +1223,53 @@ static int atmel_qspi_probe(struct udevice *dev) else aq->ops = &atmel_qspi_priv_ops; + if (IS_ENABLED(CONFIG_DM_GPIO)) { + ret = gpio_request_list_by_name(dev, "cs-gpios", aq->cs_gpios, + ARRAY_SIZE(aq->cs_gpios), 0); + if (ret < 0) { + pr_err("Can't get %s gpios! Error: %d", dev->name, ret); + return log_ret(ret); + } + + for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) { + if (!dm_gpio_is_valid(&aq->cs_gpios[i])) + continue; + + dm_gpio_set_dir_flags(&aq->cs_gpios[i], + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + } + } + /* Map the registers */ ret = dev_read_resource_byname(dev, "qspi_base", &res); if (ret) { dev_err(dev, "missing registers\n"); - return ret; + return log_ret(ret); } aq->regs = devm_ioremap(dev, res.start, resource_size(&res)); if (IS_ERR(aq->regs)) - return PTR_ERR(aq->regs); + return log_ret(PTR_ERR(aq->regs)); /* Map the AHB memory */ ret = dev_read_resource_byname(dev, "qspi_mmap", &res); if (ret) { dev_err(dev, "missing AHB memory\n"); - return ret; + return log_ret(ret); } aq->mem = devm_ioremap(dev, res.start, resource_size(&res)); if (IS_ERR(aq->mem)) - return PTR_ERR(aq->mem); + return log_ret(PTR_ERR(aq->mem)); aq->mmap_size = resource_size(&res); ret = atmel_qspi_enable_clk(dev); if (ret) - return ret; + return log_ret(ret); aq->dev = dev; - return atmel_qspi_init(aq); + return log_ret(atmel_qspi_init(aq)); } static const struct spi_controller_mem_ops atmel_qspi_mem_ops = { @@ -1121,9 +1278,12 @@ static const struct spi_controller_mem_ops atmel_qspi_mem_ops = { }; static const struct dm_spi_ops atmel_qspi_ops = { + .claim_bus = atmel_qspi_claim_bus, + .release_bus = atmel_qspi_release_bus, + .xfer = atmel_qspi_xfer, + .mem_ops = &atmel_qspi_mem_ops, .set_speed = atmel_qspi_set_speed, .set_mode = atmel_qspi_set_mode, - .mem_ops = &atmel_qspi_mem_ops, }; static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {}; diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c index a8ec2f4f7b4..50bd7be5640 100644 --- a/drivers/spi/soft_spi.c +++ b/drivers/spi/soft_spi.c @@ -124,8 +124,19 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen, u8 *rxd = din; int cpha = !!(priv->mode & SPI_CPHA); int cidle = !!(priv->mode & SPI_CPOL); + int txrx = plat->flags; unsigned int j; + if (priv->mode & SPI_3WIRE) { + if (txd && rxd) + return -EINVAL; + + txrx = txd ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX; + dm_gpio_set_dir_flags(&plat->mosi, + txd ? GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE : + GPIOD_IS_IN | GPIOD_PULL_UP); + } + debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n", dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd, bitlen); @@ -160,7 +171,7 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen, */ if (cpha) soft_spi_scl(dev, !cidle); - if ((plat->flags & SPI_MASTER_NO_TX) == 0) + if ((txrx & SPI_MASTER_NO_TX) == 0) soft_spi_sda(dev, !!(tmpdout & 0x80)); udelay(plat->spi_delay_us); @@ -174,8 +185,10 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen, else soft_spi_scl(dev, cidle); tmpdin <<= 1; - if ((plat->flags & SPI_MASTER_NO_RX) == 0) - tmpdin |= dm_gpio_get_value(&plat->miso); + if ((txrx & SPI_MASTER_NO_RX) == 0) + tmpdin |= dm_gpio_get_value((priv->mode & SPI_3WIRE) ? + &plat->mosi : + &plat->miso); tmpdout <<= 1; udelay(plat->spi_delay_us); diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c index e8b54a02965..c1baf3c69ec 100644 --- a/drivers/timer/sandbox_timer.c +++ b/drivers/timer/sandbox_timer.c @@ -18,6 +18,11 @@ void timer_test_add_offset(unsigned long offset) sandbox_timer_offset += offset; } +ulong timer_test_get_offset(void) +{ + return sandbox_timer_offset; +}; + u64 notrace timer_early_get_count(void) { return os_get_nsec() / 1000 + sandbox_timer_offset * 1000; |