1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-01 00:32:04 +02:00
- add rtc driver for stm32mp1
- add remoteproc driver for stm32mp1
- use kernel qspi compatible string for stm32
This commit is contained in:
Tom Rini
2019-07-23 14:16:21 -04:00
29 changed files with 1126 additions and 77 deletions

View File

@@ -311,6 +311,7 @@ F: drivers/power/pmic/stpmic1.c
F: drivers/power/regulator/stm32-vrefbuf.c F: drivers/power/regulator/stm32-vrefbuf.c
F: drivers/power/regulator/stpmic1.c F: drivers/power/regulator/stpmic1.c
F: drivers/ram/stm32mp1/ F: drivers/ram/stm32mp1/
F: drivers/remoteproc/stm32_copro.c
F: drivers/misc/stm32_rcc.c F: drivers/misc/stm32_rcc.c
F: drivers/reset/stm32-reset.c F: drivers/reset/stm32-reset.c
F: drivers/spi/stm32_qspi.c F: drivers/spi/stm32_qspi.c

View File

@@ -67,7 +67,7 @@
}; };
qspi: quadspi@A0001000 { qspi: quadspi@A0001000 {
compatible = "st,stm32-qspi"; compatible = "st,stm32f469-qspi";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>; reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>;

View File

@@ -44,7 +44,7 @@
}; };
qspi: quadspi@A0001000 { qspi: quadspi@A0001000 {
compatible = "st,stm32-qspi"; compatible = "st,stm32f469-qspi";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>; reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>;

View File

@@ -756,6 +756,10 @@
3 0x300 0xB000 0x1000 3 0x300 0xB000 0x1000
>; >;
dma-ranges = <0 0x000 0x10000000 0x1000
1 0x100 0x20000000 0x1000
>;
dev@0,0 { dev@0,0 {
compatible = "denx,u-boot-fdt-dummy"; compatible = "denx,u-boot-fdt-dummy";
reg = <0 0x0 0x1000>; reg = <0 0x0 0x1000>;

View File

@@ -1292,6 +1292,12 @@ u64 fdt_translate_address(const void *blob, int node_offset,
return __of_translate_address(blob, node_offset, in_addr, "ranges"); return __of_translate_address(blob, node_offset, in_addr, "ranges");
} }
u64 fdt_translate_dma_address(const void *blob, int node_offset,
const fdt32_t *in_addr)
{
return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
}
/** /**
* fdt_node_offset_by_compat_reg: Find a node that matches compatiable and * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
* who's reg property matches a physical cpu address * who's reg property matches a physical cpu address

View File

@@ -101,6 +101,9 @@ CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y
CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_DM_REGULATOR_STPMIC1=y
CONFIG_REMOTEPROC_STM32_COPRO=y
CONFIG_DM_RTC=y
CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y CONFIG_SERIAL_RX_BUFFER=y
CONFIG_STM32_SERIAL=y CONFIG_STM32_SERIAL=y
CONFIG_SPI=y CONFIG_SPI=y

View File

@@ -88,6 +88,9 @@ CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y
CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_DM_REGULATOR_STPMIC1=y
CONFIG_REMOTEPROC_STM32_COPRO=y
CONFIG_DM_RTC=y
CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y CONFIG_SERIAL_RX_BUFFER=y
CONFIG_STM32_SERIAL=y CONFIG_STM32_SERIAL=y
CONFIG_SPI=y CONFIG_SPI=y

View File

@@ -87,6 +87,9 @@ CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STM32_VREFBUF=y
CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_DM_REGULATOR_STPMIC1=y
CONFIG_REMOTEPROC_STM32_COPRO=y
CONFIG_DM_RTC=y
CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y CONFIG_SERIAL_RX_BUFFER=y
CONFIG_STM32_SERIAL=y CONFIG_STM32_SERIAL=y
CONFIG_SPI=y CONFIG_SPI=y

View File

@@ -1,39 +1,44 @@
STM32 QSPI controller device tree bindings * STMicroelectronics Quad Serial Peripheral Interface(QSPI)
--------------------------------------------
Required properties: Required properties:
- compatible : should be "st,stm32-qspi". - compatible: should be "st,stm32f469-qspi"
- reg : 1. Physical base address and size of SPI registers map. - reg: the first contains the register location and length.
2. Physical base address & size of mapped NOR Flash. the second contains the memory mapping address and length
- spi-max-frequency : Max supported spi frequency. - reg-names: should contain the reg names "qspi" "qspi_mm"
- status : enable in requried dts. - interrupts: should contain the interrupt for the device
- clocks: the phandle of the clock needed by the QSPI controller
- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
Connected flash properties Optional properties:
-------------------------- - resets: must contain the phandle to the reset controller.
- spi-max-frequency : Max supported spi frequency.
- spi-tx-bus-width : Bus width (number of lines) for writing (1-4) A spi flash (NOR/NAND) must be a child of spi node and could have some
- spi-rx-bus-width : Bus width (number of lines) for reading (1-4) properties. Also see jedec,spi-nor.txt.
- memory-map : Address and size for memory-mapping the flash
Required properties:
- reg: chip-Select number (QSPI controller may connect 2 flashes)
- spi-max-frequency: max frequency of spi bus
Optional property:
- spi-rx-bus-width: see ./spi-bus.txt for the description
Example: Example:
qspi: quadspi@A0001000 {
compatible = "st,stm32-qspi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xA0001000 0x1000>, <0x90000000 0x10000000>;
reg-names = "QuadSPI", "QuadSPI-memory";
interrupts = <92>;
spi-max-frequency = <108000000>;
status = "okay";
qflash0: n25q128a { qspi: spi@a0001000 {
#address-cells = <1>; compatible = "st,stm32f469-qspi";
#size-cells = <1>; reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
compatible = "micron,n25q128a13", "jedec,spi-nor"; reg-names = "qspi", "qspi_mm";
spi-max-frequency = <108000000>; interrupts = <91>;
spi-tx-bus-width = <4>; resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
spi-rx-bus-width = <4>; clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
memory-map = <0x90000000 0x1000000>; pinctrl-names = "default";
reg = <0>; pinctrl-0 = <&pinctrl_qspi0>;
};
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-rx-bus-width = <4>;
spi-max-frequency = <108000000>;
...
}; };
};

View File

@@ -300,6 +300,7 @@ enum stm32mp1_parent_sel {
_DSI_SEL, _DSI_SEL,
_ADC12_SEL, _ADC12_SEL,
_SPI1_SEL, _SPI1_SEL,
_RTC_SEL,
_PARENT_SEL_NB, _PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff, _UNKNOWN_SEL = 0xff,
}; };
@@ -534,6 +535,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB2ENSETR, 5, ADC12, _HCLK2), STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB2ENSETR, 5, ADC12, _HCLK2),
@@ -569,6 +571,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
STM32MP1_CLK(RCC_BDCR, 20, RTC, _RTC_SEL),
}; };
static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER}; static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER};
@@ -594,6 +598,7 @@ static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P};
static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q};
static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER,
_PLL3_R}; _PLL3_R};
static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE};
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents),
@@ -619,6 +624,9 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents),
STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents), STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents),
STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents),
STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT,
(RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT),
rtc_parents),
}; };
#ifdef STM32MP1_CLOCK_TREE_INIT #ifdef STM32MP1_CLOCK_TREE_INIT
@@ -734,6 +742,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = {
[_DSI_SEL] = "DSI", [_DSI_SEL] = "DSI",
[_ADC12_SEL] = "ADC12", [_ADC12_SEL] = "ADC12",
[_SPI1_SEL] = "SPI1", [_SPI1_SEL] = "SPI1",
[_RTC_SEL] = "RTC",
}; };
static const struct stm32mp1_clk_data stm32mp1_data = { static const struct stm32mp1_clk_data stm32mp1_data = {

View File

@@ -318,6 +318,10 @@ u64 of_translate_address(const struct device_node *dev, const __be32 *in_addr)
return __of_translate_address(dev, in_addr, "ranges"); return __of_translate_address(dev, in_addr, "ranges");
} }
u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_addr)
{
return __of_translate_address(dev, in_addr, "dma-ranges");
}
static int __of_address_to_resource(const struct device_node *dev, static int __of_address_to_resource(const struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags, const __be32 *addrp, u64 size, unsigned int flags,

View File

@@ -770,6 +770,14 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr); return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
} }
u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
{
if (ofnode_is_np(node))
return of_translate_dma_address(ofnode_to_np(node), in_addr);
else
return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
}
int ofnode_device_is_compatible(ofnode node, const char *compat) int ofnode_device_is_compatible(ofnode node, const char *compat)
{ {
if (ofnode_is_np(node)) if (ofnode_is_np(node))

View File

@@ -265,6 +265,11 @@ u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr)
return ofnode_translate_address(dev_ofnode(dev), in_addr); return ofnode_translate_address(dev_ofnode(dev), in_addr);
} }
u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr)
{
return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
}
int dev_read_alias_highest_id(const char *stem) int dev_read_alias_highest_id(const char *stem)
{ {
if (of_live_active()) if (of_live_active())

View File

@@ -40,6 +40,16 @@ config REMOTEPROC_SANDBOX
Say 'y' here to add support for test processor which does dummy Say 'y' here to add support for test processor which does dummy
operations for sandbox platform. operations for sandbox platform.
config REMOTEPROC_STM32_COPRO
bool "Support for STM32 coprocessor"
select REMOTEPROC
depends on DM
depends on ARCH_STM32MP
depends on OF_CONTROL
help
Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the
remoteproc framework.
config REMOTEPROC_TI_POWER config REMOTEPROC_TI_POWER
bool "Support for TI Power processor" bool "Support for TI Power processor"
select REMOTEPROC select REMOTEPROC

View File

@@ -4,10 +4,11 @@
# Texas Instruments Incorporated - http://www.ti.com/ # Texas Instruments Incorporated - http://www.ti.com/
# #
obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted. # Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
obj-$(CONFIG_REMOTEPROC_K3) += k3_rproc.o obj-$(CONFIG_REMOTEPROC_K3) += k3_rproc.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o

View File

@@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#include <common.h>
#include <dm.h>
#include <elf.h>
#include <remoteproc.h>
/* Basic function to verify ELF32 image format */
int rproc_elf32_sanity_check(ulong addr, ulong size)
{
Elf32_Ehdr *ehdr;
char class;
if (!addr) {
pr_debug("Invalid fw address?\n");
return -EFAULT;
}
if (size < sizeof(Elf32_Ehdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
}
ehdr = (Elf32_Ehdr *)addr;
class = ehdr->e_ident[EI_CLASS];
if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
pr_debug("Not an executable ELF32 image\n");
return -EPROTONOSUPPORT;
}
/* We assume the firmware has the same endianness as the host */
# ifdef __LITTLE_ENDIAN
if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
# else /* BIG ENDIAN */
if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
# endif
pr_debug("Unsupported firmware endianness\n");
return -EILSEQ;
}
if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
}
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
pr_debug("Image is corrupted (bad magic)\n");
return -EBADF;
}
if (ehdr->e_phnum == 0) {
pr_debug("No loadable segments\n");
return -ENOEXEC;
}
if (ehdr->e_phoff > size) {
pr_debug("Firmware size is too small\n");
return -ENOSPC;
}
return 0;
}
/* A very simple elf loader, assumes the image is valid */
int rproc_elf32_load_image(struct udevice *dev, unsigned long addr)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
Elf32_Phdr *phdr; /* Program header structure pointer */
const struct dm_rproc_ops *ops;
unsigned int i;
ehdr = (Elf32_Ehdr *)addr;
phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
ops = rproc_get_ops(dev);
/* Load each program header */
for (i = 0; i < ehdr->e_phnum; ++i) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
if (phdr->p_type != PT_LOAD)
continue;
if (ops->device_to_virt)
dst = ops->device_to_virt(dev, (ulong)dst);
dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
if (phdr->p_filesz)
memcpy(dst, src, phdr->p_filesz);
if (phdr->p_filesz != phdr->p_memsz)
memset(dst + phdr->p_filesz, 0x00,
phdr->p_memsz - phdr->p_filesz);
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
roundup((unsigned long)dst + phdr->p_filesz,
ARCH_DMA_MINALIGN) -
rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
++phdr;
}
return 0;
}

View File

@@ -8,6 +8,7 @@
#include <dm.h> #include <dm.h>
#include <errno.h> #include <errno.h>
#include <remoteproc.h> #include <remoteproc.h>
#include <asm/io.h>
/** /**
* enum sandbox_state - different device states * enum sandbox_state - different device states
@@ -300,6 +301,23 @@ static int sandbox_testproc_ping(struct udevice *dev)
return ret; return ret;
} }
#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000
/**
* sandbox_testproc_device_to_virt() - Convert device address to virtual address
* @dev: device to operate upon
* @da: device address
* @return converted virtual address
*/
static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da)
{
u64 paddr;
/* Use a simple offset conversion */
paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
return phys_to_virt(paddr);
}
static const struct dm_rproc_ops sandbox_testproc_ops = { static const struct dm_rproc_ops sandbox_testproc_ops = {
.init = sandbox_testproc_init, .init = sandbox_testproc_init,
.reset = sandbox_testproc_reset, .reset = sandbox_testproc_reset,
@@ -308,6 +326,7 @@ static const struct dm_rproc_ops sandbox_testproc_ops = {
.stop = sandbox_testproc_stop, .stop = sandbox_testproc_stop,
.is_running = sandbox_testproc_is_running, .is_running = sandbox_testproc_is_running,
.ping = sandbox_testproc_ping, .ping = sandbox_testproc_ping,
.device_to_virt = sandbox_testproc_device_to_virt,
}; };
static const struct udevice_id sandbox_ids[] = { static const struct udevice_id sandbox_ids[] = {

View File

@@ -0,0 +1,257 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <regmap.h>
#include <remoteproc.h>
#include <reset.h>
#include <syscon.h>
#include <asm/io.h>
#define RCC_GCR_HOLD_BOOT 0
#define RCC_GCR_RELEASE_BOOT 1
/**
* struct stm32_copro_privdata - power processor private data
* @reset_ctl: reset controller handle
* @hold_boot_regmap: regmap for remote processor reset hold boot
* @hold_boot_offset: offset of the register controlling the hold boot setting
* @hold_boot_mask: bitmask of the register for the hold boot field
* @is_running: is the remote processor running
*/
struct stm32_copro_privdata {
struct reset_ctl reset_ctl;
struct regmap *hold_boot_regmap;
uint hold_boot_offset;
uint hold_boot_mask;
bool is_running;
};
/**
* stm32_copro_probe() - Basic probe
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_probe(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
struct regmap *regmap;
const fdt32_t *cell;
int len, ret;
priv = dev_get_priv(dev);
regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-holdboot");
if (IS_ERR(regmap)) {
dev_err(dev, "unable to find holdboot regmap (%ld)\n",
PTR_ERR(regmap));
return PTR_ERR(regmap);
}
cell = dev_read_prop(dev, "st,syscfg-holdboot", &len);
if (len < 3 * sizeof(fdt32_t)) {
dev_err(dev, "holdboot offset and mask not available\n");
return -EINVAL;
}
priv->hold_boot_regmap = regmap;
priv->hold_boot_offset = fdtdec_get_number(cell + 1, 1);
priv->hold_boot_mask = fdtdec_get_number(cell + 2, 1);
ret = reset_get_by_index(dev, 0, &priv->reset_ctl);
if (ret) {
dev_err(dev, "failed to get reset (%d)\n", ret);
return ret;
}
dev_dbg(dev, "probed\n");
return 0;
}
/**
* stm32_copro_set_hold_boot() - Hold boot bit management
* @dev: corresponding STM32 remote processor device
* @hold: hold boot value
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold)
{
struct stm32_copro_privdata *priv;
uint val;
int ret;
priv = dev_get_priv(dev);
val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT;
/*
* Note: shall run an SMC call (STM32_SMC_RCC) if platform is secured.
* To be updated when the code for this SMC service is available which
* is not the case for the time being.
*/
ret = regmap_update_bits(priv->hold_boot_regmap, priv->hold_boot_offset,
priv->hold_boot_mask, val);
if (ret)
dev_err(dev, "failed to set hold boot\n");
return ret;
}
/**
* stm32_copro_device_to_virt() - Convert device address to virtual address
* @dev: corresponding STM32 remote processor device
* @da: device address
* @return converted virtual address
*/
static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da)
{
fdt32_t in_addr = cpu_to_be32(da);
u64 paddr;
paddr = dev_translate_dma_address(dev, &in_addr);
if (paddr == OF_BAD_ADDR) {
dev_err(dev, "Unable to convert address %ld\n", da);
return NULL;
}
return phys_to_virt(paddr);
}
/**
* stm32_copro_load() - Loadup the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @addr: Address in memory where image is stored
* @size: Size in bytes of the image
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
{
struct stm32_copro_privdata *priv;
int ret;
priv = dev_get_priv(dev);
ret = stm32_copro_set_hold_boot(dev, true);
if (ret)
return ret;
ret = reset_assert(&priv->reset_ctl);
if (ret) {
dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
return ret;
}
/* Support only ELF32 image */
ret = rproc_elf32_sanity_check(addr, size);
if (ret) {
dev_err(dev, "Invalid ELF32 image (%d)\n", ret);
return ret;
}
return rproc_elf32_load_image(dev, addr);
}
/**
* stm32_copro_start() - Start the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_start(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
int ret;
priv = dev_get_priv(dev);
/* move hold boot from true to false start the copro */
ret = stm32_copro_set_hold_boot(dev, false);
if (ret)
return ret;
/*
* Once copro running, reset hold boot flag to avoid copro
* rebooting autonomously
*/
ret = stm32_copro_set_hold_boot(dev, true);
priv->is_running = !ret;
return ret;
}
/**
* stm32_copro_reset() - Reset the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_reset(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
int ret;
priv = dev_get_priv(dev);
ret = stm32_copro_set_hold_boot(dev, true);
if (ret)
return ret;
ret = reset_assert(&priv->reset_ctl);
if (ret) {
dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
return ret;
}
priv->is_running = false;
return 0;
}
/**
* stm32_copro_stop() - Stop the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_stop(struct udevice *dev)
{
return stm32_copro_reset(dev);
}
/**
* stm32_copro_is_running() - Is the STM32 remote processor running
* @dev: corresponding STM32 remote processor device
* @return 1 if the remote processor is running, 0 otherwise
*/
static int stm32_copro_is_running(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
priv = dev_get_priv(dev);
return priv->is_running;
}
static const struct dm_rproc_ops stm32_copro_ops = {
.load = stm32_copro_load,
.start = stm32_copro_start,
.stop = stm32_copro_stop,
.reset = stm32_copro_reset,
.is_running = stm32_copro_is_running,
.device_to_virt = stm32_copro_device_to_virt,
};
static const struct udevice_id stm32_copro_ids[] = {
{.compatible = "st,stm32mp1-rproc"},
{}
};
U_BOOT_DRIVER(stm32_copro) = {
.name = "stm32_m4_proc",
.of_match = stm32_copro_ids,
.id = UCLASS_REMOTEPROC,
.ops = &stm32_copro_ops,
.probe = stm32_copro_probe,
.priv_auto_alloc_size = sizeof(struct stm32_copro_privdata),
};

View File

@@ -120,4 +120,10 @@ config RTC_M41T62
Enable driver for ST's M41T62 compatible RTC devices (like RV-4162). Enable driver for ST's M41T62 compatible RTC devices (like RV-4162).
It is a serial (I2C) real-time clock (RTC) with alarm. It is a serial (I2C) real-time clock (RTC) with alarm.
config RTC_STM32
bool "Enable STM32 RTC driver"
depends on DM_RTC
help
Enable STM32 RTC driver. This driver supports the rtc that is present
on some STM32 SoCs.
endmenu endmenu

View File

@@ -51,5 +51,6 @@ obj-$(CONFIG_RTC_RX8025) += rx8025.o
obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o
obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
obj-$(CONFIG_RTC_S35392A) += s35392a.o obj-$(CONFIG_RTC_S35392A) += s35392a.o
obj-$(CONFIG_RTC_STM32) += stm32_rtc.o
obj-$(CONFIG_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
obj-$(CONFIG_RTC_X1205) += x1205.o obj-$(CONFIG_RTC_X1205) += x1205.o

323
drivers/rtc/stm32_rtc.c Normal file
View File

@@ -0,0 +1,323 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <rtc.h>
#include <asm/io.h>
#include <linux/iopoll.h>
#define STM32_RTC_TR 0x00
#define STM32_RTC_DR 0x04
#define STM32_RTC_ISR 0x0C
#define STM32_RTC_PRER 0x10
#define STM32_RTC_CR 0x18
#define STM32_RTC_WPR 0x24
/* STM32_RTC_TR bit fields */
#define STM32_RTC_SEC_SHIFT 0
#define STM32_RTC_SEC GENMASK(6, 0)
#define STM32_RTC_MIN_SHIFT 8
#define STM32_RTC_MIN GENMASK(14, 8)
#define STM32_RTC_HOUR_SHIFT 16
#define STM32_RTC_HOUR GENMASK(21, 16)
/* STM32_RTC_DR bit fields */
#define STM32_RTC_DATE_SHIFT 0
#define STM32_RTC_DATE GENMASK(5, 0)
#define STM32_RTC_MONTH_SHIFT 8
#define STM32_RTC_MONTH GENMASK(12, 8)
#define STM32_RTC_WDAY_SHIFT 13
#define STM32_RTC_WDAY GENMASK(15, 13)
#define STM32_RTC_YEAR_SHIFT 16
#define STM32_RTC_YEAR GENMASK(23, 16)
/* STM32_RTC_CR bit fields */
#define STM32_RTC_CR_FMT BIT(6)
/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
#define STM32_RTC_ISR_INITS BIT(4)
#define STM32_RTC_ISR_RSF BIT(5)
#define STM32_RTC_ISR_INITF BIT(6)
#define STM32_RTC_ISR_INIT BIT(7)
/* STM32_RTC_PRER bit fields */
#define STM32_RTC_PRER_PRED_S_SHIFT 0
#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
#define STM32_RTC_PRER_PRED_A_SHIFT 16
#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
/* STM32_RTC_WPR key constants */
#define RTC_WPR_1ST_KEY 0xCA
#define RTC_WPR_2ND_KEY 0x53
#define RTC_WPR_WRONG_KEY 0xFF
struct stm32_rtc_priv {
fdt_addr_t base;
};
static int stm32_rtc_get(struct udevice *dev, struct rtc_time *tm)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
u32 tr, dr;
tr = readl(priv->base + STM32_RTC_TR);
dr = readl(priv->base + STM32_RTC_DR);
tm->tm_sec = bcd2bin((tr & STM32_RTC_SEC) >> STM32_RTC_SEC_SHIFT);
tm->tm_min = bcd2bin((tr & STM32_RTC_MIN) >> STM32_RTC_MIN_SHIFT);
tm->tm_hour = bcd2bin((tr & STM32_RTC_HOUR) >> STM32_RTC_HOUR_SHIFT);
tm->tm_mday = bcd2bin((dr & STM32_RTC_DATE) >> STM32_RTC_DATE_SHIFT);
tm->tm_mon = bcd2bin((dr & STM32_RTC_MONTH) >> STM32_RTC_MONTH_SHIFT);
tm->tm_year = bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT);
tm->tm_wday = bcd2bin((dr & STM32_RTC_WDAY) >> STM32_RTC_WDAY_SHIFT);
tm->tm_yday = 0;
tm->tm_isdst = 0;
dev_dbg(dev, "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return 0;
}
static void stm32_rtc_unlock(struct udevice *dev)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
writel(RTC_WPR_1ST_KEY, priv->base + STM32_RTC_WPR);
writel(RTC_WPR_2ND_KEY, priv->base + STM32_RTC_WPR);
}
static void stm32_rtc_lock(struct udevice *dev)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
writel(RTC_WPR_WRONG_KEY, priv->base + STM32_RTC_WPR);
}
static int stm32_rtc_enter_init_mode(struct udevice *dev)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
u32 isr = readl(priv->base + STM32_RTC_ISR);
if (!(isr & STM32_RTC_ISR_INITF)) {
isr |= STM32_RTC_ISR_INIT;
writel(isr, priv->base + STM32_RTC_ISR);
return readl_poll_timeout(priv->base + STM32_RTC_ISR,
isr,
(isr & STM32_RTC_ISR_INITF),
100000);
}
return 0;
}
static int stm32_rtc_wait_sync(struct udevice *dev)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
u32 isr = readl(priv->base + STM32_RTC_ISR);
isr &= ~STM32_RTC_ISR_RSF;
writel(isr, priv->base + STM32_RTC_ISR);
/*
* Wait for RSF to be set to ensure the calendar registers are
* synchronised, it takes around 2 rtc_ck clock cycles
*/
return readl_poll_timeout(priv->base + STM32_RTC_ISR,
isr, (isr & STM32_RTC_ISR_RSF),
100000);
}
static void stm32_rtc_exit_init_mode(struct udevice *dev)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
u32 isr = readl(priv->base + STM32_RTC_ISR);
isr &= ~STM32_RTC_ISR_INIT;
writel(isr, priv->base + STM32_RTC_ISR);
}
static int stm32_rtc_set_time(struct udevice *dev, u32 time, u32 date)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
int ret;
stm32_rtc_unlock(dev);
ret = stm32_rtc_enter_init_mode(dev);
if (ret)
goto lock;
writel(time, priv->base + STM32_RTC_TR);
writel(date, priv->base + STM32_RTC_DR);
stm32_rtc_exit_init_mode(dev);
ret = stm32_rtc_wait_sync(dev);
lock:
stm32_rtc_lock(dev);
return ret;
}
static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm)
{
u32 t, d;
dev_dbg(dev, "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
/* Time in BCD format */
t = (bin2bcd(tm->tm_sec) << STM32_RTC_SEC_SHIFT) & STM32_RTC_SEC;
t |= (bin2bcd(tm->tm_min) << STM32_RTC_MIN_SHIFT) & STM32_RTC_MIN;
t |= (bin2bcd(tm->tm_hour) << STM32_RTC_HOUR_SHIFT) & STM32_RTC_HOUR;
/* Date in BCD format */
d = (bin2bcd(tm->tm_mday) << STM32_RTC_DATE_SHIFT) & STM32_RTC_DATE;
d |= (bin2bcd(tm->tm_mon) << STM32_RTC_MONTH_SHIFT) & STM32_RTC_MONTH;
d |= (bin2bcd(tm->tm_year) << STM32_RTC_YEAR_SHIFT) & STM32_RTC_YEAR;
d |= (bin2bcd(tm->tm_wday) << STM32_RTC_WDAY_SHIFT) & STM32_RTC_WDAY;
return stm32_rtc_set_time(dev, t, d);
}
static int stm32_rtc_reset(struct udevice *dev)
{
dev_dbg(dev, "Reset DATE\n");
return stm32_rtc_set_time(dev, 0, 0);
}
static int stm32_rtc_init(struct udevice *dev)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
unsigned int rate;
struct clk clk;
int ret;
u32 isr = readl(priv->base + STM32_RTC_ISR);
if (isr & STM32_RTC_ISR_INITS)
return 0;
ret = clk_get_by_index(dev, 1, &clk);
if (ret)
return ret;
ret = clk_enable(&clk);
if (ret) {
clk_free(&clk);
return ret;
}
rate = clk_get_rate(&clk);
/* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
pred_s = (rate / (pred_a + 1)) - 1;
if (((pred_s + 1) * (pred_a + 1)) == rate)
break;
}
/*
* Can't find a 1Hz, so give priority to RTC power consumption
* by choosing the higher possible value for prediv_a
*/
if (pred_s > pred_s_max || pred_a > pred_a_max) {
pred_a = pred_a_max;
pred_s = (rate / (pred_a + 1)) - 1;
}
stm32_rtc_unlock(dev);
ret = stm32_rtc_enter_init_mode(dev);
if (ret) {
dev_err(dev,
"Can't enter in init mode. Prescaler config failed.\n");
goto unlock;
}
prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
writel(prer, priv->base + STM32_RTC_PRER);
/* Force 24h time format */
cr = readl(priv->base + STM32_RTC_CR);
cr &= ~STM32_RTC_CR_FMT;
writel(cr, priv->base + STM32_RTC_CR);
stm32_rtc_exit_init_mode(dev);
ret = stm32_rtc_wait_sync(dev);
unlock:
stm32_rtc_lock(dev);
if (ret) {
clk_disable(&clk);
clk_free(&clk);
}
return ret;
}
static int stm32_rtc_probe(struct udevice *dev)
{
struct stm32_rtc_priv *priv = dev_get_priv(dev);
struct clk clk;
int ret;
priv->base = dev_read_addr(dev);
if (priv->base == FDT_ADDR_T_NONE)
return -EINVAL;
ret = clk_get_by_index(dev, 0, &clk);
if (ret)
return ret;
ret = clk_enable(&clk);
if (ret) {
clk_free(&clk);
return ret;
}
ret = stm32_rtc_init(dev);
if (ret) {
clk_disable(&clk);
clk_free(&clk);
}
return ret;
}
static const struct rtc_ops stm32_rtc_ops = {
.get = stm32_rtc_get,
.set = stm32_rtc_set,
.reset = stm32_rtc_reset,
};
static const struct udevice_id stm32_rtc_ids[] = {
{ .compatible = "st,stm32mp1-rtc" },
{ }
};
U_BOOT_DRIVER(rtc_stm32) = {
.name = "rtc-stm32",
.id = UCLASS_RTC,
.probe = stm32_rtc_probe,
.of_match = stm32_rtc_ids,
.ops = &stm32_rtc_ops,
.priv_auto_alloc_size = sizeof(struct stm32_rtc_priv),
};

View File

@@ -526,7 +526,6 @@ static const struct dm_spi_ops stm32_qspi_ops = {
}; };
static const struct udevice_id stm32_qspi_ids[] = { static const struct udevice_id stm32_qspi_ids[] = {
{ .compatible = "st,stm32-qspi" },
{ .compatible = "st,stm32f469-qspi" }, { .compatible = "st,stm32f469-qspi" },
{ } { }
}; };

View File

@@ -26,6 +26,24 @@
*/ */
u64 of_translate_address(const struct device_node *no, const __be32 *in_addr); u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
/**
* of_translate_dma_address() - translate a device-tree DMA address to a CPU
* address
*
* Translate a DMA address from the device-tree into a CPU physical address,
* this walks up the tree and applies the various bus mappings on the way.
*
* Note: We consider that crossing any level with #size-cells == 0 to mean
* that translation is impossible (that is we are not dealing with a value
* that can be mapped to a cpu physical address). This is not really specified
* that way, but this is traditionally the way IBM at least do things
*
* @np: node to check
* @in_addr: pointer to input DMA address
* @return translated DMA address or OF_BAD_ADDR on error
*/
u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr);
/** /**
* of_get_address() - obtain an address from a node * of_get_address() - obtain an address from a node
* *

View File

@@ -767,7 +767,7 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname,
node = ofnode_next_subnode(node)) node = ofnode_next_subnode(node))
/** /**
* ofnode_translate_address() - Tranlate a device-tree address * ofnode_translate_address() - Translate a device-tree address
* *
* Translate an address from the device-tree into a CPU physical address. This * Translate an address from the device-tree into a CPU physical address. This
* function walks up the tree and applies the various bus mappings along the * function walks up the tree and applies the various bus mappings along the
@@ -780,6 +780,20 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname,
*/ */
u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr); u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
/**
* ofnode_translate_dma_address() - Translate a device-tree DMA address
*
* Translate a DMA address from the device-tree into a CPU physical address.
* This function walks up the tree and applies the various bus mappings along
* the way.
*
* @ofnode: Device tree node giving the context in which to translate the
* DMA address
* @in_addr: pointer to the DMA address to translate
* @return the translated DMA address; OF_BAD_ADDR on error
*/
u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr);
/** /**
* ofnode_device_is_compatible() - check if the node is compatible with compat * ofnode_device_is_compatible() - check if the node is compatible with compat
* *

View File

@@ -499,7 +499,7 @@ int dev_read_resource_byname(struct udevice *dev, const char *name,
struct resource *res); struct resource *res);
/** /**
* dev_translate_address() - Tranlate a device-tree address * dev_translate_address() - Translate a device-tree address
* *
* Translate an address from the device-tree into a CPU physical address. This * Translate an address from the device-tree into a CPU physical address. This
* function walks up the tree and applies the various bus mappings along the * function walks up the tree and applies the various bus mappings along the
@@ -511,6 +511,19 @@ int dev_read_resource_byname(struct udevice *dev, const char *name,
*/ */
u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr); u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr);
/**
* dev_translate_dma_address() - Translate a device-tree DMA address
*
* Translate a DMA address from the device-tree into a CPU physical address.
* This function walks up the tree and applies the various bus mappings along
* the way.
*
* @dev: device giving the context in which to translate the DMA address
* @in_addr: pointer to the DMA address to translate
* @return the translated DMA address; OF_BAD_ADDR on error
*/
u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr);
/** /**
* dev_read_alias_highest_id - Get highest alias id for the given stem * dev_read_alias_highest_id - Get highest alias id for the given stem
* @stem: Alias stem to be examined * @stem: Alias stem to be examined
@@ -751,6 +764,11 @@ static inline u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_a
return ofnode_translate_address(dev_ofnode(dev), in_addr); return ofnode_translate_address(dev_ofnode(dev), in_addr);
} }
static inline u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr)
{
return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
}
static inline int dev_read_alias_highest_id(const char *stem) static inline int dev_read_alias_highest_id(const char *stem)
{ {
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem); return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);

View File

@@ -218,8 +218,32 @@ static inline void fdt_fixup_mtdparts(void *fdt,
#endif #endif
void fdt_del_node_and_alias(void *blob, const char *alias); void fdt_del_node_and_alias(void *blob, const char *alias);
/**
* Translate an address from the DT into a CPU physical address
*
* The translation relies on the "ranges" property.
*
* @param blob Pointer to device tree blob
* @param node_offset Node DT offset
* @param in_addr Pointer to the address to translate
* @return translated address or OF_BAD_ADDR on error
*/
u64 fdt_translate_address(const void *blob, int node_offset, u64 fdt_translate_address(const void *blob, int node_offset,
const __be32 *in_addr); const __be32 *in_addr);
/**
* Translate a DMA address from the DT into a CPU physical address
*
* The translation relies on the "dma-ranges" property.
*
* @param blob Pointer to device tree blob
* @param node_offset Node DT offset
* @param in_addr Pointer to the DMA address to translate
* @return translated DMA address or OF_BAD_ADDR on error
*/
u64 fdt_translate_dma_address(const void *blob, int node_offset,
const __be32 *in_addr);
int fdt_node_offset_by_compat_reg(void *blob, const char *compat, int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
phys_addr_t compat_off); phys_addr_t compat_off);
int fdt_alloc_phandle(void *blob); int fdt_alloc_phandle(void *blob);

View File

@@ -45,33 +45,86 @@ struct dm_rproc_uclass_pdata {
}; };
/** /**
* struct dm_rproc_ops - Operations that are provided by remote proc driver * struct dm_rproc_ops - Driver model remote proc operations.
* @init: Initialize the remoteproc device invoked after probe (optional) *
* Return 0 on success, -ve error on fail * This defines the operations provided by remote proc driver.
* @load: Load the remoteproc device using data provided(mandatory)
* This takes the following additional arguments.
* addr- Address of the binary image to be loaded
* size- Size of the binary image to be loaded
* Return 0 on success, -ve error on fail
* @start: Start the remoteproc device (mandatory)
* Return 0 on success, -ve error on fail
* @stop: Stop the remoteproc device (optional)
* Return 0 on success, -ve error on fail
* @reset: Reset the remote proc device (optional)
* Return 0 on success, -ve error on fail
* @is_running: Check if the remote processor is running(optional)
* Return 0 on success, 1 if not running, -ve on others errors
* @ping: Ping the remote device for basic communication check(optional)
* Return 0 on success, 1 if not responding, -ve on other errors
*/ */
struct dm_rproc_ops { struct dm_rproc_ops {
/**
* init() - Initialize the remoteproc device (optional)
*
* This is called after the probe is completed allowing the remote
* processor drivers to split up the initializations between probe and
* init if needed.
*
* @dev: Remote proc device
* @return 0 if all ok, else appropriate error value.
*/
int (*init)(struct udevice *dev); int (*init)(struct udevice *dev);
/**
* load() - Load the remoteproc device using data provided (mandatory)
*
* Load the remoteproc device with an image, do not start the device.
*
* @dev: Remote proc device
* @addr: Address of the image to be loaded
* @size: Size of the image to be loaded
* @return 0 if all ok, else appropriate error value.
*/
int (*load)(struct udevice *dev, ulong addr, ulong size); int (*load)(struct udevice *dev, ulong addr, ulong size);
/**
* start() - Start the remoteproc device (mandatory)
*
* @dev: Remote proc device
* @return 0 if all ok, else appropriate error value.
*/
int (*start)(struct udevice *dev); int (*start)(struct udevice *dev);
/**
* stop() - Stop the remoteproc device (optional)
*
* @dev: Remote proc device
* @return 0 if all ok, else appropriate error value.
*/
int (*stop)(struct udevice *dev); int (*stop)(struct udevice *dev);
/**
* reset() - Reset the remoteproc device (optional)
*
* @dev: Remote proc device
* @return 0 if all ok, else appropriate error value.
*/
int (*reset)(struct udevice *dev); int (*reset)(struct udevice *dev);
/**
* is_running() - Check if the remote processor is running (optional)
*
* @dev: Remote proc device
* @return 0 if running, 1 if not running, -ve on error.
*/
int (*is_running)(struct udevice *dev); int (*is_running)(struct udevice *dev);
/**
* ping() - Ping the remote device for basic communication (optional)
*
* @dev: Remote proc device
* @return 0 on success, 1 if not responding, -ve on other errors.
*/
int (*ping)(struct udevice *dev); int (*ping)(struct udevice *dev);
/**
* device_to_virt() - Return translated virtual address (optional)
*
* Translate a device address (remote processor view) to virtual
* address (main processor view).
*
* @dev: Remote proc device
* @da: Device address
* @return virtual address.
*/
void * (*device_to_virt)(struct udevice *dev, ulong da);
}; };
/* Accessor */ /* Accessor */
@@ -80,82 +133,93 @@ struct dm_rproc_ops {
#ifdef CONFIG_REMOTEPROC #ifdef CONFIG_REMOTEPROC
/** /**
* rproc_init() - Initialize all bound remote proc devices * rproc_init() - Initialize all bound remote proc devices
* * @return 0 if all ok, else appropriate error value.
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_init(void); int rproc_init(void);
/** /**
* rproc_dev_init() - Initialize a remote proc device based on id * rproc_dev_init() - Initialize a remote proc device based on id
* @id: id of the remote processor * @id: id of the remote processor
* * @return 0 if all ok, else appropriate error value.
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_dev_init(int id); int rproc_dev_init(int id);
/** /**
* rproc_is_initialized() - check to see if remoteproc devices are initialized * rproc_is_initialized() - check to see if remoteproc devices are initialized
* * @return true if all devices are initialized, false otherwise.
* Return: 0 if all devices are initialized, else appropriate error value.
*/ */
bool rproc_is_initialized(void); bool rproc_is_initialized(void);
/** /**
* rproc_load() - load binary to a remote processor * rproc_load() - load binary or elf to a remote processor
* @id: id of the remote processor * @id: id of the remote processor
* @addr: address in memory where the binary image is located * @addr: address in memory where the image is located
* @size: size of the binary image * @size: size of the image
* * @return 0 if all ok, else appropriate error value.
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_load(int id, ulong addr, ulong size); int rproc_load(int id, ulong addr, ulong size);
/** /**
* rproc_start() - Start a remote processor * rproc_start() - Start a remote processor
* @id: id of the remote processor * @id: id of the remote processor
* * @return 0 if all ok, else appropriate error value.
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_start(int id); int rproc_start(int id);
/** /**
* rproc_stop() - Stop a remote processor * rproc_stop() - Stop a remote processor
* @id: id of the remote processor * @id: id of the remote processor
* * @return 0 if all ok, else appropriate error value.
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_stop(int id); int rproc_stop(int id);
/** /**
* rproc_reset() - reset a remote processor * rproc_reset() - reset a remote processor
* @id: id of the remote processor * @id: id of the remote processor
* * @return 0 if all ok, else appropriate error value.
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_reset(int id); int rproc_reset(int id);
/** /**
* rproc_ping() - ping a remote processor to check if it can communicate * rproc_ping() - ping a remote processor to check if it can communicate
* @id: id of the remote processor * @id: id of the remote processor
* @return 0 if all ok, else appropriate error value.
* *
* NOTE: this might need communication path available, which is not implemented * NOTE: this might need communication path available, which is not implemented
* as part of remoteproc framework - hook on to appropriate bus architecture to * as part of remoteproc framework - hook on to appropriate bus architecture to
* do the same * do the same
*
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_ping(int id); int rproc_ping(int id);
/** /**
* rproc_is_running() - check to see if remote processor is running * rproc_is_running() - check to see if remote processor is running
* @id: id of the remote processor * @id: id of the remote processor
* @return 0 if running, 1 if not running, -ve on error.
* *
* NOTE: this may not involve actual communication capability of the remote * NOTE: this may not involve actual communication capability of the remote
* processor, but just ensures that it is out of reset and executing code. * processor, but just ensures that it is out of reset and executing code.
*
* Return: 0 if all ok, else appropriate error value.
*/ */
int rproc_is_running(int id); int rproc_is_running(int id);
/**
* rproc_elf32_sanity_check() - Verify if an image is a valid ELF32 one
*
* Check if a valid ELF32 image exists at the given memory location. Verify
* basic ELF32 format requirements like magic number and sections size.
*
* @addr: address of the image to verify
* @size: size of the image
* @return 0 if the image looks good, else appropriate error value.
*/
int rproc_elf32_sanity_check(ulong addr, ulong size);
/**
* rproc_elf32_load_image() - load an ELF32 image
* @dev: device loading the ELF32 image
* @addr: valid ELF32 image address
* @return 0 if the image is successfully loaded, else appropriate error value.
*/
int rproc_elf32_load_image(struct udevice *dev, unsigned long addr);
#else #else
static inline int rproc_init(void) { return -ENOSYS; } static inline int rproc_init(void) { return -ENOSYS; }
static inline int rproc_dev_init(int id) { return -ENOSYS; } static inline int rproc_dev_init(int id) { return -ENOSYS; }
@@ -166,6 +230,10 @@ static inline int rproc_stop(int id) { return -ENOSYS; }
static inline int rproc_reset(int id) { return -ENOSYS; } static inline int rproc_reset(int id) { return -ENOSYS; }
static inline int rproc_ping(int id) { return -ENOSYS; } static inline int rproc_ping(int id) { return -ENOSYS; }
static inline int rproc_is_running(int id) { return -ENOSYS; } static inline int rproc_is_running(int id) { return -ENOSYS; }
static inline int rproc_elf32_sanity_check(ulong addr,
ulong size) { return -ENOSYS; }
static inline int rproc_elf32_load_image(struct udevice *dev,
unsigned long addr) { return -ENOSYS; }
#endif #endif
#endif /* _RPROC_H_ */ #endif /* _RPROC_H_ */

View File

@@ -5,8 +5,10 @@
*/ */
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <elf.h>
#include <errno.h> #include <errno.h>
#include <remoteproc.h> #include <remoteproc.h>
#include <asm/io.h>
#include <dm/test.h> #include <dm/test.h>
#include <test/ut.h> #include <test/ut.h>
/** /**
@@ -65,3 +67,123 @@ static int dm_test_remoteproc_base(struct unit_test_state *uts)
return 0; return 0;
} }
DM_TEST(dm_test_remoteproc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); DM_TEST(dm_test_remoteproc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
#define DEVICE_TO_PHYSICAL_OFFSET 0x1000
/**
* dm_test_remoteproc_elf() - test the ELF operations
* @uts: unit test state
*
* Return: 0 if test passed, else error
*/
static int dm_test_remoteproc_elf(struct unit_test_state *uts)
{
u8 valid_elf32[] = {
/* @0x00 - ELF HEADER - */
/* ELF magic */
0x7f, 0x45, 0x4c, 0x46,
/* 32 Bits */
0x01,
/* Endianness */
#ifdef __LITTLE_ENDIAN
0x01,
#else
0x02,
#endif
/* Version */
0x01,
/* Padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Type : executable */
0x02, 0x00,
/* Machine: ARM */
0x28, 0x00,
/* Version */
0x01, 0x00, 0x00, 0x00,
/* Entry */
0x00, 0x00, 0x00, 0x08,
/* phoff (program header offset @ 0x40)*/
0x40, 0x00, 0x00, 0x00,
/* shoff (section header offset : none) */
0x00, 0x00, 0x00, 0x00,
/* flags */
0x00, 0x00, 0x00, 0x00,
/* ehsize (elf header size = 0x34) */
0x34, 0x00,
/* phentsize (program header size = 0x20) */
0x20, 0x00,
/* phnum (program header number : 1) */
0x01, 0x00,
/* shentsize (section heade size : none) */
0x00, 0x00,
/* shnum (section header number: none) */
0x00, 0x00,
/* shstrndx (section header name section index: none) */
0x00, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
/* @0x40 - PROGRAM HEADER TABLE - */
/* type : PT_LOAD */
0x01, 0x00, 0x00, 0x00,
/* offset */
0x00, 0x00, 0x00, 0x00,
/* vaddr */
0x00, 0x00, 0x00, 0x00,
/* paddr : physical address */
0x00, 0x00, 0x00, 0x00,
/* filesz : 0x20 bytes (program header size) */
0x20, 0x00, 0x00, 0x00,
/* memsz = filesz */
0x20, 0x00, 0x00, 0x00,
/* flags : readable and exectuable */
0x05, 0x00, 0x00, 0x00,
/* padding */
0x00, 0x00, 0x00, 0x00,
};
unsigned int size = ARRAY_SIZE(valid_elf32);
struct udevice *dev;
phys_addr_t loaded_firmware_paddr;
void *loaded_firmware;
u32 loaded_firmware_size;
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)valid_elf32;
Elf32_Phdr *phdr = (Elf32_Phdr *)(valid_elf32 + ehdr->e_phoff);
ut_assertok(uclass_get_device(UCLASS_REMOTEPROC, 0, &dev));
/*
* In its Program Header Table, let the firmware specifies to be loaded
* at SDRAM_BASE *device* address (p_paddr field).
* Its size is defined by the p_filesz field.
*/
phdr->p_paddr = CONFIG_SYS_SDRAM_BASE;
loaded_firmware_size = phdr->p_filesz;
/*
* This *device* address is converted to a *physical* address by the
* device_to_virt() operation of sandbox_test_rproc which returns
* DeviceAddress + DEVICE_TO_PHYSICAL_OFFSET.
* This is where we expect to get the firmware loaded.
*/
loaded_firmware_paddr = phdr->p_paddr + DEVICE_TO_PHYSICAL_OFFSET;
loaded_firmware = map_physmem(loaded_firmware_paddr,
loaded_firmware_size, MAP_NOCACHE);
ut_assertnonnull(loaded_firmware);
memset(loaded_firmware, 0, loaded_firmware_size);
/* Verify valid ELF format */
ut_assertok(rproc_elf32_sanity_check((ulong)valid_elf32, size));
/* Load firmware in loaded_firmware, and verify it */
ut_assertok(rproc_elf32_load_image(dev, (unsigned long)valid_elf32));
ut_assertok(memcmp(loaded_firmware, valid_elf32, loaded_firmware_size));
unmap_physmem(loaded_firmware, MAP_NOCACHE);
/* Invalid ELF Magic */
valid_elf32[0] = 0;
ut_asserteq(-EPROTONOSUPPORT,
rproc_elf32_sanity_check((ulong)valid_elf32, size));
return 0;
}
DM_TEST(dm_test_remoteproc_elf, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

View File

@@ -490,6 +490,7 @@ U_BOOT_DRIVER(fdt_dummy_drv) = {
static int dm_test_fdt_translation(struct unit_test_state *uts) static int dm_test_fdt_translation(struct unit_test_state *uts)
{ {
struct udevice *dev; struct udevice *dev;
fdt32_t dma_addr[2];
/* Some simple translations */ /* Some simple translations */
ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev)); ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev));
@@ -509,6 +510,17 @@ static int dm_test_fdt_translation(struct unit_test_state *uts)
ut_asserteq_str("dev@42", dev->name); ut_asserteq_str("dev@42", dev->name);
ut_asserteq(0x42, dev_read_addr(dev)); ut_asserteq(0x42, dev_read_addr(dev));
/* dma address translation */
ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev));
dma_addr[0] = cpu_to_be32(0);
dma_addr[1] = cpu_to_be32(0);
ut_asserteq(0x10000000, dev_translate_dma_address(dev, dma_addr));
ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 1, true, &dev));
dma_addr[0] = cpu_to_be32(1);
dma_addr[1] = cpu_to_be32(0x100);
ut_asserteq(0x20000000, dev_translate_dma_address(dev, dma_addr));
return 0; return 0;
} }
DM_TEST(dm_test_fdt_translation, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); DM_TEST(dm_test_fdt_translation, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);