diff options
| -rw-r--r-- | arch/arm/dts/tegra186.dtsi | 13 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/mailbox/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/mailbox/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mailbox/tegra-hsp.c | 163 | ||||
| -rw-r--r-- | include/dt-bindings/mailbox/tegra-hsp.h | 14 | 
6 files changed, 200 insertions, 0 deletions
| diff --git a/arch/arm/dts/tegra186.dtsi b/arch/arm/dts/tegra186.dtsi index 18b6a266434..fce34fa6500 100644 --- a/arch/arm/dts/tegra186.dtsi +++ b/arch/arm/dts/tegra186.dtsi @@ -1,6 +1,7 @@  #include "skeleton.dtsi"  #include <dt-bindings/gpio/tegra-gpio.h>  #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/mailbox/tegra-hsp.h>  / {  	compatible = "nvidia,tegra186"; @@ -40,6 +41,18 @@  		status = "disabled";  	}; +	hsp: hsp@3c00000 { +		compatible = "nvidia,tegra186-hsp"; +		reg = <0x0 0x03c00000 0x0 0xa0000>; +		interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; +		nvidia,num-SM = <0x8>; +		nvidia,num-AS = <0x2>; +		nvidia,num-SS = <0x2>; +		nvidia,num-DB = <0x7>; +		nvidia,num-SI = <0x8>; +		#mbox-cells = <1>; +	}; +  	gpio@c2f0000 {  		compatible = "nvidia,tegra186-gpio-aon";  		reg-names = "security", "gpio"; diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index b18a12e3420..f4affa5512b 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -56,8 +56,10 @@ config TEGRA210  config TEGRA186  	bool "Tegra186 family" +	select DM_MAILBOX  	select TEGRA186_GPIO  	select TEGRA_ARMV8_COMMON +	select TEGRA_HSP  endchoice diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 90875123901..9649b705895 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -17,4 +17,11 @@ config SANDBOX_MBOX  	  Enable support for a test mailbox implementation, which simply echos  	  back a modified version of any message that is sent. +config TEGRA_HSP +	bool "Enable Tegra HSP controller support" +	depends on DM_MAILBOX && TEGRA +	help +	  This enables support for the NVIDIA Tegra HSP Hw module, which +	  implements doorbells, mailboxes, semaphores, and shared interrupts. +  endmenu diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index bbae4def6d4..155dbeb0994 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -5,3 +5,4 @@  obj-$(CONFIG_DM_MAILBOX) += mailbox-uclass.o  obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o  obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o +obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c new file mode 100644 index 00000000000..5c781a50b6a --- /dev/null +++ b/drivers/mailbox/tegra-hsp.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <asm/io.h> +#include <dm.h> +#include <mailbox-uclass.h> +#include <dt-bindings/mailbox/tegra-hsp.h> + +#define TEGRA_HSP_DB_REG_TRIGGER	0x0 +#define TEGRA_HSP_DB_REG_ENABLE		0x4 +#define TEGRA_HSP_DB_REG_RAW		0x8 +#define TEGRA_HSP_DB_REG_PENDING	0xc + +#define TEGRA_HSP_DB_ID_CCPLEX		1 +#define TEGRA_HSP_DB_ID_BPMP		3 +#define TEGRA_HSP_DB_ID_NUM		7 + +struct tegra_hsp { +	fdt_addr_t regs; +	uint32_t db_base; +}; + +DECLARE_GLOBAL_DATA_PTR; + +static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id, +			       uint32_t reg) +{ +	return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg); +} + +static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id, +				uint32_t reg) +{ +	uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); +	return readl(r); +} + +static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val, +			     uint32_t db_id, uint32_t reg) +{ +	uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); + +	writel(val, r); +	readl(r); +} + +static int tegra_hsp_db_id(ulong chan_id) +{ +	switch (chan_id) { +	case TEGRA_HSP_MASTER_BPMP: +		return TEGRA_HSP_DB_ID_BPMP; +	default: +		debug("Invalid channel ID\n"); +		return -EINVAL; +	} +} + +static int tegra_hsp_request(struct mbox_chan *chan) +{ +	int db_id; + +	debug("%s(chan=%p)\n", __func__, chan); + +	db_id = tegra_hsp_db_id(chan->id); +	if (db_id < 0) { +		debug("tegra_hsp_db_id() failed: %d\n", db_id); +		return -EINVAL; +	} + +	return 0; +} + +static int tegra_hsp_free(struct mbox_chan *chan) +{ +	debug("%s(chan=%p)\n", __func__, chan); + +	return 0; +} + +static int tegra_hsp_send(struct mbox_chan *chan, const void *data) +{ +	struct tegra_hsp *thsp = dev_get_priv(chan->dev); +	int db_id; + +	debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + +	db_id = tegra_hsp_db_id(chan->id); +	tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER); + +	return 0; +} + +static int tegra_hsp_recv(struct mbox_chan *chan, void *data) +{ +	struct tegra_hsp *thsp = dev_get_priv(chan->dev); +	uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX; +	uint32_t val; + +	debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + +	val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW); +	if (!(val & BIT(chan->id))) +		return -ENODATA; + +	tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW); + +	return 0; +} + +static int tegra_hsp_bind(struct udevice *dev) +{ +	debug("%s(dev=%p)\n", __func__, dev); + +	return 0; +} + +static int tegra_hsp_probe(struct udevice *dev) +{ +	struct tegra_hsp *thsp = dev_get_priv(dev); +	int nr_sm, nr_ss, nr_as; + +	debug("%s(dev=%p)\n", __func__, dev); + +	thsp->regs = dev_get_addr(dev); +	if (thsp->regs == FDT_ADDR_T_NONE) +		return -ENODEV; + +	nr_sm = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-SM", +			       0); +	nr_ss = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-SS", +			       0); +	nr_as = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-AS", +			       0); +	thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16; + +	return 0; +} + +static const struct udevice_id tegra_hsp_ids[] = { +	{ .compatible = "nvidia,tegra186-hsp" }, +	{ } +}; + +struct mbox_ops tegra_hsp_mbox_ops = { +	.request = tegra_hsp_request, +	.free = tegra_hsp_free, +	.send = tegra_hsp_send, +	.recv = tegra_hsp_recv, +}; + +U_BOOT_DRIVER(tegra_hsp) = { +	.name = "tegra-hsp", +	.id = UCLASS_MAILBOX, +	.of_match = tegra_hsp_ids, +	.bind = tegra_hsp_bind, +	.probe = tegra_hsp_probe, +	.priv_auto_alloc_size = sizeof(struct tegra_hsp), +	.ops = &tegra_hsp_mbox_ops, +}; diff --git a/include/dt-bindings/mailbox/tegra-hsp.h b/include/dt-bindings/mailbox/tegra-hsp.h new file mode 100644 index 00000000000..e8c23fa91d2 --- /dev/null +++ b/include/dt-bindings/mailbox/tegra-hsp.h @@ -0,0 +1,14 @@ +/* + * This header provides constants for binding nvidia,tegra186-hsp. + * + * The number with TEGRA_HSP_MASTER prefix indicates the bit that is + * associated with a master ID in the doorbell registers. + */ + +#ifndef _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H +#define _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H + +#define TEGRA_HSP_MASTER_CCPLEX		17 +#define TEGRA_HSP_MASTER_BPMP		19 + +#endif | 
