diff options
author | Tom Rini <trini@konsulko.com> | 2021-07-19 08:29:24 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2021-07-19 08:29:24 -0400 |
commit | 83befb446664af32ce18f0e42e99a353e6622e58 (patch) | |
tree | 563a58575010c89767e6e8d21bf82443e5f44e52 /drivers | |
parent | abf0061eabf43f43a3889871e259c9633e7a42e3 (diff) | |
parent | 652982309d316b14aae5805d09239f89eb89f038 (diff) | |
download | u-boot-83befb446664af32ce18f0e42e99a353e6622e58.zip u-boot-83befb446664af32ce18f0e42e99a353e6622e58.tar.gz u-boot-83befb446664af32ce18f0e42e99a353e6622e58.tar.bz2 |
Merge tag 'ti-v2021.10-rc1' of https://source.denx.de/u-boot/custodians/u-boot-ti
- Enabled distro boot for all TI platforms.
- Cleanup for AM335x Guardian Board
- PRUSS rproc on AM65 platform.
- Add PMIC support for J7200
- Misc fixes for Nokia RX-51
# Conflicts:
# arch/arm/mach-omap2/am33xx/Kconfig
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/bootcount/Kconfig | 34 | ||||
-rw-r--r-- | drivers/bootcount/Makefile | 1 | ||||
-rw-r--r-- | drivers/bootcount/bootcount_nvmem.c | 57 | ||||
-rw-r--r-- | drivers/power/pmic/tps65941.c | 1 | ||||
-rw-r--r-- | drivers/remoteproc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/remoteproc/Makefile | 1 | ||||
-rw-r--r-- | drivers/remoteproc/pru_rproc.c | 461 | ||||
-rw-r--r-- | drivers/soc/ti/Kconfig | 11 | ||||
-rw-r--r-- | drivers/soc/ti/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/ti/pruss.c | 217 | ||||
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/hx8238d.c | 4 |
12 files changed, 795 insertions, 6 deletions
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index b5ccea0..0de2b7b 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -42,6 +42,25 @@ config BOOTCOUNT_AM33XX This requires the RTC clocks, etc, to be enabled prior to use and not all boards with this IP block on it will have the RTC in use. +config BOOTCOUNT_AM33XX_NVMEM + bool "Boot counter in AM33XX RTC IP block with upgrade_available flag" + depends on AM33XX + select SPL_AM33XX_ENABLE_RTC32K_OSC if AM33XX + help + Add support for maintaining bootcount,upgrade_available, + version and BOOTMAGIC in a AM33xx RTC IP block + scratch register2. + + A bootcount driver for the RTC IP block found on many TI platforms. + This requires the RTC clocks, etc, to be enabled prior to use and + not all boards with this IP block on it will have the RTC in use. + + If there is upgrade in software then "upgrade_available" is 1, + "bootcount" is incremented otherwise "upgrade_available" and + "bootcount" is always 0. So the Userspace Application must set + the "upgrade_available" and "bootcount" variable to 0, if a boot + was successfully. + config BOOTCOUNT_ENV bool "Boot counter in environment" help @@ -177,16 +196,25 @@ config SYS_BOOTCOUNT_EXT_NAME config SYS_BOOTCOUNT_ADDR hex "RAM address used for reading and writing the boot counter" - default 0x44E3E000 if BOOTCOUNT_AM33XX + default 0x44E3E000 if BOOTCOUNT_AM33XX || BOOTCOUNT_AM33XX_NVMEM default 0xE0115FF8 if ARCH_LS1043A || ARCH_LS1021A depends on BOOTCOUNT_AM33XX || BOOTCOUNT_GENERIC || BOOTCOUNT_EXT || \ - BOOTCOUNT_I2C + BOOTCOUNT_I2C || BOOTCOUNT_AM33XX_NVMEM help Set the address used for reading and writing the boot counter. config SYS_BOOTCOUNT_MAGIC hex "Magic value for the boot counter" - default 0xB001C041 + default 0xB001C041 if BOOTCOUNT_GENERIC || BOOTCOUNT_EXT || \ + BOOTCOUNT_AM33XX || BOOTCOUNT_ENV || \ + BOOTCOUNT_RAM || BOOTCOUNT_I2C || \ + BOOTCOUNT_AT91 || DM_BOOTCOUNT + default 0xB0 if BOOTCOUNT_AM33XX_NVMEM + depends on BOOTCOUNT_GENERIC || BOOTCOUNT_EXT || \ + BOOTCOUNT_AM33XX || BOOTCOUNT_ENV || \ + BOOTCOUNT_RAM || BOOTCOUNT_I2C || \ + BOOTCOUNT_AT91 || DM_BOOTCOUNT || \ + BOOTCOUNT_AM33XX_NVMEM help Set the magic value used for the boot counter. diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index 51d860b..12658ff 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o obj-$(CONFIG_BOOTCOUNT_ENV) += bootcount_env.o obj-$(CONFIG_BOOTCOUNT_I2C) += bootcount_i2c.o obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o +obj-$(CONFIG_BOOTCOUNT_AM33XX_NVMEM) += bootcount_nvmem.o obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o diff --git a/drivers/bootcount/bootcount_nvmem.c b/drivers/bootcount/bootcount_nvmem.c new file mode 100644 index 0000000..5f266d5 --- /dev/null +++ b/drivers/bootcount/bootcount_nvmem.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * (C) Copyright 2018 Robert Bosch Power Tools GmbH. + * + * A bootcount driver for the RTC IP block found on many TI platforms. + * This requires the RTC clocks, etc, to be enabled prior to use and + * not all boards with this IP block on it will have the RTC in use. + */ + +#include <bootcount.h> +#include <asm/davinci_rtc.h> + +#define BC_VERSION 2 + +void bootcount_store(ulong bootcount) +{ + u8 upgrade_available = 0; + ulong val = 0; + struct davinci_rtc *reg = + (struct davinci_rtc *)CONFIG_SYS_BOOTCOUNT_ADDR; + + val = raw_bootcount_load(®->scratch2); + upgrade_available = (val >> 8) & 0x000000ff; + + /* Only update bootcount during upgrade process */ + if (!upgrade_available) + bootcount = 0; + + val = (bootcount & 0x000000ff) | + (upgrade_available << 8) | + (BC_VERSION << 16) | + (CONFIG_SYS_BOOTCOUNT_MAGIC << 24); + + /* + * write RTC kick registers to enable write + * for RTC Scratch registers. Scratch register 2 is + * used for bootcount value. + */ + writel(RTC_KICK0R_WE, ®->kick0r); + writel(RTC_KICK1R_WE, ®->kick1r); + raw_bootcount_store(®->scratch2, val); +} + +ulong bootcount_load(void) +{ + unsigned long val = 0; + struct davinci_rtc *reg = + (struct davinci_rtc *)CONFIG_SYS_BOOTCOUNT_ADDR; + + val = raw_bootcount_load(®->scratch2); + if ((val >> 24) != CONFIG_SYS_BOOTCOUNT_MAGIC) + return 0; + else + return val & 0x000000ff; +} diff --git a/drivers/power/pmic/tps65941.c b/drivers/power/pmic/tps65941.c index 3dfc191..114ef4d 100644 --- a/drivers/power/pmic/tps65941.c +++ b/drivers/power/pmic/tps65941.c @@ -72,6 +72,7 @@ static struct dm_pmic_ops tps65941_ops = { static const struct udevice_id tps65941_ids[] = { { .compatible = "ti,tps659411", .data = TPS659411 }, { .compatible = "ti,tps659413", .data = TPS659413 }, + { .compatible = "ti,lp876441", .data = LP876441 }, { } }; diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 7c2e480..24e5364 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 69ae7bd..f0e8345 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 0000000..924070a --- /dev/null +++ b/drivers/remoteproc/pru_rproc.c @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PRU-RTU remoteproc driver for various SoCs + * + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Keerthy <j-keerthy@ti.com> + */ + +#include <common.h> +#include <dm.h> +#include <elf.h> +#include <dm/of_access.h> +#include <remoteproc.h> +#include <errno.h> +#include <clk.h> +#include <reset.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <power-domain.h> +#include <linux/pruss_driver.h> +#include <dm/device_compat.h> + +/* 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; +}; + +static inline u32 pru_control_read_reg(struct pru_privdata *pru, unsigned int reg) +{ + return readl(pru->pru_ctrl + reg); +} + +static inline +void pru_control_write_reg(struct pru_privdata *pru, unsigned int reg, u32 val) +{ + writel(val, pru->pru_ctrl + reg); +} + +static inline +void pru_control_set_reg(struct pru_privdata *pru, unsigned int reg, + u32 mask, u32 set) +{ + u32 val; + + val = pru_control_read_reg(pru, reg); + val &= ~mask; + val |= (set & mask); + pru_control_write_reg(pru, reg, val); +} + +/** + * pru_rproc_set_ctable() - set the constant table index for the PRU + * @rproc: the rproc instance of the PRU + * @c: constant table index to set + * @addr: physical address to set it to + */ +static int pru_rproc_set_ctable(struct pru_privdata *pru, enum pru_ctable_idx c, u32 addr) +{ + unsigned int reg; + u32 mask, set; + u16 idx; + u16 idx_mask; + + /* pointer is 16 bit and index is 8-bit so mask out the rest */ + idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF; + + /* ctable uses bit 8 and upwards only */ + idx = (addr >> 8) & idx_mask; + + /* configurable ctable (i.e. C24) starts at PRU_CTRL_CTBIR0 */ + reg = PRU_CTRL_CTBIR0 + 4 * (c >> 1); + mask = idx_mask << (16 * (c & 1)); + set = idx << (16 * (c & 1)); + + pru_control_set_reg(pru, reg, mask, set); + + return 0; +} + +/** + * 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); + + pru_rproc_set_ctable(priv, PRU_C28, 0x100 << 8); + + 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->mem_regions[PRUSS_MEM_DRAM0].pa; + dram1 = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].pa; + shrdram2 = priv->prusspriv->mem_regions[PRUSS_MEM_SHRD_RAM2].pa; + dram0sz = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM0].size; + dram1sz = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].size; + shrdram2sz = priv->prusspriv->mem_regions[PRUSS_MEM_SHRD_RAM2].size; + + /* PRU1 has its local RAM addresses reversed */ + if (priv->id == 1) { + dram1 = dram0; + dram1sz = dram0sz; + + dram0 = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].pa; + dram0sz = priv->prusspriv->mem_regions[PRUSS_MEM_DRAM1].size; + } + + 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 (device_is_compatible(dev, "ti,am654-tx-pru")) + mask2 = 0xc000; + + 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; + 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->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"}, + { .compatible = "ti,am654-tx-pru" }, + {} +}; + +U_BOOT_DRIVER(pru) = { + .name = "pru", + .of_match = pru_ids, + .id = UCLASS_REMOTEPROC, + .ops = &pru_ops, + .probe = pru_probe, + .priv_auto = sizeof(struct pru_privdata), +}; diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index e4f8834..0ee21f9 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -23,4 +23,15 @@ 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 4ec04ee..34f80aa 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 0000000..4613909 --- /dev/null +++ b/drivers/soc/ti/pruss.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PRU-ICSS platform driver for various TI SoCs + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <common.h> +#include <dm.h> +#include <dm/of_access.h> +#include <errno.h> +#include <clk.h> +#include <reset.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <power-domain.h> +#include <linux/pruss_driver.h> +#include <dm/device_compat.h> + +#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) + +/* + * 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->mem_regions[PRUSS_MEM_DRAM0].pa) + return -EINVAL; + + *loc = priv->mem_regions[PRUSS_MEM_DRAM0].pa + ICSSG_TASK_MGR_OFFSET; + + return 0; +} + +/** + * pruss_request_mem_region() - request a memory resource + * @dev: the pruss device + * @mem_id: the memory resource id + * @region: pointer to memory region structure to be filled in + * + * This function allows a client driver to request a memory resource, + * and if successful, will let the client driver own the particular + * memory region until released using the pruss_release_mem_region() + * API. + * + * Returns the memory region if requested resource is available, an + * error otherwise + */ +int pruss_request_mem_region(struct udevice *dev, enum pruss_mem mem_id, + struct pruss_mem_region *region) +{ + struct pruss *pruss; + + pruss = dev_get_priv(dev); + if (!pruss || !region) + return -EINVAL; + + if (mem_id >= PRUSS_MEM_MAX) + return -EINVAL; + + if (pruss->mem_in_use[mem_id]) + return -EBUSY; + + *region = pruss->mem_regions[mem_id]; + pruss->mem_in_use[mem_id] = region; + + return 0; +} + +/** + * pruss_release_mem_region() - release a memory resource + * @dev: the pruss device + * @region: the memory region to release + * + * This function is the complimentary function to + * pruss_request_mem_region(), and allows the client drivers to + * release back a memory resource. + * + * Returns 0 on success, an error code otherwise + */ +int pruss_release_mem_region(struct udevice *dev, + struct pruss_mem_region *region) +{ + struct pruss *pruss; + int id; + + pruss = dev_get_priv(dev); + if (!pruss || !region) + return -EINVAL; + + /* find out the memory region being released */ + for (id = 0; id < PRUSS_MEM_MAX; id++) { + if (pruss->mem_in_use[id] == region) + break; + } + + if (id == PRUSS_MEM_MAX) + return -EINVAL; + + pruss->mem_in_use[id] = NULL; + + return 0; +} + +/** + * pruss_cfg_update() - configure a PRUSS CFG sub-module register + * @dev: the pruss device + * @reg: register offset within the CFG sub-module + * @mask: bit mask to use for programming the @val + * @val: value to write + * + * Programs a given register within the PRUSS CFG sub-module + * + * Returns 0 on success, or an error code otherwise + */ +int pruss_cfg_update(struct udevice *dev, unsigned int reg, + unsigned int mask, unsigned int val) +{ + struct pruss *pruss; + + pruss = dev_get_priv(dev); + if (IS_ERR_OR_NULL(pruss)) + return -EINVAL; + + return regmap_update_bits(pruss->cfg, reg, mask, val); +} + +/** + * 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) +{ + const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" }; + ofnode sub_node, node, memories; + struct udevice *syscon; + struct pruss *priv; + int ret, idx, i; + + priv = dev_get_priv(dev); + node = dev_ofnode(dev); + priv->dev = dev; + memories = ofnode_find_subnode(node, "memories"); + + for (i = 0; i < ARRAY_SIZE(mem_names); i++) { + idx = ofnode_stringlist_search(memories, "reg-names", mem_names[i]); + priv->mem_regions[i].pa = ofnode_get_addr_size_index(memories, idx, + (u64 *)&priv->mem_regions[i].size); + } + + sub_node = ofnode_find_subnode(node, "cfg"); + ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, sub_node, + &syscon); + + priv->cfg = syscon_get_regmap(syscon); + if (IS_ERR(priv->cfg)) { + dev_err(dev, "unable to get cfg regmap (%ld)\n", + PTR_ERR(priv->cfg)); + return -ENODEV; + } + + /* + * ToDo: To be modelled as clocks. + * 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(priv->cfg, ICSSG_CFG_CORE_SYNC, + ICSSG_CORE_VBUSP_SYNC_EN, + ICSSG_CORE_VBUSP_SYNC_EN); + if (ret) + return ret; + ret = regmap_update_bits(priv->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 = sizeof(struct pruss), +}; diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 933f06e..1c534a6 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi-host-uclass.o obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o obj-$(CONFIG_DM_VIDEO) += video_bmp.o obj-$(CONFIG_PANEL) += panel-uclass.o -obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o +obj-$(CONFIG_DM_PANEL_HX8238D) += hx8238d.o obj-$(CONFIG_SIMPLE_PANEL) += simple_panel.o endif diff --git a/drivers/video/hx8238d.c b/drivers/video/hx8238d.c index f7e7753..6ee97cb 100644 --- a/drivers/video/hx8238d.c +++ b/drivers/video/hx8238d.c @@ -191,7 +191,7 @@ U_BOOT_DRIVER(hx8238d) = { .name = "hx8238d", .id = UCLASS_PANEL, .of_match = hx8238d_ids, - .ofdata_to_platdata = hx8238d_ofdata_to_platdata, + .of_to_plat = hx8238d_ofdata_to_platdata, .probe = hx8238d_probe, - .priv_auto_alloc_size = sizeof(struct hx8238d_priv), + .priv_auto = sizeof(struct hx8238d_priv), }; |