From patchwork Tue Feb 18 05:09:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236452 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:39:55 +0530 Subject: [PATCH v2 01/10] net: eth-uclass: eth_get_dev based on SEQ_ALIAS instead of probe order In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-2-j-keerthy@ti.com> In case of multiple eth interfaces currently eth_get_dev fetches the device based on the probe order which can be random hence try with the alias. Signed-off-by: Keerthy --- Changes in v2: * Fixed comments from Tom & Lokesh as per: https://patchwork.ozlabs.org/patch/1142697/ net/eth-uclass.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/eth-uclass.c b/net/eth-uclass.c index ed81cbd537..93855e933b 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -68,9 +68,15 @@ struct udevice *eth_get_dev(void) struct eth_uclass_priv *uc_priv; uc_priv = eth_get_uclass_priv(); - if (!uc_priv->current) - eth_errno = uclass_first_device(UCLASS_ETH, - &uc_priv->current); + + if (!uc_priv->current) { + eth_errno = uclass_get_device_by_seq(UCLASS_ETH, 0, + &uc_priv->current); + if (eth_errno || !uc_priv->current) + eth_errno = uclass_first_device(UCLASS_ETH, + &uc_priv->current); + } + return uc_priv->current; } From patchwork Tue Feb 18 05:09:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236454 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:39:56 +0530 Subject: [PATCH v2 02/10] soc: ti: pruss: add a misc driver for PRUSS in TI SoCs In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-3-j-keerthy@ti.com> The Programmable Real-Time Unit - Industrial Communication Subsystem (PRU-ICSS) is present of various TI SoCs such as AM335x or AM437x or the AM654x family. Each SoC can have one or more PRUSS instances that may or may not be identical. The PRUSS consists of dual 32-bit RISC cores called the Programmable Real-Time Units (PRUs), some shared, data and instruction memories, some internal peripheral modules, and an interrupt controller. The programmable nature of the PRUs provide flexibility to implement custom peripheral interfaces, fast real-time responses, or specialized data handling. Add support for pruss driver. Currently am654x family is supported. Signed-off-by: Keerthy --- Changes in v2: * Fixed multiple comments from Andreas w.r.t header file define guards and Kconfig help typos. drivers/soc/ti/Kconfig | 12 ++++ drivers/soc/ti/Makefile | 1 + drivers/soc/ti/pruss.c | 152 ++++++++++++++++++++++++++++++++++++++++ include/ti-pruss.h | 17 +++++ 4 files changed, 182 insertions(+) create mode 100644 drivers/soc/ti/pruss.c create mode 100644 include/ti-pruss.h diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index e4f8834448..19bce14c05 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -23,4 +23,16 @@ config TI_KEYSTONE_SERDES SerDes driver for Keystone SoC used for ethernet support on TI K2 platforms. +config TI_PRUSS + bool "Support for TI's K3 based Pruss driver" + depends on DM + depends on ARCH_K3 + depends on OF_CONTROL + depends on SYSCON + help + Support for TI PRU-ICSSG subsystem. + + Currently supported on AM65xx SoCs. Say Y here to support the + Programmable Realtime Unit (PRU). + endif # SOC_TI diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile index 4ec04ee125..34f80aad29 100644 --- a/drivers/soc/ti/Makefile +++ b/drivers/soc/ti/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_TI_K3_NAVSS_RINGACC) += k3-navss-ringacc.o obj-$(CONFIG_TI_KEYSTONE_SERDES) += keystone_serdes.o +obj-$(CONFIG_TI_PRUSS) += pruss.o diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c new file mode 100644 index 0000000000..059ae11805 --- /dev/null +++ b/drivers/soc/ti/pruss.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PRU-ICSS platform driver for various TI SoCs + * + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * Keerthy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PRUSS_CFG_IEPCLK 0x30 +#define ICSSG_CFG_CORE_SYNC 0x3c + +#define ICSSG_TASK_MGR_OFFSET 0x2a000 + +/* PRUSS_IEPCLK register bits */ +#define PRUSS_IEPCLK_IEP_OCP_CLK_EN BIT(0) + +/* ICSSG CORE_SYNC register bits */ +#define ICSSG_CORE_VBUSP_SYNC_EN BIT(0) + +/** + * enum pruss_mem - PRUSS memory range identifiers + */ +enum pruss_mem { + PRUSS_MEM_DRAM0 = 0, + PRUSS_MEM_DRAM1, + PRUSS_MEM_SHRD_RAM2, + PRUSS_MEM_MAX, +}; + +/* + * pruss_request_tm_region() - Request pruss for task manager region + * @dev: corresponding k3 device + * @loc: the task manager physical address + * + * Return: 0 if all goes good, else appropriate error message. + */ +int pruss_request_tm_region(struct udevice *dev, phys_addr_t *loc) +{ + struct pruss *priv; + + priv = dev_get_priv(dev); + if (!priv || !priv->pruss_dram0) + return -EINVAL; + + *loc = priv->pruss_dram0 + ICSSG_TASK_MGR_OFFSET; + + return 0; +} + +/* + * pruss_request_shrmem_region() - Request pruss for shared memory region + * @dev: corresponding k3 device + * @loc: the shared memory physical address + * + * Return: 0 if all goes good, else appropriate error message. + */ +int pruss_request_shrmem_region(struct udevice *dev, phys_addr_t *loc) +{ + struct pruss *priv; + + priv = dev_get_priv(dev); + if (!priv || !priv->pruss_shrdram2) + return -EINVAL; + + *loc = priv->pruss_shrdram2; + + return 0; +} + +/** + * pruss_probe() - Basic probe + * @dev: corresponding k3 device + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int pruss_probe(struct udevice *dev) +{ + struct pruss *priv; + int ret, idx; + ofnode sub_node, node, memories; + struct regmap *regmap_cfg; + struct udevice *syscon; + + priv = dev_get_priv(dev); + node = dev_ofnode(dev); + sub_node = ofnode_find_subnode(node, "cfg"); + memories = ofnode_find_subnode(node, "memories"); + + idx = ofnode_stringlist_search(memories, "reg-names", "dram0"); + priv->pruss_dram0 = ofnode_get_addr_size_index(memories, idx, + (u64 *)&priv->pruss_dram0sz); + idx = ofnode_stringlist_search(memories, "reg-names", "dram1"); + priv->pruss_dram1 = ofnode_get_addr_size_index(memories, idx, + (u64 *)&priv->pruss_dram1sz); + idx = ofnode_stringlist_search(memories, "reg-names", "shrdram2"); + priv->pruss_shrdram2 = ofnode_get_addr_size_index(memories, idx, + (u64 *)&priv->pruss_shrdram2sz); + + ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, sub_node, + &syscon); + + regmap_cfg = syscon_get_regmap(syscon); + + /* + * The CORE block uses two multiplexers to allow software to + * select one of three source clocks (ICSSGn_CORE_CLK, ICSSGn_ICLK or + * ICSSGn_IEP_CLK) for the final clock source of the CORE block. + * The user needs to configure ICSSG_CORE_SYNC_REG[0] CORE_VBUSP_SYNC_EN + * bit & ICSSG_IEPCLK_REG[0] IEP_OCP_CLK_EN bit in order to select the + * clock source to the CORE block. + */ + ret = regmap_update_bits(regmap_cfg, ICSSG_CFG_CORE_SYNC, + ICSSG_CORE_VBUSP_SYNC_EN, + ICSSG_CORE_VBUSP_SYNC_EN); + if (ret) + return ret; + ret = regmap_update_bits(regmap_cfg, PRUSS_CFG_IEPCLK, + PRUSS_IEPCLK_IEP_OCP_CLK_EN, + PRUSS_IEPCLK_IEP_OCP_CLK_EN); + if (ret) + return ret; + + dev_dbg(dev, "pruss successfully probed %s\n", dev->name); + + return 0; +} + +static const struct udevice_id pruss_ids[] = { + { .compatible = "ti,am654-icssg" }, + {} +}; + +U_BOOT_DRIVER(pruss) = { + .name = "pruss", + .of_match = pruss_ids, + .id = UCLASS_MISC, + .probe = pruss_probe, + .priv_auto_alloc_size = sizeof(struct pruss), +}; diff --git a/include/ti-pruss.h b/include/ti-pruss.h new file mode 100644 index 0000000000..dd36152578 --- /dev/null +++ b/include/ti-pruss.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef __TI_PRUSS_H_ +#define __TI_PRUSS_H_ + +struct pruss { + phys_addr_t pruss_dram0; + phys_addr_t pruss_dram1; + phys_addr_t pruss_shrdram2; + phys_size_t pruss_dram0sz; + phys_size_t pruss_dram1sz; + phys_size_t pruss_shrdram2sz; +}; + +int pruss_request_shrmem_region(struct udevice *dev, phys_addr_t *loc); +int pruss_request_tm_region(struct udevice *dev, phys_addr_t *loc); +#endif /* __TI_PRUSS_H_ */ From patchwork Tue Feb 18 05:09:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236453 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:39:57 +0530 Subject: [PATCH v2 03/10] remoteproc: pruss: add PRU remoteproc driver In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-4-j-keerthy@ti.com> The Programmable Real-Time Unit Subsystem (PRUSS) consists of dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs) for program execution. This patch adds a remoteproc platform driver for managing the individual PRU RISC cores life cycle. The driver currently supports the AM65xx SoC Signed-off-by: Keerthy --- drivers/remoteproc/Kconfig | 11 + drivers/remoteproc/Makefile | 1 + drivers/remoteproc/pru_rproc.c | 405 +++++++++++++++++++++++++++++++++ 3 files changed, 417 insertions(+) create mode 100644 drivers/remoteproc/pru_rproc.c diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 7c2e4804b5..24e536463b 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -81,4 +81,15 @@ config REMOTEPROC_TI_POWER help Say 'y' here to add support for TI power processors such as those found on certain TI keystone and OMAP generation SoCs. + +config REMOTEPROC_TI_PRU + bool "Support for TI's K3 based PRU remoteproc driver" + select REMOTEPROC + depends on DM + depends on TI_PRUSS + depends on ARCH_K3 + depends on OF_CONTROL + help + Say 'y' here to add support for TI' K3 remoteproc driver. + endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 69ae7bd1e8..f0e83451d6 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -14,3 +14,4 @@ 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_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/pru_rproc.c b/drivers/remoteproc/pru_rproc.c new file mode 100644 index 0000000000..832cffb1a0 --- /dev/null +++ b/drivers/remoteproc/pru_rproc.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PRU-RTU remoteproc driver for various SoCs + * + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * Keerthy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PRU_ICSS_PRU_CTRL registers */ +#define PRU_CTRL_CTRL 0x0000 +#define PRU_CTRL_STS 0x0004 +#define PRU_CTRL_WAKEUP_EN 0x0008 +#define PRU_CTRL_CYCLE 0x000C +#define PRU_CTRL_STALL 0x0010 +#define PRU_CTRL_CTBIR0 0x0020 +#define PRU_CTRL_CTBIR1 0x0024 +#define PRU_CTRL_CTPPR0 0x0028 +#define PRU_CTRL_CTPPR1 0x002C + +/* CTRL register bit-fields */ +#define CTRL_CTRL_SOFT_RST_N BIT(0) +#define CTRL_CTRL_EN BIT(1) +#define CTRL_CTRL_SLEEPING BIT(2) +#define CTRL_CTRL_CTR_EN BIT(3) +#define CTRL_CTRL_SINGLE_STEP BIT(8) +#define CTRL_CTRL_RUNSTATE BIT(15) + +#define RPROC_FLAGS_SHIFT 16 +#define RPROC_FLAGS_NONE 0 +#define RPROC_FLAGS_ELF_PHDR BIT(0 + RPROC_FLAGS_SHIFT) +#define RPROC_FLAGS_ELF_SHDR BIT(1 + RPROC_FLAGS_SHIFT) + +/** + * enum pru_mem - PRU core memory range identifiers + */ +enum pru_mem { + PRU_MEM_IRAM = 0, + PRU_MEM_CTRL, + PRU_MEM_DEBUG, + PRU_MEM_MAX, +}; + +struct pru_privdata { + phys_addr_t pru_iram; + phys_addr_t pru_ctrl; + phys_addr_t pru_debug; + fdt_size_t pru_iramsz; + fdt_size_t pru_ctrlsz; + fdt_size_t pru_debugsz; + const char *fw_name; + u32 iram_da; + u32 pdram_da; + u32 sdram_da; + u32 shrdram_da; + u32 bootaddr; + int id; + struct pruss *prusspriv; +}; + +/** + * pru_start() - start the pru processor + * @dev: corresponding k3 remote processor device + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int pru_start(struct udevice *dev) +{ + struct pru_privdata *priv; + int val = 0; + + priv = dev_get_priv(dev); + + val = CTRL_CTRL_EN | ((priv->bootaddr >> 2) << 16); + writel(val, priv->pru_ctrl + PRU_CTRL_CTRL); + + return 0; +} + +/** + * pru_stop() - Stop pru processor + * @dev: corresponding k3 remote processor device + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int pru_stop(struct udevice *dev) +{ + struct pru_privdata *priv; + int val = 0; + + priv = dev_get_priv(dev); + + val = readl(priv->pru_ctrl + PRU_CTRL_CTRL); + val &= ~CTRL_CTRL_EN; + writel(val, priv->pru_ctrl + PRU_CTRL_CTRL); + + return 0; +} + +/** + * pru_init() - Initialize the remote processor + * @dev: rproc device pointer + * + * Return: 0 if all went ok, else return appropriate error + */ +static int pru_init(struct udevice *dev) +{ + return 0; +} + +/* + * Convert PRU device address (data spaces only) to kernel virtual address + * + * Each PRU has access to all data memories within the PRUSS, accessible at + * different ranges. So, look through both its primary and secondary Data + * RAMs as well as any shared Data RAM to convert a PRU device address to + * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data + * RAM1 is primary Data RAM for PRU1. + */ +static void *pru_d_da_to_pa(struct pru_privdata *priv, u32 da, int len) +{ + u32 offset; + void *pa = NULL; + phys_addr_t dram0, dram1, shrdram2; + u32 dram0sz, dram1sz, shrdram2sz; + + if (len <= 0) + return NULL; + + dram0 = priv->prusspriv->pruss_dram0; + dram1 = priv->prusspriv->pruss_dram1; + shrdram2 = priv->prusspriv->pruss_shrdram2; + dram0sz = priv->prusspriv->pruss_dram0sz; + dram1sz = priv->prusspriv->pruss_dram1sz; + shrdram2sz = priv->prusspriv->pruss_shrdram2sz; + + /* PRU1 has its local RAM addresses reversed */ + if (priv->id == 1) { + dram1 = priv->prusspriv->pruss_dram0; + dram0 = priv->prusspriv->pruss_dram1; + dram1sz = priv->prusspriv->pruss_dram0sz; + dram0sz = priv->prusspriv->pruss_dram1sz; + } + + if (da >= priv->pdram_da && da + len <= priv->pdram_da + dram0sz) { + offset = da - priv->pdram_da; + pa = (__force void *)(dram0 + offset); + } else if (da >= priv->sdram_da && + da + len <= priv->sdram_da + dram1sz) { + offset = da - priv->sdram_da; + pa = (__force void *)(dram1 + offset); + } else if (da >= priv->shrdram_da && + da + len <= priv->shrdram_da + shrdram2sz) { + offset = da - priv->shrdram_da; + pa = (__force void *)(shrdram2 + offset); + } + + return pa; +} + +/* + * Convert PRU device address (instruction space) to kernel virtual address + * + * A PRU does not have an unified address space. Each PRU has its very own + * private Instruction RAM, and its device address is identical to that of + * its primary Data RAM device address. + */ +static void *pru_i_da_to_pa(struct pru_privdata *priv, u32 da, int len) +{ + u32 offset; + void *pa = NULL; + + if (len <= 0) + return NULL; + + if (da >= priv->iram_da && + da + len <= priv->iram_da + priv->pru_iramsz) { + offset = da - priv->iram_da; + pa = (__force void *)(priv->pru_iram + offset); + } + + return pa; +} + +/* PRU-specific address translator */ +static void *pru_da_to_pa(struct pru_privdata *priv, u64 da, int len, u32 flags) +{ + void *pa; + u32 exec_flag; + + exec_flag = ((flags & RPROC_FLAGS_ELF_SHDR) ? flags & SHF_EXECINSTR : + ((flags & RPROC_FLAGS_ELF_PHDR) ? flags & PF_X : 0)); + + if (exec_flag) + pa = pru_i_da_to_pa(priv, da, len); + else + pa = pru_d_da_to_pa(priv, da, len); + + return pa; +} + +/* + * Custom memory copy implementation for ICSSG PRU/RTU Cores + * + * The ICSSG PRU/RTU cores have a memory copying issue with IRAM memories, that + * is not seen on previous generation SoCs. The data is reflected properly in + * the IRAM memories only for integer (4-byte) copies. Any unaligned copies + * result in all the other pre-existing bytes zeroed out within that 4-byte + * boundary, thereby resulting in wrong text/code in the IRAMs. Also, the + * IRAM memory port interface does not allow any 8-byte copies (as commonly + * used by ARM64 memcpy implementation) and throws an exception. The DRAM + * memory ports do not show this behavior. Use this custom copying function + * to properly load the PRU/RTU firmware images on all memories for simplicity. + * + * TODO: Improve the function to deal with additional corner cases like + * unaligned copy sizes or sub-integer trailing bytes when the need arises. + */ +static int pru_rproc_memcpy(void *dest, void *src, size_t count) +{ + const int *s = src; + int *d = dest; + int size = count / 4; + int *tmp_src = NULL; + + /* limited to 4-byte aligned addresses and copy sizes */ + if ((long)dest % 4 || count % 4) + return -EINVAL; + + /* src offsets in ELF firmware image can be non-aligned */ + if ((long)src % 4) { + tmp_src = malloc(count); + if (!tmp_src) + return -ENOMEM; + + memcpy(tmp_src, src, count); + s = tmp_src; + } + + while (size--) + *d++ = *s++; + + kfree(tmp_src); + + return 0; +} + +/** + * pru_load() - Load pru firmware + * @dev: corresponding k3 remote processor device + * @addr: Address on the RAM from which firmware is to be loaded + * @size: Size of the pru firmware in bytes + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int pru_load(struct udevice *dev, ulong addr, ulong size) +{ + struct pru_privdata *priv; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + int i, ret = 0; + + priv = dev_get_priv(dev); + + ehdr = (Elf32_Ehdr *)addr; + phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); + + /* go through the available ELF segments */ + for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + u32 da = phdr->p_paddr; + u32 memsz = phdr->p_memsz; + u32 filesz = phdr->p_filesz; + u32 offset = phdr->p_offset; + void *ptr; + + if (phdr->p_type != PT_LOAD) + continue; + + dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", + phdr->p_type, da, memsz, filesz); + + if (filesz > memsz) { + dev_dbg(dev, "bad phdr filesz 0x%x memsz 0x%x\n", + filesz, memsz); + ret = -EINVAL; + break; + } + + if (offset + filesz > size) { + dev_dbg(dev, "truncated fw: need 0x%x avail 0x%zx\n", + offset + filesz, size); + ret = -EINVAL; + break; + } + + /* grab the kernel address for this device address */ + ptr = pru_da_to_pa(priv, da, memsz, + RPROC_FLAGS_ELF_PHDR | phdr->p_flags); + if (!ptr) { + dev_dbg(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); + ret = -EINVAL; + break; + } + + /* skip the memzero logic performed by remoteproc ELF loader */ + if (!phdr->p_filesz) + continue; + + ret = pru_rproc_memcpy(ptr, + (void *)addr + phdr->p_offset, filesz); + if (ret) { + dev_dbg(dev, "PRU custom memory copy failed for da 0x%x memsz 0x%x\n", + da, memsz); + break; + } + } + + priv->bootaddr = ehdr->e_entry; + + return ret; +} + +static const struct dm_rproc_ops pru_ops = { + .init = pru_init, + .start = pru_start, + .stop = pru_stop, + .load = pru_load, +}; + +static void pru_set_id(struct pru_privdata *priv, struct udevice *dev) +{ + u32 mask2 = 0x38000; + + if (device_is_compatible(dev, "ti,am654-rtu")) + mask2 = 0x6000; + + if ((priv->pru_iram & mask2) == mask2) + priv->id = 1; + else + priv->id = 0; +} + +/** + * pru_probe() - Basic probe + * @dev: corresponding k3 remote processor device + * + * Return: 0 if all goes good, else appropriate error message. + */ +static int pru_probe(struct udevice *dev) +{ + struct pru_privdata *priv; + int lenp; + ofnode node; + + node = dev_ofnode(dev); + + priv = dev_get_priv(dev); + priv->prusspriv = dev_get_priv(dev->parent); + + priv->pru_iram = devfdt_get_addr_size_index(dev, PRU_MEM_IRAM, + &priv->pru_iramsz); + priv->pru_ctrl = devfdt_get_addr_size_index(dev, PRU_MEM_CTRL, + &priv->pru_ctrlsz); + priv->pru_debug = devfdt_get_addr_size_index(dev, PRU_MEM_DEBUG, + &priv->pru_debugsz); + + priv->fw_name = ofnode_get_property(node, "firmware-name", &lenp); + + priv->iram_da = 0; + priv->pdram_da = 0; + priv->sdram_da = 0x2000; + priv->shrdram_da = 0x10000; + + pru_set_id(priv, dev); + + return 0; +} + +static const struct udevice_id pru_ids[] = { + { .compatible = "ti,am654-pru"}, + { .compatible = "ti,am654-rtu"}, + {} +}; + +U_BOOT_DRIVER(pru) = { + .name = "pru", + .of_match = pru_ids, + .id = UCLASS_REMOTEPROC, + .ops = &pru_ops, + .probe = pru_probe, + .priv_auto_alloc_size = sizeof(struct pru_privdata), +}; From patchwork Tue Feb 18 05:09:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236457 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:39:58 +0530 Subject: [PATCH v2 04/10] net: ti: icssg-prueth: Add ICSSG ethernet driver In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-5-j-keerthy@ti.com> This is the Ethernet driver for TI SoCs with the ICSSG PRU Sub-system running EMAC firmware. This driver caters to either of the slices(pru/rtu pair) of the icssg subsystem. Following are the firmwares needed to run cores: am65x-pru0-prueth-fw.elf for pru0 of slice0 am65x-rtu0-prueth-fw.elf for rtu0 of slice0 am65x-pru1-prueth-fw.elf for pru1 of slice1 am65x-rtu1-prueth-fw.elf for rtu1 of slice1 One and exactly one of the slices is supported as the u-boot ethernet supports probing one interface at a time. Signed-off-by: Keerthy --- Changes in v2: * Added guards defines for icssg.h * returning errors which were missed in v1 * Removed unused prueth_print_buf function. * Removed usage misc_of_init and used uclass_get_device_by_ofnode in place of that. * Introduced started variable to keep track of the status of the prueth device. drivers/net/ti/Kconfig | 8 + drivers/net/ti/Makefile | 1 + drivers/net/ti/icssg-prueth.c | 652 ++++++++++++++++++++++++++++++ drivers/net/ti/icssg.h | 36 ++ drivers/net/ti/icssg_classifier.c | 396 ++++++++++++++++++ 5 files changed, 1093 insertions(+) create mode 100644 drivers/net/ti/icssg-prueth.c create mode 100644 drivers/net/ti/icssg.h create mode 100644 drivers/net/ti/icssg_classifier.c diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig index ecf642de10..1b6285709f 100644 --- a/drivers/net/ti/Kconfig +++ b/drivers/net/ti/Kconfig @@ -26,3 +26,11 @@ config TI_AM65_CPSW_NUSS help This driver supports TI K3 MCU CPSW Nuss Ethernet controller in Texas Instruments K3 AM65x SoCs. + +config TI_AM64_ICSSG_PRUETH + bool "TI Gigabit PRU Ethernet driver" + depends on ARCH_K3 + select PHYLIB + help + Support Gigabit Ethernet ports over the ICSSG PRU Subsystem + This subsystem is available starting with the AM65 platform. diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile index 8d3808bb4b..b486498909 100644 --- a/drivers/net/ti/Makefile +++ b/drivers/net/ti/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o cpsw_mdio.o +obj-$(CONFIG_TI_AM64_ICSSG_PRUETH) += icssg-prueth.o cpsw_mdio.o icssg_classifier.o diff --git a/drivers/net/ti/icssg-prueth.c b/drivers/net/ti/icssg-prueth.c new file mode 100644 index 0000000000..0a85ca3ab5 --- /dev/null +++ b/drivers/net/ti/icssg-prueth.c @@ -0,0 +1,652 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Texas Instruments PRU Ethernet Driver + * + * Copyright (C) 2020, Texas Instruments, Incorporated + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpsw_mdio.h" +#include "icssg.h" + +#define ICSS_SLICE0 0 +#define ICSS_SLICE1 1 + +#ifdef PKTSIZE_ALIGN +#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN +#else +#define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN) +#endif + +#ifdef PKTBUFSRX +#define UDMA_RX_DESC_NUM PKTBUFSRX +#else +#define UDMA_RX_DESC_NUM 4 +#endif + +enum prueth_mac { + PRUETH_MAC0 = 0, + PRUETH_MAC1, + PRUETH_NUM_MACS, +}; + +enum prueth_port { + PRUETH_PORT_HOST = 0, /* host side port */ + PRUETH_PORT_MII0, /* physical port MII 0 */ + PRUETH_PORT_MII1, /* physical port MII 1 */ +}; + +/* Config region lies in shared RAM */ +#define ICSS_CONFIG_OFFSET_SLICE0 0 +#define ICSS_CONFIG_OFFSET_SLICE1 0x8000 + +/* Firmware flags */ +#define ICSS_SET_RUN_FLAG_VLAN_ENABLE BIT(0) /* switch only */ +#define ICSS_SET_RUN_FLAG_FLOOD_UNICAST BIT(1) /* switch only */ +#define ICSS_SET_RUN_FLAG_PROMISC BIT(2) /* MAC only */ +#define ICSS_SET_RUN_FLAG_MULTICAST_PROMISC BIT(3) /* MAC only */ + +/* CTRLMMR_ICSSG_RGMII_CTRL register bits */ +#define ICSSG_CTRL_RGMII_ID_MODE BIT(24) + +/** + * enum pruss_pru_id - PRU core identifiers + */ +enum pruss_pru_id { + PRUSS_PRU0 = 0, + PRUSS_PRU1, + PRUSS_NUM_PRUS, +}; + +struct prueth { + struct udevice *dev; + struct regmap *miig_rt; + struct regmap *mii_rt; + fdt_addr_t mdio_base; + phys_addr_t pruss_shrdram2; + phys_addr_t tmaddr; + struct mii_dev *bus; + u32 port_id; + u32 sram_pa; + struct phy_device *phydev; + bool has_phy; + ofnode phy_node; + u32 phy_addr; + ofnode eth_node[PRUETH_NUM_MACS]; + struct icssg_config config[PRUSS_NUM_PRUS]; + u32 mdio_freq; + int phy_interface; + struct clk mdiofck; + struct dma dma_tx; + struct dma dma_rx; + u32 rx_next; + u32 rx_pend; + int slice; + bool started; +}; + +/** + * TX IPG Values to be set for 100M and 1G link speeds. These values are + * in ocp_clk cycles. So need change if ocp_clk is changed for a specific + * h/w design. + */ +#define MII_RT_TX_IPG_100M 0x166 +#define MII_RT_TX_IPG_1G 0x18 + +#define RGMII_CFG_OFFSET 4 + +/* Constant to choose between MII0 and MII1 */ +#define ICSS_MII0 0 +#define ICSS_MII1 1 + +/* RGMII CFG Register bits */ +#define RGMII_CFG_GIG_EN_MII0 BIT(17) +#define RGMII_CFG_GIG_EN_MII1 BIT(21) +#define RGMII_CFG_FULL_DUPLEX_MII0 BIT(18) +#define RGMII_CFG_FULL_DUPLEX_MII1 BIT(22) + +/* PRUSS_MII_RT Registers */ +#define PRUSS_MII_RT_RXCFG0 0x0 +#define PRUSS_MII_RT_RXCFG1 0x4 +#define PRUSS_MII_RT_TXCFG0 0x10 +#define PRUSS_MII_RT_TXCFG1 0x14 +#define PRUSS_MII_RT_TX_CRC0 0x20 +#define PRUSS_MII_RT_TX_CRC1 0x24 +#define PRUSS_MII_RT_TX_IPG0 0x30 +#define PRUSS_MII_RT_TX_IPG1 0x34 +#define PRUSS_MII_RT_PRS0 0x38 +#define PRUSS_MII_RT_PRS1 0x3c +#define PRUSS_MII_RT_RX_FRMS0 0x40 +#define PRUSS_MII_RT_RX_FRMS1 0x44 +#define PRUSS_MII_RT_RX_PCNT0 0x48 +#define PRUSS_MII_RT_RX_PCNT1 0x4c +#define PRUSS_MII_RT_RX_ERR0 0x50 +#define PRUSS_MII_RT_RX_ERR1 0x54 + +static inline void icssg_update_rgmii_cfg(struct regmap *miig_rt, bool gig_en, + bool full_duplex, int mii) +{ + u32 gig_en_mask, gig_val = 0, full_duplex_mask, full_duplex_val = 0; + + gig_en_mask = (mii == ICSS_MII0) ? RGMII_CFG_GIG_EN_MII0 : + RGMII_CFG_GIG_EN_MII1; + if (gig_en) + gig_val = gig_en_mask; + regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, gig_en_mask, gig_val); + + full_duplex_mask = (mii == ICSS_MII0) ? RGMII_CFG_FULL_DUPLEX_MII0 : + RGMII_CFG_FULL_DUPLEX_MII1; + if (full_duplex) + full_duplex_val = full_duplex_mask; + regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, full_duplex_mask, + full_duplex_val); +} + +static inline void icssg_update_mii_rt_cfg(struct regmap *mii_rt, int speed, + int mii) +{ + u32 ipg_reg, val; + + ipg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TX_IPG0 : + PRUSS_MII_RT_TX_IPG1; + switch (speed) { + case SPEED_1000: + val = MII_RT_TX_IPG_1G; + break; + case SPEED_100: + val = MII_RT_TX_IPG_100M; + break; + default: + /* Other links speeds not supported */ + pr_err("Unsupported link speed\n"); + return; + } + regmap_write(mii_rt, ipg_reg, val); +} + +static int icssg_phy_init(struct udevice *dev) +{ + struct prueth *priv = dev_get_priv(dev); + struct phy_device *phydev; + u32 supported = PHY_GBIT_FEATURES; + int ret; + + phydev = phy_connect(priv->bus, + priv->phy_addr, + priv->dev, + priv->phy_interface); + + if (!phydev) { + dev_err(dev, "phy_connect() failed\n"); + return -ENODEV; + } + + phydev->supported &= supported; + phydev->advertising = phydev->supported; + +#ifdef CONFIG_DM_ETH + if (ofnode_valid(priv->phy_node)) + phydev->node = priv->phy_node; +#endif + + priv->phydev = phydev; + ret = phy_config(phydev); + if (ret < 0) + pr_err("phy_config() failed: %d", ret); + + return ret; +} + +static int icssg_mdio_init(struct udevice *dev) +{ + struct prueth *prueth = dev_get_priv(dev); + + prueth->bus = cpsw_mdio_init(dev->name, prueth->mdio_base, + prueth->mdio_freq, + clk_get_rate(&prueth->mdiofck)); + if (!prueth->bus) + return -EFAULT; + + return 0; +} + +static void icssg_config_set(struct prueth *prueth) +{ + void __iomem *va; + + va = (void __iomem *)prueth->pruss_shrdram2 + prueth->slice * + ICSSG_CONFIG_OFFSET_SLICE1; + + memcpy_toio(va, &prueth->config[0], sizeof(prueth->config[0])); +} + +static int icssg_update_link(struct prueth *priv) +{ + struct phy_device *phy = priv->phydev; + bool gig_en = false, full_duplex = false; + + if (phy->link) { /* link up */ + if (phy->speed == 1000) + gig_en = true; + if (phy->duplex == 0x1) + full_duplex = true; + if (phy->speed == 100) + gig_en = false; + /* Set the RGMII cfg for gig en and full duplex */ + icssg_update_rgmii_cfg(priv->miig_rt, gig_en, full_duplex, + priv->slice); + /* update the Tx IPG based on 100M/1G speed */ + icssg_update_mii_rt_cfg(priv->mii_rt, phy->speed, priv->slice); + + printf("link up on port %d, speed %d, %s duplex\n", + priv->port_id, phy->speed, + (phy->duplex == DUPLEX_FULL) ? "full" : "half"); + } else { + printf("link down on port %d\n", priv->port_id); + } + + return phy->link; +} + +static int prueth_start(struct udevice *dev) +{ + struct prueth *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev->platdata; + int ret, i; + char tx_chn_name[16]; + char rx_chn_name[16]; + + icssg_class_set_mac_addr(priv->miig_rt, priv->slice, + (u8 *)pdata->enetaddr); + icssg_class_default(priv->miig_rt, priv->slice); + + /* To differentiate channels for SLICE0 vs SLICE1 */ + snprintf(tx_chn_name, sizeof(tx_chn_name), "tx%d-0", priv->slice); + snprintf(rx_chn_name, sizeof(rx_chn_name), "rx%d", priv->slice); + + ret = dma_get_by_name(dev, tx_chn_name, &priv->dma_tx); + if (ret) { + dev_err(dev, "TX dma get failed %d\n", ret); + goto tx_fail; + } + + ret = dma_get_by_name(dev, rx_chn_name, &priv->dma_rx); + if (ret) { + dev_err(dev, "RX dma get failed %d\n", ret); + goto tx_fail; + } + + for (i = 0; i < UDMA_RX_DESC_NUM; i++) { + ret = dma_prepare_rcv_buf(&priv->dma_rx, + net_rx_packets[i], + UDMA_RX_BUF_SIZE); + if (ret) + dev_err(dev, "RX dma add buf failed %d\n", ret); + } + + ret = dma_enable(&priv->dma_tx); + if (ret) { + dev_err(dev, "TX dma_enable failed %d\n", ret); + goto tx_fail; + } + + ret = dma_enable(&priv->dma_rx); + if (ret) { + dev_err(dev, "RX dma_enable failed %d\n", ret); + goto rx_fail; + } + + ret = phy_startup(priv->phydev); + if (ret) { + dev_err(dev, "phy_startup failed\n"); + goto phy_fail; + } + + ret = icssg_update_link(priv); + if (!ret) { + ret = -ENODEV; + goto phy_shut; + } + + priv->started = true; + + return 0; + +phy_shut: + phy_shutdown(priv->phydev); +phy_fail: + dma_disable(&priv->dma_rx); + dma_free(&priv->dma_rx); +rx_fail: + dma_disable(&priv->dma_tx); + dma_free(&priv->dma_tx); + +tx_fail: + icssg_class_disable(priv->miig_rt, priv->slice); + + return ret; +} + +static int prueth_send(struct udevice *dev, void *packet, int length) +{ + struct prueth *priv = dev_get_priv(dev); + int ret; + + ret = dma_send(&priv->dma_tx, packet, length, NULL); + + return ret; +} + +static int prueth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct prueth *priv = dev_get_priv(dev); + int ret; + + /* try to receive a new packet */ + ret = dma_receive(&priv->dma_rx, (void **)packetp, NULL); + + return ret; +} + +static int prueth_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct prueth *priv = dev_get_priv(dev); + int ret = 0; + + if (length > 0) { + u32 pkt = priv->rx_next % UDMA_RX_DESC_NUM; + + dev_dbg(dev, "%s length:%d pkt:%u\n", __func__, length, pkt); + + ret = dma_prepare_rcv_buf(&priv->dma_rx, + net_rx_packets[pkt], + UDMA_RX_BUF_SIZE); + priv->rx_next++; + } + + return ret; +} + +static void prueth_stop(struct udevice *dev) +{ + struct prueth *priv = dev_get_priv(dev); + + if (!priv->started) + return; + + icssg_class_disable(priv->miig_rt, priv->slice); + + phy_shutdown(priv->phydev); + + dma_disable(&priv->dma_tx); + dma_free(&priv->dma_tx); + + dma_disable(&priv->dma_rx); + dma_free(&priv->dma_rx); + + /* Workaround for shutdown command */ + writel(0x0, priv->tmaddr + priv->slice * 0x200); + + priv->started = false; +} + +static const struct eth_ops prueth_ops = { + .start = prueth_start, + .send = prueth_send, + .recv = prueth_recv, + .free_pkt = prueth_free_pkt, + .stop = prueth_stop, +}; + +static int icssg_ofdata_parse_phy(struct udevice *dev, ofnode port_np) +{ + struct prueth *priv = dev_get_priv(dev); + struct ofnode_phandle_args out_args; + const char *phy_mode; + int ret = 0; + + phy_mode = ofnode_read_string(port_np, "phy-mode"); + if (phy_mode) { + priv->phy_interface = + phy_get_interface_by_name(phy_mode); + if (priv->phy_interface == -1) { + dev_err(dev, "Invalid PHY mode '%s'\n", + phy_mode); + ret = -EINVAL; + goto out; + } + } + + ret = ofnode_parse_phandle_with_args(port_np, "phy-handle", + NULL, 0, 0, &out_args); + if (ret) { + dev_err(dev, "can't parse phy-handle port (%d)\n", ret); + ret = 0; + } + + priv->phy_node = out_args.node; + ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr); + if (ret) + dev_err(dev, "failed to get phy_addr port (%d)\n", ret); + +out: + return ret; +} + +static int prueth_config_rgmiidelay(struct prueth *prueth, + ofnode eth_np) +{ + struct regmap *ctrl_mmr; + int ret = 0; + ofnode node; + u32 tmp[2]; + + ret = ofnode_read_u32_array(eth_np, "syscon-rgmii-delay", tmp, 2); + if (ret) { + dev_err(dev, "no syscon-rgmii-delay\n"); + return ret; + } + + node = ofnode_get_by_phandle(tmp[0]); + if (!ofnode_valid(node)) { + dev_err(dev, "can't get syscon-rgmii-delay node\n"); + return -EINVAL; + } + + ctrl_mmr = syscon_node_to_regmap(node); + if (!ctrl_mmr) { + dev_err(dev, "can't get ctrl_mmr regmap\n"); + return -EINVAL; + } + + regmap_update_bits(ctrl_mmr, tmp[1], ICSSG_CTRL_RGMII_ID_MODE, 0); + + return 0; +} + +static int prueth_probe(struct udevice *dev) +{ + struct prueth *prueth; + int ret = 0, i; + ofnode eth0_node, eth1_node, node, pruss_node, mdio_node, sram_node; + u32 phandle, err, sp; + struct udevice *prussdev; + struct icssg_config *config; + + prueth = dev_get_priv(dev); + prueth->dev = dev; + err = ofnode_read_u32(dev_ofnode(dev), "prus", &phandle); + if (err) + return err; + + node = ofnode_get_by_phandle(phandle); + if (!ofnode_valid(node)) + return -EINVAL; + + pruss_node = ofnode_get_parent(node); + ret = uclass_get_device_by_ofnode(UCLASS_MISC, pruss_node, &prussdev); + if (ret) + return ret; + + ret = pruss_request_shrmem_region(prussdev, &prueth->pruss_shrdram2); + if (ret) + return ret; + + ret = pruss_request_tm_region(prussdev, &prueth->tmaddr); + if (ret) + return ret; + + node = dev_ofnode(dev); + eth0_node = ofnode_find_subnode(node, "ethernet-mii0"); + eth1_node = ofnode_find_subnode(node, "ethernet-mii1"); + /* one node must be present and available else we fail */ + if (!ofnode_valid(eth0_node) && !ofnode_valid(eth1_node)) { + dev_err(dev, "neither ethernet-mii0 nor ethernet-mii1 node available\n"); + return -ENODEV; + } + + /* + * Exactly one node must be present as uboot ethernet framework does + * not support two interfaces in a single probe. So Device Tree should + * have exactly one of mii0 or mii1 interface. + */ + if (ofnode_valid(eth0_node) && ofnode_valid(eth1_node)) { + dev_err(dev, "Both slices cannot be supported\n"); + return -EINVAL; + } + + if (ofnode_valid(eth0_node)) { + prueth->slice = 0; + icssg_ofdata_parse_phy(dev, eth0_node); + prueth->eth_node[PRUETH_MAC0] = eth0_node; + } + + if (ofnode_valid(eth1_node)) { + prueth->slice = 1; + icssg_ofdata_parse_phy(dev, eth1_node); + prueth->eth_node[PRUETH_MAC0] = eth1_node; + } + + prueth->miig_rt = syscon_regmap_lookup_by_phandle(dev, "mii-g-rt"); + if (!prueth->miig_rt) { + dev_err(dev, "couldn't get mii-g-rt syscon regmap\n"); + return -ENODEV; + } + + prueth->mii_rt = syscon_regmap_lookup_by_phandle(dev, "mii-rt"); + if (!prueth->mii_rt) { + dev_err(dev, "couldn't get mii-rt syscon regmap\n"); + return -ENODEV; + } + + ret = clk_get_by_name(dev, "mdio_fck", &prueth->mdiofck); + if (ret) { + dev_err(dev, "failed to get clock %d\n", ret); + return ret; + } + + ret = clk_enable(&prueth->mdiofck); + if (ret) { + dev_err(dev, "clk_enable failed %d\n", ret); + return ret; + } + + ret = ofnode_read_u32(dev_ofnode(dev), "sram", &sp); + if (ret) { + dev_err(dev, "sram node fetch failed %d\n", ret); + return ret; + } + + sram_node = ofnode_get_by_phandle(sp); + if (!ofnode_valid(node)) + return -EINVAL; + + prueth->sram_pa = ofnode_get_addr(sram_node); + + if (!prueth->slice) { + ret = prueth_config_rgmiidelay(prueth, eth0_node); + if (ret) { + dev_err(dev, "prueth_config_rgmiidelay failed\n"); + return ret; + } + } else { + ret = prueth_config_rgmiidelay(prueth, eth1_node); + if (ret) { + dev_err(dev, "prueth_config_rgmiidelay failed\n"); + return ret; + } + } + + mdio_node = ofnode_find_subnode(pruss_node, "mdio"); + prueth->mdio_base = ofnode_get_addr(mdio_node); + ofnode_read_u32(mdio_node, "bus_freq", &prueth->mdio_freq); + + ret = icssg_mdio_init(dev); + if (ret) + return ret; + + ret = icssg_phy_init(dev); + if (ret) { + dev_err(dev, "phy_init failed\n"); + goto out; + } + + /* Set Load time configuration */ + config = &prueth->config[0]; + memset(config, 0, sizeof(*config)); + config->addr_lo = cpu_to_le32(lower_32_bits(prueth->sram_pa)); + config->addr_hi = cpu_to_le32(upper_32_bits(prueth->sram_pa)); + config->num_tx_threads = 0; + config->rx_flow_id = 0; /* flow id for host port */ + + /* set buffer sizes for the pools. 0-7 are not used for dual-emac */ + for (i = 8; i < 16; i++) + config->tx_buf_sz[i] = cpu_to_le32(0x1800); + + icssg_config_set(prueth); + + return 0; +out: + cpsw_mdio_free(prueth->bus); + clk_disable(&prueth->mdiofck); + + return ret; +} + +static const struct udevice_id prueth_ids[] = { + { .compatible = "ti,am654-icssg-prueth" }, + { } +}; + +U_BOOT_DRIVER(prueth) = { + .name = "prueth", + .id = UCLASS_ETH, + .of_match = prueth_ids, + .probe = prueth_probe, + .ops = &prueth_ops, + .priv_auto_alloc_size = sizeof(struct prueth), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/net/ti/icssg.h b/drivers/net/ti/icssg.h new file mode 100644 index 0000000000..c01a9ac109 --- /dev/null +++ b/drivers/net/ti/icssg.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Texas Instruments ICSSG PRU Ethernet Switch SubSystem Driver + * + * Copyright (C) 2020, Texas Instruments, Incorporated + * + */ + +#ifndef _ICSSG_H_ +#define _ICSSG_H_ + +/* Config area lies in shared RAM */ +#define ICSSG_CONFIG_OFFSET_SLICE0 0 +#define ICSSG_CONFIG_OFFSET_SLICE1 0x8000 + +/* Load time Fiwmware Configuration */ +struct icssg_config { + __le32 status; /* Firmware status */ + __le32 addr_lo; /* MSMC Buffer pool base address low. */ + __le32 addr_hi; /* MSMC Buffer pool base address high. Must be 0 */ + __le32 tx_buf_sz[16]; /* Array of buffer pool sizes */ + __le32 num_tx_threads; /* Number of active egress threads, 1 to 4 */ + __le32 tx_rate_lim_en; /* Bitmask: Egress rate limit enable per thread */ + __le32 rx_flow_id; /* RX flow id for first rx ring */ + __le32 rx_mgr_flow_id; /* RX flow id for the first management ring */ + __le32 flags; /* TBD */ + __le32 n_burst; /* for debug */ + __le32 rtu_status; /* RTU status */ + __le32 info; /* reserved */ +} __packed; + +void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac); +void icssg_class_disable(struct regmap *miig_rt, int slice); +void icssg_class_default(struct regmap *miig_rt, int slice); +void icssg_class_promiscuous(struct regmap *miig_rt, int slice); +#endif /* _ICSSG_H_ */ diff --git a/drivers/net/ti/icssg_classifier.c b/drivers/net/ti/icssg_classifier.c new file mode 100644 index 0000000000..0cb63c2173 --- /dev/null +++ b/drivers/net/ti/icssg_classifier.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments ICSSG Ethernet Driver + * + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpsw_mdio.h" +#include "icssg.h" + +#define ICSSG_NUM_CLASSIFIERS 16 +#define ICSSG_NUM_FT1_SLOTS 8 +#define ICSSG_NUM_FT3_SLOTS 16 + +/* Filter 1 - FT1 */ +#define FT1_NUM_SLOTS 8 +#define FT1_SLOT_SIZE 0x10 /* bytes */ + +/* offsets from FT1 slot base i.e. slot 1 start */ +#define FT1_DA0 0x0 +#define FT1_DA1 0x4 +#define FT1_DA0_MASK 0x8 +#define FT1_DA1_MASK 0xc + +#define FT1_N_REG(slize, n, reg) (offs[slice].ft1_slot_base + FT1_SLOT_SIZE * (n) + (reg)) + +#define FT1_LEN_MASK GENMASK(19, 16) +#define FT1_LEN_SHIFT 16 +#define FT1_LEN(len) (((len) << FT1_LEN_SHIFT) & FT1_LEN_MASK) + +#define FT1_MATCH_SLOT(n) (GENMASK(23, 16) & (BIT(n) << 16)) + +enum ft1_cfg_type { + FT1_CFG_TYPE_DISABLED = 0, + FT1_CFG_TYPE_EQ, + FT1_CFG_TYPE_GT, + FT1_CFG_TYPE_LT, +}; + +#define FT1_CFG_SHIFT(n) (2 * (n)) +#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) + +/* Filter 3 - FT3 */ +#define FT3_NUM_SLOTS 16 +#define FT3_SLOT_SIZE 0x20 /* bytes */ + +/* offsets from FT3 slot n's base */ +#define FT3_START 0 +#define FT3_START_AUTO 0x4 +#define FT3_START_OFFSET 0x8 +#define FT3_JUMP_OFFSET 0xc +#define FT3_LEN 0x10 +#define FT3_CFG 0x14 +#define FT3_T 0x18 +#define FT3_T_MASK 0x1c + +#define FT3_N_REG(slize, n, reg) (offs[slice].ft3_slot_base + FT3_SLOT_SIZE * (n) + (reg)) + +/* offsets from rx_class n's base */ +#define RX_CLASS_AND_EN 0 +#define RX_CLASS_OR_EN 0x4 + +#define RX_CLASS_NUM_SLOTS 16 +#define RX_CLASS_EN_SIZE 0x8 /* bytes */ + +#define RX_CLASS_N_REG(slice, n, reg) (offs[slice].rx_class_base + RX_CLASS_EN_SIZE * (n) + (reg)) + +/* RX Class Gates */ +#define RX_CLASS_GATES_SIZE 0x4 /* bytes */ + +#define RX_CLASS_GATES_N_REG(slice, n) (offs[slice].rx_class_gates_base + RX_CLASS_GATES_SIZE * (n)) + +#define RX_CLASS_GATES_ALLOW_MASK BIT(6) +#define RX_CLASS_GATES_RAW_MASK BIT(5) +#define RX_CLASS_GATES_PHASE_MASK BIT(4) + +/* RX Class traffic data matching bits */ +#define RX_CLASS_FT_UC BIT(31) +#define RX_CLASS_FT_MC BIT(30) +#define RX_CLASS_FT_BC BIT(29) +#define RX_CLASS_FT_FW BIT(28) +#define RX_CLASS_FT_RCV BIT(27) +#define RX_CLASS_FT_VLAN BIT(26) +#define RX_CLASS_FT_DA_P BIT(25) +#define RX_CLASS_FT_DA_I BIT(24) +#define RX_CLASS_FT_FT1_MATCH_MASK GENMASK(23, 16) +#define RX_CLASS_FT_FT1_MATCH_SHIFT 16 +#define RX_CLASS_FT_FT3_MATCH_MASK GENMASK(15, 0) +#define RX_CLASS_FT_FT3_MATCH_SHIFT 0 + +enum rx_class_sel_type { + RX_CLASS_SEL_TYPE_OR = 0, + RX_CLASS_SEL_TYPE_AND = 1, + RX_CLASS_SEL_TYPE_OR_AND_AND = 2, + RX_CLASS_SEL_TYPE_OR_OR_AND = 3, +}; + +#define FT1_CFG_SHIFT(n) (2 * (n)) +#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) + +#define RX_CLASS_SEL_SHIFT(n) (2 * (n)) +#define RX_CLASS_SEL_MASK(n) (0x3 << RX_CLASS_SEL_SHIFT((n))) + +#define ICSSG_CFG_OFFSET 0 +#define RGMII_CFG_OFFSET 4 + +#define ICSSG_CFG_RX_L2_G_EN BIT(2) + +/* these are register offsets per PRU */ +struct miig_rt_offsets { + u32 mac0; + u32 mac1; + u32 ft1_start_len; + u32 ft1_cfg; + u32 ft1_slot_base; + u32 ft3_slot_base; + u32 ft3_p_base; + u32 ft_rx_ptr; + u32 rx_class_base; + u32 rx_class_cfg1; + u32 rx_class_cfg2; + u32 rx_class_gates_base; + u32 rx_green; + u32 rx_rate_cfg_base; + u32 rx_rate_src_sel0; + u32 rx_rate_src_sel1; + u32 tx_rate_cfg_base; + u32 stat_base; + u32 tx_hsr_tag; + u32 tx_hsr_seq; + u32 tx_vlan_type; + u32 tx_vlan_ins; +}; + +static struct miig_rt_offsets offs[] = { + /* PRU0 */ + { + 0x8, + 0xc, + 0x80, + 0x84, + 0x88, + 0x108, + 0x308, + 0x408, + 0x40c, + 0x48c, + 0x490, + 0x494, + 0x4d4, + 0x4e4, + 0x504, + 0x508, + 0x50c, + 0x54c, + 0x63c, + 0x640, + 0x644, + 0x648, + }, + /* PRU1 */ + { + 0x10, + 0x14, + 0x64c, + 0x650, + 0x654, + 0x6d4, + 0x8d4, + 0x9d4, + 0x9d8, + 0xa58, + 0xa5c, + 0xa60, + 0xaa0, + 0xab0, + 0xad0, + 0xad4, + 0xad8, + 0xb18, + 0xc08, + 0xc0c, + 0xc10, + 0xc14, + }, +}; + +static void rx_class_ft1_cfg_set_type(struct regmap *miig_rt, int slice, int n, + enum ft1_cfg_type type) +{ + u32 offset; + + offset = offs[slice].ft1_cfg; + regmap_update_bits(miig_rt, offset, FT1_CFG_MASK(n), + type << FT1_CFG_SHIFT(n)); +} + +static void rx_class_sel_set_type(struct regmap *miig_rt, int slice, int n, + enum rx_class_sel_type type) +{ + u32 offset; + + offset = offs[slice].rx_class_cfg1; + regmap_update_bits(miig_rt, offset, RX_CLASS_SEL_MASK(n), + type << RX_CLASS_SEL_SHIFT(n)); +} + +static void rx_class_set_and(struct regmap *miig_rt, int slice, int n, + u32 data) +{ + u32 offset; + + offset = RX_CLASS_N_REG(slice, n, RX_CLASS_AND_EN); + regmap_write(miig_rt, offset, data); +} + +static void rx_class_set_or(struct regmap *miig_rt, int slice, int n, + u32 data) +{ + u32 offset; + + offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN); + regmap_write(miig_rt, offset, data); +} + +/* disable all RX traffic */ +void icssg_class_disable(struct regmap *miig_rt, int slice) +{ + u32 data, offset; + int n; + + /* Enable RX_L2_G */ + regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_RX_L2_G_EN, + ICSSG_CFG_RX_L2_G_EN); + + for (n = 0; n < ICSSG_NUM_CLASSIFIERS; n++) { + /* AND_EN = 0 */ + rx_class_set_and(miig_rt, slice, n, 0); + /* OR_EN = 0 */ + rx_class_set_or(miig_rt, slice, n, 0); + + /* set CFG1 to OR */ + rx_class_sel_set_type(miig_rt, slice, n, RX_CLASS_SEL_TYPE_OR); + + /* configure gate */ + offset = RX_CLASS_GATES_N_REG(slice, n); + regmap_read(miig_rt, offset, &data); + /* clear class_raw */ + data &= ~RX_CLASS_GATES_RAW_MASK; + /* set allow and phase mask */ + data |= RX_CLASS_GATES_ALLOW_MASK | RX_CLASS_GATES_PHASE_MASK; + regmap_write(miig_rt, offset, data); + } + + /* FT1 uses 6 bytes of DA address */ + offset = offs[slice].ft1_start_len; + regmap_write(miig_rt, offset, FT1_LEN(6)); + + /* FT1 type EQ */ + for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) + rx_class_ft1_cfg_set_type(miig_rt, slice, n, FT1_CFG_TYPE_EQ); + + /* FT1[0] DA compare address 00-00-00-00-00-00 */ + offset = FT1_N_REG(slice, 0, FT1_DA0); + regmap_write(miig_rt, offset, 0); + offset = FT1_N_REG(slice, 0, FT1_DA1); + regmap_write(miig_rt, offset, 0); + + /* FT1[0] mask FE-FF-FF-FF-FF-FF */ + offset = FT1_N_REG(slice, 0, FT1_DA0_MASK); + regmap_write(miig_rt, offset, 0); + offset = FT1_N_REG(slice, 0, FT1_DA1_MASK); + regmap_write(miig_rt, offset, 0); + + /* clear CFG2 */ + regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); +} + +void icssg_class_default(struct regmap *miig_rt, int slice) +{ + u32 offset, data; + int n; + + /* defaults */ + icssg_class_disable(miig_rt, slice); + + /* FT1 uses 6 bytes of DA address */ + offset = offs[slice].ft1_start_len; + regmap_write(miig_rt, offset, FT1_LEN(6)); + + /* FT1 slots to EQ */ + for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) + rx_class_ft1_cfg_set_type(miig_rt, slice, n, FT1_CFG_TYPE_EQ); + + /* FT1[0] DA compare address 00-00-00-00-00-00 */ + offset = FT1_N_REG(slice, 0, FT1_DA0); + regmap_write(miig_rt, offset, 0); + offset = FT1_N_REG(slice, 0, FT1_DA1); + regmap_write(miig_rt, offset, 0); + + /* FT1[0] mask 00-00-00-00-00-00 */ + offset = FT1_N_REG(slice, 0, FT1_DA0_MASK); + regmap_write(miig_rt, offset, 0); + offset = FT1_N_REG(slice, 0, FT1_DA1_MASK); + regmap_write(miig_rt, offset, 0); + + /* Setup Classifier 4 */ + /* match on Broadcast or MAC_PRU address */ + data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P; + rx_class_set_or(miig_rt, slice, 4, data); + + /* set CFG1 for OR_OR_AND for classifier 4 */ + rx_class_sel_set_type(miig_rt, slice, 4, RX_CLASS_SEL_TYPE_OR_OR_AND); + + /* ungate classifier 4 */ + offset = RX_CLASS_GATES_N_REG(slice, 4); + regmap_read(miig_rt, offset, &data); + data |= RX_CLASS_GATES_RAW_MASK; + regmap_write(miig_rt, offset, data); + + /* clear CFG2 */ + regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); +} + +void icssg_class_promiscuous(struct regmap *miig_rt, int slice) +{ + u32 data; + u32 offset; + int n; + + /* defaults */ + icssg_class_disable(miig_rt, slice); + + /* FT1 uses 6 bytes of DA address */ + offset = offs[slice].ft1_start_len; + regmap_write(miig_rt, offset, FT1_LEN(6)); + + /* FT1 type EQ */ + for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) + rx_class_ft1_cfg_set_type(miig_rt, slice, n, FT1_CFG_TYPE_EQ); + + /* FT1[0] DA compare address 00-00-00-00-00-00 */ + offset = FT1_N_REG(slice, 0, FT1_DA0); + regmap_write(miig_rt, offset, 0); + offset = FT1_N_REG(slice, 0, FT1_DA1); + regmap_write(miig_rt, offset, 0); + + /* FT1[0] mask FE-FF-FF-FF-FF-FF */ + offset = FT1_N_REG(slice, 0, FT1_DA0_MASK); + regmap_write(miig_rt, offset, 0xfffffffe); + offset = FT1_N_REG(slice, 0, FT1_DA1_MASK); + regmap_write(miig_rt, offset, 0xffff); + + /* Setup Classifier 4 */ + /* match on multicast, broadcast or unicast (ft1-0 address) */ + data = RX_CLASS_FT_MC | RX_CLASS_FT_BC | FT1_MATCH_SLOT(0); + rx_class_set_or(miig_rt, slice, 4, data); + + /* set CFG1 for OR_OR_AND for classifier 4 */ + rx_class_sel_set_type(miig_rt, slice, 4, RX_CLASS_SEL_TYPE_OR_OR_AND); + + /* ungate classifier 4 */ + offset = RX_CLASS_GATES_N_REG(slice, 4); + regmap_read(miig_rt, offset, &data); + data |= RX_CLASS_GATES_RAW_MASK; + regmap_write(miig_rt, offset, data); +} + +void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac) +{ + u32 mac0, mac1; + + mac0 = mac[0] | mac[1] << 8 | mac[2] << 16 | mac[3] << 24; + mac1 = mac[4] | mac[5] << 8; + + regmap_write(miig_rt, offs[slice].mac0, mac0); + regmap_write(miig_rt, offs[slice].mac1, mac1); +} From patchwork Tue Feb 18 05:09:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236455 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:39:59 +0530 Subject: [PATCH v2 05/10] arm: dts: k3-am65-main: Add msmc_ram node In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-6-j-keerthy@ti.com> Add msmc_ram node needed for prueth Signed-off-by: Keerthy --- Changes in v2: * Aligned trailing 0s for consistency. arch/arm/dts/k3-am65-main.dtsi | 21 +++++++++++++++++++++ arch/arm/dts/k3-am65.dtsi | 4 +++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/k3-am65-main.dtsi b/arch/arm/dts/k3-am65-main.dtsi index ab40dafceb..631134cd65 100644 --- a/arch/arm/dts/k3-am65-main.dtsi +++ b/arch/arm/dts/k3-am65-main.dtsi @@ -9,6 +9,27 @@ #include &cbass_main { + msmc_ram: sram at 70000000 { + compatible = "mmio-sram"; + reg = <0x0 0x70000000 0x0 0x200000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x70000000 0x200000>; + u-boot,dm-spl; + + atf-sram at 0 { + reg = <0x0 0x20000>; + }; + + sysfw-sram at f0000 { + reg = <0xf0000 0x10000>; + }; + + l3cache-sram at 100000 { + reg = <0x100000 0x100000>; + }; + }; + gic500: interrupt-controller at 1800000 { compatible = "arm,gic-v3"; #address-cells = <2>; diff --git a/arch/arm/dts/k3-am65.dtsi b/arch/arm/dts/k3-am65.dtsi index 3ead944640..b2e967aaf7 100644 --- a/arch/arm/dts/k3-am65.dtsi +++ b/arch/arm/dts/k3-am65.dtsi @@ -79,7 +79,9 @@ <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, - <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>; + <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, + <0x07 0x00000000 0x07 0x00000000 0x01 0x00000000>, + <0x00 0x70000000 0x00 0x70000000 0x00 0x00200000>; cbass_mcu: interconnect at 28380000 { compatible = "simple-bus"; From patchwork Tue Feb 18 05:10:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236456 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:40:00 +0530 Subject: [PATCH v2 06/10] arm: dts: k3-am654-base-board-u-boot: Add icssg specific msmc_ram carveout nodes In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-7-j-keerthy@ti.com> Add icssg specific msmc_ram carveout nodes Signed-off-by: Keerthy --- arch/arm/dts/k3-am654-base-board-u-boot.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index a349edcfa5..a5aee02eb8 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -365,3 +365,15 @@ &usb1 { dr_mode = "peripheral"; }; + +&msmc_ram { + icssg0_sram: icssg0-sram at 40000 { + reg = <0x40000 0x10000>; + }; + icssg1_sram: icssg1-sram at 50000 { + reg = <0x50000 0x10000>; + }; + icssg2_sram: icssg2-sram at 60000 { + reg = <0x60000 0x10000>; + }; +}; From patchwork Tue Feb 18 05:10:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236458 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:40:01 +0530 Subject: [PATCH v2 07/10] arm: dts: k3-am65-main: Add scm_conf node In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-8-j-keerthy@ti.com> Add scm_conf node needed for prueth. Signed-off-by: Keerthy --- arch/arm/dts/k3-am65-main.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/dts/k3-am65-main.dtsi b/arch/arm/dts/k3-am65-main.dtsi index 631134cd65..71a540376f 100644 --- a/arch/arm/dts/k3-am65-main.dtsi +++ b/arch/arm/dts/k3-am65-main.dtsi @@ -53,6 +53,14 @@ }; }; + scm_conf: scm_conf at 100000 { + compatible = "syscon", "simple-mfd"; + reg = <0 0x00100000 0 0x1c000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x00100000 0x1c000>; + }; + secure_proxy_main: mailbox at 32c00000 { compatible = "ti,am654-secure-proxy"; #mbox-cells = <1>; From patchwork Tue Feb 18 05:10:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236459 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:40:02 +0530 Subject: [PATCH v2 08/10] arm: dts: k3-am65-main: Add pruss nodes for ICSSG2 In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-9-j-keerthy@ti.com> Add pruss nodes. This is based 4.19 DT with interrupt properties removed from pur/rtu nodes. Signed-off-by: Keerthy --- arch/arm/dts/k3-am65-main.dtsi | 162 +++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/arch/arm/dts/k3-am65-main.dtsi b/arch/arm/dts/k3-am65-main.dtsi index 71a540376f..7499bab309 100644 --- a/arch/arm/dts/k3-am65-main.dtsi +++ b/arch/arm/dts/k3-am65-main.dtsi @@ -8,6 +8,8 @@ #include #include +#include + &cbass_main { msmc_ram: sram at 70000000 { compatible = "mmio-sram"; @@ -358,4 +360,164 @@ #phy-cells = <0>; ti,dis-chg-det-quirk; }; + + icssg2: icssg at b200000 { + compatible = "ti,am654-icssg"; + power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>; + reg = <0xb200000 0x80000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + dma-ranges; + ti,psil-base = <0x4300>; /* ICSSG2 PSIL thread start */ + + ti,psil-config0 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config1 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config2 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config3 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config4 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config5 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config6 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config7 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + icssg2_mem: memories at b200000 { + reg = <0xb200000 0x2000>, + <0xb202000 0x2000>, + <0xb210000 0x10000>; + reg-names = "dram0", "dram1", + "shrdram2"; + }; + + icssg2_cfg: cfg at b226000 { + compatible = "syscon"; + reg = <0xb226000 0x200>; + }; + + icssg2_iep: iep at b22e000 { + compatible = "syscon"; + reg = <0xb22e000 0x1000>; + }; + + icssg2_mii_rt: mii-rt at b232000 { + compatible = "syscon"; + reg = <0xb232000 0x100>; + }; + + icssg2_mii_g_rt: mii-g-rt at b233000 { + compatible = "syscon"; + reg = <0xb233000 0x1000>; + }; + + icssg2_intc: interrupt-controller at b220000 { + compatible = "ti,am654-icssg-intc"; + reg = <0xb220000 0x2000>; + interrupt-controller; + #interrupt-cells = <1>; + interrupts = , + , + , + , + , + , + , + ; + interrupt-names = "host2", "host3", "host4", + "host5", "host6", "host7", + "host8", "host9"; + }; + + pru2_0: pru at b234000 { + compatible = "ti,am654-pru"; + reg = <0xb234000 0x4000>, + <0xb222000 0x100>, + <0xb222400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru2_0-fw"; + }; + + rtu2_0: rtu at b204000 { + compatible = "ti,am654-rtu"; + reg = <0xb204000 0x2000>, + <0xb223000 0x100>, + <0xb223400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu2_0-fw"; + }; + + pru2_1: pru at b238000 { + compatible = "ti,am654-pru"; + reg = <0xb238000 0x4000>, + <0xb224000 0x100>, + <0xb224400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru2_1-fw"; + }; + + rtu2_1: rtu at b206000 { + compatible = "ti,am654-rtu"; + reg = <0xb206000 0x2000>, + <0xb223800 0x100>, + <0xb223c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu2_1-fw"; + }; + + icssg2_mdio: mdio at b232400 { + compatible = "ti,davinci_mdio"; + reg = <0xb232400 0x100>; + clocks = <&k3_clks 64 3>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + status = "disabled"; + }; + }; }; From patchwork Tue Feb 18 05:10:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236461 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:40:03 +0530 Subject: [PATCH v2 09/10] arm64: dts: ti: am654-base-board: add ICSSG2 Ethernet support In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-10-j-keerthy@ti.com> ICSSG2 provide dual Gigabit Ethernet support. Currently mdio clock is part of this node and also the icssg2_rgmii_pins_default pinmux node has the mdio pins as there is no davinci mdio driver. Currently icssg2 instances are supported. Either mii0 or mii1 can be enabled at a time. Signed-off-by: Keerthy --- Changes in v2: * Removed a bunch of inconsistent white space in pins definition. arch/arm/dts/k3-am654-base-board-u-boot.dtsi | 117 +++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index a5aee02eb8..31038b7802 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -16,6 +16,64 @@ serial2 = &main_uart0; ethernet0 = &cpsw_port1; }; + + /* Dual Ethernet application node on PRU-ICSSG2 */ + pruss2_eth: pruss2_eth { + compatible = "ti,am654-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg2_rgmii_pins_default>; + sram = <&icssg2_sram>; + clocks = <&k3_clks 64 3>; + clock-names = "mdio_fck"; + u-boot,dm-spl; + + prus = <&pru2_0>, <&rtu2_0>, <&pru2_1>, <&rtu2_1>; + firmware-name = "ti-pruss/am65x-pru0-prueth-fw.elf", + "ti-pruss/am65x-rtu0-prueth-fw.elf", + "ti-pruss/am65x-pru1-prueth-fw.elf", + "ti-pruss/am65x-rtu1-prueth-fw.elf"; + mii-g-rt = <&icssg2_mii_g_rt>; + mii-rt = <&icssg2_mii_rt>; + dma-coherent; + dmas = <&mcu_udmap &icssg2 0 UDMA_DIR_TX>, /* egress slice 0 */ + <&mcu_udmap &icssg2 1 UDMA_DIR_TX>, /* egress slice 0 */ + <&mcu_udmap &icssg2 2 UDMA_DIR_TX>, /* egress slice 0 */ + <&mcu_udmap &icssg2 3 UDMA_DIR_TX>, /* mgmnt cmd slice 0 */ + <&mcu_udmap &icssg2 4 UDMA_DIR_TX>, /* egress slice 1 */ + <&mcu_udmap &icssg2 5 UDMA_DIR_TX>, /* egress slice 1 */ + <&mcu_udmap &icssg2 6 UDMA_DIR_TX>, /* egress slice 1 */ + <&mcu_udmap &icssg2 7 UDMA_DIR_TX>, /* mgmnt cmd slice 1 */ + + <&mcu_udmap &icssg2 0 UDMA_DIR_RX>, /* ingress slice 0 */ + <&mcu_udmap &icssg2 1 UDMA_DIR_RX>, /* ingress slice 1 */ + <&mcu_udmap &icssg2 2 UDMA_DIR_RX>, /* mgmnt rsp slice 0 */ + <&mcu_udmap &icssg2 3 UDMA_DIR_RX>; /* mgmnt rsp slice 1 */ + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1", + "rxmgm0", "rxmgm1"; + + pruss2_emac0: ethernet-mii0 { + phy-handle = <&pruss2_eth0_phy>; + phy-mode = "rgmii-rxid"; + syscon-rgmii-delay = <&scm_conf 0x4120>; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + +/* + * Commenting out the second mii interface as the framework + * supports one interface in a single probe + * So either mii1 or mii2 can be used. In case mii1 is needed + * uncomment mii1 and comment out mii0 + pruss2_emac1: ethernet-mii1 { + phy-handle = <&pruss2_eth1_phy>; + phy-mode = "rgmii-rxid"; + syscon-rgmii-delay = <&scm_conf 0x4124>; + local-mac-address = [00 00 00 00 00 00]; + }; +*/ + }; }; &cbass_main{ @@ -275,6 +333,47 @@ u-boot,dm-spl; }; + icssg2_rgmii_pins_default: icssg2_rgmii_pins_default { + pinctrl-single,pins = < + AM65X_IOPAD(0x00ac, PIN_INPUT, 2) /* (AH15) PRG2_PRU1_GPO0.PRG2_RGMII2_RD0 */ + AM65X_IOPAD(0x00b0, PIN_INPUT, 2) /* (AC16) PRG2_PRU1_GPO1.PRG2_RGMII2_RD1 */ + AM65X_IOPAD(0x00b4, PIN_INPUT, 2) /* (AD17) PRG2_PRU1_GPO2.PRG2_RGMII2_RD2 */ + AM65X_IOPAD(0x00b8, PIN_INPUT, 2) /* (AH14) PRG2_PRU1_GPO3.PRG2_RGMII2_RD3 */ + AM65X_IOPAD(0x00cc, PIN_OUTPUT, 2) /* (AD15) PRG2_PRU1_GPO8.PRG2_RGMII2_TD0 */ + AM65X_IOPAD(0x00d0, PIN_OUTPUT, 2) /* (AF14) PRG2_PRU1_GPO9.PRG2_RGMII2_TD1 */ + AM65X_IOPAD(0x00d4, PIN_OUTPUT, 2) /* (AC15) PRG2_PRU1_GPO10.PRG2_RGMII2_TD2 */ + AM65X_IOPAD(0x00d8, PIN_OUTPUT, 2) /* (AD14) PRG2_PRU1_GPO11.PRG2_RGMII2_TD3 */ + AM65X_IOPAD(0x00dc, PIN_INPUT, 2) /* (AE14) PRG2_PRU1_GPO16.PRG2_RGMII2_TXC */ + AM65X_IOPAD(0x00c4, PIN_OUTPUT, 2) /* (AC17) PRG2_PRU1_GPO6.PRG2_RGMII2_TX_CTL */ + AM65X_IOPAD(0x00c0, PIN_INPUT, 2) /* (AG15) PRG2_PRU1_GPO5.PRG2_RGMII2_RXC */ + AM65X_IOPAD(0x00bc, PIN_INPUT, 2) /* (AG14) PRG2_PRU1_GPO4.PRG2_RGMII2_RX_CTL */ + + AM65X_IOPAD(0x0078, PIN_INPUT, 2) /* (AF18) PRG2_PRU0_GPO0.PRG2_RGMII1_RD0 */ + AM65X_IOPAD(0x007c, PIN_INPUT, 2) /* (AE18) PRG2_PRU0_GPO1.PRG2_RGMII1_RD1 */ + AM65X_IOPAD(0x0080, PIN_INPUT, 2) /* (AH17) PRG2_PRU0_GPO2.PRG2_RGMII1_RD2 */ + AM65X_IOPAD(0x0084, PIN_INPUT, 2) /* (AG18) PRG2_PRU0_GPO3.PRG2_RGMII1_RD3 */ + AM65X_IOPAD(0x0098, PIN_OUTPUT, 2) /* (AH16) PRG2_PRU0_GPO8.PRG2_RGMII1_TD0 */ + AM65X_IOPAD(0x009c, PIN_OUTPUT, 2) /* (AG16) PRG2_PRU0_GPO9.PRG2_RGMII1_TD1 */ + AM65X_IOPAD(0x00a0, PIN_OUTPUT, 2) /* (AF16) PRG2_PRU0_GPO10.PRG2_RGMII1_TD2 */ + AM65X_IOPAD(0x00a4, PIN_OUTPUT, 2) /* (AE16) PRG2_PRU0_GPO11.PRG2_RGMII1_TD3 */ + AM65X_IOPAD(0x00a8, PIN_INPUT, 2) /* (AD16) PRG2_PRU0_GPO16.PRG2_RGMII1_TXC */ + AM65X_IOPAD(0x0090, PIN_OUTPUT, 2) /* (AE17) PRG2_PRU0_GPO6.PRG2_RGMII1_TX_CTL */ + AM65X_IOPAD(0x008c, PIN_INPUT, 2) /* (AF17) PRG2_PRU0_GPO5.PRG2_RGMII1_RXC */ + AM65X_IOPAD(0x0088, PIN_INPUT, 2) /* (AG17) PRG2_PRU0_GPO4.PRG2_RGMII1_RX_CTL */ + /* HACK to get MDIO Pins in the right state */ + AM65X_IOPAD(0x0094, PIN_INPUT, 2) /* (AC19) PRG2_PRU0_GPO7.PRG2_MDIO0_MDIO */ + AM65X_IOPAD(0x00c8, PIN_OUTPUT, 2) /* (AE15) PRG2_PRU1_GPO7.PRG2_MDIO0_MDC */ + >; + u-boot,dm-spl; + }; + + icssg2_mdio_pins_default: icssg2_mdio_pins_default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0094, PIN_INPUT, 2) /* (AC19) PRG2_PRU0_GPO7.PRG2_MDIO0_MDIO */ + AM65X_IOPAD(0x00c8, PIN_OUTPUT, 2) /* (AE15) PRG2_PRU1_GPO7.PRG2_MDIO0_MDC */ + >; + u-boot,dm-spl; + }; }; &main_pmx1 { @@ -377,3 +476,21 @@ reg = <0x60000 0x10000>; }; }; + +&icssg2_mdio{ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg2_mdio_pins_default>; + + pruss2_eth0_phy: ethernet-phy at 0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; + + pruss2_eth1_phy: ethernet-phy at 3 { + reg = <3>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; +}; From patchwork Tue Feb 18 05:10:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 236460 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Tue, 18 Feb 2020 10:40:04 +0530 Subject: [PATCH v2 10/10] configs: am65x_evm_a53_defconfig: Enable CONFIG_TI_AM64_ICSSG_PRUETH In-Reply-To: <20200218051004.32524-1-j-keerthy@ti.com> References: <20200218051004.32524-1-j-keerthy@ti.com> Message-ID: <20200218051004.32524-11-j-keerthy@ti.com> Enable ICSSG_PRUETH & related configs. This enables ethernet functionality on PRU. Signed-off-by: Keerthy --- configs/am65x_evm_a53_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig index 079cd912ba..1b0bfe6444 100644 --- a/configs/am65x_evm_a53_defconfig +++ b/configs/am65x_evm_a53_defconfig @@ -84,6 +84,7 @@ CONFIG_DM_ETH=y CONFIG_E1000=y CONFIG_CMD_E1000=y CONFIG_TI_AM65_CPSW_NUSS=y +CONFIG_TI_AM64_ICSSG_PRUETH=y CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_PCI_KEYSTONE=y @@ -98,10 +99,12 @@ CONFIG_PINCTRL_SINGLE=y CONFIG_POWER_DOMAIN=y CONFIG_TI_SCI_POWER_DOMAIN=y CONFIG_REMOTEPROC_TI_K3_R5F=y +CONFIG_REMOTEPROC_TI_PRU=y CONFIG_DM_RESET=y CONFIG_RESET_TI_SCI=y CONFIG_DM_SERIAL=y CONFIG_SOC_TI=y +CONFIG_TI_PRUSS=y CONFIG_SYSRESET=y CONFIG_SPL_SYSRESET=y CONFIG_SYSRESET_TI_SCI=y